mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-07-01 04:40:25 +03:00
implement NRES packing
This commit is contained in:
14
LandscapeExplorer/LandscapeExplorer.csproj
Normal file
14
LandscapeExplorer/LandscapeExplorer.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NResLib\NResLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
332
LandscapeExplorer/Program.cs
Normal file
332
LandscapeExplorer/Program.cs
Normal file
@ -0,0 +1,332 @@
|
||||
using System.Buffers.Binary;
|
||||
using NResLib;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace LandscapeExplorer;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
private const string MapsDirectory = @"C:\Program Files (x86)\Nikita\Iron Strategy\DATA\MAPS\SC_3";
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
Console.WriteLine("Parkan 1 Landscape Explorer\n");
|
||||
|
||||
// Get all .map and .msh files in the directory
|
||||
var mapFiles = Directory.GetFiles(MapsDirectory, "*.map");
|
||||
var mshFiles = Directory.GetFiles(MapsDirectory, "*.msh");
|
||||
|
||||
Console.WriteLine($"Found {mapFiles.Length} .map files and {mshFiles.Length} .msh files in {MapsDirectory}\n");
|
||||
|
||||
// Process .map files
|
||||
Console.WriteLine("=== MAP Files Analysis ===\n");
|
||||
foreach (var mapFile in mapFiles)
|
||||
{
|
||||
AnalyzeNResFile(mapFile);
|
||||
}
|
||||
|
||||
// Process .msh files
|
||||
Console.WriteLine("\n=== MSH Files Analysis ===\n");
|
||||
foreach (var mshFile in mshFiles)
|
||||
{
|
||||
AnalyzeNResFile(mshFile);
|
||||
|
||||
// Perform detailed landscape analysis on MSH files
|
||||
AnalyzeLandscapeMeshFile(mshFile);
|
||||
}
|
||||
|
||||
Console.WriteLine("\nAnalysis complete.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes an NRes file and displays its structure
|
||||
/// </summary>
|
||||
/// <param name="filePath">Path to the NRes file</param>
|
||||
private static void AnalyzeNResFile(string filePath)
|
||||
{
|
||||
Console.WriteLine($"Analyzing file: {Path.GetFileName(filePath)}");
|
||||
|
||||
var parseResult = NResParser.ReadFile(filePath);
|
||||
|
||||
if (parseResult.Error != null)
|
||||
{
|
||||
Console.WriteLine($" Error: {parseResult.Error}");
|
||||
return;
|
||||
}
|
||||
|
||||
var archive = parseResult.Archive!;
|
||||
|
||||
Console.WriteLine($" Header: {archive.Header.NRes}, Version: {archive.Header.Version:X}, Files: {archive.Header.FileCount}, Size: {archive.Header.TotalFileLengthBytes} bytes");
|
||||
|
||||
// Group files by type for better analysis
|
||||
var filesByType = archive.Files.GroupBy(f => f.FileType);
|
||||
|
||||
foreach (var group in filesByType)
|
||||
{
|
||||
Console.WriteLine($" File Type: {group.Key}, Count: {group.Count()}");
|
||||
|
||||
// Display details of the first file of each type as an example
|
||||
var example = group.First();
|
||||
Console.WriteLine($" Example: {example.FileName}");
|
||||
Console.WriteLine($" Elements: {example.ElementCount}, Element Size: {example.ElementSize} bytes");
|
||||
Console.WriteLine($" File Length: {example.FileLength} bytes, Offset: {example.OffsetInFile}");
|
||||
|
||||
// If this is a landscape-related file, provide more detailed analysis
|
||||
if (IsLandscapeRelatedType(group.Key))
|
||||
{
|
||||
AnalyzeLandscapeData(example, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a file type is related to landscape data
|
||||
/// </summary>
|
||||
private static bool IsLandscapeRelatedType(string fileType)
|
||||
{
|
||||
// Based on the Landscape constructor analysis, these types might be related to landscape
|
||||
return fileType == "LAND" || fileType == "TERR" || fileType == "MSH0" ||
|
||||
fileType == "MESH" || fileType == "MATR" || fileType == "TEXT";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes landscape-specific data in a file
|
||||
/// </summary>
|
||||
private static void AnalyzeLandscapeData(ListMetadataItem item, string filePath)
|
||||
{
|
||||
Console.WriteLine($" [Landscape Data Analysis]:");
|
||||
|
||||
// Read the file data for this specific item
|
||||
using var fs = new FileStream(filePath, FileMode.Open);
|
||||
fs.Seek(item.OffsetInFile, SeekOrigin.Begin);
|
||||
|
||||
var buffer = new byte[Math.Min(item.FileLength, 256)]; // Read at most 256 bytes for analysis
|
||||
fs.Read(buffer, 0, buffer.Length);
|
||||
|
||||
// Display some basic statistics based on the file type
|
||||
if (item.FileType == "LAND" || item.FileType == "TERR")
|
||||
{
|
||||
Console.WriteLine($" Terrain data with {item.ElementCount} elements");
|
||||
// If element size is known, we can calculate grid dimensions
|
||||
if (item.ElementCount > 0 && item.ElementSize > 0)
|
||||
{
|
||||
// Assuming square terrain, which is common in games from this era
|
||||
var gridSize = Math.Sqrt(item.ElementCount);
|
||||
if (Math.Abs(gridSize - Math.Round(gridSize)) < 0.001) // If it's close to a whole number
|
||||
{
|
||||
Console.WriteLine($" Terrain grid size: {Math.Round(gridSize)} x {Math.Round(gridSize)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item.FileType == "MSH0" || item.FileType == "MESH")
|
||||
{
|
||||
// For mesh data, try to estimate vertex/face counts
|
||||
Console.WriteLine($" Mesh data, possibly with vertices and faces");
|
||||
|
||||
// Common sizes: vertices are often 12 bytes (3 floats), faces are often 12 bytes (3 indices)
|
||||
if (item.ElementSize == 12)
|
||||
{
|
||||
Console.WriteLine($" Possibly {item.ElementCount} vertices or faces");
|
||||
}
|
||||
}
|
||||
|
||||
// Display first few bytes as hex for debugging
|
||||
var hexPreview = BitConverter.ToString(
|
||||
buffer.Take(32)
|
||||
.ToArray()
|
||||
)
|
||||
.Replace("-", " ");
|
||||
Console.WriteLine($" Data preview (hex): {hexPreview}...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a detailed analysis of a landscape mesh file
|
||||
/// </summary>
|
||||
/// <param name="filePath">Path to the MSH file</param>
|
||||
private static void AnalyzeLandscapeMeshFile(string filePath)
|
||||
{
|
||||
Console.WriteLine($"\nDetailed Landscape Analysis for: {Path.GetFileName(filePath)}\n");
|
||||
|
||||
var parseResult = NResParser.ReadFile(filePath);
|
||||
if (parseResult.Error != null || parseResult.Archive == null)
|
||||
{
|
||||
Console.WriteLine($" Error analyzing file: {parseResult.Error}");
|
||||
return;
|
||||
}
|
||||
|
||||
var archive = parseResult.Archive;
|
||||
|
||||
// Based on the Landscape constructor and the file analysis, we can identify specific sections
|
||||
// File types in MSH files appear to be numeric values (01, 02, 03, etc.)
|
||||
|
||||
// First, let's extract all the different data sections
|
||||
var sections = new Dictionary<string, (ListMetadataItem Meta, byte[] Data)>();
|
||||
|
||||
foreach (var item in archive.Files)
|
||||
{
|
||||
using var fs = new FileStream(filePath, FileMode.Open);
|
||||
fs.Seek(item.OffsetInFile, SeekOrigin.Begin);
|
||||
|
||||
var buffer = new byte[item.FileLength];
|
||||
fs.Read(buffer, 0, buffer.Length);
|
||||
|
||||
sections[item.FileType] = (item, buffer);
|
||||
}
|
||||
|
||||
// Now analyze each section based on what we know from the Landscape constructor
|
||||
Console.WriteLine(" Landscape Structure Analysis:");
|
||||
|
||||
// Type 01 appears to be basic landscape information (possibly header/metadata)
|
||||
if (sections.TryGetValue("01 00 00 00", out var section01))
|
||||
{
|
||||
Console.WriteLine($" Section 01: Basic Landscape Info");
|
||||
Console.WriteLine($" Elements: {section01.Meta.ElementCount}, Element Size: {section01.Meta.ElementSize} bytes");
|
||||
Console.WriteLine($" Total Size: {section01.Meta.FileLength} bytes");
|
||||
|
||||
// Try to extract some basic info if the format is as expected
|
||||
if (section01.Meta.ElementSize == 38 && section01.Data.Length >= 38)
|
||||
{
|
||||
// This is speculative based on common terrain formats
|
||||
var width = BitConverter.ToInt32(section01.Data, 0);
|
||||
var height = BitConverter.ToInt32(section01.Data, 4);
|
||||
Console.WriteLine($" Possible Dimensions: {width} x {height}");
|
||||
}
|
||||
}
|
||||
|
||||
// Type 03 appears to be vertex data (based on element size of 12 bytes which is typical for 3D vertices)
|
||||
if (sections.TryGetValue("03 00 00 00", out var section03))
|
||||
{
|
||||
Console.WriteLine($"\n Section 03: Vertex Data");
|
||||
Console.WriteLine($" Vertex Count: {section03.Meta.ElementCount}");
|
||||
Console.WriteLine($" Vertex Size: {section03.Meta.ElementSize} bytes");
|
||||
|
||||
// If we have vertex data in expected format (3 floats per vertex)
|
||||
if (section03.Meta.ElementSize == 12 && section03.Data.Length >= 36)
|
||||
{
|
||||
// Display first 3 vertices as example
|
||||
Console.WriteLine(" Sample Vertices:");
|
||||
for (int i = 0; i < Math.Min(3, section03.Meta.ElementCount); i++)
|
||||
{
|
||||
var offset = i * 12;
|
||||
var x = BitConverter.ToSingle(section03.Data, offset);
|
||||
var y = BitConverter.ToSingle(section03.Data, offset + 4);
|
||||
var z = BitConverter.ToSingle(section03.Data, offset + 8);
|
||||
Console.WriteLine($" Vertex {i}: ({x}, {y}, {z})");
|
||||
}
|
||||
|
||||
// Calculate terrain bounds
|
||||
var minX = float.MaxValue;
|
||||
var minY = float.MaxValue;
|
||||
var minZ = float.MaxValue;
|
||||
var maxX = float.MinValue;
|
||||
var maxY = float.MinValue;
|
||||
var maxZ = float.MinValue;
|
||||
|
||||
for (int i = 0; i < section03.Meta.ElementCount; i++)
|
||||
{
|
||||
var offset = i * 12;
|
||||
if (offset + 12 <= section03.Data.Length)
|
||||
{
|
||||
var x = BitConverter.ToSingle(section03.Data, offset);
|
||||
var y = BitConverter.ToSingle(section03.Data, offset + 4);
|
||||
var z = BitConverter.ToSingle(section03.Data, offset + 8);
|
||||
|
||||
minX = Math.Min(minX, x);
|
||||
minY = Math.Min(minY, y);
|
||||
minZ = Math.Min(minZ, z);
|
||||
maxX = Math.Max(maxX, x);
|
||||
maxY = Math.Max(maxY, y);
|
||||
maxZ = Math.Max(maxZ, z);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(" Terrain Bounds:");
|
||||
Console.WriteLine($" Min: ({minX}, {minY}, {minZ})");
|
||||
Console.WriteLine($" Max: ({maxX}, {maxY}, {maxZ})");
|
||||
Console.WriteLine($" Dimensions: {maxX - minX} x {maxY - minY} x {maxZ - minZ}");
|
||||
}
|
||||
}
|
||||
|
||||
// Type 02 might be face/index data for the mesh
|
||||
if (sections.TryGetValue("02 00 00 00", out var section02))
|
||||
{
|
||||
Console.WriteLine($"\n Section 02: Possible Face/Index Data");
|
||||
Console.WriteLine($" Elements: {section02.Meta.ElementCount}");
|
||||
Console.WriteLine($" Element Size: {section02.Meta.ElementSize} bytes");
|
||||
|
||||
// If element size is divisible by 4 (common for index data)
|
||||
if (section02.Meta.ElementSize % 4 == 0 && section02.Data.Length >= 12)
|
||||
{
|
||||
// Display first triangle as example (assuming 3 indices per triangle)
|
||||
Console.WriteLine(" Sample Indices (if this is index data):");
|
||||
var indicesPerElement = section02.Meta.ElementSize / 4;
|
||||
for (int i = 0; i < Math.Min(1, section02.Meta.ElementCount); i++)
|
||||
{
|
||||
Console.Write($" Element {i}: ");
|
||||
for (int j = 0; j < indicesPerElement; j++)
|
||||
{
|
||||
var offset = i * section02.Meta.ElementSize + j * 4;
|
||||
if (offset + 4 <= section02.Data.Length)
|
||||
{
|
||||
var index = BitConverter.ToInt32(section02.Data, offset);
|
||||
Console.Write($"{index} ");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Types 04, 05, 12, 0E, 0B might be texture coordinates, normals, colors, etc.
|
||||
var otherSections = new[] {"04 00 00 00", "05 00 00 00", "12 00 00 00", "0E 00 00 00", "0B 00 00 00"};
|
||||
foreach (var sectionType in otherSections)
|
||||
{
|
||||
if (sections.TryGetValue(sectionType, out var section))
|
||||
{
|
||||
Console.WriteLine($"\n Section {sectionType.Substring(0, 2)}: Additional Mesh Data");
|
||||
Console.WriteLine($" Elements: {section.Meta.ElementCount}");
|
||||
Console.WriteLine($" Element Size: {section.Meta.ElementSize} bytes");
|
||||
|
||||
// If element size is 4 bytes, it could be color data, texture indices, etc.
|
||||
if (section.Meta.ElementSize == 4 && section.Data.Length >= 12)
|
||||
{
|
||||
Console.WriteLine(" Sample Data (as integers):");
|
||||
for (int i = 0; i < Math.Min(3, section.Meta.ElementCount); i++)
|
||||
{
|
||||
var offset = i * 4;
|
||||
var value = BitConverter.ToInt32(section.Data, offset);
|
||||
Console.WriteLine($" Element {i}: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Type 15 might be material or special data (Msh_15 in the decompiled code)
|
||||
if (sections.TryGetValue("15 00 00 00", out var section15) && sections.TryGetValue("03 00 00 00", out var vertexSection))
|
||||
{
|
||||
Console.WriteLine($"\n Section 15: Special Data (Msh_15 type in decompiled code)");
|
||||
Console.WriteLine($" Elements: {section15.Meta.ElementCount}");
|
||||
Console.WriteLine($" Element Size: {section15.Meta.ElementSize} bytes");
|
||||
|
||||
int count = 0;
|
||||
for (var i = 0; i < section15.Data.Length; i += 28)
|
||||
{
|
||||
var first = BinaryPrimitives.ReadUInt32LittleEndian(section15.Data.AsSpan(i));
|
||||
|
||||
if ((first & 0x20000) != 0)
|
||||
{
|
||||
Console.WriteLine($"Found {first}/0x{first:X8} 0x20000 at index {i / 28}. &0x20000={first&0x20000}/0x{first&0x20000:X8} offset: {i:X8}");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Total found: {count}");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
151
NResLib/NResPacker.cs
Normal file
151
NResLib/NResPacker.cs
Normal file
@ -0,0 +1,151 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace NResLib;
|
||||
|
||||
public class NResPacker
|
||||
{
|
||||
public static string Pack(NResArchive archive, string srcNresPath, string contentDirectoryPath, string targetFileDirectoryPath)
|
||||
{
|
||||
var diskFiles = Directory.GetFiles(contentDirectoryPath)
|
||||
.Select(Path.GetFileName)
|
||||
.ToList();
|
||||
|
||||
var fileOffset = 16; // 16 по умолчанию, т.к. есть заголовок в 16 байт.
|
||||
|
||||
var metadataItems = new List<ListMetadataItem>();
|
||||
|
||||
foreach (var archiveFile in archive.Files)
|
||||
{
|
||||
var extension = Path.GetExtension(archiveFile.FileName);
|
||||
var fileName = Path.GetFileNameWithoutExtension(archiveFile.FileName);
|
||||
|
||||
if (extension == "")
|
||||
{
|
||||
extension = ".bin";
|
||||
}
|
||||
|
||||
var targetFileName = $"{archiveFile.Index}_{archiveFile.FileType}_{fileName}{extension}";
|
||||
|
||||
if (diskFiles.All(x => x != targetFileName))
|
||||
{
|
||||
return $"Не найдён файл {targetFileName}";
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(contentDirectoryPath, targetFileName);
|
||||
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
var newFileLength = (int)fileInfo.Length;
|
||||
|
||||
var listItem = new ListMetadataItem(
|
||||
archiveFile.FileType,
|
||||
archiveFile.ElementCount,
|
||||
archiveFile.Magic1,
|
||||
newFileLength,
|
||||
archiveFile.ElementSize,
|
||||
archiveFile.FileName,
|
||||
archiveFile.Magic3,
|
||||
archiveFile.Magic4,
|
||||
archiveFile.Magic5,
|
||||
archiveFile.Magic6,
|
||||
fileOffset,
|
||||
archiveFile.Index
|
||||
);
|
||||
|
||||
fileOffset += newFileLength;
|
||||
|
||||
metadataItems.Add(listItem);
|
||||
}
|
||||
|
||||
var totalFileLength =
|
||||
16 + // заголовок
|
||||
metadataItems.Sum(x => x.FileLength) + // сумма длин всех файлов
|
||||
metadataItems.Count * 64; // длина всех метаданных
|
||||
|
||||
var header = new NResArchiveHeader(archive.Header.NRes, archive.Header.Version, archive.Header.FileCount, totalFileLength);
|
||||
|
||||
var targetArchive = new NResArchive(header, metadataItems);
|
||||
|
||||
// имя архива = имени папки в которую архив распаковывали
|
||||
string targetArchiveFileName = Path.GetFileName(srcNresPath)!;
|
||||
|
||||
var targetArchivePath = Path.Combine(targetFileDirectoryPath, targetArchiveFileName);
|
||||
|
||||
using var fs = new FileStream(targetArchivePath, FileMode.CreateNew);
|
||||
|
||||
Span<byte> span = stackalloc byte[4];
|
||||
|
||||
span.Clear();
|
||||
Encoding.ASCII.GetBytes(header.NRes, span);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, header.Version);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, header.FileCount);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, header.TotalFileLengthBytes);
|
||||
fs.Write(span);
|
||||
|
||||
foreach (var archiveFile in targetArchive.Files)
|
||||
{
|
||||
var extension = Path.GetExtension(archiveFile.FileName);
|
||||
var fileName = Path.GetFileNameWithoutExtension(archiveFile.FileName);
|
||||
|
||||
if (extension == "")
|
||||
{
|
||||
extension = ".bin";
|
||||
}
|
||||
|
||||
var targetFileName = $"{archiveFile.Index}_{archiveFile.FileType}_{fileName}{extension}";
|
||||
|
||||
var filePath = Path.Combine(contentDirectoryPath, targetFileName);
|
||||
using var srcFs = new FileStream(filePath, FileMode.Open);
|
||||
|
||||
srcFs.CopyTo(fs);
|
||||
}
|
||||
|
||||
Span<byte> fileNameSpan = stackalloc byte[20];
|
||||
|
||||
foreach (var archiveFile in targetArchive.Files)
|
||||
{
|
||||
span.Clear();
|
||||
Encoding.ASCII.GetBytes(archiveFile.FileType, span);
|
||||
fs.Write(span);
|
||||
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(span, archiveFile.ElementCount);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic1);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.FileLength);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.ElementSize);
|
||||
fs.Write(span);
|
||||
|
||||
fileNameSpan.Clear();
|
||||
Encoding.ASCII.GetBytes(archiveFile.FileName, fileNameSpan);
|
||||
fs.Write(fileNameSpan);
|
||||
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic3);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic4);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic5);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic6);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.OffsetInFile);
|
||||
fs.Write(span);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Index);
|
||||
fs.Write(span);
|
||||
}
|
||||
|
||||
fs.Flush();
|
||||
|
||||
return "Запакован архив";
|
||||
}
|
||||
}
|
@ -138,6 +138,34 @@ namespace NResUI.ImGuiUI
|
||||
}
|
||||
}
|
||||
|
||||
if (nResExplorerViewModel.HasFile)
|
||||
{
|
||||
if (ImGui.MenuItem("Запаковать NRes"))
|
||||
{
|
||||
messageBox.Show("Выберите папку с контентом NRES");
|
||||
var contentDirectoryPicker = Dialog.FolderPicker();
|
||||
|
||||
if (contentDirectoryPicker.IsOk)
|
||||
{
|
||||
var contentDirectoryPath = contentDirectoryPicker.Path;
|
||||
|
||||
var targetFileDirectoryPicker = Dialog.FolderPicker();
|
||||
|
||||
if (targetFileDirectoryPicker.IsOk)
|
||||
{
|
||||
var targetFileDirectory = targetFileDirectoryPicker.Path;
|
||||
|
||||
var packResult = NResPacker.Pack(
|
||||
nResExplorerViewModel.Archive!,
|
||||
nResExplorerViewModel.Path!,
|
||||
contentDirectoryPath, targetFileDirectory);
|
||||
|
||||
messageBox.Show(packResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
|
@ -82,8 +82,8 @@ public class NResExplorerPanel : IImGuiPanel
|
||||
);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text(
|
||||
_viewModel.Archive.Files[i]
|
||||
.ElementSize.ToString()
|
||||
"0x" + _viewModel.Archive.Files[i]
|
||||
.ElementSize.ToString("X2")
|
||||
);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text(_viewModel.Archive.Files[i].FileName);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X86Disassembler", "X86Disas
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X86DisassemblerTests", "X86DisassemblerTests\X86DisassemblerTests.csproj", "{D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LandscapeExplorer", "LandscapeExplorer\LandscapeExplorer.csproj", "{2700BD3F-DC67-4B58-8F73-F790AA68E4FE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -94,5 +96,9 @@ Global
|
||||
{D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2700BD3F-DC67-4B58-8F73-F790AA68E4FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2700BD3F-DC67-4B58-8F73-F790AA68E4FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2700BD3F-DC67-4B58-8F73-F790AA68E4FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2700BD3F-DC67-4B58-8F73-F790AA68E4FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -5,16 +5,18 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACsvReader_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Ff7b87edd534764eebf2388a77d49e5cd9c6d49eb6788dca9b1c07d4545412715_003FCsvReader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultTypeConverter_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F64b864a5d465bc24fc4b55e1026aba213beb1733ef631abeca5a9f25357eda_003FDefaultTypeConverter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADisassembler_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa494e0aa381c41ff9484df33e5edb42535e00_003Fd4_003Fad0818f9_003FDisassembler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEncoding_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F1675dc7b710feeeb3e0bc8728be8a947537155c199480fb23b776e81d459_003FEncoding_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFailAsserts_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F807c15a7d8383b1548dff1ae33270e637836659d9caecd676ea6f2c59f1c71a_003FFailAsserts_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGL_002Egen_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F54e6df16dd99323ba9b0682ce5d5dac3648ccd10aafd29d5f3fad52b62bf3f75_003FGL_002Egen_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIAssemblyCode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa494e0aa381c41ff9484df33e5edb42535e00_003F8c_003F9fe9bac2_003FIAssemblyCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMatrix4x4_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fed6aa59cd75423c5b655901d6ec4fb4be48ab669fa6fb01b3a7a7f31be95_003FMatrix4x4_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FLocal_003FSymbols_003Fsrc_003Fdotnet_003Fruntime_003F5535e31a712343a63f5d7d796cd874e563e5ac14_003Fsrc_003Flibraries_003FSystem_002EPrivate_002ECoreLib_003Fsrc_003FSystem_003FMemory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASafeFileHandle_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa03380083db34a2faee436e29e06a72ae8e910_003Fb6_003F67cd826c_003FSafeFileHandle_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASingle_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc99a63bcf3d2a18c20ee19e58ac875ab1edf2a147c8b92ffeed185ab8a44b4_003FSingle_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStringAsserts_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F999ae9cc4ab7b7cfbc5080803e994426e97fd9d87c5b1f44544a799bc114_003FStringAsserts_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003Aud_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa494e0aa381c41ff9484df33e5edb42535e00_003F15_003F87bd9007_003Fud_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003Audis86_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa494e0aa381c41ff9484df33e5edb42535e00_003F95_003F953bbb0f_003Fudis86_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/Environment/Highlighting/HighlightingSourceSnapshotLocation/@EntryValue">C:\Users\Admin\AppData\Local\JetBrains\Rider2024.3\resharper-host\temp\Rider\vAny\CoverageData\_ParkanPlayground.1073341822\Snapshot\snapshot.utdcvr</s:String>
|
||||
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=47ebaefe_002Da806_002D4565_002Dabe7_002D4f14ac675135/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;X86DisassemblerTests&gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||
<Project Location="C:\Projects\CSharp\ParkanPlayground\X86DisassemblerTests" Presentation="&lt;X86DisassemblerTests&gt;" />
|
||||
</SessionState></s:String>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
|
Reference in New Issue
Block a user