188 lines
6.4 KiB
Python
188 lines
6.4 KiB
Python
"""
|
||
YAML单位加载器
|
||
从YAML文件加载单位定义,将游戏引擎与数据分离
|
||
"""
|
||
import yaml
|
||
import os
|
||
from typing import Dict, List, Any, Optional, Set
|
||
from pathlib import Path
|
||
|
||
from .unit import Unit
|
||
from ..core.enums import UnitType
|
||
|
||
|
||
class UnitLoader:
|
||
"""YAML单位加载器"""
|
||
|
||
def __init__(self, assets_path: Optional[str] = None):
|
||
"""初始化加载器"""
|
||
if assets_path is None:
|
||
# 默认使用项目根目录下的assets文件夹
|
||
project_root = Path(__file__).parent.parent.parent
|
||
assets_path = project_root / "assets" / "units"
|
||
|
||
self.assets_path = Path(assets_path)
|
||
self._unit_definitions: Dict[str, Dict[str, Any]] = {}
|
||
self._loaded_files: Set[str] = set()
|
||
|
||
def load_units_from_file(self, filename: str) -> Dict[str, Dict[str, Any]]:
|
||
"""从单个YAML文件加载单位定义"""
|
||
file_path = self.assets_path / filename
|
||
|
||
if not file_path.exists():
|
||
raise FileNotFoundError(f"Unit file not found: {file_path}")
|
||
|
||
try:
|
||
with open(file_path, 'r', encoding='utf-8') as f:
|
||
data = yaml.safe_load(f)
|
||
|
||
if not data or 'units' not in data:
|
||
raise ValueError(f"Invalid unit file format: {filename}")
|
||
|
||
units_data = {}
|
||
for unit_data in data['units']:
|
||
if 'id' not in unit_data:
|
||
raise ValueError(f"Unit missing 'id' field in {filename}")
|
||
|
||
unit_id = unit_data['id']
|
||
units_data[unit_id] = unit_data
|
||
|
||
self._unit_definitions.update(units_data)
|
||
self._loaded_files.add(filename)
|
||
|
||
return units_data
|
||
|
||
except yaml.YAMLError as e:
|
||
raise ValueError(f"Error parsing YAML file {filename}: {e}")
|
||
|
||
def load_all_units(self) -> Dict[str, Dict[str, Any]]:
|
||
"""加载assets目录下所有YAML单位文件"""
|
||
if not self.assets_path.exists():
|
||
raise FileNotFoundError(f"Assets directory not found: {self.assets_path}")
|
||
|
||
yaml_files = list(self.assets_path.glob("*.yaml")) + list(self.assets_path.glob("*.yml"))
|
||
|
||
# 排除规范文件
|
||
yaml_files = [f for f in yaml_files if not f.name.startswith("units_spec")]
|
||
|
||
for yaml_file in yaml_files:
|
||
if yaml_file.name not in self._loaded_files:
|
||
self.load_units_from_file(yaml_file.name)
|
||
|
||
return self._unit_definitions
|
||
|
||
def get_unit_definition(self, unit_id: str) -> Optional[Dict[str, Any]]:
|
||
"""获取单位定义"""
|
||
return self._unit_definitions.get(unit_id)
|
||
|
||
def list_available_units(self) -> List[str]:
|
||
"""列出所有可用的单位ID"""
|
||
return list(self._unit_definitions.keys())
|
||
|
||
def create_unit_from_id(self, unit_id: str) -> Unit:
|
||
"""根据单位ID创建Unit实例"""
|
||
unit_data = self.get_unit_definition(unit_id)
|
||
if not unit_data:
|
||
raise ValueError(f"Unit definition not found: {unit_id}")
|
||
|
||
return self._create_unit_from_data(unit_data)
|
||
|
||
def create_unit_from_data(self, unit_data: Dict[str, Any]) -> Unit:
|
||
"""直接从数据字典创建Unit实例"""
|
||
return self._create_unit_from_data(unit_data)
|
||
|
||
def _create_unit_from_data(self, unit_data: Dict[str, Any]) -> Unit:
|
||
"""内部方法:从数据创建Unit实例"""
|
||
# 验证必需字段
|
||
required_fields = ['name', 'type', 'stats']
|
||
for field in required_fields:
|
||
if field not in unit_data:
|
||
raise ValueError(f"Missing required field: {field}")
|
||
|
||
# 解析单位类型
|
||
unit_type_str = unit_data['type'].upper()
|
||
try:
|
||
unit_type = UnitType[unit_type_str]
|
||
except KeyError:
|
||
raise ValueError(f"Invalid unit type: {unit_data['type']}")
|
||
|
||
# 解析属性
|
||
stats = unit_data['stats']
|
||
required_stats = ['attack', 'defense', 'operation_cost']
|
||
for stat in required_stats:
|
||
if stat not in stats:
|
||
raise ValueError(f"Missing required stat: {stat}")
|
||
|
||
# 解析关键词
|
||
keywords = set(unit_data.get('keywords', []))
|
||
|
||
# 解析能力(暂时作为原始数据存储,后续可扩展)
|
||
abilities = unit_data.get('abilities', [])
|
||
|
||
# 创建单位实例
|
||
unit = Unit(
|
||
name=unit_data['name'],
|
||
unit_type=unit_type,
|
||
attack=stats['attack'],
|
||
defense=stats['defense'],
|
||
operation_cost=stats['operation_cost'],
|
||
keywords=keywords,
|
||
abilities=abilities
|
||
)
|
||
|
||
# 设置额外属性
|
||
if 'nation' in unit_data:
|
||
unit.nation = unit_data['nation']
|
||
|
||
if 'id' in unit_data:
|
||
unit.definition_id = unit_data['id']
|
||
|
||
return unit
|
||
|
||
def get_units_by_nation(self, nation: str) -> List[Dict[str, Any]]:
|
||
"""获取指定国家的所有单位定义"""
|
||
return [
|
||
unit_data for unit_data in self._unit_definitions.values()
|
||
if unit_data.get('nation', '').upper() == nation.upper()
|
||
]
|
||
|
||
def get_units_by_type(self, unit_type: str) -> List[Dict[str, Any]]:
|
||
"""获取指定类型的所有单位定义"""
|
||
return [
|
||
unit_data for unit_data in self._unit_definitions.values()
|
||
if unit_data.get('type', '').upper() == unit_type.upper()
|
||
]
|
||
|
||
|
||
# 全局单例加载器实例
|
||
_global_loader: Optional[UnitLoader] = None
|
||
|
||
|
||
def get_unit_loader() -> UnitLoader:
|
||
"""获取全局单位加载器实例"""
|
||
global _global_loader
|
||
if _global_loader is None:
|
||
_global_loader = UnitLoader()
|
||
return _global_loader
|
||
|
||
|
||
def load_unit(unit_id: str) -> Unit:
|
||
"""便捷函数:加载单位"""
|
||
loader = get_unit_loader()
|
||
|
||
# 如果还没有加载单位定义,先加载
|
||
if not loader._unit_definitions:
|
||
loader.load_all_units()
|
||
|
||
return loader.create_unit_from_id(unit_id)
|
||
|
||
|
||
def list_all_units() -> List[str]:
|
||
"""便捷函数:列出所有可用单位"""
|
||
loader = get_unit_loader()
|
||
|
||
# 如果还没有加载单位定义,先加载
|
||
if not loader._unit_definitions:
|
||
loader.load_all_units()
|
||
|
||
return loader.list_available_units() |