找回密码
 点一下
查看: 2006|回复: 15

星际争霸2信息数据表(应该算完成了吧…)

[复制链接]
发表于 2010-3-21 14:12:44 | 显示全部楼层 |阅读模式
老是来求教,偶尔还是写点东西回报下吧…

这东西可提取一些xml中有用的信息,然后导出成csv文件。用Excel打开,改下样式,排下序就OK了。
没空去翻译,自己翻翻词典就清楚了。
部分xml由于太复杂,所以不太关注的信息就无视了。

部分截图:
unitdata.png

Python代码如下:
[codes=python]# -*- coding: utf-8 -*-

try:
  from lxml import etree
except ImportError:
  try:
    import xml.etree.cElementTree as etree
  except ImportError:
    import xml.etree.ElementTree as etree

from copy import deepcopy


class Parser(object):
  elements = []
  metas = []
  meta_arrays = []
  all_metas = []
  table_heade = None
  template = {}

  @classmethod
  def meta_element_handler(cls, meta_element, obj):
    value = meta_element.get('value')
    tag = meta_element.tag
    if tag == 'EditorCategories':
      value = value.split(',')[0].split(':')[1]
    obj[tag] = value

  @classmethod
  def meta_array_handler(cls, meta_array_element, meta_array, obj):
    obj[meta_array_element.get('index')] = meta_array_element.get('value')

  @classmethod
  def other_handler(cls, element, obj):
    pass

  @classmethod
  def filter(cls, obj, element):
    return True

  @classmethod
  def parse(cls):
    objs = {}
    template = cls.template
    metas = cls.metas
    meta_arrays = cls.meta_arrays

    for element in cls.elements:
      id = element.get('id')
      if not id:
        continue

      parent = element.get('parent')
      if parent:
        try:
          obj = deepcopy(objs[parent])
        except:
          obj = deepcopy(template)
      else:
        obj = deepcopy(template)

      if not cls.filter(obj, element):
        continue

      for meta in metas:
        meta_element = element.find(meta)
        if meta_element is not None:
          cls.meta_element_handler(meta_element, obj)

      for meta_array in meta_arrays:
        for meta_array_element in element.findall(meta_array):
          cls.meta_array_handler(meta_array_element, meta_array, obj)

      cls.other_handler(element, obj)

      objs[id] = obj

    return objs

  @classmethod
  def process_additional_data(cls, data, line):
    pass

  @classmethod
  def parse_to_file(cls, name, append_header='', quote_metas=()):
    objs = cls.parse()

    lines = ['%s,%s%s' % (name, ','.join(cls.table_header), append_header)]

    for id, data in objs.iteritems():
      line = [id]
      for meta in cls.all_metas:
        if meta in quote_metas:
          line.append('"%s"' % data[meta])
        else:
          line.append(data[meta])

      cls.process_additional_data(data, line)

      lines.append(','.join(line))

    csvfile = open(name + '.csv', 'w')
    csvfile.write('\n'.join(lines))
    csvfile.close()


class UnitParser(Parser):
  elements = etree.parse('UnitData.xml').getroot().findall('CUnit')

  metas = [
    'Race',
    'EditorCategories',
    'LifeMax',
    'LifeRegenRate',
    'ShieldsMax',
    'ShieldRegenRate',
    'ShieldRegenDelay',
    'EnergyStart',
    'EnergyMax',
    'EnergyRegenRate',
    'Sight',
    'AttackTargetPriority',
    'Radius',
    'InnerRadius',
    'SeparationRadius',
    'MinimapRadius',
    'SubgroupPriority',
    'LifeArmor',
    'Speed',
    'Acceleration',
    'LateralAcceleration',
    'StationaryTurningRate',
    'TurningRate',
    'Mover',
    'Height',
    'VisionHeight',
    'RepairTime',
    'Food',
    'CargoSize',
    'Mass',
  ]

  meta_arrays = [
    'CostResource',
    'PlaneArray',
    'Collide',
    'FlagArray',
    'Attributes',
  ]

  no_prefix_unit_meta_arrays = meta_arrays[-2:]

  unit_metas_in_arrays = {}
  for unit_element in elements:
    for unit_meta_array in meta_arrays:
      for unit_meta_array_element in unit_element.findall(unit_meta_array):
        index = unit_meta_array_element.get('index')
        if not (unit_meta_array == 'FlagArray' and index.startswith('AI')):
          unit_metas_in_arrays[(unit_meta_array + ' - ' + index) if unit_meta_array not in no_prefix_unit_meta_arrays else index] = 1

  def cmp_unit_meta_arrays(x, y):
    def priority(s):
      if s.startswith('CostResource'):
        return 0
      elif s.startswith('Collide'):
        return 1
      elif s.startswith('PlaneArray'):
        return 2
      return 3
    return cmp(priority(x), priority(y)) or cmp(x, y)

  additional_unit_metas = sorted(unit_metas_in_arrays.keys(), cmp=cmp_unit_meta_arrays)
  all_metas = metas + additional_unit_metas
  table_header = all_metas[:]
  table_header[1] = 'ObjectType'

  template = dict(zip(all_metas, [''] * len(all_metas)))

  @classmethod
  def meta_array_handler(cls, meta_array_element, meta_array, obj):
    index = meta_array_element.get('index')
    obj[(meta_array + ' - ' + index) if meta_array not in cls.no_prefix_unit_meta_arrays else index] = meta_array_element.get('value')

  @classmethod
  def other_handler(cls, element, obj):
    weapons = []
    for weapon in element.findall('WeaponArray[@Link]'):
      weapons.append(weapon.get('Link'))
    obj['WeaponArray'] = weapons

  @classmethod
  def process_additional_data(cls, data, line):
    line.append('"%s"' % ','.join(data['WeaponArray']))


UnitParser.parse_to_file('Unit', ',WeaponArray')


class WeaponParser(Parser):
  elements = etree.parse('WeaponData.xml').getroot().findall('CWeaponLegacy')

  metas = [
    'EditorCategories',
    'TargetFilters',
    'Period',
    'RandomDelayMin',
    'RandomDelayMax',
    'DamagePoint',
    'AllowedMovement',
    'Backswing', # 击退?
    'Arc',
    'ArcSlop',
    'Range',
    'MinimumRange',
    'MinScanRange',
    'RangeSlop',
    'DisplayAttackCount',
  ]
  meta_arrays = [
    'Options',
    'LegacyOptions',
  ]

  weapon_metas_in_arrays = {}
  for weapon_element in elements:
    for weapon_meta_array in meta_arrays:
      for weapon_meta_array_element in weapon_element.findall(weapon_meta_array):
        weapon_metas_in_arrays[weapon_meta_array_element.get('index')] = 1

  additional_weapon_metas = weapon_metas_in_arrays.keys()
  all_metas = metas + additional_weapon_metas
  table_header = all_metas[:]
  table_header[0] = 'Race'

  template = dict(zip(all_metas, [''] * len(all_metas)))


WeaponParser.parse_to_file('Weapon', quote_metas=['TargetFilters'])


class DamageParser(Parser):
  all_metas = metas = [
    'EditorCategories',
    'Amount',
    'ArmorReduction',
    'Kind',
    'Visibility',
    'SearchFilters',
  ]

  meta_arrays = [
    'AreaArray',
    'ExcludeArray',
    #'AttributeBonus',
  ]

  damage_root = etree.parse('EffectData.xml').getroot()
  elements = damage_root.findall('CEffectDamage')

  damage_bonus = {}
  for damage_bonus_element in damage_root.findall('.//AttributeBonus'):
    damage_bonus[damage_bonus_element.get('index')] = 1
  damage_bonus = ['AttributeBonus - ' + key for key in damage_bonus.keys()]

  template = dict(zip(metas, [''] * len(metas)) + [(meta_array, []) for meta_array in meta_arrays[:2]] + zip(damage_bonus, [''] * len(damage_bonus)))

  table_header = metas + damage_bonus + ['Radius', 'Fraction'] * 3 + ['ExcludeArray']
  table_header[0] = 'Race'

  @classmethod
  def meta_array_handler(cls, meta_array_element, meta_array, obj):
    if meta_array_element.get('removed') == "1":
      del obj[meta_array_element.tag][int(meta_array_element.get('index'))]
    elif meta_array == 'AreaArray':
      obj['AreaArray'].append((meta_array_element.get('Radius'), meta_array_element.get('Fraction')))
    elif meta_array == 'ExcludeArray':
      obj['ExcludeArray'].append(meta_array_element.get('Value'))

  @classmethod
  def other_handler(cls, element, obj):
    for bonus in element.findall('AttributeBonus'):
      obj['AttributeBonus - ' + bonus.get('index')] = bonus.get('value')

  @classmethod
  def filter(cls, obj, element):
    return obj['Amount'] or element.find('Amount') is not None

  @classmethod
  def process_additional_data(cls, data, line):
    for damage_bonus_item in cls.damage_bonus:
      line.append(data.get(damage_bonus_item, ''))

    area_array = data['AreaArray']
    for (radius, fraction) in area_array:
      line.append(radius)
      line.append(fraction)

    for i in xrange(len(area_array) - 3):
      line.append('')
      line.append('')

    line.append('"%s"' % ','.join(data['ExcludeArray']))


DamageParser.parse_to_file('Damage', quote_metas=['SearchFilters'])


class UpgradeParser(Parser):
  elements = etree.parse('UpgradeData.xml').getroot().findall('CUpgrade')

  all_metas = metas = [
    'Race',
  ]

  meta_arrays = [
    'EffectArray',
  ]

  template = {'Race': '', 'EffectArray': []}

  table_header = metas + ['Effect - ' + `i` for i in xrange(1, 65)]

  @classmethod
  def meta_array_handler(cls, meta_array_element, meta_array, obj):
    if not meta_array_element.get('Operation'):
      obj['EffectArray'].append('"%s: %s"' % (meta_array_element.get('Reference'), meta_array_element.get('Value')))

  @classmethod
  def filter(cls, obj, element):
    return obj['EffectArray'] or element.find('EffectArray') is not None

  @classmethod
  def process_additional_data(cls, data, line):
    line.extend(data['EffectArray'])


UpgradeParser.parse_to_file('Upgrade')


class BehaviorParser(Parser):
  root = etree.parse('BehaviorData.xml').getroot()
  elements = root.findall('CBehaviorBuff')

  metas = [
    'EditorCategories',
    'Duration',
  ]

  meta_arrays = []

  modifications = set()
  for modification in root.findall('.//Modification'):
    modifications |= set(modification.keys())
  modifications = list(modifications)

  vital_regen_arrays  = set()
  for vital_regen_array in root.findall('CBehaviorBuff/Modification/VitalRegenArray'):
    vital_regen_arrays.add('VitalRegenArray - ' + vital_regen_array.get('index'))
  vital_regen_arrays = list(vital_regen_arrays)

  all_metas = metas + modifications + vital_regen_arrays

  template = dict(zip(all_metas, [''] * len(all_metas)))

  table_header = all_metas[:]
  table_header[0] = 'Race'

  @classmethod
  def filter(cls, obj, element):
    return element.find('Modification') is not None or obj['Duration'] or element.find('Duration') is not None

  @classmethod
  def other_handler(cls, element, obj):
    modification = element.find('Modification')
    if modification is not None:
      obj.update(modification.attrib)

    for vital_regen_array in element.findall('Modification/VitalRegenArray'):
      obj['%s - %s' % (vital_regen_array.tag, vital_regen_array.get('index'))] = vital_regen_array.get('value')


BehaviorParser.parse_to_file('Behavior', quote_metas=['RadarFilters'])


abil_root = etree.parse('AbilData.xml').getroot()

class AbilParser(Parser):
  elements = []

  table_header = all_metas = []

  template = dict(zip(all_metas, [''] * len(all_metas)))

  @classmethod
  def parse(cls):
    objs = {}
    template = cls.template

    for element in cls.elements:

      parent = element.get('parent')
      if parent:
        try:
          obj = objs[parent].copy()
        except:
          obj = template.copy()
      else:
        obj = template.copy()

      editor_categories_element = element.find('EditorCategories')
      if editor_categories_element is not None:
        obj['Race'] = editor_categories_element.get('value').split(',')[0].split(':')[1]

      cls.other_handler(element, obj, objs)

    return objs


class TrainParser(AbilParser):
  elements = abil_root.findall('CAbilTrain')

  table_header = all_metas = ['Race', 'Time', 'Minerals', 'Vespene']

  template = dict(zip(all_metas, [''] * len(all_metas)))

  @classmethod
  def other_handler(cls, element, obj, objs):
    for info_array in element.findall('InfoArray'):
      id = info_array.find('Unit')
      if id is not None:
        temp_obj = obj.copy()
        temp_obj['Time'] = info_array.get('Time')
        for resource in info_array.findall('Resource'):
          temp_obj[resource.get('index')] = resource.get('value')

        objs[id.get('value')] = temp_obj


TrainParser.parse_to_file('Train')


class WarpTrainParser(AbilParser):
  elements = abil_root.findall('CAbilWarpTrain')

  table_header = all_metas = ['Race', 'Cooldown', 'Time', 'Minerals', 'Vespene']

  template = dict(zip(all_metas, [''] * len(all_metas)))

  @classmethod
  def other_handler(cls, element, obj, objs):
    for info_array in element.findall('InfoArray'):
      id = info_array.get('Unit')
      if id:
        temp_obj = obj.copy()
        temp_obj['Time'] = info_array.get('Time')
        for resource in info_array.findall('Resource'):
          temp_obj[resource.get('index')] = resource.get('value')
        temp_obj['Cooldown'] = info_array.find('Cooldown').get('TimeUse')

        objs[id] = temp_obj


WarpTrainParser.parse_to_file('WarpTrain')


class ResearchParser(AbilParser):
  elements = abil_root.findall('CAbilResearch')

  table_header = all_metas = ['Race', 'Time', 'Minerals', 'Vespene']

  template = dict(zip(all_metas, [''] * len(all_metas)))

  @classmethod
  def other_handler(cls, element, obj, objs):
    for info_array in element.findall('InfoArray'):
      id = info_array.get('Upgrade')
      if id:
        temp_obj = obj.copy()
        temp_obj['Time'] = info_array.get('Time')
        for resource in info_array.findall('Resource'):
          temp_obj[resource.get('index')] = resource.get('value')

        objs[id] = temp_obj


ResearchParser.parse_to_file('Research')[/codes]附件是14356版的信息,以后可能还会更改。

SC2Data.zip

39 KB, 下载次数: 52

发表于 2010-3-21 21:26:36 | 显示全部楼层
LZ继续加油吧~~
回复

使用道具 举报

发表于 2010-3-21 21:30:41 | 显示全部楼层
楼上实在看不下去了吗
回复

使用道具 举报

发表于 2010-3-21 21:43:54 | 显示全部楼层
hmmm~~没那回事~~lz这个好好做做的话也挺有用的~~

现在很多对战主题的网站不是都把这些兵种数据当宝么~~
回复

使用道具 举报

发表于 2010-3-21 21:52:10 | 显示全部楼层
我是说楼主发了7个半小时,都没人理,好凄凉啊
回复

使用道具 举报

发表于 2010-3-21 21:55:47 | 显示全部楼层
http://bbs.islga.org/read-htm-tid-39088.html
这个15小时,不比内容的话,LZ应该还是挺宽心的吧..
回复

使用道具 举报

发表于 2010-3-21 21:56:31 | 显示全部楼层
那是水,不是一回事...
回复

使用道具 举报

发表于 2010-3-21 21:58:32 | 显示全部楼层
所以才说,不比内容的话...
回复

使用道具 举报

发表于 2010-3-21 22:44:41 | 显示全部楼层
http://bbs.islga.org/read-htm-tid-10242.html
这个2年多了,而且不是水……
回复

使用道具 举报

发表于 2010-3-21 22:46:57 | 显示全部楼层
你们举这些例子是想安慰楼主,还是想冰冻楼主啊
回复

使用道具 举报

发表于 2010-3-21 22:52:56 | 显示全部楼层
4月底,会放出编辑器吧?
回复

使用道具 举报

发表于 2010-3-22 00:38:29 | 显示全部楼层
8L.........
回复

使用道具 举报

 楼主| 发表于 2010-3-22 00:43:13 | 显示全部楼层
其实现在的代码已经被我改得面目全非了,从一开始的结构化,变成了伪面向对象,考虑到性能问题,又改成了类方法

现在正为effect头痛中,格式太凌乱了,瞬间代码超过300行了…
回复

使用道具 举报

发表于 2010-3-22 01:16:46 | 显示全部楼层
。。。单位还好……effect那种很多细分的处理成表比较麻烦……
回复

使用道具 举报

发表于 2010-3-22 09:04:45 | 显示全部楼层
LZ请继续。。。我笑纳了。。
回复

使用道具 举报

 楼主| 发表于 2010-3-22 16:36:00 | 显示全部楼层
终于全部完成了,发现版主把Python的代码高亮也加上了…
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-23 19:59 , Processed in 0.071498 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表