fpopov thanks

This commit is contained in:
bird_egop
2026-05-09 20:36:43 +03:00
parent d73a6dde70
commit eb458ad9a8
43 changed files with 1562 additions and 1233 deletions
+26 -28
View File
@@ -1,30 +1,28 @@
namespace MissionTmaLib;
public class ClanInfo
{
public string ClanName { get; set; }
public int UnkInt1 { get; set; }
public float X { get; set; }
public float Y { get; set; }
/// <summary>
/// 1 - игрок, 2 AI, 3 - нейтральный
/// </summary>
public ClanType ClanType { get; set; }
public string ScriptsString { get; set; }
public int UnknownClanPartCount { get; set; }
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
/// <summary>
/// Игра называет этот путь TreeName
/// </summary>
public string ResearchNResPath { get; set; }
public int Brains { get; set; }
public int AlliesMapCount { get; set; }
/// <summary>
/// мапа союзников (ключ - имя клана, значение - число, всегда либо 0 либо 1)
/// </summary>
public Dictionary<string, int> AlliesMap { get; set; }
}
/// <summary>Информация о клане из mission TMA.</summary>
/// <param name="ClanName">Имя клана.</param>
/// <param name="UnkInt1">Неизвестное целочисленное поле.</param>
/// <param name="X">TODO</param>
/// <param name="Y">TODO</param>
/// <param name="ClanType">Тип клана: 1 = игрок, 2 = AI, 3 = нейтральный.</param>
/// <param name="ScriptsString">TODO</param>
/// <param name="UnknownClanPartCount">Количество записей UnknownParts.</param>
/// <param name="UnknownParts">TODO</param>
/// <param name="ResearchNResPath">Путь к NRes с деревом исследований. Игра называет этот путь TreeName.</param>
/// <param name="Brains">Количество "мозгов" AI/brains.</param>
/// <param name="AlliesMapCount">Количество записей AlliesMap.</param>
/// <param name="AlliesMap">Мапа союзников: ключ = имя клана, значение всегда 0 или 1.</param>
public record ClanInfo(
string ClanName,
int UnkInt1,
float X,
float Y,
ClanType ClanType,
string ScriptsString,
int UnknownClanPartCount,
List<UnknownClanTreeInfoPart> UnknownParts,
string ResearchNResPath,
int Brains,
int AlliesMapCount,
Dictionary<string, int> AlliesMap);
+28 -36
View File
@@ -2,39 +2,31 @@
namespace MissionTmaLib;
public class GameObjectInfo
{
// 0 - здание, 1 - бот, 2 - окружение
public GameObjectType Type { get; set; }
public int UnknownFlags { get; set; }
public string DatString { get; set; }
/// <summary>
/// Индекс клана, которому принадлежит объект
/// </summary>
/// <remarks>
/// <para>
/// Некоторые объекты окружения иногда почему-то принадлежат клану отличному от -1
/// </para>
/// <para>
/// Может быть -1, если объект никому не принадлежит, я такое встречал только у объектов окружения
/// </para>
/// </remarks>
public int OwningClanIndex { get; set; }
public int Order { get; set; }
public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Scale { get; set; }
public string UnknownString2 { get; set; }
public int UnknownInt4 { get; set; }
public int UnknownInt5 { get; set; }
public int UnknownInt6 { get; set; }
public GameObjectSettings Settings { get; set; }
}
/// <summary>Информация об объекте миссии из mission TMA.</summary>
/// <param name="Type">Тип объекта: 0 = здание, 1 = бот, 2 = окружение.</param>
/// <param name="UnknownFlags">Неизвестные флаги объекта.</param>
/// <param name="DatString">Путь к DAT ресурсу объекта.</param>
/// <param name="OwningClanIndex">Индекс клана-владельца. Может быть -1, если объект никому не принадлежит. Некоторые объекты окружения иногда почему-то принадлежат клану отличному от -1</param>
/// <param name="Order">Порядок объекта. Для зданий парсер добавляет int.MaxValue.</param>
/// <param name="Position">Позиция объекта.</param>
/// <param name="Rotation">Поворот объекта.</param>
/// <param name="Scale">Масштаб объекта. Для старых feature set может быть принудительно (1, 1, 1).</param>
/// <param name="UnknownString2">Неизвестная строка, например у HERO бывает пустой.</param>
/// <param name="UnknownInt4">Неизвестное целочисленное поле.</param>
/// <param name="UnknownInt5">Неизвестное целочисленное поле.</param>
/// <param name="UnknownInt6">Неизвестное целочисленное поле.</param>
/// <param name="Settings">Настройки объекта.</param>
public record class GameObjectInfo(
GameObjectType Type,
int UnknownFlags,
string DatString,
int OwningClanIndex,
int Order,
Vector3 Position,
Vector3 Rotation,
Vector3 Scale,
string UnknownString2,
int UnknownInt4,
int UnknownInt5,
int UnknownInt6,
GameObjectSettings Settings);
+73 -42
View File
@@ -72,32 +72,36 @@ public class MissionTmaParser
List<ClanInfo> infos = [];
for (var i = 0; i < clanCount; i++)
{
var clanTreeInfo = new ClanInfo();
clanTreeInfo.ClanName = fileStream.ReadLengthPrefixedString();
clanTreeInfo.UnkInt1 = fileStream.ReadInt32LittleEndian();
clanTreeInfo.X = fileStream.ReadFloatLittleEndian();
clanTreeInfo.Y = fileStream.ReadFloatLittleEndian();
clanTreeInfo.ClanType = (ClanType) fileStream.ReadInt32LittleEndian();
var clanName = fileStream.ReadLengthPrefixedString();
var unkInt1 = fileStream.ReadInt32LittleEndian();
var x = fileStream.ReadFloatLittleEndian();
var y = fileStream.ReadFloatLittleEndian();
var clanType = (ClanType) fileStream.ReadInt32LittleEndian();
var scriptsString = string.Empty;
var unknownClanPartCount = 0;
List<UnknownClanTreeInfoPart> unknownParts = [];
var researchNResPath = string.Empty;
var brains = 0;
var alliesMapCount = 0;
Dictionary<string, int> alliesMap = [];
if (1 < clanFeatureSet)
{
// MISSIONS\SCRIPTS\default
// MISSIONS\SCRIPTS\tut1_pl
// MISSIONS\SCRIPTS\tut1_en
clanTreeInfo.ScriptsString = fileStream.ReadLengthPrefixedString();
scriptsString = fileStream.ReadLengthPrefixedString();
}
if (2 < clanFeatureSet)
{
clanTreeInfo.UnknownClanPartCount = fileStream.ReadInt32LittleEndian();
unknownClanPartCount = fileStream.ReadInt32LittleEndian();
// тут игра читает число, затем 12 байт и ещё 2 числа
List<UnknownClanTreeInfoPart> unknownClanTreeInfoParts = [];
for (var i1 = 0; i1 < clanTreeInfo.UnknownClanPartCount; i1++)
for (var i1 = 0; i1 < unknownClanPartCount; i1++)
{
unknownClanTreeInfoParts.Add(
unknownParts.Add(
new UnknownClanTreeInfoPart(
fileStream.ReadInt32LittleEndian(),
new Vector3(
@@ -110,8 +114,6 @@ public class MissionTmaParser
)
);
}
clanTreeInfo.UnknownParts = unknownClanTreeInfoParts;
}
if (3 < clanFeatureSet)
@@ -120,17 +122,17 @@ public class MissionTmaParser
// MISSIONS\SCRIPTS\data.trf
// указатель на NRes файл с данными
// может быть пустым, например у Ntrl в туториале
clanTreeInfo.ResearchNResPath = fileStream.ReadLengthPrefixedString();
researchNResPath = fileStream.ReadLengthPrefixedString();
}
if (4 < clanFeatureSet)
{
clanTreeInfo.Brains = fileStream.ReadInt32LittleEndian();
brains = fileStream.ReadInt32LittleEndian();
}
if (5 < clanFeatureSet)
{
clanTreeInfo.AlliesMapCount = fileStream.ReadInt32LittleEndian();
alliesMapCount = fileStream.ReadInt32LittleEndian();
// тут какая-то мапа
// в демо миссии тут
@@ -142,20 +144,29 @@ public class MissionTmaParser
// Trgt -> 1
// Enm -> 0
// Ntrl -> 1
Dictionary<string, int> map = [];
for (var i1 = 0; i1 < clanTreeInfo.AlliesMapCount; i1++)
for (var i1 = 0; i1 < alliesMapCount; i1++)
{
var keyIdString = fileStream.ReadLengthPrefixedString();
// это число всегда либо 0 либо 1
var unkNumber = fileStream.ReadInt32LittleEndian();
map[keyIdString] = unkNumber;
alliesMap[keyIdString] = unkNumber;
}
clanTreeInfo.AlliesMap = map;
}
infos.Add(clanTreeInfo);
infos.Add(new ClanInfo(
clanName,
unkInt1,
x,
y,
clanType,
scriptsString,
unknownClanPartCount,
unknownParts,
researchNResPath,
brains,
alliesMapCount,
alliesMap));
}
var clanInfo = new ClansFileData(clanFeatureSet, clanCount, infos);
@@ -177,51 +188,58 @@ public class MissionTmaParser
for (var i = 0; i < gameObjectsCount; i++)
{
var gameObjectInfo = new GameObjectInfo();
// ReadGameObjectData
gameObjectInfo.Type = (GameObjectType) fileStream.ReadInt32LittleEndian();
gameObjectInfo.UnknownFlags = fileStream.ReadInt32LittleEndian();
var type = (GameObjectType) fileStream.ReadInt32LittleEndian();
var unknownFlags = fileStream.ReadInt32LittleEndian();
// UNITS\UNITS\HERO\hero_t.dat
gameObjectInfo.DatString = fileStream.ReadLengthPrefixedString();
var datString = fileStream.ReadLengthPrefixedString();
var owningClanIndex = 0;
var order = 0;
var unknownString2 = string.Empty;
var unknownInt4 = 0;
var unknownInt5 = 0;
var unknownInt6 = 0;
var settingsData = new GameObjectSettings(0, 0, []);
if (2 < gameObjectsFeatureSet)
{
gameObjectInfo.OwningClanIndex = fileStream.ReadInt32LittleEndian();
owningClanIndex = fileStream.ReadInt32LittleEndian();
}
if (3 < gameObjectsFeatureSet)
{
gameObjectInfo.Order = fileStream.ReadInt32LittleEndian();
if (gameObjectInfo.Type == GameObjectType.Building)
order = fileStream.ReadInt32LittleEndian();
if (type == GameObjectType.Building)
{
gameObjectInfo.Order += int.MaxValue;
order += int.MaxValue;
}
}
// читает 12 байт
gameObjectInfo.Position = new Vector3(
var position = new Vector3(
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian()
);
// ещё раз читает 12 байт
gameObjectInfo.Rotation = new Vector3(
var rotation = new Vector3(
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian()
);
Vector3 scale;
if (gameObjectsFeatureSet < 10)
{
// если фичесет меньше 10, то игра забивает вектор единицами
gameObjectInfo.Scale = new Vector3(1, 1, 1);
scale = new Vector3(1, 1, 1);
}
else
{
// в противном случае читает ещё вектор из файла
gameObjectInfo.Scale = new Vector3(
scale = new Vector3(
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian(),
fileStream.ReadFloatLittleEndian()
@@ -231,18 +249,18 @@ public class MissionTmaParser
if (6 < gameObjectsFeatureSet)
{
// у HERO пустая строка
gameObjectInfo.UnknownString2 = fileStream.ReadLengthPrefixedString();
unknownString2 = fileStream.ReadLengthPrefixedString();
}
if (7 < gameObjectsFeatureSet)
{
gameObjectInfo.UnknownInt4 = fileStream.ReadInt32LittleEndian();
unknownInt4 = fileStream.ReadInt32LittleEndian();
}
if (8 < gameObjectsFeatureSet)
{
gameObjectInfo.UnknownInt5 = fileStream.ReadInt32LittleEndian();
gameObjectInfo.UnknownInt6 = fileStream.ReadInt32LittleEndian();
unknownInt5 = fileStream.ReadInt32LittleEndian();
unknownInt6 = fileStream.ReadInt32LittleEndian();
}
if (5 < gameObjectsFeatureSet)
@@ -318,10 +336,23 @@ public class MissionTmaParser
);
}
gameObjectInfo.Settings = new GameObjectSettings(unused, innerCount, settings);
settingsData = new GameObjectSettings(unused, innerCount, settings);
}
gameObjectInfos.Add(gameObjectInfo);
gameObjectInfos.Add(new GameObjectInfo(
type,
unknownFlags,
datString,
owningClanIndex,
order,
position,
rotation,
scale,
unknownString2,
unknownInt4,
unknownInt5,
unknownInt6,
settingsData));
// end ReadGameObjectData
}
@@ -389,4 +420,4 @@ public class MissionTmaParser
lodeData
);
}
}
}