ScriptFile(.bin)支持仅导出text

剩余部分以.bat形式存储
This commit is contained in:
Chenx221 2024-10-18 20:32:22 +08:00
parent 6516dbde44
commit 5d23d7d09f
4 changed files with 164 additions and 80 deletions

View File

@ -1,4 +1,4 @@
//以下是垃圾代码,仅供参考 //以下是垃圾代码,闲人勿入
namespace EscudeTools namespace EscudeTools
{ {
public static class Define public static class Define
@ -19,7 +19,7 @@ namespace EscudeTools
"proc_bgv_fx", "proc_set_param", "proc_get_param", "proc_jump", "proc_date", "proc_flow", "proc_diary", "proc_bgv_fx", "proc_set_param", "proc_get_param", "proc_jump", "proc_date", "proc_flow", "proc_diary",
"proc_unlock", "proc_section", "proc_omake" "proc_unlock", "proc_section", "proc_omake"
]; ];
// 说句实话,我觉得这些定义可能会发生变化
public const byte INST_POP = 1; public const byte INST_POP = 1;
public const byte INST_POP_N = 2; public const byte INST_POP_N = 2;
public const byte INST_POP_RET = 3; public const byte INST_POP_RET = 3;
@ -151,7 +151,7 @@ namespace EscudeTools
case INST_POP_N: case INST_POP_N:
{ {
Mark(sf, (uint)c.Parameter); Mark(sf, BitConverter.ToUInt32(c.Parameter));
return $"Pop multiple values"; return $"Pop multiple values";
} }
case INST_POP_RET: case INST_POP_RET:
@ -163,7 +163,7 @@ namespace EscudeTools
case INST_PUSH_RET: case INST_PUSH_RET:
return $"Push the return value"; return $"Push the return value";
case INST_PUSH_TEXT: case INST_PUSH_TEXT:
return $"Push a string: {sf.TextString[(uint)c.Parameter]}"; return $"Push a string: {sf.TextString[BitConverter.ToUInt32(c.Parameter)]}";
case INST_PUSH_MESS: case INST_PUSH_MESS:
{ {
messIndex++; messIndex++;
@ -186,7 +186,7 @@ namespace EscudeTools
case INST_JMPZ: case INST_JMPZ:
return $"Conditional jump"; return $"Conditional jump";
case INST_CALL: case INST_CALL:
return $"Call function offset: {(uint)c.Parameter + 1}"; return $"Call function offset: {BitConverter.ToUInt32(c.Parameter) + 1}";
case INST_RET: case INST_RET:
return $"Return"; return $"Return";
case INST_LOG_OR: case INST_LOG_OR:
@ -240,7 +240,7 @@ namespace EscudeTools
case INST_LINE: case INST_LINE:
return $"File line number"; return $"File line number";
case INST_PROC: case INST_PROC:
uint index = (uint)c.Parameter; uint index = BitConverter.ToUInt32(c.Parameter);
return $"Execute built-in function: {ProcNames[index]} {SetExtStr(c, sf)}"; return $"Execute built-in function: {ProcNames[index]} {SetExtStr(c, sf)}";
case INST_TEXT: case INST_TEXT:
messIndex++; messIndex++;
@ -264,7 +264,7 @@ namespace EscudeTools
private static string SetExtStr(Command c, ScriptFile sf) private static string SetExtStr(Command c, ScriptFile sf)
{ {
switch ((uint)c.Parameter) switch (BitConverter.ToUInt32(c.Parameter))
{ {
case 0: case 0:
{ {

View File

@ -4,8 +4,11 @@
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
// NOTE
// 推荐使用DB Browser for SQLite (https://sqlitebrowser.org/) 查看、编辑导出的数据库文件
// 这不是广告,这只是我在开发期间使用的工具
////Batch Unpack ////Batch Unpack ESC-ARC Package
//if (Directory.Exists(args[0])) //if (Directory.Exists(args[0]))
//{ //{
// string[] files = Directory.GetFiles(args[0], "*.bin"); // string[] files = Directory.GetFiles(args[0], "*.bin");
@ -30,64 +33,66 @@
// } // }
//} //}
if (Directory.Exists(args[0]) && Directory.Exists(args[1])) ////Batch Repack ESC-ARC Package
//if (Directory.Exists(args[0]) && Directory.Exists(args[1]))
//{
// string[] directories = Directory.GetDirectories(args[0]);
// foreach (string directory in directories)
// {
// PackManager pm = new();
// string providerFilePath = Path.Combine(args[1], Path.GetFileName(directory) + ".bin");
// if (pm.Repack(directory, 2,true, providerFilePath))
// Console.WriteLine("Repack Package Success");
// else
// {
// Console.WriteLine("Repack Package Failed");
// return;
// }
// }
//}
//Batch Unpack Script(Full, Text, Mess)
if (Directory.Exists(args[0]))
{ {
string[] directories = Directory.GetDirectories(args[0]); string[] files = Directory.GetFiles(args[0], "*.bin");
foreach (string directory in directories) foreach (string file in files)
{ {
PackManager pm = new(); ScriptManager smr = new();
string providerFilePath = Path.Combine(args[1], Path.GetFileName(directory) + ".bin"); if (smr.LoadScriptFile(file))
if (pm.Repack(directory, 2,true, providerFilePath)) {
Console.WriteLine("Export Database Success"); Console.WriteLine($"Load {file} Success");
}
else else
{ {
Console.WriteLine("Export Database Failed"); Console.WriteLine($"Load {file} Failed");
return;
}
if (smr.ExportDatabase(Path.GetDirectoryName(args[0])))
Console.WriteLine("Export Script Success");
else
{
Console.WriteLine("Export Script Failed");
return;
}
if (smr.ExportTextDatabase(Path.GetDirectoryName(args[0])))
Console.WriteLine("Export Text Success");
else
{
Console.WriteLine("Export Text Failed");
return;
}
if (smr.ExportMessDatabase(Path.GetDirectoryName(args[0])))
Console.WriteLine("Export Mess Success");
else
{
Console.WriteLine("Export Mess Failed");
return; return;
} }
} }
} }
//if (Directory.Exists(args[0]))
//{
// string[] files = Directory.GetFiles(args[0], "*.bin");
// foreach (string file in files)
// {
// ScriptManager smr = new();
// //目前不支持二次加载
// //Todo
// //修复
// if (smr.LoadScriptFile(file))
// {
// Console.WriteLine($"Load {file} Success");
// }
// else
// {
// Console.WriteLine($"Load {file} Failed");
// return;
// }
// if (smr.ExportDatabase(Path.GetDirectoryName(args[0])))
// Console.WriteLine("Export Database Success");
// else
// {
// Console.WriteLine("Export Database Failed");
// return;
// }
// if (smr.ExportMessDatabase(Path.GetDirectoryName(args[0])))
// Console.WriteLine("Export Mess Database Success");
// else
// {
// Console.WriteLine("Export Mess Database Failed");
// return;
// }
// }
//}
//ScriptManager smr = new(); //ScriptManager smr = new();
//smr.LoadScriptFile(args[0]); //加载.bin文件 //smr.LoadScriptFile(args[0]); //加载.bin文件
//smr.ExportDatabase(Path.GetDirectoryName(args[0])); //smr.ExportDatabase(Path.GetDirectoryName(args[0]));

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"EscudeTools": { "EscudeTools": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "G:\\x221.local\\lab\\unpack_pack\\orgin\\output\r\nG:\\x221.local\\lab\\unpack_pack\\1" "commandLineArgs": "G:\\x221.local\\lab\\test1\\script"
} }
} }
} }

View File

@ -1,4 +1,5 @@
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using System.ComponentModel;
using System.Reflection; using System.Reflection;
namespace EscudeTools namespace EscudeTools
@ -32,7 +33,7 @@ namespace EscudeTools
public uint Offset { get; set; } public uint Offset { get; set; }
public byte Instruction { get; set; } public byte Instruction { get; set; }
public string InstructionString { get; set; } public string InstructionString { get; set; }
public Object Parameter { get; set; } public byte[] Parameter { get; set; }
public String Helper { get; set; } public String Helper { get; set; }
public bool IsProcSet { get; set; } public bool IsProcSet { get; set; }
} }
@ -46,7 +47,6 @@ namespace EscudeTools
private string name = string.Empty; private string name = string.Empty;
private ScriptFile sf; private ScriptFile sf;
private int messIndex = 0; private int messIndex = 0;
private bool enableCommandHelper = true;
public ScriptMessage GetSM() public ScriptMessage GetSM()
{ {
@ -58,12 +58,6 @@ namespace EscudeTools
return sf; return sf;
} }
public bool ToggleCommandHelper()
{
enableCommandHelper = !enableCommandHelper;
return enableCommandHelper;
}
public bool LoadScriptFile(string path) public bool LoadScriptFile(string path)
{ {
if (!File.Exists(path)) if (!File.Exists(path))
@ -106,19 +100,17 @@ namespace EscudeTools
{ {
Instruction = sf.Code[i++], Instruction = sf.Code[i++],
Offset = (uint)i, Offset = (uint)i,
IsProcSet = false IsProcSet = false,
}; };
if (enableCommandHelper)
{
c.InstructionString = Define.GetInstructionString(c.Instruction, out int paramNum); c.InstructionString = Define.GetInstructionString(c.Instruction, out int paramNum);
for (int j = 0; j < paramNum; j++) if (paramNum > 0)
{ {
c.Parameter = Define.TyperHelper(c.Instruction, sf.Code, i); c.Parameter = new byte[paramNum*4];
i += 4; Buffer.BlockCopy(sf.Code, i, c.Parameter, 0, 4 * paramNum);
i += 4 * paramNum;
} }
if (sm != null) if (sm != null)
c.Helper = Define.SetCommandStr(c, sf, sm, ref messIndex); c.Helper = Define.SetCommandStr(c, sf, sm, ref messIndex);
}
sf.Commands.Add(c); sf.Commands.Add(c);
} }
return true; return true;
@ -195,7 +187,8 @@ namespace EscudeTools
return true; return true;
} }
public bool ExportDatabase(string? storePath) //此导出功能导出的sqlite数据库
public bool ExportDatabase(string storePath)
{ {
if (sf.Code == null) if (sf.Code == null)
return false; return false;
@ -208,7 +201,8 @@ namespace EscudeTools
return SqliteProcess(sf, targetPath); return SqliteProcess(sf, targetPath);
} }
public bool ExportMessDatabase(string? storePath) //从ScriptMessage中导出游戏文本
public bool ExportMessDatabase(string storePath)
{ {
if (sf == null) if (sf == null)
return false; return false;
@ -223,6 +217,37 @@ namespace EscudeTools
return SqliteProcess(sm, targetPath); return SqliteProcess(sm, targetPath);
} }
//从ScriptFile中导出Text部分剩余指令部分导出至.dat文件以便重新封包
public bool ExportTextDatabase(string storePath)
{
if (sf == null)
return false;
//分成两个文件一个是放text的sqlite数据库一个是放code的dat文件
//dat
string datPath = Path.Combine(storePath, name + ".dat");
if (File.Exists(datPath))
return false;
using FileStream fs = new(datPath, FileMode.Create);
using BinaryWriter bw = new(fs);
bw.Write(FileHeader);//文件头
bw.Write(sf.CodeSize);//代码区大小
bw.Write(sf.TextCount);//文本数量
byte[] empty4B = new byte[4];
bw.Write(empty4B);//文本大小(占位)
bw.Write(sf.MessCount);//消息数量
bw.Write(sf.Code);//代码区
//sqlite
storePath ??= Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException("Unable to determine the directory.");
if (string.IsNullOrEmpty(name))
return false;
string targetPath = Path.Combine(storePath, "script_text.db");
if (!File.Exists(targetPath))
Utils.ExtractEmbeddedDatabase(targetPath);
return SqliteProcess(sf.TextString, targetPath);
}
private bool SqliteProcess(ScriptFile sf, string path) private bool SqliteProcess(ScriptFile sf, string path)
{ {
using SqliteConnection connection = new($"Data Source={path};"); using SqliteConnection connection = new($"Data Source={path};");
@ -240,7 +265,7 @@ namespace EscudeTools
Offset INTEGER, Offset INTEGER,
Instruction INTEGER, Instruction INTEGER,
InstructionString TEXT, InstructionString TEXT,
Parameter TEXT, Parameter BLOB,
Helper TEXT Helper TEXT
);"; );";
using (var createTableCmd = new SqliteCommand(createTableQuery, connection)) using (var createTableCmd = new SqliteCommand(createTableQuery, connection))
@ -259,7 +284,9 @@ namespace EscudeTools
insertCmd.Parameters.AddWithValue("@Offset", command.Offset); insertCmd.Parameters.AddWithValue("@Offset", command.Offset);
insertCmd.Parameters.AddWithValue("@Instruction", command.Instruction); insertCmd.Parameters.AddWithValue("@Instruction", command.Instruction);
insertCmd.Parameters.AddWithValue("@InstructionString", command.InstructionString); insertCmd.Parameters.AddWithValue("@InstructionString", command.InstructionString);
insertCmd.Parameters.AddWithValue("@Parameter", command.Parameter ?? ""); insertCmd.Parameters.AddWithValue("@Parameter", (command.Parameter == null)
? DBNull.Value
: command.Parameter);
insertCmd.Parameters.AddWithValue("@Helper", command.Helper ?? ""); insertCmd.Parameters.AddWithValue("@Helper", command.Helper ?? "");
insertCmd.ExecuteNonQuery(); insertCmd.ExecuteNonQuery();
@ -305,5 +332,57 @@ namespace EscudeTools
transaction.Commit(); transaction.Commit();
return true; return true;
} }
private bool SqliteProcess(string[] ts,string path)
{
using SqliteConnection connection = new($"Data Source={path};");
connection.Open();
string checkTableExistsQuery = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{name}';";
using (var checkTableCmd = new SqliteCommand(checkTableExistsQuery, connection))
{
var result = checkTableCmd.ExecuteScalar();
if (result != null) return true;
}
string createTableQuery = $@"
CREATE TABLE {name} (
Text TEXT
);";
using (var createTableCmd = new SqliteCommand(createTableQuery, connection))
{
createTableCmd.ExecuteNonQuery();
}
string insertQuery = $"INSERT INTO {name} (Text) VALUES (@Text);";
using var transaction = connection.BeginTransaction();
using var insertCmd = new SqliteCommand(insertQuery, connection, transaction);
foreach (var t in ts)
{
insertCmd.Parameters.Clear();
insertCmd.Parameters.AddWithValue("@Text", t ?? "");
insertCmd.ExecuteNonQuery();
}
transaction.Commit();
return true;
}
public bool Repackv1()
{
throw new NotImplementedException();
}
public bool Repackv2()
{
throw new NotImplementedException();
}
public bool Repackv3()
{
throw new NotImplementedException();
}
} }
} }