Jump to content

Outfit7 starlite engine (pre-2023) 3d models (My Talking Tom 2/My Talking Angela 2 etc)


Recommended Posts

Posted

Nice!

I haven't stopped work completely, but I'm focusing on different mysteries. I did find some files in the asset bundle that describe colorsets. So like you can find strings like 

wardrobe-bottom-basicShorts-turquoise
wardrobe-bottom-basicShorts-lightGreen
wardrobe-bottom-basicShorts-gray
wardrobe-bottom-basicShorts-yellow
wardrobe-bottom-basicShorts-pink

and there are consecutive float values in the same file such as:

FAF9793F 8F8E0E3F FAF9793F 0000803F ➡ 0.9764706, 0.5568628, 0.9764706, 1
F1F0703F ADAC2C3F F1F0703F 0000803F ➡ 0.9411765, 0.6745098, 0.9411765, 1
BDBC3C3F D5D4D43E D4D3533F 0000803F ➡ 0.7372549, 0.41568628, 0.827451, 1

Those specific values are shades of pink, and my guess is that those are the base color, the highlights and the shadows for the "pink" colorset listed above.

Posted (edited)
On 3/21/2025 at 7:00 PM, scratchcat579 said:

note: you forgot to add scale transformations in your blender importer. the format is float time, uint16 track, float16 sx, float 16 sy, float 16 sz.

What do you mean? blender-outfit7-skeleton-converter in the zip i attached has
 

        # scales
        sxs = struct.unpack_from('<ffff', ozz_skeleton, offset)
        sys = struct.unpack_from('<ffff', ozz_skeleton, offset + 16)
        szs = struct.unpack_from('<ffff', ozz_skeleton, offset + 32)
        for i in range(4):
            bind_pose_scales.append(Vector((sxs[i], sys[i], szs[i])))

and blender-outfit7-animation-converter has
 

    for i in range(scale_count):
        time = struct.unpack_from('<f', input_data[offset:offset + 4])[0]
        track = struct.unpack_from('<H', input_data[offset + 4:offset + 6])[0]
        sx = struct.unpack_from('<e', input_data[offset + 6:offset + 8])[0]
        sy = struct.unpack_from('<e', input_data[offset + 8:offset + 10])[0]
        sz = struct.unpack_from('<e', input_data[offset + 10:offset + 12])[0]

edit: And all the animations I have seen seem to work fine. Except for the fact that the animations are in absolute pose space and not relative to the rest pose. (Absolute pose space meaning that the bones must be at the origin of the skeleton, in their default orientation and scale. Or in other words: their transformation matrx must be the identity matrix)

Edited by yarcunham
  • 2 months later...
Posted (edited)

i think why these header and footer exist because of the way Starlite loads assets using a memcpy and pointer fix.

the values i found in the header are here (the vertex information in the header is at the end in the new format for whatever reason):

struct HeaderNew {
    Vec4f boundsPosition @ 0x30; Vec4f boundsSize @ 0x40; 
    u64 bindPosesPtr @ 0x50; u32 numBindPoses @ 0x58; u32 bindPosesExist @ 0x5C;
    u64 boneLengthsPtr @ 0x60; u32 numBoneLengths @ 0x68; u32 boneLengthsExist @ 0x6C;
    u64 boneIDsPtr @ 0x70; u32 numBoneIDs @ 0x78; u32 boneIDsExist @ 0x7C;
    u64 vertexDataPtr @ 0x110; u32 vertexDataLength @ 0x118; u32 vertexDataExist @ 0x11C;
    u64 blendShapesPtr @ 0x80; u32 numBlendShapes @ 0x88; u32 blendShapesExist @ 0x8C;
    u64 indicesPtr @ 0x90; u32 numIndices @ 0x98; u32 indicesExist @ 0x9C;
    u64 unknownDataPtr @ 0xB0; u32 unknownDataCount @ 0xB8; u32 unknownDataExist @ 0xBC;
    u32 vertexStride @ 0xC4;
};

struct Header {
    Vec4f boundsPosition @ 0x30; Vec4f boundsSize @ 0x40;
    u64 bindPosesPtr @ 0x50; u32 numBindPoses @ 0x58; u32 bindPosesExist @ 0x5C;
    u64 boneLengthsPtr @ 0x60; u32 numBoneLengths @ 0x68; u32 boneLengthsExist @ 0x6C;
    u64 boneIDsPtr @ 0x70; u32 numBoneIDs @ 0x78; u32 boneIDsExist @ 0x7C;
    u64 vertexDataPtr @ 0x80; u32 vertexDataLength @ 0x88; u32 vertexDataExist @ 0x8C;
    u64 blendShapesPtr @ 0x90; u32 numBlendShapes @ 0x98; u32 blendShapesExist @ 0x9C;
    u64 indicesPtr @ 0xA0; u32 numIndices @ 0xA8; u32 indicesExist @ 0xAC;
    u64 unknownDataPtr @ 0xB0; u32 unknownDataCount @ 0xB8; u32 unknownDataExist @ 0xBC;
    u32 vertexStride @ 0xC4;
};

i have also attached the imhex scripts to highlight values in a zip.

mesh hexpat.zip

Edited by scratchcat579
grammar fix
  • 3 months later...
  • 3 weeks later...
  • 3 weeks later...
Posted

This is not a complete solution yet, but maybe it will help someone get started. This describes the new structure of the project, bundle and assets files. They all seem to either use LZMA compression or none. This uses the pattern language from ImHex, but I'm sure it's "self documenting" enough that another programmer is able to decode it:

enum Compression: u32 {
    None,
    zStd,
    LZMA,
    Lz4
};

struct lzmaData<auto size> {
    u24 lzma_conf;
    be u24 lzma_dict_size;
    
    u8 data[size-6];
};

struct Chunk {
    u32 uncompressed_size;
    u32 compressed_size;
    u32 hash;
    Compression compression;
    u32 hash2;
    
    match(compression) {
        (Compression::None): u8 data[compressed_size];
        (Compression::LZMA): lzmaData<compressed_size>;
    }
};

struct ProjectHeader {
    char magic[0x04];
    u32 version;
    u32 uncompressed_size_of_file;
    u32 zeros;
};


struct ProjectFile {
    ProjectHeader header;
    Chunk data;
};

// for the .project file:
// ProjectFile project @ 0x00;

// for .bundle and .assets files:
// Chunk chunks[50] @ 0x00; // the number of entries varies

 

  • 2 weeks later...
Posted

So, the project and bundle files contain a bunch of hashes. The engine uses xxhash64 to store references to text strings and just by hashing strings found in the engine binary and also in the decompressed data files, I was able to make reverse mappings for a bunch of them. The algorithm itself is just xxhash64("string"), no seed value. The hex values I got from web pages that let you encode strings as xxhash, such as https://www.coderstool.com/xxh-hash-generator, give the result in the opposite endianness.

So for example the above site gives me 0735c614e52391c9 for the string "root" when the hex sequence in the files is c99123e514c63507

The attachment root.project.string_hashes.zip contains a mapping of strings to hashes I found in the decompressed root.project file.

root.bundle.string_hashes.zip contains the same for the root.bundle file.

You should be able to just copy-paste the hex strings into your favorite hex editor's "find hex value" functionality and find any offsets that refer to a specific string.

Unfortunately this does not completely blow open the file format, but I think it might help at least.

root.project.string_hashes.zip root.bundle.string_hashes.zip

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...