mirror of
https://github.com/System-End/Discord-MC-Chat.git
synced 2026-04-19 19:45:14 +00:00
Implement stats command for viewing Minecraft statistics
This commit is contained in:
parent
42977b2eb6
commit
6978a4ab8b
10 changed files with 413 additions and 27 deletions
|
|
@ -1,8 +1,10 @@
|
|||
package com.xujiayao.discord_mc_chat.commands;
|
||||
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.StatsCommand;
|
||||
import com.xujiayao.discord_mc_chat.utils.LogFileUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -27,35 +29,78 @@ public class CommandAutoCompleter {
|
|||
|
||||
if (input == null || input.isBlank()) {
|
||||
// Return all command names
|
||||
suggestions.addAll(CommandManager.getCommandNames());
|
||||
CommandManager.getCommands().stream()
|
||||
.sorted(Comparator.comparing(Command::name))
|
||||
.forEach(cmd -> {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append(cmd.name());
|
||||
for (Command.CommandArgument arg : cmd.args()) {
|
||||
builder.append(" <").append(arg.name()).append(">");
|
||||
}
|
||||
|
||||
suggestions.add(builder.toString());
|
||||
});
|
||||
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
String trimmed = input.trim();
|
||||
String[] parts = trimmed.split("\\s+", 2);
|
||||
String[] parts = input.trim().split("\\s+");
|
||||
String commandName = parts[0].toLowerCase();
|
||||
|
||||
if (parts.length == 1 && !input.endsWith(" ")) {
|
||||
// User is still typing the command name — suggest matching command names
|
||||
for (String name : CommandManager.getCommandNames()) {
|
||||
if (name.startsWith(commandName)) {
|
||||
suggestions.add(name);
|
||||
}
|
||||
}
|
||||
// User is still typing the command name
|
||||
CommandManager.getCommands().stream()
|
||||
.filter(cmd -> cmd.name().startsWith(commandName))
|
||||
.sorted(Comparator.comparing(Command::name))
|
||||
.forEach(cmd -> {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append(cmd.name());
|
||||
for (Command.CommandArgument arg : cmd.args()) {
|
||||
builder.append(" <").append(arg.name()).append(">");
|
||||
}
|
||||
|
||||
suggestions.add(builder.toString());
|
||||
});
|
||||
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
// User has typed a command name and moved on to arguments
|
||||
String argInput = parts.length > 1 ? parts[1] : "";
|
||||
|
||||
switch (commandName) {
|
||||
case "log" -> {
|
||||
// Suggest log file names
|
||||
List<String> logFiles = LogFileUtils.listLogFiles();
|
||||
String lowerArgInput = argInput.toLowerCase();
|
||||
for (String file : logFiles) {
|
||||
if (file.toLowerCase().startsWith(lowerArgInput) || file.toLowerCase().contains(lowerArgInput)) {
|
||||
suggestions.add("log " + file);
|
||||
String argInput = parts.length > 1 ? parts[1] : "";
|
||||
if (parts.length == 1 || (parts.length == 2 && !input.endsWith(" "))) {
|
||||
List<String> logFiles = LogFileUtils.listLogFiles();
|
||||
String lowerArgInput = argInput.toLowerCase();
|
||||
for (String file : logFiles) {
|
||||
if (file.toLowerCase().startsWith(lowerArgInput) || file.toLowerCase().contains(lowerArgInput)) {
|
||||
suggestions.add("log " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "stats" -> {
|
||||
StatsCommand.StatsProvider provider = StatsCommand.getProvider();
|
||||
if (provider != null) {
|
||||
if (parts.length == 1 || (parts.length == 2 && !input.endsWith(" "))) {
|
||||
String typeInput = parts.length > 1 ? parts[1] : "";
|
||||
String lowerType = typeInput.toLowerCase();
|
||||
for (String type : provider.getStatTypes()) {
|
||||
if (type.toLowerCase().startsWith(lowerType) || type.toLowerCase().contains(lowerType)) {
|
||||
suggestions.add("stats " + type);
|
||||
}
|
||||
}
|
||||
} else if (parts.length == 2 || (parts.length == 3 && !input.endsWith(" "))) {
|
||||
String type = parts[1];
|
||||
String statInput = parts.length > 2 ? parts[2] : "";
|
||||
String lowerStat = statInput.toLowerCase();
|
||||
for (String stat : provider.getStatNames(type)) {
|
||||
if (stat.toLowerCase().startsWith(lowerStat) || stat.toLowerCase().contains(lowerStat)) {
|
||||
suggestions.add("stats " + type + " " + stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.xujiayao.discord_mc_chat.commands.impl.InfoCommand;
|
|||
import com.xujiayao.discord_mc_chat.commands.impl.LogCommand;
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.ReloadCommand;
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.ShutdownCommand;
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.StatsCommand;
|
||||
import com.xujiayao.discord_mc_chat.utils.ExecutorServiceUtils;
|
||||
import com.xujiayao.discord_mc_chat.utils.config.ModeManager;
|
||||
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
|
||||
|
|
@ -46,6 +47,8 @@ public class CommandManager {
|
|||
if ("standalone".equals(ModeManager.getMode())) {
|
||||
register(new ExecuteCommand());
|
||||
register(new ShutdownCommand());
|
||||
} else {
|
||||
register(new StatsCommand());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,15 +80,6 @@ public class CommandManager {
|
|||
return new ArrayList<>(COMMANDS.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered command names.
|
||||
*
|
||||
* @return A collection of registered command names
|
||||
*/
|
||||
public static Collection<String> getCommandNames() {
|
||||
return new ArrayList<>(COMMANDS.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command line.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
package com.xujiayao.discord_mc_chat.commands.impl;
|
||||
|
||||
import com.xujiayao.discord_mc_chat.commands.Command;
|
||||
import com.xujiayao.discord_mc_chat.commands.CommandSender;
|
||||
import com.xujiayao.discord_mc_chat.utils.JsonUtils;
|
||||
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Stats command implementation.
|
||||
*
|
||||
* @author Xujiayao
|
||||
*/
|
||||
public class StatsCommand implements Command {
|
||||
|
||||
private static StatsProvider provider;
|
||||
|
||||
public static StatsProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void setProvider(StatsProvider provider) {
|
||||
StatsCommand.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "stats";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandArgument[] args() {
|
||||
return new CommandArgument[]{
|
||||
new CommandArgument() {
|
||||
@Override
|
||||
public String name() {
|
||||
return "type";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return I18nManager.getDmccTranslation("commands.stats.args_desc.type");
|
||||
}
|
||||
},
|
||||
new CommandArgument() {
|
||||
@Override
|
||||
public String name() {
|
||||
return "stat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return I18nManager.getDmccTranslation("commands.stats.args_desc.stat");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return I18nManager.getDmccTranslation("commands.stats.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String... args) {
|
||||
if (provider == null) {
|
||||
sender.reply(I18nManager.getDmccTranslation("commands.stats.server_not_ready"));
|
||||
return;
|
||||
}
|
||||
|
||||
provider.saveAll(); // Ensure data is written to disk
|
||||
|
||||
String type = args[0];
|
||||
String stat = args[1];
|
||||
|
||||
Path statsDir = provider.getStatsDirectory();
|
||||
|
||||
if (statsDir == null || !Files.exists(statsDir) || !Files.isDirectory(statsDir)) {
|
||||
sender.reply(I18nManager.getDmccTranslation("commands.stats.dir_not_found"));
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Integer> leaderboard = new ConcurrentHashMap<>();
|
||||
|
||||
try (Stream<Path> stream = Files.list(statsDir)) {
|
||||
stream.filter(Files::isRegularFile)
|
||||
.filter(p -> p.getFileName().toString().endsWith(".json"))
|
||||
.forEach(p -> {
|
||||
String fileName = p.getFileName().toString();
|
||||
String uuidStr = fileName.substring(0, fileName.length() - 5);
|
||||
try {
|
||||
UUID uuid = UUID.fromString(uuidStr);
|
||||
int value = JsonUtils.getStat(p, type, stat);
|
||||
if (value > 0) {
|
||||
String name = provider.getPlayerName(uuid);
|
||||
if (name == null || name.isBlank()) {
|
||||
name = uuidStr;
|
||||
}
|
||||
leaderboard.put(name, value);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
sender.reply(I18nManager.getDmccTranslation("commands.stats.read_failed", e.getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (leaderboard.isEmpty()) {
|
||||
sender.reply(I18nManager.getDmccTranslation("commands.stats.no_stats", type, stat));
|
||||
return;
|
||||
}
|
||||
|
||||
List<Map.Entry<String, Integer>> sorted = new ArrayList<>(leaderboard.entrySet());
|
||||
sorted.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String colon = I18nManager.getDmccTranslation("commands.stats.colon");
|
||||
|
||||
sb.append("========== ").append(I18nManager.getDmccTranslation("commands.stats.stats")).append(" ==========\n\n")
|
||||
.append(I18nManager.getDmccTranslation("commands.stats.args_desc.type")).append(colon).append(type).append("\n")
|
||||
.append(I18nManager.getDmccTranslation("commands.stats.args_desc.stat")).append(colon).append(stat).append("\n\n");
|
||||
|
||||
for (int i = 0; i < sorted.size(); i++) {
|
||||
Map.Entry<String, Integer> entry = sorted.get(i);
|
||||
sb.append(i + 1).append(". ").append(entry.getKey()).append(": ").append(entry.getValue());
|
||||
if (i < sorted.size() - 1) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sender.reply(sb.toString());
|
||||
}
|
||||
|
||||
public interface StatsProvider {
|
||||
void saveAll();
|
||||
|
||||
Path getStatsDirectory();
|
||||
|
||||
String getPlayerName(UUID uuid);
|
||||
|
||||
List<String> getStatTypes();
|
||||
|
||||
List<String> getStatNames(String type);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.xujiayao.discord_mc_chat.server.discord;
|
||||
|
||||
import com.xujiayao.discord_mc_chat.commands.CommandManager;
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.StatsCommand;
|
||||
import com.xujiayao.discord_mc_chat.network.NetworkManager;
|
||||
import com.xujiayao.discord_mc_chat.utils.LogFileUtils;
|
||||
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
|
||||
|
|
@ -46,6 +47,11 @@ public class DiscordEventHandler extends ListenerAdapter {
|
|||
String file = event.getOption("file", OptionMapping::getAsString);
|
||||
CommandManager.execute(new JdaCommandSender(event), name, file);
|
||||
}
|
||||
case "stats" -> {
|
||||
String type = event.getOption("type", OptionMapping::getAsString);
|
||||
String stat = event.getOption("stat", OptionMapping::getAsString);
|
||||
CommandManager.execute(new JdaCommandSender(event), name, type, stat);
|
||||
}
|
||||
default -> CommandManager.execute(new JdaCommandSender(event), name);
|
||||
}
|
||||
}
|
||||
|
|
@ -71,6 +77,14 @@ public class DiscordEventHandler extends ListenerAdapter {
|
|||
choices = getLogFileChoices(currentValue);
|
||||
}
|
||||
}
|
||||
case "stats" -> {
|
||||
if ("type".equals(focusedOption)) {
|
||||
choices = getStatsTypeChoices(currentValue);
|
||||
} else if ("stat".equals(focusedOption)) {
|
||||
String type = event.getOption("type", OptionMapping::getAsString);
|
||||
choices = getStatsStatChoices(type, currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event.replyChoices(choices).queue();
|
||||
|
|
@ -145,6 +159,43 @@ public class DiscordEventHandler extends ListenerAdapter {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets auto-complete choices for the 'type' parameter of the stats command.
|
||||
*
|
||||
* @param currentValue The current user input for filtering
|
||||
* @return List of choices
|
||||
*/
|
||||
private List<Command.Choice> getStatsTypeChoices(String currentValue) {
|
||||
StatsCommand.StatsProvider provider = StatsCommand.getProvider();
|
||||
if (provider == null) return List.of();
|
||||
|
||||
String lowerValue = currentValue.toLowerCase();
|
||||
return provider.getStatTypes().stream()
|
||||
.filter(t -> t.toLowerCase().contains(lowerValue))
|
||||
.limit(25)
|
||||
.map(t -> new Command.Choice(t, t))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets auto-complete choices for the 'stat' parameter of the stats command.
|
||||
*
|
||||
* @param type The selected stat type
|
||||
* @param currentValue The current user input for filtering
|
||||
* @return List of choices
|
||||
*/
|
||||
private List<Command.Choice> getStatsStatChoices(String type, String currentValue) {
|
||||
StatsCommand.StatsProvider provider = StatsCommand.getProvider();
|
||||
if (provider == null || type == null || type.isBlank()) return List.of();
|
||||
|
||||
String lowerValue = currentValue.toLowerCase();
|
||||
return provider.getStatNames(type).stream()
|
||||
.filter(s -> s.toLowerCase().contains(lowerValue))
|
||||
.limit(25)
|
||||
.map(s -> new Command.Choice(s, s))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
|
||||
if (event.getAuthor().isBot() || event.isWebhookMessage()) {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ public class DiscordManager {
|
|||
.addOption(OptionType.STRING, "at", I18nManager.getDmccTranslation("commands.execute.args_desc.at"), true, true)
|
||||
.addOption(OptionType.STRING, "command", I18nManager.getDmccTranslation("commands.execute.args_desc.command"), true, true));
|
||||
commands.add(Commands.slash("shutdown", I18nManager.getDmccTranslation("commands.shutdown.description")));
|
||||
} else {
|
||||
commands.add(Commands.slash("stats", I18nManager.getDmccTranslation("commands.stats.description"))
|
||||
.addOption(OptionType.STRING, "type", I18nManager.getDmccTranslation("commands.stats.args_desc.type"), true, true)
|
||||
.addOption(OptionType.STRING, "stat", I18nManager.getDmccTranslation("commands.stats.args_desc.stat"), true, true));
|
||||
}
|
||||
|
||||
CompletableFuture<List<Command>> updateFuture = jda.updateCommands().addCommands(commands).submit();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
package com.xujiayao.discord_mc_chat.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.xujiayao.discord_mc_chat.Constants.JSON_MAPPER;
|
||||
import static com.xujiayao.discord_mc_chat.Constants.YAML_MAPPER;
|
||||
|
||||
/**
|
||||
|
|
@ -53,4 +58,24 @@ public class JsonUtils {
|
|||
return YAML_MAPPER.readValue(inputStream, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a specific statistic from a player's stats JSON file.
|
||||
*
|
||||
* @param path The path to the JSON file
|
||||
* @param type The stat type (e.g., "minecraft:custom")
|
||||
* @param stat The stat name (e.g., "minecraft:deaths")
|
||||
* @return The stat value, or 0 if not found
|
||||
*/
|
||||
public static int getStat(Path path, String type, String stat) {
|
||||
try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
||||
JsonNode root = JSON_MAPPER.readTree(reader);
|
||||
JsonNode typeNode = root.path("stats").path(type);
|
||||
if (!typeNode.isMissingNode() && typeNode.has(stat)) {
|
||||
return typeNode.path(stat).asInt();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,17 @@ commands:
|
|||
saved_to_cache: "Log file saved to: {}"
|
||||
save_failed: "Failed to save log file to cache: {}"
|
||||
terminal_not_supported: "Retrieving log files in terminal is not supported. Please access the \"./logs\" directory directly."
|
||||
stats:
|
||||
description: "View Minecraft statistics"
|
||||
args_desc:
|
||||
type: "Stat type"
|
||||
stat: "Stat name"
|
||||
server_not_ready: "Minecraft Server is not ready yet."
|
||||
dir_not_found: "Stats directory not found."
|
||||
read_failed: "Failed to read stats: {}"
|
||||
no_stats: "No stats found for {0} {1}."
|
||||
stats: "Stats"
|
||||
colon: ": "
|
||||
|
||||
main:
|
||||
init:
|
||||
|
|
|
|||
|
|
@ -94,6 +94,17 @@ commands:
|
|||
saved_to_cache: "日志文件已保存到:{}"
|
||||
save_failed: "保存日志文件到缓存失败:{}"
|
||||
terminal_not_supported: "在终端中获取日志文件不受支持。请直接访问 \"./logs\" 目录。"
|
||||
stats:
|
||||
description: "查看 Minecraft 统计数据"
|
||||
args_desc:
|
||||
type: "统计数据类型"
|
||||
stat: "统计数据名称"
|
||||
server_not_ready: "Minecraft 服务器尚未准备就绪。"
|
||||
dir_not_found: "未找到统计数据目录。"
|
||||
read_failed: "读取统计数据失败:{}"
|
||||
no_stats: "未找到关于 {0} {1} 的统计数据。"
|
||||
stats: "统计数据"
|
||||
colon: ":"
|
||||
|
||||
main:
|
||||
init:
|
||||
|
|
|
|||
|
|
@ -5,8 +5,17 @@ import com.xujiayao.discord_mc_chat.commands.CommandManager;
|
|||
import com.xujiayao.discord_mc_chat.commands.LocalCommandSender;
|
||||
import com.xujiayao.discord_mc_chat.utils.config.ConfigManager;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.stats.StatType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
/**
|
||||
|
|
@ -46,11 +55,36 @@ public class MinecraftCommands {
|
|||
CommandManager.execute(new MinecraftCommandSender(ctx.getSource()), "reload");
|
||||
return 1;
|
||||
});
|
||||
var stats = literal("stats")
|
||||
.requires(source -> source.hasPermission(ConfigManager.getInt("command_permission_levels.stats", 0)))
|
||||
.then(argument("type", ResourceLocationArgument.id())
|
||||
.suggests((ctx, builder) -> SharedSuggestionProvider.suggestResource(
|
||||
BuiltInRegistries.STAT_TYPE.keySet(), builder))
|
||||
.then(argument("stat", ResourceLocationArgument.id())
|
||||
.suggests((ctx, builder) -> {
|
||||
try {
|
||||
ResourceLocation typeLoc = ctx.getArgument("type", ResourceLocation.class);
|
||||
Optional<Holder.Reference<StatType<?>>> optional = BuiltInRegistries.STAT_TYPE.get(typeLoc);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
return SharedSuggestionProvider.suggestResource(optional.get().value().getRegistry().keySet(), builder);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return builder.buildFuture();
|
||||
})
|
||||
.executes(ctx -> {
|
||||
ResourceLocation typeLoc = ctx.getArgument("type", ResourceLocation.class);
|
||||
ResourceLocation statLoc = ctx.getArgument("stat", ResourceLocation.class);
|
||||
CommandManager.execute(new MinecraftCommandSender(ctx.getSource()), "stats", typeLoc.toString(), statLoc.toString());
|
||||
return 1;
|
||||
})));
|
||||
|
||||
dispatcher.register(root
|
||||
.then(help)
|
||||
.then(info)
|
||||
.then(reload));
|
||||
.then(reload)
|
||||
.then(stats));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.xujiayao.discord_mc_chat.minecraft.events;
|
||||
|
||||
import com.xujiayao.discord_mc_chat.DMCC;
|
||||
import com.xujiayao.discord_mc_chat.commands.impl.StatsCommand;
|
||||
import com.xujiayao.discord_mc_chat.minecraft.commands.MinecraftCommands;
|
||||
import com.xujiayao.discord_mc_chat.minecraft.translations.TranslationManager;
|
||||
import com.xujiayao.discord_mc_chat.network.NetworkManager;
|
||||
|
|
@ -11,15 +12,26 @@ import com.xujiayao.discord_mc_chat.utils.config.ConfigManager;
|
|||
import com.xujiayao.discord_mc_chat.utils.config.ModeManager;
|
||||
import com.xujiayao.discord_mc_chat.utils.events.EventManager;
|
||||
import net.minecraft.advancements.DisplayInfo;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.ServerTickRateManager;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.players.NameAndId;
|
||||
import net.minecraft.stats.StatType;
|
||||
import net.minecraft.util.TimeUtil;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
|
|
@ -34,6 +46,51 @@ public class MinecraftEventHandler {
|
|||
*/
|
||||
public static void init() {
|
||||
EventManager.register(MinecraftEvents.ServerStarted.class, event -> {
|
||||
StatsCommand.setProvider(new StatsCommand.StatsProvider() {
|
||||
@Override
|
||||
public void saveAll() {
|
||||
event.minecraftServer().getPlayerList().saveAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getStatsDirectory() {
|
||||
return event.minecraftServer().getWorldPath(LevelResource.PLAYER_STATS_DIR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerName(UUID uuid) {
|
||||
return event.minecraftServer().services().nameToIdCache()
|
||||
.get(uuid)
|
||||
.map(NameAndId::name)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStatTypes() {
|
||||
List<String> types = new ArrayList<>();
|
||||
for (ResourceLocation loc : BuiltInRegistries.STAT_TYPE.keySet()) {
|
||||
types.add(loc.toString());
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStatNames(String typeStr) {
|
||||
List<String> stats = new ArrayList<>();
|
||||
try {
|
||||
ResourceLocation typeLoc = ResourceLocation.parse(typeStr);
|
||||
Optional<Holder.Reference<StatType<?>>> optional = BuiltInRegistries.STAT_TYPE.get(typeLoc);
|
||||
if (optional.isPresent()) {
|
||||
for (ResourceLocation loc : optional.get().value().getRegistry().keySet()) {
|
||||
stats.add(loc.toString());
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, String> placeholders = Map.of();
|
||||
NetworkManager.sendPacketToServer(new MinecraftEventPacket(MinecraftEventPacket.MessageType.SERVER_STARTED, placeholders));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue