修bug修bug
This commit is contained in:
parent
a5b4efc36e
commit
eef2bbebad
@ -6,7 +6,7 @@ minecraft_version=1.21.4
|
|||||||
yarn_mappings=1.21.4+build.8
|
yarn_mappings=1.21.4+build.8
|
||||||
loader_version=0.16.10
|
loader_version=0.16.10
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=1.14.514.131
|
mod_version=1.14.514.132
|
||||||
maven_group=org.example1
|
maven_group=org.example1
|
||||||
archives_base_name=ServerPlayerOnlineTracker
|
archives_base_name=ServerPlayerOnlineTracker
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
@ -9,7 +9,6 @@ public class ModConfig {
|
|||||||
private final Path configPath;
|
private final Path configPath;
|
||||||
private int webPort = 60048;
|
private int webPort = 60048;
|
||||||
private String language = "zh_cn";
|
private String language = "zh_cn";
|
||||||
private long autoSaveSeconds = 300;
|
|
||||||
|
|
||||||
public ModConfig(Path configDir) {
|
public ModConfig(Path configDir) {
|
||||||
this.configPath = configDir.resolve("playertime-config.json");
|
this.configPath = configDir.resolve("playertime-config.json");
|
||||||
@ -37,19 +36,13 @@ public class ModConfig {
|
|||||||
if (json.has("webPort")) {
|
if (json.has("webPort")) {
|
||||||
webPort = json.get("webPort").getAsInt();
|
webPort = json.get("webPort").getAsInt();
|
||||||
} else {
|
} else {
|
||||||
PlayerTimeMod.LOGGER.info("[在线时间] 配置文件缺少“webPort”字段,添加默认值'%s'并保存", webPort);
|
PlayerTimeMod.LOGGER.info("[在线时间] 配置文件缺少webPort字段,添加默认值'%s'并保存", webPort);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
if (json.has("language")) {
|
if (json.has("language")) {
|
||||||
language = json.get("language").getAsString();
|
language = json.get("language").getAsString();
|
||||||
} else {
|
} else {
|
||||||
PlayerTimeMod.LOGGER.info("[在线时间] 配置文件缺少“language”字段,添加默认值'%s'并保存", language);
|
PlayerTimeMod.LOGGER.info("[在线时间] 配置文件缺少language字段,添加默认值'%s'并保存", language);
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
if (json.has("autoSaveSeconds")) {
|
|
||||||
autoSaveSeconds = json.get("autoSaveSeconds").getAsLong();
|
|
||||||
} else {
|
|
||||||
PlayerTimeMod.LOGGER.info("[在线时间] 配置文件缺少“autoSaveSeconds”字段,添加默认值'%s'并保存", autoSaveSeconds);
|
|
||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +57,6 @@ public class ModConfig {
|
|||||||
JsonObject json = new JsonObject();
|
JsonObject json = new JsonObject();
|
||||||
json.addProperty("webPort", webPort);
|
json.addProperty("webPort", webPort);
|
||||||
json.addProperty("language", language);
|
json.addProperty("language", language);
|
||||||
json.addProperty("autoSaveSeconds", autoSaveSeconds);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(configPath.getParent());
|
Files.createDirectories(configPath.getParent());
|
||||||
@ -86,9 +78,4 @@ public class ModConfig {
|
|||||||
public String getLanguage() {
|
public String getLanguage() {
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取保存间隔
|
|
||||||
public long getSeconds() {
|
|
||||||
return autoSaveSeconds;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class PlayerTimeMod implements ModInitializer {
|
public class PlayerTimeMod implements ModInitializer {
|
||||||
@ -30,29 +26,16 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
private static PlayerTimeTracker timeTracker;
|
private static PlayerTimeTracker timeTracker;
|
||||||
private static WebServer webServer;
|
private static WebServer webServer;
|
||||||
private static ModConfig config;
|
private static ModConfig config;
|
||||||
public static LocalizationManager localizationManager; // 新增本地化管理器
|
public static LocalizationManager localizationManager;
|
||||||
|
|
||||||
// TODO 定时保存配置文件没整,暂时硬编码
|
|
||||||
private ScheduledExecutorService scheduler;
|
|
||||||
private ScheduledFuture<?> saveTask;
|
|
||||||
private static long AUTO_SAVE_INTERVAL_SECONDS;
|
|
||||||
|
|
||||||
// 后续还是想把logger改成英文
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
|
||||||
config = new ModConfig(FabricLoader.getInstance().getConfigDir());
|
config = new ModConfig(FabricLoader.getInstance().getConfigDir());
|
||||||
localizationManager = new LocalizationManager(config.getLanguage());
|
localizationManager = new LocalizationManager(config.getLanguage());
|
||||||
|
|
||||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOGGER.info("[在线时间] 初始化 玩家在线时长视奸Mod");
|
LOGGER.info("[在线时间] 初始化 玩家在线时长视奸Mod");
|
||||||
|
|
||||||
AUTO_SAVE_INTERVAL_SECONDS = config.getSeconds();
|
|
||||||
|
|
||||||
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
|
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
|
||||||
timeTracker = new PlayerTimeTracker(server);
|
timeTracker = new PlayerTimeTracker(server);
|
||||||
try {
|
try {
|
||||||
@ -62,21 +45,6 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("[在线时间] 无法启动Web服务器", e);
|
LOGGER.error("[在线时间] 无法启动Web服务器", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info("[在线时间] 每{}秒({}分钟)安排自动保存任务。",
|
|
||||||
AUTO_SAVE_INTERVAL_SECONDS, AUTO_SAVE_INTERVAL_SECONDS / 60);
|
|
||||||
saveTask = scheduler.scheduleAtFixedRate(
|
|
||||||
() -> {
|
|
||||||
if (timeTracker != null) {
|
|
||||||
LOGGER.info("[在线时间] 自动保存玩家数据中...");
|
|
||||||
timeTracker.saveAll();
|
|
||||||
LOGGER.info("[在线时间] 自动保存完成。");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AUTO_SAVE_INTERVAL_SECONDS,
|
|
||||||
AUTO_SAVE_INTERVAL_SECONDS,
|
|
||||||
TimeUnit.SECONDS
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||||
@ -94,24 +62,6 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
|
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
|
||||||
LOGGER.info("[在线时间] 服务器停止 - 正在保存数据");
|
LOGGER.info("[在线时间] 服务器停止 - 正在保存数据");
|
||||||
|
|
||||||
if (saveTask != null) {
|
|
||||||
saveTask.cancel(false);
|
|
||||||
LOGGER.info("[在线时间] 自动保存任务已取消。");
|
|
||||||
}
|
|
||||||
if (scheduler != null && !scheduler.isShutdown()) {
|
|
||||||
scheduler.shutdown();
|
|
||||||
try {
|
|
||||||
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
|
|
||||||
LOGGER.warn("[在线时间] 调度程序未在5秒内终止。");
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOGGER.error("[在线时间] 调度程序终止被中断", e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
LOGGER.info("[在线时间] 调度程序关闭");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (webServer != null) {
|
if (webServer != null) {
|
||||||
webServer.stop();
|
webServer.stop();
|
||||||
}
|
}
|
||||||
@ -123,12 +73,8 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("[在线时间] Mod出屎化失败", e);
|
LOGGER.error("[在线时间] Mod初始化失败", e);
|
||||||
if (scheduler != null && !scheduler.isShutdown()) {
|
|
||||||
scheduler.shutdownNow();
|
|
||||||
}
|
|
||||||
throw new RuntimeException("[在线时间] Mod初始化失败 ", e);
|
throw new RuntimeException("[在线时间] Mod初始化失败 ", e);
|
||||||
}
|
}
|
||||||
registerCommands();
|
registerCommands();
|
||||||
@ -146,12 +92,11 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
return localizationManager;
|
return localizationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void registerCommands() {
|
public static void registerCommands() {
|
||||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||||
dispatcher.register(CommandManager.literal("onlineTime")
|
dispatcher.register(CommandManager.literal("onlineTime")
|
||||||
.requires(source -> source.hasPermissionLevel(0))
|
.requires(source -> source.hasPermissionLevel(0))
|
||||||
.executes(context -> showOnlineTime(context.getSource(), 1)) // 默认第一页
|
.executes(context -> showOnlineTime(context.getSource(), 1))
|
||||||
.then(CommandManager.argument("page", IntegerArgumentType.integer(1))
|
.then(CommandManager.argument("page", IntegerArgumentType.integer(1))
|
||||||
.executes(context -> showOnlineTime(
|
.executes(context -> showOnlineTime(
|
||||||
context.getSource(),
|
context.getSource(),
|
||||||
@ -172,7 +117,7 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
Map<String, String> stats = tracker.getWhitelistedPlayerStats();
|
Map<String, String> stats = tracker.getWhitelistedPlayerStats();
|
||||||
|
|
||||||
List<String> sorted = stats.entrySet().stream()
|
List<String> sorted = stats.entrySet().stream()
|
||||||
.sorted((a, b) -> comparePlayTime(b.getValue(), a.getValue()))
|
.sorted((a, b) -> comparePlayTime(a.getValue(), b.getValue()))
|
||||||
.map(entry -> formatPlayerTime(entry.getKey(), entry.getValue()))
|
.map(entry -> formatPlayerTime(entry.getKey(), entry.getValue()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
@ -249,5 +194,4 @@ public class PlayerTimeMod implements ModInitializer {
|
|||||||
|
|
||||||
player.sendMessage(footer, false);
|
player.sendMessage(footer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,6 @@ public class PlayerTimeTracker {
|
|||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没用了,但是先保留吧
|
|
||||||
// private boolean isWhitelisted(String playerName) {
|
|
||||||
// MinecraftServer server = this.server;
|
|
||||||
// if (server == null) return false;
|
|
||||||
//
|
|
||||||
// return server.getPlayerManager().getWhitelist()
|
|
||||||
// .isAllowed(server.getUserCache().findByName(playerName).orElse(null));
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
public void onPlayerJoin(ServerPlayerEntity player) {
|
public void onPlayerJoin(ServerPlayerEntity player) {
|
||||||
PlayerTimeData data = playerData.computeIfAbsent(player.getUuid(), uuid -> new PlayerTimeData());
|
PlayerTimeData data = playerData.computeIfAbsent(player.getUuid(), uuid -> new PlayerTimeData());
|
||||||
data.lastLogin = Instant.now().getEpochSecond();
|
data.lastLogin = Instant.now().getEpochSecond();
|
||||||
@ -202,17 +192,6 @@ public class PlayerTimeTracker {
|
|||||||
PlayerTimeMod.LOGGER.info("[在线时间] 开始保存所有玩家数据...");
|
PlayerTimeMod.LOGGER.info("[在线时间] 开始保存所有玩家数据...");
|
||||||
JsonObject root = new JsonObject();
|
JsonObject root = new JsonObject();
|
||||||
playerData.forEach((uuid, data) -> {
|
playerData.forEach((uuid, data) -> {
|
||||||
if (data.lastLogin > 0) {
|
|
||||||
long now = Instant.now().getEpochSecond();
|
|
||||||
long sessionTime = now - data.lastLogin;
|
|
||||||
if (sessionTime > 0) {
|
|
||||||
data.totalTime += sessionTime;
|
|
||||||
data.rolling30Days.addPlayTime(now, sessionTime);
|
|
||||||
data.rolling7Days.addPlayTime(now, sessionTime);
|
|
||||||
PlayerTimeMod.LOGGER.debug("[在线时间] 累积当前会话时间 {} 秒,保存期间玩家 {}", sessionTime, getPlayerName(uuid));
|
|
||||||
}
|
|
||||||
data.lastLogin = 0;
|
|
||||||
}
|
|
||||||
root.add(uuid.toString(), GSON.toJsonTree(data));
|
root.add(uuid.toString(), GSON.toJsonTree(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -254,7 +233,6 @@ public class PlayerTimeTracker {
|
|||||||
|
|
||||||
try (Writer writer = Files.newBufferedWriter(dataFile)) {
|
try (Writer writer = Files.newBufferedWriter(dataFile)) {
|
||||||
GSON.toJson(root, writer);
|
GSON.toJson(root, writer);
|
||||||
// PlayerTimeMod.LOGGER.debug("[在线时间] Async save successful for player {}", getPlayerName(uuid));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
PlayerTimeMod.LOGGER.error("[在线时间] 无法异步保存玩家的在线时间数据 " + getPlayerName(uuid) + " (UUID: " + uuid + ")", e);
|
PlayerTimeMod.LOGGER.error("[在线时间] 无法异步保存玩家的在线时间数据 " + getPlayerName(uuid) + " (UUID: " + uuid + ")", e);
|
||||||
}
|
}
|
||||||
@ -325,5 +303,4 @@ public class PlayerTimeTracker {
|
|||||||
public Path getDataFile() {
|
public Path getDataFile() {
|
||||||
return this.dataFile;
|
return this.dataFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
BIN
src/main/resources/assets/playertime/web/favicon.ico
Normal file
BIN
src/main/resources/assets/playertime/web/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -6,6 +6,7 @@
|
|||||||
<title data-lang-key="playertime.web.title">玩家在线及状态统计</title>
|
<title data-lang-key="playertime.web.title">玩家在线及状态统计</title>
|
||||||
<link rel="stylesheet" href="css/style.css">
|
<link rel="stylesheet" href="css/style.css">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user