0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-09-13 18:20:30 +03:00

Hack .msh

This commit is contained in:
bird_egop
2025-08-31 01:07:24 +03:00
parent fca052365f
commit 055694a4b4
8 changed files with 284 additions and 178 deletions

View File

@@ -32,23 +32,24 @@ public static class Msh01
OffsetIntoFile13 = OffsetIntoFile13 =
BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 4)), BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 4)),
IndexInFile08 = IndexInFile08 =
BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 6)), BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 6))
State00 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 8)),
State01 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 10)),
State10 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 12)),
State11 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 14)),
State20 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 16)),
State21 = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 18)),
S20 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 20)),
S22 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 22)),
S24 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 24)),
S26 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 26)),
S28 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 28)),
S30 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 30)),
S32 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 32)),
S34 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 34)),
S36 = BinaryPrimitives.ReadInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 36))
}; };
element.Lod[0] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 8));
element.Lod[1] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 10));
element.Lod[2] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 12));
element.Lod[3] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 14));
element.Lod[4] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 16));
element.Lod[5] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 18));
element.Lod[6] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 20));
element.Lod[7] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 22));
element.Lod[8] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 24));
element.Lod[9] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 26));
element.Lod[10] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 28));
element.Lod[11] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 30));
element.Lod[12] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 32));
element.Lod[13] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 34));
element.Lod[14] = BinaryPrimitives.ReadUInt16LittleEndian(dataSpan.Slice(i * headerFileEntry.ElementSize + 36));
elements.Add(element); elements.Add(element);
} }
@@ -71,20 +72,6 @@ public static class Msh01
public short ParentIndex { get; set; } public short ParentIndex { get; set; }
public short OffsetIntoFile13 { get; set; } public short OffsetIntoFile13 { get; set; }
public short IndexInFile08 { get; set; } public short IndexInFile08 { get; set; }
public ushort State00 { get; set; } public ushort[] Lod { get; set; } = new ushort[15];
public ushort State01 { get; set; }
public ushort State10 { get; set; }
public ushort State11 { get; set; }
public ushort State20 { get; set; }
public ushort State21 { get; set; }
public short S20 { get; set; }
public short S22 { get; set; }
public short S24 { get; set; }
public short S26 { get; set; }
public short S28 { get; set; }
public short S30 { get; set; }
public short S32 { get; set; }
public short S34 { get; set; }
public short S36 { get; set; }
} }
} }

View File

@@ -159,18 +159,6 @@ public static class Msh02
public float XYRadius { get; set; } public float XYRadius { get; set; }
} }
public class BoundingBox
{
public Vector3 Vec1 { get; set; }
public Vector3 Vec2 { get; set; }
public Vector3 Vec3 { get; set; }
public Vector3 Vec4 { get; set; }
public Vector3 Vec5 { get; set; }
public Vector3 Vec6 { get; set; }
public Vector3 Vec7 { get; set; }
public Vector3 Vec8 { get; set; }
}
public class Msh02Element public class Msh02Element
{ {
public ushort StartIndexIn07 { get; set; } public ushort StartIndexIn07 { get; set; }
@@ -183,4 +171,16 @@ public static class Msh02
public Vector3 Vector4 { get; set; } public Vector3 Vector4 { get; set; }
public Vector3 Vector5 { get; set; } public Vector3 Vector5 { get; set; }
} }
public class BoundingBox
{
public Vector3 Vec1 { get; set; }
public Vector3 Vec2 { get; set; }
public Vector3 Vec3 { get; set; }
public Vector3 Vec4 { get; set; }
public Vector3 Vec5 { get; set; }
public Vector3 Vec6 { get; set; }
public Vector3 Vec7 { get; set; }
public Vector3 Vec8 { get; set; }
}
} }

35
ParkanPlayground/Msh03.cs Normal file
View File

@@ -0,0 +1,35 @@
using System.Buffers.Binary;
using Common;
using NResLib;
namespace ParkanPlayground;
public class Msh03
{
public static List<Vector3> ReadComponent(FileStream mshFs, NResArchive mshNres)
{
var verticesFileEntry = mshNres.Files.FirstOrDefault(x => x.FileType == "03 00 00 00");
if (verticesFileEntry is null)
{
throw new Exception("Archive doesn't contain vertices file (03)");
}
if (verticesFileEntry.ElementSize != 12)
{
throw new Exception("Vertices file (03) element size is not 12");
}
var verticesFile = new byte[verticesFileEntry.ElementCount * verticesFileEntry.ElementSize];
mshFs.Seek(verticesFileEntry.OffsetInFile, SeekOrigin.Begin);
mshFs.ReadExactly(verticesFile, 0, verticesFile.Length);
var vertices = verticesFile.Chunk(12).Select(x => new Vector3(
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(0)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(4)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(8))
)
).ToList();
return vertices;
}
}

View File

@@ -25,7 +25,8 @@ public static class Msh07
{ {
Flags = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(0)), Flags = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(0)),
Magic02 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(2)), Magic02 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(2)),
Magic04 = BinaryPrimitives.ReadUInt32LittleEndian(x.AsSpan(4)), Magic04 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(4)),
Magic06 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(6)),
OffsetX = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(8)), OffsetX = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(8)),
OffsetY = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(10)), OffsetY = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(10)),
OffsetZ = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(12)), OffsetZ = BinaryPrimitives.ReadInt16LittleEndian(x.AsSpan(12)),
@@ -39,7 +40,8 @@ public static class Msh07
{ {
public ushort Flags { get; set; } public ushort Flags { get; set; }
public ushort Magic02 { get; set; } public ushort Magic02 { get; set; }
public uint Magic04 { get; set; } public ushort Magic04 { get; set; }
public ushort Magic06 { get; set; }
// normalized vector X, need to divide by 32767 to get float in range -1..1 // normalized vector X, need to divide by 32767 to get float in range -1..1
public short OffsetX { get; set; } public short OffsetX { get; set; }
// normalized vector Y, need to divide by 32767 to get float in range -1..1 // normalized vector Y, need to divide by 32767 to get float in range -1..1

View File

@@ -26,11 +26,12 @@ public static class Msh0D
var elements = elementBytes.Select(x => new Msh0DElement() var elements = elementBytes.Select(x => new Msh0DElement()
{ {
Flags = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(0)), Flags = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(0)),
Magic04 = BinaryPrimitives.ReadUInt32LittleEndian(x.AsSpan(4)), Magic04 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(4)),
number_of_triangles = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(8)), Magic06 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(6)),
IndexInto06 = BinaryPrimitives.ReadInt32LittleEndian(x.AsSpan(10)), CountOf06 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(8)),
Magic0C = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(14)), IndexInto06 = BinaryPrimitives.ReadInt32LittleEndian(x.AsSpan(0xA)),
IndexInto03 = BinaryPrimitives.ReadInt32LittleEndian(x.AsSpan(16)), CountOf03 = BinaryPrimitives.ReadUInt16LittleEndian(x.AsSpan(0xE)),
IndexInto03 = BinaryPrimitives.ReadInt32LittleEndian(x.AsSpan(0x10)),
}).ToList(); }).ToList();
return elements; return elements;
@@ -39,10 +40,14 @@ public static class Msh0D
public class Msh0DElement public class Msh0DElement
{ {
public uint Flags { get; set; } public uint Flags { get; set; }
public uint Magic04 { get; set; }
public ushort number_of_triangles { get; set; } // Magic04 и Magic06 обрабатываются вместе
public ushort Magic04 { get; set; }
public ushort Magic06 { get; set; }
public ushort CountOf06 { get; set; }
public int IndexInto06 { get; set; } public int IndexInto06 { get; set; }
public ushort Magic0C { get; set; } public ushort CountOf03 { get; set; }
public int IndexInto03 { get; set; } public int IndexInto03 { get; set; }
} }
} }

View File

@@ -1,4 +1,5 @@
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Globalization;
using System.Text; using System.Text;
using Common; using Common;
using NResLib; using NResLib;
@@ -19,11 +20,17 @@ public class MshConverter
var component0A = Msh0A.ReadComponent(mshFs, mshNres); var component0A = Msh0A.ReadComponent(mshFs, mshNres);
var component07 = Msh07.ReadComponent(mshFs, mshNres); var component07 = Msh07.ReadComponent(mshFs, mshNres);
var component0D = Msh0D.ReadComponent(mshFs, mshNres); var component0D = Msh0D.ReadComponent(mshFs, mshNres);
// Triangle Vertex Indices
var component06 = Msh06.ReadComponent(mshFs, mshNres); var component06 = Msh06.ReadComponent(mshFs, mshNres);
var component03 = Read03Component(mshFs, mshNres);
// vertices
var component03 = Msh03.ReadComponent(mshFs, mshNres);
_ = 5;
// --- Write OBJ --- // --- Write OBJ ---
using var sw = new StreamWriter("test.obj", false, Encoding.UTF8); using var sw = new StreamWriter("test.obj", false, new UTF8Encoding(false));
foreach (var v in component03) foreach (var v in component03)
sw.WriteLine($"v {v.X:F8} {v.Y:F8} {v.Z:F8}"); sw.WriteLine($"v {v.X:F8} {v.Y:F8} {v.Z:F8}");
@@ -31,48 +38,56 @@ public class MshConverter
var vertices = new List<Vector3>(); var vertices = new List<Vector3>();
var faces = new List<(int, int, int)>(); // store indices into vertices list var faces = new List<(int, int, int)>(); // store indices into vertices list
// 01 - это части меша (Piece)
for (var pieceIndex = 0; pieceIndex < component01.Elements.Count; pieceIndex++) for (var pieceIndex = 0; pieceIndex < component01.Elements.Count; pieceIndex++)
{ {
var piece = component01.Elements[pieceIndex]; var piece01 = component01.Elements[pieceIndex];
var state = (piece.State00 == 0xffff) ? 0 : piece.State00; // var state = (piece.State00 == 0xffff) ? 0 : piece.State00;
var mesh02Element = component02.Elements[state]; for (var lodIndex = 0; lodIndex < piece01.Lod.Length; lodIndex++)
{
var lod = piece01.Lod[lodIndex];
if (lod == 0xffff)
{
Console.WriteLine($"Piece {pieceIndex} has lod -1 at {lodIndex}. Skipping");
continue;
}
int indexInto07 = mesh02Element.StartIndexIn07; sw.WriteLine($"o piece_{pieceIndex}_lod_{lodIndex}");
// 02 - Submesh
var part02 = component02.Elements[lod];
var element0Dstart = mesh02Element.StartOffsetIn0d; int indexInto07 = part02.StartIndexIn07;
var element0Dcount = mesh02Element.ByteLengthIn0D;
Console.WriteLine($"Started piece {pieceIndex}. State={state}. 0D start={element0Dstart}, count={element0Dcount}"); var element0Dstart = part02.StartOffsetIn0d;
var element0Dcount = part02.ByteLengthIn0D;
// Console.WriteLine($"Started piece {pieceIndex}. LOD={lod}. 0D start={element0Dstart}, count={element0Dcount}");
for (var comp0Dindex = 0; comp0Dindex < element0Dcount; comp0Dindex++) for (var comp0Dindex = 0; comp0Dindex < element0Dcount; comp0Dindex++)
{ {
var element0D = component0D[element0Dstart + comp0Dindex]; var element0D = component0D[element0Dstart + comp0Dindex];
var indexInto03 = element0D.IndexInto03; var indexInto03 = element0D.IndexInto03;
var indexInto06 = element0D.IndexInto06; var indexInto06 = element0D.IndexInto06; // indices
uint maxIndex = element0D.CountOf03;
uint indicesCount = element0D.CountOf06;
var count = (uint)element0D.number_of_triangles;
// Convert IndexInto06 to ushort array index (3 ushorts per triangle) // Convert IndexInto06 to ushort array index (3 ushorts per triangle)
Console.WriteLine( // Console.WriteLine($"Processing 0D element[{element0Dstart + comp0Dindex}]. IndexInto03={indexInto03}, IndexInto06={indexInto06}. Number of triangles={indicesCount}");
$"Processing 0D element[{element0Dstart + comp0Dindex}]. IndexInto03={indexInto03}, IndexInto06={indexInto06}. Number of triangles={count}");
if (count != 0) if (indicesCount != 0)
{ {
sw.WriteLine($"o piece_{pieceIndex++}_of_mesh_{comp0Dindex}"); // sw.WriteLine($"o piece_{pieceIndex}_of_mesh_{comp0Dindex}");
if (count % 3 != 0)
{
Console.WriteLine("Number of triangles is not multiple of 3");
_ = 5;
}
count = (count + 2) / 3; // number of triangles for (int ind = 0; ind < indicesCount; ind += 3)
for (int tri = 0; tri < count; tri++)
{ {
// Each triangle uses 3 consecutive ushorts in component06 // Each triangle uses 3 consecutive ushorts in component06
// sw.WriteLine($"o piece_{pieceIndex}_of_mesh_{comp0Dindex}_tri_{ind}");
var comp07 = component07[indexInto07]; var comp07 = component07[indexInto07];
var i1 = indexInto03 + component06[indexInto06]; var i1 = indexInto03 + component06[indexInto06];
@@ -103,6 +118,87 @@ public class MshConverter
} }
} }
} }
}
public void Convert2(string mshPath)
{
var mshNresResult = NResParser.ReadFile(mshPath);
var mshNres = mshNresResult.Archive!;
using var mshFs = new FileStream(mshPath, FileMode.Open, FileAccess.Read, FileShare.Read);
var component01 = Msh01.ReadComponent(mshFs, mshNres);
var component02 = Msh02.ReadComponent(mshFs, mshNres);
var component0A = Msh0A.ReadComponent(mshFs, mshNres);
var component07 = Msh07.ReadComponent(mshFs, mshNres);
var component0D = Msh0D.ReadComponent(mshFs, mshNres);
// Triangle Vertex Indices
var component06 = Msh06.ReadComponent(mshFs, mshNres);
// vertices
var component03 = Msh03.ReadComponent(mshFs, mshNres);
var csv06 = new StreamWriter("06.csv", false, Encoding.UTF8);
for (var i = 0; i < component06.Count; i += 3)
{
// csv06.WriteLine($"{component06[i]}");
csv06.WriteLine($"{component06[i]}, {component06[i + 1]}, {component06[i + 2]}");
}
csv06.Dispose();
var csv03 = new StreamWriter("03.obj", false, Encoding.UTF8);
csv03.WriteLine();
for (var i = 7525; i < component03.Count; i++)
{
// csv06.WriteLine($"{component06[i]}");
// csv03.WriteAsync($"o {i - 7525}");
csv03.WriteLine(
$"v {component03[i].X.ToString("F2", CultureInfo.InvariantCulture)} {component03[i].Y.ToString("F2", CultureInfo.InvariantCulture)} {component03[i].Z.ToString("F2", CultureInfo.InvariantCulture)}");
}
for (var i = 10485; i < component06.Count; i += 3)
{
csv03.WriteLine($"f {component06[i] + 1} {component06[i + 1] + 1} {component06[i + 2] + 1}");
}
csv03.Dispose();
// --- Write OBJ ---
using var sw = new StreamWriter("test.obj", false, Encoding.UTF8);
for (var index = 0; index < component03.Count; index++)
{
var v = component03[index];
sw.WriteLine($"v {v.X:F8} {v.Y:F8} {v.Z:F8}");
}
for (var i = 0; i < 1; i++)
{
sw.WriteLine($"o elem_0d_{i}");
var element0D = component0D[i];
Console.WriteLine($"Processing element 0D [{i}]:");
var elementsOf06 = component06
.Skip(element0D.IndexInto06)
.Take(element0D.CountOf06)
.ToList();
Console.WriteLine($"\tCount of 06: {elementsOf06.Count}, starting from {element0D.IndexInto06}");
var indexInto03 = element0D.IndexInto03;
Console.WriteLine($"\tIndexInto03: {indexInto03}");
if (elementsOf06.Count < 3)
{
throw new Exception("Less than 3 points");
}
}
}
public record Face(Vector3 P1, Vector3 P2, Vector3 P3); public record Face(Vector3 P1, Vector3 P2, Vector3 P3);
@@ -189,34 +285,6 @@ public class MshConverter
} }
} }
private static List<Vector3> Read03Component(FileStream mshFs, NResArchive mshNres)
{
var verticesFileEntry = mshNres.Files.FirstOrDefault(x => x.FileType == "03 00 00 00");
if (verticesFileEntry is null)
{
throw new Exception("Archive doesn't contain vertices file (03)");
}
if (verticesFileEntry.ElementSize != 12)
{
throw new Exception("Vertices file (03) element size is not 12");
}
var verticesFile = new byte[verticesFileEntry.ElementCount * verticesFileEntry.ElementSize];
mshFs.Seek(verticesFileEntry.OffsetInFile, SeekOrigin.Begin);
mshFs.ReadExactly(verticesFile, 0, verticesFile.Length);
var vertices = verticesFile.Chunk(12).Select(x => new Vector3(
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(0)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(4)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(8))
)
).ToList();
return vertices;
}
void Export(string filePath, IEnumerable<Vector3> vertices, List<IndexedEdge> edges) void Export(string filePath, IEnumerable<Vector3> vertices, List<IndexedEdge> edges)
{ {
using (var writer = new StreamWriter(filePath)) using (var writer = new StreamWriter(filePath))

View File

@@ -1,4 +1,4 @@
using System.Buffers.Binary; using System.Buffers.Binary;
using Common; using Common;
using MissionTmaLib.Parsing; using MissionTmaLib.Parsing;
using NResLib; using NResLib;
@@ -10,6 +10,7 @@ using ParkanPlayground;
var converter = new MshConverter(); var converter = new MshConverter();
converter.Convert("E:\\ParkanUnpacked\\fortif.rlb\\133_fr_m_bunker.msh"); converter.Convert("E:\\ParkanUnpacked\\fortif.rlb\\133_fr_m_bunker.msh");
// converter.Convert("E:\\ParkanUnpacked\\fortif.rlb\\73_fr_m_brige.msh");
// converter.Convert("E:\\ParkanUnpacked\\intsys.rlb\\277_MESH_o_pws_l_01.msh"); // converter.Convert("E:\\ParkanUnpacked\\intsys.rlb\\277_MESH_o_pws_l_01.msh");
// converter.Convert("E:\\ParkanUnpacked\\static.rlb\\2_MESH_s_stn_0_01.msh"); // converter.Convert("E:\\ParkanUnpacked\\static.rlb\\2_MESH_s_stn_0_01.msh");
// converter.Convert("E:\\ParkanUnpacked\\bases.rlb\\25_MESH_R_H_02.msh"); // converter.Convert("E:\\ParkanUnpacked\\bases.rlb\\25_MESH_R_H_02.msh");

View File

@@ -87,6 +87,10 @@ grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
Затем `Comp.ini` - тут системные функции, которые используются для загрузки объектов. Затем `Comp.ini` - тут системные функции, которые используются для загрузки объектов.
```
IComponent ** LoadSomething(undefined4, undefined4, undefined4, undefined4)
```
- `Host.url` - этого файла нет - `Host.url` - этого файла нет
- `palettes.lib` - тут палитры, но этот NRes пустой - `palettes.lib` - тут палитры, но этот NRes пустой
- `system.rlb` - не понятно что - `system.rlb` - не понятно что
@@ -211,17 +215,16 @@ grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
Загружается в `AniMesh.dll/LoadAniMesh` Загружается в `AniMesh.dll/LoadAniMesh`
- Тип 01 - заголовок - Тип 01 - заголовок. Он хранит список деталей (submesh) в разных LOD
``` ```
нулевому элементу добавляется флаг 0x1000000 нулевому элементу добавляется флаг 0x1000000
Хранит стейты меша (в один стейт может входить несколько submesh)
Содержит 2 ссылки на файлы анимаций (короткие - файл 13, длинные - файл 08) Содержит 2 ссылки на файлы анимаций (короткие - файл 13, длинные - файл 08)
Если интерполируется анимация -0.5s короче чем magic1 у файла 13 Если интерполируется анимация -0.5s короче чем magic1 у файла 13
И у файла есть OffsetIntoFile13 И у файла есть OffsetIntoFile13
И ushort значение в файле 13 по этому оффсету > IndexInFile08 (это по-моему выполняется всегда) И ushort значение в файле 13 по этому оффсету > IndexInFile08 (это по-моему выполняется всегда)
Тогда вместо IndexInFile08 используется значение из файла 13 по этому оффсету (второй байт) Тогда вместо IndexInFile08 используется значение из файла 13 по этому оффсету (второй байт)
``` ```
- Тип 02 - описание submesh - Тип 02 - описание одного LOD Submesh
``` ```
Вначале идёт заголовок 0x8C (140) байт Вначале идёт заголовок 0x8C (140) байт
В заголовке: В заголовке:
@@ -233,7 +236,7 @@ grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
Далее инфа про куски меша Далее инфа про куски меша
``` ```
- Тип 03 - это вершины (vertex) - Тип 03 - это вершины (vertex)
- Тип 06 - - Тип 06 - индексы треугольников в файле 03
- Тип 04 - скорее всего какие-то цвета RGBA или типа того - Тип 04 - скорее всего какие-то цвета RGBA или типа того
- Тип 08 - меш-анимации (см файл 01) - Тип 08 - меш-анимации (см файл 01)
``` ```
@@ -257,21 +260,19 @@ grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
Буквально (hex) Буквально (hex)
00 01 01 02 ... 00 01 01 02 ...
``` ```
- Тип 0A - Тип 0A - ссылка на части меша, не упакованные в текущий меш (например у бункера 4 и 5 части хранятся в parts.rlb)
``` ```
Не имеет фиксированной длины. Хранит какие-то строки в следующем формате. Не имеет фиксированной длины. Хранит строки в следующем формате.
Игра обращается по индексу, пропуская суммарную длину и пропуская 4 байта на каждую строку (длина). Игра обращается по индексу, пропуская суммарную длину и пропуская 4 байта на каждую строку (длина).
т.е. буквально файл выглядит так т.е. буквально файл выглядит так
00 00 00 00 - пустая строка 00 00 00 00 - пустая строка
03 00 00 00 - длина строки 1 03 00 00 00 - длина строки 1
73 74 72 00 - строка "str" + null terminator 73 74 72 00 - строка "str" + null terminator
.. и повторяется до конца файла .. и повторяется до конца файла
Кол-во элементов из NRes должно быть равно кол-ву строк в этом файле, хотя игра это не проверяет. Кол-во элементов из файла 01 должно быть равно кол-ву строк в этом файле, хотя игра это не проверяет.
Если у элемента эта строка равна "central", ему выставляется флаг (flag |= 1) Если у элемента эта строка равна "central", ему выставляется флаг (flag |= 1)
``` ```
Тип 02 имеет заголовок 140 байт.
## `.wea` ## `.wea`
Загружается в `World3D.dll/LoadMatManager` Загружается в `World3D.dll/LoadMatManager`
@@ -289,26 +290,32 @@ grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
- `0xb` - IAnimation - `0xb` - IAnimation
- `0xd` - IMatManager - `0xd` - IMatManager
- `0xe` - ILightManager - `0xe` - ILightManager
- `0x10` - unknown (implemented by Wizard in Wizard.dll, also by Hallway in ArealMap.dll) - `0x10` - IBehavior
- `0x11` - IBasement - `0x11` - IBasement
- `0x12` - ICamera2 - BufferingCamera - `0x12` - ICamera2 или IBufferingCamera
- `0x13` - IEffectManager - `0x13` - IEffectManager
- `0x14` - IPosition - `0x14` - IPosition
- `0x15` - IAgent
- `0x16` - ILifeSystem - `0x16` - ILifeSystem
- `0x17` - IBuilding - `0x17` - IBuilding - точно он, т.к. ArealMap.CreateObject на него проверяет
- `0x18` - IMesh2 - `0x18` - IMesh2
- `0x19` - unknown (implemented by Wizard in Wizard.dll, also by Agent in AniMesh.dll) - `0x19` - IManManager
- `0x20` - IJointMesh - `0x20` - IJointMesh
- `0x21` - IShade - `0x21` - IShade
- `0x23` - IGameSettings - `0x23` - IGameSettings
- `0x24` - IGameObject2 - `0x24` - IGameObject2
- `0x25` - unknown (implemented by AniMesh)
- `0x26` - unknown (implemented by AniMesh)
- `0x28` - ICollObject
- `0x101` - 3DRender - `0x101` - 3DRender
- `0x105` - NResFile
- `0x201` - IWizard - `0x201` - IWizard
- `0x202` - IItemManager - `0x202` - IItemManager
- `0x203` - ICollManager - `0x203` - ICollManager
- `0x301` - IArealMap - `0x301` - IArealMap
- `0x302` - ISystemArealMap - `0x302` - ISystemArealMap
- `0x303` - IHallway - `0x303` - IHallway
- `0x304` - Distributor
- `0x401` - ISuperAI - `0x401` - ISuperAI
- `0x105` - NResFile - `0x105` - NResFile
- `0x106` - NResFileMetadata - `0x106` - NResFileMetadata
@@ -330,7 +337,7 @@ World3D.dll содержит функцию CreateGameSettings.
Остальные наверное не трогают настройки. Остальные наверное не трогают настройки.
| Resource ID | wOptionID | Name | Default | Description | | Resource ID | wOptionID | Name | Default | Description |
|:-----------:|:---------------:|:--------------------------:|:-------:|---------------------| |:-----------:|:---------------:|:--------------------------:|:-------:|--------------------|
| 1 | 100 (0x64) | "Texture detail" | | | | 1 | 100 (0x64) | "Texture detail" | | |
| 2 | 101 (0x65) | "3D Sound" | | | | 2 | 101 (0x65) | "3D Sound" | | |
| 3 | 102 (0x66) | "Mouse sensitivity" | | | | 3 | 102 (0x66) | "Mouse sensitivity" | | |
@@ -348,6 +355,7 @@ World3D.dll содержит функцию CreateGameSettings.
| 15 | 92 (0x5c) | "Play sound buffer always" | | | | 15 | 92 (0x5c) | "Play sound buffer always" | | |
| 16 | 93 (0x5d) | "Select best sound device" | | | | 16 | 93 (0x5d) | "Select best sound device" | | |
| ---- | 30 (0x1e) | ShadeConfig | | из файла shade.cfg | | ---- | 30 (0x1e) | ShadeConfig | | из файла shade.cfg |
| ---- | (0x8001e) | | | добавляет AniMesh |
## Контакты ## Контакты