Skip to content

Commit a2ba2e1

Browse files
committed
Refpack compression (from S3PI)
1 parent 2921795 commit a2ba2e1

8 files changed

Lines changed: 920 additions & 73 deletions

File tree

MorcuTool/MorcuTool.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<Compile Include="src\FileTypes\Model\DAEModel.cs" />
5353
<Compile Include="src\FileTypes\Model\RevoModel.cs" />
5454
<Compile Include="src\FileTypes\Generic\XML.cs" />
55+
<Compile Include="src\FileTypes\Subfiles\MsaAnimation.cs" />
5556
<Compile Include="src\FileTypes\Subfiles\HavokShapes\havokObject.cs" />
5657
<Compile Include="src\FileTypes\Subfiles\HavokShapes\hkArray.cs" />
5758
<Compile Include="src\FileTypes\Subfiles\HavokShapes\hkSimpleMeshShapeTriangle.cs" />

MorcuTool/global.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public enum TypeID : uint
4040
BUILDABLEREGION_MSA = 0x41C4A8EF,
4141
BUILDABLEREGION_MSK = 0xC84ACD30,
4242
LLMF_MSK = 0x58969018, //"LevelData"
43-
LLMF_MSA = 0xA5DCD485,
43+
LLMF_MSA = 0xA5DCD485, //(FNV-1 32bit hash of "level")
4444
RIG_MSK = 0x8EAF13DE, //"RigData" based on granny3D seemingly
4545
RIG_MSA = 0x4672E5BD, //Interesting granny struct info at 0x49CFDD in MSA's main.dol
4646
ANIMCLIP_MSK =0x6B20C4F3, //"ClipData"

MorcuTool/src/FileTypes/Package.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,9 +1037,8 @@ public void RebuildPackage()
10371037
if (subfiles[f].should_be_compressed_when_in_package)
10381038
{
10391039
if (subfiles[f].has_been_decompressed) //if it was decompressed by the user then compress it
1040-
{
1041-
MessageBox.Show("Because you modified a compressed file, it needs to be recompressed. This feature is currently not implemented! The package saving will therefore fail.");
1042-
subfiles[f].filebytes = Utility.Compress_QFS(filebytes);
1040+
{
1041+
subfiles[f].filebytes = Utility.Compress_QFS(subfiles[f].filebytes);
10431042
}
10441043
}
10451044

@@ -1053,10 +1052,10 @@ public void RebuildPackage()
10531052
else //if it was modified or read, use the bytes from its filebytes array
10541053
{
10551054
subfiles[f].filesize = (uint)subfiles[f].filebytes.Length;
1055+
Console.WriteLine("LENGTH BEING ADDED IS: "+subfiles[f].filesize);
10561056
for (int i = 0; i < subfiles[f].filebytes.Length; i++)
10571057
{
10581058
output.Add(subfiles[f].filebytes[i]);
1059-
MessageBox.Show("Need to ensure that the file is compressed if it needs to be");
10601059
}
10611060
}
10621061

@@ -1107,16 +1106,14 @@ public void RebuildPackage()
11071106

11081107
}
11091108

1110-
File.WriteAllBytes("test.package", output.ToArray());
1111-
}
1112-
1113-
1114-
1115-
1116-
1117-
1118-
1109+
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
1110+
saveFileDialog1.Title = "Save new package";
1111+
saveFileDialog1.Filter = ".package files (*.package)|*.package";
11191112

1113+
if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
1114+
File.WriteAllBytes(saveFileDialog1.FileName, output.ToArray());
1115+
}
1116+
}
11201117
}
11211118

11221119
public class IndexEntry
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace MorcuTool
8+
{
9+
public class MsaAnimation
10+
{
11+
12+
public class Table1Entry { //setting table 1's count to 1 turns the animation into a T-pose in-game
13+
14+
public uint unk1; //start frame, possibly?
15+
public uint unk2; //flags? padding? usually 0
16+
public uint unk3; //u32 end of this frame's data, relative to the unknown section offset. The start of the frame's data is the end of the previous one (or from the unknown section offset if it's the first frame)
17+
18+
public Table1Entry(byte[] filebytes, int offset) {
19+
unk1 = Utility.ReadUInt32BigEndian(filebytes, offset);
20+
unk2 = Utility.ReadUInt32BigEndian(filebytes, offset+4);
21+
unk3 = Utility.ReadUInt32BigEndian(filebytes, offset+8);
22+
}
23+
}
24+
25+
public class Table2Entry //setting table 2's count to 1 doesn't seem to change anything in-game
26+
{
27+
public uint unk1; // u32 flags? padding? usually 0x00000001
28+
public uint unk2; // u32 offset to something (relative to unknown section 1)
29+
public uint unk3; // u32 usually 0 ?
30+
public uint unk4; // u32 offset to float data for bone movement
31+
32+
public Table2Entry(byte[] filebytes, int offset) {
33+
34+
unk1 = Utility.ReadUInt32BigEndian(filebytes, offset);
35+
unk2 = Utility.ReadUInt32BigEndian(filebytes, offset + 4);
36+
unk3 = Utility.ReadUInt32BigEndian(filebytes, offset + 8);
37+
unk4 = Utility.ReadUInt32BigEndian(filebytes, offset + 12);
38+
}
39+
}
40+
41+
public class BoneTableEntry
42+
{
43+
public uint unk1;
44+
public uint unk2;
45+
public uint unk3;
46+
public uint boneNameHash;
47+
public uint unk4; //usually 1?
48+
public uint unk5;
49+
public uint unk6;
50+
public uint unk7;
51+
52+
public BoneTableEntry(byte[] filebytes, int offset)
53+
{
54+
unk1 = Utility.ReadUInt32BigEndian(filebytes, offset);
55+
unk2 = Utility.ReadUInt32BigEndian(filebytes, offset+4);
56+
unk3 = Utility.ReadUInt32BigEndian(filebytes, offset+8);
57+
boneNameHash = Utility.ReadUInt32BigEndian(filebytes, offset+12);
58+
unk4 = Utility.ReadUInt32BigEndian(filebytes, offset+16);
59+
unk5 = Utility.ReadUInt32BigEndian(filebytes, offset+20);
60+
unk6 = Utility.ReadUInt32BigEndian(filebytes, offset+24);
61+
unk7 = Utility.ReadUInt32BigEndian(filebytes, offset+28);
62+
Console.WriteLine("Found bone: " + boneNameHash);
63+
}
64+
}
65+
66+
public uint dataSectionOffset;
67+
public uint boneTableRelativeOffset;
68+
public uint firstTableOffset;
69+
public uint firstTableCount;
70+
public uint secondTableOffset;
71+
public uint secondTableCount;
72+
73+
public List<Table1Entry> table1 = new List<Table1Entry>();
74+
public List<Table2Entry> table2 = new List<Table2Entry>();
75+
public List<BoneTableEntry> boneTable = new List<BoneTableEntry>();
76+
77+
public MsaAnimation(Subfile basis) {
78+
79+
dataSectionOffset = Utility.ReadUInt32BigEndian(basis.filebytes,0x6C);
80+
boneTableRelativeOffset = Utility.ReadUInt32BigEndian(basis.filebytes, 0x40);
81+
82+
firstTableOffset = Utility.ReadUInt32BigEndian(basis.filebytes, 0x84);
83+
firstTableCount = Utility.ReadUInt32BigEndian(basis.filebytes, 0x88);
84+
secondTableOffset = Utility.ReadUInt32BigEndian(basis.filebytes, 0x8C);
85+
secondTableCount = Utility.ReadUInt32BigEndian(basis.filebytes, 0x90);
86+
87+
for (int i = 0; i < firstTableCount; i++){
88+
table1.Add(new Table1Entry(basis.filebytes, (int)(firstTableOffset + (i * 0x0C))));
89+
}
90+
91+
for (int i = 0; i < secondTableCount; i++){
92+
table2.Add(new Table2Entry(basis.filebytes, (int)(secondTableOffset + (i * 0x0C))));
93+
}
94+
95+
uint boneTableCount = Utility.ReadUInt32BigEndian(basis.filebytes, (int)(dataSectionOffset + boneTableRelativeOffset + 0x80));
96+
97+
for (int i = 0; i < boneTableCount; i++) {
98+
boneTable.Add(new BoneTableEntry(basis.filebytes, (int)(dataSectionOffset + boneTableRelativeOffset + 0xF0 + (i * 0x20))));
99+
}
100+
}
101+
}
102+
}

MorcuTool/src/FileTypes/Subfiles/Subfile.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class Subfile
3939
public MaterialSet mtst; //if needed
4040
public MaterialData matd; //if needed
4141
public TPLtexture tpl; //if needed
42+
public MsaAnimation msaAnim; //if needed
4243

4344
public void Load()
4445
{
@@ -85,6 +86,9 @@ public void Load()
8586
case global.TypeID.TPL_MSA:
8687
tpl = new TPLtexture(this);
8788
break;
89+
case global.TypeID.ANIMCLIP_MSA:
90+
msaAnim = new MsaAnimation(this);
91+
break;
8892
}
8993
}
9094
}

MorcuTool/src/Forms/Form1.Designer.cs

Lines changed: 34 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MorcuTool/src/Forms/Form1.cs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ public partial class Form1 : Form
1919
public Dictionary<TreeNode, Subfile> treeNodesAndSubfiles = new Dictionary<TreeNode, Subfile>();
2020

2121

22+
//bone names that have had their FNV-1 32bit hashes identified in model/animation files
23+
public string[] commonBoneNames = new string[] { "pelvis", "root", "spine0","spine1","spine2", "neck", "head", "l_ankle","r_ankle"};
24+
2225
public Form1()
2326
{
2427
InitializeComponent();
@@ -540,7 +543,7 @@ private void decompressQFSToolStripMenuItem_Click_1(object sender, EventArgs e)
540543
{
541544
foreach (string filename in openFileDialog2.FileNames)
542545
{
543-
File.WriteAllBytes(filename+"decomp" , Utility.Decompress_QFS(File.ReadAllBytes(filename)).ToArray());
546+
File.WriteAllBytes(filename+"_decomp" , Utility.Decompress_QFS(File.ReadAllBytes(filename)).ToArray());
544547
}
545548
}
546549
}
@@ -753,12 +756,7 @@ private void hashLabel_Click(object sender, EventArgs e)
753756

754757
}
755758

756-
private void backtrackToModel_Click(object sender, EventArgs e)
757-
{
758-
Subfile s = treeNodesAndSubfiles[FileTree.SelectedNode];
759-
s.Load();
760-
backtrackSubfile(s);
761-
}
759+
762760

763761
public void backtrackSubfile(Subfile s) {
764762

@@ -869,5 +867,47 @@ public void backtrackSubfile(Subfile s) {
869867
}
870868

871869
}
870+
871+
private void compressToQFSToolStripMenuItem_Click(object sender, EventArgs e)
872+
{
873+
OpenFileDialog openFileDialog2 = new OpenFileDialog();
874+
875+
openFileDialog2.Title = "Select file to QFS compress";
876+
openFileDialog2.CheckFileExists = true;
877+
openFileDialog2.CheckPathExists = true;
878+
879+
if (openFileDialog2.ShowDialog() == DialogResult.OK)
880+
{
881+
foreach (string filename in openFileDialog2.FileNames)
882+
{
883+
File.WriteAllBytes(filename + "_comp", Utility.Compress_QFS(File.ReadAllBytes(filename)));
884+
}
885+
}
886+
}
887+
888+
private void backtrackToModelToolStripMenuItem_Click(object sender, EventArgs e)
889+
{
890+
Subfile s = treeNodesAndSubfiles[FileTree.SelectedNode];
891+
s.Load();
892+
backtrackSubfile(s);
893+
}
894+
895+
private void replaceToolStripMenuItem_Click(object sender, EventArgs e)
896+
{
897+
OpenFileDialog openFileDialog1 = new OpenFileDialog();
898+
899+
Subfile s = treeNodesAndSubfiles[FileTree.SelectedNode];
900+
s.Load();
901+
902+
openFileDialog1.Title = "Replace "+ s.filename;
903+
openFileDialog1.Filter = "All files (*.*)|*.*";
904+
openFileDialog1.CheckFileExists = true;
905+
openFileDialog1.CheckPathExists = true;
906+
907+
if (openFileDialog1.ShowDialog() == DialogResult.OK)
908+
{
909+
s.filebytes = File.ReadAllBytes(openFileDialog1.FileName);
910+
}
911+
}
872912
}
873913
}

0 commit comments

Comments
 (0)