aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorsyeyoung <cyong06@naver.com>2021-03-06 13:01:03 +0900
committersyeyoung <cyong06@naver.com>2021-03-06 13:01:03 +0900
commitccdcb508b1b7b5fcc212efc39466434631118e87 (patch)
treef09e4fb0db49a10a1f91757c0432a908e6f89a6d /src/main/java
parentd07cfe08841302ad1ce1e29902d06c4c439a589f (diff)
downloadSkyblock-Dungeons-Guide-ccdcb508b1b7b5fcc212efc39466434631118e87.tar.gz
Skyblock-Dungeons-Guide-ccdcb508b1b7b5fcc212efc39466434631118e87.tar.bz2
Skyblock-Dungeons-Guide-ccdcb508b1b7b5fcc212efc39466434631118e87.zip
UHH why would you troll
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/RichPresenceManager.java39
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java5
-rw-r--r--src/main/java/net/arikia/dev/drpc/DiscordEventHandlers.java90
-rw-r--r--src/main/java/net/arikia/dev/drpc/DiscordRPC.java234
-rw-r--r--src/main/java/net/arikia/dev/drpc/DiscordRichPresence.java232
-rw-r--r--src/main/java/net/arikia/dev/drpc/DiscordUser.java39
-rw-r--r--src/main/java/net/arikia/dev/drpc/OSUtil.java25
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/DisconnectedCallback.java21
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/ErroredCallback.java21
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/JoinGameCallback.java20
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/JoinRequestCallback.java22
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/ReadyCallback.java23
-rw-r--r--src/main/java/net/arikia/dev/drpc/callbacks/SpectateGameCallback.java20
13 files changed, 776 insertions, 15 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/RichPresenceManager.java b/src/main/java/kr/syeyoung/dungeonsguide/RichPresenceManager.java
index 422d15e1..641522a6 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/RichPresenceManager.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/RichPresenceManager.java
@@ -6,18 +6,23 @@ import kr.syeyoung.dungeonsguide.features.FeatureRegistry;
import kr.syeyoung.dungeonsguide.party.PartyManager;
import kr.syeyoung.dungeonsguide.stomp.StompHeader;
import kr.syeyoung.dungeonsguide.stomp.StompPayload;
-import net.arikia.dev.drpc.DiscordEventHandlers;
-import net.arikia.dev.drpc.DiscordRPC;
-import net.arikia.dev.drpc.DiscordRichPresence;
-import net.arikia.dev.drpc.DiscordUser;
+import net.arikia.dev.drpc.*;
import net.arikia.dev.drpc.callbacks.*;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.json.JSONObject;
-public class RichPresenceManager implements JoinRequestCallback, JoinGameCallback, ErroredCallback, DisconnectedCallback {
+import java.io.*;
+import java.net.URL;
+
+public class RichPresenceManager implements JoinRequestCallback, JoinGameCallback, ErroredCallback, DisconnectedCallback, Runnable {
public static RichPresenceManager INSTANCE = new RichPresenceManager();
+ public RichPresenceManager() {
+ setup();
+ new Thread(this).start();
+ Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC::discordShutdown));
+ }
public void setup() {
DiscordRPC.discordInitialize("816298079732498473", new DiscordEventHandlers.Builder()
.setReadyEventHandler(new ReadyCallback() {
@@ -36,7 +41,6 @@ public class RichPresenceManager implements JoinRequestCallback, JoinGameCallbac
public void updatePresence() {
- nextUpdate= System.currentTimeMillis() + 10000L;
if (!skyblockStatus.isOnHypixel() || !FeatureRegistry.ADVANCED_RICHPRESENCE.isEnabled()) {
DiscordRPC.discordClearPresence();
} else {
@@ -67,17 +71,9 @@ public class RichPresenceManager implements JoinRequestCallback, JoinGameCallbac
}
private String lastLoc = "";
- private long nextUpdate = System.currentTimeMillis() + 10000L;
+
@SubscribeEvent
public void tick(TickEvent.ClientTickEvent clientTickEvent) {
- try {
- if (skyblockStatus.isOnSkyblock() && !lastLoc.equalsIgnoreCase(skyblockStatus.getDungeonName())) {
- lastLoc = skyblockStatus.getDungeonName()+"";
- updatePresence();
- } else if (nextUpdate < System.currentTimeMillis()) {
- updatePresence();
- }
- } catch (Exception e) {e.printStackTrace();}
}
@Override
@@ -99,4 +95,17 @@ public class RichPresenceManager implements JoinRequestCallback, JoinGameCallbac
System.out.println(user.username+" wants to join");
DiscordRPC.discordRespond(user.userId, DiscordRPC.DiscordReply.YES);
}
+
+ @Override
+ public void run() {
+ while(true) {
+ try {
+ DiscordRPC.discordRunCallbacks();
+ if (skyblockStatus.isOnSkyblock() && !lastLoc.equalsIgnoreCase(skyblockStatus.getDungeonName())) {
+ lastLoc = skyblockStatus.getDungeonName()+"";
+ }
+ updatePresence();
+ } catch (Exception e) {e.printStackTrace();}
+ }
+ }
}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java b/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java
index 08492ae8..e3c3ff49 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java
@@ -148,6 +148,9 @@ public class PartyManager implements StompMessageHandler {
} else if (str.startsWith("§cYou are not currently in a party.§r")) {
members.clear();
setPartyID(null);
+ } else if (str.startsWith("§cYou are not in a party!§r")) {
+ members.clear();
+ setPartyID(null);
} else if (str.startsWith("§eParty ") && str.contains(":")) {
String playerNames = TextUtils.stripColor(str.split(":")[1]);
for (String s : playerNames.split(" ")) {
@@ -163,6 +166,8 @@ public class PartyManager implements StompMessageHandler {
RichPresenceManager.INSTANCE.updatePresence();
} else if (str.equals("§cCouldn't find a player with that name!§r")) {
canInvite = true;
+ } else if (str.equals("§cYou cannot invite that player since they're not online.")) {
+ canInvite = true;
} else if (str.endsWith("§aenabled All Invite§r")) {
canInvite = true;
} else if (str.endsWith("§cdisabled All Invite§r")) {
diff --git a/src/main/java/net/arikia/dev/drpc/DiscordEventHandlers.java b/src/main/java/net/arikia/dev/drpc/DiscordEventHandlers.java
new file mode 100644
index 00000000..3e5ccbbd
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/DiscordEventHandlers.java
@@ -0,0 +1,90 @@
+package net.arikia.dev.drpc;
+
+import com.sun.jna.Structure;
+import net.arikia.dev.drpc.callbacks.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Object containing references to all event handlers registered. No callbacks are necessary,
+ * every event handler is optional. Non-assigned handlers are being ignored.
+ */
+public class DiscordEventHandlers extends Structure {
+
+ /**
+ * Callback called when Discord-RPC was initialized successfully.
+ */
+ public ReadyCallback ready;
+ /**
+ * Callback called when the Discord connection was disconnected.
+ */
+ public DisconnectedCallback disconnected;
+ /**
+ * Callback called when a Discord error occurred.
+ */
+ public ErroredCallback errored;
+ /**
+ * Callback called when the player joins the game.
+ */
+ public JoinGameCallback joinGame;
+ /**
+ * Callback called when the player spectates a game.
+ */
+ public SpectateGameCallback spectateGame;
+ /**
+ * Callback called when a join request is received.
+ */
+ public JoinRequestCallback joinRequest;
+
+ @Override
+ public List<String> getFieldOrder() {
+ return Arrays.asList("ready", "disconnected", "errored", "joinGame", "spectateGame", "joinRequest");
+ }
+
+ public static class Builder {
+
+ DiscordEventHandlers h;
+
+ public Builder() {
+ h = new DiscordEventHandlers();
+ }
+
+ public Builder setReadyEventHandler(ReadyCallback r) {
+ h.ready = r;
+ return this;
+ }
+
+ public Builder setDisconnectedEventHandler(DisconnectedCallback d) {
+ h.disconnected = d;
+ return this;
+ }
+
+ public Builder setErroredEventHandler(ErroredCallback e) {
+ h.errored = e;
+ return this;
+ }
+
+ public Builder setJoinGameEventHandler(JoinGameCallback j) {
+ h.joinGame = j;
+ return this;
+ }
+
+ public Builder setSpectateGameEventHandler(SpectateGameCallback s) {
+ h.spectateGame = s;
+ return this;
+ }
+
+ public Builder setJoinRequestEventHandler(JoinRequestCallback j) {
+ h.joinRequest = j;
+ return this;
+ }
+
+ public DiscordEventHandlers build() {
+ return h;
+ }
+ }
+}
diff --git a/src/main/java/net/arikia/dev/drpc/DiscordRPC.java b/src/main/java/net/arikia/dev/drpc/DiscordRPC.java
new file mode 100644
index 00000000..b16974ec
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/DiscordRPC.java
@@ -0,0 +1,234 @@
+package net.arikia.dev.drpc;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+
+import java.io.*;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Java Wrapper of the Discord-RPC Library for Discord Rich Presence.
+ */
+public final class DiscordRPC {
+
+ //DLL-Version for Update Check (soon).
+ private static final String DLL_VERSION = "3.4.0";
+ private static final String LIB_VERSION = "1.6.2";
+
+ static {
+ loadDLL();
+ }
+
+ /**
+ * Method to initialize the Discord-RPC.
+ *
+ * @param applicationId ApplicationID/ClientID
+ * @param handlers EventHandlers
+ * @param autoRegister AutoRegister
+ */
+ public static void discordInitialize(String applicationId, DiscordEventHandlers handlers, boolean autoRegister) {
+ DLL.INSTANCE.Discord_Initialize(applicationId, handlers, autoRegister ? 1 : 0, null);
+ }
+
+ /**
+ * Method to register the executable of the application/game.
+ * Only applicable when autoRegister in discordInitialize is false.
+ *
+ * @param applicationId ApplicationID/ClientID
+ * @param command Launch Command of the application/game.
+ */
+ public static void discordRegister(String applicationId, String command) {
+ DLL.INSTANCE.Discord_Register(applicationId, command);
+ }
+
+ /**
+ * Method to initialize the Discord-RPC within a Steam Application.
+ *
+ * @param applicationId ApplicationID/ClientID
+ * @param handlers EventHandlers
+ * @param autoRegister AutoRegister
+ * @param steamId SteamAppID
+ * @see DiscordEventHandlers
+ */
+ public static void discordInitialize(String applicationId, DiscordEventHandlers handlers, boolean autoRegister, String steamId) {
+ DLL.INSTANCE.Discord_Initialize(applicationId, handlers, autoRegister ? 1 : 0, steamId);
+ }
+
+ /**
+ * Method to register the Steam-Executable of the application/game.
+ * Only applicable when autoRegister in discordInitializeSteam is false.
+ *
+ * @param applicationId ApplicationID/ClientID
+ * @param steamId SteamID of the application/game.
+ */
+ public static void discordRegisterSteam(String applicationId, String steamId) {
+ DLL.INSTANCE.Discord_RegisterSteamGame(applicationId, steamId);
+ }
+
+ /**
+ * Method to update the registered EventHandlers, after the initialization was
+ * already called.
+ *
+ * @param handlers DiscordEventHandler object with updated callbacks.
+ */
+ public static void discordUpdateEventHandlers(DiscordEventHandlers handlers) {
+ DLL.INSTANCE.Discord_UpdateHandlers(handlers);
+ }
+
+ /**
+ * Method to shutdown the Discord-RPC from within the application.
+ */
+ public static void discordShutdown() {
+ DLL.INSTANCE.Discord_Shutdown();
+ }
+
+ /**
+ * Method to call Callbacks from within the library.
+ * Must be called periodically.
+ */
+ public static void discordRunCallbacks() {
+ DLL.INSTANCE.Discord_RunCallbacks();
+ }
+
+ /**
+ * Method to update the DiscordRichPresence of the client.
+ *
+ * @param presence Instance of DiscordRichPresence
+ * @see DiscordRichPresence
+ */
+ public static void discordUpdatePresence(DiscordRichPresence presence) {
+ DLL.INSTANCE.Discord_UpdatePresence(presence);
+ }
+
+ /**
+ * Method to clear(and therefor hide) the DiscordRichPresence until a new
+ * presence is applied.
+ */
+ public static void discordClearPresence() {
+ DLL.INSTANCE.Discord_ClearPresence();
+ }
+
+ /**
+ * Method to respond to Join/Spectate Callback.
+ *
+ * @param userId UserID of the user to respond to.
+ * @param reply DiscordReply to request.
+ * @see DiscordReply
+ */
+ public static void discordRespond(String userId, DiscordReply reply) {
+ DLL.INSTANCE.Discord_Respond(userId, reply.reply);
+ }
+
+ //Load DLL depending on the user's architecture.
+ private static void loadDLL() {
+ String name = System.mapLibraryName("discord-rpc");
+ OSUtil osUtil = new OSUtil();
+ String finalPath;
+ String dir;
+
+ if (osUtil.isMac()) {
+ dir = "darwin";
+ } else if (osUtil.isWindows()) {
+ boolean is64bit = System.getProperty("sun.arch.data.model").equals("64");
+ dir = (is64bit ? "win-x64" : "win-x86");
+ } else {
+ dir = "linux";
+ }
+
+ finalPath = "/" + dir + "/" + name;
+
+ try {
+ File f = File.createTempFile("drpc", name);
+
+ try (InputStream in = DiscordRPC.class.getResourceAsStream(finalPath); OutputStream out = openOutputStream(f)) {
+ copyFile(in, out);
+ f.deleteOnExit();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.load(f.getAbsolutePath());
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void copyFile(final InputStream input, final OutputStream output) throws IOException {
+ byte[] buffer = new byte[1024 * 4];
+ int n;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ }
+ }
+
+ private static FileOutputStream openOutputStream(final File file) throws IOException {
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ throw new IOException("File '" + file + "' exists but is a directory");
+ }
+ if (!file.canWrite()) {
+ throw new IOException("File '" + file + "' cannot be written to");
+ }
+ } else {
+ final File parent = file.getParentFile();
+ if (parent != null) {
+ if (!parent.mkdirs() && !parent.isDirectory()) {
+ throw new IOException("Directory '" + parent + "' could not be created");
+ }
+ }
+ }
+ return new FileOutputStream(file);
+ }
+
+ //------------------------ Taken from apache commons ------------------------------//
+
+ /**
+ * Enum containing reply codes for join request events.
+ *
+ * @see net.arikia.dev.drpc.callbacks.JoinRequestCallback
+ */
+ public enum DiscordReply {
+ /**
+ * Denies the join request immediately.
+ * Currently behaving the same way like DiscordReply.IGNORE.
+ */
+ NO(0),
+ /**
+ * Accepts the join request, requesting player received a JoinGameCallback.
+ *
+ * @see net.arikia.dev.drpc.callbacks.JoinGameCallback
+ */
+ YES(1),
+ /**
+ * Denies the join request by letting it time out(10s).
+ */
+ IGNORE(2);
+
+ /**
+ * Integer reply code send to Discord.
+ */
+ public final int reply;
+
+ DiscordReply(int reply) {
+ this.reply = reply;
+ }
+ }
+
+ //JNA Interface
+ private interface DLL extends Library {
+ //DLL INSTANCE = Native.load("discord-rpc", DLL.class);
+ DLL INSTANCE = Native.loadLibrary("discord-rpc", DLL.class);
+
+ void Discord_Initialize(String applicationId, DiscordEventHandlers handlers, int autoRegister, String optionalSteamId);
+ void Discord_Register(String applicationId, String command);
+ void Discord_RegisterSteamGame(String applicationId, String steamId);
+ void Discord_UpdateHandlers(DiscordEventHandlers handlers);
+ void Discord_Shutdown();
+ void Discord_RunCallbacks();
+ void Discord_UpdatePresence(DiscordRichPresence presence);
+ void Discord_ClearPresence();
+ void Discord_Respond(String userId, int reply);
+ }
+}
diff --git a/src/main/java/net/arikia/dev/drpc/DiscordRichPresence.java b/src/main/java/net/arikia/dev/drpc/DiscordRichPresence.java
new file mode 100644
index 00000000..d45c0a63
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/DiscordRichPresence.java
@@ -0,0 +1,232 @@
+package net.arikia.dev.drpc;
+
+import com.sun.jna.Structure;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ */
+public class DiscordRichPresence extends Structure {
+
+ /**
+ * State of the player's current party.
+ */
+ public String state;
+ /**
+ * Details to the current game-session of the player.
+ */
+ public String details;
+ /**
+ * Unix timestamp for the start of the game
+ */
+ public long startTimestamp;
+ /**
+ * Unix timestamp for when the game will end
+ */
+ public long endTimestamp;
+ /**
+ * Name of the uploaded image for the large profile artwork.
+ */
+ public String largeImageKey;
+ /**
+ * Tooltip for the largeImageKey
+ */
+ public String largeImageText;
+ /**
+ * Name of the uploaded image for the small profile artwork.
+ */
+ public String smallImageKey;
+ /**
+ * Tooltip for the smallImageKey
+ */
+ public String smallImageText;
+ /**
+ * Id of the player's party, lobby, or group.
+ */
+ public String partyId;
+ /**
+ * Current size of the player's party, lobby, or group.
+ */
+ public int partySize;
+ /**
+ * Maximum size of the player's party, lobby, or group.
+ */
+ public int partyMax;
+ /**
+ * Unused.
+ */
+ @Deprecated
+ public String matchSecret;
+ /**
+ * Unique hashed string for Spectate button.
+ */
+ public String spectateSecret;
+ /**
+ * Unique hashed string for chat invitations and Ask to Join.
+ */
+ public String joinSecret;
+ /**
+ * Unused.
+ */
+ @Deprecated
+ public int instance;
+
+ @Override
+ public List<String> getFieldOrder() {
+ return Arrays.asList("state", "details", "startTimestamp", "endTimestamp", "largeImageKey", "largeImageText", "smallImageKey", "smallImageText", "partyId", "partySize", "partyMax", "matchSecret", "spectateSecret", "joinSecret","instance");
+ }
+
+ /*+
+ * Builder object provided to easily assemble DiscordRichPresence objects without having to add a huge assignment Block.
+ * No method is essential, not called methods/unassigned fields are simply ignored and not applied in the final DiscordRichPresence
+ * seen inside the Discord client.
+ */
+ public static class Builder {
+
+ private DiscordRichPresence p;
+
+ /**
+ * Initiates a new instance of the Presence builder.
+ *
+ * @param state String representing the player's current state.
+ * @see DiscordRichPresence
+ */
+ public Builder(String state) {
+ p = new DiscordRichPresence();
+ p.state = state;
+ }
+
+ /**
+ * Sets the details field of the DiscordRichPresence object.
+ *
+ * @param details String representing details to the player's current state.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setDetails(String details) {
+ p.details = details;
+ return this;
+ }
+
+ /**
+ * Sets the starting timestamps of the DiscordRichPresence object, to activate the timer display.
+ *
+ * @param start Long Unix Timestamp representing the starting point of the timer.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setStartTimestamps(long start) {
+ p.startTimestamp = start;
+ return this;
+ }
+
+ /**
+ * Sets the ending timestamps of the DiscordRichPresence object, to activate the timer display.
+ *
+ * @param end Long Unix Timestamp representing the ending point of the timer.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setEndTimestamp(long end) {
+ p.endTimestamp = end;
+ return this;
+ }
+
+ /**
+ * Sets the large image fields of the DiscordRichPresence object. key cannot be null when text is not null.
+ *
+ * @param key String key assigned to the image asset inside of the Discord Application.
+ * @param text String text shown as hover text when hovering over the image of the presence.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setBigImage(String key, String text) {
+ if ((text != null && !text.equalsIgnoreCase("")) && key == null)
+ throw new IllegalArgumentException("Image key must not be null when assigning a hover text.");
+
+ p.largeImageKey = key;
+ p.largeImageText = text;
+ return this;
+ }
+
+ /**
+ * Sets the small image fields of the DiscordRichPresence object. key cannot be null when text is not null.
+ *
+ * @param key String key assigned to the image asset inside of the Discord Application.
+ * @param text String text shown as hover text when hovering over the image of the presence.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setSmallImage(String key, String text) {
+ if ((text != null && !text.equalsIgnoreCase("")) && key == null)
+ throw new IllegalArgumentException("Image key must not be null when assigning a hover text.");
+
+ p.smallImageKey = key;
+ p.smallImageText = text;
+ return this;
+ }
+
+ /**
+ * Sets the party information for the "Party" section of the user's presence.
+ *
+ * @param party Unique String given to the party as identifier.
+ * @param size Integer representing the current size of the user's party.
+ * @param max Integer representing the maximal size of the user's party.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setParty(String party, int size, int max) {
+ p.partyId = party;
+ p.partySize = size;
+ p.partyMax = max;
+ return this;
+ }
+
+ /**
+ * Unused.
+ */
+ @Deprecated
+ public Builder setSecrets(String match, String join, String spectate) {
+ p.matchSecret = match;
+ p.joinSecret = join;
+ p.spectateSecret = spectate;
+ return this;
+ }
+
+ /**
+ * Sets the secret fields of the DiscordRichPresence object.
+ *
+ * @param join Unique String containing necessary information passed to the joining player.
+ * @param spectate Unique String containing necessary information passed to the spectating player.
+ * @return Current Builder object.
+ * @see DiscordRichPresence
+ */
+ public Builder setSecrets(String join, String spectate) {
+ p.joinSecret = join;
+ p.spectateSecret = spectate;
+ return this;
+ }
+
+ /**
+ * Unused.
+ */
+ @Deprecated
+ public Builder setInstance(boolean i) {
+ p.instance = i ? 1 : 0;
+ return this;
+ }
+
+ /**
+ * Returns the fully finished DiscordRichPresence object. Non-assigned fields are being ignored.
+ *
+ * @return The build DiscordRichPresence object.
+ * @see DiscordRichPresence
+ */
+ public DiscordRichPresence build() {
+ return p;
+ }
+ }
+}
diff --git a/src/main/java/net/arikia/dev/drpc/DiscordUser.java b/src/main/java/net/arikia/dev/drpc/DiscordUser.java
new file mode 100644
index 00000000..7c735393
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/DiscordUser.java
@@ -0,0 +1,39 @@
+package net.arikia.dev.drpc;
+
+import com.sun.jna.Structure;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Object containing information about a Discord user.
+ */
+public class DiscordUser extends Structure {
+
+ /**
+ * The userId of the player asking to join.
+ */
+ public String userId;
+ /**
+ * The username of the player asking to join.
+ */
+ public String username;
+ /**
+ * The discriminator of the player asking to join.
+ */
+ public String discriminator;
+ /**
+ * The avatar hash of the player asking to join.
+ *
+ * @see <a href="https://discordapp.com/developers/docs/reference#image-formatting">Image Formatting</a>
+ */
+ public String avatar;
+
+ @Override
+ public List<String> getFieldOrder() {
+ return Arrays.asList("userId", "username", "discriminator", "avatar");
+ }
+} \ No newline at end of file
diff --git a/src/main/java/net/arikia/dev/drpc/OSUtil.java b/src/main/java/net/arikia/dev/drpc/OSUtil.java
new file mode 100644
index 00000000..74ca35c6
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/OSUtil.java
@@ -0,0 +1,25 @@
+package net.arikia.dev.drpc;
+
+/**
+ * @author DeJay
+ * @version 1.6.1
+ * <p>
+ * Class containing utils for detecting the user's OS.
+ */
+public final class OSUtil {
+
+ public boolean isMac() {
+ return getOS().toLowerCase()
+ .startsWith("mac");
+ }
+
+ public boolean isWindows() {
+ return getOS().toLowerCase()
+ .startsWith("win");
+ }
+
+ public String getOS() {
+ return System.getProperty("os.name").toLowerCase();
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/DisconnectedCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/DisconnectedCallback.java
new file mode 100644
index 00000000..ccc11a24
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/DisconnectedCallback.java
@@ -0,0 +1,21 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "DisconnectedCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface DisconnectedCallback extends Callback {
+
+ /**
+ * Method called when disconnected.
+ *
+ * @param errorCode Error code returned on disconnection.
+ * @param message Message containing details about the disconnection.
+ */
+ void apply(int errorCode, String message);
+}
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/ErroredCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/ErroredCallback.java
new file mode 100644
index 00000000..f5d736d7
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/ErroredCallback.java
@@ -0,0 +1,21 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "ErroredCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface ErroredCallback extends Callback {
+
+ /**
+ * Method called when a error occurs.
+ *
+ * @param errorCode Error code returned.
+ * @param message Message containing details about the error.
+ */
+ void apply(int errorCode, String message);
+}
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/JoinGameCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/JoinGameCallback.java
new file mode 100644
index 00000000..c4e865db
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/JoinGameCallback.java
@@ -0,0 +1,20 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "JoinGameCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface JoinGameCallback extends Callback {
+
+ /**
+ * Method called when joining a game.
+ *
+ * @param joinSecret Unique String containing information needed to let the player join.
+ */
+ void apply(String joinSecret);
+}
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/JoinRequestCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/JoinRequestCallback.java
new file mode 100644
index 00000000..ddcc9614
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/JoinRequestCallback.java
@@ -0,0 +1,22 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+import net.arikia.dev.drpc.DiscordUser;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "JoinRequestCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface JoinRequestCallback extends Callback {
+
+ /**
+ * Method called when another player requests to join a game.
+ *
+ * @param request Object containing all required information about the user requesting to join.
+ * @see DiscordUser
+ */
+ void apply(DiscordUser request);
+}
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/ReadyCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/ReadyCallback.java
new file mode 100644
index 00000000..292ce2fd
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/ReadyCallback.java
@@ -0,0 +1,23 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+import net.arikia.dev.drpc.DiscordUser;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "ReadyCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface ReadyCallback extends Callback {
+
+ /**
+ * Method called when the connection to Discord has been established.
+ *
+ * @param user Object containing all required information about the user executing the app.
+ * @see DiscordUser
+ **/
+ void apply(DiscordUser user);
+}
+
diff --git a/src/main/java/net/arikia/dev/drpc/callbacks/SpectateGameCallback.java b/src/main/java/net/arikia/dev/drpc/callbacks/SpectateGameCallback.java
new file mode 100644
index 00000000..28af7329
--- /dev/null
+++ b/src/main/java/net/arikia/dev/drpc/callbacks/SpectateGameCallback.java
@@ -0,0 +1,20 @@
+package net.arikia.dev.drpc.callbacks;
+
+import com.sun.jna.Callback;
+
+/**
+ * @author Nicolas "Vatuu" Adamoglou
+ * @version 1.5.1
+ * <p>
+ * Interface to be implemented in classes that will be registered as "SpectateGameCallback" Event Handler.
+ * @see net.arikia.dev.drpc.DiscordEventHandlers
+ **/
+public interface SpectateGameCallback extends Callback {
+
+ /**
+ * Method called when joining a game.
+ *
+ * @param spectateSecret Unique String containing information needed to let the player spectate.
+ */
+ void apply(String spectateSecret);
+}