troops.py 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. # coding: utf-8
  2. import typing
  3. from _elementtree import Element
  4. from lxml import etree
  5. from synergine2.config import Config
  6. from synergine2.log import get_logger
  7. from opencombat.simulation.base import TileStrategySimulation
  8. from opencombat.simulation.subject import TileSubject
  9. from opencombat.strategy.team.model import TeamModel
  10. from opencombat.strategy.team.stash import TeamStash
  11. from opencombat.strategy.unit.stash import UnitStash
  12. from opencombat.util import get_class_from_string_path, pretty_xml
  13. from opencombat.xml import XmlValidator
  14. class Troop(object):
  15. def __init__(
  16. self,
  17. config: Config,
  18. state_root: Element,
  19. simulation: TileStrategySimulation,
  20. ) -> None:
  21. self._config = config
  22. self._state_root = state_root
  23. self._subjects = None # type: typing.List[TileSubject]
  24. self._simulation = simulation
  25. self._builder = TroopClassBuilder(config)
  26. @property
  27. def subjects(self) -> typing.List[TileSubject]:
  28. if self._subjects is None:
  29. self._subjects = self._get_computed_subjects()
  30. return self._subjects
  31. def _get_computed_subjects(self) -> typing.List[TileSubject]:
  32. units_file_path = self._config.get(
  33. 'global.units',
  34. 'opencombat/strategy/units.xml',
  35. )
  36. teams_file_path = self._config.get(
  37. 'global.teams',
  38. 'opencombat/strategy/teams.xml',
  39. )
  40. team_stash = self._builder.get_team_stash(
  41. units_file_path,
  42. teams_file_path,
  43. )
  44. # Parse team, build Subjects
  45. subjects = [] # type: typing.List[TileSubject]
  46. for troop in self._state_root.findall('troop'):
  47. country = troop.attrib['country']
  48. team_id = troop.attrib['team_id']
  49. team = team_stash.get_team(team_id, country)
  50. for unit in team.units:
  51. subject = unit.class_(self._config, self._simulation)
  52. properties = \
  53. self._simulation.get_default_properties_for_country(
  54. country,
  55. )
  56. subject.properties.update(properties)
  57. subjects.append(subject)
  58. return subjects
  59. class TroopDumper(object):
  60. def __init__(
  61. self,
  62. config: Config,
  63. ) -> None:
  64. self._config = config
  65. self._logger = get_logger('TroopDumper', config)
  66. def get_troop_dump(
  67. self,
  68. countries_troops: typing.Dict[str, typing.List[TeamModel]],
  69. ) -> str:
  70. troops_template = self._config.resolve(
  71. 'global.troops_template',
  72. 'opencombat/strategy/troops_template.xml',
  73. )
  74. with open(troops_template, 'r') as xml_file:
  75. template_str = xml_file.read()
  76. parser = etree.XMLParser(remove_blank_text=True)
  77. state_root = etree.fromstring(
  78. template_str.encode('utf-8'),
  79. parser,
  80. )
  81. for country, teams in countries_troops.items():
  82. for team in teams:
  83. troop_element = etree.SubElement(state_root, 'troop')
  84. troop_element.attrib['country'] = country
  85. troop_element.attrib['team_id'] = team.id
  86. return pretty_xml(
  87. etree.tostring(
  88. state_root,
  89. ).decode('utf-8'),
  90. )
  91. class TroopClassBuilder(object):
  92. def __init__(
  93. self,
  94. config: Config,
  95. ) -> None:
  96. self._logger = get_logger('TroopManagerBuilder', config)
  97. self._config = config
  98. def get_unit_stash(
  99. self,
  100. units_file_path: str,
  101. ) -> UnitStash:
  102. class_address = self._config.resolve(
  103. 'global.unit_stash',
  104. 'opencombat.strategy.unit.stash.UnitStash',
  105. )
  106. class_ = get_class_from_string_path(
  107. self._config,
  108. class_address,
  109. )
  110. return class_(
  111. self._config,
  112. units_file_path,
  113. )
  114. def get_team_stash(
  115. self,
  116. units_file_path: str,
  117. teams_file_path: str,
  118. ) -> TeamStash:
  119. class_address = self._config.resolve(
  120. 'global.team_stash',
  121. 'opencombat.strategy.team.stash.TeamStash',
  122. )
  123. class_ = get_class_from_string_path(
  124. self._config,
  125. class_address,
  126. )
  127. unit_stash = self.get_unit_stash(units_file_path)
  128. return class_(
  129. self._config,
  130. teams_file_path,
  131. unit_stash=unit_stash,
  132. )
  133. def get_troop_dumper(self) -> TroopDumper:
  134. class_address = self._config.resolve(
  135. 'global.troop_dumper',
  136. 'opencombat.strategy.troops.TroopDumper',
  137. )
  138. class_ = get_class_from_string_path(
  139. self._config,
  140. class_address,
  141. )
  142. return class_(
  143. self._config,
  144. )
  145. class TroopLoader(object):
  146. def __init__(
  147. self,
  148. config: Config,
  149. simulation: TileStrategySimulation,
  150. ) -> None:
  151. self._logger = get_logger('TroopLoader', config)
  152. self._config = config
  153. self._simulation = simulation
  154. schema_file_path = self._config.get(
  155. 'global.troop_schema',
  156. 'opencombat/strategy/troops.xsd',
  157. )
  158. self._xml_validator = XmlValidator(
  159. config,
  160. schema_file_path,
  161. )
  162. def get_troop(
  163. self,
  164. troop_file_path: str,
  165. ) -> Troop:
  166. return Troop(
  167. self._config,
  168. self._validate_and_return_state_element(troop_file_path),
  169. self._simulation,
  170. )
  171. def _validate_and_return_state_element(
  172. self,
  173. troop_file_path: str,
  174. ) -> Element:
  175. return self._xml_validator.validate_and_return(troop_file_path)
  176. class TroopConstructorBuilder(object):
  177. def __init__(
  178. self,
  179. config: Config,
  180. simulation: TileStrategySimulation,
  181. ) -> None:
  182. self._logger = get_logger('TroopConstructorBuilder', config)
  183. self._config = config
  184. self._simulation = simulation
  185. def get_troop_loader(
  186. self,
  187. ) -> TroopLoader:
  188. class_address = self._config.resolve(
  189. 'global.troop_loader',
  190. 'opencombat.strategy.troops.TroopLoader',
  191. )
  192. troop_loader_class = get_class_from_string_path(
  193. self._config,
  194. class_address,
  195. )
  196. return troop_loader_class(
  197. self._config,
  198. self._simulation,
  199. )