【优化】优化LubanAssistant保存,只保存改变的记录。优化记录显示顺序,如果key为int和long类型,按从小到大排序,而不是按字符串顺序排序。

main
walon 2021-10-22 14:33:12 +08:00
parent fb55a7a4c6
commit 5665e76299
14 changed files with 186 additions and 35 deletions

View File

@ -1,4 +1,5 @@
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System.Collections.Generic; using System.Collections.Generic;
@ -17,6 +18,16 @@ namespace Luban.Job.Cfg.Datas
this.Datas = datas; this.Datas = datas;
} }
public override bool Equals(object obj)
{
return obj is DArray d && DataUtil.IsCollectionEqual(Datas, d.Datas);
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);

View File

@ -1,5 +1,6 @@
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils;
using System.Collections.Generic; using System.Collections.Generic;
namespace Luban.Job.Cfg.Datas namespace Luban.Job.Cfg.Datas
@ -21,6 +22,16 @@ namespace Luban.Job.Cfg.Datas
this.Fields = fields; this.Fields = fields;
} }
public override bool Equals(object obj)
{
return obj is DBean d && string.Equals(ImplType?.FullName, d.ImplType?.FullName) && DataUtil.IsCollectionEqual(Fields, d.Fields);
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public DType GetField(string fieldName) public DType GetField(string fieldName)
{ {
if (ImplType.TryGetField(fieldName, out var _, out var findex)) if (ImplType.TryGetField(fieldName, out var _, out var findex))

View File

@ -11,6 +11,16 @@ namespace Luban.Job.Cfg.Datas
{ {
} }
public override bool Equals(object obj)
{
return obj is DBytes d && System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Value, d.Value);
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);

View File

@ -20,6 +20,16 @@ namespace Luban.Job.Cfg.Datas
this._localTime = (int)new DateTimeOffset(time).ToUnixTimeSeconds(); this._localTime = (int)new DateTimeOffset(time).ToUnixTimeSeconds();
} }
public override bool Equals(object obj)
{
return obj is DDateTime d && Time == d.Time;
}
public override int GetHashCode()
{
return _localTime.GetHashCode();
}
public int GetUnixTime(TimeZoneInfo asTimeZone) public int GetUnixTime(TimeZoneInfo asTimeZone)
{ {
if (asTimeZone == null || asTimeZone == TimeZoneInfo.Local) if (asTimeZone == null || asTimeZone == TimeZoneInfo.Local)

View File

@ -17,6 +17,16 @@ namespace Luban.Job.Cfg.Datas
{ {
} }
public override bool Equals(object obj)
{
return obj is DFshort d && Value == d.Value;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);
@ -36,15 +46,5 @@ namespace Luban.Job.Cfg.Datas
{ {
return visitor.Accept(this, x); return visitor.Accept(this, x);
} }
public override bool Equals(object obj)
{
return obj is DFshort o && o.Value == this.Value;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
} }
} }

View File

@ -1,4 +1,5 @@
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System.Collections.Generic; using System.Collections.Generic;
@ -17,6 +18,17 @@ namespace Luban.Job.Cfg.Datas
this.Datas = datas; this.Datas = datas;
} }
public override bool Equals(object obj)
{
return obj is DList d && DataUtil.IsCollectionEqual(Datas, d.Datas);
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);

View File

@ -1,7 +1,9 @@
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Luban.Job.Cfg.Datas namespace Luban.Job.Cfg.Datas
{ {
@ -27,6 +29,16 @@ namespace Luban.Job.Cfg.Datas
} }
} }
public override bool Equals(object obj)
{
return obj is DMap d && Datas.Count == d.Datas.Count && Datas.All(e => d.Datas.TryGetValue(e.Key, out var v) && object.Equals(e.Value, v));
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);

View File

@ -1,4 +1,5 @@
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -27,6 +28,16 @@ namespace Luban.Job.Cfg.Datas
} }
} }
public override bool Equals(object obj)
{
return obj is DList d && DataUtil.IsCollectionEqual(Datas, d.Datas);
}
public override int GetHashCode()
{
throw new System.NotSupportedException();
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x) public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{ {
visitor.Accept(this, x); visitor.Accept(this, x);

View File

@ -157,6 +157,23 @@ namespace Luban.Job.Cfg.Utils
default: return ""; default: return "";
} }
} }
public static bool IsCollectionEqual(List<DType> a, List<DType> b)
{
if (a.Count == b.Count)
{
for (int i = 0, n = a.Count; i < n; i++)
{
if (!object.Equals(a[i], b[i]))
{
return false;
}
}
return true;
}
return false;
}
//public static string Data2String(DType data) //public static string Data2String(DType data)
//{ //{
// var s = new StringBuilder(); // var s = new StringBuilder();

View File

@ -114,6 +114,7 @@ namespace LubanAssistant
var tableDataInfo = LastLoadTableData = await DataLoaderUtil.LoadTableDataAsync(RootDefineFile, InputDataDir, rawSheet.TableName); var tableDataInfo = LastLoadTableData = await DataLoaderUtil.LoadTableDataAsync(RootDefineFile, InputDataDir, rawSheet.TableName);
var title = ExcelUtil.ParseTitles(sheet); var title = ExcelUtil.ParseTitles(sheet);
ExcelUtil.FillRecords(sheet, rawSheet.TitleRowCount, title, tableDataInfo); ExcelUtil.FillRecords(sheet, rawSheet.TitleRowCount, title, tableDataInfo);
MessageBox.Show("加载成功");
} }
catch (Exception e) catch (Exception e)
{ {
@ -158,7 +159,7 @@ namespace LubanAssistant
} }
} }
private void SaveRecords(Action<Worksheet, int, TableDataInfo, DefTable, Title> saveTask) private void SaveRecords(Func<Worksheet, int, TableDataInfo, DefTable, Title, Task> saveTask)
{ {
Worksheet sheet = Globals.LubanAssistant.Application.ActiveSheet; Worksheet sheet = Globals.LubanAssistant.Application.ActiveSheet;
@ -181,7 +182,7 @@ namespace LubanAssistant
var tableDef = await DataLoaderUtil.LoadTableDefAsync(RootDefineFile, InputDataDir, tableName); var tableDef = await DataLoaderUtil.LoadTableDefAsync(RootDefineFile, InputDataDir, tableName);
var title = ExcelUtil.ParseTitles(sheet); var title = ExcelUtil.ParseTitles(sheet);
saveTask(sheet, rawSheet.TitleRowCount, LastLoadTableData, tableDef, title); await saveTask(sheet, rawSheet.TitleRowCount, LastLoadTableData, tableDef, title);
} }
catch (Exception e) catch (Exception e)
{ {
@ -192,15 +193,16 @@ namespace LubanAssistant
private void BtnSaveAllClick(object sender, RibbonControlEventArgs e) private void BtnSaveAllClick(object sender, RibbonControlEventArgs e)
{ {
SaveRecords((Worksheet sheet, int titleRowNum, TableDataInfo tableDataInfo, DefTable defTable, Title title) => SaveRecords(async (Worksheet sheet, int titleRowNum, TableDataInfo tableDataInfo, DefTable defTable, Title title) =>
{ {
int usedRowNum = sheet.UsedRange.Rows.Count; int usedRowNum = sheet.UsedRange.Rows.Count;
int firstDataRowNum = titleRowNum + 2; int firstDataRowNum = titleRowNum + 2;
if (firstDataRowNum <= usedRowNum) if (firstDataRowNum <= usedRowNum)
{ {
var newRecords = ExcelUtil.LoadRecordsInRange(defTable, sheet, title, (sheet.Range[$"A{firstDataRowNum}:A{usedRowNum}"]).EntireRow); var newRecords = ExcelUtil.LoadRecordsInRange(defTable, sheet, title, (sheet.Range[$"A{firstDataRowNum}:A{usedRowNum}"]).EntireRow);
ExcelUtil.SaveRecords(InputDataDir, defTable, newRecords); await ExcelUtil.SaveRecordsAsync(InputDataDir, defTable, GetModifyRecords(LastLoadTableData, newRecords));
CleanRemovedRecordFiles(LastLoadTableData, newRecords); CleanRemovedRecordFiles(LastLoadTableData, newRecords);
MessageBox.Show("保存成功");
} }
else else
{ {
@ -209,6 +211,15 @@ namespace LubanAssistant
}); });
} }
private List<Record> GetModifyRecords(TableDataInfo lastTableDataInfo, List<Record> newRecords)
{
string index = lastTableDataInfo.Table.IndexField.Name;
var oldRecordDic = lastTableDataInfo.MainRecords.ToDictionary(r => r.Data.GetField(index));
var newRecordDic = newRecords.ToDictionary(r => r.Data.GetField(index));
return newRecordDic.Where(e => !oldRecordDic.TryGetValue(e.Key, out var r) || !object.Equals(e.Value.Data, r.Data)).Select(e => e.Value).ToList();
}
private void CleanRemovedRecordFiles(TableDataInfo lastTableDataInfo, List<Record> newRecords) private void CleanRemovedRecordFiles(TableDataInfo lastTableDataInfo, List<Record> newRecords)
{ {
string index = lastTableDataInfo.Table.IndexField.Name; string index = lastTableDataInfo.Table.IndexField.Name;
@ -241,13 +252,14 @@ namespace LubanAssistant
MessageBox.Show("没有选中的行"); MessageBox.Show("没有选中的行");
return; return;
} }
SaveRecords((Worksheet sheet, int titleRowNum, TableDataInfo tableDataInfo, DefTable defTable, Title title) => SaveRecords(async (Worksheet sheet, int titleRowNum, TableDataInfo tableDataInfo, DefTable defTable, Title title) =>
{ {
int usedRowNum = sheet.UsedRange.Rows.Count; int usedRowNum = sheet.UsedRange.Rows.Count;
if (titleRowNum + 1 < usedRowNum) if (titleRowNum + 1 < usedRowNum)
{ {
var newRecords = ExcelUtil.LoadRecordsInRange(defTable, sheet, title, selectRange.EntireRow); var newRecords = ExcelUtil.LoadRecordsInRange(defTable, sheet, title, selectRange.EntireRow);
ExcelUtil.SaveRecords(InputDataDir, defTable, newRecords); await ExcelUtil.SaveRecordsAsync(InputDataDir, defTable, GetModifyRecords(LastLoadTableData, newRecords));
MessageBox.Show("保存成功");
} }
else else
{ {

View File

@ -1,9 +1,11 @@
using Luban.Job.Cfg.DataExporters; using Luban.Common.Utils;
using Luban.Job.Cfg.DataExporters;
using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel; using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils; using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types;
using Microsoft.Office.Interop.Excel; using Microsoft.Office.Interop.Excel;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -150,9 +152,28 @@ namespace LubanAssistant
//int nextRowIndex = titleRowNum + 2; //int nextRowIndex = titleRowNum + 2;
// 对于 int和long类型记录按值排序
var records = tableDataInfo.MainRecords;
DefField keyField = tableDataInfo.Table.IndexField;
if (keyField != null && (keyField.CType is TInt || keyField.CType is TLong))
{
string keyFieldName = keyField.Name;
records.Sort((a, b) =>
{
DType keya = a.Data.GetField(keyFieldName);
DType keyb = b.Data.GetField(keyFieldName);
switch (keya)
{
case DInt ai: return ai.Value.CompareTo((keyb as DInt).Value);
case DLong al: return al.Value.CompareTo((keyb as DLong).Value);
default: throw new NotSupportedException();
}
});
}
int totalRowCount = 0; int totalRowCount = 0;
var dataRangeArray = new List<object[]>(); var dataRangeArray = new List<object[]>();
foreach (var rec in tableDataInfo.MainRecords) foreach (var rec in records)
{ {
var fillVisitor = new FillSheetVisitor(dataRangeArray, title.ToIndex + 1, totalRowCount); var fillVisitor = new FillSheetVisitor(dataRangeArray, title.ToIndex + 1, totalRowCount);
totalRowCount += rec.Data.Apply(fillVisitor, title); totalRowCount += rec.Data.Apply(fillVisitor, title);
@ -168,7 +189,7 @@ namespace LubanAssistant
} }
} }
Range recordFillRange = sheet.Range[sheet.Cells[titleRowNum + 2, 1], sheet.Cells[titleRowNum + dataRangeArray.Count, title.ToIndex + 1]]; Range recordFillRange = sheet.Range[sheet.Cells[titleRowNum + 2, 1], sheet.Cells[titleRowNum + 1 + dataRangeArray.Count, title.ToIndex + 1]];
recordFillRange.Value = resultDataRangeArray; recordFillRange.Value = resultDataRangeArray;
} }
@ -181,11 +202,16 @@ namespace LubanAssistant
return excelSource.ReadMulti(table.ValueTType); return excelSource.ReadMulti(table.ValueTType);
} }
public static void SaveRecords(string inputDataDir, DefTable table, List<Record> records) public static async Task SaveRecordsAsync(string inputDataDir, DefTable table, List<Record> records)
{ {
var recordOutputDir = Path.Combine(inputDataDir, table.InputFiles[0]); var recordOutputDir = Path.Combine(inputDataDir, table.InputFiles[0]);
string index = table.IndexField.Name; string index = table.IndexField.Name;
var saveRecordTasks = new List<Task>();
foreach (var r in records) foreach (var r in records)
{
saveRecordTasks.Add(Task.Run(async () =>
{ {
var ss = new MemoryStream(); var ss = new MemoryStream();
var jsonWriter = new Utf8JsonWriter(ss, new JsonWriterOptions() var jsonWriter = new Utf8JsonWriter(ss, new JsonWriterOptions()
@ -197,11 +223,25 @@ namespace LubanAssistant
RawJsonExportor.Ins.Accept(r.Data, jsonWriter); RawJsonExportor.Ins.Accept(r.Data, jsonWriter);
jsonWriter.Flush(); jsonWriter.Flush();
byte[] resultBytes = DataUtil.StreamToBytes(ss);
var key = r.Data.GetField(index); var key = r.Data.GetField(index);
var fileName = $"{key.Apply(ToStringVisitor.Ins)}.json"; var fileName = $"{key.Apply(ToStringVisitor.Ins)}.json";
File.WriteAllBytes(Path.Combine(recordOutputDir, fileName), DataUtil.StreamToBytes(ss));
// 只有文件内容改变才重新加载
string fileFullPath = Path.Combine(recordOutputDir, fileName);
if (File.Exists(fileFullPath))
{
var oldBytes = await FileUtil.ReadAllBytesAsync(fileFullPath);
if (System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(resultBytes, oldBytes))
{
return;
} }
} }
await FileUtil.SaveFileAsync(recordOutputDir, fileName, resultBytes);
}));
}
await Task.WhenAll(saveRecordTasks);
}
//public static void FillRecord(Worksheet sheet, ref int nextRowIndex, Title title, Record record) //public static void FillRecord(Worksheet sheet, ref int nextRowIndex, Title title, Record record)
//{ //{

View File

@ -260,21 +260,21 @@ namespace LubanAssistant
public int Accept(DVector2 type, Title x) public int Accept(DVector2 type, Title x)
{ {
var v = type.Value; var v = type.Value;
SetTitleValue(x, $"{v.X},{v.Y}"); SetTitleValue(x, $"{v.X}, {v.Y}");
return 1; return 1;
} }
public int Accept(DVector3 type, Title x) public int Accept(DVector3 type, Title x)
{ {
var v = type.Value; var v = type.Value;
SetTitleValue(x, $"{v.X},{v.Y},{v.Z}"); SetTitleValue(x, $"{v.X}, {v.Y}, {v.Z}");
return 1; return 1;
} }
public int Accept(DVector4 type, Title x) public int Accept(DVector4 type, Title x)
{ {
var v = type.Value; var v = type.Value;
SetTitleValue(x, $"{v.X},{v.Y},{v.Z},{v.W}"); SetTitleValue(x, $"{v.X}, {v.Y}, {v.Z}, {v.W}");
return 1; return 1;
} }

View File

@ -24,5 +24,10 @@ namespace Luban.Job.Cfg.Datas
{ {
Value = value; Value = value;
} }
public override int GetHashCode()
{
return Value.GetHashCode();
}
} }
} }

View File

@ -127,7 +127,7 @@ namespace LubanAssistant
{ {
if (string.IsNullOrEmpty(sep) && type.Type.ElementType.Apply(IsNotSepTypeVisitor.Ins)) if (string.IsNullOrEmpty(sep) && type.Type.ElementType.Apply(IsNotSepTypeVisitor.Ins))
{ {
sep = ","; sep = ";";
} }
return string.Join(sep, type.Datas.Select(d => d.Apply(this, sep))); return string.Join(sep, type.Datas.Select(d => d.Apply(this, sep)));
} }