masterdb读取尚未完全实现(1/3)

This commit is contained in:
Chenx221 2024-10-12 23:16:37 +08:00
parent 46a7fc20a1
commit 7ee930b9d1
10 changed files with 387 additions and 193 deletions

16
EscudeTools/Database.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EscudeTools
{
public class Database
{
public static bool ExportSheet()
{
throw new NotImplementedException();
}
}
}

View File

@ -1,11 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EscudeTools
namespace EscudeTools
{
public class BGT : Database
{
public string name; // 登録名
public string file; // ファイル名
public string option; // オプション
public uint coverd; // 白消しID
public uint filter; // フィルター
public uint color; // 色
public uint id; // 画像識別ID
public uint loc; // 関連座標
public int order; // CG表示順
public uint link; // 関連CG
}
public class EVT : Database
{
public string name; // 登録名
public string file; // ファイル名
public string option; // オプション
public uint coverd; // 白消しID
public uint filter; // フィルター
public uint color; // 色
public uint id; // 画像識別ID
public uint loc; // 関連座標
public int order; // CG表示順
public uint link; // 関連CG
}
public class STT : Database
{
public string name; // 登録名
public string file; // ファイル名
public string option; // オプション
public uint coverd; // 白消しID
public uint filter; // 背景フィルタ
public uint face; // 表情
public uint id; // 画像識別ID
public uint loc; // 関連座標
public int order; // CG表示順
public uint link; // 関連CG
}
public class FACET : Database
{
public string name; // 登録名
public string option; // オプション
public byte[] exists = new byte[32]; //
}
public class EFXT : Database
{
public string name; // 登録名
public string file; // ファイル名
public int spot; // 座標インデックス
public int dx, dy; // 相対座標
public int scale; // 倍率
public bool loop; // ループフラグ
}
public class PT
{
public short x;
public short y;
}
public class LOCT : Database
{
public PT[] pt = new PT[8]; // 座標
}
internal class DatabaseGraphics
{
}

View File

@ -1,11 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EscudeTools
namespace EscudeTools
{
public class LOCTEXTT : Database
{
public string key; // 登録名
public string text; // テキスト
}
public class LOCFILET : Database
{
public string key; // 登録名
public string path; // ファイルパス
}
public class LOCNUMT : Database
{
public string key; // 登録名
public int[] nums = new int[8]; // 数値リスト
}
internal class DatabaseLocalize
{
}

View File

@ -0,0 +1,130 @@
using System.Text;
namespace EscudeTools
{
public class Sheet
{
public string name;
public uint cols;
public Column[] col;
public Record records;
}
public class Column
{
public string name;
public ushort type;
public ushort size;
}
public class Record(int columnCount)
{
public object[] values = new object[columnCount]; // 每列的数据值
}
internal class DatabaseManager
{
static readonly byte[] fileSignature = [0x6D, 0x64, 0x62, 0x00];
static readonly byte[] stopBytes = [0x00, 0x00, 0x00, 0x00];
public static bool LoadDatabase(string path)
{
if (!File.Exists(path))
return false;
List<Sheet> sheets = [];
using (FileStream fs = new(path, FileMode.Open))
using (BinaryReader br = new(fs))
{
byte[] head = br.ReadBytes(4);
if (!head.SequenceEqual(fileSignature))
return false;
byte[] nextBytes = br.ReadBytes(4);
if (nextBytes.Length < 4)
return false;
while (!nextBytes.SequenceEqual(stopBytes))
{
uint sheet_struct_size = BitConverter.ToUInt32(nextBytes, 0);
byte[] sheet_struct = br.ReadBytes((int)sheet_struct_size);
nextBytes = br.ReadBytes(4);
uint sheet_data_size = BitConverter.ToUInt32(nextBytes, 0);
byte[] sheet_data = br.ReadBytes((int)sheet_data_size);
nextBytes = br.ReadBytes(4);
uint sheet_text_size = BitConverter.ToUInt32(nextBytes, 0);
byte[] sheet_text = br.ReadBytes((int)sheet_text_size);
Sheet sheet = ProcessSheet(sheet_struct, sheet_data, sheet_text);
sheets.Add(sheet);
nextBytes = br.ReadBytes(4);
if (nextBytes.Length < 4)
return false;
}
}
Sheet[] sheetArray = [.. sheets];
throw new NotImplementedException();
}
private static Sheet ProcessSheet(byte[] sheet_struct, byte[] sheet_data, byte[] sheet_text)
{
Sheet sheet = new();
//process struct
uint nameOffset = BitConverter.ToUInt32(sheet_struct, 0);
sheet.name = ReadStringFromTextData(sheet_text, (int)nameOffset);
sheet.cols = BitConverter.ToUInt32(sheet_struct, 4);
sheet.col = new Column[sheet.cols];
int offset = 8;
for (int i = 0; i < sheet.cols; i++)
{
Column column = new()
{
type = BitConverter.ToUInt16(sheet_struct, offset)
};
if (column.type == 0x3 || column.type == 0x2)
throw new NotImplementedException(); //暂时不受支持的0x2 0x3
column.size = BitConverter.ToUInt16(sheet_struct, offset + 2);
uint columnNameOffset = BitConverter.ToUInt32(sheet_struct, offset + 4);
column.name = ReadStringFromTextData(sheet_text, (int)columnNameOffset);
sheet.col[i] = column;
offset += 8;
}
//process data
offset = 0;
int recordNum = (int)(sheet_data.Length / (4 * sheet.cols));
Record recordFather = new(recordNum);
for (int i = 0; i < recordNum; i++)
{
Record record = new((int)sheet.cols);
for (int j = 0; j < sheet.cols; j++) //色值处理好像有点问题?
{
if (sheet.col[j].type == 4)
{
uint textOffset = BitConverter.ToUInt32(sheet_data, offset);
record.values[j] = ReadStringFromTextData(sheet_text, (int)textOffset);
}
else
{
record.values[j] = BitConverter.ToInt32(sheet_data, offset);
}
offset += 4; //可能有问题
}
recordFather.values[i] = record;
}
sheet.records = recordFather;
return sheet;
}
private static string ReadStringFromTextData(byte[] sheet_text, int offset)
{
List<byte> stringBytes = [];
for (int i = offset; i < sheet_text.Length && sheet_text[i] != 0x00; i++)
{
stringBytes.Add(sheet_text[i]);
}
EncodingProvider provider = CodePagesEncodingProvider.Instance;
Encoding? shiftJis = provider.GetEncoding("shift-jis");
return shiftJis == null
? throw new InvalidOperationException("Shift-JIS encoding not supported.")
: shiftJis.GetString(stringBytes.ToArray());
}
//public static bool OutputDatabase(DatabaseEntry db, int outputType)
//{
// throw new NotImplementedException();
//}
}
}

View File

@ -1,11 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EscudeTools
namespace EscudeTools
{
public class SCRIPTT : Database
{
public string name; // 登録名
public string file; // ファイル名
public int days; // 経過日数
public int chart; // チャートID
public int block; // ブロックID
public int shape; // ブロック画像
public string title; // ブロックタイトル
public int chapter; // チャプターID
public int boundary; // チャプター境界
public int diary; // 日記
public int attrib; // 属性
public int unlock; // ルート開放条件
}
public class CHAPTERT : Database
{
public string name; // 登録名
public string text; // 概要
}
public class NAMET : Database
{
public string text; // 表示名
public uint color; // 文字色
public uint id; // 画像ID
public uint group; // 音声グループ
public string face; // 顔画像ファイル名
}
public class DIARYT : Database
{
public string title; // タイトル
public string[] text = new string[2]; // 日記本文
}
public class VOCT : Database
{
public string name; // キャラ識別子
public string path; // サブフォルダ
public uint group; // 音声グループ
public uint sample_voice; // サンプル音声
public int sample_count; // サンプル音声数
}
public class VART : Database
{
public string name; // 変数名
public byte scope; // スコープ
public uint index; // 変数番号
public int value; // 初期値
public bool inherit; // 継承フラグ
public bool debug; // 表示フラグ
}
public class TWEENT : Database
{
public string name; // 登録名
public int time; // 時間
public int[] param = new int[6]; // パラメータ
public byte rel_flag; // 相対フラグ
public byte def_flag; // 定義フラグ
}
public class SCENET : Database
{
public uint script; // スクリプト番号
public string title; // シーン名
public string thumbnail; // サムネイル名
public int icon; // アイコン表示用
public int order; // SCENE鑑賞表示順
}
internal class DatabaseScripts
{
}

View File

@ -1,11 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EscudeTools
namespace EscudeTools
{
public class BGMT : Database
{
public string name; // 登録名
public string file; // ファイル名
public byte volume; // 再生ボリューム
public byte loop; // 途中ループ
public string title; // 曲名
public int order; // 曲順
}
public class AMBT : Database
{
public string name; // 登録名
public string file; // ファイル名
public byte volume; // 再生ボリューム
}
public class BGVT : Database
{
public string name; // 登録名
public string file; // ファイル名
public byte volume; // 再生ボリューム
}
public class SET : Database
{
public string name; // 登録名
public string file; // ファイル名
public byte volume; // 再生ボリューム
public byte type; // H効果音フラグ
public byte sample; // サンプル音声フラグ
}
public class SFXT : Database
{
public string name; // 登録名
public string file; // ファイル名
}
internal class DatabaseSounds
{
}

View File

@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="14.0.0" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.10" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
</ItemGroup>

View File

@ -1,140 +0,0 @@
using System.Text;
namespace EscudeTools
{
public class Sheet
{
public string Name { get; set; }
public uint Cols { get; set; }
public Column[] Columns { get; set; }
public class Column
{
public ushort Type { get; set; }
public ushort Size { get; set; }
public string Name { get; set; }
}
}
public class DatabaseLoader
{
public static byte[] LoadFile(string file)
{
return File.ReadAllBytes(file);
}
public static byte[] DbLoad(string file)
{
byte[] db = LoadFile(file);
int p = 0;
if (BitConverter.ToUInt32(db, p) != 0x0062646D) // check file magic number == "mdb"
{
// Handle error (e.g., log or throw an exception)
throw new InvalidOperationException($"db_load: {file}");
}
p += 4;
while (BitConverter.ToUInt32(db, p) != 0)
{
uint size = BitConverter.ToUInt32(db, p);
var sheet = new Sheet
{
Columns = new Sheet.Column[1] // Initialize with 1 column (adjust as needed)
};
p += 4 + (int)size;
uint dataSize = BitConverter.ToUInt32(db, p);
byte[] data = new byte[dataSize];
Array.Copy(db, p + 4, data, 0, dataSize);
p += 4 + (int)dataSize;
uint textSize = BitConverter.ToUInt32(db, p);
byte[] text = new byte[textSize];
Array.Copy(db, p + 4, text, 0, textSize);
p += 4 + (int)textSize;
sheet.Name = Encoding.UTF8.GetString(text); // Assuming UTF-8 encoding
uint totalSize = 0;
for (int i = 0; i < sheet.Cols; i++)
{
sheet.Columns[i].Name = Encoding.UTF8.GetString(text); // Adjust accordingly
totalSize += sheet.Columns[i].Size;
}
uint index = 0;
for (int i = 0; i < sheet.Columns.Length; i++)
{
if (sheet.Columns[i].Type == 4) // 假设4表示可变长字符串类型
{
for (uint j = index; j < dataSize; j += totalSize)
{
// 假设 data 是 byte[],我们需要将 byte[] 转换为 uint 数组
uint currentValue = BitConverter.ToUInt32(data, (int)j); // 从字节数组中读取当前的 uint 值
currentValue += (uint)text; // 加上 text 的值
Array.Copy(BitConverter.GetBytes(currentValue), 0, data, (int)j, sizeof(uint)); // 将更新后的值写回 data
}
}
index += sheet.Columns[i].Size; // 更新索引
}
}
return db; // Return the database as a byte array
}
public static bool DbSet(byte[] db, string name, uint elemSize, out byte[] data, out int count)
{
data = null;
count = 0;
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("Invalid argument: name cannot be null or empty.", nameof(name));
}
if (db == null)
{
throw new ArgumentNullException(nameof(db));
}
int p = 0;
if (BitConverter.ToUInt32(db, p) != 0x0062646D)
{
throw new InvalidOperationException($"db_set: {name}");
}
p += 4;
while (BitConverter.ToUInt32(db, p) != 0)
{
var sheet = new Sheet(); // Create a new instance for each sheet
// Assume sheet.Name is set somewhere during loading...
if (sheet.Name == name)
{
uint size = 0;
for (int i = 0; i < sheet.Cols; i++)
{
size += sheet.Columns[i].Size;
}
if (size != elemSize)
{
throw new InvalidOperationException($"db_set: {name} - Data size mismatch.");
}
p += 4 + (int)(BitConverter.ToUInt32(db, p));
size = BitConverter.ToUInt32(db, p);
data = new byte[size];
Array.Copy(db, p + 4, data, 0, size);
count = (int)(size / elemSize);
return true;
}
p += 4 + (int)(BitConverter.ToUInt32(db, p)); // Move past the data
p += 4 + (int)(BitConverter.ToUInt32(db, p)); // Move past text size
}
throw new InvalidOperationException($"db_set: {name} not found.");
}
}
}

View File

@ -7,32 +7,33 @@ namespace EscudeTools
{
static void Main(string[] args)
{
if (args.Length == 0 || args.Length > 2)
{
Console.WriteLine("Invalid arguments. Use -h for help.");
return;
}
DatabaseManager.LoadDatabase(args[0]);
// if (args.Length == 0 || args.Length > 2)
// {
// Console.WriteLine("Invalid arguments. Use -h for help.");
// return;
// }
switch (args[0])
{
case "-h":
case "-r":
case "-d":
case "-s":
default:
break;
}
// switch (args[0])
// {
// case "-h":
// case "-r":
// case "-d":
// case "-s":
// default:
// break;
// }
//}
//static void DisplayHelp()
//{
// Console.WriteLine("Usage: EscudeTools.exe [-r <filepath>] [-d <directory>] [-s <filepath>] [-h]");
// Console.WriteLine("Options:");
// Console.WriteLine(" <filepath> Single lsf process");
// Console.WriteLine(" -r <filepath> Read single lsf file");
// Console.WriteLine(" -d <directory> Process all lsf files in directory");
// Console.WriteLine(" -s <filepath> Same as <filepath>");
// Console.WriteLine(" -h Display help info");
//}
}
//static void DisplayHelp()
//{
// Console.WriteLine("Usage: EscudeTools.exe [-r <filepath>] [-d <directory>] [-s <filepath>] [-h]");
// Console.WriteLine("Options:");
// Console.WriteLine(" <filepath> Single lsf process");
// Console.WriteLine(" -r <filepath> Read single lsf file");
// Console.WriteLine(" -d <directory> Process all lsf files in directory");
// Console.WriteLine(" -s <filepath> Same as <filepath>");
// Console.WriteLine(" -h Display help info");
//}
}
}

View File

@ -0,0 +1,8 @@
{
"profiles": {
"EscudeTools": {
"commandName": "Project",
"commandLineArgs": "G:\\x221.local\\resource\\data\\db_graphics.bin"
}
}
}