config-importer.rb 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. require_relative 'common'
  2. options = get_options(__FILE__)
  3. config_path = options['config_path']
  4. ini_path = options['generate_ini_path']
  5. text_path = options['generate_text_path']
  6. code_path = options['generate_code_path']
  7. language = options['source_text_language']
  8. is_generate_field_info = options['generate_field_info']
  9. recreate_dir ini_path
  10. recreate_dir text_path
  11. recreate_dir code_path
  12. require 'csv'
  13. # 各类型定义
  14. TypeInfo = Struct.new(:data_type, :data_type_extra, :ref_info, :default_value, :struct_info)
  15. FieldInfo = Struct.new(:column_id, :identifier, :comment, :type_info)
  16. Table = Struct.new(:csv, :fields, :name2id, :id_field, :raw_name)
  17. Ini = Struct.new(:io, :tables)
  18. inis = {}
  19. # 读取配置表子目录,以形成配置数据目录
  20. Dir["#{config_path}/*"].each do |path|
  21. ini_name = File::basename(path)
  22. ini = (inis[ini_name] ||= Ini.new(File.open("#{ini_path}/#{ini_name}.ini", 'wb'), {}))
  23. next unless File::directory?(path)
  24. # 每个配置表子目录将成为一个 ini 文件
  25. # 内含全部子 .csv 表格的导入数据
  26. Dir["#{path}/*.csv"].each do |file|
  27. table_name = File::basename(file, '.csv')
  28. table = (ini.tables[convert_case(table_name)] = Table.new(csv = CSV.open(file), [], {}, nil, table_name))
  29. identifiers = csv.readline
  30. comments = csv.readline
  31. type_infos = csv.readline
  32. field_id = nil
  33. field_id_name = nil
  34. # 处理表头列
  35. identifiers.each_with_index do |identifier, index|
  36. next if identifier.nil? || identifier.empty?
  37. type_info = TypeInfo.new(nil, nil, nil, nil, nil)
  38. type_infos[index].gsub(/\s+/, '').scan(/[(:|,|@|=)][a-zA-Z_]+/).each do |info|
  39. type_info.data_type = info[1..info.size] if info.start_with?(':')
  40. type_info.data_type_extra = info[1..info.size] if info.start_with?(',')
  41. type_info.ref_info = convert_case(info[1..info.size]) if info.start_with?('@')
  42. type_info.default_value = info[1..info.size] if info.start_with?('=')
  43. type_info.struct_info = info[1..info.size] if info.start_with?('!')
  44. end
  45. field = FieldInfo.new(index, identifier, comments[index], type_info)
  46. # 处理特殊类型的字段
  47. case type_info.data_type
  48. when 'id'
  49. field_id = field
  50. next
  51. when 'id_name'
  52. field_id_name = field
  53. next
  54. end
  55. # 参与导入的条目
  56. table.fields << field
  57. end
  58. # 验证 Id 列
  59. table.id_field = field_id
  60. # 处理条目形成引用表
  61. while !csv.eof?
  62. line = csv.readline
  63. next if field_id_name.nil?
  64. id = line[field_id.column_id]
  65. next if id.nil? || id.empty?
  66. table.name2id[line[field_id_name.column_id]] = id.upcase
  67. end
  68. # 回滚 csv 状态至表头读取后
  69. csv.rewind
  70. 3.times { csv.readline }
  71. end
  72. end
  73. # 所有表格缓存
  74. tables = inis.values.collect{|ini| ini.tables}.inject(:merge)
  75. # 导入实际数据条目
  76. inis.each_pair do |ini_name, ini_data|
  77. register_table = {}
  78. enum_table = {}
  79. buffer = StringIO.new
  80. # 逐目录生成 ini
  81. ini_data.tables.each_pair do |table_name, table|
  82. register = (register_table[table_name] = [])
  83. texts = {}
  84. count = 0
  85. # 逐行扫描
  86. while !table.csv.eof?
  87. line = table.csv.readline
  88. id = line[table.id_field.column_id]
  89. next if id.nil? || id.empty?
  90. id = id.upcase
  91. buffer.puts "[#{id}]"
  92. table.fields.each do |field|
  93. value = line[field.column_id]
  94. next if value.nil? || value.empty?
  95. # 引用名替换处理
  96. if field.type_info.ref_info
  97. ref_table = tables[field.type_info.ref_info]
  98. value = value.split(',').collect do |ref_name|
  99. ref_name.strip!
  100. ref_table.name2id[ref_name] || ref_name.upcase
  101. end.join(',')
  102. # 数据类型处理
  103. else
  104. case field.type_info.data_type
  105. # 文本内容
  106. when 'text'
  107. index = 0
  108. value = value.split(',').collect do |text|
  109. key = "#{id}"
  110. key = "#{key}:#{index}" if index > 0
  111. global_key = "C:#{table_name}:#{field.identifier}:#{key}"
  112. texts[global_key] = text
  113. index += 1
  114. key
  115. end.join(',')
  116. # 枚举内容
  117. when 'enum'
  118. case field.type_info.data_type_extra
  119. # 自动型枚举
  120. when 'auto'
  121. enum_key = "#{table_name}#{field.identifier}"
  122. value.split(',').each do |v|
  123. enums = (enum_table[enum_key] ||= {})
  124. enums[v] = enums.size
  125. end
  126. end
  127. end
  128. end
  129. buffer.puts "#{field.identifier}=#{value}"
  130. count += 1
  131. end
  132. buffer.puts
  133. register << id
  134. end
  135. # 导出语言表
  136. if !texts.empty?
  137. csf = CSV.open("#{text_path}/#{table.raw_name}.csv", 'wb')
  138. csf << ['', language]
  139. texts.keys.sort.each do |k|
  140. csf << [k, texts[k]]
  141. end
  142. end
  143. end
  144. # 导出 ini
  145. File.open("#{ini_path}/#{ini_name}.ini", 'wb') do |ini|
  146. # 导出注册表
  147. if !register_table.empty?
  148. ini.puts '[REGISTER]'
  149. register_table.each_pair do |table_name, register|
  150. ini.puts "#{table_name}=#{register.join(',')}"
  151. end
  152. ini.puts
  153. end
  154. # 导出枚举
  155. if !enum_table.empty?
  156. ini.puts '[ENUM]'
  157. enum_table.keys.sort.each do |enum_name|
  158. ini.puts "#{enum_name}=#{enum_table[enum_name].keys.join(',')}"
  159. end
  160. ini.puts
  161. end
  162. # 导出所有条目
  163. ini.puts buffer.string
  164. end
  165. end