feat: support new index format of Cyberworks/TinkerBell games after 2024

This commit is contained in:
scientificworld
2026-01-16 12:33:33 +08:00
parent d37285960f
commit 7355ead1f6

View File

@@ -220,7 +220,7 @@ namespace GameRes.Formats.Cyberworks
var toc = ReadToc (toc_name, 8);
if (null == toc)
return null;
using (var index = new ArcIndexReader (toc, file, arc_idx, game_name))
using (var index = GetIndexReader (toc, file, arc_idx, game_name))
{
if (!index.Read())
return null;
@@ -228,6 +228,16 @@ namespace GameRes.Formats.Cyberworks
}
}
internal virtual IndexReader GetIndexReader (byte[] toc, ArcView file, int arc_idx, string game_name)
{
return new ArcIndexReader (toc, file, arc_idx, game_name);
}
internal virtual TocUnpacker GetTocUnpacker (string toc_name)
{
return new TocUnpacker (toc_name);
}
internal ArcFile ArchiveFromDir (ArcView file, List<Entry> dir, bool has_images)
{
if (0 == dir.Count)
@@ -245,7 +255,7 @@ namespace GameRes.Formats.Cyberworks
{
if (!VFS.FileExists (meta_arc_name))
return null;
using (var unpacker = new TocUnpacker (meta_arc_name))
using (var unpacker = GetTocUnpacker (meta_arc_name))
{
if (unpacker.Length > 0x1000)
return null;
@@ -269,7 +279,7 @@ namespace GameRes.Formats.Cyberworks
{
if (!VFS.FileExists (toc_name))
return null;
using (var toc_unpacker = new TocUnpacker (toc_name))
using (var toc_unpacker = GetTocUnpacker (toc_name))
return toc_unpacker.Unpack (num_length);
}
@@ -403,6 +413,26 @@ namespace GameRes.Formats.Cyberworks
public AImageScheme Scheme;
}
[Export(typeof(ArchiveFormat))]
public class DatOpener2024 : DatOpener
{
public override string Tag { get { return "ARC/Cyberworks/2"; } }
public override string Description { get { return "Cyberworks/TinkerBell resource archive"; } }
public override uint Signature { get { return 0; } }
public override bool IsHierarchic { get { return false; } }
public override bool CanWrite { get { return false; } }
internal override IndexReader GetIndexReader (byte[] toc, ArcView file, int arc_idx, string game_name)
{
return new ArcIndexReader2 (toc, file, arc_idx, game_name);
}
internal override TocUnpacker GetTocUnpacker (string toc_name)
{
return new TocUnpacker (toc_name, true);
}
}
[Export(typeof(ArchiveFormat))]
public class OldDatOpener : DatOpener
{
@@ -514,19 +544,22 @@ namespace GameRes.Formats.Cyberworks
{
ArcView m_file;
bool m_should_dispose;
bool m_reversed_decimal;
public long Length { get { return m_file.MaxOffset; } }
public uint PackedSize { get; private set; }
public uint UnpackedSize { get; private set; }
public TocUnpacker (string toc_name) : this (VFS.OpenView (toc_name), true)
public TocUnpacker (string toc_name, bool reversed_decimal = false)
: this (VFS.OpenView (toc_name), true, reversed_decimal)
{
}
public TocUnpacker (ArcView file, bool should_dispose = false)
public TocUnpacker (ArcView file, bool should_dispose = false, bool reversed_decimal = false)
{
m_file = file;
m_should_dispose = should_dispose;
m_reversed_decimal = reversed_decimal;
}
public byte[] Unpack (int num_length)
@@ -564,7 +597,22 @@ namespace GameRes.Formats.Cyberworks
{
uint v = 0;
uint rank = 1;
for (int i = num_length-1; i >= 0; --i, rank *= 10)
int start, end, step;
if (m_reversed_decimal)
{
start = 0;
end = num_length;
step = 1;
}
else
{
start = num_length-1;
end = -1;
step = -1;
}
for (int i = start; i != end; i += step, rank *= 10)
{
uint b = m_file.View.ReadByte (offset+i);
if (b != 0xFF)
@@ -627,9 +675,9 @@ namespace GameRes.Formats.Cyberworks
return true;
}
uint m_fault_id = 100000;
protected uint m_fault_id = 100000;
internal PackedEntry ReadEntryInfo ()
internal virtual PackedEntry ReadEntryInfo ()
{
uint id = m_index.ReadUInt32();
if (id > m_fault_id)
@@ -707,6 +755,27 @@ namespace GameRes.Formats.Cyberworks
}
}
internal class ArcIndexReader2 : ArcIndexReader
{
public ArcIndexReader2 (byte[] toc, ArcView file, int arc_number, string game_name = null)
: base (toc, file, arc_number, game_name)
{
}
internal override PackedEntry ReadEntryInfo ()
{
uint id = m_index.ReadUInt32();
if (id > m_fault_id)
id = m_fault_id++;
var entry = new PackedEntry { Name = id.ToString ("D6") };
entry.UnpackedSize = m_index.ReadUInt32();
entry.Offset = m_index.ReadUInt32();
entry.Size = m_index.ReadUInt32();
entry.IsPacked = entry.UnpackedSize != entry.Size && entry.UnpackedSize != 0;
return entry;
}
}
internal class DatIndexReader : IndexReader
{
public DatIndexReader (byte[] toc, ArcView file) : base (toc, file)