Skip to content

Commit ca40bbb

Browse files
authored
Merge pull request #187 from hackclub/nova-shrimpshuffler
Add a task to change the server icon to the Slack icon
2 parents bd0a54f + 27a80d2 commit ca40bbb

File tree

5 files changed

+142
-5
lines changed

5 files changed

+142
-5
lines changed

build.gradle.kts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies {
2525
implementation("org.apache.commons:commons-collections4:4.4")
2626

2727
compileOnly("com.frengor:ultimateadvancementapi:2.2.3")
28-
compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0")
28+
compileOnly("net.dmulloy2:ProtocolLib:5.4.0")
2929
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
3030
compileOnly("com.mojang:brigadier:1.0.18")
3131
}
@@ -59,7 +59,7 @@ tasks {
5959

6060

6161
runServer {
62-
minecraftVersion("1.21")
62+
minecraftVersion("1.21.10")
6363
systemProperty("net.kyori.adventure.text.warnWhenLegacyFormattingDetected", false)
6464
}
6565
}
@@ -73,9 +73,6 @@ repositories {
7373
// NBT-API
7474
maven("https://repo.codemc.org/repository/maven-public/")
7575

76-
// ProtoLib
77-
maven("https://repo.dmulloy2.net/nexus/repository/public/")
78-
7976
// Papermc
8077
maven("https://repo.papermc.io/repository/maven-public/")
8178

src/main/java/com/hackclub/hccore/HCCorePlugin.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
import com.hackclub.hccore.listeners.BeehiveInteractionListener;
4141
import com.hackclub.hccore.listeners.NameChangeListener;
4242
import com.hackclub.hccore.listeners.PlayerListener;
43+
import com.hackclub.hccore.listeners.ServerListPingListener;
4344
import com.hackclub.hccore.slack.SlackBot;
4445
import com.hackclub.hccore.tasks.AutoAFKTask;
46+
import com.hackclub.hccore.tasks.IconTask;
4547
import com.hackclub.hccore.utils.TimeUtil;
4648
import java.util.ArrayList;
4749
import java.util.List;
@@ -56,13 +58,17 @@
5658
import org.bukkit.inventory.ItemStack;
5759
import org.bukkit.inventory.meta.BannerMeta;
5860
import org.bukkit.plugin.java.JavaPlugin;
61+
import org.bukkit.util.CachedServerIcon;
5962

6063
public class HCCorePlugin extends JavaPlugin {
6164

6265
private DataManager dataManager;
6366
private ProtocolManager protocolManager;
6467
private SlackBot bot;
6568

69+
// Server icon from Shrimp Shuffler
70+
public volatile CachedServerIcon serverIcon = null;
71+
6672
@Override
6773
public void onEnable() {
6874
// enable default advancement announcements, should probably leave default, but removes need to re-enable on each server
@@ -119,6 +125,7 @@ public void onEnable() {
119125
this.getServer().getPluginManager().registerEvents(new AFKListener(this), this);
120126
this.getServer().getPluginManager().registerEvents(new BeehiveInteractionListener(), this);
121127
this.getServer().getPluginManager().registerEvents(new PlayerListener(this), this);
128+
this.getServer().getPluginManager().registerEvents(new ServerListPingListener(this), this);
122129

123130
// Register packet listeners
124131
this.getProtocolManager().addPacketListener(
@@ -128,10 +135,14 @@ public void onEnable() {
128135
new AutoAFKTask(this).runTaskTimer(this,
129136
(long) this.getConfig().getInt("settings.auto-afk-time") * TimeUtil.TICKS_PER_SECOND,
130137
30 * TimeUtil.TICKS_PER_SECOND);
138+
getServer().getScheduler().runTaskTimerAsynchronously(this, new IconTask(this), 20, (long) this.getConfig().getInt("settings.icon-change-time") * TimeUtil.TICKS_PER_SECOND);
131139

132140
// Register all the players that were online before this plugin was enabled (example
133141
// scenario: plugin reload) to prevent null pointer errors.
134142
this.getDataManager().registerAll();
143+
144+
// Add the server icon to the variable
145+
serverIcon = getServer().getServerIcon();
135146
}
136147

137148
@Override
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.hackclub.hccore.listeners;
2+
3+
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
4+
import com.hackclub.hccore.HCCorePlugin;
5+
import org.bukkit.event.EventHandler;
6+
import org.bukkit.event.Listener;
7+
8+
public class ServerListPingListener implements Listener {
9+
private final HCCorePlugin plugin;
10+
public ServerListPingListener(HCCorePlugin plugin) {
11+
this.plugin = plugin;
12+
}
13+
@EventHandler
14+
public void serverListPing(PaperServerListPingEvent e) {
15+
if (plugin.serverIcon != null) {
16+
e.setServerIcon(plugin.serverIcon);
17+
}
18+
}
19+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.hackclub.hccore.tasks;
2+
3+
import com.hackclub.hccore.HCCorePlugin;
4+
import java.awt.Graphics2D;
5+
import java.awt.RenderingHints;
6+
import java.awt.image.BufferedImage;
7+
import java.io.ByteArrayInputStream;
8+
import java.io.IOException;
9+
import java.net.URI;
10+
import java.net.http.HttpClient;
11+
import java.net.http.HttpRequest;
12+
import java.net.http.HttpResponse;
13+
import java.time.Duration;
14+
import java.util.logging.Logger;
15+
import javax.imageio.ImageIO;
16+
import org.bukkit.Bukkit;
17+
18+
public class IconTask implements Runnable {
19+
private final HCCorePlugin plugin;
20+
private final HttpClient client;
21+
public IconTask(HCCorePlugin plugin) {
22+
this.plugin = plugin;
23+
this.client = HttpClient.newHttpClient();
24+
}
25+
26+
@Override
27+
public void run() {
28+
Logger logger = plugin.getLogger();
29+
30+
// get the icon url from Shrimp Shuffler
31+
HttpRequest ssRequest = HttpRequest.newBuilder()
32+
.uri(URI.create("https://shrimp-shuffler.a.hackclub.dev/api/current"))
33+
.GET()
34+
.timeout(Duration.ofSeconds(20))
35+
.build();
36+
HttpResponse<String> ssResponse;
37+
try {
38+
ssResponse = client.send(ssRequest, HttpResponse.BodyHandlers.ofString());
39+
} catch (InterruptedException e) {
40+
Thread.currentThread().interrupt();
41+
logger.severe("Failed to get the current icon from Shrimp Shuffler!");
42+
logger.severe(e.getMessage());
43+
return;
44+
} catch (IOException e) {
45+
logger.severe("Failed to get the current icon from Shrimp Shuffler!");
46+
logger.severe(e.getMessage());
47+
return;
48+
}
49+
if (ssResponse == null || ssResponse.body() == null) {
50+
logger.severe("Failed to get the current icon from Shrimp Shuffler!");
51+
return;
52+
}
53+
// load that icon and save to a temp file
54+
HttpRequest cdnRequest = HttpRequest.newBuilder()
55+
.uri(URI.create(ssResponse.body()))
56+
.GET()
57+
.timeout(Duration.ofSeconds(20))
58+
.build();
59+
HttpResponse<byte[]> cdnResponse;
60+
try {
61+
cdnResponse = client.send(cdnRequest, HttpResponse.BodyHandlers.ofByteArray());
62+
} catch (InterruptedException e) {
63+
Thread.currentThread().interrupt();
64+
logger.severe("Failed to get the current icon from the Hack Club CDN!");
65+
logger.severe(e.getMessage());
66+
return;
67+
} catch (IOException e) {
68+
logger.severe("Failed to get the current icon from the Hack Club CDN!");
69+
logger.severe(e.getMessage());
70+
return;
71+
}
72+
// load as a buffered image and cache in plugin
73+
BufferedImage image;
74+
try {
75+
ByteArrayInputStream in = new ByteArrayInputStream(cdnResponse.body());
76+
image = ImageIO.read(in);
77+
} catch (IOException e) {
78+
logger.severe("Failed to load the current icon from the CDN response!");
79+
logger.severe(e.getMessage());
80+
return;
81+
}
82+
if (image == null) {
83+
logger.severe("Failed to load the current icon from the CDN response!");
84+
return;
85+
}
86+
BufferedImage serverIcon = resizeToIcon(image);
87+
Bukkit.getScheduler().runTask(plugin, () -> {
88+
try {
89+
plugin.serverIcon = Bukkit.loadServerIcon(serverIcon);
90+
} catch (Exception e) {
91+
logger.severe("Failed to cache the current icon!");
92+
logger.severe(e.getMessage());
93+
}
94+
});
95+
}
96+
// little resizing method to make it work with minecraft's server list
97+
private static BufferedImage resizeToIcon(BufferedImage original) {
98+
BufferedImage resizedImage = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
99+
Graphics2D graphics = resizedImage.createGraphics();
100+
try {
101+
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
102+
graphics.drawImage(original, 0, 0, 64, 64, null);
103+
} finally {
104+
graphics.dispose();
105+
}
106+
return resizedImage;
107+
}
108+
}

src/main/resources/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ claim-stickers-url: "https://example.com/claim-stickers"
33
settings:
44
# Time in seconds after which a player will be automatically set to AFK
55
auto-afk-time: 600
6+
# Time in seconds between requests are made to the Shrimp Shuffler API to change the server icon.
7+
icon-change-time: 600
68
spawn-command:
79
# Radius extending from the world spawn in which the command can be used
810
allowed-radius: 2000

0 commit comments

Comments
 (0)