Описание
# Custom Player Data
  
**Fabric Framework 1.20.6** for managing persistent and synchronized player data.
This mod allows you to define custom variables attached to each player, which are saved in Minecraft's native `player.dat` file and automatically synchronized between the server and the client.
---
## Features
- **JSON Schema**: Define your variables in a `player_data_schema.json` file automatically generated in the map folder.
- **Native persistence**: Data is stored directly in `player.dat` via Mixin — zero data loss, even after a crash.
- **Automatic synchronization**: All variables are sent to the client upon connection and with every change (ideal for HUDs).
- **Developer API**: Can be used as a dependency by other mods to inject and manipulate variables programmatically.
- **Custom types**: Create your own complex data types (e.g., `Power`, `Skill`, `Quest`...).
- **Admin commands**: `/playerdata get` and `/playerdata set` for operators.
- **Validation**: Min/max for `int`, null checks, runtime type verification.
---
## For Server Administrators
### Installation
1. Place the `.jar` file in the `mods/` folder of your Fabric 1.20.6 server.
2. Start the server for the first time—the `player_data_schema.json` file will be generated in your world folder (next to `level.dat`).
3. Modify the JSON as needed, then restart.
### JSON Schema Format
```json
{
"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
}
}
```
| Parameter | Description | Required |
|-----------------|-------------------------------------------------------|------------|
| `type` | `int`, `string`, `boolean`, or a registered custom type | Yes |
| `defaultValue` | Default value for new players | No |
| `maxValue` | Maximum value (`int` type only) | No |
| `minValue` | Minimum value (`int` type only) | No |
| `null` | Allows `null` (`false` by default) | No |
| `array` | The variable is an array (`false` by default) | No |
> **Important**: If a variable has `“null”: false` and no `defaultValue`, an error will be logged at startup.
### Commandes
| Command | Description | Permission |
|---------|-------------|------------|
| `/playerdata get ` | Displays the current value | OP level 2+ |
| `/playerdata set ` | Modifies the value (primitive types only) | OP level 2+ |
Examples :
```
/playerdata get note Steve
/playerdata set hudColor Steve red
/playerdata set note Steve 3
```
---
## Developer Guide — Using Custom Player Data as an API
### 1. Add the dependency
In your `build.gradle` file, add the JAR as a local dependency (or via a Maven repository if published):
```groovy
dependencies {
// add this one
modImplementation files("libs/custom-player-data-1.0.0.jar")
}
```
In your `fabric.mod.json` file, add the following dependency:
```json
{
"depends": {
"custom-player-data": ">=1.0.0"
}
}
```
### 2. Create a custom type (optional)
If you need to store complex data, implement `ICustomDataType`:
```java
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. Register your types and variables
In your mod's `onInitialize()` method:
```java
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. Register custom Type
TypeRegistry.register("Skill", Skill::new);
// 2. Register variables schema all possibilties
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. Reading and Writing Player Data
Use `PlayerDataStore` to access data from anywhere in your server code:
```java
import fr.hdi.api.PlayerDataStore;
import net.minecraft.server.network.ServerPlayerEntity;
// Read classic type
int level = PlayerDataStore.getInt(player, "level");
String clan = PlayerDataStore.getString(player, "clan");
boolean done = PlayerDataStore.getBoolean(player, "hasCompletedTutorial");
// Read with default value
String color = PlayerDataStore.getString(player, "color", "red");
// Read custom type
Skill skill = PlayerDataStore.getCustom(player, "mainSkill", Skill.class);
// List reading
List skills = PlayerDataStore.getList(player, "skills", Skill.class);
// Generic reading
Object raw = PlayerDataStore.getData(player, "level");
// set basic variables
PlayerDataStore.setData(player, "level", 42);
PlayerDataStore.setData(player, "clan", "Dragons");
PlayerDataStore.setData(player, "hasCompletedTutorial", true);
// write custom type array
Skill newSkill = new Skill("Archery", 150, true);
List skillList = new ArrayList();
skillList.add(newSkill);
PlayerDataStore.setData(player, "skills", skillList);
```
### 5. Reading data on the client side
Data is automatically synchronized to the client. Use `CustomPlayerDataClient`:
```java
import fr.hdi.CustomPlayerDataClient;
int level = CustomPlayerDataClient.getClientInt("level");
String color = CustomPlayerDataClient.getClientString("hudColor");
boolean done = CustomPlayerDataClient.getClientBoolean("hasCompletedTutorial");
```
---