RRRRRRRRRRRRRRRR

This commit is contained in:
BRanulf 2025-07-17 09:19:51 +08:00
parent e5eca44059
commit 245103cf44
30 changed files with 680 additions and 157 deletions

103
README.md
View File

@ -1,24 +1,87 @@
# 一个服务器在线玩家时间以及服务器状态的简单的mod ## 简体中文
[English](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README_EN.md) [English](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README_EN.md)
注意本mod并不完善可能会存在些许的bug # ServerPlayerOnlineTracker - 服务器玩家在线及状态追踪
### 包含功能:
* 显示/记录服务器在线玩家时间
* 显示服务器状态
* 显示服务器在线玩家列表
* ~~移除游戏中的Herobrine~~
### 使用方法: 一个简单的 Fabric 服务器端 Mod用于追踪玩家在线时长、显示服务器实时状态并提供一个美观的网页界面。
1. 安装Fabric Loader和Fabric API
2. 将最新版本的mod放入mods文件夹
3. 首次启动服务器自动生成配置文件
4. 修改Web服务器端口(默认60048),语言(目前仅支持zh_cn和en_us),自动保存时间(默认300秒)
5. 如需在外部访问请确保端口已开放
### API获取数据 ## 主要功能
*(也许可以用于机器人?)*
* 获取服务器在线玩家列表【服务器IP+配置的端口】+`/api/online-players` * **玩家在线时长追踪**
* 获取服务器状态【服务器IP+配置的端口】+`/api/server-status` * 记录玩家总在线时长、最近30天和最近7天的在线时长。
* 获取服务器在线玩家时间【服务器IP+配置的端口】+`/api/stats` * 支持仅追踪白名单玩家(可在配置文件中设置)。
* 获取服务器在线玩家数量【服务器IP+配置的端口】+`/api/player-count` * 数据自动保存,防止服务器崩溃导致数据丢失。
* ~~原始数据文件【服务器IP+配置的端口】+`/api/playerdata`~~ * **服务器状态监控**
* 实时显示服务器内存使用情况(已用/可用/使用率)。
* 实时显示服务器磁盘使用情况(总量/已用/可用/使用率)。
* 实时显示服务器性能指标TPS/MSPT
* 显示服务器运行时间、版本、在线玩家数、最大玩家数、MOTD、处理器核心数。
* **网页界面**
* 提供一个直观、响应式的网页界面,方便查看所有统计数据。
* 支持深色/浅色主题切换。
* 数据自动刷新。
* **游戏内命令**
* `/onlineTime [页码]`:在游戏内查看玩家在线时长排行榜。
* **多语言支持**
* 支持简体中文 (`zh_cn`) 和英文 (`en_us`)。
* 可在配置文件中切换语言。
* **更新检查**
* Mod 启动时自动检查新版本。
## 安装
1. 确保您的 Minecraft 服务器已安装 Fabric Loader (推荐 0.15.0+)。
2. 下载最新版本的 `ServerPlayerOnlineTracker-*.jar` 文件。
3. 将下载的 `.jar` 文件放入服务器的 `mods` 文件夹。
4. 启动服务器。
## 使用方法
### 网页界面
Mod 启动后,会自动在您配置的端口(默认 `60048`)启动一个 Web 服务器。
1. 在浏览器中访问 `http://您的服务器IP:60048` 即可查看所有统计数据。
2. 如果端口被占用或您想更改端口,请修改 `config/playertime-config.json` 文件中的 `webPort` 字段。
### 游戏内命令
* `/onlineTime`:查看第一页玩家在线时长排行榜。
* `/onlineTime <页码>`:查看指定页码的玩家在线时长排行榜。
## 配置文件
首次运行 Mod 后,会在服务器根目录的 `config` 文件夹下生成一个 `playertime-config.json` 文件。您可以编辑此文件来调整 Mod 的行为。
```json
{
"webPort": 60048, // 网页服务器监听的端口,默认 60048
"language": "zh_cn", // 网页和游戏内消息的语言,可选 "zh_cn" 或 "en_us"
"whitelistOnly": true, // 是否只追踪和显示白名单玩家的在线时间,默认 true
"saveIntervalMinutes": 5 // 自动保存玩家数据的时间间隔(分钟),默认 5 分钟,设置为 0 禁用
}
```
## API
[API文档](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README_API.md)
## 兼容性
* **Minecraft 版本:** 1.21.4+
* **Fabric Loader:** 0.16.10+
* **依赖:** Fabric API
## 许可证
本项目基于 [GPL3 许可证](https://www.gnu.org/licenses/gpl-3.0.en.html) 开源。
## 链接
* **源代码:** [https://git.branulf.top/Branulf/ServerPlayerOnlineTracker](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker)
* **主页:** [https://git.branulf.top/Branulf](https://git.branulf.top/Branulf)
## 鸣谢
* **作者:** BRanulf

230
README_API.md Normal file
View File

@ -0,0 +1,230 @@
### 可用 API 接口
本 Mod 提供了一系列 RESTful API 接口,允许外部应用获取服务器的玩家在线数据和实时状态。所有 API 接口均通过 HTTP GET 请求访问。
**基础 URL:** `http://您的服务器IP:配置的端口` (默认端口为 `60048`)
---
#### `GET /api/stats`
* **描述:** 获取所有玩家的在线时长统计数据。
* **响应:** JSON 数组,每个元素代表一个玩家的统计信息。
* **响应示例结构:**
```json
[
{
"playerName": "玩家名称",
"uuid": "114514-1919810",
"totalTimeSeconds": 123456,
"totalTimeFormatted": "34h 17m",
"last30DaysSeconds": 54321,
"last30DaysFormatted": "15h 05m",
"last7DaysSeconds": 9876,
"last7DaysFormatted": "02h 44m"
}
// ... 更多玩家
]
```
* **字段说明:**
* `playerName` (String): 玩家名称。
* `uuid` (String): 玩家的 UUID。
* `totalTimeSeconds` (long): 总在线时长(秒)。
* `totalTimeFormatted` (String): 总在线时长(格式化字符串,例如 "34h 17m")。
* `last30DaysSeconds` (long): 最近 30 天在线时长(秒)。
* `last30DaysFormatted` (String): 最近 30 天在线时长(格式化字符串)。
* `last7DaysSeconds` (long): 最近 7 天在线时长(秒)。
* `last7DaysFormatted` (String): 最近 7 天在线时长(格式化字符串)。
---
#### `GET /api/lang`
* **描述:** 获取 Mod 当前加载的本地化语言字符串。
* **注意:** 此接口主要用于内部调试和网页前端加载语言,不建议公开暴露。
* **响应:** JSON 对象,键为语言字符串的 key值为对应的翻译文本。
* **响应示例结构:**
```json
{
"playertime.command.title": "§6===== 玩家在线时长 (第 {0}/{1} 页) =====",
"playertime.web.title": "玩家在线及状态统计",
// ... 更多语言键值对
}
```
---
#### `GET /api/online-players`
* **描述:** 获取当前在线玩家的列表,按白名单状态分类。
* **响应:** JSON 对象,包含两个列表:`whitelisted``non_whitelisted`
* **响应示例结构:**
```json
{
"whitelisted": [
{
"name": "WhitelistedPlayer1",
"uuid": "114514-1919810"
}
],
"non_whitelisted": [
{
"name": "NonWhitelistedPlayer1",
"uuid": "51121-55555121"
}
]
}
```
* **字段说明:**
* `whitelisted` (List<Map<String, String>>): 白名单在线玩家列表。每个 Map 包含 `name` (玩家名称) 和 `uuid` (玩家 UUID)。
* `non_whitelisted` (List<Map<String, String>>): 非白名单在线玩家列表。每个 Map 包含 `name` (玩家名称) 和 `uuid` (玩家 UUID)。
---
#### `GET /api/player-count`
* **描述:** 获取当前在线玩家的数量统计。
* **响应:** JSON 对象,包含总数、白名单玩家数和非白名单玩家数。
* **响应示例结构:**
```json
{
"total": 10,
"whitelisted": 8,
"non_whitelisted": 2
}
```
* **字段说明:**
* `total` (int): 在线玩家总数。
* `whitelisted` (int): 在线白名单玩家数。
* `non_whitelisted` (int): 在线非白名单玩家数(通常指假人或未在白名单的玩家)。
---
#### `GET /api/whitelist`
* **描述:** 获取服务器的白名单列表。
* **响应:** JSON 数组,每个元素代表一个白名单玩家的信息。
* **响应示例结构:**
```json
[
{
"name": "BRanulf",
"uuid": "114514-1919810",
"online": true
},
{
"name": "DarkSharkBee",
"uuid": "51121-55555121",
"online": false
}
// ... 更多白名单玩家
]
```
* **字段说明:**
* `name` (String): 白名单玩家名称。
* `uuid` (String): 白名单玩家的 UUID。
* `online` (boolean): 该玩家当前是否在线。
---
#### `GET /api/server-status`
* **描述:** 获取服务器的详细运行状态信息。
* **响应:** JSON 对象,包含内存、磁盘、处理器、运行时间及服务器自身信息。
* **响应示例结构:**
```json
{
"memory": {
"max": 8589934592,
"total": 8589934592,
"used": 2147483648,
"free": 6442450944,
"usage_percentage": 25.0
},
"disk": {
"total": 1073741824000,
"free": 536870912000,
"usable": 536870912000,
"usage_percentage": 50.0
},
"available_processors": 8,
"uptime": 3600,
"uptime_formatted": "01小时 00分钟 00秒",
"server": {
"version": "1.21.4",
"motd": "§aWelcome to My Server!",
"player_count": 5,
"max_players": 20,
"average_tick_time_ms": 15.23,
"recent_tick_samples_ms": [14.5, 16.1, 15.0, 15.8, ...]
}
}
```
* **字段说明:**
* `memory` (Object): 内存统计信息。
* `max` (long): JVM 可用的最大内存(字节)。
* `total` (long): JVM 当前分配的总内存(字节)。
* `used` (long): JVM 已使用的内存(字节)。
* `free` (long): JVM 可用的空闲内存(字节)。
* `usage_percentage` (double): 内存使用率(已用 / 最大 * 100
* `disk` (Object): 磁盘统计信息。
* `total` (long): 磁盘总空间(字节)。
* `free` (long): 磁盘空闲空间(字节)。
* `usable` (long): 磁盘可用空间(字节)。
* `usage_percentage` (double): 磁盘使用率((总 - 空闲) / 总 * 100
* `available_processors` (int): 服务器可用的处理器核心数。
* `uptime` (long): 服务器运行时间(秒)。
* `uptime_formatted` (String): 服务器运行时间(格式化字符串,例如 "01小时 00分钟 00秒")。
* `server` (Object): Minecraft 服务器自身信息。
* `version` (String): Minecraft 服务器版本。
* `motd` (String): 服务器 MOTD。
* `player_count` (int): 当前在线玩家数。
* `max_players` (int): 服务器最大玩家容量。
* `average_tick_time_ms` (double): 服务器平均 Tick 时间(毫秒,即 MSPT
* `recent_tick_samples_ms` (List<Double>): 最近的 Tick 时间样本(毫秒)。
---
#### `GET /api/playerdata`
* **描述:** 获取原始的玩家在线时间数据文件内容。
* **警告:** 此接口直接暴露服务器的玩家数据文件内容,包含 UUID 和在线时间等敏感信息。**强烈建议不要将此接口公开暴露给外部网络。**
* **响应:** JSON 对象,内容与 `player_time_data.json` 文件完全一致。
* **响应示例结构:**
```json
{
"114514-1919810": {
"totalTime": 123456,
"lastLogin": 0, // 0 表示离线,非 0 表示上次登录时间戳
"rolling30Days": {
"days": 30,
"entries": [
{ "timestamp": 1678886400, "seconds": 3600 },
// ...
]
},
"rolling7Days": {
"days": 7,
"entries": [
{ "timestamp": 1678886400, "seconds": 1800 },
// ...
]
}
},
"51121-55555121": {
// ...
}
}
```

View File

@ -1,24 +1,87 @@
# A simple mod for tracking online player time and server status ## English
[中文简体](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README.md) [中文简体](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README.md)
Note: This mod is not perfect and may have some bugs. # ServerPlayerOnlineTracker - Server Player Online & Status Tracker
### Features include:
* Display/record server online player time
* Show server status
* Display a list of online players on the server
* ~~Remove Herobrine from the game~~
### How to use: A simple Fabric server-side mod designed to track player online time, display real-time server status, and provide a beautiful web interface.
1. Install Fabric Loader and Fabric API.
2. Place the latest version of the mod into the mods folder.
3. The configuration file will be generated automatically when starting the server for the first time.
4. Modify the web server port (default 60048), language (currently only supports zh_cn and en_us), and automatic save interval (default 300 seconds).
5. If external access is needed, ensure that the port is open.
### API data retrieval: ## Key Features
*(Maybe can be used for bots?)*
* Get a list of online players on the server: [Server IP + configured port] + `/api/online-players` * **Player Online Time Tracking**
* Get server status: [Server IP + configured port] + `/api/server-status` * Records total online time, last 30 days, and last 7 days online time for players.
* Get online player time on the server: [Server IP + configured port] + `/api/stats` * Supports tracking whitelisted players only (configurable in the config file).
* Get number of online players on the server: [Server IP + configured port] + `/api/player-count` * Automatic data saving to prevent data loss from server crashes.
* ~~Raw data file: [Server IP + configured port] + `/api/playerdata`~~ * **Server Status Monitoring**
* Real-time display of server memory usage (used/available/percentage).
* Real-time display of server disk usage (total/used/available/percentage).
* Real-time display of server performance metrics (TPS/MSPT).
* Shows server uptime, version, current player count, max players, MOTD, and processor cores.
* **Web Interface**
* Provides an intuitive and responsive web interface for easy viewing of all statistics.
* Supports dark/light theme toggling.
* Automatic data refresh.
* **In-Game Command**
* `/onlineTime [page]` to view the player online time leaderboard in-game.
* **Multi-language Support**
* Supports Simplified Chinese (`zh_cn`) and English (`en_us`).
* Language can be switched in the configuration file.
* **Update Checker**
* Automatically checks for new mod versions on startup.
## Installation
1. Ensure you have Fabric Loader installed on your Minecraft server (recommended 0.15.0+).
2. Download the latest `ServerPlayerOnlineTracker-*.jar` file.
3. Place the downloaded `.jar` file into your server's `mods` folder.
4. Start your server.
## Usage
### Web Interface
After the mod starts, a web server will automatically launch on your configured port (default `60048`).
1. Access it in your browser by navigating to `http://YOUR_SERVER_IP:60048` to view all statistics.
2. If the port is occupied or you wish to change it, modify the `webPort` field in the `config/playertime-config.json` file.
### In-Game Command
* `/onlineTime`: View the first page of the player online time leaderboard.
* `/onlineTime <page>`: View a specific page of the player online time leaderboard.
## Configuration
Upon the first run of the mod, a `playertime-config.json` file will be generated in your server's `config` folder. You can edit this file to adjust the mod's behavior.
```json
{
"webPort": 60048, // Port for the web server to listen on, default 60048
"language": "zh_cn", // Language for web and in-game messages, options: "zh_cn" or "en_us"
"whitelistOnly": true, // Whether to track and display online time only for whitelisted players, default true
"saveIntervalMinutes": 5 // Interval for automatic player data saving in minutes, default 5 minutes, set to 0 to disable
}
```
## API
[API Documentation](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker/src/branch/master/README_API.md)
## Compatibility
* **Minecraft Version:** 1.21.4+
* **Fabric Loader:** 0.16.10+
* **Dependencies:** Fabric API
## License
This project is open-source under the [GPL3 License](https://www.gnu.org/licenses/gpl-3.0.en.html).
## Links
* **Source Code:** [https://git.branulf.top/Branulf/ServerPlayerOnlineTracker](https://git.branulf.top/Branulf/ServerPlayerOnlineTracker)
* **Homepage:** [https://git.branulf.top/Branulf](https://git.branulf.top/Branulf)
## Credits
* **Author:** BRanulf

View File

@ -1,96 +1,46 @@
plugins { plugins {
id 'fabric-loom' version '1.9.2' id 'fabric-loom' version '1.10.5' apply false
id 'maven-publish' id 'com.replaymod.preprocess' version '9d21b334a7'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
} }
version = project.mod_version version = project.mod_version
group = project.maven_group group = project.maven_group
base { preprocess {
archivesName = project.archives_base_name strictExtraMappings.set(false)
def mc12104 = createNode("1.21.4", 1_21_04, "")
def mc12105 = createNode("1.21.5", 1_21_05, "")
def mc12106 = createNode("1.21.6", 1_21_06, "")
def mc12107 = createNode("1.21.7", 1_21_07, "")
mc12107.link(mc12106, file("versions/mapping_12107_12106.txt"))
mc12106.link(mc12105, file("versions/mapping_12106_12105.txt"))
mc12105.link(mc12104, file("versions/mapping_12105_12104.txt"))
} }
tasks.register('buildAndGather') {
repositories { subprojects {
// Add repositories to retrieve artifacts from in here. dependsOn project.tasks.named('build').get()
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
}
dependencies {
// To change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
implementation 'com.google.code.gson:gson:2.8.9'
}
processResources {
inputs.property "version", project.version
inputs.property "minecraft_version", project.minecraft_version
inputs.property "loader_version", project.loader_version
filteringCharset "UTF-8"
filesMatching("fabric.mod.json") {
expand "version": project.version,
"minecraft_version": project.minecraft_version,
"loader_version": project.loader_version
} }
doFirst {
// from(sourceSets.main.resources.srcDirs) { println 'Gathering builds'
// include "assets/**" def buildLibs = {
// } p -> p.buildDir.toPath().resolve('libs')
} }
delete fileTree(buildLibs(rootProject)) {
def targetJavaVersion = 21 include '*'
tasks.withType(JavaCompile).configureEach { }
// ensure that the encoding is set to UTF-8, no matter what the system default is subprojects {
// this fixes some edge cases with special characters not displaying correctly copy {
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html from(buildLibs(project)) {
// If Javadoc is generated, this must be specified in that task too. include '*.jar'
it.options.encoding = "UTF-8" exclude '*-dev.jar', '*-sources.jar', '*-shadow.jar'
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { }
it.options.release.set(targetJavaVersion) into buildLibs(rootProject)
} duplicatesStrategy DuplicatesStrategy.INCLUDE
} }
java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
if (JavaVersion.current() < javaVersion) {
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
}
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar()
}
jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}" }
}
}
// configure the maven publication
publishing {
publications {
create("mavenJava", MavenPublication) {
artifactId = project.archives_base_name
from components.java
} }
} }
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
// Notice: This block does NOT have the same function as the block in the top level.
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
} }

144
common.gradle Normal file
View File

@ -0,0 +1,144 @@
apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'fabric-loom'
apply plugin: 'com.replaymod.preprocess'
int mcVersion = project.mcVersion
repositories {
maven {
url 'https://maven.fabricmc.net/'
}
maven {
url 'https://masa.dy.fi/maven'
}
maven {
url 'https://maven.fallenbreath.me/releases'
}
maven {
url 'https://jitpack.io'
}
maven {
url 'https://www.cursemaven.com'
}
maven { url "https://maven.shedaniel.me/" }
maven {url "https://maven.terraformersmc.com/"}
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}" //
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" //
modImplementation "net.fabricmc:fabric-loader:${rootProject.loader_version}" //
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
implementation 'com.google.code.gson:gson:2.8.9'
}
JavaVersion JAVA_COMPATIBILITY
if (mcVersion >= 12100) {
JAVA_COMPATIBILITY = JavaVersion.VERSION_21
} else if (mcVersion >= 11800) {
JAVA_COMPATIBILITY = JavaVersion.VERSION_17
} else if (mcVersion >= 11700) {
JAVA_COMPATIBILITY = JavaVersion.VERSION_16
} else {
JAVA_COMPATIBILITY = JavaVersion.VERSION_1_8
}
JavaVersion MIXIN_COMPATIBILITY_LEVEL = JAVA_COMPATIBILITY
loom {
def commonVmArgs = ['-Dmixin.debug.export=true']
runConfigs.configureEach {
runDir '../../run'
vmArgs commonVmArgs
ideConfigGenerated true
}
}
shadowJar {
configurations = [project.configurations.shadow]
exclude("META-INF")
archiveClassifier.set('shadow')
}
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
tasks.withType(ShadowJar).configureEach {
enableRelocation true
relocationPrefix 'branulf.playertime.libs'
}
remapJar {
dependsOn(shadowJar)
mustRunAfter(shadowJar)
inputFile = shadowJar.archiveFile
}
String modVersionSuffix = ''
if (System.getenv("BUILD_RELEASE") != "true") {
String buildNumber = System.getenv("BUILD_ID")
modVersionSuffix += buildNumber != null ? ('+build.' + buildNumber) : ''
}
String fullModVersion = rootProject.mod_version + modVersionSuffix
String fullProjectVersion
group = rootProject.maven_group
if (System.getenv("JITPACK") == "true") {
base.archivesName = rootProject.archives_base_name + '-mc' + project.minecraft_version
fullProjectVersion = 'v' + rootProject.mod_version + modVersionSuffix
} else {
base.archivesName = rootProject.archives_base_name
fullProjectVersion = 'v' + rootProject.mod_version + '-mc' + project.minecraft_version + modVersionSuffix
}
version = fullProjectVersion
processResources {
inputs.property "id", rootProject.mod_id
inputs.property "name", rootProject.mod_name
inputs.property "version", fullModVersion
filesMatching("fabric.mod.json") {
def valueMap = [
"id" : rootProject.mod_id,
"name" : rootProject.mod_name,
"version" : fullModVersion,
"minecraft_version": project.minecraft_dependency,
"loader_version" : rootProject.loader_version
]
expand valueMap
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.compilerArgs << "-Xlint:deprecation" << "-Xlint:unchecked"
if (JAVA_COMPATIBILITY <= JavaVersion.VERSION_1_8) {
options.compilerArgs << '-Xlint:-options'
}
}
java {
sourceCompatibility = JAVA_COMPATIBILITY
targetCompatibility = JAVA_COMPATIBILITY
withSourcesJar()
}
jar {
from(rootProject.file('LICENSE')) {
rename { "${it}_${rootProject.archives_base_name}" }
}
}
//publishing {
// publications {
// mavenJava(MavenPublication) {
// from components.java
// }
// }
// repositories {
// }
//}

View File

@ -6,7 +6,9 @@ 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.141 mod_name=Disc Jockey Revive
mod_id=disc_jockey_revive
mod_version=1.14.514.144
maven_group=org.example1 maven_group=org.example1
archives_base_name=ServerPlayerOnlineTracker archives_base_name=ServerPlayerOnlineTracker
# Dependencies # Dependencies

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.11.1-bin.zip distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.12.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -1,9 +1,35 @@
import groovy.json.JsonSlurper
pluginManagement { pluginManagement {
repositories { repositories {
maven { maven {
name = 'Fabric' name = 'Fabric'
url = 'https://maven.fabricmc.net/' url = 'https://maven.fabricmc.net/'
} }
maven {
name = 'Jitpack'
url = 'https://jitpack.io'
}
mavenCentral()
gradlePluginPortal() gradlePluginPortal()
} }
resolutionStrategy {
eachPlugin {
switch (requested.id.id) {
case "com.replaymod.preprocess": {
useModule("com.github.Fallen-Breath:preprocessor:${requested.version}")
break
}
}
}
}
}
def settings = new JsonSlurper().parseText(file('settings.json').text)
for (String version : settings.versions) {
include(":$version")
def proj = project(":$version")
proj.projectDir = file("versions/$version")
proj.buildFileName = "../../common.gradle"
} }

8
settings.json Normal file
View File

@ -0,0 +1,8 @@
{
"versions": [
"1.21.4",
"1.21.5",
"1.21.6",
"1.21.7"
]
}

View File

@ -1,6 +1,5 @@
package com.example.playertime; package org.branulf.playertime;
import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
@ -12,7 +11,7 @@ import java.text.MessageFormat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
// 这个是gemini写的 (保留原注释但代码已根据需求调整) // 这个是AI写的 (保留原注释但代码已根据需求调整)
public class LocalizationManager { public class LocalizationManager {
private final Map<String, String> translations = new HashMap<>(); private final Map<String, String> translations = new HashMap<>();
private final String defaultLanguage = "zh_cn"; // 默认语言代码 private final String defaultLanguage = "zh_cn"; // 默认语言代码

View File

@ -1,4 +1,4 @@
package com.example.playertime; package org.branulf.playertime;
import com.google.gson.*; import com.google.gson.*;
import java.io.*; import java.io.*;

View File

@ -1,4 +1,4 @@
package com.example.playertime; package org.branulf.playertime;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
@ -26,12 +26,10 @@ import org.w3c.dom.NodeList;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class PlayerTimeMod implements ModInitializer { public class PlayerTimeMod implements ModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("PlayerTimeTracker"); public static final Logger LOGGER = LoggerFactory.getLogger("PlayerTimeTracker");
@ -223,11 +221,18 @@ public class PlayerTimeMod implements ModInitializer {
MutableText footer = Text.literal(""); MutableText footer = Text.literal("");
if (currentPage > 1) { if (currentPage > 1) {
//#if MC >= 12105
//$ footer.append(Text.literal(localizationManager.getString("playertime.command.prev_page"))
//$ .styled(style -> style.withClickEvent(new ClickEvent.RunCommand(
//$ "/onlineTime " + (currentPage - 1)
//$ )).withColor(Formatting.GREEN)));
//#else
footer.append(Text.literal(localizationManager.getString("playertime.command.prev_page")) footer.append(Text.literal(localizationManager.getString("playertime.command.prev_page"))
.styled(style -> style.withClickEvent(new ClickEvent( .styled(style -> style.withClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND, ClickEvent.Action.RUN_COMMAND,
"/onlineTime " + (currentPage - 1) "/onlineTime " + (currentPage - 1)
)).withColor(Formatting.GREEN))); )).withColor(Formatting.GREEN)));
//#endif
} }
if (currentPage > 1 && currentPage < totalPages) { if (currentPage > 1 && currentPage < totalPages) {
@ -240,11 +245,18 @@ public class PlayerTimeMod implements ModInitializer {
if (currentPage > 1 || totalEntries > 0) { if (currentPage > 1 || totalEntries > 0) {
footer.append(" "); footer.append(" ");
} }
//#if MC >= 12105
//$ footer.append(Text.literal(localizationManager.getString("playertime.command.next_page"))
//$ .styled(style -> style.withClickEvent(new ClickEvent.RunCommand(
//$ "/onlineTime " + (currentPage + 1)
//$ )).withColor(Formatting.GREEN)));
//#else
footer.append(Text.literal(localizationManager.getString("playertime.command.next_page")) footer.append(Text.literal(localizationManager.getString("playertime.command.next_page"))
.styled(style -> style.withClickEvent(new ClickEvent( .styled(style -> style.withClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND, ClickEvent.Action.RUN_COMMAND,
"/onlineTime " + (currentPage + 1) "/onlineTime " + (currentPage + 1)
)).withColor(Formatting.GREEN))); )).withColor(Formatting.GREEN)));
//#endif
} }
player.sendMessage(footer, false); player.sendMessage(footer, false);

View File

@ -1,4 +1,4 @@
package com.example.playertime; package org.branulf.playertime;
import com.google.gson.*; import com.google.gson.*;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -14,7 +14,6 @@ import java.nio.file.Path;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class PlayerTimeTracker { public class PlayerTimeTracker {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

View File

@ -1,18 +1,14 @@
package com.example.playertime; package org.branulf.playertime;
import com.google.gson.*; import com.google.gson.*;
import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import java.io.*; import java.io.*;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.*; import java.nio.file.*;
import java.util.*; import java.util.*;
@ -20,11 +16,11 @@ import java.util.concurrent.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
// 导入API类别忘了 // 导入API类别忘了
import com.example.playertime.api.PlayerStatsResponse; import org.branulf.playertime.api.PlayerStatsResponse;
import com.example.playertime.api.ServerStatusResponse; import org.branulf.playertime.api.ServerStatusResponse;
import com.example.playertime.api.OnlinePlayersResponse; import org.branulf.playertime.api.OnlinePlayersResponse;
import com.example.playertime.api.PlayerCountResponse; import org.branulf.playertime.api.PlayerCountResponse;
import com.example.playertime.api.WhitelistResponse; import org.branulf.playertime.api.WhitelistResponse;
public class WebServer { public class WebServer {

View File

@ -1,4 +1,4 @@
package com.example.playertime.api; package org.branulf.playertime.api;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package com.example.playertime.api; package org.branulf.playertime.api;
// 用于 /api/player-count 接口返回的玩家数量数据结构 // 用于 /api/player-count 接口返回的玩家数量数据结构
public class PlayerCountResponse { public class PlayerCountResponse {

View File

@ -1,4 +1,4 @@
package com.example.playertime.api; package org.branulf.playertime.api;
// 用于 /api/stats 接口返回的玩家统计数据结构 // 用于 /api/stats 接口返回的玩家统计数据结构
public class PlayerStatsResponse { public class PlayerStatsResponse {

View File

@ -1,4 +1,4 @@
package com.example.playertime.api; package org.branulf.playertime.api;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package com.example.playertime.api; package org.branulf.playertime.api;
// 用于 /api/whitelist 接口返回的白名单列表数据结构 // 用于 /api/whitelist 接口返回的白名单列表数据结构
public class WhitelistResponse { public class WhitelistResponse {

View File

@ -1,5 +1,6 @@
{ {
"webPort": 60048, "webPort": 60048,
"language": "zh_cn", "language": "zh_cn",
"autoSaveSeconds": 60 "whitelistOnly": true,
} "saveIntervalMinutes": 5
}

View File

@ -16,12 +16,9 @@
"environment": "server", "environment": "server",
"entrypoints": { "entrypoints": {
"main": [ "main": [
"com.example.playertime.PlayerTimeMod" "org.branulf.playertime.PlayerTimeMod"
] ]
}, },
"mixins": [
"playertime.mixins.json"
],
"depends": { "depends": {
"fabricloader": ">=${loader_version}", "fabricloader": ">=${loader_version}",
"fabric": "*", "fabric": "*",

View File

@ -1,6 +1,6 @@
{ {
"required": true, "required": true,
"package": "com.example.playertime.mixins", "package": "org.branulf.playertime.mixins",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -0,0 +1,8 @@
minecraft_version=1.21.4
yarn_mappings=1.21.4+build.8
minecraft_dependency=1.21.4
game_versions=1.21.4
fabric_api_version=0.119.2+1.21.4

View File

@ -0,0 +1,8 @@
minecraft_version=1.21.5
yarn_mappings=1.21.5+build.1
minecraft_dependency=1.21.5
game_versions=1.21.5
fabric_api_version=0.119.5+1.21.5

View File

@ -0,0 +1,8 @@
minecraft_version=1.21.6
yarn_mappings=1.21.6+build.1
minecraft_dependency=1.21.6
game_versions=1.21.6
fabric_api_version=0.127.0+1.21.6

View File

@ -0,0 +1,8 @@
minecraft_version=1.21.7
yarn_mappings=1.21.7+build.7
minecraft_dependency=1.21.7
game_versions=1.21.7
fabric_api_version=0.128.1+1.21.7

1
versions/mainProject Normal file
View File

@ -0,0 +1 @@
1.21.4

View File

View File

View File