自定义玩家数据

自定义玩家数据

对Minecraft服务器有用的模组或模组开发者的框架。

管理

自定义玩家数据

版本 加载器 状态

Fabric 框架 1.20.6,用于管理持久化且同步的玩家数据。

此模组允许你定义附加到每个玩家的自定义变量,这些变量保存在 Minecraft 原生的 player.dat 文件中,并在服务器与客户端之间自动同步。


功能

  • JSON Schema:在自动生成于地图文件夹中的 player_data_schema.json 文件里定义你的变量。
  • 原生持久化:数据通过 Mixin 直接存储在 player.dat 中——零数据丢失,即使崩溃后也不会丢失。
  • 自动同步:所有变量在连接时以及每次变更时发送到客户端(非常适合 HUD)。
  • 开发者 API:可被其他模组作为依赖项使用,以编程方式注入和操作变量。
  • 自定义类型:创建你自己的复杂数据类型(例如 PowerSkillQuest……)。
  • 管理员命令/playerdata get/playerdata set,供管理员使用。
  • 校验int 的最小/最大值、空值检查、运行时类型验证。

面向服务器管理员

安装

  1. .jar 文件放入你的 Fabric 1.20.6 服务器的 mods/ 文件夹中。
  2. 首次启动服务器——player_data_schema.json 文件将在你的世界文件夹中生成(与 level.dat 相邻)。
  3. 根据需要修改 JSON,然后重启。

JSON Schema 格式

{
  "note": {
    "type": "int",
    "defaultValue": 0,
    "maxValue": 5,
    "minValue": 0,
    "null": false
  },
  "hudColor": {
    "type": "string",
    "defaultValue": "light_blue",
    "null": false
  },
  "powers": {
    "type": "Power",
    "array": true,
    "defaultValue": null,
    "null": true
  }
}
参数 描述 必需
type intstringboolean 或已注册的自定义类型
defaultValue 新玩家的默认值
maxValue 最大值(仅 int 类型)
minValue 最小值(仅 int 类型)
null 允许 null(默认为 false
array 该变量为数组(默认为 false

重要:如果某个变量设置为 "null": false 且没有 defaultValue,启动时将记录错误。

命令

命令 描述 权限
/playerdata get <variable> <joueur> 显示当前值 OP 等级 2+
/playerdata set <variable> <joueur> <valeur> 修改值(仅限原始类型) OP 等级 2+

示例:

/playerdata get note Steve
/playerdata set hudColor Steve red
/playerdata set note Steve 3

开发者指南——将自定义玩家数据用作 API

1. 添加依赖项

在你的 build.gradle 文件中,将该 JAR 添加为本地依赖项(或者如果已发布,则通过 Maven 仓库):

dependencies {
    // 添加这一项
    modImplementation files("libs/custom-player-data-1.0.0.jar")
}

在你的 fabric.mod.json 文件中,添加以下依赖项:

{
  "depends": {
    "custom-player-data": ">=1.0.0"
  }
}

2. 创建自定义类型(可选)

如果你需要存储复杂数据,请实现 ICustomDataType

package com.myMod.data;

import fr.hdi.api.ICustomDataType;
import net.minecraft.nbt.NbtCompound;

public class Skill implements ICustomDataType {

    private String name = "";
    private int xp = 0;
    private boolean unlocked = false;

    public Skill() {}

    public Skill(String name, int xp, boolean unlocked) {
        this.name = name;
        this.xp = xp;
        this.unlocked = unlocked;
    }

    @Override
    public void writeNbt(NbtCompound nbt) {
        nbt.putString("name", name);
        nbt.putInt("xp", xp);
        nbt.putBoolean("unlocked", unlocked);
    }

    @Override
    public void readNbt(NbtCompound nbt) {
        this.name = nbt.getString("name");
        this.xp = nbt.getInt("xp");
        this.unlocked = nbt.getBoolean("unlocked");
    }

    public String getName() { return name; }
    public int getXp() { return xp; }
    public boolean isUnlocked() { return unlocked; }
    public void setXp(int xp) { this.xp = xp; }
    public void setUnlocked(boolean unlocked) { this.unlocked = unlocked; }

    @Override
    public String toString() {
        return "Skill{" + name + ", xp=" + xp + ", unlocked=" + unlocked + "}";
    }
}

3. 注册你的类型和变量

在你的模组的 onInitialize() 方法中:

package com.myMod;

import com.myMod.data.Skill;
import fr.hdi.api.TypeRegistry;
import fr.hdi.schema.SchemaManager;
import fr.hdi.schema.VariableDefinition;
import net.fabricmc.api.ModInitializer;

public class myMod implements ModInitializer {

    @Override
    public void onInitialize() {
        // 1. 注册自定义类型
        TypeRegistry.register("Skill", Skill::new);

        // 2. 注册所有可能的变量 schema
        SchemaManager.registerVariable(
            VariableDefinition.builder("level", "int")
                .defaultValue(1)
                .minValue(1)
                .maxValue(100)
                .build()
        );

        SchemaManager.registerVariable(
            VariableDefinition.builder("clan", "string")
                .defaultValue("none")
                .build()
        );

        SchemaManager.registerVariable(
            VariableDefinition.builder("hasCompletedTutorial", "boolean")
                .defaultValue(false)
                .build()
        );

        SchemaManager.registerVariable(
            VariableDefinition.builder("skills", "Skill")
                .array(true)
                .nullable(true)
                .defaultNull()
                .build()
        );
    }
}

4. 读取和写入玩家数据

使用 PlayerDataStore 从服务器代码中的任何位置访问数据:

import fr.hdi.api.PlayerDataStore;
import net.minecraft.server.network.ServerPlayerEntity;

// 读取经典类型
int level = PlayerDataStore.getInt(player, "level");
String clan = PlayerDataStore.getString(player, "clan");
boolean done = PlayerDataStore.getBoolean(player, "hasCompletedTutorial");

// 使用默认值读取
String color = PlayerDataStore.getString(player, "color", "red");

// 读取自定义类型
Skill skill = PlayerDataStore.getCustom(player, "mainSkill", Skill.class);

// 列表读取
List<Skill> skills = PlayerDataStore.getList(player, "skills", Skill.class);

// 泛型读取
Object raw = PlayerDataStore.getData(player, "level");

// 设置基础变量
PlayerDataStore.setData(player, "level", 42);
PlayerDataStore.setData(player, "clan", "Dragons");
PlayerDataStore.setData(player, "hasCompletedTutorial", true);

// 写入自定义类型数组
Skill newSkill = new Skill("Archery", 150, true);
List<Skill> skillList = new ArrayList<>();
skillList.add(newSkill);
PlayerDataStore.setData(player, "skills", skillList);

5. 在客户端读取数据

数据会自动同步到客户端。使用 CustomPlayerDataClient

import fr.hdi.CustomPlayerDataClient;

int level = CustomPlayerDataClient.getClientInt("level");
String color = CustomPlayerDataClient.getClientString("hudColor");
boolean done = CustomPlayerDataClient.getClientBoolean("hasCompletedTutorial");