Files
blight/blight-common/src/main/java/de/blight/common/model/CharacterIO.java
Mario 50f496c864 Atmosphäre-Tools, EZ-Tree-Fixes, i18n, AnimSet, Baum-Export
- blight-lang: TextResolver + EN/DE Sprachpakete (TextReference i18n)
- AnimSet: Clips + ActionMap in .animset.json zusammengeführt
- EZ-Tree: Branch-Parameter-Fixes (length/radius/children/force nicht senden,
  twist Grad→Radiant, leaves.size ×5); Ordner-ComboBox mit Auto-Refresh
- Logging beim Baum-Export in allen drei Generatoren (EZ-Tree, Blight, Palme)
- Atmosphäre-Tools: Emitter, Licht, Wasser, Sound-/Musikbereiche, Spiel-Starten
- AnimPreviewState, RetargetingSystem, AnimationLibrary (Animations-Editor)
- Terrain-Transparenz-Fix, Schatten-Fix, ThirdPersonCamera-Fix
- DayNightState, WeatherState, CloudsNode, JmeConsole
- MapIO v6, neue blight-common Modell-Klassen (GameCharacter, NPC, Quests…)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 23:12:46 +02:00

92 lines
3.9 KiB
Java

package de.blight.common.model;
import com.google.gson.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Stream;
/**
* Lädt und speichert {@link GameCharacter}-Instanzen als JSON.
* Dateiformat: <id>.character im Verzeichnis character/
*
* JSON-Struktur:
* {
* "type": "MAIN_CHARACTER" | "NPC",
* "characterId": "hero",
* "name": "Der Held",
* "modelPath": "Models/hero.j3o",
* "animSetPath": "animations/sets/hero.j3o",
* ... (subclass fields via Gson)
* }
* Die Aktions-Zuweisung (IDLE → Clip-Name usw.) ist im AnimSet gespeichert
* (animSetPath.replaceAll(".j3o", "") + ".animset.json").
*/
public final class CharacterIO {
private static final Logger log = LoggerFactory.getLogger(CharacterIO.class);
private static final String EXTENSION = ".character";
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private CharacterIO() {}
// ── Save ──────────────────────────────────────────────────────────────────
public static void save(GameCharacter character, Path directory) throws IOException {
String id = character.getCharacterId();
if (id == null || id.isBlank()) throw new IllegalArgumentException("characterId must be set");
Files.createDirectories(directory);
JsonObject obj = (JsonObject) GSON.toJsonTree(character);
obj.addProperty("type", character instanceof MainCharacter ? "MAIN_CHARACTER" : "NPC");
Files.writeString(directory.resolve(id + EXTENSION),
GSON.toJson(obj), StandardCharsets.UTF_8);
log.debug("[CharacterIO] Gespeichert: {}", id);
}
// ── Load ──────────────────────────────────────────────────────────────────
public static GameCharacter load(Path file) throws IOException {
String json = Files.readString(file, StandardCharsets.UTF_8);
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
String type = obj.has("type") ? obj.get("type").getAsString() : "NPC";
GameCharacter c = "MAIN_CHARACTER".equals(type)
? GSON.fromJson(obj, MainCharacter.class)
: GSON.fromJson(obj, NPC.class);
log.debug("[CharacterIO] Geladen: {}", file.getFileName());
return c;
}
/** Lädt alle .character-Dateien aus dem angegebenen Verzeichnis. */
public static List<GameCharacter> loadAll(Path directory) {
if (!Files.isDirectory(directory)) return List.of();
List<GameCharacter> result = new ArrayList<>();
try (Stream<Path> walk = Files.list(directory)) {
walk.filter(p -> p.toString().endsWith(EXTENSION))
.sorted()
.forEach(p -> {
try { result.add(load(p)); } catch (IOException e) {
log.warn("[CharacterIO] Fehler beim Laden von {}: {}", p, e.getMessage());
}
});
} catch (IOException e) {
log.warn("[CharacterIO] Fehler beim Scannen von {}: {}", directory, e.getMessage());
}
return result;
}
/** Gibt true zurück wenn bereits eine MainCharacter-Datei im Verzeichnis existiert (außer der mit excludeId). */
public static boolean mainCharacterExists(Path directory, String excludeId) {
for (GameCharacter c : loadAll(directory)) {
if (c instanceof MainCharacter
&& !Objects.equals(c.getCharacterId(), excludeId)) return true;
}
return false;
}
}