mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-18 19:31:17 +03:00
теперь читает данные о миссии)
This commit is contained in:
parent
d1b02ecc67
commit
b14742f2cd
@ -1,18 +1,21 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Autodemo.00\\data.tma";
|
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Autodemo.00\\data.tma";
|
||||||
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Tutorial.01\\data.tma";
|
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Tutorial.01\\data.tma";
|
||||||
var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\CAMPAIGN\\CAMPAIGN.01\\Mission.03\\data.tma";
|
var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\CAMPAIGN\\CAMPAIGN.01\\Mission.02\\data.tma";
|
||||||
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Single.01\\data.tma";
|
// var missionFilePath = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\Single.01\\data.tma";
|
||||||
var fs = new FileStream(missionFilePath, FileMode.Open);
|
var fs = new FileStream(missionFilePath, FileMode.Open);
|
||||||
|
|
||||||
var arealData = LoadAreals(fs);
|
var arealData = LoadAreals(fs);
|
||||||
|
|
||||||
var clans = LoadClans(fs);
|
var clansData = LoadClans(fs);
|
||||||
|
|
||||||
|
var gameObjectsData = LoadGameObjects(fs);
|
||||||
|
|
||||||
_ = 5;
|
_ = 5;
|
||||||
// LoadGameObjects(fs);
|
|
||||||
|
|
||||||
ArealsFileData LoadAreals(FileStream fileStream)
|
ArealsFileData LoadAreals(FileStream fileStream)
|
||||||
{
|
{
|
||||||
@ -58,16 +61,16 @@ ClansFileData? LoadClans(FileStream fileStream)
|
|||||||
|
|
||||||
var treeInfoCount = fileStream.ReadInt32LittleEndian();
|
var treeInfoCount = fileStream.ReadInt32LittleEndian();
|
||||||
|
|
||||||
List<ClanTreeInfo> infos = [];
|
List<ClanInfo> infos = [];
|
||||||
for (var i = 0; i < treeInfoCount; i++)
|
for (var i = 0; i < treeInfoCount; i++)
|
||||||
{
|
{
|
||||||
var clanTreeInfo = new ClanTreeInfo();
|
var clanTreeInfo = new ClanInfo();
|
||||||
|
|
||||||
clanTreeInfo.ClanName = fileStream.ReadLengthPrefixedString();
|
clanTreeInfo.ClanName = fileStream.ReadLengthPrefixedString();
|
||||||
clanTreeInfo.UnkInt1 = fileStream.ReadInt32LittleEndian();
|
clanTreeInfo.UnkInt1 = fileStream.ReadInt32LittleEndian();
|
||||||
clanTreeInfo.X = fileStream.ReadFloatLittleEndian();
|
clanTreeInfo.X = fileStream.ReadFloatLittleEndian();
|
||||||
clanTreeInfo.Y = fileStream.ReadFloatLittleEndian();
|
clanTreeInfo.Y = fileStream.ReadFloatLittleEndian();
|
||||||
clanTreeInfo.ClanType = fileStream.ReadInt32LittleEndian();
|
clanTreeInfo.ClanType = (ClanType)fileStream.ReadInt32LittleEndian();
|
||||||
|
|
||||||
if (1 < clanFeatureSet)
|
if (1 < clanFeatureSet)
|
||||||
{
|
{
|
||||||
@ -152,6 +155,221 @@ ClansFileData? LoadClans(FileStream fileStream)
|
|||||||
return clanInfo;
|
return clanInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static int ReadInt32LittleEndian(this FileStream fs)
|
public static int ReadInt32LittleEndian(this FileStream fs)
|
||||||
@ -174,6 +392,11 @@ public static class Extensions
|
|||||||
{
|
{
|
||||||
var len = fs.ReadInt32LittleEndian();
|
var len = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
var buffer = new byte[len];
|
var buffer = new byte[len];
|
||||||
|
|
||||||
fs.ReadExactly(buffer, 0, len);
|
fs.ReadExactly(buffer, 0, len);
|
||||||
@ -190,9 +413,9 @@ public record Vector3(float X, float Y, float Z);
|
|||||||
|
|
||||||
// ----
|
// ----
|
||||||
|
|
||||||
public record ClansFileData(int ClanFeatureSet, int TreeCount, List<ClanTreeInfo> TreeInfos);
|
public record ClansFileData(int ClanFeatureSet, int ClanCount, List<ClanInfo> ClanInfos);
|
||||||
|
|
||||||
public class ClanTreeInfo
|
public class ClanInfo
|
||||||
{
|
{
|
||||||
public string ClanName { get; set; }
|
public string ClanName { get; set; }
|
||||||
public int UnkInt1 { get; set; }
|
public int UnkInt1 { get; set; }
|
||||||
@ -202,10 +425,15 @@ public class ClanTreeInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 1 - игрок, 2 AI, 3 - нейтральный
|
/// 1 - игрок, 2 AI, 3 - нейтральный
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ClanType { get; set; }
|
public ClanType ClanType { get; set; }
|
||||||
|
|
||||||
public string UnkString2 { get; set; }
|
public string UnkString2 { get; set; }
|
||||||
public int UnknownClanPartCount { get; set; }
|
public int UnknownClanPartCount { get; set; }
|
||||||
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
|
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Игра называет этот путь TreeName
|
||||||
|
/// </summary>
|
||||||
public string ResearchNResPath { get; set; }
|
public string ResearchNResPath { get; set; }
|
||||||
public int UnkInt3 { get; set; }
|
public int UnkInt3 { get; set; }
|
||||||
public int AlliesMapCount { get; set; }
|
public int AlliesMapCount { get; set; }
|
||||||
@ -217,3 +445,73 @@ public class ClanTreeInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
public record UnknownClanTreeInfoPart(int UnkInt1, Vector3 UnkVector, float UnkInt2, float UnkInt3);
|
public record UnknownClanTreeInfoPart(int UnkInt1, Vector3 UnkVector, float UnkInt2, float UnkInt3);
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GameObjectsFileData(int GameObjectsFeatureSet, int GameObjectsCount, List<GameObjectInfo> GameObjectInfos, string LandString, int UnknownInt, string? MissionTechDescription, LodeData? LodeData);
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GameObjectSettings(int Unused, int SettingsCount, List<GameObjectSetting> Settings);
|
||||||
|
|
||||||
|
public record GameObjectSetting(int SettingType, IntFloatValue Unk1, IntFloatValue Unk2, IntFloatValue Unk3, string Name);
|
||||||
|
|
||||||
|
public record LodeData(int Unused, int LodeCount, List<LodeInfo> Lodes);
|
||||||
|
|
||||||
|
public record LodeInfo(Vector3 UnknownVector, int UnknownInt1, int UnknownInt2, float UnknownFloat, int UnknownInt3);
|
||||||
|
|
||||||
|
public enum GameObjectType
|
||||||
|
{
|
||||||
|
Building = 0,
|
||||||
|
Warbot = 1,
|
||||||
|
Tree = 2,
|
||||||
|
Stone = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ClanType
|
||||||
|
{
|
||||||
|
Environment = 0,
|
||||||
|
Player = 1,
|
||||||
|
AI = 2,
|
||||||
|
Neutral = 3
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user