using System.Linq; using System.Collections.Generic; using System.IO; using System.Text; namespace GameEditor.Core.DataConfig { public class DataToOptimizeLuaExporter { private DataSheet dataSheet; private DataConfigSetting setting; public DataToOptimizeLuaExporter(DataSheet sheet, DataConfigSetting setting) { dataSheet = sheet; this.setting = setting; summary = new DataToOptimizeLuaSummary(dataSheet); CreateSummary(); } public static bool CheckIsExport(DataSheet sheet) { int count = 0; for (int i = 0; i < sheet.fields.Count; i++) { DataField dfInfo = sheet.fields[i]; if (dfInfo.exportType == DataFieldExportType.None || dfInfo.exportType == DataFieldExportType.Server || dfInfo.exportType == DataFieldExportType.Unexport) { continue; } count++; } return count > 0; } private DataToOptimizeLuaSummary summary; private void CreateSummary() { for (int i = 0; i < dataSheet.fields.Count; i++) { DataField dfInfo = dataSheet.fields[i]; if (dfInfo.exportType == DataFieldExportType.None || dfInfo.exportType == DataFieldExportType.Server || dfInfo.exportType == DataFieldExportType.Unexport) { continue; } summary.fields.Add(dfInfo); summary.fieldIndexs.Add(i); } } public void Export() { string dirPath = setting.clientOutputDir; if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } summary.Export(dataSheet.name, dirPath); string subDirPath = dirPath + "/" + dataSheet.name; if (Directory.Exists(subDirPath)) { Directory.Delete(subDirPath, true); } } } public class DataToOptimizeLuaSummary { public DataSheet dataSheet; public List fields = new List(); public List fieldIndexs = new List(); public DataToOptimizeLuaSummary(DataSheet dataSheet) { this.dataSheet = dataSheet; } public void Export(string name, string dirPath) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("local {0} = {{\n", name); Dictionary IdDic = new Dictionary(); List Ids = new List(); for (int i = 0; i < dataSheet.lines.Count; i++) { DataField dfInfo = fields[0]; var cell = dataSheet.lines[i][0]; string data = DataHelper.GetClientValByDefault(cell, dfInfo.defaultContent, dfInfo.fieldType); if (!string.IsNullOrEmpty(data)) { if (!IdDic.ContainsKey(data)) { Ids.Add(data); IdDic[data] = i; } else { UnityEngine.Debug.LogError("存在重复的id! Config :" + name + " id:" + data + " orgin Line:" + (IdDic[data] + 8) + " error Line:" + (i + 8)); } } } dataSheet.lines.Sort((c1, c2) => { int i1 = int.Parse(c1[0]); int i2 = int.Parse(c2[0]); return i1 - i2; }); sb.AppendFormat("__count = {0},\n", Ids.Count); List ids = new List(); List idslz = new List(); for (int i = 0; i < Ids.Count; i++) { DataField dfInfo = fields[0]; var cell = dataSheet.lines[IdDic[Ids[i]]][0]; string data = DataHelper.GetClientValByDefault(cell, dfInfo.defaultContent, dfInfo.fieldType); ids.Add(data); } CalLz77List(ids, ref idslz); sb.Append("__indexs = {"); for (int i = 0; i < idslz.Count; i++) { sb.AppendFormat("{0},", idslz[i]); } if (idslz.Count > 0) sb.Remove(sb.Length - 1, 1); sb.AppendLine("},"); Dictionary record = new Dictionary(); for (int i = 0; i < fields.Count - 1; i++) { DataField dfInfo = fields[i + 1]; List list = new List(); for (int j = 0; j < Ids.Count; j++) { var cell = dataSheet.lines[IdDic[Ids[j]]][fieldIndexs[i + 1]]; list.Add(DataHelper.GetClientValByDefault(cell, dfInfo.defaultContent, dfInfo.fieldType)); } List d = new List(); List d_idx = new List(); string dflt = null; int ntimes = CalDedaultList(list, ref dflt, ref d, ref d_idx); if (dflt != null) { DataHelper.GetValueString(dfInfo, dflt, (s, s1) => { int nn; if (int.TryParse(s, out nn)) { record[s] = nn; } else { if (!record.ContainsKey(s)) { record[s] = 1; } else { record[s]--; } } return s; }); } for (int j = 0; j < d.Count; j++) { DataHelper.GetValueString(dfInfo, d[j], (s, s1) => { int nn; if (int.TryParse(s, out nn)) { record[s] = nn; } else { if (!record.ContainsKey(s)) { record[s] = 1; } else { record[s]--; } } return s; }); } } int n; var dicSort = from objDic in record orderby objDic.Value ascending select objDic; Dictionary ItemIndex = new Dictionary(); int index = 0; List values = new List(); List values_item = new List(); foreach (KeyValuePair kvp in dicSort) { if (int.TryParse(kvp.Key, out n)) { ItemIndex[kvp.Key] = ++index; values.Add(kvp.Key); } } CalLz77List(values, ref values_item); sb.Append("__values = {"); for (int i = 0; i < values_item.Count; i++) { sb.AppendFormat("{0},", values_item[i]); } if (values_item.Count > 0) sb.Remove(sb.Length - 1, 1); sb.AppendLine("},"); if (values.Count < record.Count) { sb.AppendFormat("__exVals = {{{0},", record.Count - values.Count); foreach (KeyValuePair kvp in dicSort) { if (!int.TryParse(kvp.Key, out n)) { var st = kvp.Key; double d; if (double.TryParse(st, out d) && (int)d == 0) { sb.Append(string.Format("{0},", st.Replace("0.", "."))); } else { sb.Append(string.Format("{0},", st)); } ItemIndex[kvp.Key] = ++index; } } sb.Remove(sb.Length - 1, 1); sb.AppendLine("},"); } List> lineRefs = new List>(); List lineDflt = new List(); List> lineDL_idx = new List>(); List>> ref_tbs = new List>>(); List> lineTb_idx = new List>(); for (int i = 0; i < fields.Count - 1; i++) { List list = new List(); DataField dfInfo = fields[i + 1]; Dictionary> tbList = new Dictionary>(); for (int j = 0; j < Ids.Count; j++) { var cell = dataSheet.lines[IdDic[Ids[j]]][fieldIndexs[i + 1]]; string data = DataHelper.GetClientValByDefault(cell, dfInfo.defaultContent, dfInfo.fieldType); if (dfInfo.fieldType != DataFieldType.Mut) list.Add(DataHelper.GetValueString(dfInfo, data, (s, s1) => ItemIndex[s].ToString())); else { list.Add(DataHelper.GetValueString(dfInfo, data, (s, s1) => { var rs = ItemIndex[s].ToString(); if (!string.IsNullOrEmpty(s1)) { if (!tbList.ContainsKey(s1)) { tbList[s1] = new Dictionary(); } tbList[s1][j] = rs; } return rs; })); } } List d = new List(); List d_item = new List(); List d_idx = new List(); List d_idx_item = new List(); List d_tbIdx = new List(); string dflt = null; CalDedaultList(list, ref dflt, ref d, ref d_idx); lineDflt.Add(dflt); if (dfInfo.fieldType != DataFieldType.Mut) { CalLz77List(d, ref d_item); lineRefs.Add(d_item); } else { for (int j = 0; j < d_idx.Count; j++) //当list引用表有默认值时,记录剔除默认值后,list引用位置 { d_tbIdx.Add(d_idx[j]); } lineRefs.Add(d); } CalLz77List(d_idx, ref d_idx_item); lineDL_idx.Add(d_idx_item); ref_tbs.Add(tbList); lineTb_idx.Add(d_tbIdx); } sb.AppendLine("__fields = {"); for (int i = 0; i < fields.Count; i++) { sb.AppendFormat("\t\'{0}\'", fields[i].name); sb.AppendLine(i != fields.Count - 1 ? "," : ""); } sb.AppendLine("},"); sb.AppendLine("__defaults = {"); for (int i = 0; i < fields.Count - 1; i++) { var dflt = lineDflt[i]; if (string.IsNullOrEmpty(dflt)) { sb.Append("\tnil"); } else { sb.AppendFormat("\t{0}", dflt); } sb.Append(i != fields.Count - 2 ? ",\n" : "\n"); } sb.AppendLine("},"); List>> ref_tbLists = new List>>(); List>> ref_tbPosLists = new List>>(); for (int i = 0; i < fields.Count - 1; i++) { DataField dfInfo = fields[i + 1]; var d = ref_tbs[i]; List> tb_list = new List>(); List> tbPos_list = new List>(); if (lineRefs[i].Count == 0 || dfInfo.fieldType != DataFieldType.Mut) { } else { var keys = new List(d.Keys); for (int j = 0; j < keys.Count; j++) { var key = keys[j]; var kdic = d[key]; List list = new List(); List list_item = new List(); List poslist = new List(); List poslist_item = new List(); for (int k = 0; k < lineRefs[i].Count; k++) { var idx = lineTb_idx[i].Count > 0 ? int.Parse(lineTb_idx[i][k]) : k + 1; //有默认值,则读取引用表id,否则读取顺序索引 if (kdic.ContainsKey(idx - 1)) { list.Add(kdic[idx - 1]); if (kdic.Count < lineRefs[i].Count && kdic.Count <= (lineRefs[i].Count + 1) / 2) { poslist.Add((k + 1).ToString()); } } else { if (kdic.Count < lineRefs[i].Count && kdic.Count > (lineRefs[i].Count + 1) / 2) { poslist.Add((k + 1).ToString()); } } } CalLz77List(list, ref list_item); tb_list.Add(list_item); CalLz77List(poslist, ref poslist_item); tbPos_list.Add(poslist_item); } } ref_tbLists.Add(tb_list); ref_tbPosLists.Add(tbPos_list); } sb.AppendLine("__refs = {"); for (int i = 0; i < fields.Count - 1; i++) { DataField dfInfo = fields[i + 1]; var d = lineRefs[i]; if (d.Count == 0) { sb.Append("\tnil"); } else { if (dfInfo.fieldType == DataFieldType.Mut) { var dic = ref_tbs[i]; var d_info = ref_tbLists[i]; var d_pos = ref_tbPosLists[i]; sb.Append("\t{"); var keys = new List(dic.Keys); for (int j = 0; j < keys.Count; j++) { var key = keys[j]; sb.AppendFormat("{{{0},{{", key); var kdic = d_info[j]; for (int k = 0; k < kdic.Count; k++) { sb.AppendFormat("{0}", kdic[k]); if (k < kdic.Count - 1) { sb.Append(","); } } sb.Append("}"); var kPos = d_pos[j]; if (kPos.Count > 0) { sb.Append(",{"); for (int k = 0; k < kPos.Count; k++) { sb.AppendFormat("{0}", kPos[k]); if (k < kPos.Count - 1) { sb.Append(","); } } sb.Append("}}"); } else { sb.Append("}"); } if (j < keys.Count - 1) { sb.Append(","); } } sb.Append("}"); } else { sb.AppendFormat("\t{{"); for (int j = 0; j < d.Count; j++) { sb.AppendFormat("{0}", d[j]); if (j < d.Count - 1) { sb.Append(","); } } sb.Append("}"); } } sb.Append(i != fields.Count - 2 ? ",\n" : "\n"); } sb.AppendLine("},"); sb.AppendLine("__refPoss = {"); for (int i = 0; i < fields.Count - 1; i++) { var d = lineDL_idx[i]; if (d.Count == 0) { sb.Append("\tnil"); } else { sb.AppendFormat("\t{{"); for (int j = 0; j < d.Count; j++) { sb.AppendFormat("{0}", d[j]); if (j < d.Count - 1) { sb.Append(","); } } sb.Append("}"); } sb.Append(i != fields.Count - 2 ? ",\n" : "\n"); } sb.AppendLine("},"); sb.Append("}\n"); sb.AppendFormat("return {0}", name); string fileContent = sb.ToString(); File.WriteAllText(string.Format("{0}/{1}.lua", dirPath, name), fileContent); } //计算一列数据是否需要默认值 public int CalDedaultList(List dataList, ref string dflt, ref List d, ref List d_idx) { if (dataList.Count == 1) { dflt = dataList[0]; return 1; } string flag = null; int ntimes = 0; for (int i = 0; i < dataList.Count; i++) { if (ntimes == 0) { flag = dataList[i]; ntimes = 1; } else { if (flag == dataList[i]) { ntimes++; } else { ntimes--; } } } ntimes = 0; for (int i = 0; i < dataList.Count; i++) { if (flag == dataList[i]) { ntimes++; } } //if (ntimes >= dataList.Count / 3 * 2) if (false) { dflt = flag; for (int i = 0; i < dataList.Count; i++) { if (flag != dataList[i]) { d.Add(dataList[i]); d_idx.Add((i + 1).ToString()); } } } else { d = dataList; } return ntimes; } public void CalDeltaStringList(ref List dataList) { if (dataList.Count <= 1) return; int odata = 0; try { odata = int.Parse(dataList[0]); } catch (System.Exception ex) { int a = 9; throw ex; } int oId = 0; string oData = dataList[0]; List d = new List(); d.Add(oData); for (int i = 1; i < dataList.Count; i++) { int item = int.Parse(dataList[i]); dataList[i] = (item - odata).ToString(); if (dataList[i] == oData && item - odata >= 0) { if (i == dataList.Count - 1) { d[d.Count - 1] = PrintPos(oData == "0" || oData == "1" ? oData : "-" + oData, (i - oId + 1).ToString()); } } else { if (i - oId > 1) { d[d.Count - 1] = PrintPos(oData == "0" || oData == "1" ? oData : "-" + oData, (i - oId).ToString()); } oData = dataList[i]; d.Add(oData); oId = i; } odata = item; } dataList = d; } public void Match(List text, Dictionary> dic, int t1, ref int count, ref int off) { int t2 = 2 * t1 <= text.Count ? t1 : text.Count - t1; if (t1 < t2 || t2 < 2) { count = 0; off = -1; return; } int index = -1; int max = 0; if (dic.ContainsKey(text[t1])) { int q; bool flag; var qL = dic[text[t1]]; max = 1; for (int i = qL.Count - 1; i >= 0; i--) { int c = System.Math.Min(t1 - qL[i], t2); q = max; for (int j = max; j < c; j++) { if (text[j + t1] != text[j + qL[i]]) { break; } else { q++; } } if (q > max) { flag = true; for (int j = 1; j < max; j++) { if (text[j + t1] != text[j + qL[i]]) { flag = false; break; } } if (flag) { max = q; index = qL[i]; if (max == t2) { count = max; off = index; return; } } } } if (max > 1) { int qLen = 0; int iLen = (t1 - index).ToString().Length + 3; flag = true; for (int i = 0; i < max; i++) { qLen += text[i + index].Length + 1; if (qLen > iLen) { flag = false; break; } } if (flag) { count = 0; off = -1; return; } } } count = max; off = index; } //执行lz77压缩算法 public void CalLz77List(List dataList, ref List d) { //d = dataList; //return; CalDeltaStringList(ref dataList); if (dataList.Count <= 1) { for (int k = 0; k < dataList.Count; k++) { d.Add(dataList[k]); } return; } int i = 0; int offset = -1; int count = 0; Dictionary> dic = new Dictionary>(); while (i < dataList.Count) { Match(dataList, dic, i, ref count, ref offset); if (count < 2) { d.Add(dataList[i]); if (!dic.ContainsKey(dataList[i])) { dic[dataList[i]] = new List(); } dic[dataList[i]].Add(i); i++; } else { if (i - offset == count) { d.Add(PrintPos(count.ToString(), "1")); } else { d.Add(PrintPos((i - offset).ToString(), count.ToString())); } for (int j = 0; j < count; j++) { if (!dic.ContainsKey(dataList[j])) { dic[dataList[j]] = new List(); } dic[dataList[i + j]].Add(i + j); } i += count; } } } //输入两个参数x,y,将y反序成z,以"x.z"形式输出 public string PrintPos(string x, string y) { if (y.Length > 1) { char[] cArray = y.ToCharArray(); StringBuilder reverse = new StringBuilder(); for (int i = cArray.Length - 1; i >= 0; i--) { reverse.Append(cArray[i]); } y = reverse.ToString(); } return string.Format("{0}.{1}", x == "0" ? "" : x, y); } } }