游戏资源自动转换成Lua表

关于这个问题,几年前已经做过一个工具,自动导出成一个c++的struct,然后用vector存储这些数据,实践效果并不好。现在用Lua与GO重写了一下,可以导出lua及json数据格式。

一、在制定Excel表时需要遵守以下几个规则:

1.第一行为变量类型,变量类型为三种:数字, 布尔值,字符串(n, b, s)
2.第二行为列名,只能为英文名,且不能有空格
3.列名前缀不能包含xxxxx_、ooooo_
4.特殊列名valid只能用来控制是否导出该行数据,不作它用

规则还是比较简单的,现有表fate.xlsx如下:

数据可以从第2行之后的任意行开始,我这里从第4行开始,中间可以留给策划写注释或者给列名取中文名。

二、导出时需要自定义一个列的table表,table表的左侧key值可以是自己命名的key值,也可以是来自原excel表的列名,右侧value则一定是原excel的列名。示例如下:

local head_struct = {
    id = 'id',
    fate = 'fate',
    servant = {
        [1] = {
            id = 'servant1_id',
            name = 'name1'
        },
        [2] = {
            id = 'servant2_id',
            name = 'name2'
        },
        [3] = {
            id = 'servant3_id',
            name = 'name3'
        },
    },
    player = {
        [right_name('servant1_id')] = {
            id = 'servant1_id',
            name = 'name1'
        },
        [right_name('servant2_id')] = {
            id = 'servant2_id',
            name = 'name2'
        },
        [right_name('servant3_id')] = {
            id = 'servant3_id',
            name = 'name3'
        },
    },
    type = table_name('type'),
    type2 = table_name('type2'),
    min = 'min',
    max = 'max',
    correct = 'correct'
}

注意:

1.head_struct表的左侧有用到excel表的servant2_id字段,需要用right_name函数包裹,程序会取出server2_id字段里的数据作为key值。

2.如果策划想一个字段里包含多个字段,像上表里的type, type2字段一样,则需要策划略懂lua的table表语法。用table_name函数包裹后,会生成table数据。

三、最后导出的数据可以是lua表也可以是json,现贴出lua数据:

g_fate_cfg = {
    [1] =
    {
        ["type2"] =
        {
            [1] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
            [2] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
        },
        ["type"] =
        {
            [1] = "1",
            [2] = 2,
            [3] = 3,
        },
        ["id"] = 1,
        ["correct"] = true,
        ["min"] = 2000,
        ["servant"] =
        {
            [1] =
            {
                ["id"] = 800032,
                ["name"] = "灞波儿奔",
            },
            [2] =
            {
                ["id"] = 800033,
                ["name"] = "老鼋",
            },
            [3] =
            {
                ["id"] = 800034,
                ["name"] = "",
            },
        },
        ["fate"] = "卖主求荣",
        ["player"] =
        {
            [800034] =
            {
                ["id"] = 800034,
                ["name"] = "",
            },
            [800033] =
            {
                ["id"] = 800033,
                ["name"] = "老鼋",
            },
            [800032] =
            {
                ["id"] = 800032,
                ["name"] = "灞波儿奔",
            },
        },
        ["max"] = 5000,
    },
    [2] =
    {
        ["type2"] =
        {
            [1] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
            [2] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
        },
        ["type"] =
        {
            [1] = "1",
            [2] = 2,
            [3] = 3,
        },
        ["id"] = 2,
        ["correct"] = false,
        ["min"] = 2000,
        ["servant"] =
        {
            [1] =
            {
                ["id"] = 800032,
                ["name"] = "灞波儿奔",
            },
            [2] =
            {
                ["id"] = 800031,
                ["name"] = "奔波儿灞",
            },
            [3] =
            {
                ["id"] = 800028,
                ["name"] = "蛇后",
            },
        },
        ["fate"] = "三贱客",
        ["player"] =
        {
            [800031] =
            {
                ["id"] = 800031,
                ["name"] = "奔波儿灞",
            },
            [800032] =
            {
                ["id"] = 800032,
                ["name"] = "灞波儿奔",
            },
            [800028] =
            {
                ["id"] = 800028,
                ["name"] = "蛇后",
            },
        },
        ["max"] = 5000,
    },
    [3] =
    {
        ["type2"] =
        {
            [1] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
            [2] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
        },
        ["type"] =
        {
            [1] = "1",
            [2] = 2,
            [3] = 3,
        },
        ["id"] = 3,
        ["correct"] = true,
        ["min"] = 2000,
        ["servant"] =
        {
            [1] =
            {
                ["id"] = 800016,
                ["name"] = "白骨精",
            },
            [2] =
            {
                ["id"] = 800027,
                ["name"] = "百花羞",
            },
            [3] =
            {
                ["id"] = 800028,
                ["name"] = "",
            },
        },
        ["fate"] = "金兰之好",
        ["player"] =
        {
            [800016] =
            {
                ["id"] = 800016,
                ["name"] = "白骨精",
            },
            [800027] =
            {
                ["id"] = 800027,
                ["name"] = "百花羞",
            },
            [800028] =
            {
                ["id"] = 800028,
                ["name"] = "",
            },
        },
        ["max"] = 5000,
    },
    [4] =
    {
        ["type2"] =
        {
            [1] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
            [2] =
            {
                ["id"] = 1,
                ["cnt"] = 2,
            },
        },
        ["type"] =
        {
            [1] = "1",
            [2] = 2,
            [3] = 3,
        },
        ["id"] = 4,
        ["correct"] = true,
        ["min"] = 1000,
        ["servant"] =
        {
            [1] =
            {
                ["id"] = 800016,
                ["name"] = "白骨精",
            },
            [2] =
            {
                ["id"] = 800063,
                ["name"] = "孙小空",
            },
            [3] =
            {
                ["id"] = 800028,
                ["name"] = "",
            },
        },
        ["fate"] = "失之交臂",
        ["player"] =
        {
            [800016] =
            {
                ["id"] = 800016,
                ["name"] = "白骨精",
            },
            [800063] =
            {
                ["id"] = 800063,
                ["name"] = "孙小空",
            },
            [800028] =
            {
                ["id"] = 800028,
                ["name"] = "",
            },
        },
        ["max"] = 3000,
    },
}

基本上可以满足现实需要。

Excel数据读取部分我采用GO做的,读出来后保存为*_tmp.lua的临时数据。里面是一个2维的table表,与excel表一一对应。GO代码如下:

  1 /*------------------------------------------------------------------
  2 // 著作版权:Copyright (C) liuxb
  3 // 创建时间:[liuxb|20160704]
  4 // 功能描述:字符串转换
  5 //
  6 // 修改时间:
  7 // 修改描述:
  8 // 
  9 //----------------------------------------------------------------*/
 10 
 11 package main
 12  
 13 import (
 14     "flex/log"
 15     "github.com/tealeg/xlsx"
 16     "os"
 17     "strings"
 18     "strconv"
 19 )
 20 
 21 type column struct {
 22     name string 
 23     type_ string 
 24 }
 25 
 26 type table struct {
 27     columns []column
 28     rows [][]string 
 29 }
 30 
 31 var valid string
 32 
 33 func init() {
 34     valid = "valid"
 35 }
 36 
 37 func getStrings(cells []*xlsx.Cell) []string {
 38     str := make([]string, 0)
 39     for _, cell := range cells {
 40         s, err := cell.String()
 41         if err != nil {
 42             log.Error(err.Error())
 43             s = "" 
 44         }        
 45         str = append(str, s)
 46     }
 47     return str 
 48 }
 49 
 50 func getColumn(types []string, names []string) []column {
 51     cols := make([]column, 0)
 52     if len(types)<len(names) {
 53         for i := len(types); i<len(names); i++ {
 54             types = append(types, "s")
 55         }
 56     }
 57     for i := 0; i<len(types); i++ {
 58         types[i] = strings.ToLower(types[i])
 59         switch types[i] {
 60         case "n":
 61         case "i":
 62             types[i] = "n"
 63         case "int":
 64             types[i] = "n"
 65         case "float":
 66             types[i] = "n"
 67         case "number":
 68             types[i] = "n"
 69         case "b":
 70         case "bool":
 71             types[i] = "b"
 72         case "string":
 73             types[i] = "s"
 74         default:
 75             types[i] = "s"
 76         }
 77     }
 78     for i:= 0; i<len(names); i++ {
 79         if names[i] == "" {
 80             break 
 81         }
 82         col := column{
 83             name : names[i],
 84             type_: types[i],
 85         }
 86         v := strings.ToLower(col.name)
 87         if v == valid {
 88             col.name = v 
 89         }
 90         cols = append(cols, col)
 91     }
 92     return cols 
 93 }
 94 
 95 func getRow(cols []column, vals []string) []string {
 96     if len(vals)<len(cols) {
 97         for i := len(vals); i<len(cols); i++ {
 98             vals = append(vals, "")
 99         }        
100     }
101     if len(vals)>len(cols) {
102         vals = vals[0:len(cols)]
103     }    
104     for i:= 0; i<len(cols); i++ {
105         if cols[i].name == valid {
106             v := strings.ToLower(vals[i])
107             if v == "false" || v == "0" {
108                 return nil 
109             }
110         }
111     }
112     return vals 
113 }
114 
115 func getTable(start int, rows []*xlsx.Row) *table {
116     if len(rows)<4 || len(rows)<start {
117         return nil 
118     }
119     t := new(table)
120     t.rows = make([][]string, 0)
121     
122     types := getStrings(rows[0].Cells)
123     names := getStrings(rows[1].Cells)
124     cols := getColumn(types, names)
125     t.columns = cols 
126     for i := start; i<len(rows); i++ {
127         row := getRow(cols, getStrings(rows[i].Cells))
128         if row != nil {
129             t.rows = append(t.rows, row)
130         }
131     }
132     return t 
133 }
134 
135 func toLuaTable(tableName string, t *table) string {
136     lines := "g_tmp_" + tableName + " = {\n"
137     if t!=nil {
138         for id, row := range t.rows {
139             lines = lines + "\t[" + strconv.Itoa(id+1) + "] = {\n"
140             for k, v := range row {
141                 if t.columns[k].name != valid {
142                     line := "\t\t" + t.columns[k].name + " = "
143                     if t.columns[k].type_ == "s" {
144                         line = line + "\"" + v + "\",\n"
145                     }else if t.columns[k].type_ == "b" {
146                         v = strings.ToLower(v)
147                         if v == "true" || v == "1" {
148                             v = "true" 
149                         }else {
150                             v = "false"
151                         }
152                         line = line + v + ",\n"
153                     }else{
154                         _, err := strconv.ParseFloat(v, 32)
155                         if err != nil {
156                             v = "nil"
157                         }
158                         line = line + v + ",\n"
159                     }
160                     lines = lines + line 
161                 }
162             }
163             lines = lines + "\t},\n"
164         }
165     }
166     lines = lines + "}"
167     return lines
168 }
169 
170 func main() {
171     log.SetFilename("xlsx")
172     excelFileName := os.Args[1]
173     outPath := os.Args[2]
174     start, e := strconv.Atoi(os.Args[3])
175     if e!=nil {
176         log.Error(e.Error())
177         return        
178     }
179     xlFile, err := xlsx.OpenFile(excelFileName)
180     if err != nil {
181         log.Error(err.Error())
182         return 
183     }
184     for _, sheet := range xlFile.Sheets {
185         fileName := outPath + "\\" + sheet.Name + "_tmp.lua"
186         file, err := os.Create(fileName)
187         if err != nil {
188             log.Error(err.Error())
189             return 
190         }
191         t := getTable(start-1, sheet.Rows)
192         luaStr := toLuaTable(sheet.Name, t)
193         file.WriteString(luaStr)
194     }
195 }

将临时数据转换为自定义的结构导出,我用了两个lua文件,分别为import_base.lua:

  1 --[[*------------------------------------------------------------------
  2 // 著作版权:Copyright (C) liuxb
  3 // 创建时间:[liuxb|20160704]
  4 // 功能描述:将二维数据表转换为自定义表结构
  5 //
  6 // 修改时间:
  7 // 修改描述:
  8 // 
  9 //----------------------------------------------------------------]]
 10 
 11 local table_word = 'ooooo_'
 12 local right_word = 'xxxxx_'
 13 
 14 function table_name(name)
 15     return table_word..name
 16 end 
 17 
 18 function right_name(name)
 19     return right_word..name
 20 end
 21 
 22 local function string_to_table(str)
 23     local ret = loadstring("return "..str)()  
 24     return ret  
 25 end
 26 
 27 local head_struct_sample = {
 28     id = 'id',
 29     name = 'name', 
 30     buff = {
 31         [1] = 'buff_id1',
 32         [2] = 'buff_id2',
 33     },    
 34     skill = {        
 35         [1] = {
 36             id = 'skill_id',
 37             level = 'skill_level',        
 38         },
 39         [2] = {
 40             id = 'skill_id2',
 41             level = 'skill_level2',        
 42         }
 43     },
 44     skill2 = {        
 45         [right_name('skill_id')] = {
 46             id = 'skill_id',
 47             level = 'skill_level',        
 48         },
 49         [right_name('skill_id2')] = {
 50             id = 'skill_id2',
 51             level = 'skill_level2',        
 52         }
 53     },
 54     reward = table_name('reward'),
 55 }
 56 
 57 
 58 
 59 -- 简单结构,如:id = id 
 60 function field_sample(row, name, original_row, original_name)
 61     if original_row[original_name] == nil then 
 62         print('not exist column name:'..original_name..' in xlsx line 62')
 63         --return 1/nil
 64     else 
 65         row[name] = original_row[original_name]
 66     end     
 67 end 
 68 
 69 -- 字符串转table结构
 70 function field_string_table(row, name, original_row, original_name)
 71     org_name = string.sub(original_name,7)
 72     if org_name == nil or original_row[org_name] == nil then 
 73         print('not exist column name:'..(org_name or original_name)..' in xlsx line 73')
 74         --return 1/nil 
 75     else 
 76         row[name] = string_to_table(original_row[org_name])
 77     end     
 78 end 
 79 
 80 local function create_row(head_struct, row, t)
 81     if t == nil then t = {} end 
 82     for k, v in pairs(head_struct) do 
 83         start, _ = string.find(k, right_word)
 84         if start ~= 1 then    -- new key
 85             if type(v) == "string" then 
 86                 start, _ = string.find(v, table_word)
 87                 if start == 1 then    -- str_table
 88                     field_string_table(t, k, row, v)
 89                 else
 90                     field_sample(t, k, row, v)
 91                 end
 92             elseif type(v) == "table" then 
 93                 t[k] = {}
 94                 t[k] = create_row(v, row, t[k]) 
 95             else
 96                 print('not exist column name:'..v..' in xlsx line 96')
 97                 return 1/nil 
 98             end         
 99         else  -- key from xlsx 
100             k = string.sub(k,7)
101             if k == nil or row[k] == nil then 
102                 print('not exist column name:'..(k or 'nil')..' in xlsx line 102')
103                 return 1/nil                
104             end 
105             if type(v) == "string" then 
106                 start, _ = string.find(v, table_word)
107                 if start == 1 then    -- str_table
108                     field_string_table(t, row[k], row, v)
109                 else
110                     field_sample(t, row[k], row, v)
111                 end
112             elseif type(v) == "table" then 
113                 t[row[k]] = {}
114                 t[row[k]] = create_row(v, row, t[row[k]]) 
115             else
116                 print('not exist column name:'..v..' in xlsx line 116')
117                 return 1/nil 
118             end             
119         end 
120     end
121     return t 
122 end 
123 
124 function make_table(head_struct, original_table, index_name)
125     if index_name == nil then 
126         index_name = 'id'
127     end 
128     local t = {}
129     for _, row in pairs(original_table) do 
130         local r = create_row(head_struct, row) 
131         t[r[index_name]] = r 
132     end 
133     return t 
134 end

 

import_base_ex.lua中主要是将数据写入文本:

 1 --[[*------------------------------------------------------------------
 2 // 著作版权:Copyright (C) liuxb
 3 // 创建时间:[liuxb|20160704]
 4 // 功能描述:将自定义表结构导出文本
 5 //
 6 // 修改时间:
 7 // 修改描述:
 8 // 
 9 //----------------------------------------------------------------]]
10 
11 assert(require 'import_base')
12 require('std')
13 
14 require("json")
15 --output_server_path = [[../../../Server/data/lua/data/]]
16 output_server_path = [[./data_lua/]]
17 out_json_path = [[./data_json/]]
18 
19 
20 
21 function make_server_lua_file(name, data)
22     local name_adj = 'g_'.. name .. '_cfg'
23     local content = name_adj .. ' = ' .. prettytostring(data)
24     local out_name_adj = 'd_' .. name .. '.lua'
25     local out_full = output_server_path .. out_name_adj
26     local f = io.open(out_full,'w+')
27     print(out_full)
28     f:write(content)
29     f:close()
30 end
31 
32 function make_json_file(name, data)
33     local content = json.encode(data)
34     local out_full = out_json_path..name..'.json'
35     local f = io.open(out_full, 'w+')
36     print(out_full)
37     f:write(content)
38     f:close()
39 end

接下来是最后一个fate.lua,每个excel表都需要写一个lua文件,用来存放最开始展示的自定义表结构:head_struct。

 1 package.path = package.path .. ";.\\base\\?.lua;.\\tmp\\?.lua"
 2 require 'os'
 3 assert(require 'import_base')
 4 assert(require 'import_base_ex')
 5 assert(require 'fate_tmp')
 6 
 7 local head_struct = {
 8     id = 'id',
 9     fate = 'fate',
10     servant = {
11         [1] = {
12             id = 'servant1_id',
13             name = 'name1'
14         },
15         [2] = {
16             id = 'servant2_id',
17             name = 'name2'
18         },
19         [3] = {
20             id = 'servant3_id',
21             name = 'name3'
22         },
23     },
24     player = {
25         [right_name('servant1_id')] = {
26             id = 'servant1_id',
27             name = 'name1'
28         },
29         [right_name('servant2_id')] = {
30             id = 'servant2_id',
31             name = 'name2'
32         },
33         [right_name('servant3_id')] = {
34             id = 'servant3_id',
35             name = 'name3'
36         },
37     },
38     type = table_name('type'),
39     type2 = table_name('type2'),
40     min = 'min',
41     max = 'max',
42     correct = 'correct'
43 }
44 
45 function make_fate_lua()
46     local t = make_table(head_struct, g_tmp_fate, 'id')
47     make_server_lua_file('fate', t)
48 end
49 
50 function make_fate_json()
51     local t = make_table(head_struct, g_tmp_fate, 'id')
52     make_json_file('fate', t)
53 end
54 
55 os.execute("xlsx.exe .\\xlsx\\fate.xlsx .\\tmp\\ 4")
56 
57 make_fate_lua()
58 make_fate_json()

 

posted @ 2016-07-04 10:58  traits  阅读(363)  评论(0编辑  收藏  举报