Configuration
Dokumentace ke konfiguraci pluginů a práci s BSON/JSON soubory.
Obsah
| Soubor | Popis |
|--------|-------|
| BSON_JSON.md | Práce s BSON/JSON soubory, BsonUtil API |
| CODECS.md | Codec systém pro serializaci objektů |
| CONFIG_PATTERNS.md | Běžné vzory pro konfigurace |
---
Rychlý Přehled
| Operace | Metoda |
|---------|--------|
| Async čtení | BsonUtil.readDocument(path) |
| Async zápis | BsonUtil.writeDocument(path, doc) |
| Sync čtení | BsonUtil.readDocumentNow(path) |
| BSON → JSON | BsonUtil.toJson(doc) |
| JSON → BSON | BsonDocument.parse(json) |
---
BSON Utility
Hytale používá BSON formát pro konfigurační soubory. Hlavní utility třída je BsonUtil.
Čtení Souboru
Path path = Universe.get().getPath().resolve("myconfig.json");// Asynchronní čtení
CompletableFuture future = BsonUtil.readDocument(path);
BsonDocument document = future.join(); // Blokující čekání
if (document != null) {
// Zpracování dokumentu
String value = document.getString("key").getValue();
int number = document.getInt32("count").getValue();
}
Zápis Souboru
Path path = Universe.get().getPath().resolve("myconfig.json");BsonDocument document = new BsonDocument();
document.put("key", new BsonString("value"));
document.put("count", new BsonInt32(42));
// Asynchronní zápis
CompletableFuture future = BsonUtil.writeDocument(path, document);
future.join(); // Počkej na dokončení
---
Příklad: Warps (z TeleportPlugin)
Načítání Warpů
public void loadWarps() {
BsonDocument document = null;
Path universePath = Universe.get().getPath();
Path oldPath = universePath.resolve("warps.bson");
Path path = universePath.resolve("warps.json"); // Migrace starého formátu
if (Files.exists(oldPath) && !Files.exists(path)) {
try {
Files.move(oldPath, path);
} catch (IOException e) {
// Ignoruj chybu
}
}
// Načti dokument
if (Files.exists(path)) {
document = BsonUtil.readDocument(path).join();
}
if (document != null) {
// Podpora obou klíčů (Warps i warps)
BsonArray bsonWarps = document.containsKey("Warps")
? document.getArray("Warps")
: document.getArray("warps");
this.warps.clear();
// Dekódování pomocí codeku
for (Warp warp : Warp.ARRAY_CODEC.decode(bsonWarps)) {
this.warps.put(warp.getId().toLowerCase(), warp);
}
getLogger().atInfo().log("Loaded %d warps", bsonWarps.size());
} else {
getLogger().atInfo().log("Loaded 0 warps (No warps.json found)");
}
this.loaded.set(true);
}
Ukládání Warpů
private void saveWarps0() {
Warp[] array = this.warps.values().toArray(Warp[]::new); // Enkódování pomocí codeku
BsonDocument document = new BsonDocument("Warps", Warp.ARRAY_CODEC.encode(array));
Path path = Universe.get().getPath().resolve("warps.json");
BsonUtil.writeDocument(path, document).join();
getLogger().atInfo().log("Saved %d warps to warps.json", array.length);
}
// Thread-safe save s lockem
public void saveWarps() {
if (this.saveLock.tryLock()) {
try {
this.saveWarps0();
} catch (Throwable e) {
getLogger().at(Level.SEVERE).withCause(e).log("Failed to save warps:");
} finally {
this.saveLock.unlock();
}
// Pokud někdo chtěl uložit během ukládání
if (this.postSaveRedo.getAndSet(false)) {
this.saveWarps();
}
} else {
// Někdo jiný ukládá, označíme pro opakování
this.postSaveRedo.set(true);
}
}
---
Codecs
Codecs slouží k serializaci/deserializaci objektů do/z BSON.
Použití Codeku
// Enkódování objektu do BSON
BsonValue bson = MyClass.CODEC.encode(myObject);// Dekódování z BSON
MyClass obj = MyClass.CODEC.decode(bsonValue);
// Array codec
BsonArray array = MyClass.ARRAY_CODEC.encode(objectArray);
MyClass[] objects = MyClass.ARRAY_CODEC.decode(bsonArray);
Příklad Codeku
public class Warp {
private final String id;
private final String world;
private final Transform transform; // Codec pro serializaci
public static final Codec CODEC = ...;
public static final ArrayCodec ARRAY_CODEC = Codec.array(CODEC);
// Gettery...
}
---
Cesty k Souborům
Universe Path
// Hlavní adresář universe (server data)
Path universePath = Universe.get().getPath();// Konfigurace pluginu
Path configPath = universePath.resolve("plugins/myplugin/config.json");
// Globální data
Path dataPath = universePath.resolve("data/mydata.json");
Plugin Data Path
// V pluginu
Path pluginDataPath = getDataFolder();
Path configPath = pluginDataPath.resolve("config.json");
---
BSON Typy
| Java Typ | BSON Typ | Příklad |
|----------|----------|---------|
| String | BsonString | new BsonString("text") |
| int | BsonInt32 | new BsonInt32(42) |
| long | BsonInt64 | new BsonInt64(1000L) |
| double | BsonDouble | new BsonDouble(3.14) |
| boolean | BsonBoolean | new BsonBoolean(true) |
| List | BsonArray | new BsonArray() |
| Map | BsonDocument | new BsonDocument() |
Práce s BsonDocument
BsonDocument doc = new BsonDocument();// Zápis
doc.put("name", new BsonString("Test"));
doc.put("count", new BsonInt32(10));
doc.put("enabled", new BsonBoolean(true));
// Čtení
String name = doc.getString("name").getValue();
int count = doc.getInt32("count").getValue();
boolean enabled = doc.getBoolean("enabled").getValue();
// Kontrola existence klíče
if (doc.containsKey("optional")) {
// ...
}
Práce s BsonArray
BsonArray array = new BsonArray();// Přidání prvků
array.add(new BsonString("item1"));
array.add(new BsonString("item2"));
// Iterace
for (BsonValue value : array) {
String item = value.asString().getValue();
}
// Z dokumentu
BsonArray items = doc.getArray("items");
---
Thread-Safe Konfigurace
Vzor pro Bezpečné Ukládání
public class ConfigManager {
private final ReentrantLock saveLock = new ReentrantLock();
private final AtomicBoolean pendingSave = new AtomicBoolean(false);
private final Map config = new ConcurrentHashMap<>(); public void save() {
if (saveLock.tryLock()) {
try {
doSave();
} finally {
saveLock.unlock();
}
if (pendingSave.getAndSet(false)) {
save(); // Rekurzivní volání pro čekající save
}
} else {
pendingSave.set(true);
}
}
private void doSave() {
// Async zápis
CompletableFuture.runAsync(() -> {
BsonDocument doc = serialize(config);
BsonUtil.writeDocument(configPath, doc).join();
});
}
}
---
Načítání při Startu
AllWorldsLoadedEvent
@Override
protected void setup() {
// Registruj listener pro načtení konfigurace
getEventRegistry().registerGlobal(AllWorldsLoadedEvent.class, event -> {
loadConfig();
});
}private void loadConfig() {
Path path = Universe.get().getPath().resolve("myplugin/config.json");
if (Files.exists(path)) {
BsonDocument doc = BsonUtil.readDocument(path).join();
// Zpracování...
} else {
// Vytvoř výchozí konfiguraci
createDefaultConfig();
}
}
---
Shrnutí
| Operace | Metoda |
|---------|--------|
| Čtení | BsonUtil.readDocument(path).join() |
| Zápis | BsonUtil.writeDocument(path, doc).join() |
| Universe path | Universe.get().getPath() |
| Kontrola souboru | Files.exists(path) |
| Migrace | Files.move(oldPath, newPath) |