mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-06-18 15:49:47 +03:00
добавил tma в просмотр и отрефакторил код
This commit is contained in:
3
MissionTmaLib/ArealInfo.cs
Normal file
3
MissionTmaLib/ArealInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record ArealInfo(int Index, int CoordsCount, List<Vector3> Coords);
|
4
MissionTmaLib/ArealsFileData.cs
Normal file
4
MissionTmaLib/ArealsFileData.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
|
||||
public record ArealsFileData(int UnusedHeader, int ArealCount, List<ArealInfo> ArealInfos);
|
30
MissionTmaLib/ClanInfo.cs
Normal file
30
MissionTmaLib/ClanInfo.cs
Normal file
@ -0,0 +1,30 @@
|
||||
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 UnkString2 { get; set; }
|
||||
public int UnknownClanPartCount { get; set; }
|
||||
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Игра называет этот путь TreeName
|
||||
/// </summary>
|
||||
public string ResearchNResPath { get; set; }
|
||||
public int UnkInt3 { get; set; }
|
||||
public int AlliesMapCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// мапа союзников (ключ - имя клана, значение - число, всегда либо 0 либо 1)
|
||||
/// </summary>
|
||||
public Dictionary<string, int> AlliesMap { get; set; }
|
||||
}
|
24
MissionTmaLib/ClanType.cs
Normal file
24
MissionTmaLib/ClanType.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public enum ClanType
|
||||
{
|
||||
Environment = 0,
|
||||
Player = 1,
|
||||
AI = 2,
|
||||
Neutral = 3
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string ToReadableString(this ClanType clanType)
|
||||
{
|
||||
return clanType switch
|
||||
{
|
||||
ClanType.Environment => $"Окружение ({clanType:D})",
|
||||
ClanType.Player => $"Игрок ({clanType:D})",
|
||||
ClanType.AI => $"AI ({clanType:D})",
|
||||
ClanType.Neutral => $"Нейтральный ({clanType:D})",
|
||||
_ => $"Неизвестный ({clanType:D})"
|
||||
};
|
||||
}
|
||||
}
|
3
MissionTmaLib/ClansFileData.cs
Normal file
3
MissionTmaLib/ClansFileData.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record ClansFileData(int ClanFeatureSet, int ClanCount, List<ClanInfo> ClanInfos);
|
38
MissionTmaLib/GameObjectInfo.cs
Normal file
38
MissionTmaLib/GameObjectInfo.cs
Normal file
@ -0,0 +1,38 @@
|
||||
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 UnknownInt3 { 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; }
|
||||
}
|
3
MissionTmaLib/GameObjectSetting.cs
Normal file
3
MissionTmaLib/GameObjectSetting.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record GameObjectSetting(int SettingType, IntFloatValue Unk1, IntFloatValue Unk2, IntFloatValue Unk3, string Name);
|
3
MissionTmaLib/GameObjectSettings.cs
Normal file
3
MissionTmaLib/GameObjectSettings.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record GameObjectSettings(int Unused, int SettingsCount, List<GameObjectSetting> Settings);
|
9
MissionTmaLib/GameObjectType.cs
Normal file
9
MissionTmaLib/GameObjectType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public enum GameObjectType
|
||||
{
|
||||
Building = 0,
|
||||
Warbot = 1,
|
||||
Tree = 2,
|
||||
Stone = 3
|
||||
}
|
3
MissionTmaLib/GameObjectsFileData.cs
Normal file
3
MissionTmaLib/GameObjectsFileData.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record GameObjectsFileData(int GameObjectsFeatureSet, int GameObjectsCount, List<GameObjectInfo> GameObjectInfos, string LandString, int UnknownInt, string? MissionTechDescription, LodeData? LodeData);
|
11
MissionTmaLib/IntFloatValue.cs
Normal file
11
MissionTmaLib/IntFloatValue.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MissionTmaLib;
|
||||
|
||||
[DebuggerDisplay("AsInt = {AsInt}, AsFloat = {AsFloat}")]
|
||||
public class IntFloatValue(Span<byte> span)
|
||||
{
|
||||
public int AsInt { get; set; } = MemoryMarshal.Read<int>(span);
|
||||
public float AsFloat { get; set; } = MemoryMarshal.Read<float>(span);
|
||||
}
|
3
MissionTmaLib/LodeData.cs
Normal file
3
MissionTmaLib/LodeData.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record LodeData(int Unused, int LodeCount, List<LodeInfo> Lodes);
|
3
MissionTmaLib/LodeInfo.cs
Normal file
3
MissionTmaLib/LodeInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record LodeInfo(Vector3 UnknownVector, int UnknownInt1, int UnknownInt2, float UnknownFloat, int UnknownInt3);
|
9
MissionTmaLib/MissionTmaLib.csproj
Normal file
9
MissionTmaLib/MissionTmaLib.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
39
MissionTmaLib/Parsing/Extensions.cs
Normal file
39
MissionTmaLib/Parsing/Extensions.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace MissionTmaLib.Parsing;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static int ReadInt32LittleEndian(this FileStream fs)
|
||||
{
|
||||
Span<byte> buf = stackalloc byte[4];
|
||||
fs.ReadExactly(buf);
|
||||
|
||||
return BinaryPrimitives.ReadInt32LittleEndian(buf);
|
||||
}
|
||||
|
||||
public static float ReadFloatLittleEndian(this FileStream fs)
|
||||
{
|
||||
Span<byte> buf = stackalloc byte[4];
|
||||
fs.ReadExactly(buf);
|
||||
|
||||
return BinaryPrimitives.ReadSingleLittleEndian(buf);
|
||||
}
|
||||
|
||||
public static string ReadLengthPrefixedString(this FileStream fs)
|
||||
{
|
||||
var len = fs.ReadInt32LittleEndian();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var buffer = new byte[len];
|
||||
|
||||
fs.ReadExactly(buffer, 0, len);
|
||||
|
||||
return Encoding.ASCII.GetString(buffer, 0, len);
|
||||
}
|
||||
}
|
3
MissionTmaLib/Parsing/MissionTmaParseResult.cs
Normal file
3
MissionTmaLib/Parsing/MissionTmaParseResult.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib.Parsing;
|
||||
|
||||
public record MissionTmaParseResult(MissionTma? Mission, string? Error);
|
383
MissionTmaLib/Parsing/MissionTmaParser.cs
Normal file
383
MissionTmaLib/Parsing/MissionTmaParser.cs
Normal file
@ -0,0 +1,383 @@
|
||||
namespace MissionTmaLib.Parsing;
|
||||
|
||||
public class MissionTmaParser
|
||||
{
|
||||
public static MissionTmaParseResult ReadFile(string filePath)
|
||||
{
|
||||
var fs = new FileStream(filePath, FileMode.Open);
|
||||
|
||||
var arealData = LoadAreals(fs);
|
||||
|
||||
var clansData = LoadClans(fs);
|
||||
|
||||
if (clansData is null) return new MissionTmaParseResult(null, "Не обнаружена информация о кланах");
|
||||
|
||||
var gameObjectsData = LoadGameObjects(fs);
|
||||
|
||||
var missionDat = new MissionTma(arealData, clansData, gameObjectsData);
|
||||
return new MissionTmaParseResult(missionDat, null);
|
||||
}
|
||||
|
||||
private static ArealsFileData LoadAreals(FileStream fileStream)
|
||||
{
|
||||
var unusedHeader = fileStream.ReadInt32LittleEndian();
|
||||
var arealCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
// В демо миссии нет ареалов, ровно как и в первой миссии кампании
|
||||
// Span<byte> arealBuffer = stackalloc byte[12];
|
||||
|
||||
List<ArealInfo> infos = [];
|
||||
for (var i = 0; i < arealCount; i++)
|
||||
{
|
||||
// игра читает 4 байта - видимо количество
|
||||
var unknown4Bytes = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
var count = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
List<Vector3> vectors = [];
|
||||
if (0 < count)
|
||||
{
|
||||
for (var i1 = 0; i1 < count; i1++)
|
||||
{
|
||||
// потом читает 12 байт разом (тут видимо какой-то вектор)
|
||||
var unknownFloat1 = fileStream.ReadFloatLittleEndian();
|
||||
var unknownFloat2 = fileStream.ReadFloatLittleEndian();
|
||||
var unknownFloat3 = fileStream.ReadFloatLittleEndian();
|
||||
|
||||
vectors.Add(new Vector3(unknownFloat1, unknownFloat2, unknownFloat3));
|
||||
}
|
||||
}
|
||||
|
||||
infos.Add(new ArealInfo(unknown4Bytes, count, vectors));
|
||||
}
|
||||
|
||||
return new ArealsFileData(unusedHeader, arealCount, infos);
|
||||
}
|
||||
|
||||
private static ClansFileData? LoadClans(FileStream fileStream)
|
||||
{
|
||||
var clanFeatureSet = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
if (clanFeatureSet is <= 0 or >= 7) return null;
|
||||
|
||||
var clanCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
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();
|
||||
|
||||
if (1 < clanFeatureSet)
|
||||
{
|
||||
// MISSIONS\SCRIPTS\default
|
||||
// MISSIONS\SCRIPTS\tut1_pl
|
||||
// MISSIONS\SCRIPTS\tut1_en
|
||||
clanTreeInfo.UnkString2 = fileStream.ReadLengthPrefixedString();
|
||||
}
|
||||
|
||||
if (2 < clanFeatureSet)
|
||||
{
|
||||
clanTreeInfo.UnknownClanPartCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
// тут игра читает число, затем 12 байт и ещё 2 числа
|
||||
|
||||
List<UnknownClanTreeInfoPart> unknownClanTreeInfoParts = [];
|
||||
for (var i1 = 0; i1 < clanTreeInfo.UnknownClanPartCount; i1++)
|
||||
{
|
||||
unknownClanTreeInfoParts.Add(
|
||||
new UnknownClanTreeInfoPart(
|
||||
fileStream.ReadInt32LittleEndian(),
|
||||
new Vector3(
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
clanTreeInfo.UnknownParts = unknownClanTreeInfoParts;
|
||||
}
|
||||
|
||||
if (3 < clanFeatureSet)
|
||||
{
|
||||
// MISSIONS\SCRIPTS\auto.trf
|
||||
// MISSIONS\SCRIPTS\data.trf
|
||||
// указатель на NRes файл с данными
|
||||
// может быть пустым, например у Ntrl в туториале
|
||||
clanTreeInfo.ResearchNResPath = fileStream.ReadLengthPrefixedString();
|
||||
}
|
||||
|
||||
if (4 < clanFeatureSet)
|
||||
{
|
||||
clanTreeInfo.UnkInt3 = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
|
||||
if (5 < clanFeatureSet)
|
||||
{
|
||||
clanTreeInfo.AlliesMapCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
// тут какая-то мапа
|
||||
// в демо миссии тут
|
||||
// player -> 1
|
||||
// player2 -> 0
|
||||
|
||||
// в туториале
|
||||
// Plr -> 1
|
||||
// Trgt -> 1
|
||||
// Enm -> 0
|
||||
// Ntrl -> 1
|
||||
Dictionary<string, int> map = [];
|
||||
for (var i1 = 0; i1 < clanTreeInfo.AlliesMapCount; i1++)
|
||||
{
|
||||
var keyIdString = fileStream.ReadLengthPrefixedString();
|
||||
// это число всегда либо 0 либо 1
|
||||
var unkNumber = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
map[keyIdString] = unkNumber;
|
||||
}
|
||||
|
||||
clanTreeInfo.AlliesMap = map;
|
||||
}
|
||||
|
||||
infos.Add(clanTreeInfo);
|
||||
}
|
||||
|
||||
var clanInfo = new ClansFileData(clanFeatureSet, clanCount, infos);
|
||||
|
||||
return clanInfo;
|
||||
}
|
||||
|
||||
private static GameObjectsFileData LoadGameObjects(FileStream fileStream)
|
||||
{
|
||||
var gameObjectsFeatureSet = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
var gameObjectsCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
Span<byte> settingVal1 = stackalloc byte[4];
|
||||
Span<byte> settingVal2 = stackalloc byte[4];
|
||||
Span<byte> settingVal3 = stackalloc byte[4];
|
||||
|
||||
List<GameObjectInfo> gameObjectInfos = [];
|
||||
|
||||
for (var i = 0; i < gameObjectsCount; i++)
|
||||
{
|
||||
var gameObjectInfo = new GameObjectInfo();
|
||||
// ReadGameObjectData
|
||||
gameObjectInfo.Type = (GameObjectType) fileStream.ReadInt32LittleEndian();
|
||||
gameObjectInfo.UnknownFlags = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
// UNITS\UNITS\HERO\hero_t.dat
|
||||
gameObjectInfo.DatString = fileStream.ReadLengthPrefixedString();
|
||||
|
||||
if (2 < gameObjectsFeatureSet)
|
||||
{
|
||||
gameObjectInfo.OwningClanIndex = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
|
||||
if (3 < gameObjectsFeatureSet)
|
||||
{
|
||||
gameObjectInfo.UnknownInt3 = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
|
||||
// читает 12 байт
|
||||
gameObjectInfo.Position = new Vector3(
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
);
|
||||
|
||||
// ещё раз читает 12 байт
|
||||
gameObjectInfo.Rotation = new Vector3(
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
);
|
||||
|
||||
if (gameObjectsFeatureSet < 10)
|
||||
{
|
||||
// если фичесет меньше 10, то игра забивает вектор единицами
|
||||
gameObjectInfo.Scale = new Vector3(1, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// в противном случае читает ещё вектор из файла
|
||||
gameObjectInfo.Scale = new Vector3(
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
);
|
||||
}
|
||||
|
||||
if (6 < gameObjectsFeatureSet)
|
||||
{
|
||||
// у HERO пустая строка
|
||||
gameObjectInfo.UnknownString2 = fileStream.ReadLengthPrefixedString();
|
||||
}
|
||||
|
||||
if (7 < gameObjectsFeatureSet)
|
||||
{
|
||||
gameObjectInfo.UnknownInt4 = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
|
||||
if (8 < gameObjectsFeatureSet)
|
||||
{
|
||||
gameObjectInfo.UnknownInt5 = fileStream.ReadInt32LittleEndian();
|
||||
gameObjectInfo.UnknownInt6 = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
|
||||
if (5 < gameObjectsFeatureSet)
|
||||
{
|
||||
// тут игра вызывает ещё одну функцию чтения файла - видимо это настройки объекта
|
||||
|
||||
var unused = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
var innerCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
List<GameObjectSetting> settings = [];
|
||||
for (var i1 = 0; i1 < innerCount; i1++)
|
||||
{
|
||||
// судя по всему это тип настройки
|
||||
// 0 - float, 1 - int, 2?
|
||||
var settingType = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
settingVal1.Clear();
|
||||
settingVal2.Clear();
|
||||
settingVal3.Clear();
|
||||
fileStream.ReadExactly(settingVal1);
|
||||
fileStream.ReadExactly(settingVal2);
|
||||
fileStream.ReadExactly(settingVal3);
|
||||
|
||||
IntFloatValue val1;
|
||||
IntFloatValue val2;
|
||||
IntFloatValue val3;
|
||||
|
||||
if (settingType == 0)
|
||||
{
|
||||
// float
|
||||
val1 = new IntFloatValue(settingVal1);
|
||||
val2 = new IntFloatValue(settingVal2);
|
||||
val3 = new IntFloatValue(settingVal3);
|
||||
// var innerFloat1 = fileStream.ReadFloatLittleEndian();
|
||||
// var innerFloat2 = fileStream.ReadFloatLittleEndian();
|
||||
// судя по всему это значение настройки
|
||||
// var innerFloat3 = fileStream.ReadFloatLittleEndian();
|
||||
}
|
||||
else if (settingType == 1)
|
||||
{
|
||||
val1 = new IntFloatValue(settingVal1);
|
||||
val2 = new IntFloatValue(settingVal2);
|
||||
val3 = new IntFloatValue(settingVal3);
|
||||
// var innerInt1 = fileStream.ReadInt32LittleEndian();
|
||||
// var innerInt2 = fileStream.ReadInt32LittleEndian();
|
||||
// судя по всему это значение настройки
|
||||
// var innerInt3 = fileStream.ReadInt32LittleEndian();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Settings value type is not float or int");
|
||||
}
|
||||
|
||||
// Invulnerability
|
||||
// Life state
|
||||
// LogicalID
|
||||
// ClanID
|
||||
// Type
|
||||
// MaxSpeedPercent
|
||||
// MaximumOre
|
||||
// CurrentOre
|
||||
var name = fileStream.ReadLengthPrefixedString();
|
||||
|
||||
settings.Add(
|
||||
new GameObjectSetting(
|
||||
settingType,
|
||||
val1,
|
||||
val2,
|
||||
val3,
|
||||
name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gameObjectInfo.Settings = new GameObjectSettings(unused, innerCount, settings);
|
||||
}
|
||||
|
||||
gameObjectInfos.Add(gameObjectInfo);
|
||||
|
||||
// end ReadGameObjectData
|
||||
}
|
||||
|
||||
// DATA\MAPS\KM_2\land
|
||||
// DATA\MAPS\SC_3\land
|
||||
var landString = fileStream.ReadLengthPrefixedString();
|
||||
|
||||
int unkInt7 = 0;
|
||||
string? missionTechDescription = null;
|
||||
if (1 < gameObjectsFeatureSet)
|
||||
{
|
||||
unkInt7 = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
// ? - байт cd
|
||||
|
||||
// Mission??????????trm\Is.\Ir
|
||||
// Skirmish 1. Full Base, One opponent?????
|
||||
// New mission?????????????????M
|
||||
missionTechDescription = fileStream.ReadLengthPrefixedString();
|
||||
}
|
||||
|
||||
LodeData? lodeData = null;
|
||||
if (4 < gameObjectsFeatureSet)
|
||||
{
|
||||
var unused = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
var lodeCount = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
List<LodeInfo> lodeInfos = [];
|
||||
for (var i1 = 0; i1 < lodeCount; i1++)
|
||||
{
|
||||
var unkLodeVector = new Vector3(
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian(),
|
||||
fileStream.ReadFloatLittleEndian()
|
||||
);
|
||||
|
||||
var unkLodeInt1 = fileStream.ReadInt32LittleEndian();
|
||||
var unkLodeFlags2 = fileStream.ReadInt32LittleEndian();
|
||||
var unkLodeFloat3 = fileStream.ReadFloatLittleEndian();
|
||||
var unkLodeInt4 = fileStream.ReadInt32LittleEndian();
|
||||
|
||||
lodeInfos.Add(
|
||||
new LodeInfo(
|
||||
unkLodeVector,
|
||||
unkLodeInt1,
|
||||
unkLodeFlags2,
|
||||
unkLodeFloat3,
|
||||
unkLodeInt4
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
lodeData = new LodeData(unused, lodeCount, lodeInfos);
|
||||
}
|
||||
|
||||
return new GameObjectsFileData(
|
||||
gameObjectsFeatureSet,
|
||||
gameObjectsCount,
|
||||
gameObjectInfos,
|
||||
landString,
|
||||
unkInt7,
|
||||
missionTechDescription,
|
||||
lodeData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public record MissionTma(ArealsFileData ArealData, ClansFileData ClansData, GameObjectsFileData GameObjectsData);
|
3
MissionTmaLib/UnknownClanTreeInfoPart.cs
Normal file
3
MissionTmaLib/UnknownClanTreeInfoPart.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record UnknownClanTreeInfoPart(int UnkInt1, Vector3 UnkVector, float UnkInt2, float UnkInt3);
|
3
MissionTmaLib/Vector3.cs
Normal file
3
MissionTmaLib/Vector3.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace MissionTmaLib;
|
||||
|
||||
public record Vector3(float X, float Y, float Z);
|
Reference in New Issue
Block a user