0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-05-18 19:31:17 +03:00

теперь читает данные о миссии)

This commit is contained in:
bird_egop 2024-11-25 03:37:52 +03:00
parent d1b02ecc67
commit b14742f2cd

View File

@ -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,17 +61,17 @@ 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)
{ {
// MISSIONS\SCRIPTS\default // MISSIONS\SCRIPTS\default
@ -120,7 +123,7 @@ ClansFileData? LoadClans(FileStream fileStream)
if (5 < clanFeatureSet) if (5 < clanFeatureSet)
{ {
clanTreeInfo.AlliesMapCount = fileStream.ReadInt32LittleEndian(); clanTreeInfo.AlliesMapCount = fileStream.ReadInt32LittleEndian();
// тут какая-то мапа // тут какая-то мапа
// в демо миссии тут // в демо миссии тут
// player -> 1 // player -> 1
@ -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,30 +413,105 @@ 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; }
public float X { get; set; } public float X { get; set; }
public float Y { get; set; } public float Y { get; set; }
/// <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; }
/// <summary> /// <summary>
/// мапа союзников (ключ - имя клана, значение - число, всегда либо 0 либо 1) /// мапа союзников (ключ - имя клана, значение - число, всегда либо 0 либо 1)
/// </summary> /// </summary>
public Dictionary<string, int> AlliesMap { get; set; } public Dictionary<string, int> AlliesMap { get; set; }
} }
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
}