using Newtonsoft.Json; using Newtonsoft.Json.Linq; using XGame.Framework.Serialization; namespace etoy { internal class CmdExportBytesDatabase : Command { public override string Description => "导出数据库-字节流文本"; protected virtual TableTag AllowedTableTag => TableTag.Client; protected virtual KeyValueTag AllowedKeyValueTag => KeyValueTag.Client; protected virtual string DatabaseOutput => Context.Option.ClientDatabaseOutput; private readonly string TableExt = "Table.bytes"; private readonly List _errors = new List(); protected override void OnProcess() { var outputPath = DatabaseOutput.ToPath(); if (Directory.Exists(outputPath)) Directory.Delete(outputPath, true); Directory.CreateDirectory(outputPath); SetProgress(0.1f); ExportTables(Context, outputPath); if (_errors.Count > 0) { SetException(new Exception(string.Join('\n', (from e in _errors select $"## ERROR: {e.Message}").ToArray()))); } else { Completed(); } } private void ExportTables(Context context, string outputPath) { foreach (var table in Context.Blackboard.Tables) { if (HasTableFlag(table.TableTag)) { try { ExportTable(context, outputPath, table); } catch (Exception ex) { _errors.Add(ex); Console.WriteLine($"配置表导出异常 Name:{table.Name} Message:{ex.Message}\n\nStack:{ex.StackTrace}"); } } } } private void ExportTable(Context context, string outputPath, Table table) { var fileName = table.Name + TableExt; var filePath = Path.Combine(outputPath, fileName); var serializables = new List(); for (int i = 0, rowCount = table.Rows.Count; i < rowCount; i++) { var row = table.Rows[i]; var fieldGroup = new SerializableFieldGroup(); for (int j = 0, colCount = row.Cells.Count; j < colCount; j++) { var cell = row.Cells[j]; var fieldInfo = cell.FieldInfo; if (HasTableFlag(fieldInfo.OutputTag) == false) { continue; } if (context.Blackboard.TryGetMetadata(fieldInfo.FieldType, out var metadata)) { // 是自定义属性 if (metadata.StructType == MetadataStructType.Enum) {// 枚举 fieldGroup.fields.Add(new SerializableEnum() { fieldType = fieldInfo.FieldType, fieldName = fieldInfo.FieldName, isRepeated = fieldInfo.IsRepeated, value = cell.Value, meta = metadata }); } else { // 数据结构 var structField = GenStructField(fieldInfo, cell.Value, table.Name, context, metadata); fieldGroup.fields.Add(structField); } } else { // 普通字段 fieldGroup.fields.Add(new SerializableField() { fieldType = fieldInfo.FieldType, fieldName = fieldInfo.FieldName, isRepeated = fieldInfo.IsRepeated, value = cell.Value }); } } if (fieldGroup.fields.Count > 0) { serializables.Add(fieldGroup); } } var writer = new Writer(); writer.Write(serializables); var bytes = writer.Finish(); File.WriteAllBytes(filePath, bytes); } private ISerializable GenStructField(FieldInfo fieldInfo, string value, string tableName, Context context, MetadataStruct metadata) { if (fieldInfo.IsRepeated) { var fieldArray = new SerializableArray(); var jArray = JsonConvert.DeserializeObject(value); foreach (var item in jArray) { if (item is JObject jobj) { fieldArray.fields.Add(GenSingleStructField(jobj, tableName, context, metadata)); } else { throw new Exception($"配置表序列化结构体数据错误. Table:{tableName} FieldType: {fieldInfo.FieldType} Name:{fieldInfo.FieldName} Value:{value}"); } } return fieldArray; } else { return GenSingleStructField(JsonConvert.DeserializeObject(value), tableName, context, metadata); } } private ISerializable GenSingleStructField(JObject jobj, string tableName, Context context, MetadataStruct metadata) { var fieldGroup = new SerializableFieldGroup(); for (int i = 0; i < metadata.Fields.Length; i++) { var metaField = metadata.Fields[i]; var fieldVal = jobj[metaField.Name].ToString(); if (context.Blackboard.TryGetMetadata(metaField.FieldType, out var subMeta)) { // 嵌套 if (subMeta.StructType == MetadataStructType.Enum) { // 枚举 fieldGroup.fields.Add(new SerializableEnum() { fieldType = metaField.FieldType, fieldName = metaField.Name, isRepeated = metaField.StructRepeated, value = fieldVal, meta = subMeta, }); } else { //结构体 递归 if (metaField.StructRepeated) { // 数组 var jArray = jobj[metaField.Name] as JArray; var fieldArray = new SerializableArray(); foreach (var item in jArray) { if (item is JObject subObj) { fieldArray.fields.Add(GenSingleStructField(subObj, tableName, context, subMeta)); } else { throw new Exception($"配置表序列化结构体数据错误.Table:{tableName} FieldType: {subMeta.Name} Value:{fieldVal}"); } } fieldGroup.fields.Add(fieldArray); } else { fieldGroup.fields.Add(GenSingleStructField(jobj[metaField.Name] as JObject, tableName, context, subMeta)); } } } else { fieldGroup.fields.Add(new SerializableField() { fieldType = metaField.FieldType, fieldName = metaField.Name, isRepeated = metaField.StructRepeated, value = fieldVal }); } } return fieldGroup; } private bool HasTableFlag(TableTag tag) { return AllowedTableTag == TableTag.All || tag.HasFlag(AllowedTableTag); } //private bool HasKeyValueFlag(KeyValueTag tag) //{ // return AllowedKeyValueTag == KeyValueTag.All || tag.HasFlag(AllowedKeyValueTag); //} } }