feat: Paper plugin + external API POST endpoint

This commit is contained in:
2026-07-13 01:28:33 +08:00
parent ea3cd67e02
commit de5a46f392
9 changed files with 403 additions and 0 deletions

47
mc-report-plugin/pom.xml Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mcreport</groupId>
<artifactId>mc-report-plugin</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,87 @@
package com.mcreport.plugin;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
public class ApiClient {
private final String apiUrl;
private final String externalKey;
private final Gson gson = new Gson();
public ApiClient(String apiUrl, String externalKey) {
this.apiUrl = apiUrl;
this.externalKey = externalKey;
}
public boolean submitTicket(String type, String title, String reporterName, UUID reporterUuid,
String targetName, UUID targetUuid, String reason, String description) {
try {
JsonObject body = new JsonObject();
body.addProperty("type", type);
body.addProperty("title", title);
body.addProperty("reporter_game_name", reporterName);
body.addProperty("reporter_game_uid", reporterUuid != null ? reporterUuid.toString() : "");
if (targetName != null && !targetName.isEmpty()) {
body.addProperty("target_game_name", targetName);
}
if (targetUuid != null) {
body.addProperty("target_game_uid", targetUuid.toString());
}
if (reason != null && !reason.isEmpty()) {
body.addProperty("reason", reason);
}
if (description != null && !description.isEmpty()) {
body.addProperty("description", description);
}
URL url = new URI(apiUrl + "/tickets").toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("x-external-key", externalKey);
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = gson.toJson(body).getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
int code = conn.getResponseCode();
conn.disconnect();
return code == 200 || code == 201;
} catch (Exception e) {
return false;
}
}
public String resolveUuid(String playerName) {
try {
URL url = new URI("https://api.mojang.com/users/profiles/minecraft/" + playerName).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
if (conn.getResponseCode() != 200) {
conn.disconnect();
return null;
}
String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
conn.disconnect();
JsonObject json = gson.fromJson(response, JsonObject.class);
return json != null ? json.get("id").getAsString() : null;
} catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,51 @@
package com.mcreport.plugin;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class AppealCommand implements CommandExecutor {
private final MCReportPlugin plugin;
public AppealCommand(MCReportPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§c仅玩家可使用此命令");
return true;
}
if (args.length == 0) {
sender.sendMessage("§e/appeal <原因> §7- 提交申诉");
return true;
}
String reason = String.join(" ", args);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean ok = plugin.getApiClient().submitTicket(
"appeal",
"游戏内申诉: " + player.getName(),
player.getName(),
player.getUniqueId(),
null, null,
reason,
reason
);
if (ok) {
player.sendMessage("§a申诉已提交请等待处理");
} else {
player.sendMessage("§c提交失败请联系管理员");
}
});
return true;
}
}

View File

@@ -0,0 +1,31 @@
package com.mcreport.plugin;
import org.bukkit.plugin.java.JavaPlugin;
public final class MCReportPlugin extends JavaPlugin {
private ApiClient apiClient;
@Override
public void onEnable() {
saveDefaultConfig();
String apiUrl = getConfig().getString("api_url", "http://localhost:3100/api/external");
String externalKey = getConfig().getString("external_key", "");
apiClient = new ApiClient(apiUrl, externalKey);
getCommand("report").setExecutor(new ReportCommand(this));
getCommand("sugg").setExecutor(new SuggCommand(this));
getCommand("appeal").setExecutor(new AppealCommand(this));
getLogger().info("MC举报系统插件已启用");
}
@Override
public void onDisable() {
getLogger().info("MC举报系统插件已卸载");
}
public ApiClient getApiClient() {
return apiClient;
}
}

View File

@@ -0,0 +1,72 @@
package com.mcreport.plugin;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class ReportCommand implements CommandExecutor {
private final MCReportPlugin plugin;
public ReportCommand(MCReportPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§c仅玩家可使用此命令");
return true;
}
if (args.length == 0) {
sender.sendMessage("§6===== MC举报系统 ======");
sender.sendMessage("§e/report <玩家名> <原因> §7- 举报玩家");
sender.sendMessage("§e/report <原因> §7- 提交事项举报");
sender.sendMessage("§e/sugg <内容> §7- 提交建议");
sender.sendMessage("§e/appeal <原因> §7- 提交申诉");
return true;
}
Player target = Bukkit.getPlayer(args[0]);
String targetName = null;
String targetUuid = null;
int reasonStart = 0;
if (target != null && target.isOnline()) {
targetName = target.getName();
targetUuid = target.getUniqueId().toString();
reasonStart = 1;
}
if (args.length <= reasonStart) {
sender.sendMessage("§c请填写举报原因");
return true;
}
String reason = String.join(" ", java.util.Arrays.copyOfRange(args, reasonStart, args.length));
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean ok = plugin.getApiClient().submitTicket(
"report",
"游戏内举报: " + player.getName(),
player.getName(),
player.getUniqueId(),
targetName,
targetUuid != null ? java.util.UUID.fromString(targetUuid) : null,
reason,
null
);
if (ok) {
player.sendMessage("§a举报已提交工作人员将尽快处理");
} else {
player.sendMessage("§c举报提交失败请联系管理员");
}
});
return true;
}
}

View File

@@ -0,0 +1,50 @@
package com.mcreport.plugin;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SuggCommand implements CommandExecutor {
private final MCReportPlugin plugin;
public SuggCommand(MCReportPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§c仅玩家可使用此命令");
return true;
}
if (args.length == 0) {
sender.sendMessage("§e/sugg <内容> §7- 提交建议");
return true;
}
String content = String.join(" ", args);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean ok = plugin.getApiClient().submitTicket(
"suggestion",
"游戏内建议: " + player.getName(),
player.getName(),
player.getUniqueId(),
null, null, null,
content
);
if (ok) {
player.sendMessage("§a建议已提交感谢反馈");
} else {
player.sendMessage("§c提交失败请联系管理员");
}
});
return true;
}
}

View File

@@ -0,0 +1,5 @@
# MC举报系统 - 插件配置
# API地址 (web服务地址)
api_url: "http://localhost:3100/api/external"
# 外部API密钥 (安装时生成)
external_key: ""

View File

@@ -0,0 +1,25 @@
name: MCReport
version: 1.0.0
main: com.mcreport.plugin.MCReportPlugin
api-version: 1.20
author: Sea-Studio
description: MC举报系统 - 游戏内举报插件
commands:
report:
description: 提交玩家举报
usage: /<command> <玩家名> [原因]
aliases: [jubao,举报]
sugg:
description: 提交建议
usage: /<command> <内容>
aliases: [jianyi,建议]
appeal:
description: 提交申诉
usage: /<command> <原因>
aliases: [shensu,申诉]
permissions:
mcreport.use:
description: 使用举报功能
default: true