1
0
mirror of synced 2024-12-11 15:25:59 +01:00
Switch-Toolbox/File_Format_Library/FileFormats/DKCTF/PAK.cs

277 lines
9.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Toolbox.Library;
using Toolbox.Library.IO;
using System.IO;
namespace DKCTF
{
public class PAK : TreeNodeFile, IArchiveFile, IFileFormat, ILeaveOpenOnLoad
{
public FileType FileType { get; set; } = FileType.Layout;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "DKCTF Archive" };
public string[] Extension { get; set; } = new string[] { "*.pak" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool CanAddFiles { get; set; }
public bool CanRenameFiles { get; set; }
public bool CanReplaceFiles { get; set; }
public bool CanDeleteFiles { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
bool IsForm = reader.CheckSignature(4, "RFRM");
bool FormType = reader.CheckSignature(4, "PACK", 20);
return IsForm && FormType;
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public List<FileEntry> files = new List<FileEntry>();
public IEnumerable<ArchiveFileInfo> Files => files;
public void ClearFiles() { files.Clear(); }
//For file searching
public Dictionary<string, FileEntry> ModelFiles = new Dictionary<string, FileEntry>();
public Dictionary<string, FileEntry> SkeletonFiles = new Dictionary<string, FileEntry>();
public Dictionary<string, FileEntry> TextureFiles = new Dictionary<string, FileEntry>();
public Dictionary<string, CHAR> CharFiles = new Dictionary<string, CHAR>();
public Dictionary<string, FileEntry> AnimFiles = new Dictionary<string, FileEntry>();
public PACK PakData;
internal bool IsMPR;
public void Load(System.IO.Stream stream)
{
PACK pack = new PACK(stream);
PakData = pack;
for (int i = 0; i < pack.Assets.Count; i++)
{
string ext = pack.Assets[i].Type.ToLower();
FileEntry file = new FileEntry();
file.ParentArchive = this;
file.ArchiveStream = stream;
file.AssetEntry = pack.Assets[i];
string dir = pack.Assets[i].Type;
if (DirectoryLabels.ContainsKey(dir))
dir = DirectoryLabels[dir];
file.FileName = $"{dir}/{pack.Assets[i].FileID}.{ext}";
file.SubData = new SubStream(stream, pack.Assets[i].Offset, pack.Assets[i].Size);
if (pack.MetaOffsets.ContainsKey(pack.Assets[i].FileID.ToString()))
file.MetaPointer = pack.MetaDataOffset + pack.MetaOffsets[pack.Assets[i].FileID.ToString()];
files.Add(file);
switch (file.AssetEntry.Type)
{
case "SMDL": ModelFiles.Add(file.AssetEntry.FileID.ToString(), file); break;
case "TXTR": TextureFiles.Add(file.AssetEntry.FileID.ToString(), file); break;
case "SKEL": SkeletonFiles.Add(file.AssetEntry.FileID.ToString(), file); break;
case "ANIM": AnimFiles.Add(file.AssetEntry.FileID.ToString(), file); break;
case "CHAR":
var c = new CHAR(new MemoryStream(file.FileData));
file.FileName = $"Characters/{c.Name}/{c.Name}.char";
CharFiles.Add(file.AssetEntry.FileID.ToString(), c);
break;
}
}
foreach (var c in CharFiles)
{
if (SkeletonFiles.ContainsKey(c.Value.SkeletonFileID.ToString()))
SkeletonFiles[c.Value.SkeletonFileID.ToString()].FileName = $"Characters/{c.Value.Name}/Models/{c.Value.SkeletonFileID}.skel";
foreach (var m in c.Value.Models)
{
if (ModelFiles.ContainsKey(m.FileID.ToString()))
ModelFiles[m.FileID.ToString()].FileName = $"Characters/{c.Value.Name}/Models/{m.Name}.smdl";
}
foreach (var m in c.Value.Animations)
{
if (AnimFiles.ContainsKey(m.FileID.ToString()))
AnimFiles[m.FileID.ToString()].FileName = $"Characters/{c.Value.Name}/Animations/{m.Name}.anim";
}
}
foreach (var file in files)
{
if (PakFileList.GuiToFilePath.ContainsKey(file.AssetEntry.FileID.ToString()))
{
file.FileName = "_LabeledFiles/" + PakFileList.GuiToFilePath[file.AssetEntry.FileID.ToString()];
//Organize the data type folders for easier access.
if (file.AssetEntry.Type == "SMDL") file.FileName = file.FileName.Replace("exportData", "models");
if (file.AssetEntry.Type == "CMDL") file.FileName = file.FileName.Replace("exportData", "models");
if (file.AssetEntry.Type == "TXTR") file.FileName = file.FileName.Replace("exportData", "textures");
if (file.AssetEntry.Type == "ANIM") file.FileName = file.FileName.Replace("exportData", "animations");
}
}
// files = files.OrderBy(x => x.FileName).ToList();
}
Dictionary<string, string> DirectoryLabels = new Dictionary<string, string>()
{
{ "CHAR", "Characters" },
{ "CHPR", "Character Project" },
{ "CMDL", "Static Models" },
{ "SMDL", "Skinned Models" },
{ "TXTR", "Textures" },
{ "MTRL", "Shaders" },
{ "CSMP", "AudioSample" },
{ "CAUD", "AudioData" },
{ "GENP", "Gpsys" },
{ "ANIM", "Animations" },
{ "XFRM", "Xfpsys" },
{ "WMDL", "World Models" },
{ "DCLN", "Collision Models" },
{ "CLSN", "Collision Static Models" },
};
public void Unload()
{
}
public void Save(System.IO.Stream stream)
{
}
public bool AddFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
}
public class FileEntry : ArchiveFileInfo
{
public PACK.DirectoryAssetEntry AssetEntry;
public PAK ParentArchive;
public long MetaPointer;
public Stream SubData;
public Stream ArchiveStream;
public override byte[] FileData
{
get
{
List<byte[]> Data = new List<byte[]>();
using (var reader = new FileReader(SubData, true))
{
var data = reader.ReadBytes((int)reader.BaseStream.Length);
reader.Position = 0;
if (AssetEntry.DecompressedSize != AssetEntry.Size)
data = IOFileExtension.DecompressedBuffer(reader, (uint)AssetEntry.Size, (uint)AssetEntry.DecompressedSize, true);
Data.Add(data);
if (WriteMetaData)
{
using (var r = new FileReader(ArchiveStream, true)) {
r.SetByteOrder(!ParentArchive.PakData.IsLittleEndian);
Data.Add(FileForm.WriteMetaFooter(r, (uint)MetaPointer, AssetEntry.Type, ParentArchive.PakData));
}
}
}
if (AssetEntry.Type == "TXTR")
{
var txt = new TXTR();
return txt.CreateUncompressedFile(Utils.CombineByteArray(Data.ToArray()), ParentArchive.PakData.FileHeader, ParentArchive.PakData.IsMPR);
}
return Utils.CombineByteArray(Data.ToArray());
}
}
public bool WriteMetaData
{
get
{
switch (AssetEntry.Type)
{
case "CMDL":
case "SMDL":
case "WMDL":
case "TXTR":
return true;
default:
return false;
}
}
}
public override IFileFormat OpenFile()
{
var pak = this.ParentArchive;
var file = base.OpenFile();
if (file is CModel)
{
((CModel)file).LoadTextures(pak.TextureFiles);
FileEntry GetSkeleton()
{
foreach (var c in pak.CharFiles)
{
foreach (var m in c.Value.Models)
{
if (AssetEntry.FileID.ToString() == m.FileID.ToString())
return pak.SkeletonFiles[c.Value.SkeletonFileID.ToString()];
}
}
return null;
}
var skelFile = GetSkeleton();
if (skelFile != null)
{
var skel = new SKEL(new MemoryStream(skelFile.FileData));
((CModel)file).LoadSkeleton(skel);
}
}
if (file is CCharacter)
((CCharacter)file).LoadModels(pak);
this.FileFormat = file;
return file;
}
}
}