mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-07-03 13:20:26 +03:00
Compare commits
4 Commits
backup2611
...
backup0103
Author | SHA1 | Date | |
---|---|---|---|
d7eb23e9e0 | |||
b47a9aff5d | |||
ba7c2afe2a | |||
c50512ea52 |
@ -12,7 +12,7 @@ public class ClanInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ClanType ClanType { get; set; }
|
public ClanType ClanType { get; set; }
|
||||||
|
|
||||||
public string UnkString2 { get; set; }
|
public string ScriptsString { get; set; }
|
||||||
public int UnknownClanPartCount { get; set; }
|
public int UnknownClanPartCount { get; set; }
|
||||||
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
|
public List<UnknownClanTreeInfoPart> UnknownParts { get; set; }
|
||||||
|
|
||||||
|
@ -6,19 +6,4 @@ public enum ClanType
|
|||||||
Player = 1,
|
Player = 1,
|
||||||
AI = 2,
|
AI = 2,
|
||||||
Neutral = 3
|
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})"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
28
MissionTmaLib/Extensions.cs
Normal file
28
MissionTmaLib/Extensions.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
namespace MissionTmaLib;
|
||||||
|
|
||||||
|
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})"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToReadableString(this GameObjectType type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
GameObjectType.Building => $"Строение {type:D}",
|
||||||
|
GameObjectType.Warbot => $"Варбот {type:D}",
|
||||||
|
GameObjectType.Tree => $"Дерево {type:D}",
|
||||||
|
GameObjectType.Stone => $"Камень {type:D}",
|
||||||
|
_ => $"Неизвестный ({type:D})"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ public class GameObjectInfo
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public int OwningClanIndex { get; set; }
|
public int OwningClanIndex { get; set; }
|
||||||
|
|
||||||
public int UnknownInt3 { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
public Vector3 Position { get; set; }
|
public Vector3 Position { get; set; }
|
||||||
public Vector3 Rotation { get; set; }
|
public Vector3 Rotation { get; set; }
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
namespace MissionTmaLib;
|
namespace MissionTmaLib;
|
||||||
|
|
||||||
public record LodeInfo(Vector3 UnknownVector, int UnknownInt1, int UnknownInt2, float UnknownFloat, int UnknownInt3);
|
public record LodeInfo(Vector3 UnknownVector, int UnknownInt1, int UnknownFlags2, float UnknownFloat, int UnknownInt3);
|
3
MissionTmaLib/Parsing/MissionTma.cs
Normal file
3
MissionTmaLib/Parsing/MissionTma.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace MissionTmaLib.Parsing;
|
||||||
|
|
||||||
|
public record MissionTma(ArealsFileData ArealData, ClansFileData ClansData, GameObjectsFileData GameObjectsData);
|
@ -78,7 +78,7 @@ public class MissionTmaParser
|
|||||||
// MISSIONS\SCRIPTS\default
|
// MISSIONS\SCRIPTS\default
|
||||||
// MISSIONS\SCRIPTS\tut1_pl
|
// MISSIONS\SCRIPTS\tut1_pl
|
||||||
// MISSIONS\SCRIPTS\tut1_en
|
// MISSIONS\SCRIPTS\tut1_en
|
||||||
clanTreeInfo.UnkString2 = fileStream.ReadLengthPrefixedString();
|
clanTreeInfo.ScriptsString = fileStream.ReadLengthPrefixedString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (2 < clanFeatureSet)
|
if (2 < clanFeatureSet)
|
||||||
@ -185,7 +185,11 @@ public class MissionTmaParser
|
|||||||
|
|
||||||
if (3 < gameObjectsFeatureSet)
|
if (3 < gameObjectsFeatureSet)
|
||||||
{
|
{
|
||||||
gameObjectInfo.UnknownInt3 = fileStream.ReadInt32LittleEndian();
|
gameObjectInfo.Order = fileStream.ReadInt32LittleEndian();
|
||||||
|
if (gameObjectInfo.Type == GameObjectType.Building)
|
||||||
|
{
|
||||||
|
gameObjectInfo.Order += int.MaxValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// читает 12 байт
|
// читает 12 байт
|
||||||
@ -378,6 +382,4 @@ public class MissionTmaParser
|
|||||||
lodeData
|
lodeData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record MissionTma(ArealsFileData ArealData, ClansFileData ClansData, GameObjectsFileData GameObjectsData);
|
|
@ -53,6 +53,8 @@ public class App
|
|||||||
serviceCollection.AddSingleton(new NResExplorerViewModel());
|
serviceCollection.AddSingleton(new NResExplorerViewModel());
|
||||||
serviceCollection.AddSingleton(new TexmExplorerViewModel());
|
serviceCollection.AddSingleton(new TexmExplorerViewModel());
|
||||||
serviceCollection.AddSingleton(new MissionTmaViewModel());
|
serviceCollection.AddSingleton(new MissionTmaViewModel());
|
||||||
|
serviceCollection.AddSingleton(new BinaryExplorerViewModel());
|
||||||
|
serviceCollection.AddSingleton(new ScrViewModel());
|
||||||
|
|
||||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
262
NResUI/ImGuiUI/BinaryExplorerPanel.cs
Normal file
262
NResUI/ImGuiUI/BinaryExplorerPanel.cs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using ImGuiNET;
|
||||||
|
using NativeFileDialogSharp;
|
||||||
|
using NResUI.Abstractions;
|
||||||
|
using NResUI.Models;
|
||||||
|
|
||||||
|
namespace NResUI.ImGuiUI;
|
||||||
|
|
||||||
|
public class BinaryExplorerPanel : IImGuiPanel
|
||||||
|
{
|
||||||
|
private readonly BinaryExplorerViewModel _viewModel;
|
||||||
|
|
||||||
|
public BinaryExplorerPanel(BinaryExplorerViewModel viewModel)
|
||||||
|
{
|
||||||
|
_viewModel = viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnImGuiRender()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
if (ImGui.Begin("Binary Explorer"))
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Open File"))
|
||||||
|
{
|
||||||
|
OpenFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_viewModel.HasFile)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(_viewModel.Path);
|
||||||
|
|
||||||
|
if (ImGui.Button("Сохранить регионы"))
|
||||||
|
{
|
||||||
|
File.WriteAllText("preset.json", JsonSerializer.Serialize(_viewModel.Regions));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Загрузить регионы"))
|
||||||
|
{
|
||||||
|
_viewModel.Regions = JsonSerializer.Deserialize<List<Region>>(File.ReadAllText("preset.json"))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int bytesPerRow = 16;
|
||||||
|
if (ImGui.BeginTable("HexTable", bytesPerRow + 1, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Address", ImGuiTableColumnFlags.WidthFixed);
|
||||||
|
for (var i = 0; i < bytesPerRow; i++)
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn(i.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
for (int i = 0; i < _viewModel.Data.Length; i += bytesPerRow)
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text($"{i:x8} ");
|
||||||
|
|
||||||
|
for (int j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
var index = i + j;
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (index < _viewModel.Data.Length)
|
||||||
|
{
|
||||||
|
uint? regionColor = GetRegionColor(i + j);
|
||||||
|
|
||||||
|
if (regionColor is not null)
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Header, regionColor.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Selectable($"{_viewModel.Data[i + j]}##sel{i + j}", regionColor.HasValue))
|
||||||
|
{
|
||||||
|
HandleRegionSelect(i + j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionColor is not null)
|
||||||
|
{
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
ImGui.SetNextItemWidth(200f);
|
||||||
|
if (ImGui.ColorPicker4("NextColor", ref _viewModel.NextColor, ImGuiColorEditFlags.Float))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("Регионы", 5, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Номер");
|
||||||
|
ImGui.TableSetupColumn("Старт");
|
||||||
|
ImGui.TableSetupColumn("Длина");
|
||||||
|
ImGui.TableSetupColumn("Значение");
|
||||||
|
ImGui.TableSetupColumn("Действия");
|
||||||
|
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
for (int k = 0; k < _viewModel.Regions.Count; k++)
|
||||||
|
{
|
||||||
|
var region = _viewModel.Regions[k];
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(k.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(region.Begin.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(region.Length.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(region.Value ?? "unknown");
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
if (ImGui.Button($"float##f{k}"))
|
||||||
|
{
|
||||||
|
region.Value = BinaryPrimitives.ReadSingleLittleEndian(_viewModel.Data.AsSpan()[region.Begin..(region.Begin + region.Length)])
|
||||||
|
.ToString("F2");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button($"int##i{k}"))
|
||||||
|
{
|
||||||
|
region.Value = BinaryPrimitives.ReadInt32LittleEndian(_viewModel.Data.AsSpan()[region.Begin..(region.Begin + region.Length)])
|
||||||
|
.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button($"ASCII##a{k}"))
|
||||||
|
{
|
||||||
|
region.Value = Encoding.ASCII.GetString(_viewModel.Data.AsSpan()[region.Begin..(region.Begin + region.Length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button($"raw##r{k}"))
|
||||||
|
{
|
||||||
|
region.Value = string.Join(
|
||||||
|
"",
|
||||||
|
_viewModel.Data[region.Begin..(region.Begin + region.Length)]
|
||||||
|
.Select(x => x.ToString("x2"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint? GetRegionColor(int index)
|
||||||
|
{
|
||||||
|
Region? inRegion = _viewModel.Regions.Find(x => x.Begin <= index && x.Begin + x.Length > index);
|
||||||
|
|
||||||
|
return inRegion?.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleRegionSelect(int index)
|
||||||
|
{
|
||||||
|
Region? inRegion = _viewModel.Regions.FirstOrDefault(x => x.Begin <= index && index < x.Begin + x.Length);
|
||||||
|
|
||||||
|
if (inRegion is null)
|
||||||
|
{
|
||||||
|
// not in region
|
||||||
|
Region? prependRegion;
|
||||||
|
Region? appendRegion;
|
||||||
|
|
||||||
|
if ((prependRegion = _viewModel.Regions.Find(x => x.Begin + x.Length == index)) is not null)
|
||||||
|
{
|
||||||
|
if (prependRegion.Color == GetImGuiColor(_viewModel.NextColor))
|
||||||
|
{
|
||||||
|
prependRegion.Length += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((appendRegion = _viewModel.Regions.Find(x => x.Begin - 1 == index)) is not null)
|
||||||
|
{
|
||||||
|
if (appendRegion.Color == GetImGuiColor(_viewModel.NextColor))
|
||||||
|
{
|
||||||
|
appendRegion.Begin--;
|
||||||
|
appendRegion.Length += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = ImGui.ColorConvertFloat4ToU32(_viewModel.NextColor);
|
||||||
|
|
||||||
|
color = unchecked((uint) (0xFF << 24)) | color;
|
||||||
|
_viewModel.Regions.Add(
|
||||||
|
new Region()
|
||||||
|
{
|
||||||
|
Begin = index,
|
||||||
|
Length = 1,
|
||||||
|
Color = color
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (inRegion.Length == 1)
|
||||||
|
{
|
||||||
|
_viewModel.Regions.Remove(inRegion);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (inRegion.Begin == index)
|
||||||
|
{
|
||||||
|
inRegion.Begin++;
|
||||||
|
inRegion.Length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inRegion.Begin + inRegion.Length - 1 == index)
|
||||||
|
{
|
||||||
|
inRegion.Length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint GetImGuiColor(Vector4 vec)
|
||||||
|
{
|
||||||
|
var color = ImGui.ColorConvertFloat4ToU32(vec);
|
||||||
|
|
||||||
|
color = unchecked((uint) (0xFF << 24)) | color;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OpenFile()
|
||||||
|
{
|
||||||
|
var result = Dialog.FileOpen("*");
|
||||||
|
|
||||||
|
if (result.IsOk)
|
||||||
|
{
|
||||||
|
var path = result.Path;
|
||||||
|
|
||||||
|
var bytes = File.ReadAllBytes(path);
|
||||||
|
_viewModel.HasFile = true;
|
||||||
|
_viewModel.Data = bytes;
|
||||||
|
_viewModel.Path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,24 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using MissionTmaLib;
|
||||||
using MissionTmaLib.Parsing;
|
using MissionTmaLib.Parsing;
|
||||||
using NativeFileDialogSharp;
|
using NativeFileDialogSharp;
|
||||||
using NResLib;
|
using NResLib;
|
||||||
using NResUI.Abstractions;
|
using NResUI.Abstractions;
|
||||||
using NResUI.Models;
|
using NResUI.Models;
|
||||||
|
using ScrLib;
|
||||||
using TexmLib;
|
using TexmLib;
|
||||||
|
|
||||||
namespace NResUI.ImGuiUI
|
namespace NResUI.ImGuiUI
|
||||||
{
|
{
|
||||||
public class MainMenuBar : IImGuiPanel
|
public class MainMenuBar(
|
||||||
|
NResExplorerViewModel nResExplorerViewModel,
|
||||||
|
TexmExplorerViewModel texmExplorerViewModel,
|
||||||
|
ScrViewModel scrViewModel,
|
||||||
|
MissionTmaViewModel missionTmaViewModel,
|
||||||
|
MessageBoxModalPanel messageBox)
|
||||||
|
: IImGuiPanel
|
||||||
{
|
{
|
||||||
private readonly NResExplorerViewModel _nResExplorerViewModel;
|
|
||||||
private readonly TexmExplorerViewModel _texmExplorerViewModel;
|
|
||||||
private readonly MissionTmaViewModel _missionTmaViewModel;
|
|
||||||
|
|
||||||
private readonly MessageBoxModalPanel _messageBox;
|
|
||||||
public MainMenuBar(NResExplorerViewModel nResExplorerViewModel, TexmExplorerViewModel texmExplorerViewModel, MessageBoxModalPanel messageBox, MissionTmaViewModel missionTmaViewModel)
|
|
||||||
{
|
|
||||||
_nResExplorerViewModel = nResExplorerViewModel;
|
|
||||||
_texmExplorerViewModel = texmExplorerViewModel;
|
|
||||||
_messageBox = messageBox;
|
|
||||||
_missionTmaViewModel = missionTmaViewModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnImGuiRender()
|
public void OnImGuiRender()
|
||||||
{
|
{
|
||||||
if (ImGui.BeginMenuBar())
|
if (ImGui.BeginMenuBar())
|
||||||
@ -40,7 +35,7 @@ namespace NResUI.ImGuiUI
|
|||||||
|
|
||||||
var parseResult = NResParser.ReadFile(path);
|
var parseResult = NResParser.ReadFile(path);
|
||||||
|
|
||||||
_nResExplorerViewModel.SetParseResult(parseResult, path);
|
nResExplorerViewModel.SetParseResult(parseResult, path);
|
||||||
Console.WriteLine("Read NRES");
|
Console.WriteLine("Read NRES");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,10 +49,10 @@ namespace NResUI.ImGuiUI
|
|||||||
var path = result.Path;
|
var path = result.Path;
|
||||||
|
|
||||||
using var fs = new FileStream(path, FileMode.Open);
|
using var fs = new FileStream(path, FileMode.Open);
|
||||||
|
|
||||||
var parseResult = TexmParser.ReadFromStream(fs, path);
|
var parseResult = TexmParser.ReadFromStream(fs, path);
|
||||||
|
|
||||||
_texmExplorerViewModel.SetParseResult(parseResult, path);
|
texmExplorerViewModel.SetParseResult(parseResult, path);
|
||||||
Console.WriteLine("Read TEXM");
|
Console.WriteLine("Read TEXM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,11 +68,11 @@ namespace NResUI.ImGuiUI
|
|||||||
using var fs = new FileStream(path, FileMode.Open);
|
using var fs = new FileStream(path, FileMode.Open);
|
||||||
|
|
||||||
fs.Seek(4116, SeekOrigin.Begin);
|
fs.Seek(4116, SeekOrigin.Begin);
|
||||||
|
|
||||||
var parseResult = TexmParser.ReadFromStream(fs, path);
|
var parseResult = TexmParser.ReadFromStream(fs, path);
|
||||||
|
|
||||||
_texmExplorerViewModel.SetParseResult(parseResult, path);
|
texmExplorerViewModel.SetParseResult(parseResult, path);
|
||||||
Console.WriteLine("Read TEXM");
|
Console.WriteLine("Read TFNT TEXM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,12 +84,27 @@ namespace NResUI.ImGuiUI
|
|||||||
{
|
{
|
||||||
var path = result.Path;
|
var path = result.Path;
|
||||||
var parseResult = MissionTmaParser.ReadFile(path);
|
var parseResult = MissionTmaParser.ReadFile(path);
|
||||||
|
|
||||||
_missionTmaViewModel.SetParseResult(parseResult, path);
|
missionTmaViewModel.SetParseResult(parseResult, path);
|
||||||
|
Console.WriteLine("Read TMA");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nResExplorerViewModel.HasFile)
|
if (ImGui.MenuItem("Open SCR Scripts File"))
|
||||||
|
{
|
||||||
|
var result = Dialog.FileOpen("scr");
|
||||||
|
|
||||||
|
if (result.IsOk)
|
||||||
|
{
|
||||||
|
var path = result.Path;
|
||||||
|
var parseResult = ScrParser.ReadFile(path);
|
||||||
|
|
||||||
|
scrViewModel.SetParseResult(parseResult, path);
|
||||||
|
Console.WriteLine("Read SCR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nResExplorerViewModel.HasFile)
|
||||||
{
|
{
|
||||||
if (ImGui.MenuItem("Экспортировать NRes"))
|
if (ImGui.MenuItem("Экспортировать NRes"))
|
||||||
{
|
{
|
||||||
@ -103,10 +113,10 @@ namespace NResUI.ImGuiUI
|
|||||||
if (result.IsOk)
|
if (result.IsOk)
|
||||||
{
|
{
|
||||||
var path = result.Path;
|
var path = result.Path;
|
||||||
|
|
||||||
NResExporter.Export(_nResExplorerViewModel.Archive!, path, _nResExplorerViewModel.Path!);
|
NResExporter.Export(nResExplorerViewModel.Archive!, path, nResExplorerViewModel.Path!);
|
||||||
|
|
||||||
_messageBox.Show("Успешно экспортировано");
|
messageBox.Show("Успешно экспортировано");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,6 +127,5 @@ namespace NResUI.ImGuiUI
|
|||||||
ImGui.EndMenuBar();
|
ImGui.EndMenuBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,6 +21,8 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
var mission = _viewModel.Mission;
|
var mission = _viewModel.Mission;
|
||||||
if (_viewModel.HasFile && mission is not null)
|
if (_viewModel.HasFile && mission is not null)
|
||||||
{
|
{
|
||||||
|
ImGui.Columns(2);
|
||||||
|
|
||||||
ImGui.Text("Путь к файлу: ");
|
ImGui.Text("Путь к файлу: ");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(_viewModel.Path);
|
ImGui.Text(_viewModel.Path);
|
||||||
@ -65,32 +67,44 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
{
|
{
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Text(arealInfo.Coords[k].X.ToString("F2"));
|
ImGui.Text(
|
||||||
|
arealInfo.Coords[k]
|
||||||
|
.X.ToString("F2")
|
||||||
|
);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Text(arealInfo.Coords[k].Y.ToString("F2"));
|
ImGui.Text(
|
||||||
|
arealInfo.Coords[k]
|
||||||
|
.Y.ToString("F2")
|
||||||
|
);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Text(arealInfo.Coords[k].Z.ToString("F2"));
|
ImGui.Text(
|
||||||
|
arealInfo.Coords[k]
|
||||||
|
.Z.ToString("F2")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTable();
|
ImGui.EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.TreeNodeEx("Кланы"))
|
if (ImGui.TreeNodeEx("Кланы"))
|
||||||
{
|
{
|
||||||
var (clanFeatureSet, clanCount, clanInfos) = mission.ClansData;
|
var (clanFeatureSet, clanCount, clanInfos) = mission.ClansData;
|
||||||
|
|
||||||
ImGui.Text("Фиче-сет: ");
|
ImGui.Text("Фиче-сет: ");
|
||||||
Utils.ShowHint("Магическое число из файла, на основе которого игра читает разные секции о клане");
|
Utils.ShowHint("Магическое число из файла, на основе которого игра читает разные секции о клане");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanFeatureSet.ToString());
|
ImGui.Text(clanFeatureSet.ToString());
|
||||||
|
|
||||||
ImGui.Text("Количество кланов: ");
|
ImGui.Text("Количество кланов: ");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanCount.ToString());
|
ImGui.Text(clanCount.ToString());
|
||||||
@ -113,15 +127,15 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
ImGui.Text(" Y: ");
|
ImGui.Text(" Y: ");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanInfo.Y.ToString());
|
ImGui.Text(clanInfo.Y.ToString());
|
||||||
|
|
||||||
ImGui.Text("Тип клана: ");
|
ImGui.Text("Тип клана: ");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanInfo.ClanType.ToReadableString());
|
ImGui.Text(clanInfo.ClanType.ToReadableString());
|
||||||
|
|
||||||
ImGui.Text("Неизвестная строка 1: ");
|
ImGui.Text("Скрипты поведения: ");
|
||||||
Utils.ShowHint("Кажется это путь к файлу поведения (Behavior), но пока не понятно. Обычно пути соответствуют 2 файла.");
|
Utils.ShowHint("Пути к файлам .scr и .fml описывающих настройку объектов и поведение AI");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanInfo.UnkString2);
|
ImGui.Text(clanInfo.ScriptsString);
|
||||||
|
|
||||||
if (clanInfo.UnknownParts.Count > 0)
|
if (clanInfo.UnknownParts.Count > 0)
|
||||||
{
|
{
|
||||||
@ -166,7 +180,7 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
Utils.ShowHint("Не до конца понятно, что означает, вероятно это NRes с деревом исследований");
|
Utils.ShowHint("Не до конца понятно, что означает, вероятно это NRes с деревом исследований");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanInfo.ResearchNResPath);
|
ImGui.Text(clanInfo.ResearchNResPath);
|
||||||
|
|
||||||
ImGui.Text("Неизвестное число 3: ");
|
ImGui.Text("Неизвестное число 3: ");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text(clanInfo.UnkInt3.ToString());
|
ImGui.Text(clanInfo.UnkInt3.ToString());
|
||||||
@ -178,20 +192,23 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
ImGui.TableSetupColumn("Клан");
|
ImGui.TableSetupColumn("Клан");
|
||||||
ImGui.TableSetupColumn("Союзник?");
|
ImGui.TableSetupColumn("Союзник?");
|
||||||
ImGui.TableHeadersRow();
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
foreach (var alliesMapKey in clanInfo.AlliesMap.Keys)
|
foreach (var alliesMapKey in clanInfo.AlliesMap.Keys)
|
||||||
{
|
{
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Text(alliesMapKey);
|
ImGui.Text(alliesMapKey);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.Text(clanInfo.AlliesMap[alliesMapKey].ToString());
|
ImGui.Text(
|
||||||
|
clanInfo.AlliesMap[alliesMapKey]
|
||||||
|
.ToString()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTable();
|
ImGui.EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,8 +221,189 @@ public class MissionTmaExplorer : IImGuiPanel
|
|||||||
|
|
||||||
if (ImGui.TreeNodeEx("Объекты"))
|
if (ImGui.TreeNodeEx("Объекты"))
|
||||||
{
|
{
|
||||||
|
var gameObjectsData = mission.GameObjectsData;
|
||||||
|
|
||||||
|
ImGui.Text("Фиче-сет: ");
|
||||||
|
Utils.ShowHint("Магическое число из файла, на основе которого игра читает разные секции об объекте");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectsData.GameObjectsFeatureSet.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Кол-во объектов: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectsData.GameObjectsCount.ToString());
|
||||||
|
|
||||||
|
for (var i = 0; i < gameObjectsData.GameObjectInfos.Count; i++)
|
||||||
|
{
|
||||||
|
var gameObjectInfo = gameObjectsData.GameObjectInfos[i];
|
||||||
|
if (ImGui.TreeNodeEx($"Объект {i} - {gameObjectInfo.DatString}"))
|
||||||
|
{
|
||||||
|
ImGui.Text("Тип объекта: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.Type.ToReadableString());
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестные флаги: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.UnknownFlags.ToString("X8"));
|
||||||
|
|
||||||
|
ImGui.Text("Путь к файлу .dat: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.DatString);
|
||||||
|
|
||||||
|
ImGui.Text("Индекс владеющего клана: ");
|
||||||
|
Utils.ShowHint("-1 если объект никому не принадлежит");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.OwningClanIndex.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Порядковый номер: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.Order.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Вектор позиции: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text($"{gameObjectInfo.Position.X} : {gameObjectInfo.Position.Y} : {gameObjectInfo.Position.Z}");
|
||||||
|
|
||||||
|
ImGui.Text("Вектор поворота: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text($"{gameObjectInfo.Rotation.X} : {gameObjectInfo.Rotation.Y} : {gameObjectInfo.Rotation.Z}");
|
||||||
|
|
||||||
|
ImGui.Text("Вектор масштаба: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text($"{gameObjectInfo.Scale.X} : {gameObjectInfo.Scale.Y} : {gameObjectInfo.Scale.Z}");
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестная строка 2: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.UnknownString2);
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестное число 4: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.UnknownInt4.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестное число 5: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.UnknownInt5.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестное число 6: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.UnknownInt6.ToString());
|
||||||
|
|
||||||
|
if (ImGui.TreeNodeEx("Настройки"))
|
||||||
|
{
|
||||||
|
ImGui.Text("Неиспользуемый заголовок: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.Settings.Unused.ToString());
|
||||||
|
ImGui.Text("Кол-во настроек: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectInfo.Settings.SettingsCount.ToString());
|
||||||
|
ImGui.Text("0 - дробное число, 1 - целое число");
|
||||||
|
if (ImGui.BeginTable("Настройки", 5, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Тип");
|
||||||
|
ImGui.TableSetupColumn("Число 1");
|
||||||
|
ImGui.TableSetupColumn("Число 2");
|
||||||
|
ImGui.TableSetupColumn("Число 3");
|
||||||
|
ImGui.TableSetupColumn("Название");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
for (var i1 = 0; i1 < gameObjectInfo.Settings.Settings.Count; i1++)
|
||||||
|
{
|
||||||
|
var setting = gameObjectInfo.Settings.Settings[i1];
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(setting.SettingType.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(setting.SettingType == 0 ? setting.Unk1.AsFloat.ToString() : setting.Unk1.AsInt.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(setting.SettingType == 0 ? setting.Unk1.AsFloat.ToString() : setting.Unk1.AsInt.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(setting.SettingType == 0 ? setting.Unk1.AsFloat.ToString() : setting.Unk1.AsInt.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(setting.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text("LAND строка: ");
|
||||||
|
Utils.ShowHint("Видимо это путь к настройкам поверхности");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectsData.LandString);
|
||||||
|
|
||||||
|
ImGui.Text("Неизвестное число: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectsData.UnknownInt.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Техническое описание: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(gameObjectsData.MissionTechDescription?.Replace((char)0xcd, '.') ?? "Отсутствует");
|
||||||
|
|
||||||
|
var lodeData = gameObjectsData.LodeData;
|
||||||
|
if (lodeData is not null)
|
||||||
|
{
|
||||||
|
ImGui.Text("Информация о LOD-ах");
|
||||||
|
|
||||||
|
ImGui.Text("Неиспользуемый заголовок: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(lodeData.Unused.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Кол-во LOD-ов: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(lodeData.LodeCount.ToString());
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("Информация о лодах", 7, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("X");
|
||||||
|
ImGui.TableSetupColumn("Y");
|
||||||
|
ImGui.TableSetupColumn("Z");
|
||||||
|
ImGui.TableSetupColumn("Число 1");
|
||||||
|
ImGui.TableSetupColumn("Флаги 2");
|
||||||
|
ImGui.TableSetupColumn("Число 3");
|
||||||
|
ImGui.TableSetupColumn("Число 4");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
for (var i1 = 0; i1 < lodeData.Lodes.Count; i1++)
|
||||||
|
{
|
||||||
|
var lode = lodeData.Lodes[i1];
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownVector.X.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownVector.Y.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownVector.Z.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownInt1.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownFlags2.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownFloat.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(lode.UnknownInt3.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text("Информаия о LOD-ах отсутствует");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui.TreePop();
|
ImGui.TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.NextColumn();
|
||||||
|
|
||||||
|
ImGui.Text("Тут хочу сделать карту");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
98
NResUI/ImGuiUI/ScrExplorer.cs
Normal file
98
NResUI/ImGuiUI/ScrExplorer.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using ImGuiNET;
|
||||||
|
using NResUI.Abstractions;
|
||||||
|
using NResUI.Models;
|
||||||
|
|
||||||
|
namespace NResUI.ImGuiUI;
|
||||||
|
|
||||||
|
public class ScrExplorer : IImGuiPanel
|
||||||
|
{
|
||||||
|
private readonly ScrViewModel _viewModel;
|
||||||
|
|
||||||
|
public ScrExplorer(ScrViewModel viewModel)
|
||||||
|
{
|
||||||
|
_viewModel = viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnImGuiRender()
|
||||||
|
{
|
||||||
|
if (ImGui.Begin("SCR Explorer"))
|
||||||
|
{
|
||||||
|
var scr = _viewModel.Scr;
|
||||||
|
if (_viewModel.HasFile && scr is not null)
|
||||||
|
{
|
||||||
|
ImGui.Text("Магия: ");
|
||||||
|
Utils.ShowHint("тут всегда число 59 (0x3b) - это число известных игре скриптов");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(scr.Magic.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Кол-во секций: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(scr.EntryCount.ToString());
|
||||||
|
|
||||||
|
if (ImGui.TreeNodeEx("Секции"))
|
||||||
|
{
|
||||||
|
for (var i = 0; i < scr.Entries.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = scr.Entries[i];
|
||||||
|
if (ImGui.TreeNodeEx($"Секция {i} - \"{entry.Title}\""))
|
||||||
|
{
|
||||||
|
ImGui.Text("Индекс: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(entry.Index.ToString());
|
||||||
|
|
||||||
|
ImGui.Text("Кол-во элементов: ");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(entry.InnerCount.ToString());
|
||||||
|
|
||||||
|
if (ImGui.BeginTable($"Элементы##{i:0000}", 8, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Индекс скрипта");
|
||||||
|
ImGui.TableSetupColumn("UnkInner2");
|
||||||
|
ImGui.TableSetupColumn("UnkInner3");
|
||||||
|
ImGui.TableSetupColumn("UnkInner4");
|
||||||
|
ImGui.TableSetupColumn("UnkInner5");
|
||||||
|
ImGui.TableSetupColumn("Кол-во аргументов");
|
||||||
|
ImGui.TableSetupColumn("Аргументы");
|
||||||
|
ImGui.TableSetupColumn("UnkInner7");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
for (int j = 0; j < entry.Inners.Count; j++)
|
||||||
|
{
|
||||||
|
var inner = entry.Inners[j];
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.ScriptIndex.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.UnkInner2.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.UnkInner3.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.UnkInner4.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.UnkInner5.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.ArgumentsCount.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(string.Join(", ", inner.Arguments));
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text(inner.UnkInner7.ToString());
|
||||||
|
}
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text("SCR не открыт");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
NResUI/Models/BinaryExplorerViewModel.cs
Normal file
27
NResUI/Models/BinaryExplorerViewModel.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace NResUI.Models;
|
||||||
|
|
||||||
|
public class BinaryExplorerViewModel
|
||||||
|
{
|
||||||
|
public bool HasFile { get; set; }
|
||||||
|
public string? Error { get; set; }
|
||||||
|
|
||||||
|
public string Path { get; set; } = "";
|
||||||
|
public byte[] Data { get; set; } = [];
|
||||||
|
|
||||||
|
public List<Region> Regions { get; set; } = [];
|
||||||
|
|
||||||
|
public Vector4 NextColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Region
|
||||||
|
{
|
||||||
|
public int Begin { get; set; }
|
||||||
|
|
||||||
|
public int Length { get; set; }
|
||||||
|
|
||||||
|
public uint Color { get; set; }
|
||||||
|
|
||||||
|
public string? Value;
|
||||||
|
}
|
20
NResUI/Models/ScrViewModel.cs
Normal file
20
NResUI/Models/ScrViewModel.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using ScrLib;
|
||||||
|
|
||||||
|
namespace NResUI.Models;
|
||||||
|
|
||||||
|
public class ScrViewModel
|
||||||
|
{
|
||||||
|
public bool HasFile { get; set; }
|
||||||
|
public string? Error { get; set; }
|
||||||
|
|
||||||
|
public ScrFile? Scr { get; set; }
|
||||||
|
|
||||||
|
public string? Path { get; set; }
|
||||||
|
|
||||||
|
public void SetParseResult(ScrFile scrFile, string path)
|
||||||
|
{
|
||||||
|
Scr = scrFile;
|
||||||
|
HasFile = true;
|
||||||
|
Path = path;
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MissionTmaLib\MissionTmaLib.csproj" />
|
<ProjectReference Include="..\MissionTmaLib\MissionTmaLib.csproj" />
|
||||||
<ProjectReference Include="..\NResLib\NResLib.csproj" />
|
<ProjectReference Include="..\NResLib\NResLib.csproj" />
|
||||||
|
<ProjectReference Include="..\ScrLib\ScrLib.csproj" />
|
||||||
<ProjectReference Include="..\TexmLib\TexmLib.csproj" />
|
<ProjectReference Include="..\TexmLib\TexmLib.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{BAF212FE-A
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MissionTmaLib", "MissionTmaLib\MissionTmaLib.csproj", "{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MissionTmaLib", "MissionTmaLib\MissionTmaLib.csproj", "{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrLib", "ScrLib\ScrLib.csproj", "{C445359B-97D4-4432-9331-708B5A14887A}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -65,5 +67,9 @@ Global
|
|||||||
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C445359B-97D4-4432-9331-708B5A14887A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C445359B-97D4-4432-9331-708B5A14887A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C445359B-97D4-4432-9331-708B5A14887A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C445359B-97D4-4432-9331-708B5A14887A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
39
ParkanPlayground/Extensions.cs
Normal file
39
ParkanPlayground/Extensions.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ParkanPlayground;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,41 +1,64 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NResLib;
|
using NResLib;
|
||||||
|
using ParkanPlayground;
|
||||||
|
|
||||||
var libFile = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\ui\\ui_back.lib";
|
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\default.scr";
|
||||||
|
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\scr_pl_1.scr";
|
||||||
|
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\scream.scr";
|
||||||
|
var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\scream1.scr";
|
||||||
|
|
||||||
var parseResult = NResParser.ReadFile(libFile);
|
using var fs = new FileStream(path, FileMode.Open);
|
||||||
|
|
||||||
if (parseResult.Error != null)
|
// тут всегда число 59 (0x3b) - это число известных игре скриптов
|
||||||
|
var magic = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
Console.WriteLine($"Count: {magic}");
|
||||||
|
|
||||||
|
var entryCount = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
Console.WriteLine($"EntryCount: {entryCount}");
|
||||||
|
|
||||||
|
for (var i = 0; i < entryCount; i++)
|
||||||
{
|
{
|
||||||
Console.WriteLine(parseResult.Error);
|
Console.WriteLine($"Entry: {i}");
|
||||||
return;
|
var str = fs.ReadLengthPrefixedString();
|
||||||
}
|
|
||||||
|
Console.WriteLine($"\tStr: {str}");
|
||||||
|
|
||||||
|
// тут игра дополнительно вычитывает ещё 1 байт, видимо как \0 для char*
|
||||||
|
fs.ReadByte();
|
||||||
|
|
||||||
// var libFileName = new FileInfo(libFile).Name;
|
var index = fs.ReadInt32LittleEndian();
|
||||||
//
|
Console.WriteLine($"\tIndex: {index}");
|
||||||
// if (Directory.Exists(libFileName))
|
var innerCount = fs.ReadInt32LittleEndian();
|
||||||
// {
|
Console.WriteLine($"\tInnerCount: {innerCount}");
|
||||||
// Directory.Delete(libFileName, true);
|
for (var i1 = 0; i1 < innerCount; i1++)
|
||||||
// }
|
{
|
||||||
//
|
var scriptIndex = fs.ReadInt32LittleEndian();
|
||||||
// var dir = Directory.CreateDirectory(libFileName);
|
var unkInner2 = fs.ReadInt32LittleEndian();
|
||||||
//
|
var unkInner3 = fs.ReadInt32LittleEndian();
|
||||||
// byte[] copyBuffer = new byte[8192];
|
var unkInner4 = fs.ReadInt32LittleEndian();
|
||||||
//
|
var unkInner5 = fs.ReadInt32LittleEndian();
|
||||||
// foreach (var element in elements)
|
|
||||||
// {
|
Console.WriteLine($"\t\tScriptIndex: {scriptIndex}");
|
||||||
// nResFs.Seek(element.OffsetInFile, SeekOrigin.Begin);
|
Console.WriteLine($"\t\tUnkInner2: {unkInner2}");
|
||||||
// using var destFs = new FileStream(Path.Combine(libFileName, element.FileName), FileMode.CreateNew);
|
Console.WriteLine($"\t\tUnkInner3: {unkInner3}");
|
||||||
//
|
Console.WriteLine($"\t\tUnkInner4: {unkInner4}");
|
||||||
// var totalCopiedBytes = 0;
|
Console.WriteLine($"\t\tUnkInner5: {unkInner5}");
|
||||||
// while (totalCopiedBytes < element.ItemLength)
|
|
||||||
// {
|
var scriptArgumentsCount = fs.ReadInt32LittleEndian();
|
||||||
// var needReadBytes = Math.Min(element.ItemLength - totalCopiedBytes, copyBuffer.Length);
|
Console.WriteLine($"\t\tScript Arguments Count: {scriptArgumentsCount}");
|
||||||
// var readBytes = nResFs.Read(copyBuffer, 0, needReadBytes);
|
|
||||||
//
|
for (var i2 = 0; i2 < scriptArgumentsCount; i2++)
|
||||||
// destFs.Write(copyBuffer, 0, readBytes);
|
{
|
||||||
//
|
var scriptArgument = fs.ReadInt32LittleEndian();
|
||||||
// totalCopiedBytes += readBytes;
|
Console.WriteLine($"\t\t\t{scriptArgument}");
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
var unkInner7 = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
Console.WriteLine($"\t\tUnkInner7 {unkInner7}");
|
||||||
|
Console.WriteLine("---");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
39
ScrLib/Extensions.cs
Normal file
39
ScrLib/Extensions.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ScrLib;
|
||||||
|
|
||||||
|
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
ScrLib/MissionTmaParseResult.cs
Normal file
3
ScrLib/MissionTmaParseResult.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace ScrLib;
|
||||||
|
|
||||||
|
public record ScrParseResult(ScrFile? Scr, string? Error);
|
43
ScrLib/ScrFile.cs
Normal file
43
ScrLib/ScrFile.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
namespace ScrLib;
|
||||||
|
|
||||||
|
public class ScrFile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// тут всегда число 59 (0x3b) - это число известных игре скриптов
|
||||||
|
/// </summary>
|
||||||
|
public int Magic { get; set; }
|
||||||
|
|
||||||
|
public int EntryCount { get; set; }
|
||||||
|
|
||||||
|
public List<ScrEntry> Entries { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScrEntry
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
public int InnerCount { get; set; }
|
||||||
|
|
||||||
|
public List<ScrEntryInner> Inners { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScrEntryInner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Номер скрипта в игре (это тех, которых 0x3b)
|
||||||
|
/// </summary>
|
||||||
|
public int ScriptIndex { get; set; }
|
||||||
|
|
||||||
|
public int UnkInner2 { get; set; }
|
||||||
|
public int UnkInner3 { get; set; }
|
||||||
|
public int UnkInner4 { get; set; }
|
||||||
|
public int UnkInner5 { get; set; }
|
||||||
|
|
||||||
|
public int ArgumentsCount { get; set; }
|
||||||
|
|
||||||
|
public List<int> Arguments { get; set; }
|
||||||
|
|
||||||
|
public int UnkInner7 { get; set; }
|
||||||
|
}
|
9
ScrLib/ScrLib.csproj
Normal file
9
ScrLib/ScrLib.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>
|
55
ScrLib/ScrParser.cs
Normal file
55
ScrLib/ScrParser.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
namespace ScrLib;
|
||||||
|
|
||||||
|
public class ScrParser
|
||||||
|
{
|
||||||
|
public static ScrFile ReadFile(string filePath)
|
||||||
|
{
|
||||||
|
var fs = new FileStream(filePath, FileMode.Open);
|
||||||
|
|
||||||
|
var scrFile = new ScrFile();
|
||||||
|
|
||||||
|
scrFile.Magic = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
scrFile.EntryCount = fs.ReadInt32LittleEndian();
|
||||||
|
scrFile.Entries = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < scrFile.EntryCount; i++)
|
||||||
|
{
|
||||||
|
var entry = new ScrEntry();
|
||||||
|
entry.Title = fs.ReadLengthPrefixedString();
|
||||||
|
|
||||||
|
// тут игра дополнительно вычитывает ещё 1 байт, видимо как \0 для char*
|
||||||
|
fs.ReadByte();
|
||||||
|
|
||||||
|
entry.Index = fs.ReadInt32LittleEndian();
|
||||||
|
entry.InnerCount = fs.ReadInt32LittleEndian();
|
||||||
|
entry.Inners = [];
|
||||||
|
for (var i1 = 0; i1 < entry.InnerCount; i1++)
|
||||||
|
{
|
||||||
|
var entryInner = new ScrEntryInner();
|
||||||
|
entryInner.ScriptIndex = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
entryInner.UnkInner2 = fs.ReadInt32LittleEndian();
|
||||||
|
entryInner.UnkInner3 = fs.ReadInt32LittleEndian();
|
||||||
|
entryInner.UnkInner4 = fs.ReadInt32LittleEndian();
|
||||||
|
entryInner.UnkInner5 = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
entryInner.ArgumentsCount = fs.ReadInt32LittleEndian();
|
||||||
|
|
||||||
|
entryInner.Arguments = [];
|
||||||
|
|
||||||
|
for (var i2 = 0; i2 < entryInner.ArgumentsCount; i2++)
|
||||||
|
{
|
||||||
|
entryInner.Arguments.Add(fs.ReadInt32LittleEndian());
|
||||||
|
}
|
||||||
|
|
||||||
|
entryInner.UnkInner7 = fs.ReadInt32LittleEndian();
|
||||||
|
entry.Inners.Add(entryInner);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrFile.Entries.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scrFile;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user