mirror of
				https://github.com/sampletext32/ParkanPlayground.git
				synced 2025-10-30 21:19:44 +03:00 
			
		
		
		
	Implement SCR UI
This commit is contained in:
		| @@ -12,7 +12,7 @@ public class ClanInfo | ||||
|     /// </summary> | ||||
|     public ClanType ClanType { get; set; } | ||||
|  | ||||
|     public string UnkString2 { get; set; } | ||||
|     public string ScriptsString { get; set; } | ||||
|     public int UnknownClanPartCount { get; set; } | ||||
|     public List<UnknownClanTreeInfoPart> UnknownParts { get; set; } | ||||
|      | ||||
|   | ||||
| @@ -78,7 +78,7 @@ public class MissionTmaParser | ||||
|                 // MISSIONS\SCRIPTS\default | ||||
|                 // MISSIONS\SCRIPTS\tut1_pl | ||||
|                 // MISSIONS\SCRIPTS\tut1_en | ||||
|                 clanTreeInfo.UnkString2 = fileStream.ReadLengthPrefixedString(); | ||||
|                 clanTreeInfo.ScriptsString = fileStream.ReadLengthPrefixedString(); | ||||
|             } | ||||
|  | ||||
|             if (2 < clanFeatureSet) | ||||
|   | ||||
| @@ -53,6 +53,8 @@ public class App | ||||
|             serviceCollection.AddSingleton(new NResExplorerViewModel()); | ||||
|             serviceCollection.AddSingleton(new TexmExplorerViewModel()); | ||||
|             serviceCollection.AddSingleton(new MissionTmaViewModel()); | ||||
|             serviceCollection.AddSingleton(new BinaryExplorerViewModel()); | ||||
|             serviceCollection.AddSingleton(new ScrViewModel()); | ||||
|  | ||||
|             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; | ||||
|     } | ||||
| } | ||||
| @@ -6,25 +6,19 @@ using NativeFileDialogSharp; | ||||
| using NResLib; | ||||
| using NResUI.Abstractions; | ||||
| using NResUI.Models; | ||||
| using ScrLib; | ||||
| using TexmLib; | ||||
|  | ||||
| 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() | ||||
|         { | ||||
|             if (ImGui.BeginMenuBar()) | ||||
| @@ -41,7 +35,7 @@ namespace NResUI.ImGuiUI | ||||
|  | ||||
|                             var parseResult = NResParser.ReadFile(path); | ||||
|  | ||||
|                             _nResExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             nResExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             Console.WriteLine("Read NRES"); | ||||
|                         } | ||||
|                     } | ||||
| @@ -58,7 +52,7 @@ namespace NResUI.ImGuiUI | ||||
|  | ||||
|                             var parseResult = TexmParser.ReadFromStream(fs, path); | ||||
|  | ||||
|                             _texmExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             texmExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             Console.WriteLine("Read TEXM"); | ||||
|                         } | ||||
|                     } | ||||
| @@ -77,8 +71,8 @@ namespace NResUI.ImGuiUI | ||||
|  | ||||
|                             var parseResult = TexmParser.ReadFromStream(fs, path); | ||||
|  | ||||
|                             _texmExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             Console.WriteLine("Read TEXM"); | ||||
|                             texmExplorerViewModel.SetParseResult(parseResult, path); | ||||
|                             Console.WriteLine("Read TFNT TEXM"); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
| @@ -91,20 +85,26 @@ namespace NResUI.ImGuiUI | ||||
|                             var path = result.Path; | ||||
|                             var parseResult = MissionTmaParser.ReadFile(path); | ||||
|  | ||||
|                             _missionTmaViewModel.SetParseResult(parseResult, path); | ||||
|  | ||||
|                             var orderedBuildings = parseResult.Mission.GameObjectsData.GameObjectInfos.Where(x => x.Type == GameObjectType.Building) | ||||
|                                 .OrderBy(x => x.Order) | ||||
|                                 .ToList(); | ||||
|                              | ||||
|                             foreach (var gameObjectInfo in orderedBuildings) | ||||
|                             { | ||||
|                                 Console.WriteLine($"{gameObjectInfo.Order} : {gameObjectInfo.DatString}"); | ||||
|                             } | ||||
|                             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")) | ||||
|                         { | ||||
| @@ -114,9 +114,9 @@ namespace NResUI.ImGuiUI | ||||
|                             { | ||||
|                                 var path = result.Path; | ||||
|  | ||||
|                                 NResExporter.Export(_nResExplorerViewModel.Archive!, path, _nResExplorerViewModel.Path!); | ||||
|                                 NResExporter.Export(nResExplorerViewModel.Archive!, path, nResExplorerViewModel.Path!); | ||||
|  | ||||
|                                 _messageBox.Show("Успешно экспортировано"); | ||||
|                                 messageBox.Show("Успешно экспортировано"); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| @@ -127,6 +127,5 @@ namespace NResUI.ImGuiUI | ||||
|                 ImGui.EndMenuBar(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -132,10 +132,10 @@ public class MissionTmaExplorer : IImGuiPanel | ||||
|                                 ImGui.SameLine(); | ||||
|                                 ImGui.Text(clanInfo.ClanType.ToReadableString()); | ||||
|  | ||||
|                                 ImGui.Text("Неизвестная строка 1: "); | ||||
|                                 Utils.ShowHint("Кажется это путь к файлу поведения (Behavior), но пока не понятно. Обычно пути соответствуют 2 файла."); | ||||
|                                 ImGui.Text("Скрипты поведения: "); | ||||
|                                 Utils.ShowHint("Пути к файлам .scr и .fml описывающих настройку объектов и поведение AI"); | ||||
|                                 ImGui.SameLine(); | ||||
|                                 ImGui.Text(clanInfo.UnkString2); | ||||
|                                 ImGui.Text(clanInfo.ScriptsString); | ||||
|  | ||||
|                                 if (clanInfo.UnknownParts.Count > 0) | ||||
|                                 { | ||||
|   | ||||
							
								
								
									
										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> | ||||
|       <ProjectReference Include="..\MissionTmaLib\MissionTmaLib.csproj" /> | ||||
|       <ProjectReference Include="..\NResLib\NResLib.csproj" /> | ||||
|       <ProjectReference Include="..\ScrLib\ScrLib.csproj" /> | ||||
|       <ProjectReference Include="..\TexmLib\TexmLib.csproj" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|   | ||||
| @@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{BAF212FE-A | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MissionTmaLib", "MissionTmaLib\MissionTmaLib.csproj", "{773D8EEA-6005-4127-9CB4-5F9F1A028B5D}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrLib", "ScrLib\ScrLib.csproj", "{C445359B-97D4-4432-9331-708B5A14887A}" | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		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}.Release|Any CPU.ActiveCfg = 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 | ||||
| EndGlobal | ||||
|   | ||||
| @@ -3,7 +3,10 @@ using System.Text; | ||||
| using NResLib; | ||||
| using ParkanPlayground; | ||||
|  | ||||
| var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\11p.scr"; | ||||
| // 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"; | ||||
|  | ||||
| using var fs = new FileStream(path, FileMode.Open); | ||||
|  | ||||
| @@ -32,25 +35,25 @@ for (var i = 0; i < entryCount; i++) | ||||
|     Console.WriteLine($"\tInnerCount: {innerCount}"); | ||||
|     for (var i1 = 0; i1 < innerCount; i1++) | ||||
|     { | ||||
|         var unkInner1 = fs.ReadInt32LittleEndian(); | ||||
|         var scriptIndex = fs.ReadInt32LittleEndian(); | ||||
|         var unkInner2 = fs.ReadInt32LittleEndian(); | ||||
|         var unkInner3 = fs.ReadInt32LittleEndian(); | ||||
|         var unkInner4 = fs.ReadInt32LittleEndian(); | ||||
|         var unkInner5 = fs.ReadInt32LittleEndian(); | ||||
|          | ||||
|         Console.WriteLine($"\t\tUnkInner1: {unkInner1}"); | ||||
|         Console.WriteLine($"\t\tScriptIndex: {scriptIndex}"); | ||||
|         Console.WriteLine($"\t\tUnkInner2: {unkInner2}"); | ||||
|         Console.WriteLine($"\t\tUnkInner3: {unkInner3}"); | ||||
|         Console.WriteLine($"\t\tUnkInner4: {unkInner4}"); | ||||
|         Console.WriteLine($"\t\tUnkInner5: {unkInner5}"); | ||||
|          | ||||
|         var innerInnerCount = fs.ReadInt32LittleEndian(); | ||||
|         Console.WriteLine($"\t\tInnerInnerCount: {innerInnerCount}"); | ||||
|         var scriptArgumentsCount = fs.ReadInt32LittleEndian(); | ||||
|         Console.WriteLine($"\t\tScript Arguments Count: {scriptArgumentsCount}"); | ||||
|          | ||||
|         for (var i2 = 0; i2 < innerInnerCount; i2++) | ||||
|         for (var i2 = 0; i2 < scriptArgumentsCount; i2++) | ||||
|         { | ||||
|             var innerInner = fs.ReadInt32LittleEndian(); | ||||
|             Console.WriteLine($"\t\t\t{innerInner}"); | ||||
|             var scriptArgument = fs.ReadInt32LittleEndian(); | ||||
|             Console.WriteLine($"\t\t\t{scriptArgument}"); | ||||
|         } | ||||
|  | ||||
|         var unkInner7 = fs.ReadInt32LittleEndian(); | ||||
|   | ||||
							
								
								
									
										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
	 bird_egop
					bird_egop