Compare commits

..

3 Commits

Author SHA1 Message Date
608bbb36d6
移除ESC-ARC带lzw压缩的打包功能
*没研究明白*游戏针对data script是强制lzw
2024-10-26 22:46:12 +08:00
b0f19dbace
补上遗漏的LzwDecode代码,这部分来自Garbro
*打包我就不考虑lzw压缩了,不压也没事
2024-10-26 20:11:20 +08:00
bb66d3ff70
更新少量示例文件 2024-10-26 16:15:09 +08:00
9 changed files with 622 additions and 300 deletions

View File

@ -0,0 +1,162 @@
//! \file BitStream.cs
//! \date Sat Aug 22 21:33:39 2015
//! \brief Bit stream on top of the IO.Stream
//
// Copyright (C) 2015 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System;
using System.Diagnostics;
using System.IO;
namespace EscudeTools.Garbro
{
public class BitStream : IDisposable
{
protected Stream m_input;
private bool m_should_dispose;
protected int m_bits = 0;
protected int m_cached_bits = 0;
public Stream Input { get { return m_input; } }
public int CacheSize { get { return m_cached_bits; } }
protected BitStream(Stream file, bool leave_open)
{
m_input = file;
m_should_dispose = !leave_open;
}
public void Reset()
{
m_cached_bits = 0;
}
#region IDisposable Members
bool m_disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing && m_should_dispose && null != m_input)
m_input.Dispose();
m_disposed = true;
}
}
#endregion
}
public interface IBitStream
{
int GetBits(int count);
int GetNextBit();
void Reset();
}
public class MsbBitStream : BitStream, IBitStream
{
public MsbBitStream(Stream file, bool leave_open = false)
: base(file, leave_open)
{
}
public int GetBits(int count)
{
Debug.Assert(count <= 24, "MsbBitStream does not support sequences longer than 24 bits");
while (m_cached_bits < count)
{
int b = m_input.ReadByte();
if (-1 == b)
return -1;
m_bits = m_bits << 8 | b;
m_cached_bits += 8;
}
int mask = (1 << count) - 1;
m_cached_bits -= count;
return m_bits >> m_cached_bits & mask;
}
public int GetNextBit()
{
return GetBits(1);
}
}
public class LsbBitStream : BitStream, IBitStream
{
public LsbBitStream(Stream file, bool leave_open = false)
: base(file, leave_open)
{
}
public int GetBits(int count)
{
Debug.Assert(count <= 32, "LsbBitStream does not support sequences longer than 32 bits");
int value;
if (m_cached_bits >= count)
{
int mask = (1 << count) - 1;
value = m_bits & mask;
m_bits = (int)((uint)m_bits >> count);
m_cached_bits -= count;
}
else
{
value = m_bits & (1 << m_cached_bits) - 1;
count -= m_cached_bits;
int shift = m_cached_bits;
m_cached_bits = 0;
while (count >= 8)
{
int b = m_input.ReadByte();
if (-1 == b)
return -1;
value |= b << shift;
shift += 8;
count -= 8;
}
if (count > 0)
{
int b = m_input.ReadByte();
if (-1 == b)
return -1;
value |= (b & (1 << count) - 1) << shift;
m_bits = b >> count;
m_cached_bits = 8 - count;
}
}
return value;
}
public int GetNextBit()
{
return GetBits(1);
}
}
}

View File

@ -1,5 +1,7 @@
//这里的提取代码参考(Ctrl+C, Ctrl+V)了Garbro中关于ESCUDE BIN封包的实现 //这里的提取代码参考(Ctrl+C, Ctrl+V)了Garbro中关于ESCUDE BIN封包的实现
using EscudeTools.Garbro;
using System.Text; using System.Text;
using System.Text.Json;
namespace EscudeTools namespace EscudeTools
{ {
@ -9,9 +11,15 @@ namespace EscudeTools
public long Offset { get; set; } public long Offset { get; set; }
public uint Size { get; set; } public uint Size { get; set; }
} }
public class LzwEntry
{
public string Name { get; set; }
public int UnpackSize { get; set; }
}
public class PackManager public class PackManager
{ {
static readonly byte[] fileSignature = [0x45, 0x53, 0x43, 0x2D, 0x41, 0x52, 0x43]; //"ESC-ARC" static readonly byte[] fileSignature = [0x45, 0x53, 0x43, 0x2D, 0x41, 0x52, 0x43]; //"ESC-ARC"
static readonly byte[] LzwSignature = [0x61, 0x63, 0x70, 0x00]; //"acp\0"
static readonly byte[] supportPackVersion = [0x31, 0x32]; //1, 2 static readonly byte[] supportPackVersion = [0x31, 0x32]; //1, 2
private bool isLoaded = false; private bool isLoaded = false;
private uint LoadedKey; private uint LoadedKey;
@ -161,8 +169,10 @@ namespace EscudeTools
string output = Path.Combine(Path.GetDirectoryName(pFile), "output", Path.GetFileNameWithoutExtension(pFile)); string output = Path.Combine(Path.GetDirectoryName(pFile), "output", Path.GetFileNameWithoutExtension(pFile));
if (!Directory.Exists(output)) if (!Directory.Exists(output))
Directory.CreateDirectory(output); Directory.CreateDirectory(output);
var lzwManifest = new List<LzwEntry>();
using FileStream inputStream = new(pFile, FileMode.Open); string jsonPath = Path.Combine(output, "lzwManifest.json");
using FileStream inputStream = new(pFile, FileMode.Open, FileAccess.Read);
using BinaryReader br = new(inputStream);
foreach (Entry entry in pItem) foreach (Entry entry in pItem)
{ {
string entryPath = Path.Combine(output, entry.Name); string entryPath = Path.Combine(output, entry.Name);
@ -170,22 +180,145 @@ namespace EscudeTools
if (!Directory.Exists(entryDirectory)) if (!Directory.Exists(entryDirectory))
Directory.CreateDirectory(entryDirectory); Directory.CreateDirectory(entryDirectory);
byte[] test;
br.BaseStream.Seek(entry.Offset, SeekOrigin.Begin);
test = br.ReadBytes(LzwSignature.Length);
using FileStream outputStream = new(entryPath, FileMode.Create); if (entry.Size > 8 && test.SequenceEqual(LzwSignature))
inputStream.Seek(entry.Offset, SeekOrigin.Begin); {
byte[] buffer = new byte[entry.Size]; entryPath += ".lzw";
inputStream.Read(buffer, 0, buffer.Length); int upackSize = Utils.ToBigEndian(br.ReadInt32());
outputStream.Write(buffer, 0, buffer.Length); lzwManifest.Add(new LzwEntry { Name = entry.Name, UnpackSize = upackSize });
using FileStream outputStream = new(entryPath, FileMode.Create);
inputStream.Seek(entry.Offset + 8, SeekOrigin.Begin);
byte[] buffer = new byte[entry.Size - 8];
inputStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, buffer.Length);
}
else
{
using FileStream outputStream = new(entryPath, FileMode.Create);
inputStream.Seek(entry.Offset, SeekOrigin.Begin);
byte[] buffer = new byte[entry.Size];
inputStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, buffer.Length);
}
} }
if (lzwManifest.Count > 0)
{
using (FileStream fs = File.Create(jsonPath))
{
byte[] jsonBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(lzwManifest));
fs.Write(jsonBytes, 0, jsonBytes.Length);
}
LzwDecode(lzwManifest, output);
};
return true; return true;
} }
private void LzwDecode(List<LzwEntry> lzwManifest, string output)
{
foreach (var i in lzwManifest)
{
string targetPath = Path.Combine(output, i.Name);
int unpacked_size = i.UnpackSize;
using FileStream inputStream = new(targetPath + ".lzw", FileMode.Open, FileAccess.Read);
using var decoder = new LzwDecoder(inputStream, unpacked_size);
decoder.Unpack();
using FileStream outputStream = new(targetPath, FileMode.Create);
outputStream.Write(decoder.Output, 0, decoder.Output.Length);
outputStream.Flush();
outputStream.Close();
inputStream.Close();
File.Delete(targetPath + ".lzw");
}
}
internal sealed class LzwDecoder : IDisposable
{
private MsbBitStream m_input;
private byte[] m_output;
public byte[] Output { get { return m_output; } }
public LzwDecoder(Stream input, int unpacked_size)
{
m_input = new MsbBitStream(input, true);
m_output = new byte[unpacked_size];
}
public void Unpack()
{
int dst = 0;
var lzw_dict = new int[0x8900];
int token_width = 9;
int dict_pos = 0;
while (dst < m_output.Length)
{
int token = m_input.GetBits(token_width);
if (-1 == token)
throw new EndOfStreamException("Invalid compressed stream");
else if (0x100 == token) // end of input
break;
else if (0x101 == token) // increase token width
{
++token_width;
if (token_width > 24)
throw new Exception("Invalid comressed stream");
}
else if (0x102 == token) // reset dictionary
{
token_width = 9;
dict_pos = 0;
}
else
{
if (dict_pos >= lzw_dict.Length)
throw new Exception("Invalid comressed stream");
lzw_dict[dict_pos++] = dst;
if (token < 0x100)
{
m_output[dst++] = (byte)token;
}
else
{
token -= 0x103;
if (token >= dict_pos)
throw new Exception("Invalid comressed stream");
int src = lzw_dict[token];
int count = Math.Min(m_output.Length - dst, lzw_dict[token + 1] - src + 1);
if (count < 0)
throw new Exception("Invalid comressed stream");
Utils.CopyOverlapped(m_output, src, dst, count);
dst += count;
}
}
}
}
#region IDisposable Members
bool _disposed = false;
public void Dispose()
{
if (!_disposed)
{
m_input.Dispose();
_disposed = true;
}
GC.SuppressFinalize(this);
}
#endregion
}
public bool Repack(string path, int version, bool useCustomKey = false, string customKeyProviderPath = "") //目前支持v2v1 public bool Repack(string path, int version, bool useCustomKey = false, string customKeyProviderPath = "") //目前支持v2v1
{ {
if (useCustomKey) if (useCustomKey)
LoadKey(customKeyProviderPath); LoadKey(customKeyProviderPath);
GeneratePItem(path); GeneratePItem(path);
if(File.Exists(Path.Combine(path, "lzwManifest.json")))
return false; //Q:为什么不支持 //A:因为我实在不想研究lzw算法欢迎PR
m_seed = isLoaded ? LoadedKey : 2210579460; m_seed = isLoaded ? LoadedKey : 2210579460;
string outputPath = Path.Combine(Path.GetDirectoryName(path), Path.GetFileName(path) + ".bin"); string outputPath = Path.Combine(Path.GetDirectoryName(path), Path.GetFileName(path) + ".bin");
using (FileStream fs = new(outputPath, FileMode.Create)) using (FileStream fs = new(outputPath, FileMode.Create))
@ -244,27 +377,29 @@ namespace EscudeTools
} }
foreach (Entry entry in pItem) foreach (Entry entry in pItem)
{ {
byte[] data = File.ReadAllBytes(Path.Combine(path, entry.Name)); byte[] data = File.ReadAllBytes(Path.Combine(path, entry.Name));
bw.Write(data); bw.Write(data);
} }
} }
return true; return true;
} }
private void GeneratePItem(string path) private void GeneratePItem(string path)
{ {
pItem.Clear(); pItem.Clear();
var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories)
.Where(file => !file.EndsWith("lzwManifest.json", StringComparison.OrdinalIgnoreCase))
.ToArray();
foreach (var file in files) foreach (var file in files)
{
var relativePath = Path.GetRelativePath(path, file);
var fileInfo = new FileInfo(file);
pItem.Add(new Entry
{ {
Name = relativePath, var relativePath = Path.GetRelativePath(path, file);
Size = (uint)fileInfo.Length var fileInfo = new FileInfo(file);
}); pItem.Add(new Entry
} {
Name = relativePath,
Size = (uint)fileInfo.Length
});
}
m_count = (uint)pItem.Count; m_count = (uint)pItem.Count;
} }
} }

View File

@ -6,270 +6,270 @@ namespace EscudeTools
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
//批量处理EV/ST ////批量处理EV/ST
if (Directory.Exists(args[0]) && File.Exists(args[1])) //if (Directory.Exists(args[0]) && File.Exists(args[1]))
//if (File.Exists(args[0])) ////if (File.Exists(args[0]))
{ //{
string graphicsDBPath = args[1]; // string graphicsDBPath = args[1];
using SqliteConnection connection = new($"Data Source={graphicsDBPath};"); // using SqliteConnection connection = new($"Data Source={graphicsDBPath};");
connection.Open(); // connection.Open();
List<string> tableNames = []; // List<string> tableNames = [];
string[] foundTN = new string[3]; // string[] foundTN = new string[3];
List<int> tableIds = []; // List<int> tableIds = [];
bool found1 = false, found2 = false, found3 = false; // bool found1 = false, found2 = false, found3 = false;
using (var command = new SqliteCommand("SELECT name FROM sqlite_master WHERE type='table';", connection)) // using (var command = new SqliteCommand("SELECT name FROM sqlite_master WHERE type='table';", connection))
using (var reader = command.ExecuteReader()) // using (var reader = command.ExecuteReader())
{ // {
int id = 0; // int id = 0;
while (reader.Read()) // while (reader.Read())
{ // {
string tableName = reader.GetString(0); // string tableName = reader.GetString(0);
if (tableName.StartsWith("イベント")) // if (tableName.StartsWith("イベント"))
{ // {
foundTN[0] = tableName; // foundTN[0] = tableName;
found1 = true; // found1 = true;
} // }
else if (tableName.StartsWith("立ち")) // else if (tableName.StartsWith("立ち"))
{ // {
foundTN[1] = tableName; // foundTN[1] = tableName;
found2 = true; // found2 = true;
} // }
else if (tableName.StartsWith("表情")) // else if (tableName.StartsWith("表情"))
{ // {
foundTN[2] = tableName; // foundTN[2] = tableName;
found3 = true; // found3 = true;
} // }
tableNames.Add(tableName); // tableNames.Add(tableName);
tableIds.Add(id++); // tableIds.Add(id++);
} // }
} // }
if (!(found1 && found2 && found3)) //这里的代码未经测试 // if (!(found1 && found2 && found3)) //这里的代码未经测试
{ // {
for (int i = 0; i < tableNames.Count; i++) // for (int i = 0; i < tableNames.Count; i++)
Console.WriteLine($"{tableIds[i]}: {tableNames[i]}"); // Console.WriteLine($"{tableIds[i]}: {tableNames[i]}");
if (!found1) // if (!found1)
{ // {
Console.WriteLine("自动识别失败请选择存放CG信息的数据表ID: "); // Console.WriteLine("自动识别失败请选择存放CG信息的数据表ID: ");
string? input = Console.ReadLine(); // string? input = Console.ReadLine();
if (int.TryParse(input, out int userInputId)) // if (int.TryParse(input, out int userInputId))
{ // {
if (userInputId >= 0 && userInputId < tableIds.Count) // if (userInputId >= 0 && userInputId < tableIds.Count)
{ // {
foundTN[0] = tableNames[userInputId]; // foundTN[0] = tableNames[userInputId];
} // }
else // else
{ // {
Console.WriteLine("Invalid ID."); // Console.WriteLine("Invalid ID.");
return; // return;
} // }
} // }
else // else
{ // {
Console.WriteLine("Invalid input. Please enter a valid number."); // Console.WriteLine("Invalid input. Please enter a valid number.");
return; // return;
} // }
} // }
if (!found2) // if (!found2)
{ // {
Console.WriteLine("自动识别失败请选择存放立绘信息的数据表ID: "); // Console.WriteLine("自动识别失败请选择存放立绘信息的数据表ID: ");
string? input = Console.ReadLine(); // string? input = Console.ReadLine();
if (int.TryParse(input, out int userInputId)) // if (int.TryParse(input, out int userInputId))
{ // {
if (userInputId >= 0 && userInputId < tableIds.Count) // if (userInputId >= 0 && userInputId < tableIds.Count)
{ // {
foundTN[1] = tableNames[userInputId]; // foundTN[1] = tableNames[userInputId];
} // }
else // else
{ // {
Console.WriteLine("Invalid ID."); // Console.WriteLine("Invalid ID.");
return; // return;
} // }
} // }
else // else
{ // {
Console.WriteLine("Invalid input. Please enter a valid number."); // Console.WriteLine("Invalid input. Please enter a valid number.");
return; // return;
} // }
} // }
if (!found3) // if (!found3)
{ // {
Console.WriteLine("自动识别失败请选择存放表情信息的数据表ID: "); // Console.WriteLine("自动识别失败请选择存放表情信息的数据表ID: ");
string? input = Console.ReadLine(); // string? input = Console.ReadLine();
if (int.TryParse(input, out int userInputId)) // if (int.TryParse(input, out int userInputId))
{ // {
if (userInputId >= 0 && userInputId < tableIds.Count) // if (userInputId >= 0 && userInputId < tableIds.Count)
{ // {
foundTN[2] = tableNames[userInputId]; // foundTN[2] = tableNames[userInputId];
} // }
else // else
{ // {
Console.WriteLine("Invalid ID."); // Console.WriteLine("Invalid ID.");
return; // return;
} // }
} // }
else // else
{ // {
Console.WriteLine("Invalid input. Please enter a valid number."); // Console.WriteLine("Invalid input. Please enter a valid number.");
return; // return;
} // }
} // }
} // }
List<EvTable> evts = []; // List<EvTable> evts = [];
List<StTable> stts = []; // List<StTable> stts = [];
Face[] faces = new Face[32]; // Face[] faces = new Face[32];
using (var command = new SqliteCommand($"SELECT * FROM {foundTN[0]};", connection)) // using (var command = new SqliteCommand($"SELECT * FROM {foundTN[0]};", connection))
{ // {
using var reader = command.ExecuteReader(); // using var reader = command.ExecuteReader();
while (reader.Read()) // while (reader.Read())
{ // {
if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0))) // if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0)))
continue; // continue;
evts.Add(new EvTable // evts.Add(new EvTable
{ // {
name = reader.GetString(0), // name = reader.GetString(0),
file = reader.GetString(1), // file = reader.GetString(1),
option = reader.GetString(2).Split(' '), // option = reader.GetString(2).Split(' '),
coverd = (uint)reader.GetInt32(3), // coverd = (uint)reader.GetInt32(3),
filter = (uint)reader.GetInt32(4), // filter = (uint)reader.GetInt32(4),
color = (uint)reader.GetInt32(5), // color = (uint)reader.GetInt32(5),
id = (uint)reader.GetInt32(6), // id = (uint)reader.GetInt32(6),
loc = (uint)reader.GetInt32(7), // loc = (uint)reader.GetInt32(7),
order = reader.GetInt32(8), // order = reader.GetInt32(8),
link = (uint)reader.GetInt32(9) // link = (uint)reader.GetInt32(9)
}); // });
} // }
} // }
using (var command = new SqliteCommand($"SELECT * FROM {foundTN[1]};", connection)) // using (var command = new SqliteCommand($"SELECT * FROM {foundTN[1]};", connection))
{ // {
using var reader = command.ExecuteReader(); // using var reader = command.ExecuteReader();
while (reader.Read()) // while (reader.Read())
{ // {
if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0))) // if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0)))
continue; // continue;
stts.Add(new StTable // stts.Add(new StTable
{ // {
name = reader.GetString(0), // name = reader.GetString(0),
file = reader.GetString(1), // file = reader.GetString(1),
option = reader.GetString(2).Split(' '), // option = reader.GetString(2).Split(' '),
coverd = (uint)reader.GetInt32(3), // coverd = (uint)reader.GetInt32(3),
filter = (uint)reader.GetInt32(4), // filter = (uint)reader.GetInt32(4),
face = (uint)reader.GetInt32(5), // face = (uint)reader.GetInt32(5),
id = (uint)reader.GetInt32(6), // id = (uint)reader.GetInt32(6),
loc = (uint)reader.GetInt32(7), // loc = (uint)reader.GetInt32(7),
order = reader.GetInt32(8), // order = reader.GetInt32(8),
link = (uint)reader.GetInt32(9) // link = (uint)reader.GetInt32(9)
}); // });
} // }
} // }
using (var command = new SqliteCommand($"SELECT * FROM {foundTN[2]};", connection)) // using (var command = new SqliteCommand($"SELECT * FROM {foundTN[2]};", connection))
{ // {
using var reader = command.ExecuteReader(); // using var reader = command.ExecuteReader();
while (reader.Read()) // while (reader.Read())
{ // {
if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0))) // if (reader.IsDBNull(0) || string.IsNullOrEmpty(reader.GetString(0)))
continue; // continue;
for (int i = 0; i < faces.Length; i++) // for (int i = 0; i < faces.Length; i++)
{ // {
if (faces[i] == null) // if (faces[i] == null)
faces[i] = new Face(); // faces[i] = new Face();
if (reader.GetInt32(2 + i) == 1) // if (reader.GetInt32(2 + i) == 1)
faces[i].faceOptions.Add(reader.GetString(1)); // faces[i].faceOptions.Add(reader.GetString(1));
} // }
} // }
} // }
string[] files = Directory.GetFiles(args[0], "*.lsf", SearchOption.AllDirectories); // string[] files = Directory.GetFiles(args[0], "*.lsf", SearchOption.AllDirectories);
LsfManager lm = new(); // LsfManager lm = new();
foreach (string file in files) // foreach (string file in files)
{ // {
if (lm.LoadLsf(file, true)) // if (lm.LoadLsf(file, true))
Console.WriteLine($"Load {file} Success"); // Console.WriteLine($"Load {file} Success");
else // else
{ // {
Console.WriteLine($"Load {file} Failed"); // Console.WriteLine($"Load {file} Failed");
} // }
} // }
connection.Close(); // connection.Close();
string outputDir = Path.Combine(Path.GetDirectoryName(args[0]), "Output"); // string outputDir = Path.Combine(Path.GetDirectoryName(args[0]), "Output");
if (!Directory.Exists(outputDir)) // if (!Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir); // Directory.CreateDirectory(outputDir);
var parallelOptions = new ParallelOptions // var parallelOptions = new ParallelOptions
{ // {
MaxDegreeOfParallelism = 6 // 设置最大并行线程数 // MaxDegreeOfParallelism = 6 // 设置最大并行线程数
}; // };
// //ST //表情还要另取? // //ST //表情还要另取?
// Parallel.ForEach(stts, parallelOptions, stt => // Parallel.ForEach(stts, parallelOptions, stt =>
// //foreach (StTable stt in stts) // //foreach (StTable stt in stts)
// { // {
// if (stt.order == 0) //仅提取鉴赏中有的ST // if (stt.order == 0) //仅提取鉴赏中有的ST
// return; // return;
// //continue; // //continue;
// string targetFilename = Path.Combine(outputDir, stt.name); //最后保存可用的文件名 // string targetFilename = Path.Combine(outputDir, stt.name); //最后保存可用的文件名
// LsfData? lsfData = lm.FindLsfDataByName(stt.file) ?? throw new Exception($"错误,未找到与{stt.file}对应的lsf数据"); // LsfData? lsfData = lm.FindLsfDataByName(stt.file) ?? throw new Exception($"错误,未找到与{stt.file}对应的lsf数据");
// List<int> pendingList = []; // List<int> pendingList = [];
// List<string> pendingListFn = []; // List<string> pendingListFn = [];
// foreach (string o in stt.option) // foreach (string o in stt.option)
// { // {
// List<int> t = TableManagercs.ParseOptions(lsfData, o); // List<int> t = TableManagercs.ParseOptions(lsfData, o);
// if (t.Count == 0) // if (t.Count == 0)
// continue; // continue;
// pendingList.AddRange(t); // pendingList.AddRange(t);
// foreach (int i in t) // foreach (int i in t)
// { // {
// pendingListFn.Add(lsfData.lli[i].nameStr); // pendingListFn.Add(lsfData.lli[i].nameStr);
// } // }
// } // }
// pendingList = TableManagercs.OrderLayer(pendingList, pendingListFn); // pendingList = TableManagercs.OrderLayer(pendingList, pendingListFn);
// int n = 0; // int n = 0;
// foreach (string o in faces[(int)stt.face].faceOptions) // foreach (string o in faces[(int)stt.face].faceOptions)
// { // {
// List<int> pendingListCopy = new(pendingList); // List<int> pendingListCopy = new(pendingList);
// List<int> t = TableManagercs.ParseOptions(lsfData, o); // List<int> t = TableManagercs.ParseOptions(lsfData, o);
// if (t.Count == 0) // if (t.Count == 0)
// continue; // continue;
// pendingListCopy.AddRange(t); // pendingListCopy.AddRange(t);
// if (!ImageManager.Process(lsfData, [.. pendingListCopy], targetFilename + $"_{n++}.png")) // if (!ImageManager.Process(lsfData, [.. pendingListCopy], targetFilename + $"_{n++}.png"))
// throw new Exception("Process Fail"); // throw new Exception("Process Fail");
// else // else
// Console.WriteLine($"Export {stt.name}_{n - 1} Success"); // Console.WriteLine($"Export {stt.name}_{n - 1} Success");
// } // }
// }); // });
////} ////}
//EV // //EV
Parallel.ForEach(evts, parallelOptions, evt => // Parallel.ForEach(evts, parallelOptions, evt =>
//foreach (EvTable evt in evts) // //foreach (EvTable evt in evts)
{ // {
if (evt.order == 0) //仅提取鉴赏中有的CG // if (evt.order == 0) //仅提取鉴赏中有的CG
return; // return;
//continue; // //continue;
string targetFilename = Path.Combine(outputDir, evt.name + ".png"); //最后保存可用的文件名 // string targetFilename = Path.Combine(outputDir, evt.name + ".png"); //最后保存可用的文件名
LsfData lsfData = lm.FindLsfDataByName(evt.file) ?? throw new Exception("Something Wrong"); // LsfData lsfData = lm.FindLsfDataByName(evt.file) ?? throw new Exception("Something Wrong");
List<int> pendingList = []; // List<int> pendingList = [];
List<string> pendingListFn = []; // List<string> pendingListFn = [];
foreach (string o in evt.option) // foreach (string o in evt.option)
{ // {
List<int> t = TableManagercs.ParseOptions(lsfData, o); // List<int> t = TableManagercs.ParseOptions(lsfData, o);
if (t.Count == 0) // if (t.Count == 0)
continue; // continue;
pendingList.AddRange(t); // pendingList.AddRange(t);
foreach (int i in t) // foreach (int i in t)
{ // {
pendingListFn.Add(lsfData.lli[i].nameStr); // pendingListFn.Add(lsfData.lli[i].nameStr);
} // }
} // }
pendingList = TableManagercs.OrderLayer(pendingList, pendingListFn); // pendingList = TableManagercs.OrderLayer(pendingList, pendingListFn);
if (pendingList[0] != 0) // if (pendingList[0] != 0)
pendingList.Insert(0, 0); // pendingList.Insert(0, 0);
if (!ImageManager.Process(lsfData, [.. pendingList], targetFilename)) // if (!ImageManager.Process(lsfData, [.. pendingList], targetFilename))
throw new Exception("Process Fail"); // throw new Exception("Process Fail");
else // else
Console.WriteLine($"Export {evt.name} Success"); // Console.WriteLine($"Export {evt.name} Success");
}); // });
//} // //}
} //}
@ -328,23 +328,22 @@ namespace EscudeTools
// } // }
//} //}
////Batch Repack ESC-ARC Package //Batch Repack ESC-ARC Package
//if (Directory.Exists(args[0]) && Directory.Exists(args[1])) if (Directory.Exists(args[0]))// && Directory.Exists(args[1])
//{ {
// string[] directories = Directory.GetDirectories(args[0]); string[] directories = Directory.GetDirectories(args[0]);
// foreach (string directory in directories) foreach (string directory in directories)
// { {
// PackManager pm = new(); PackManager pm = new();
// string providerFilePath = Path.Combine(args[1], Path.GetFileName(directory) + ".bin"); //string providerFilePath = Path.Combine(args[1], Path.GetFileName(directory) + ".bin");
// if (pm.Repack(directory, 2,true, providerFilePath)) if (pm.Repack(directory, 2, true))
// Console.WriteLine("Repack Package Success"); Console.WriteLine("Repack Package Success");
// else else
// { {
// Console.WriteLine("Repack Package Failed"); Console.WriteLine("Repack Package Failed");
// return; }
// } }
// } }
//}
////Batch Unpack Script(Full, Text, Mess) ////Batch Unpack Script(Full, Text, Mess)
@ -413,7 +412,7 @@ namespace EscudeTools
//smr.ExportMessDatabase(Path.GetDirectoryName(args[0])); //smr.ExportMessDatabase(Path.GetDirectoryName(args[0]));
//return; //return;
////repack sqlite to bin
//if (Directory.Exists(args[0])) //if (Directory.Exists(args[0]))
//{ //{
// string[] files = Directory.GetFiles(args[0], "*.db"); // string[] files = Directory.GetFiles(args[0], "*.db");
@ -425,6 +424,7 @@ namespace EscudeTools
// } // }
//} //}
//if (Directory.Exists(args[0])) //if (Directory.Exists(args[0]))
//{ //{
// string[] files = Directory.GetFiles(args[0], "*.bin"); // string[] files = Directory.GetFiles(args[0], "*.bin");

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"EscudeTools": { "EscudeTools": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "G:\\x221.local\\lab2\\ev\\1\r\n\"G:\\x221.local\\lab2\\db_graphics.db\"" "commandLineArgs": "G:\\x221.local\\lab3\\Haison\\output\\output"
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System.Reflection; //部分代码来自Garbro
using System.Reflection;
using System.Text; using System.Text;
namespace EscudeTools namespace EscudeTools
@ -139,5 +140,29 @@ namespace EscudeTools
count &= 7; count &= 7;
return (byte)(v << count | v >> (8 - count)); return (byte)(v << count | v >> (8 - count));
} }
public static int ToBigEndian(int value)
{
byte[] bytes = BitConverter.GetBytes(value);
Array.Reverse(bytes);
return BitConverter.ToInt32(bytes, 0);
}
public static void CopyOverlapped(byte[] data, int src, int dst, int count)
{
if (dst > src)
{
while (count > 0)
{
int preceding = Math.Min(dst - src, count);
Buffer.BlockCopy(data, src, data, dst, preceding);
dst += preceding;
count -= preceding;
}
}
else
{
Buffer.BlockCopy(data, src, data, dst, count);
}
}
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.