package com.zombie.game.template; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.util.*; /** * 模板管理器 * * 负责从 JSON 配置文件加载和管理所有游戏模板(僵尸、武器、玩家)。 * 单例模式,在服务器启动时加载一次。 */ public class TemplateManager { private static final Logger logger = LoggerFactory.getLogger(TemplateManager.class); private static TemplateManager instance; private final Map zombieTemplates = new LinkedHashMap<>(); private final Map weaponTemplates = new LinkedHashMap<>(); private PlayerTemplate playerTemplate; private TemplateManager() { loadAll(); } public static synchronized TemplateManager getInstance() { if (instance == null) { instance = new TemplateManager(); } return instance; } private void loadAll() { loadZombies(); loadWeapons(); loadPlayer(); logger.info("Templates loaded: {} zombies, {} weapons, 1 player base", zombieTemplates.size(), weaponTemplates.size()); } private void loadZombies() { try (InputStream is = getClass().getResourceAsStream("/data/zombies.json")) { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(is); JsonNode types = root.get("types"); for (JsonNode node : types) { ZombieTemplate t = new ZombieTemplate( node.get("id").asText(), node.get("name").asText(), (float) node.get("baseHealth").asDouble(), (float) node.get("baseSpeed").asDouble(), (float) node.get("damage").asDouble(), (float) node.get("attackRate").asDouble(), node.get("canRangedAttack").asBoolean(), (float) node.get("rangedRange").asDouble(), node.get("rangedDamage").asInt(), (float) node.get("rangedBulletSpeed").asDouble(), node.get("canSplit").asBoolean(), node.get("minSplit").asInt(), node.get("maxSplit").asInt(), (float) node.get("spawnWeight").asDouble() ); zombieTemplates.put(t.getId(), t); } } catch (Exception e) { throw new RuntimeException("Failed to load zombie templates", e); } } private void loadWeapons() { try (InputStream is = getClass().getResourceAsStream("/data/weapons.json")) { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(is); JsonNode types = root.get("types"); for (JsonNode node : types) { WeaponTemplate t = new WeaponTemplate( node.get("id").asText(), node.get("name").asText(), node.has("category") ? node.get("category").asText() : "firearm", node.get("damage").asInt(), node.get("fireRate").asLong(), node.get("pelletCount").asInt(), (float) node.get("spread").asDouble(), (float) node.get("bulletSpeed").asDouble(), (float) node.get("range").asDouble(), node.get("maxAmmo").asInt(), node.get("chargeable").asBoolean(), node.get("explosive").asBoolean(), (float) node.get("explosionRadius").asDouble(), node.has("fireZoneRadius") ? (float) node.get("fireZoneRadius").asDouble() : 0, node.has("fireZoneDamage") ? (float) node.get("fireZoneDamage").asDouble() : 0, node.has("fireZoneDuration") ? (float) node.get("fireZoneDuration").asDouble() : 0, node.has("turretHealth") ? (float) node.get("turretHealth").asDouble() : 0, node.has("turretRange") ? (float) node.get("turretRange").asDouble() : 0, node.has("turretFireRate") ? node.get("turretFireRate").asLong() : 0, node.has("turretDamage") ? node.get("turretDamage").asInt() : 0, node.has("turretBulletSpeed") ? (float) node.get("turretBulletSpeed").asDouble() : 0 ); weaponTemplates.put(t.getId(), t); } } catch (Exception e) { throw new RuntimeException("Failed to load weapon templates", e); } } private void loadPlayer() { try (InputStream is = getClass().getResourceAsStream("/data/players.json")) { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(is); JsonNode base = root.get("base"); playerTemplate = new PlayerTemplate( (float) base.get("speed").asDouble(), (float) base.get("maxHealth").asDouble(), (float) base.get("invulnerableTime").asDouble(), (float) base.get("respawnTime").asDouble(), (float) base.get("size").asDouble() ); } catch (Exception e) { throw new RuntimeException("Failed to load player template", e); } } public ZombieTemplate getZombieTemplate(String id) { return zombieTemplates.get(id); } public Collection getAllZombieTemplates() { return zombieTemplates.values(); } public WeaponTemplate getWeaponTemplate(String id) { return weaponTemplates.get(id); } public Collection getAllWeaponTemplates() { return weaponTemplates.values(); } public PlayerTemplate getPlayerTemplate() { return playerTemplate; } public int getWeaponIndex(String id) { int idx = 0; for (String key : weaponTemplates.keySet()) { if (key.equals(id)) return idx; idx++; } return 0; } public String getWeaponId(int index) { int idx = 0; for (String key : weaponTemplates.keySet()) { if (idx == index) return key; idx++; } return weaponTemplates.keySet().iterator().next(); } }