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
{
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_unlock", "proc_section", "proc_omake"
];
// 说句实话,我觉得这些定义可能会发生变化
public const byte INST_POP = 1;
public const byte INST_POP_N = 2;
public const byte INST_POP_RET = 3;
@ -148,10 +148,10 @@ namespace EscudeTools
Mark(sf, 1);
return "Pop a value";
}
case INST_POP_N:
{
Mark(sf, (uint)c.Parameter);
Mark(sf, BitConverter.ToUInt32(c.Parameter));
return $"Pop multiple values";
}
case INST_POP_RET:
@ -163,7 +163,7 @@ namespace EscudeTools
case INST_PUSH_RET:
return $"Push the return value";
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:
{
messIndex++;
@ -186,7 +186,7 @@ namespace EscudeTools
case INST_JMPZ:
return $"Conditional jump";
case INST_CALL:
return $"Call function offset: {(uint)c.Parameter + 1}";
return $"Call function offset: {BitConverter.ToUInt32(c.Parameter) + 1}";
case INST_RET:
return $"Return";
case INST_LOG_OR:
@ -240,7 +240,7 @@ namespace EscudeTools
case INST_LINE:
return $"File line number";
case INST_PROC:
uint index = (uint)c.Parameter;
uint index = BitConverter.ToUInt32(c.Parameter);
return $"Execute built-in function: {ProcNames[index]} {SetExtStr(c, sf)}";
case INST_TEXT:
messIndex++;
@ -264,7 +264,7 @@ namespace EscudeTools
private static string SetExtStr(Command c, ScriptFile sf)
{
switch ((uint)c.Parameter)
switch (BitConverter.ToUInt32(c.Parameter))
{
case 0:
{

View File

@ -4,8 +4,11 @@
{
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]))
//{
// 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]);
foreach (string directory in directories)
string[] files = Directory.GetFiles(args[0], "*.bin");
foreach (string file in files)
{
PackManager pm = new();
string providerFilePath = Path.Combine(args[1], Path.GetFileName(directory) + ".bin");
if (pm.Repack(directory, 2,true, providerFilePath))
Console.WriteLine("Export Database Success");
ScriptManager smr = new();
if (smr.LoadScriptFile(file))
{
Console.WriteLine($"Load {file} Success");
}
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;
}
}
}
//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();
//smr.LoadScriptFile(args[0]); //加载.bin文件
//smr.ExportDatabase(Path.GetDirectoryName(args[0]));

View File

@ -2,7 +2,7 @@
"profiles": {
"EscudeTools": {
"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 System.ComponentModel;
using System.Reflection;
namespace EscudeTools
@ -32,7 +33,7 @@ namespace EscudeTools
public uint Offset { get; set; }
public byte Instruction { get; set; }
public string InstructionString { get; set; }
public Object Parameter { get; set; }
public byte[] Parameter { get; set; }
public String Helper { get; set; }
public bool IsProcSet { get; set; }
}
@ -46,7 +47,6 @@ namespace EscudeTools
private string name = string.Empty;
private ScriptFile sf;
private int messIndex = 0;
private bool enableCommandHelper = true;
public ScriptMessage GetSM()
{
@ -58,12 +58,6 @@ namespace EscudeTools
return sf;
}
public bool ToggleCommandHelper()
{
enableCommandHelper = !enableCommandHelper;
return enableCommandHelper;
}
public bool LoadScriptFile(string path)
{
if (!File.Exists(path))
@ -106,19 +100,17 @@ namespace EscudeTools
{
Instruction = sf.Code[i++],
Offset = (uint)i,
IsProcSet = false
IsProcSet = false,
};
if (enableCommandHelper)
c.InstructionString = Define.GetInstructionString(c.Instruction, out int paramNum);
if (paramNum > 0)
{
c.InstructionString = Define.GetInstructionString(c.Instruction, out int paramNum);
for (int j = 0; j < paramNum; j++)
{
c.Parameter = Define.TyperHelper(c.Instruction, sf.Code, i);
i += 4;
}
if (sm != null)
c.Helper = Define.SetCommandStr(c, sf, sm, ref messIndex);
c.Parameter = new byte[paramNum*4];
Buffer.BlockCopy(sf.Code, i, c.Parameter, 0, 4 * paramNum);
i += 4 * paramNum;
}
if (sm != null)
c.Helper = Define.SetCommandStr(c, sf, sm, ref messIndex);
sf.Commands.Add(c);
}
return true;
@ -195,7 +187,8 @@ namespace EscudeTools
return true;
}
public bool ExportDatabase(string? storePath)
//此导出功能导出的sqlite数据库
public bool ExportDatabase(string storePath)
{
if (sf.Code == null)
return false;
@ -208,7 +201,8 @@ namespace EscudeTools
return SqliteProcess(sf, targetPath);
}
public bool ExportMessDatabase(string? storePath)
//从ScriptMessage中导出游戏文本
public bool ExportMessDatabase(string storePath)
{
if (sf == null)
return false;
@ -223,6 +217,37 @@ namespace EscudeTools
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)
{
using SqliteConnection connection = new($"Data Source={path};");
@ -240,7 +265,7 @@ namespace EscudeTools
Offset INTEGER,
Instruction INTEGER,
InstructionString TEXT,
Parameter TEXT,
Parameter BLOB,
Helper TEXT
);";
using (var createTableCmd = new SqliteCommand(createTableQuery, connection))
@ -259,7 +284,9 @@ namespace EscudeTools
insertCmd.Parameters.AddWithValue("@Offset", command.Offset);
insertCmd.Parameters.AddWithValue("@Instruction", command.Instruction);
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.ExecuteNonQuery();
@ -305,5 +332,57 @@ namespace EscudeTools
transaction.Commit();
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();
}
}
}