Markemp / Cryengine-Converter

A c# program to convert Crytek files to Collada (XML) format
https://www.heffaypresents.com/GitHub/
GNU General Public License v2.0
208 stars 53 forks source link

ChunkMtlName_804 #165

Open giniedp opened 9 months ago

giniedp commented 9 months ago

I'm hitting some chunk materials with version 804 which is currently not implemented. Some time ago i simply added the following which solved the issue at the time being.

internal sealed class ChunkMtlName_804 : ChunkMtlName
{
    public override void Read(BinaryReader b)
    {
        base.Read(b);

        Name = b.ReadFString(128);
        NumChildren = 0;
    }
}

now, the game client has changed and this does not work any more. At least on some models. I am not sure how to proceed or decode the chunk structure. This is what i've got so far

Chunk Metadata

{
  type: 3435921428, // 0xCCCC0014 -> MtlName
  version: 2052, // 0x804
  id: 2,
  size: 78,
  offset: 528
}

The byte content is

Int8Array(78) [
  123,  56,  53,  67,  67, 50, 52, 67, 69, 45, 68, 52,
   49,  53,  45,  53,  50, 67, 66, 45, 66, 53, 57, 48,
   45,  69,  66,  68,  56, 67, 57, 57, 52, 65, 48, 52,
   50, 125,   0,   0,   0,  0,  0,  0,  0,  0,  0,  0,
    0,   0,   0,   0,   0,  0,  0,  0,  0,  0,  0,  0,
    0,   0,   0,   0,   1,  0,  0,  0, -1, -1, -1, -1,
   99, 104, 101, 115, 116,  0
]

The first part is some UUID in curly braces: {85CC24CE-D415-52CB-B590-EBD8C994A042} The middle part i can not digest The last part is the actual material name: chest

Any chance this can be properly decoded?

i will try to collect all models with that chunk format to find a solid pattern

Markemp commented 9 months ago

Which game is this for? And are there other mtlname chunks in the file?

giniedp commented 9 months ago

The game is "New World" There are no other mtlname chunks, however, there are lots of "UnknownSC1" chunks

I am seeing some success with following

internal sealed class ChunkMtlName_804 : ChunkMtlName
{
    public override void Read(BinaryReader b)
    {
        base.Read(b);

        SkipBytes(b, 38); // contains some ID e.g.: {85CC24CE-D415-52CB-B590-EBD8C994A042}
        SkipBytes(b, 26); // usually empty bytes
        // some count followed by 3 emtpy bytes 
        var count = b.ReadByte();
        SkipBytes(b, 3);

        // skip some flags
        SkipBytes(b, count * 4);

        Name = b.ReadCString();
        NumChildren = 0;
    }
}
giniedp commented 9 months ago

Ok, I think I can see what is happening.

First I have to note, that the result of ChunkMtlName is not needed for my workflow. I have a patch where i can tell cgf-converter which material file to use. However, cgf-converter still needs to read all the chunks and my addition of ChunkMtlName_804 (https://github.com/Markemp/Cryengine-Converter/issues/165#issue-1847945664) was sufficient.

The error I encountered today was the following

The output char buffer is too small to contain the decoded characters, encoding 'Unicode (UTF-8)' fallback 'System.Text.DecoderReplacementFallback'. (Parameter 'chars') This made me look into the chunk format.

All ChunkMtlName_804 chunks had the following structure

ID_STRING     // e.g. {33099872-8B47-513B-9EE5-49CEDEBD603A}
UNKNOWN       // varying length
MATERIAL_NAME

So I thought that the MATERIAL_NAME was the section i was looking for

However, when I check all the ChunkMtlName_800 chunks, I see the following structure

MATERIAL_FILE_NAME // e.g. male_femininelacelt2_forearms_matgroup
UNKNOWN            // varying length
MATERIAL_NAME      // e.g. male_FeminineLaceLT2_00_forearms

So the ID_STRING in the 804 version seems to be an asset ID. This may be either something New World or chunk version specific. For me, I can fix this with:

internal sealed class ChunkMtlName_804 : ChunkMtlName
{
    public override void Read(BinaryReader b)
    {
        base.Read(b);
-        Name = b.ReadFString(128);
+        Name = b.ReadCString(0);
        NumChildren = 0;
    }
}
Markemp commented 5 months ago

Does New World use both 0x0800 and 0x0804 MtlName chunks?

giniedp commented 5 months ago

there was a time they used both. I think its the latter for all assets now.

Markemp commented 5 months ago

Ish, if they modified the 0x0800 MtlName format, that's going to cause a lot of problems. Those models may only work with the mtl file provided as an argument. I suspect you'd be ok with that though? The material in each submesh is referenced by the index they are found in the mtl file, so as long as the converter doesn't blow up on reading the file, it should still be able to use the correct material.

That work for you?

giniedp commented 5 months ago

yeah, for NW i have no other choice as to pass in the material. So not blowing up on reading would be the only thing i actually need here, thx.