First build
This commit is contained in:
36
README.md
36
README.md
@@ -1,2 +1,36 @@
|
|||||||
# smartcraft-notifier
|
# SmartCraft Notifier
|
||||||
|
|
||||||
|
A lightweight Paper plugin that sends player events (join, leave, server switch, and advancements) to a Gotify server via HTTP notifications. Designed for Minecraft 1.19+ networks using BungeeCord or standalone setups.
|
||||||
|
|
||||||
|
## 🧰 Features
|
||||||
|
|
||||||
|
- Optional BungeeCord integration via Plugin Messaging Channel
|
||||||
|
- Detects player join/leave and advancement events
|
||||||
|
- Sends customizable notifications to Gotify servers
|
||||||
|
- Configurable via `config.yml` (no in-game commands except `/gotifystatus`)
|
||||||
|
- Console/log alert if Gotify connection fails at startup
|
||||||
|
|
||||||
|
## ⚙️ Requirements
|
||||||
|
|
||||||
|
- Minecraft Paper server 1.19+
|
||||||
|
- Java 17+
|
||||||
|
- [Gotify](https://gotify.net/) server for receiving notifications
|
||||||
|
- If using BungeeCord, set `bungeecord: true` in `spigot.yml` and enable the flag in the plugin config
|
||||||
|
|
||||||
|
## 🔧 Build Instructions
|
||||||
|
|
||||||
|
1. Install [Apache Maven](https://maven.apache.org/)
|
||||||
|
2. Run `build.bat` (Windows) or `mvn clean package` (Linux/macOS)
|
||||||
|
3. Your compiled plugin will be at `target/SmartCraftNotifier.jar`
|
||||||
|
|
||||||
|
## 🚀 Usage
|
||||||
|
|
||||||
|
- Drop the plugin into your server’s `plugins/` folder
|
||||||
|
- Edit `config.yml` to set your Gotify server URL, app token, and feature toggles
|
||||||
|
- Restart your server to generate logs or test with `/gotifystatus`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🧠 Inspired by the idea of keeping server owners effortlessly informed.
|
||||||
|
|
||||||
|
*Built with care by Eric’s Copilot.*
|
14
build.bat
Normal file
14
build.bat
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
echo Building SmartCraft Notifier...
|
||||||
|
|
||||||
|
REM Run Maven clean & package
|
||||||
|
mvn clean package
|
||||||
|
|
||||||
|
IF %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo Build failed! Check errors above.
|
||||||
|
pause
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Build completed! Check the 'target' folder for your .jar
|
||||||
|
pause
|
59
pom.xml
Normal file
59
pom.xml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.smartcraft.notifier</groupId>
|
||||||
|
<artifactId>SmartCraftNotifier</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>SmartCraftNotifier</name>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.10.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.3.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.smartcraft.notifier.SmartCraftNotifier</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.20-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>4.12.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@@ -0,0 +1,23 @@
|
|||||||
|
package com.smartcraft.notifier;
|
||||||
|
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerAdvancementDoneEvent;
|
||||||
|
|
||||||
|
public class AdvancementListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onAdvancement(PlayerAdvancementDoneEvent event) {
|
||||||
|
String advancementKey = event.getAdvancement().getKey().getKey();
|
||||||
|
String playerName = event.getPlayer().getName();
|
||||||
|
|
||||||
|
// Filter out root advancements or hidden criteria
|
||||||
|
if (advancementKey.contains("root") || advancementKey.contains("recipes")) return;
|
||||||
|
|
||||||
|
SmartCraftNotifier.instance.getGotifyClient().sendMessage(
|
||||||
|
"📜 Advancement Unlocked!",
|
||||||
|
playerName + " has earned: " + advancementKey,
|
||||||
|
5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
package com.smartcraft.notifier;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BungeeMessageListener implements PluginMessageListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
||||||
|
if (!channel.equals("BungeeCord")) return;
|
||||||
|
|
||||||
|
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
|
||||||
|
String subChannel = in.readUTF();
|
||||||
|
|
||||||
|
if (subChannel.equals("PlayerJoin")) {
|
||||||
|
String joinedPlayer = in.readUTF();
|
||||||
|
SmartCraftNotifier.instance.getGotifyClient().sendMessage(
|
||||||
|
"👤 Player Joined",
|
||||||
|
joinedPlayer + " connected to the network.",
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (subChannel.equals("PlayerQuit")) {
|
||||||
|
String leftPlayer = in.readUTF();
|
||||||
|
SmartCraftNotifier.instance.getGotifyClient().sendMessage(
|
||||||
|
"🚪 Player Left",
|
||||||
|
leftPlayer + " disconnected from the network.",
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (subChannel.equals("ServerSwitch")) {
|
||||||
|
String playerName = in.readUTF();
|
||||||
|
String fromServer = in.readUTF();
|
||||||
|
String toServer = in.readUTF();
|
||||||
|
SmartCraftNotifier.instance.getGotifyClient().sendMessage(
|
||||||
|
"🔁 Server Switch",
|
||||||
|
playerName + " switched from " + fromServer + " to " + toServer,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().warning("[SmartCraftNotifier] Failed to parse BungeeCord message: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
src/main/java/com/smartcraft/notifier/GotifyClient.java
Normal file
75
src/main/java/com/smartcraft/notifier/GotifyClient.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package com.smartcraft.notifier;
|
||||||
|
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GotifyClient {
|
||||||
|
|
||||||
|
private final String serverUrl;
|
||||||
|
private final String appToken;
|
||||||
|
private final boolean enabled;
|
||||||
|
private final OkHttpClient http;
|
||||||
|
|
||||||
|
public GotifyClient(FileConfiguration config) {
|
||||||
|
this.enabled = config.getBoolean("gotify.enabled", false);
|
||||||
|
this.serverUrl = config.getString("gotify.serverUrl", "").trim();
|
||||||
|
this.appToken = config.getString("gotify.appToken", "").trim();
|
||||||
|
this.http = new OkHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReady() {
|
||||||
|
return enabled && !serverUrl.isEmpty() && !appToken.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(String title, String message, int priority) {
|
||||||
|
if (!isReady()) return;
|
||||||
|
|
||||||
|
HttpUrl url = HttpUrl.parse(serverUrl + "/message");
|
||||||
|
if (url == null) return;
|
||||||
|
|
||||||
|
RequestBody body = new FormBody.Builder()
|
||||||
|
.add("title", title)
|
||||||
|
.add("message", message)
|
||||||
|
.add("priority", String.valueOf(priority))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.addHeader("X-Gotify-Key", appToken)
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
http.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
Bukkit.getLogger().warning("[SmartCraftNotifier] Failed to send Gotify message: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean pingServer() {
|
||||||
|
if (!isReady()) return false;
|
||||||
|
|
||||||
|
HttpUrl url = HttpUrl.parse(serverUrl + "/application");
|
||||||
|
if (url == null) return false;
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.addHeader("X-Gotify-Key", appToken)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = http.newCall(request).execute()) {
|
||||||
|
return response.isSuccessful();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,59 @@
|
|||||||
|
package com.smartcraft.notifier;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.plugin.messaging.Messenger;
|
||||||
|
|
||||||
|
public class SmartCraftNotifier extends JavaPlugin {
|
||||||
|
|
||||||
|
public static SmartCraftNotifier instance;
|
||||||
|
private GotifyClient gotifyClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
saveDefaultConfig();
|
||||||
|
FileConfiguration config = getConfig();
|
||||||
|
|
||||||
|
this.gotifyClient = new GotifyClient(config);
|
||||||
|
|
||||||
|
if (!gotifyClient.isReady()) {
|
||||||
|
getLogger().warning("Gotify is not properly configured. Notifications will not be sent.");
|
||||||
|
} else {
|
||||||
|
getLogger().info("Gotify is ready to send messages.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
if (config.getBoolean("events.logAdvancements", true)) {
|
||||||
|
getServer().getPluginManager().registerEvents(new AdvancementListener(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BungeeCord plugin messaging setup
|
||||||
|
if (config.getBoolean("bungeecord", false)) {
|
||||||
|
Messenger messenger = getServer().getMessenger();
|
||||||
|
messenger.registerOutgoingPluginChannel(this, "BungeeCord");
|
||||||
|
messenger.registerIncomingPluginChannel(this, "BungeeCord", new BungeeMessageListener());
|
||||||
|
getLogger().info("BungeeCord messaging enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register command
|
||||||
|
getCommand("gotifystatus").setExecutor((sender, command, label, args) -> {
|
||||||
|
boolean result = gotifyClient.pingServer();
|
||||||
|
sender.sendMessage("Gotify status: " + (result ? "✅ Online" : "❌ Unreachable"));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
getLogger().info("SmartCraft Notifier has been enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
getLogger().info("SmartCraft Notifier has been disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public GotifyClient getGotifyClient() {
|
||||||
|
return gotifyClient;
|
||||||
|
}
|
||||||
|
}
|
12
src/main/resources/config.yml
Normal file
12
src/main/resources/config.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
bungeecord: false
|
||||||
|
|
||||||
|
gotify:
|
||||||
|
enabled: true
|
||||||
|
serverUrl: "https://your.gotify.server"
|
||||||
|
appToken: "YOUR_SECRET_TOKEN"
|
||||||
|
|
||||||
|
events:
|
||||||
|
logJoins: true
|
||||||
|
logLeaves: true
|
||||||
|
logServerSwitch: true
|
||||||
|
logAdvancements: true
|
14
src/main/resources/plugin.yml
Normal file
14
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: SmartCraftNotifier
|
||||||
|
version: 1.0.0
|
||||||
|
main: com.smartcraft.notifier.SmartCraftNotifier
|
||||||
|
api-version: 1.20
|
||||||
|
description: Sends player events to Gotify and supports optional BungeeCord messaging.
|
||||||
|
commands:
|
||||||
|
gotifystatus:
|
||||||
|
description: Check if Gotify is reachable.
|
||||||
|
usage: /gotifystatus
|
||||||
|
permission: smartcraftnotifier.status
|
||||||
|
permissions:
|
||||||
|
smartcraftnotifier.status:
|
||||||
|
description: Allows use of /gotifystatus command
|
||||||
|
default: op
|
Reference in New Issue
Block a user