1
0
mirror of synced 2024-11-30 18:24:39 +01:00

More fixes and additions

Archives now use a link list for archive infos and treenodes. Handling replaced treenodes is easier and fixes renaming issues if a file was opened and renamed.
More LM2 archive improvements, with more chunk loading.
This commit is contained in:
KillzXGaming 2019-07-22 15:06:49 -04:00
parent 1059113cee
commit 1429a00178
12 changed files with 539 additions and 192 deletions

Binary file not shown.

View File

@ -5,8 +5,24 @@ using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.IO;
namespace FirstPlugin
namespace FirstPlugin.LuigisMansion.DarkMoon
{
public class ChunkEntry
{
public uint Unknown1;
public uint ChunkOffset;
public DataType ChunkType;
public uint ChunkSubCount;
public uint Unknown3;
}
public class ChunkSubEntry
{
public SubDataType ChunkType;
public uint ChunkSize;
public uint ChunkOffset;
}
//Table consists of 2 chunk entry lists that define how the .data reads sections
public class LM2_ChunkTable
{
@ -18,28 +34,6 @@ namespace FirstPlugin
public List<ChunkEntry> ChunkEntries = new List<ChunkEntry>();
public List<ChunkSubEntry> ChunkSubEntries = new List<ChunkSubEntry>();
public class ChunkEntry
{
public uint Unknown1;
public uint ChunkOffset;
public uint ChunkType;
public uint ChunkSubCount;
public uint Unknown3;
}
public class ChunkSubEntry
{
public uint ChunkSize;
public DataType ChunkType;
public uint Unknown;
}
public enum DataType : uint
{
TextureHeader = 0x0201B501,
TextureData = 0x1701B502,
}
public void Read(FileReader tableReader)
{
tableReader.SetByteOrder(false);
@ -52,8 +46,8 @@ namespace FirstPlugin
entry.Unknown1 = tableReader.ReadUInt32(); //8
entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
entry.ChunkType = tableReader.ReadUInt32(); //The type of chunk. 0x8701B5 for example for texture info
entry.ChunkSubCount = tableReader.ReadUInt32();
entry.ChunkType = tableReader.ReadEnum<DataType>(false); //The type of chunk. 0x8701B5 for example for texture info
entry.ChunkSubCount = tableReader.ReadUInt32(); //Uncertain about this. 2 for textures (info + block). Some sections however use large numbers.
//This increases by 2 each chunk info, however the starting value is not 0
//Note the last entry does not have this
@ -71,9 +65,9 @@ namespace FirstPlugin
while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12)
{
ChunkSubEntry subEntry = new ChunkSubEntry();
subEntry.ChunkType = tableReader.ReadEnum<DataType>(false); //The type of chunk. 0x8701B5 for example for texture info
subEntry.ChunkType = tableReader.ReadEnum<SubDataType>(false); //The type of chunk. 0x8701B5 for example for texture info
subEntry.ChunkSize = tableReader.ReadUInt32();
subEntry.Unknown = tableReader.ReadUInt32();
subEntry.ChunkOffset = tableReader.ReadUInt32();
ChunkSubEntries.Add(subEntry);
}
}

View File

@ -10,7 +10,7 @@ using Toolbox.Library.IO;
using Toolbox.Library.Forms;
using System.Drawing;
namespace FirstPlugin
namespace FirstPlugin.LuigisMansion.DarkMoon
{
//Parse info based on https://github.com/TheFearsomeDzeraora/LM2L
public class LM2_DICT : TreeNodeFile, IFileFormat, IArchiveFile
@ -47,7 +47,7 @@ namespace FirstPlugin
}
}
public List<FileEntry> files = new List<FileEntry>();
public List<ChunkDataEntry> files = new List<ChunkDataEntry>();
public IEnumerable<ArchiveFileInfo> Files => files;
public void ClearFiles() { files.Clear(); }
@ -55,6 +55,23 @@ namespace FirstPlugin
public bool IsCompressed = false;
public LM2_ChunkTable ChunkTable;
public List<FileEntry> fileEntries = new List<FileEntry>();
//The click event will load the viewport and any models found in the file if there are any
public override void OnClick(TreeView treeview)
{
if (modelFolder.Nodes.Count != 0)
{
}
else
{
}
}
TreeNode textureFolder = new TreeNode("Textures");
TreeNode modelFolder = new TreeNode("Models");
public void Load(System.IO.Stream stream)
{
@ -71,23 +88,22 @@ namespace FirstPlugin
reader.SeekBegin(0x2C);
byte[] Unknowns = reader.ReadBytes((int)FileCount);
TreeNode tableNodes = new TreeNode("File Section Entries");
long FileTablePos = reader.Position;
for (int i = 0; i < FileCount; i++)
{
var file = new FileEntry(this);
file.Text = $"entry {i}";
file.Read(reader);
fileEntries.Add(file);
tableNodes.Nodes.Add(file);
//Skip the file table entries as those are not needed to be loaded
if (file.FileType != 0 && i > 1)
{
file.FileName = $"File {i} (FileType: ({file.FileType}) Unknowns: {file.Unknown2} {file.Unknown3})";
files.Add(file);
}
//The first file stores a chunk layout
//The second one seems to be a duplicate?
if (i == 0)
{
using (var tableReader = new FileReader(file.FileData))
using (var tableReader = new FileReader(file.GetData()))
{
ChunkTable = new LM2_ChunkTable();
ChunkTable.Read(tableReader);
@ -97,68 +113,120 @@ namespace FirstPlugin
TreeNode list1 = new TreeNode("Entry List 1");
TreeNode list2 = new TreeNode("Entry List 2 ");
debugFolder.Nodes.Add(tableNodes);
debugFolder.Nodes.Add(list1);
debugFolder.Nodes.Add(list2);
foreach (var chunk in ChunkTable.ChunkEntries)
{
list1.Nodes.Add($"ChunkType {chunk.ChunkType.ToString("X")} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
list1.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
}
foreach (var chunk in ChunkTable.ChunkSubEntries)
{
list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.Unknown}");
list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.ChunkOffset}");
}
}
}
}
//Now go through each file and format and connect the headers and blocks
uint ImageIndex = 0;
//Set an instance of our current data
//Chunks are in order, so you build off of when an instance gets loaded
TexturePOWE currentTexture = new TexturePOWE();
LM2_Model currentModel = new LM2_Model();
List<TexturePOWE> Textures = new List<TexturePOWE>();
//Each part of the file is divided into multiple file/section entries
//The first entry being the chunk table parsed before this
//The second file being a duplicate (sometimes slightly larger than the first)
//The third file stores texture headers, while the fourth one usually has the rest of the main data
//Any additional ones currently are unknown how they work. Some of which have unknown compression aswell
TreeNode textureFolder = new TreeNode("Textures");
byte[] File002Data = fileEntries[2].GetData(); //Get the third file
byte[] File003Data = fileEntries[3].GetData(); //Get the fourth file
for (int i = 0; i < files.Count; i++)
int chunkId = 0;
uint ImageHeaderIndex = 0;
uint modelIndex = 0;
foreach (var chunk in ChunkTable.ChunkSubEntries)
{
if (files[i].FileType == FileEntry.DataType.Texture)
{
if (files[i].Unknown3 == 1) //Info
{
//Read the info
using (var textureReader = new FileReader(files[i].FileData))
{
int headerIndex = 0;
while (!textureReader.EndOfStream && textureReader.ReadUInt32() == TexturePOWE.Identifier)
{
var texture = new TexturePOWE();
texture.ImageKey = "texture";
texture.SelectedImageKey = texture.ImageKey;
texture.Index = ImageIndex;
texture.Read(textureReader);
texture.Text = $"Texture {headerIndex++}";
textureFolder.Nodes.Add(texture);
Textures.Add(texture);
}
}
}
else //Block
{
uint Offset = 0;
foreach (var tex in Textures)
{
if (tex.Index == ImageIndex)
{
tex.ImageData = Utils.SubArray(files[i].FileData, Offset, tex.ImageSize);
}
var chunkEntry = new ChunkDataEntry(this, chunk);
chunkEntry.DataFile = File003Data;
chunkEntry.FileName = $"Chunk {chunk.ChunkType} {chunkId++}";
files.Add(chunkEntry);
Offset += tex.ImageSize;
switch (chunk.ChunkType)
{
case SubDataType.TextureHeader:
chunkEntry.DataFile = File002Data;
//Read the info
using (var textureReader = new FileReader(chunkEntry.FileData))
{
currentTexture = new TexturePOWE();
currentTexture.ImageKey = "texture";
currentTexture.SelectedImageKey = currentTexture.ImageKey;
currentTexture.Index = ImageHeaderIndex;
currentTexture.Read(textureReader);
currentTexture.Text = $"Texture {ImageHeaderIndex}";
textureFolder.Nodes.Add(currentTexture);
ImageHeaderIndex++;
}
ImageIndex++;
}
break;
case SubDataType.TextureData:
currentTexture.ImageData = chunkEntry.FileData;
break;
case SubDataType.ModelStart:
currentModel.ModelInfo = new LM2_ModelInfo();
currentModel.Text = $"Model {modelIndex}";
currentModel.ModelInfo.Data = chunkEntry.FileData;
modelFolder.Nodes.Add(currentModel);
modelIndex++;
break;
case SubDataType.VertexStartPointers:
using (var vtxPtrReader = new FileReader(chunkEntry.FileData))
{
while (!vtxPtrReader.EndOfStream)
currentModel.VertexBufferPointers.Add(vtxPtrReader.ReadUInt32());
}
break;
case SubDataType.SubmeshInfo:
int MeshCount = chunkEntry.FileData.Length / 0x28;
using (var meshReader = new FileReader(chunkEntry.FileData))
{
for (uint i = 0; i < MeshCount; i++)
{
LM2_Mesh mesh = new LM2_Mesh();
mesh.Read(meshReader);
currentModel.Meshes.Add(mesh);
}
}
break;
case SubDataType.ModelTransform:
using (var transformReader = new FileReader(chunkEntry.FileData))
currentModel.Transform = transformReader.ReadMatrix4();
break;
default:
break;
}
}
foreach (LM2_Model model in modelFolder.Nodes)
{
for (int i = 0; i < model.VertexBufferPointers.Count; i++)
{
LM2_Mesh mesh = model.Meshes[i];
RenderableMeshWrapper genericObj = new RenderableMeshWrapper();
genericObj.Mesh = mesh;
genericObj.Text = $"Mesh {i}";
model.Nodes.Add(genericObj);
}
}
if (modelFolder.Nodes.Count > 0)
Nodes.Add(modelFolder);
if (textureFolder.Nodes.Count > 0)
Nodes.Add(textureFolder);
}
@ -184,102 +252,16 @@ namespace FirstPlugin
return false;
}
public class TexturePOWE : STGenericTexture
{
public static readonly uint Identifier = 0xE977D350;
public uint Index { get; set; }
public uint ID { get; set; }
public uint ImageSize { get; set; }
public uint ID2 { get; set; }
public byte[] ImageData { get; set; }
public void Read(FileReader reader)
{
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
ID = reader.ReadUInt32();
ImageSize = reader.ReadUInt32();
ID2 = reader.ReadUInt32();
reader.Seek(0x8);
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.Seek(3);
var numMips = reader.ReadByte();
reader.Seek(0x14);
byte FormatCtr = reader.ReadByte();
reader.Seek(3);
MipCount = 1;
Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr);
}
public override void OnClick(TreeView treeview)
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.LoadProperties(this.GenericProperties);
editor.LoadImage(this);
}
public override bool CanEdit { get; set; } = false;
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
{
throw new NotImplementedException();
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
return ImageData;
}
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.B5G6R5_UNORM,
TEX_FORMAT.R8G8_UNORM,
TEX_FORMAT.B5G5R5A1_UNORM,
TEX_FORMAT.B4G4R4A4_UNORM,
TEX_FORMAT.LA8,
TEX_FORMAT.HIL08,
TEX_FORMAT.L8,
TEX_FORMAT.A8_UNORM,
TEX_FORMAT.LA4,
TEX_FORMAT.A4,
TEX_FORMAT.ETC1_UNORM,
TEX_FORMAT.ETC1_A4,
};
}
}
}
public class FileEntry : ArchiveFileInfo
public class ChunkDataEntry : ArchiveFileInfo
{
public byte[] DataFile;
public LM2_DICT ParentDictionary { get; set; }
public ChunkSubEntry Entry;
public uint Offset;
public uint DecompressedSize;
public uint CompressedSize;
public DataType FileType;
public byte Unknown2;
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
public enum DataType : ushort
public ChunkDataEntry(LM2_DICT dict, ChunkSubEntry entry)
{
Texture = 0x80,
ParentDictionary = dict;
Entry = entry;
}
public override byte[] FileData
@ -291,6 +273,27 @@ namespace FirstPlugin
}
}
private byte[] GetData( )
{
using (var reader = new FileReader(DataFile))
{
reader.SeekBegin(Entry.ChunkOffset);
return reader.ReadBytes((int)Entry.ChunkSize);
}
}
}
public class FileEntry : TreeNodeFile, IContextMenuNode
{
public LM2_DICT ParentDictionary { get; set; }
public uint Offset;
public uint DecompressedSize;
public uint CompressedSize;
public ushort Unknown1;
public byte Unknown2;
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
public FileEntry(LM2_DICT dict)
{
ParentDictionary = dict;
@ -301,7 +304,7 @@ namespace FirstPlugin
Offset = reader.ReadUInt32();
DecompressedSize = reader.ReadUInt32();
CompressedSize = reader.ReadUInt32();
FileType = reader.ReadEnum<DataType>(false);
Unknown1 = reader.ReadUInt16();
Unknown2 = reader.ReadByte();
Unknown3 = reader.ReadByte();
}
@ -319,7 +322,39 @@ namespace FirstPlugin
}
}
private byte[] GetData()
public ToolStripItem[] GetContextMenuItems()
{
List<ToolStripItem> Items = new List<ToolStripItem>();
Items.Add(new STToolStipMenuItem("Export Raw Data", null, Export, Keys.Control | Keys.E));
return Items.ToArray();
}
private void Export(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.FileName = Text;
sfd.Filter = "Raw Data (*.*)|*.*";
if (sfd.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllBytes(sfd.FileName, GetData());
}
}
public override void OnClick(TreeView treeView)
{
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
if (editor == null)
{
editor = new HexEditor();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadData(GetData());
}
public byte[] GetData()
{
byte[] Data = new byte[DecompressedSize];

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FirstPlugin.LuigisMansion.DarkMoon
{
public enum DataType : uint
{
Texture = 0x8701B500,
}
public enum SubDataType : uint
{
ModelStart = 0x1201B006,
SubmeshInfo = 0x1201B003, //Or polygon groups?
VertexStartPointers = 0x1201B004,
ModelTransform = 0x1301B001, //Matrix4x4. 0x40 in size
MeshBuffers = 0x1301B005, //vertex and index buffer
MaterialName = 0x1201B333,
MeshIndexTable = 0x12017105,
MessageData = 0x12027020,
ShaderData = 0x1401B400,
TextureHeader = 0x0201B501,
TextureData = 0x1701B502,
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
using OpenTK;
namespace FirstPlugin.LuigisMansion.DarkMoon
{
public class LM2_Model : TreeNodeCustom
{
public LM2_ModelInfo ModelInfo;
public List<LM2_Mesh> Meshes = new List<LM2_Mesh>();
public List<uint> VertexBufferPointers = new List<uint>();
public Matrix4 Transform { get; set; }
public override void OnClick(TreeView treeView)
{
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
if (editor == null)
{
editor = new STPropertyGrid();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadProperty(this, OnPropertyChanged);
}
public void OnPropertyChanged() { }
}
public class LM2_ModelInfo
{
public byte[] Data;
}
public class RenderableMeshWrapper : STGenericObject
{
public LM2_Mesh Mesh { get; set; }
public override void OnClick(TreeView treeView)
{
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
if (editor == null)
{
editor = new STPropertyGrid();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadProperty(Mesh, OnPropertyChanged);
}
public void OnPropertyChanged() { }
}
public class LM2_IndexList
{
public short[] UnknownIndices { get; set; }
public uint Unknown { get; set; }
public short[] UnknownIndices2 { get; set; }
public uint[] Unknown2 { get; set; }
public void Read(FileReader reader)
{
UnknownIndices = reader.ReadInt16s(4);
Unknown = reader.ReadUInt32();
UnknownIndices2 = reader.ReadInt16s(8);
Unknown2 = reader.ReadUInt32s(6); //Increases by 32 each entry
}
}
public class LM2_Mesh
{
public uint IndexStartOffset { get; private set; } //relative to buffer start
public ushort IndexCount { get; private set; } //divide by 3 to get face count
public ushort IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte
public ushort BufferStride { get; private set; }
public ushort Unknown { get; private set; }
public ushort Unknown2 { get; private set; }
public ulong DataFormat { get; private set; }
public uint Unknown4 { get; private set; }
public uint Unknown5 { get; private set; }
public uint Unknown6 { get; private set; }
public ushort VertexCount { get; private set; }
public ushort Unknown7 { get; private set; }
public uint HashID { get; private set; }
public void Read(FileReader reader)
{
IndexStartOffset = reader.ReadUInt32();
IndexCount = reader.ReadUInt16();
IndexFormat = reader.ReadUInt16();
BufferStride = reader.ReadUInt16();
Unknown = reader.ReadUInt16();
Unknown2 = reader.ReadUInt16();
DataFormat = reader.ReadUInt64();
Unknown4 = reader.ReadUInt32();
Unknown5 = reader.ReadUInt32();
Unknown6 = reader.ReadUInt32();
VertexCount = reader.ReadUInt16();
Unknown7 = reader.ReadUInt16(); //0x100
HashID = reader.ReadUInt32(); //0x100
}
public class FormatInfo
{
}
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Threading.Tasks;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
using System.Windows.Forms;
namespace FirstPlugin.LuigisMansion.DarkMoon
{
public class TexturePOWE : STGenericTexture
{
public static readonly uint Identifier = 0xE977D350;
public uint Index { get; set; }
public uint ID { get; set; }
public uint ImageSize { get; set; }
public uint ID2 { get; set; }
public byte[] ImageData { get; set; }
public void Read(FileReader reader)
{
//Magic and ID not pointed to for sub entries so just skip them for now
// uint magic = reader.ReadUInt32();
// if (magic != Identifier)
// throw new Exception($"Invalid texture header magic! Expected {Identifier.ToString("x")}. Got {Identifier.ToString("x")}");
// ID = reader.ReadUInt32();
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
ImageSize = reader.ReadUInt32();
ID2 = reader.ReadUInt32();
reader.Seek(0x8);
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.Seek(3);
var numMips = reader.ReadByte();
reader.Seek(0x14);
byte FormatCtr = reader.ReadByte();
reader.Seek(3);
MipCount = 1;
Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr);
}
public override void OnClick(TreeView treeview)
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.LoadProperties(this.GenericProperties);
editor.LoadImage(this);
}
public override bool CanEdit { get; set; } = false;
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
{
throw new NotImplementedException();
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
return ImageData;
}
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.B5G6R5_UNORM,
TEX_FORMAT.R8G8_UNORM,
TEX_FORMAT.B5G5R5A1_UNORM,
TEX_FORMAT.B4G4R4A4_UNORM,
TEX_FORMAT.LA8,
TEX_FORMAT.HIL08,
TEX_FORMAT.L8,
TEX_FORMAT.A8_UNORM,
TEX_FORMAT.LA4,
TEX_FORMAT.A4,
TEX_FORMAT.ETC1_UNORM,
TEX_FORMAT.ETC1_A4,
};
}
}
}
}

View File

@ -206,6 +206,9 @@
<Compile Include="FileFormats\Archives\IGA_PAK.cs" />
<Compile Include="FileFormats\Archives\LM2\LM2_ChunkTable.cs" />
<Compile Include="FileFormats\Archives\LM2\LM2_DICT.cs" />
<Compile Include="FileFormats\Archives\LM2\LM2_Enums.cs" />
<Compile Include="FileFormats\Archives\LM2\LM2_Model.cs" />
<Compile Include="FileFormats\Archives\LM2\TexturePOWE.cs" />
<Compile Include="FileFormats\Archives\LZARC.cs" />
<Compile Include="FileFormats\Archives\ME01.cs" />
<Compile Include="FileFormats\Archives\MKGPDX_PAC.cs" />

View File

@ -7,6 +7,7 @@ using Toolbox.Library;
using Toolbox.Library.Forms;
using Toolbox.Library.IO;
using FirstPlugin.Forms;
using FirstPlugin.LuigisMansion.DarkMoon;
namespace FirstPlugin
{

View File

@ -540,8 +540,8 @@ namespace Toolbox.Library.Forms
private void treeViewCustom1_DragOver(object sender, DragEventArgs e)
{
var file = GetActiveArchive();
if (file == null || !file.CanReplaceFiles)
var root = GetActiveArchive();
if (root == null || !root.ArchiveFile.CanReplaceFiles)
return;
Point pt = treeViewCustom1.PointToClient(new Point(e.X, e.Y));
@ -557,10 +557,15 @@ namespace Toolbox.Library.Forms
// e.Effect = DragDropEffects.None;
}
private IArchiveFile GetActiveArchive()
private ArchiveRootNodeWrapper GetActiveArchive()
{
if (treeViewCustom1.SelectedNode != null && treeViewCustom1.SelectedNode is ArchiveBase)
return ((ArchiveBase)treeViewCustom1.SelectedNode).ArchiveFile;
var node = treeViewCustom1.SelectedNode;
if (node != null && node is ArchiveRootNodeWrapper)
return (ArchiveRootNodeWrapper)node;
if (node != null && node is ArchiveFileWrapper)
return ((ArchiveFileWrapper)node).RootNode;
if (node != null && node is ArchiveFolderNodeWrapper)
return ((ArchiveFolderNodeWrapper)node).RootNode;
return null;
}

View File

@ -183,13 +183,15 @@ namespace Toolbox.Library
}
public static void AddFiles(TreeNode parentNode, IArchiveFile archiveFile, string[] Files)
public static void AddFiles(TreeNode parentNode, ArchiveRootNodeWrapper rootNode, string[] Files)
{
var archiveFile = rootNode.ArchiveFile;
if (Files == null || Files.Length <= 0 || !archiveFile.CanAddFiles) return;
for (int i = 0; i < Files.Length; i++)
{
var File = ArchiveFileWrapper.FromPath(Files[i], archiveFile);
var File = ArchiveFileWrapper.FromPath(Files[i], rootNode);
string FileName = Path.GetFileName(Files[i]);
//Don't add the root file name
@ -209,9 +211,9 @@ namespace Toolbox.Library
if (HasAddedFile)
{
if (parentNode is ArchiveRootNodeWrapper)
((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File);
((ArchiveRootNodeWrapper)parentNode).AddFileNode(File);
if (parentNode is ArchiveFolderNodeWrapper)
((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File);
((ArchiveRootNodeWrapper)parentNode).AddFileNode(File);
parentNode.Nodes.Add(File);
}

View File

@ -147,6 +147,50 @@ namespace Toolbox.Library.IO
return new Syroot.IOExtension.Half(ReadUInt16());
}
public Matrix4 ReadMatrix4(bool SwapRows = false)
{
Matrix4 mat4 = new Matrix4();
if (SwapRows)
{
mat4.M11 = ReadSingle();
mat4.M21 = ReadSingle();
mat4.M31 = ReadSingle();
mat4.M41 = ReadSingle();
mat4.M12 = ReadSingle();
mat4.M22 = ReadSingle();
mat4.M32 = ReadSingle();
mat4.M42 = ReadSingle();
mat4.M13 = ReadSingle();
mat4.M23 = ReadSingle();
mat4.M33 = ReadSingle();
mat4.M43 = ReadSingle();
mat4.M14 = ReadSingle();
mat4.M24 = ReadSingle();
mat4.M34 = ReadSingle();
mat4.M44 = ReadSingle();
}
else
{
mat4.M11 = ReadSingle();
mat4.M12 = ReadSingle();
mat4.M13 = ReadSingle();
mat4.M14 = ReadSingle();
mat4.M21 = ReadSingle();
mat4.M22 = ReadSingle();
mat4.M23 = ReadSingle();
mat4.M24 = ReadSingle();
mat4.M31 = ReadSingle();
mat4.M32 = ReadSingle();
mat4.M33 = ReadSingle();
mat4.M34 = ReadSingle();
mat4.M41 = ReadSingle();
mat4.M42 = ReadSingle();
mat4.M43 = ReadSingle();
mat4.M44 = ReadSingle();
}
return mat4;
}
public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); }
public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); }
public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); }

View File

@ -183,7 +183,8 @@ namespace Toolbox.Library
//Wrapper for the archive file itself
public class ArchiveRootNodeWrapper : ArchiveBase, IContextMenuNode
{
public List<ArchiveFileWrapper> FileNodes = new List<ArchiveFileWrapper>();
//A list that links archive file infos to treenodes of varying types
public List<Tuple<ArchiveFileInfo, TreeNode>> FileNodes = new List<Tuple<ArchiveFileInfo, TreeNode>>();
public virtual object PropertyDisplay { get; set; }
@ -195,6 +196,11 @@ namespace Toolbox.Library
PropertyDisplay = new GenericArchiveProperties(archiveFile, text);
}
public void AddFileNode(ArchiveFileWrapper fileWrapper)
{
FileNodes.Add(Tuple.Create(fileWrapper.ArchiveFileInfo, (TreeNode)fileWrapper));
}
public ToolStripItem[] GetContextMenuItems()
{
var ToolStrips = new ToolStripItem[]
@ -232,7 +238,7 @@ namespace Toolbox.Library
if (ofd.ShowDialog() == DialogResult.OK)
{
TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames);
TreeHelper.AddFiles(this, this, ofd.FileNames);
}
}
@ -242,7 +248,9 @@ namespace Toolbox.Library
return;
for (int i = 0; i < FileNodes.Count; i++)
FileNodes[i].ArchiveFileInfo.FileName = SetFullPath(FileNodes[i], this);
{
FileNodes[i].Item1.FileName = SetFullPath(FileNodes[i].Item2, this);
}
}
private static string SetFullPath(TreeNode node, TreeNode root)
@ -411,7 +419,7 @@ namespace Toolbox.Library
}
else if (node is ArchiveFileInfo)
{
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, archiveFile);
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, this);
wrapperFile.Name = node.Name;
parent.Nodes.Add(wrapperFile);
}
@ -468,11 +476,11 @@ namespace Toolbox.Library
if (rootIndex == roots.Length - 1)
{
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, archiveFile);
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, this);
wrapperFile.Name = nodeName;
parentNode.Nodes.Add(wrapperFile);
parentNode = wrapperFile;
FileNodes.Add(wrapperFile);
AddFileNode(wrapperFile);
}
else
{
@ -557,7 +565,7 @@ namespace Toolbox.Library
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK) {
TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames);
TreeHelper.AddFiles(this, RootNode, ofd.FileNames);
}
}
@ -618,11 +626,14 @@ namespace Toolbox.Library
//Wrapper for files
public class ArchiveFileWrapper : ArchiveBase, IContextMenuNode
{
public ArchiveRootNodeWrapper RootNode;
public virtual ArchiveFileInfo ArchiveFileInfo { get; set; }
public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, IArchiveFile archiveFile) : base(archiveFile)
public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, ArchiveRootNodeWrapper rootNode) : base(rootNode.ArchiveFile)
{
Text = text;
RootNode = rootNode;
// ReloadMenus(archiveFile);
ArchiveFileInfo = archiveFileInfo;
@ -705,12 +716,12 @@ namespace Toolbox.Library
else return "";
}
public static ArchiveFileWrapper FromPath(string FilePath, IArchiveFile archiveFile)
public static ArchiveFileWrapper FromPath(string FilePath, ArchiveRootNodeWrapper rootNode)
{
var ArchiveFileInfo = new ArchiveFileInfo();
ArchiveFileInfo.FileName = FilePath;
ArchiveFileInfo.FileData = File.ReadAllBytes(FilePath);
return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, archiveFile);
return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, rootNode);
}
public ToolStripItem[] GetContextMenuItems()
@ -781,12 +792,12 @@ namespace Toolbox.Library
OpenFormDialog(file);
}
else if (file is TreeNode)
ReplaceNode(this.Parent, this, (TreeNode)file);
ReplaceNode(this.Parent, this, (TreeNode)file, RootNode);
else if (file is IArchiveFile)
{
var FileRoot = new ArchiveRootNodeWrapper(file.FileName, (IArchiveFile)file);
FileRoot.FillTreeNodes();
ReplaceNode(this.Parent, this, FileRoot);
ReplaceNode(this.Parent, this, FileRoot, RootNode);
}
}
@ -847,15 +858,20 @@ namespace Toolbox.Library
editor.UpdateEditor();
}
public static void ReplaceNode(TreeNode node, TreeNode replaceNode, TreeNode NewNode)
public static void ReplaceNode(TreeNode node, ArchiveFileWrapper replaceNode, TreeNode NewNode, ArchiveRootNodeWrapper rootNode)
{
if (NewNode == null)
return;
var fileInfo = replaceNode.ArchiveFileInfo;
int index = node.Nodes.IndexOf(replaceNode);
node.Nodes.RemoveAt(index);
node.Nodes.Insert(index, NewNode);
rootNode.FileNodes.RemoveAt(index);
rootNode.FileNodes.Insert(index, Tuple.Create(fileInfo, NewNode));
NewNode.ImageKey = replaceNode.ImageKey;
NewNode.SelectedImageKey = replaceNode.SelectedImageKey;
NewNode.Text = replaceNode.Text;