Skip to content

Commit 2e029b5

Browse files
authored
Discord Rich Presence (#16)
* Add base for discord rich presence * Update status depending on what you are editing * Remove library files * Add support for chunk grid * Set the discord update thread to a daemon
1 parent 25ca878 commit 2e029b5

File tree

6 files changed

+180
-1
lines changed

6 files changed

+180
-1
lines changed

build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ dependencies {
2222
implementation('com.formdev:flatlaf-extras:2.6')
2323
implementation('com.fifesoft:rsyntaxtextarea:3.3.0')
2424
implementation('com.fifesoft:autocomplete:3.2.0')
25+
implementation('com.github.JnCrMx:discord-game-sdk4j:v0.5.5')
2526

2627
implementation("org.apache.commons:commons-compress:1.21")
2728
implementation('com.google.code.gson:gson:2.10')

src/main/java/com/github/minecraft_ta/totalDebugCompanion/CompanionApp.java

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.github.minecraft_ta.totalDebugCompanion.messages.search.OpenSearchResultsMessage;
1919
import com.github.minecraft_ta.totalDebugCompanion.ui.components.global.SimpleMenuBarBorder;
2020
import com.github.minecraft_ta.totalDebugCompanion.ui.views.MainWindow;
21+
import com.github.minecraft_ta.totalDebugCompanion.util.DiscordRPCManager;
2122
import com.github.minecraft_ta.totalDebugCompanion.util.FileUtils;
2223
import com.github.minecraft_ta.totalDebugCompanion.util.UIUtils;
2324
import com.github.tth05.scnet.IConnectedListener;
@@ -41,6 +42,7 @@
4142
public class CompanionApp {
4243

4344
public static final Server SERVER = new Server();
45+
public static final DiscordRPCManager DISCORD_RPC_MANAGER = new DiscordRPCManager();
4446
private static Path ROOT_PATH;
4547

4648
public static void main(String[] args) {

src/main/java/com/github/minecraft_ta/totalDebugCompanion/ui/components/global/EditorTabs.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ public void removeTabAt(int index) {
5656
public CompletableFuture<Void> openEditorTab(IEditorPanel editorPanel) {
5757
var future = new CompletableFuture<Void>();
5858
SwingUtilities.invokeLater(() -> {
59+
editors.add(editorPanel);
5960
Component component = editorPanel.getComponent();
6061
addTab(editorPanel.getTitle(), component);
6162
int index = indexOfComponent(component);
6263
setToolTipTextAt(index, editorPanel.getTooltip());
6364
setTabComponentAt(index, new LabelWithButtonTabComponent(this, editorPanel.getIcon()));
6465
setSelectedIndex(index);
6566

66-
editors.add(editorPanel);
6767
future.complete(null);
6868
});
6969

@@ -81,4 +81,11 @@ public <T extends IEditorPanel> CompletableFuture<T> focusOrCreateIfAbsent(Class
8181
var tab = supplier.get();
8282
return openEditorTab(tab).thenApply(v -> tab);
8383
}
84+
85+
public IEditorPanel getSelectedEditor() {
86+
if (getSelectedIndex() == -1)
87+
return null;
88+
89+
return editors.get(getSelectedIndex());
90+
}
8491
}

src/main/java/com/github/minecraft_ta/totalDebugCompanion/ui/views/ChunkGridWindow.java

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ public ChunkGridWindow() {
160160
@Override
161161
public void windowClosing(WindowEvent e) {
162162
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new ReceiveDataStateMessage(false));
163+
CompanionApp.DISCORD_RPC_MANAGER.loadLastState();
163164
}
164165
});
165166

@@ -225,6 +226,9 @@ public static void open() {
225226
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new ReceiveDataStateMessage(true));
226227
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new ChunkGridRequestInfoUpdateMessage(INSTANCE.getChunkGridRequestInfo()));
227228
CompanionApp.SERVER.getMessageProcessor().enqueueMessage(new UpdateFollowPlayerStateMessage(UpdateFollowPlayerStateMessage.STATE_ONCE));
229+
230+
CompanionApp.DISCORD_RPC_MANAGER.setState("Chunk Grid", false);
231+
228232
INSTANCE.setVisible(true);
229233
UIUtils.centerJFrame(INSTANCE);
230234
}

src/main/java/com/github/minecraft_ta/totalDebugCompanion/ui/views/MainWindow.java

+21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.github.minecraft_ta.totalDebugCompanion.ui.views;
22

3+
import com.github.minecraft_ta.totalDebugCompanion.CompanionApp;
34
import com.github.minecraft_ta.totalDebugCompanion.Icons;
5+
import com.github.minecraft_ta.totalDebugCompanion.model.CodeView;
46
import com.github.minecraft_ta.totalDebugCompanion.model.PacketLoggerView;
7+
import com.github.minecraft_ta.totalDebugCompanion.model.ScriptView;
58
import com.github.minecraft_ta.totalDebugCompanion.ui.components.global.EditorTabs;
69
import com.github.minecraft_ta.totalDebugCompanion.ui.components.treeView.FileTreeView;
710
import com.github.minecraft_ta.totalDebugCompanion.ui.components.treeView.FileTreeViewHeader;
@@ -32,6 +35,24 @@ private MainWindow() {
3235
root.setDividerLocation(350);
3336
root.setOneTouchExpandable(true);
3437

38+
this.editorTabs.getModel().addChangeListener(e -> {
39+
var selectedEditor = this.editorTabs.getSelectedEditor();
40+
41+
switch (selectedEditor) {
42+
case ScriptView view -> {
43+
String name = view.getPath().getFileName().toString();
44+
CompanionApp.DISCORD_RPC_MANAGER.setState("Editing " + name, true);
45+
}
46+
case CodeView view -> {
47+
String fullName = view.getPath().getFileName().toString().replace(".java", "");
48+
String name = fullName.substring(fullName.lastIndexOf('.') + 1) + ".java";
49+
CompanionApp.DISCORD_RPC_MANAGER.setState("Reading " + name, true);
50+
}
51+
case PacketLoggerView ignored -> CompanionApp.DISCORD_RPC_MANAGER.setState("Packet Logger", true);
52+
case null, default -> CompanionApp.DISCORD_RPC_MANAGER.setState("", true);
53+
}
54+
});
55+
3556
try {
3657
var dividerField = root.getUI().getClass().getSuperclass().getDeclaredField("divider");
3758
dividerField.setAccessible(true);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package com.github.minecraft_ta.totalDebugCompanion.util;
2+
3+
4+
import de.jcm.discordgamesdk.Core;
5+
import de.jcm.discordgamesdk.CreateParams;
6+
import de.jcm.discordgamesdk.activity.Activity;
7+
8+
import java.io.File;
9+
import java.io.IOException;
10+
import java.net.URL;
11+
import java.nio.file.Files;
12+
import java.time.Instant;
13+
import java.util.Locale;
14+
import java.util.zip.ZipEntry;
15+
import java.util.zip.ZipInputStream;
16+
17+
public class DiscordRPCManager {
18+
private Core core;
19+
private Activity activity;
20+
private String lastActivity = "";
21+
private boolean enabled = true;
22+
23+
public DiscordRPCManager() {
24+
try {
25+
File discordLibrary = downloadDiscordLibrary();
26+
Core.init(discordLibrary);
27+
} catch (IOException e) {
28+
this.enabled = false;
29+
System.err.println("Failed to download Discord Game SDK: ");
30+
e.printStackTrace();
31+
return;
32+
}
33+
34+
try (CreateParams params = new CreateParams()) {
35+
params.setClientID(1116710018369204286L);
36+
params.setFlags(CreateParams.getDefaultFlags());
37+
this.core = new Core(params);
38+
}
39+
40+
this.activity = new Activity();
41+
this.activity.timestamps().setStart(Instant.now());
42+
this.activity.assets().setLargeImage("default");
43+
updateActivity();
44+
45+
Thread callbackThread = new Thread(() -> {
46+
while (true) {
47+
core.runCallbacks();
48+
try {
49+
Thread.sleep(16);
50+
} catch (InterruptedException e) {
51+
e.printStackTrace();
52+
}
53+
}
54+
});
55+
callbackThread.setDaemon(true);
56+
callbackThread.start();
57+
}
58+
59+
private static File downloadDiscordLibrary() throws IOException {
60+
File tempDir = new File(System.getProperty("java.io.tmpdir"), "total_debug_discord_game_sdk");
61+
62+
// Find out which name Discord's library has (.dll for Windows, .so for Linux)
63+
String name = "discord_game_sdk";
64+
String suffix;
65+
66+
String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT);
67+
String arch = System.getProperty("os.arch").toLowerCase(Locale.ROOT);
68+
69+
if (osName.contains("windows")) {
70+
suffix = ".dll";
71+
} else if (osName.contains("linux")) {
72+
suffix = ".so";
73+
} else if (osName.contains("mac os")) {
74+
suffix = ".dylib";
75+
} else {
76+
throw new RuntimeException("cannot determine OS type: " + osName);
77+
}
78+
79+
/*
80+
Some systems report "amd64" (e.g. Windows and Linux), some "x86_64" (e.g. Mac OS).
81+
At this point we need the "x86_64" version, as this one is used in the ZIP.
82+
*/
83+
if (arch.equals("amd64"))
84+
arch = "x86_64";
85+
86+
// Path of Discord's library inside the ZIP
87+
String zipPath = "lib/" + arch + "/" + name + suffix;
88+
89+
// Return the file if it already exists
90+
File file = new File(tempDir, name + suffix);
91+
if (file.exists())
92+
return file;
93+
94+
// Open the URL as a ZipInputStream
95+
URL downloadUrl = new URL("https://dl-game-sdk.discordapp.net/2.5.6/discord_game_sdk.zip");
96+
ZipInputStream zin = new ZipInputStream(downloadUrl.openStream());
97+
98+
// Search for the right file inside the ZIP
99+
ZipEntry entry;
100+
while ((entry = zin.getNextEntry()) != null) {
101+
if (entry.getName().equals(zipPath)) {
102+
// Create a new temporary directory
103+
// We need to do this, because we may not change the filename on Windows
104+
if (!tempDir.mkdir())
105+
throw new IOException("Cannot create temporary directory");
106+
107+
File temp = new File(tempDir, name + suffix);
108+
109+
Files.copy(zin, temp.toPath());
110+
111+
zin.close();
112+
113+
return temp;
114+
}
115+
zin.closeEntry();
116+
}
117+
zin.close();
118+
return null;
119+
}
120+
121+
public void setDetails(String details) {
122+
if (!enabled) return;
123+
activity.setDetails(details);
124+
updateActivity();
125+
}
126+
127+
public void setState(String state, boolean saveLastState) {
128+
if (!enabled) return;
129+
if (saveLastState) this.lastActivity = state;
130+
activity.setState(state);
131+
updateActivity();
132+
}
133+
134+
public void loadLastState() {
135+
if (!enabled) return;
136+
activity.setState(lastActivity);
137+
updateActivity();
138+
}
139+
140+
private void updateActivity() {
141+
if (!enabled) return;
142+
core.activityManager().updateActivity(activity);
143+
}
144+
}

0 commit comments

Comments
 (0)