kards-env/kards_battle/units/unit_loader.py

188 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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()