vampire-like/Assets/GameMain/Scripts/Editor/DataTableGenerator/DataTableProcessor.cs

499 lines
18 KiB
C#

//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using GameFramework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
namespace StarForce.Editor.DataTableTools
{
public sealed partial class DataTableProcessor
{
private const string CommentLineSeparator = "#";
private static readonly char[] DataSplitSeparators = new char[] { '\t' };
private static readonly char[] DataTrimSeparators = new char[] { '\"' };
private readonly string[] m_NameRow;
private readonly string[] m_TypeRow;
private readonly string[] m_DefaultValueRow;
private readonly string[] m_CommentRow;
private readonly int m_ContentStartRow;
private readonly int m_IdColumn;
private readonly DataProcessor[] m_DataProcessor;
private readonly string[][] m_RawValues;
private readonly string[] m_Strings;
private string m_CodeTemplate;
private DataTableCodeGenerator m_CodeGenerator;
public DataTableProcessor(string dataTableFileName, Encoding encoding, int nameRow, int typeRow, int? defaultValueRow, int? commentRow, int contentStartRow, int idColumn)
{
if (string.IsNullOrEmpty(dataTableFileName))
{
throw new GameFrameworkException("Data table file name is invalid.");
}
if (!dataTableFileName.EndsWith(".txt", StringComparison.Ordinal))
{
throw new GameFrameworkException(Utility.Text.Format("Data table file '{0}' is not a txt.", dataTableFileName));
}
if (!File.Exists(dataTableFileName))
{
throw new GameFrameworkException(Utility.Text.Format("Data table file '{0}' is not exist.", dataTableFileName));
}
string[] lines = File.ReadAllLines(dataTableFileName, encoding);
int rawRowCount = lines.Length;
int rawColumnCount = 0;
List<string[]> rawValues = new List<string[]>();
for (int i = 0; i < lines.Length; i++)
{
string[] rawValue = lines[i].Split(DataSplitSeparators);
for (int j = 0; j < rawValue.Length; j++)
{
rawValue[j] = rawValue[j].Trim(DataTrimSeparators);
}
if (i == 0)
{
rawColumnCount = rawValue.Length;
}
else if (rawValue.Length != rawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Data table file '{0}', raw Column is '{2}', but line '{1}' column is '{3}'.", dataTableFileName, i, rawColumnCount, rawValue.Length));
}
rawValues.Add(rawValue);
}
m_RawValues = rawValues.ToArray();
if (nameRow < 0)
{
throw new GameFrameworkException(Utility.Text.Format("Name row '{0}' is invalid.", nameRow));
}
if (typeRow < 0)
{
throw new GameFrameworkException(Utility.Text.Format("Type row '{0}' is invalid.", typeRow));
}
if (contentStartRow < 0)
{
throw new GameFrameworkException(Utility.Text.Format("Content start row '{0}' is invalid.", contentStartRow));
}
if (idColumn < 0)
{
throw new GameFrameworkException(Utility.Text.Format("Id column '{0}' is invalid.", idColumn));
}
if (nameRow >= rawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Name row '{0}' >= raw row count '{1}' is not allow.", nameRow, rawRowCount));
}
if (typeRow >= rawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Type row '{0}' >= raw row count '{1}' is not allow.", typeRow, rawRowCount));
}
if (defaultValueRow.HasValue && defaultValueRow.Value >= rawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Default value row '{0}' >= raw row count '{1}' is not allow.", defaultValueRow.Value, rawRowCount));
}
if (commentRow.HasValue && commentRow.Value >= rawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Comment row '{0}' >= raw row count '{1}' is not allow.", commentRow.Value, rawRowCount));
}
if (contentStartRow > rawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Content start row '{0}' > raw row count '{1}' is not allow.", contentStartRow, rawRowCount));
}
if (idColumn >= rawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Id column '{0}' >= raw column count '{1}' is not allow.", idColumn, rawColumnCount));
}
m_NameRow = m_RawValues[nameRow];
m_TypeRow = m_RawValues[typeRow];
m_DefaultValueRow = defaultValueRow.HasValue ? m_RawValues[defaultValueRow.Value] : null;
m_CommentRow = commentRow.HasValue ? m_RawValues[commentRow.Value] : null;
m_ContentStartRow = contentStartRow;
m_IdColumn = idColumn;
m_DataProcessor = new DataProcessor[rawColumnCount];
for (int i = 0; i < rawColumnCount; i++)
{
if (i == IdColumn)
{
m_DataProcessor[i] = DataProcessorUtility.GetDataProcessor("id");
}
else
{
m_DataProcessor[i] = DataProcessorUtility.GetDataProcessor(m_TypeRow[i]);
}
}
Dictionary<string, int> strings = new Dictionary<string, int>(StringComparer.Ordinal);
for (int i = contentStartRow; i < rawRowCount; i++)
{
if (IsCommentRow(i))
{
continue;
}
for (int j = 0; j < rawColumnCount; j++)
{
if (m_DataProcessor[j].LanguageKeyword != "string")
{
continue;
}
string str = m_RawValues[i][j];
if (strings.ContainsKey(str))
{
strings[str]++;
}
else
{
strings[str] = 1;
}
}
}
m_Strings = strings.OrderBy(value => value.Key).OrderByDescending(value => value.Value).Select(value => value.Key).ToArray();
m_CodeTemplate = null;
m_CodeGenerator = null;
}
public int RawRowCount
{
get
{
return m_RawValues.Length;
}
}
public int RawColumnCount
{
get
{
return m_RawValues.Length > 0 ? m_RawValues[0].Length : 0;
}
}
public int StringCount
{
get
{
return m_Strings.Length;
}
}
public int ContentStartRow
{
get
{
return m_ContentStartRow;
}
}
public int IdColumn
{
get
{
return m_IdColumn;
}
}
public bool IsIdColumn(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_DataProcessor[rawColumn].IsId;
}
public bool IsCommentRow(int rawRow)
{
if (rawRow < 0 || rawRow >= RawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw row '{0}' is out of range.", rawRow));
}
return GetValue(rawRow, 0).StartsWith(CommentLineSeparator, StringComparison.Ordinal);
}
public bool IsCommentColumn(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return string.IsNullOrEmpty(GetName(rawColumn)) || m_DataProcessor[rawColumn].IsComment;
}
public string GetName(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
if (IsIdColumn(rawColumn))
{
return "Id";
}
return m_NameRow[rawColumn];
}
public bool IsSystem(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_DataProcessor[rawColumn].IsSystem;
}
public System.Type GetType(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_DataProcessor[rawColumn].Type;
}
public string GetLanguageKeyword(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_DataProcessor[rawColumn].LanguageKeyword;
}
public string GetDefaultValue(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_DefaultValueRow != null ? m_DefaultValueRow[rawColumn] : null;
}
public string GetComment(int rawColumn)
{
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_CommentRow != null ? m_CommentRow[rawColumn] : null;
}
public string GetValue(int rawRow, int rawColumn)
{
if (rawRow < 0 || rawRow >= RawRowCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw row '{0}' is out of range.", rawRow));
}
if (rawColumn < 0 || rawColumn >= RawColumnCount)
{
throw new GameFrameworkException(Utility.Text.Format("Raw column '{0}' is out of range.", rawColumn));
}
return m_RawValues[rawRow][rawColumn];
}
public string GetString(int index)
{
if (index < 0 || index >= StringCount)
{
throw new GameFrameworkException(Utility.Text.Format("String index '{0}' is out of range.", index));
}
return m_Strings[index];
}
public int GetStringIndex(string str)
{
for (int i = 0; i < StringCount; i++)
{
if (m_Strings[i] == str)
{
return i;
}
}
return -1;
}
public bool GenerateDataFile(string outputFileName)
{
if (string.IsNullOrEmpty(outputFileName))
{
throw new GameFrameworkException("Output file name is invalid.");
}
try
{
using (FileStream fileStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter binaryWriter = new BinaryWriter(fileStream, Encoding.UTF8))
{
for (int rawRow = ContentStartRow; rawRow < RawRowCount; rawRow++)
{
if (IsCommentRow(rawRow))
{
continue;
}
byte[] bytes = GetRowBytes(outputFileName, rawRow);
binaryWriter.Write7BitEncodedInt32(bytes.Length);
binaryWriter.Write(bytes);
}
}
}
Debug.Log(Utility.Text.Format("Parse data table '{0}' success.", outputFileName));
return true;
}
catch (Exception exception)
{
Debug.LogError(Utility.Text.Format("Parse data table '{0}' failure, exception is '{1}'.", outputFileName, exception));
return false;
}
}
public bool SetCodeTemplate(string codeTemplateFileName, Encoding encoding)
{
try
{
m_CodeTemplate = File.ReadAllText(codeTemplateFileName, encoding);
Debug.Log(Utility.Text.Format("Set code template '{0}' success.", codeTemplateFileName));
return true;
}
catch (Exception exception)
{
Debug.LogError(Utility.Text.Format("Set code template '{0}' failure, exception is '{1}'.", codeTemplateFileName, exception));
return false;
}
}
public void SetCodeGenerator(DataTableCodeGenerator codeGenerator)
{
m_CodeGenerator = codeGenerator;
}
public bool GenerateCodeFile(string outputFileName, Encoding encoding, object userData = null)
{
if (string.IsNullOrEmpty(m_CodeTemplate))
{
throw new GameFrameworkException("You must set code template first.");
}
if (string.IsNullOrEmpty(outputFileName))
{
throw new GameFrameworkException("Output file name is invalid.");
}
try
{
StringBuilder stringBuilder = new StringBuilder(m_CodeTemplate);
if (m_CodeGenerator != null)
{
m_CodeGenerator(this, stringBuilder, userData);
}
using (FileStream fileStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write))
{
using (StreamWriter stream = new StreamWriter(fileStream, encoding))
{
stream.Write(stringBuilder.ToString());
}
}
Debug.Log(Utility.Text.Format("Generate code file '{0}' success.", outputFileName));
return true;
}
catch (Exception exception)
{
Debug.LogError(Utility.Text.Format("Generate code file '{0}' failure, exception is '{1}'.", outputFileName, exception));
return false;
}
}
private byte[] GetRowBytes(string outputFileName, int rawRow)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8))
{
for (int rawColumn = 0; rawColumn < RawColumnCount; rawColumn++)
{
if (IsCommentColumn(rawColumn))
{
continue;
}
try
{
m_DataProcessor[rawColumn].WriteToStream(this, binaryWriter, GetValue(rawRow, rawColumn));
}
catch
{
if (m_DataProcessor[rawColumn].IsId || string.IsNullOrEmpty(GetDefaultValue(rawColumn)))
{
Debug.LogError(Utility.Text.Format("Parse raw value failure. OutputFileName='{0}' RawRow='{1}' RowColumn='{2}' Name='{3}' Type='{4}' RawValue='{5}'", outputFileName, rawRow, rawColumn, GetName(rawColumn), GetLanguageKeyword(rawColumn), GetValue(rawRow, rawColumn)));
return null;
}
else
{
Debug.LogWarning(Utility.Text.Format("Parse raw value failure, will try default value. OutputFileName='{0}' RawRow='{1}' RowColumn='{2}' Name='{3}' Type='{4}' RawValue='{5}'", outputFileName, rawRow, rawColumn, GetName(rawColumn), GetLanguageKeyword(rawColumn), GetValue(rawRow, rawColumn)));
try
{
m_DataProcessor[rawColumn].WriteToStream(this, binaryWriter, GetDefaultValue(rawColumn));
}
catch
{
Debug.LogError(Utility.Text.Format("Parse default value failure. OutputFileName='{0}' RawRow='{1}' RowColumn='{2}' Name='{3}' Type='{4}' RawValue='{5}'", outputFileName, rawRow, rawColumn, GetName(rawColumn), GetLanguageKeyword(rawColumn), GetComment(rawColumn)));
return null;
}
}
}
}
return memoryStream.ToArray();
}
}
}
}
}