删除无用的旧版代码

This commit is contained in:
Xujiayao 2022-03-24 22:43:05 +08:00
parent f7e2d390a6
commit 898f0ead28
23 changed files with 11 additions and 1133 deletions

View file

@ -10,47 +10,11 @@ public class Config {
public Generic generic = new Generic();
public MultiServer multiServer = new MultiServer();
public TextsZH textsZH = new TextsZH();
public TextsEN textsEN = new TextsEN();
public static class Generic {
// [Required] Language MCDiscordChat uses
// (Chinese if true, English if false)
public boolean switchLanguageFromChinToEng = true;
// [Required] Discord bot token
public String botToken = "MCDiscordChat Docs: https://blog.xujiayao.top/posts/4ba0a17a/";
// [Optional] Discord bot activity status
// (null when empty)
public String botListeningStatus = "";
// [Required] Webhook URL
public String webhookURL = "";
// [Required] Discord Channel ID
// (right-click the channel to copy the ID, you have to turn on developer mode in Discord settings)
public String channelId = "";
// [Optional] Discord Channel ID for Console Log Broadcast
// (leave blank to disable this feature)
// (the method to get the ID is the same)
public String consoleLogChannelId = "";
// [Required] Server world name
public String worldName = "world";
// [Required] URL of the Avatar API for Webhook
// (example: 2D: https://mc-heads.net/avatar/%player%.png 3D: https://visage.surgeplay.com/bust/%player%.png)
public String avatarAPI = "https://visage.surgeplay.com/bust/%player%.png";
// [Required] Modify in-game chat messages
// (not enable or disable MCDiscordChat)
public boolean modifyChatMessages = true;
// [Required] Broadcast player command execution
public boolean broadcastCommandExecution = true;
// [Required] Use more than two MCDiscordChat in one Discord channel
// (name of the bot must be in the following format: [%serverDisplayName%] %botName%)
public boolean multiServer = false;
@ -58,37 +22,12 @@ public class Config {
// [Required] Use UUID instead nickname to request player head on Webhook
public boolean useUUIDInsteadNickname = true;
// [Required] Enable in-game mentions (@) Discord users
public boolean membersIntents = true;
// [Required] Announce when a player join / leave the server
public boolean announcePlayers = true;
// [Required] Announce when a player reached a progress / achieved a goal / completed a challenge
public boolean announceAdvancements = true;
// [Required] Announce when a player die
public boolean announceDeaths = true;
// [Required] Announce when Server MSPT is above MSPT Limit
public boolean announceHighMSPT = true;
// [Required] Server MSPT Limit
public int msptLimit = 50;
// [Required] Replaces the § symbol with & in any discord message to avoid formatted messages
public boolean removeVanillaFormattingFromDiscord = false;
// [Required] Removes line break from any discord message to avoid spam
public boolean removeLineBreakFromDiscord = false;
// [Required] Discord bot command prefix
public String botCommandPrefix = "!";
// [Optional] MCDiscordChat Excluded Commands List, do not process and send specified commands
// (can have more than one)
public List<String> excludedCommands = List.of("/tell");
// [Required] MCDiscordChat Super Admin ID List, has permission to add and remove admins, and have all permissions admins have
// (can have more than one)
public List<String> superAdminsIds = new ArrayList<>();
@ -114,73 +53,4 @@ public class Config {
// (example: when the name of the bot is '[SMP] MCDC Bot', set it to 'MCDC Bot')
public String botName = "MCDC Bot";
}
public static class TextsZH {
// Placeholders Description
// ------------------------------
// %playername% Name of a Minecraft player
// %deathmessage% Death message
// %advancement% Progress / goal / challenge name
// %servername% 'Discord' (becomes server name when using multi-server mode)
// %name% Nickname of a user in Discord (becomes player name when using multi-server mode)
// %message% Content of message
// %mspt% Server MSPT
// %msptLimit% Server MSPT Limit
// %timestamp% Current timestamp
public String serverStarted = "**服务器已启动!**";
public String serverStopped = "**服务器已关闭!**";
public String joinServer = "**%playername% 加入了服务器**";
public String leftServer = "**%playername% 离开了服务器**";
public String deathMessage = "**%deathmessage%**";
public String advancementTask = "**%playername% 达成了进度 [%advancement%]**";
public String advancementChallenge = "**%playername% 完成了挑战 [%advancement%]**";
public String advancementGoal = "**%playername% 达成了目标 [%advancement%]**";
public String highMSPT = "**服务器 MSPT (%mspt%) 高于 %msptLimit%**";
public String consoleLogMessage = "**[%timestamp%] [INFO]:** %message%";
public String blueColoredText = "[%servername%] ";
public String roleColoredText = "<%name%>";
public String colorlessText = " %message%";
}
public static class TextsEN {
// Placeholders Description
// ------------------------------
// %playername% Name of a Minecraft player
// %deathmessage% Death message
// %advancement% Progress / goal / challenge name
// %servername% 'Discord' (becomes server name when using multi-server mode)
// %name% Nickname of a user in Discord (becomes player name when using multi-server mode)
// %message% Content of message
// %mspt% Server MSPT
// %msptLimit% Server MSPT Limit
// %timestamp% Current timestamp
public String serverStarted = "**Server started!**";
public String serverStopped = "**Server stopped!**";
public String joinServer = "**%playername% joined the game**";
public String leftServer = "**%playername% left the game**";
public String deathMessage = "**%deathmessage%**";
public String advancementTask = "**%playername% has made the advancement [%advancement%]**";
public String advancementChallenge = "**%playername% has completed the challenge [%advancement%]**";
public String advancementGoal = "**%playername% has reached the goal [%advancement%]**";
public String highMSPT = "**Server MSPT (%mspt%) is above %msptLimit%!**";
public String consoleLogMessage = "**[%timestamp%] [INFO]:** %message%";
public String blueColoredText = "[%servername%] ";
public String roleColoredText = "<%name%>";
public String colorlessText = " %message%";
}
}

View file

@ -10,8 +10,6 @@ import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import okhttp3.OkHttpClient;
import top.xujiayao.mcdiscordchat.listeners.DiscordEventListener;
import top.xujiayao.mcdiscordchat.listeners.MinecraftEventListener;
import top.xujiayao.mcdiscordchat.objects.Texts;
import top.xujiayao.mcdiscordchat.utils.ConfigManager;
import top.xujiayao.mcdiscordchat.utils.Utils;
@ -28,89 +26,24 @@ public class Main implements DedicatedServerModInitializer {
public static TextChannel textChannel;
public static TextChannel consoleLogTextChannel;
public static Config config;
public static Texts texts;
public static boolean stop = false;
public static Timer msptMonitorTimer;
public static Timer consoleLogTimer1;
public static Timer consoleLogTimer2;
@Override
public void onInitializeServer() {
ConfigManager.initConfig();
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
if (config.generic.announceHighMSPT) {
msptMonitorTimer = new Timer();
Utils.monitorMSPT();
}
});
try {
if (config.generic.membersIntents) {
jda = JDABuilder.createDefault(config.generic.botToken)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.addEventListeners(new DiscordEventListener())
.build();
} else {
jda = JDABuilder.createDefault(config.generic.botToken)
.addEventListeners(new DiscordEventListener())
.build();
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
if (config.generic.announceHighMSPT) {
msptMonitorTimer.cancel();
}
jda.awaitReady();
textChannel = jda.getTextChannelById(config.generic.channelId);
if (!config.generic.consoleLogChannelId.isEmpty()) {
consoleLogTextChannel = jda.getTextChannelById(config.generic.consoleLogChannelId);
}
} catch (Exception e) {
e.printStackTrace();
jda = null;
Thread.currentThread().interrupt();
}
if (jda != null) {
if (!config.generic.botListeningStatus.isEmpty()) {
jda.getPresence().setActivity(Activity.listening(config.generic.botListeningStatus));
}
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
textChannel.sendMessage(texts.serverStarted()).queue();
Utils.checkUpdate(false);
if (config.generic.announceHighMSPT) {
msptMonitorTimer = new Timer();
Utils.monitorMSPT();
}
});
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
stop = true;
textChannel.sendMessage(texts.serverStopped()).queue();
if (config.generic.announceHighMSPT) {
msptMonitorTimer.cancel();
}
if (!config.generic.consoleLogChannelId.isEmpty()) {
consoleLogTimer1.cancel();
consoleLogTimer2.cancel();
}
try {
Thread.sleep(250);
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
jda.shutdown();
try {
Thread.sleep(250);
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
});
new MinecraftEventListener().init();
}
jda.shutdown();
});
}
}

View file

@ -1,20 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.command.ServerCommandSource;
/**
* @author Xujiayao
*/
public interface CommandExecutionCallback {
Event<CommandExecutionCallback> EVENT = EventFactory.createArrayBacked(CommandExecutionCallback.class,
callbacks -> (command, source) -> {
for (CommandExecutionCallback callback : callbacks) {
callback.onExecuted(command, source);
}
});
void onExecuted(String command, ServerCommandSource source);
}

View file

@ -1,21 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.advancement.Advancement;
import net.minecraft.server.network.ServerPlayerEntity;
/**
* @author Xujiayao
*/
public interface PlayerAdvancementCallback {
Event<PlayerAdvancementCallback> EVENT = EventFactory.createArrayBacked(PlayerAdvancementCallback.class,
callbacks -> (playerEntity, advancement) -> {
for (PlayerAdvancementCallback callback : callbacks) {
callback.onPlayerAdvancement(playerEntity, advancement);
}
});
void onPlayerAdvancement(ServerPlayerEntity playerEntity, Advancement advancement);
}

View file

@ -1,21 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.network.ServerPlayerEntity;
/**
* @author Xujiayao
*/
public interface PlayerDeathCallback {
Event<PlayerDeathCallback> EVENT = EventFactory.createArrayBacked(PlayerDeathCallback.class,
callbacks -> (playerEntity, damageSource) -> {
for (PlayerDeathCallback callback : callbacks) {
callback.onPlayerDeath(playerEntity, damageSource);
}
});
void onPlayerDeath(ServerPlayerEntity playerEntity, DamageSource damageSource);
}

View file

@ -1,21 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.network.ServerPlayerEntity;
/**
* @author Xujiayao
*/
public interface PlayerJoinCallback {
Event<PlayerJoinCallback> EVENT = EventFactory.createArrayBacked(PlayerJoinCallback.class,
callbacks -> (connection, playerEntity) -> {
for (PlayerJoinCallback callback : callbacks) {
callback.onJoin(connection, playerEntity);
}
});
void onJoin(ClientConnection connection, ServerPlayerEntity playerEntity);
}

View file

@ -1,20 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.network.ServerPlayerEntity;
/**
* @author Xujiayao
*/
public interface PlayerLeaveCallback {
Event<PlayerLeaveCallback> EVENT = EventFactory.createArrayBacked(PlayerLeaveCallback.class,
callbacks -> playerEntity -> {
for (PlayerLeaveCallback callback : callbacks) {
callback.onLeave(playerEntity);
}
});
void onLeave(ServerPlayerEntity playerEntity);
}

View file

@ -1,28 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.Optional;
/**
* @author Xujiayao
*/
public interface ServerChatCallback {
Event<ServerChatCallback> EVENT = EventFactory.createArrayBacked(ServerChatCallback.class,
callbacks -> (playerEntity, rawMessage, message) -> {
Optional<Text> msg = Optional.empty();
for (ServerChatCallback callback : callbacks) {
Optional<Text> callbackResult = callback.onServerChat(playerEntity, rawMessage, message);
if (callbackResult.isPresent()) {
msg = callbackResult;
}
}
return msg;
});
Optional<Text> onServerChat(ServerPlayerEntity playerEntity, String rawMessage, Text message);
}

View file

@ -1,19 +0,0 @@
package top.xujiayao.mcdiscordchat.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
/**
* @author Xujiayao
*/
public interface SystemMessageCallback {
Event<SystemMessageCallback> EVENT = EventFactory.createArrayBacked(SystemMessageCallback.class,
callbacks -> (message) -> {
for (SystemMessageCallback callback : callbacks) {
callback.onSystemMessage(message);
}
});
void onSystemMessage(String message);
}

View file

@ -1,264 +0,0 @@
package top.xujiayao.mcdiscordchat.listeners;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.utils.MarkdownSanitizer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.Pair;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONObject;
import top.xujiayao.mcdiscordchat.Main;
import top.xujiayao.mcdiscordchat.events.CommandExecutionCallback;
import top.xujiayao.mcdiscordchat.events.PlayerAdvancementCallback;
import top.xujiayao.mcdiscordchat.events.PlayerDeathCallback;
import top.xujiayao.mcdiscordchat.events.PlayerJoinCallback;
import top.xujiayao.mcdiscordchat.events.PlayerLeaveCallback;
import top.xujiayao.mcdiscordchat.events.ServerChatCallback;
import top.xujiayao.mcdiscordchat.events.SystemMessageCallback;
import top.xujiayao.mcdiscordchat.utils.MarkdownParser;
import top.xujiayao.mcdiscordchat.utils.Utils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import static top.xujiayao.mcdiscordchat.Main.client;
import static top.xujiayao.mcdiscordchat.Main.config;
import static top.xujiayao.mcdiscordchat.Main.consoleLogTextChannel;
import static top.xujiayao.mcdiscordchat.Main.consoleLogTimer1;
import static top.xujiayao.mcdiscordchat.Main.consoleLogTimer2;
import static top.xujiayao.mcdiscordchat.Main.textChannel;
/**
* @author Xujiayao
*/
public class MinecraftEventListener {
private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public static int consoleLogSentTimes = 0;
long lastTime = System.currentTimeMillis();
String lastPlayer = "";
public void init() {
ServerChatCallback.EVENT.register((playerEntity, rawMessage, message) -> {
if (!Main.stop) {
try {
if (StringUtils.countMatches(rawMessage, ":") >= 2) {
String[] emoteNames = StringUtils.substringsBetween(rawMessage, ":", ":");
for (String emoteName : emoteNames) {
List<Emote> emotes = Main.jda.getEmotesByName(emoteName, true);
if (!emotes.isEmpty()) {
rawMessage = RegExUtils.replaceFirst(rawMessage, ":" + emoteName + ":", "<:" + emoteName + ":" + emotes.get(0).getId() + ">");
}
}
}
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
Pair<String, String> convertedPair = Utils.convertMentionsFromNames(rawMessage);
if (config.generic.bannedMinecraft.contains(playerEntity.getEntityName())) {
return Optional.empty();
}
JSONObject body = new JSONObject();
body.put("username", (config.generic.multiServer ? "[" + config.multiServer.serverDisplayName + "] " + playerEntity.getEntityName() : playerEntity.getEntityName()));
body.put("avatar_url", config.generic.avatarAPI.replace("%player%", (config.generic.useUUIDInsteadNickname ? playerEntity.getUuid().toString() : playerEntity.getEntityName())));
JSONObject allowedMentions = new JSONObject();
allowedMentions.put("parse", new String[]{"users", "roles"});
body.put("allowed_mentions", allowedMentions);
body.put("content", convertedPair.getLeft().replace("_", "\\_"));
try {
Request request = new Request.Builder()
.url(config.generic.webhookURL)
.post(RequestBody.create(body.toString(), MediaType.get("application/json")))
.build();
client.newCall(request).execute();
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
if (config.generic.modifyChatMessages) {
String jsonString = Text.Serializer.toJson(message);
JSONObject newComponent = new JSONObject(jsonString);
if (convertedPair.getRight().startsWith("!!")) {
newComponent.getJSONArray("with").put(1, convertedPair.getRight());
} else {
newComponent.getJSONArray("with").put(1, MarkdownParser.parseMarkdown(convertedPair.getRight()));
}
Text finalText = Text.Serializer.fromJson(newComponent.toString());
return Optional.ofNullable(finalText);
}
}
return Optional.empty();
});
CommandExecutionCallback.EVENT.register((command, source) -> {
if (!Main.stop && config.generic.broadcastCommandExecution) {
try {
String temp = command;
if (temp.contains(" ")) {
temp = temp.substring(0, temp.indexOf(" "));
}
if (config.generic.excludedCommands.contains(temp)) {
return;
}
if (config.generic.bannedMinecraft.contains(source.getPlayer().getEntityName())) {
return;
}
if (source.getPlayer().getEntityName().equals(lastPlayer)
&& (System.currentTimeMillis() - lastTime) < 100) {
return;
}
lastTime = System.currentTimeMillis();
lastPlayer = source.getPlayer().getEntityName();
JSONObject body = new JSONObject();
body.put("username", (config.generic.multiServer ? "[" + config.multiServer.serverDisplayName + "] " + source.getPlayer().getEntityName() : source.getPlayer().getEntityName()));
body.put("avatar_url", config.generic.avatarAPI.replace("%player%", (config.generic.useUUIDInsteadNickname ? source.getPlayer().getUuid().toString() : source.getPlayer().getEntityName())));
JSONObject allowedMentions = new JSONObject();
allowedMentions.put("parse", new String[]{"users", "roles"});
body.put("allowed_mentions", allowedMentions);
body.put("content", command.replace("_", "\\_"));
Request request = new Request.Builder()
.url(config.generic.webhookURL)
.post(RequestBody.create(body.toString(), MediaType.get("application/json")))
.build();
client.newCall(request).execute();
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
try {
List<ServerPlayerEntity> list = new ArrayList<>(Objects.requireNonNull(Utils.getServer()).getPlayerManager().getPlayerList());
list.remove(source.getPlayer());
list.forEach(
serverPlayerEntity -> {
try {
serverPlayerEntity.sendMessage(new LiteralText("<").append(source.getPlayer().getEntityName()).append("> ").append(command), false);
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
});
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
}
});
if (!config.generic.consoleLogChannelId.isEmpty()) {
consoleLogTimer1 = new Timer();
consoleLogTimer2 = new Timer();
consoleLogTimer1.schedule(new TimerTask() {
@Override
public void run() {
consoleLogSentTimes = 0;
}
}, 0, 30000);
}
SystemMessageCallback.EVENT.register((message) -> {
if (!Main.stop && !config.generic.consoleLogChannelId.isEmpty()) {
try {
consoleLogSentTimes++;
if (consoleLogSentTimes > 10) {
return;
}
consoleLogTextChannel.sendMessage(Main.texts.consoleLogMessage()
.replace("%timestamp%", sdf.format(new Date()))
.replace("%message%", message)).queue();
if (consoleLogSentTimes == 10) {
consoleLogTimer2.schedule(new TimerTask() {
@Override
public void run() {
consoleLogSentTimes = 0;
}
}, 20000);
consoleLogTextChannel.sendMessage("**" + (config.generic.switchLanguageFromChinToEng ? "Rate limit exceeded! Wait 20 seconds..." : "发送次数超出限制!等待 20 秒...") + "**").queue();
}
} catch (Exception e) {
e.printStackTrace();
textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
}
});
PlayerAdvancementCallback.EVENT.register((playerEntity, advancement) -> {
if (config.generic.announceAdvancements && advancement.getDisplay() != null
&& advancement.getDisplay().shouldAnnounceToChat()
&& playerEntity.getAdvancementTracker().getProgress(advancement).isDone() && !Main.stop) {
switch (advancement.getDisplay().getFrame()) {
case GOAL -> textChannel.sendMessage(Main.texts.advancementGoal()
.replace("%playername%", MarkdownSanitizer.escape(playerEntity.getEntityName()))
.replace("%advancement%", advancement.getDisplay().getTitle().getString())).queue();
case TASK -> textChannel.sendMessage(Main.texts.advancementTask()
.replace("%playername%", MarkdownSanitizer.escape(playerEntity.getEntityName()))
.replace("%advancement%", advancement.getDisplay().getTitle().getString())).queue();
case CHALLENGE -> textChannel.sendMessage(Main.texts.advancementChallenge()
.replace("%playername%", MarkdownSanitizer.escape(playerEntity.getEntityName()))
.replace("%advancement%", advancement.getDisplay().getTitle().getString())).queue();
}
}
});
PlayerDeathCallback.EVENT.register((playerEntity, damageSource) -> {
if (config.generic.announceDeaths && !Main.stop) {
textChannel.sendMessage(Main.texts.deathMessage()
.replace("%deathmessage%", MarkdownSanitizer.escape(damageSource.getDeathMessage(playerEntity).getString()))
.replace("%playername%", MarkdownSanitizer.escape(playerEntity.getEntityName()))).queue();
}
});
PlayerJoinCallback.EVENT.register((connection, playerEntity) -> {
if (config.generic.announcePlayers && !Main.stop) {
textChannel.sendMessage(Main.texts.joinServer().replace("%playername%",
MarkdownSanitizer.escape(playerEntity.getEntityName()))).queue();
}
});
PlayerLeaveCallback.EVENT.register(playerEntity -> {
if (config.generic.announcePlayers && !Main.stop) {
textChannel.sendMessage(Main.texts.leftServer().replace("%playername%",
MarkdownSanitizer.escape(playerEntity.getEntityName()))).queue();
}
});
}
}

View file

@ -1,23 +0,0 @@
package top.xujiayao.mcdiscordchat.mixins;
import net.minecraft.server.MinecraftServer;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.xujiayao.mcdiscordchat.events.SystemMessageCallback;
import java.util.UUID;
/**
* @author Xujiayao
*/
@Mixin(MinecraftServer.class)
public class MixinMinecraftServer {
@Inject(method = "sendSystemMessage", at = @At("HEAD"))
private void onSystemMessage(Text message, UUID sender, CallbackInfo ci) {
SystemMessageCallback.EVENT.invoker().onSystemMessage(message.getString());
}
}

View file

@ -1,26 +0,0 @@
package top.xujiayao.mcdiscordchat.mixins;
import net.minecraft.advancement.Advancement;
import net.minecraft.advancement.PlayerAdvancementTracker;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import top.xujiayao.mcdiscordchat.events.PlayerAdvancementCallback;
/**
* @author Xujiayao
*/
@Mixin(PlayerAdvancementTracker.class)
public class MixinPlayerAdvancementTracker {
@Shadow
private ServerPlayerEntity owner;
@Inject(method = "grantCriterion", at = @At("RETURN"))
private void grantCriterion(Advancement advancement, String criterionName, CallbackInfoReturnable<Boolean> cir) {
PlayerAdvancementCallback.EVENT.invoker().onPlayerAdvancement(owner, advancement);
}
}

View file

@ -1,28 +0,0 @@
package top.xujiayao.mcdiscordchat.mixins;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.xujiayao.mcdiscordchat.events.PlayerJoinCallback;
import top.xujiayao.mcdiscordchat.events.PlayerLeaveCallback;
/**
* @author Xujiayao
*/
@Mixin(PlayerManager.class)
public class MixinPlayerManager {
@Inject(method = "onPlayerConnect", at = @At("RETURN"))
private void onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) {
PlayerJoinCallback.EVENT.invoker().onJoin(connection, player);
}
@Inject(method = "remove", at = @At("HEAD"))
private void remove(ServerPlayerEntity player, CallbackInfo ci) {
PlayerLeaveCallback.EVENT.invoker().onLeave(player);
}
}

View file

@ -1,65 +0,0 @@
package top.xujiayao.mcdiscordchat.mixins;
import net.minecraft.network.MessageType;
import net.minecraft.network.Packet;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.filter.TextStream.Message;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.apache.commons.lang3.StringUtils;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.xujiayao.mcdiscordchat.events.CommandExecutionCallback;
import top.xujiayao.mcdiscordchat.events.ServerChatCallback;
import java.util.Optional;
/**
* @author Xujiayao
*/
@Mixin(ServerPlayNetworkHandler.class)
public abstract class MixinServerPlayNetworkHandler {
@Shadow
public ServerPlayerEntity player;
@Final
@Shadow
private MinecraftServer server;
@Shadow
private int messageCooldown;
@Shadow
public abstract void sendPacket(Packet<?> packet);
@Shadow
public abstract void disconnect(Text reason);
@Shadow
protected abstract void executeCommand(String input);
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Ljava/util/function/Function;Lnet/minecraft/network/MessageType;Ljava/util/UUID;)V"), method = "handleMessage", cancellable = true)
private void handleMessage(Message message, CallbackInfo ci) {
String string = message.getRaw();
String msg = StringUtils.normalizeSpace(string);
Text text = new TranslatableText("chat.type.text", this.player.getDisplayName(), msg);
Optional<Text> eventResult = ServerChatCallback.EVENT.invoker().onServerChat(this.player, msg, text);
if (eventResult.isPresent()) {
this.server.getPlayerManager().broadcast(eventResult.get(), MessageType.CHAT, this.player.getUuid());
ci.cancel();
}
}
@Inject(at = @At(value = "TAIL"), method = "executeCommand")
private void onCommandExecuted(String input, CallbackInfo ci) {
CommandExecutionCallback.EVENT.invoker().onExecuted(input, this.player.getCommandSource());
}
}

View file

@ -1,22 +0,0 @@
package top.xujiayao.mcdiscordchat.mixins;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.xujiayao.mcdiscordchat.events.PlayerDeathCallback;
/**
* @author Xujiayao
*/
@Mixin(ServerPlayerEntity.class)
public class MixinServerPlayerEntity {
@Inject(method = "onDeath", at = @At("HEAD"))
private void onDeath(DamageSource source, CallbackInfo ci) {
ServerPlayerEntity serverPlayerEntity = (ServerPlayerEntity) (Object) this;
PlayerDeathCallback.EVENT.invoker().onPlayerDeath(serverPlayerEntity, source);
}
}

View file

@ -1,18 +0,0 @@
package top.xujiayao.mcdiscordchat.objects;
/**
* @author Xujiayao
*/
public class ModJson {
private final String version;
public ModJson(String version) {
this.version = version;
}
public String version() {
return version;
}
}

View file

@ -1,19 +0,0 @@
package top.xujiayao.mcdiscordchat.objects;
/**
* @author Xujiayao
*/
public record Texts(String serverStarted,
String serverStopped,
String joinServer,
String leftServer,
String deathMessage,
String advancementTask,
String advancementChallenge,
String advancementGoal,
String highMSPT,
String consoleLogMessage,
String blueColoredText,
String roleColoredText,
String colorlessText) {
}

View file

@ -1,17 +0,0 @@
package top.xujiayao.mcdiscordchat.objects;
/**
* @author Xujiayao
*/
public class Version {
private final String version;
public Version(String version) {
this.version = version;
}
public String version() {
return version;
}
}

View file

@ -1,108 +0,0 @@
package top.xujiayao.mcdiscordchat.utils;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import net.fabricmc.loader.api.FabricLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import top.xujiayao.mcdiscordchat.Config;
import top.xujiayao.mcdiscordchat.Main;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author Xujiayao
*/
public class ConfigManager {
private static File file;
private ConfigManager() {
throw new IllegalStateException("Utility class");
}
public static void initConfig() {
file = new File(FabricLoader.getInstance().getConfigDir().toFile(), "mcdiscordchat.json");
if (file.exists() && file.length() != 0) {
try {
loadConfig();
} catch (Exception e) {
e.printStackTrace();
Main.config = new Config();
}
updateConfig();
Utils.reloadTextsConfig();
} else {
createConfig();
Logger LOGGER = LogManager.getLogger();
LOGGER.error("--------------------");
LOGGER.error("错误:找不到配置文件或配置文件为空!");
LOGGER.error("Error: The config file cannot be found or is empty!");
LOGGER.error("");
LOGGER.error("请在重新启动服务器前编辑 /config/mcdiscordchat.json 以配置 MCDiscordChat");
LOGGER.error("Please edit /config/mcdiscordchat.json to configure MCDiscordChat before restarting the server!");
LOGGER.error("");
LOGGER.error("正在停止服务器...");
LOGGER.error("Stopping the server...");
LOGGER.error("--------------------");
System.exit(1);
}
}
public static void loadConfig() throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String temp;
StringBuilder jsonString = new StringBuilder();
while ((temp = reader.readLine()) != null) {
jsonString.append(temp);
}
Main.config = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create()
.fromJson(jsonString.toString(), new TypeToken<Config>() {
}.getType());
}
}
private static void createConfig() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
String jsonString = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create()
.toJson(new Config());
writer.write(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void updateConfig() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
String jsonString = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create()
.toJson(Main.config);
writer.write(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View file

@ -1,69 +1,20 @@
package top.xujiayao.mcdiscordchat.utils;
import com.google.gson.Gson;
import net.dv8tion.jda.api.entities.Member;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Formatting;
import net.minecraft.util.Pair;
import net.minecraft.util.math.MathHelper;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import top.xujiayao.mcdiscordchat.Main;
import top.xujiayao.mcdiscordchat.objects.ModJson;
import top.xujiayao.mcdiscordchat.objects.Texts;
import top.xujiayao.mcdiscordchat.objects.Version;
import java.io.File;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static top.xujiayao.mcdiscordchat.Main.client;
/**
* @author Xujiayao
*/
public class Utils {
private Utils() {
throw new IllegalStateException("Utility class");
}
public static String adminsMentionString() {
StringBuilder text = new StringBuilder();
for (String id : Main.config.generic.superAdminsIds) {
text.append("<@").append(id).append("> ");
}
for (String id : Main.config.generic.adminsIds) {
text.append("<@").append(id).append("> ");
}
return text.toString();
}
public static MinecraftServer getServer() {
@SuppressWarnings("deprecation")
Object gameInstance = FabricLoader.getInstance().getGameInstance();
if (gameInstance instanceof MinecraftServer minecraftServer) {
return minecraftServer;
}
return null;
}
public static void monitorMSPT() {
Main.msptMonitorTimer.schedule(new TimerTask() {
@Override
@ -79,44 +30,6 @@ public class Utils {
}, 0, 5000);
}
public static void checkUpdate(boolean isManualCheck) {
try {
Request request = new Request.Builder()
.url("https://cdn.jsdelivr.net/gh/Xujiayao/MCDiscordChat@master/update/version.json")
.build();
String result = null;
try (Response response = client.newCall(request).execute()) {
result = Objects.requireNonNull(response.body()).string();
}
Version version = new Gson().fromJson(result, Version.class);
ModJson modJson = new Gson().fromJson(IOUtils.toString(new URI("jar:file:" + Main.class.getProtectionDomain().getCodeSource().getLocation().getPath() + "!/fabric.mod.json"), StandardCharsets.UTF_8), ModJson.class);
if (!version.version().equals(modJson.version().substring(modJson.version().indexOf("-") + 1))) {
StringBuilder text;
if (Main.config.generic.switchLanguageFromChinToEng) {
text = new StringBuilder("**A new version is available!**\n\nMCDiscordChat **" + modJson.version().substring(modJson.version().indexOf("-") + 1) + "** -> **" + version.version() + "**\n\nDownload link: https://github.com/Xujiayao/MCDiscordChat/blob/master/README.md#Download\n\n");
} else {
text = new StringBuilder("**新版本可用!**\n\nMCDiscordChat **" + modJson.version().substring(modJson.version().indexOf("-") + 1) + "** -> **" + version.version() + "**\n\n下载链接https://github.com/Xujiayao/MCDiscordChat/blob/master/README_CN.md#%E4%B8%8B%E8%BD%BD\n\n");
}
text.append(adminsMentionString());
Main.textChannel.sendMessage(text).queue();
} else {
if (isManualCheck) {
Main.textChannel.sendMessage("MCDiscordChat **" + modJson.version().substring(modJson.version().indexOf("-") + 1) + (Main.config.generic.switchLanguageFromChinToEng ? "**\n\n**MCDiscordChat is up to date!**" : "**\n\n**当前版本已经是最新版本!**")).queue();
}
}
} catch (Exception e) {
e.printStackTrace();
Main.textChannel.sendMessage("```\n" + ExceptionUtils.getStackTrace(e) + "\n```").queue();
}
}
public static void reloadTextsConfig() {
if (Main.config.generic.switchLanguageFromChinToEng) {
Main.texts = new Texts(Main.config.textsEN.serverStarted,
@ -158,55 +71,4 @@ public class Utils {
return result;
}
public static Pair<String, String> convertMentionsFromNames(String message) {
if (!message.contains("@")) {
return new Pair<>(message, message);
}
List<String> messageList = Arrays.asList(message.split("@[\\S]+"));
if (messageList.isEmpty()) {
messageList = new ArrayList<>();
messageList.add("");
}
StringBuilder discordString = new StringBuilder();
StringBuilder mcString = new StringBuilder();
Pattern pattern = Pattern.compile("@[\\S]+");
Matcher matcher = pattern.matcher(message);
int x = 0;
while (matcher.find()) {
Member member = null;
for (Member m : Main.textChannel.getMembers()) {
String name = matcher.group().substring(1);
if (m.getUser().getName().equalsIgnoreCase(name) || (m.getNickname() != null && m.getNickname().equalsIgnoreCase(name))) {
member = m;
}
}
if (member == null) {
discordString.append(messageList.get(x)).append(matcher.group());
mcString.append(messageList.get(x)).append(matcher.group());
} else {
discordString.append(messageList.get(x)).append(member.getAsMention());
mcString.append(messageList.get(x)).append(Formatting.YELLOW).append("@")
.append(member.getEffectiveName()).append(Formatting.WHITE);
}
x++;
}
if (x < messageList.size()) {
discordString.append(messageList.get(x));
mcString.append(messageList.get(x));
}
return new Pair<>(discordString.toString(), mcString.toString());
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -1,32 +0,0 @@
{
"schemaVersion": 1,
"id": "mcdiscordchat",
"version": "${version}",
"name": "MCDiscordChat",
"description": "MCDiscordChat (MCDC), a practical and powerful Fabric Minecraft <> Discord chat bridge inspired by BRForgers/DisFabric",
"authors": [
"Xujiayao"
],
"contact": {
"homepage": "https://blog.xujiayao.top/posts/4ba0a17a/",
"issues": "https://github.com/Xujiayao/MCDiscordChat/issues",
"sources": "https://github.com/Xujiayao/MCDiscordChat"
},
"license": "MIT",
"icon": "assets/mcdiscordchat/icon.png",
"environment": "server",
"entrypoints": {
"server": [
"top.xujiayao.mcdiscordchat.Main"
]
},
"mixins": [
"mcdiscordchat.mixins.json"
],
"depends": {
"fabricloader": ">=0.13.3",
"fabric": "*",
"minecraft": "1.18.x",
"java": ">=17"
}
}

View file

@ -1,15 +0,0 @@
{
"required": true,
"package": "top.xujiayao.mcdiscordchat.mixins",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MixinPlayerAdvancementTracker",
"MixinPlayerManager",
"MixinServerPlayerEntity",
"MixinServerPlayNetworkHandler",
"MixinMinecraftServer"
],
"injectors": {
"defaultRequire": 1
}
}