0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-10-13 23:10:23 +03:00

improvements

This commit is contained in:
bird_egop
2025-10-05 18:17:18 +03:00
parent c1ea70efe0
commit a774db37a6
17 changed files with 472 additions and 128 deletions

View File

@@ -6,7 +6,26 @@ public record CpDatEntry(
int Magic1,
int Magic2,
string Description,
int Magic3,
DatEntryType Type,
int ChildCount, // игра не хранит это число в объекте, но оно есть в файле
List<CpDatEntry> Children
);
);
// Magic3 seems to be a type
// 0 - chassis
// 1 - turret (у зданий почему-то дефлектор тоже 1), может быть потому, что дефлектор вращается так же как башня у юнитов
// 2 - armour
// 3 - part
// 4 - cannon
// 5 - ammo
public enum DatEntryType
{
Unspecified = -1,
Chassis = 0,
Turret = 1,
Armour = 2,
Part = 3,
Cannon = 4,
Ammo = 5,
}

View File

@@ -6,23 +6,29 @@ public class CpDatParser
{
public static CpDatParseResult Parse(string filePath)
{
Span<byte> f0f1 = stackalloc byte[4];
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return Parse(fs);
}
public static CpDatParseResult Parse(Stream fs)
{
Span<byte> f0f1 = stackalloc byte[4];
if (fs.Length < 8)
return new CpDatParseResult(null, "File too small to be a valid \"cp\" .dat file.");
fs.ReadExactly(f0f1);
if (f0f1[0] != 0xf1 || f0f1[1] != 0xf0)
{
return new CpDatParseResult(null, "File does not start with expected header bytes f1_f0");
}
var schemeType = (SchemeType)fs.ReadInt32LittleEndian();
var entryLength = 0x6c + 4; // нам нужно прочитать 0x6c (108) байт - это root, и ещё 4 байта - кол-во вложенных объектов
var entryLength =
0x6c + 4; // нам нужно прочитать 0x6c (108) байт - это root, и ещё 4 байта - кол-во вложенных объектов
if ((fs.Length - 8) % entryLength != 0)
{
return new CpDatParseResult(null, "File size is not valid according to expected entry length.");
@@ -35,7 +41,7 @@ public class CpDatParser
return new CpDatParseResult(scheme, null);
}
private static CpDatEntry ReadEntryRecursive(FileStream fs)
private static CpDatEntry ReadEntryRecursive(Stream fs)
{
var str1 = fs.ReadNullTerminatedString();
@@ -47,22 +53,22 @@ public class CpDatParser
var magic1 = fs.ReadInt32LittleEndian();
var magic2 = fs.ReadInt32LittleEndian();
var descriptionString = fs.ReadNullTerminatedString();
var descriptionString = fs.ReadNullTerminated1251String();
fs.Seek(32 - descriptionString.Length - 1, SeekOrigin.Current); // -1 ignore null terminator
var magic3 = fs.ReadInt32LittleEndian();
var type = (DatEntryType)fs.ReadInt32LittleEndian();
// игра не читает количество внутрь схемы, вместо этого она сразу рекурсией читает нужно количество вложенных объектов
var childCount = fs.ReadInt32LittleEndian();
List<CpDatEntry> children = new List<CpDatEntry>(childCount);
for (var i = 0; i < childCount; i++)
{
var child = ReadEntryRecursive(fs);
children.Add(child);
}
return new CpDatEntry(str1, str2, magic1, magic2, descriptionString, magic3, childCount, Children: children);
return new CpDatEntry(str1, str2, magic1, magic2, descriptionString, type, childCount, Children: children);
}
}