Search Results

  1. root670
    From what I've seen it goes something like this:

    Let x = 7th section offset in ARD file's header.
    Goto offset x.
    Let y = 2nd offset from section beginning at x.
    Goto beginning of ARD file.

    So x+y would give you an offset to a table of strings. This seems to be the pattern in several files, but I might be wrong.
    Post by: root670, Jul 3, 2013 in forum: Code Vault
  2. root670
    Awesome, now the real translating side of things can happen :).

    Found a bug in your ARDread program, though. As a test, I used dh01.ard (which contains text from the first cut scene in the game, including "So much to do," and "so little time..." in the English version). It extracts 3 text files containing 4, 0, and 99 strings each. For the second one (0 strings), it gives a red error instructing me to submit the name ;)
    This was the output when using the Final Mix version ARD, but the same error occurs with the US version at different offsets. It didn't extract the area of the file that contained "So much to do," in the US version (which is in the section beginning at 0x3ED80 in dh01.ard, the 7th offset in the initial header). I belive this bad entry resulted in the <1KB file named "dh01.ard-1.txt"

    How are you determining if an ARD section contains strings? I noticed when I try to extract strings from another ARD (di01.ard, containing first Destiny Islands cut scene), the cut scene strings are again found in the 7th section of the ard (err, pointed to by the 7th offset in the begging of the file), but this time your tool successfully extracts the strings to di01.ard-1.txt.

    I think the cutscene text from dh01.ard is supposed to be extracted to dh01.ard-1.txt, but your error catching routine discards it as bad data. Oddly, the part that contains the strings in dh01 does in fact end with the "Obtained Postcard." line.
    Post by: root670, Jul 3, 2013 in forum: Code Vault
  3. root670
    Yes, in the OP. Gummy HP code in under "HP MODS" and all the rest you'd want are in the attachment
    Post by: root670, Jul 2, 2013 in forum: Code Vault
  4. root670
    Great work, as always! If I wasn't so bogged down with school and work, I'd have time to look at how text is stored in other files (like the ARD files and evm). I think I said something about this in an earlier post, but ARD files seem to be a collection of assets for various levels/rooms in the game. Most of them begin with 3D meshes for interactive (non-static) objects, like doors/crates/etc. There're strings near the end too that are used in the level, seems to include captions for NPC speech bubbles as well as cut scene subtitles.
    Post by: root670, Jun 26, 2013 in forum: Code Vault
  5. root670
    Ahh, I knew it :/. Well, good things take time
    Post by: root670, Jun 23, 2013 in forum: Kingdom Hearts News & Updates
  6. root670
    I've always heard that SM Coder used AR2 encrypted codes, but maybe I'm wrong. I converted the codes to AR2 for you using Omniconvert 1.1.1, see if these do the trick:

    kingdom hearts 2 final mix.
    (M) master code :
    CB6+/Gs3+/Xp4+
    BCA70B09 14265F05
    409BA208 1456E7A5

    Inf MP In Battle (Pyriels Code Ported)
    1C9B8228 90D3E5CD
    1C9B822C 90D5E621
    1C9B8230 1433D7A0
    1C9B8234 0C58698D
    1C9B8238 B0D4E625
    Post by: root670, May 26, 2013 in forum: Code Vault
  7. root670
    Try this one: http://kh-vids.net/threads/kingdom-hearts-ii-final-mix-codes.117695/page-66#post-4063896
    Post by: root670, May 25, 2013 in forum: Code Vault
  8. root670
    Here's a code that will switch the X and O buttons, made with PS2 Controller Remapper. I didn't have a chance to test it, but it should work fine:
    Code:
    202f5e7c 0803f408
    200fd020 00a0782d
    200fd024 24020334
    200fd028 080bd7a1
    202f5f44 0803f40b
    200fd02c 3c08000f
    200fd030 3508d000
    200fd034 8de90000
    200fd038 ad090000
    200fd03c 8de90004
    200fd040 ad090004
    200fd044 8de90008
    200fd048 ad090008
    200fd04c 8de9000c
    200fd050 ad09000c
    200fd054 8de90010
    200fd058 ad090010
    200fd05c 81e9000c
    200fd060 a109000b
    200fd064 2d2a0080
    200fd068 85090000
    200fd06c 11400002
    200fd070 3129dfff
    200fd074 35292000
    200fd078 a5090000
    200fd07c 81e9000b
    200fd080 a109000c
    200fd084 2d2a0080
    200fd088 85090000
    200fd08c 11400002
    200fd090 3129bfff
    200fd094 35294000
    200fd098 a5090000
    200fd09c 8d090000
    200fd0a0 ade90000
    200fd0a4 8d090004
    200fd0a8 ade90004
    200fd0ac 8d090008
    200fd0b0 ade90008
    200fd0b4 8d09000c
    200fd0b8 ade9000c
    200fd0bc 8d090010
    200fd0c0 ade90010
    200fd0c4 03e00008
    200fd0c8 00000000
    
    Post by: root670, May 25, 2013 in forum: Code Vault
  9. root670
    Using the recently released "PS2 Controller Remapper", I was able to generate a code to swap the X and O buttons, so the game plays more like the NTSC/PAL versions
    Code:
    20268cec 0803f408
    200fd020 00a0782d
    200fd024 24020330
    200fd028 0809a33d
    20268db4 0803f40b
    200fd02c 3c08000f
    200fd030 3508d000
    200fd034 8de90000
    200fd038 ad090000
    200fd03c 8de90004
    200fd040 ad090004
    200fd044 8de90008
    200fd048 ad090008
    200fd04c 8de9000c
    200fd050 ad09000c
    200fd054 8de90010
    200fd058 ad090010
    200fd05c 81e9000c
    200fd060 a109000b
    200fd064 2d2a0080
    200fd068 85090000
    200fd06c 11400002
    200fd070 3129dfff
    200fd074 35292000
    200fd078 a5090000
    200fd07c 81e9000b
    200fd080 a109000c
    200fd084 2d2a0080
    200fd088 85090000
    200fd08c 11400002
    200fd090 3129bfff
    200fd094 35294000
    200fd098 a5090000
    200fd09c 8d090000
    200fd0a0 ade90000
    200fd0a4 8d090004
    200fd0a8 ade90004
    200fd0ac 8d090008
    200fd0b0 ade90008
    200fd0b4 8d09000c
    200fd0b8 ade9000c
    200fd0bc 8d090010
    200fd0c0 ade90010
    200fd0c4 03e00008
    200fd0c8 00000000
    
    Post by: root670, May 24, 2013 in forum: Code Vault
  10. root670
    For a look at how 3D models and textures are stored, take a look at the source for the Noesis KH plugin. The textures in particular aren't your typical TIM2 images; they use their own format. Here's a link to the plugin w/ the source included: http://oasis.xentax.com/files/plug/kingdom_hearts.zip. Below is the meat of the plugin
    Code:
    //this is kind of a poor example for plugins, since the format's not totally known and the code is WIP.
    //but it does showcase some interesting usages.
     
    #include "stdafx.h"
     
    mathImpFn_t *g_mfn = NULL;
    noePluginFn_t *g_nfn = NULL;
     
    #pragma pack(push, 1)
     
    typedef  unsigned char    uint8;
    typedef  unsigned short  uint16;
    typedef  unsigned long    uint32;
    typedef  unsigned __int64 uint64;
    typedef  signed  char    int8;
    typedef  signed  short  int16;
    typedef  signed  long    int32;
    typedef  signed  __int64 int64;
     
    struct MDLS_MOBJ_HEADER
    {
    // 0x00
    uint32 dataTag; // 'MOBJ'
    uint32 dataSize;
    uint32 imageInfoOffset;
    uint32 imageInfoSize;
    // 0x10
    uint32 imageOffset;
    uint32 imageSize;
    uint32 clutOffset;
    uint32 clutSize;
    // 0x20
    uint32 meshDataOffset;
    uint32 meshDataSize;
    uint32 unknownOffset0x28;
    uint32 unknownSize0x2C;
    // 0x30
    uint32 unknown0x30;
    uint32 unknown0x34[3];
    };
     
    struct MDLS_IMAGE_INFO
    {
    uint16 dataSize; // image data size / 16
    uint8  w_exp;    // width exponent (2^w)
    uint8  h_exp;    // height exponent (2^h)
    uint16 width;
    uint16 height;
    uint32 unknown0x0C[2];
    };
     
    struct MDLS_MODEL_HEADER
    {
    // 0x00
    uint32 jointCount;
    uint32 jointDataOffset;
    uint32 unknownOffset0x08;
    uint32 meshCount;
    };
     
    struct MDLS_JOINT_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 jointIndex;
    uint32 tableIndex;
    uint32 unknown0x0C;
    // 0x10
    uint32 unknown0x10[28];
    };
     
    struct MDLS_MESH_ENTRY
    {
    uint32 unknown0x00; // unk, object id, unk, unk
    uint32 unknown0x04; // texture index
    uint32 unknown0x08; // texture index
    uint32 dataOffset;
    };
     
    struct MDLS_VERTEX
    {
    // 0x00
    float  normal[3];
    uint32 jointIndex;
    // 0x10
    float  position[3];
    float  jointWeight;
    // 0x20
    float  textureCoord[3];
    uint32 unknown0x2C; // ?
    };
     
    struct MDLS_VERTEX_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 dataSize;
    uint32 vertexCount0;
    uint32 unknown0x0C;
    // 0x10
    uint32 vertexCount1;
    uint32 unknown0x14;
    uint32 unknown0x18;
    uint32 unknown0x1C;
    // 0x20
    //struct MDLS_VERTEX vertices[vertexCount0];
    };
     
    struct MDLS_MODEL_JOINT
    {
    float  scale[3];
    uint32 index;
     
    float  rotation[3];
    uint32 padding;
     
    float  position[3];
    int32  parent  : 10;
    int32  sibling : 10;
    int32  child  : 10;
    int32  unk1    :  2;
    };
     
    struct MDLS_MATRIX_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 dataSize;
    uint32 lineCount;
    uint32 unknown0x0C;
    // 0x10
    uint32 matrixIndices[1];
    };
     
    #pragma pack(pop)
     
    //see if something is valid KH .mdls data
    bool Model_KH_Check(BYTE *fileBuffer, int bufferLen, noeRAPI_t *rapi)
    {
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + 8))
    {
    return false;
    }
     
    // read mobj data offset
    uint32 mobjOffset = *((uint32*)(fileBuffer + 4));
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + mobjOffset))
    {
    return false;
    }
     
    uint8 *mobjData = (fileBuffer + mobjOffset);
     
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(mobjData);
     
    if (mobjHeader->dataTag != 0x4A424F4D)
    {
    return false;
    }
     
    if ((bufferLen < (mobjHeader->dataSize + mobjOffset)) ||
    (mobjHeader->imageInfoOffset > 0 && bufferLen < (mobjHeader->imageInfoOffset + mobjOffset)) ||
    (mobjHeader->imageOffset    > 0 && bufferLen < (mobjHeader->imageOffset    + mobjOffset)) ||
    (mobjHeader->clutOffset      > 0 && bufferLen < (mobjHeader->clutOffset      + mobjOffset)) ||
    (mobjHeader->meshDataOffset  > 0 && bufferLen < (mobjHeader->meshDataOffset  + mobjOffset)))
    {
    return false;
    }
     
    return true;
    }
     
    //load texture bundle
    static void Model_KH_LoadTextures(CArrayList<noesisTex_t *> &textures, CArrayList<noesisMaterial_t *> &materials, BYTE *data, int dataSize, noeRAPI_t *rapi)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    char matName[128] = {0};
     
    noesisTex_t *nt = NULL;
    noesisMaterial_t *nmat = NULL;
     
    // calculate texture count
    int textureCount = mobjHeader->imageInfoSize >> 4;
    if (textureCount > 0)
    {
    // calculate image data offsets
    uint8 *imageInfo = (data + mobjHeader->imageInfoOffset);
    uint8 *imageData = (data + mobjHeader->imageOffset);
    uint8 *clutData  = (data + mobjHeader->clutOffset);
     
    // read texture information
    int texNum = 0;
    for (texNum = 0; texNum < textureCount; ++texNum, imageInfo += sizeof(MDLS_IMAGE_INFO), clutData  += 0x400)
    {
    MDLS_IMAGE_INFO &info = *((MDLS_IMAGE_INFO*)imageInfo);
     
    int imageSize = (info.dataSize << 4);
     
    uint8 *tempImage = (uint8 *)rapi->Noesis_UnpooledAlloc(info.width * info.height * 4);
    uint8 *dstPixel = tempImage;
     
    int pixelNum = 0;
    for (pixelNum = 0; pixelNum < imageSize; ++pixelNum, ++imageData, dstPixel += 4)
    {
    uint32 pixelIndex = *imageData;
     
    if ((pixelIndex & 31) >= 8)
    {
    if ((pixelIndex & 31) < 16)
    {
    pixelIndex += 8; // +8 - 15 to +16 - 23
    }
    else if ((pixelIndex & 31) < 24)
    {
    pixelIndex -= 8; // +16 - 23 to +8 - 15
    }
    }
     
    pixelIndex <<= 2;
     
    dstPixel[0] =  clutData[pixelIndex + 0];
    dstPixel[1] =  clutData[pixelIndex + 1];
    dstPixel[2] =  clutData[pixelIndex + 2];
    dstPixel[3] = (clutData[pixelIndex + 3] * 0xFF) >> 7;
    }
     
    // create texture
    sprintf_s(matName, 128, "texture%03d", texNum);
    nt = rapi->Noesis_TextureAlloc(matName, info.width, info.height, tempImage, NOESISTEX_RGBA32);
    nt->shouldFreeData = true;
    textures.Append(nt);
     
    sprintf_s(matName, 128, "material%03d", texNum);
    nmat = rapi->Noesis_GetMaterialList(1, true);
    nmat->name = rapi->Noesis_PooledString(matName);
    nmat->noDefaultBlend = false;
    nmat->noLighting = true;
    nmat->texIdx = texNum;
    materials.Append(nmat);
    }
    }
    }
     
    #define PI (3.1415926535897932384626433832795)
    #define DEG2RAD(a) ((a) * PI / 180.0)
    #define RAD2DEG(a) ((a) * 180.0 / PI)
     
    //convert the bones
    modelBone_t *Model_KH_CreateBones(BYTE *data, noeRAPI_t *rapi, int &numBones)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    uint8 *modelData = (data + mobjHeader->meshDataOffset);
     
    MDLS_MODEL_HEADER *modelHeader = (MDLS_MODEL_HEADER*)modelData;
     
    numBones = 0;
     
    if (modelHeader->jointCount > 0)
    {
    uint8 *jointData = (modelData + modelHeader->jointDataOffset);
     
    // save joint count...
    numBones = modelHeader->jointCount;
    // ...and allocate joint data
    modelBone_t *bones = rapi->Noesis_AllocBones(numBones);
    modelBone_t *bone = bones;
     
    modelMatrix_t sclMatrix = g_identityMatrix;
    modelMatrix_t xMatrix = g_identityMatrix;
    modelMatrix_t yMatrix = g_identityMatrix;
    modelMatrix_t zMatrix = g_identityMatrix;
    modelMatrix_t rotMatrix = g_identityMatrix;
     
    MDLS_MODEL_JOINT *joint = (MDLS_MODEL_JOINT*)jointData;
     
    int jointNum = 0;
    for (jointNum = 0; jointNum < numBones; ++jointNum, ++joint, ++bone)
    {
    bone->index = jointNum;
    sprintf_s(bone->name, 30, "bone%03i", jointNum);
     
    // copy joint information
    sclMatrix.x1[0] = joint->scale[0];
    sclMatrix.x2[1] = joint->scale[1];
    sclMatrix.x3[2] = joint->scale[2];
     
    rotMatrix = g_identityMatrix;
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG(-joint->rotation[2]), 0, 0, 1);
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG( joint->rotation[1]), 0, 1, 0);
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG(-joint->rotation[0]), 1, 0, 0);
    g_mfn->Math_MatrixMultiply(&sclMatrix, &rotMatrix, &bone->mat);
    // g_mfn->Math_RotationMatrix( joint->rotation[0], 0, &xMatrix);
    // g_mfn->Math_RotationMatrix(-joint->rotation[1], 1, &yMatrix);
    // g_mfn->Math_RotationMatrix( joint->rotation[2], 2, &zMatrix);
    // g_mfn->Math_MatrixMultiply(&zMatrix,  &yMatrix,  &rotMatrix);
    // g_mfn->Math_MatrixMultiply(&rotMatrix, &xMatrix,  &zMatrix);
    // g_mfn->Math_MatrixMultiply(&zMatrix,  &sclMatrix, &bone->mat);
     
    g_mfn->Math_VecCopy(joint->position, bone->mat.o);
     
    bone->eData.parent = (joint->parent < 0) ? NULL : (bones + joint->parent);
    }
     
    // transform bones
    rapi->rpgMultiplyBones(bones, numBones);
    return bones;
    }
     
    return NULL;
    }
     
    //load a single model from a dat set
    static void Model_KH_LoadModel(BYTE* data, CArrayList<noesisTex_t *> &textures, CArrayList<noesisMaterial_t *> &materials, modelBone_t *bones, int numBones, noeRAPI_t *rapi)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    uint8 *modelData = (data + mobjHeader->meshDataOffset);
     
    MDLS_MODEL_HEADER *modelHeader = (MDLS_MODEL_HEADER*)modelData;
     
    // process mesh information
    if (modelHeader->meshCount > 0)
    {
    uint8 *meshInfo = (modelData + 0x10);
     
    MDLS_MESH_ENTRY *meshEntries = (MDLS_MESH_ENTRY*)meshInfo;
     
    int meshCount = modelHeader->meshCount;
     
    char meshName[128] = {0};
    int meshCnt = 0;
     
    int meshNum = 0;
    for (meshNum = 0; meshNum < meshCount; ++meshNum, ++meshEntries)
    {
    rapi->rpgSetMaterialIndex(meshEntries->unknown0x04);
     
    uint8 *meshStart = (meshInfo + meshEntries->dataOffset);
     
    uint32 vertexCount = 0;
    uint32 faceCount = 0;
     
    MDLS_MATRIX_BLOCK *matrixPalette = NULL;
    uint32 matrixIndices[16] = {0};
     
    uint32 tableSize = 0;
    uint32 extraMax = 0;
    uint32 extraCount = 0;
    uint32 nextOffset = 0;
    do
    {
    uint32 dataTag = *((uint32*)meshStart);
    switch (dataTag)
    {
    case 0:
    {
    uint32 jointIndex  = *((uint32*)(meshStart + 0x04));
    uint32 tableIndex0 = *((uint32*)(meshStart + 0x08));
    uint32 tableIndex1 = *((uint32*)(meshStart + 0x0C));
     
    if (tableIndex1 == 0)
    {
    matrixIndices[tableIndex0] = jointIndex;
    }
     
    if (tableIndex1 > 0)
    {
    if (tableIndex1 == 1)
    tableSize = 0;
    matrixIndices[tableSize + 8] = jointIndex;
    ++tableSize;
    }
     
    nextOffset = 0x80;
    }
    break;
    case 1:
    {
    nextOffset = *((uint32*)(meshStart + 4));
     
    MDLS_VERTEX_BLOCK *vertexBlock = (MDLS_VERTEX_BLOCK*)meshStart;
     
    if (vertexBlock->dataSize > 0 && vertexBlock->vertexCount0 > 0)
    {
    uint8 *vertexStart = (meshStart + 0x20);
     
    CArrayList<modelVert_t> vertices;
    CArrayList<modelVert_t> normals;
    CArrayList<modelTexCoord_t> texCoords;
     
    uint32 numVertices = vertexBlock->vertexCount0;
    uint32 vertexNum = 0;
    rapi->rpgBegin(RPGEO_TRIANGLE_STRIP);
    for (vertexNum = 0; vertexNum < numVertices; ++vertexNum)
    {
    uint32 jointInfo = *((uint32*)(vertexStart + 0x0C));
    uint32 jointIndex = 0;
    uint32 positionCount = 1;
     
    uint8 *normalStart = vertexStart;
    vertexStart += 0x10;
     
    uint8 *positionStart = vertexStart;
    if (matrixPalette)
    {
    positionCount = jointInfo;
    vertexStart += 0x10 * jointInfo;
    }
    else
    {
    vertexStart += 0x10;
    }
     
    uint8 *uvStart = vertexStart;
    vertexStart += 0x10;
     
    CArrayList<DWORD> boneIndices;
    CArrayList<float> boneWeights;
     
    uint32 posNum = 0;
    float position[4] = {0};
    float temp[4] = {0};
    modelBone_t *bone = NULL;
    fourxMatrix_t jointMatrix = g_identityMatrix4x4;
    fourxMatrix_t vertexMatrix = g_identityMatrix4x4;
    fourxMatrix_t outputMatrix = g_identityMatrix4x4;
    for (posNum = 0; posNum < positionCount; ++posNum, ++extraCount)
    {
    if (matrixPalette)
    {
    jointIndex = matrixPalette->matrixIndices[extraCount];
    if (jointIndex < 0x100)
    jointIndex = matrixIndices[jointIndex];
    else
    {
    jointIndex = ((jointIndex & 0xFF) >> 3);
    matrixIndices[2] = matrixIndices[jointIndex + 8];
    jointIndex = matrixIndices[2];
    }
    }
    else
    {
    jointIndex = matrixIndices[jointInfo];
    }
    bone = bones + jointIndex;
    memcpy(vertexMatrix.c4, (float*)positionStart, sizeof(vertexMatrix.c4));
    g_mfn->Math_ModelMatToGL(&bone->mat, (float*)(&jointMatrix));
    g_mfn->Math_MatrixMultiply4x4(&vertexMatrix, &jointMatrix, &outputMatrix);
    g_mfn->Math_VecAdd(outputMatrix.c4, position, position);
     
    boneIndices.Append(jointIndex);
    boneWeights.Append(vertexMatrix.c4[3]);
     
    positionStart += 0x10;
    }
    normals.Append(*((modelVert_t*)normalStart));
    texCoords.Append(*((modelTexCoord_t*)uvStart));
    vertices.Append(*((modelVert_t*)position));
    if (vertexNum == 0 &&
    vertexBlock->unknown0x0C != 0)
    {
    rapi->rpgVertBoneIndexUI(&boneIndices[0], boneIndices.Num());
    rapi->rpgVertBoneWeightF(&boneWeights[0], boneWeights.Num());
    rapi->rpgVertNormal3f((float*)normalStart);
    rapi->rpgVertUV2f((float*)uvStart, 0);
    rapi->rpgVertex3f((float*)position);
    }
    rapi->rpgVertBoneIndexUI(&boneIndices[0], boneIndices.Num());
    rapi->rpgVertBoneWeightF(&boneWeights[0], boneWeights.Num());
    rapi->rpgVertNormal3f((float*)normalStart);
    rapi->rpgVertUV2f((float*)uvStart, 0);
    rapi->rpgVertex3f((float*)position);
    }
    rapi->rpgEnd();
    }
    }
    break;
    case 2:
    {
    matrixPalette = (MDLS_MATRIX_BLOCK*)meshStart;
    extraCount = 0;
    extraMax = matrixPalette->lineCount * 4;
     
    nextOffset = matrixPalette->dataSize;
    }
    break;
    case 0x8000:
    {
    nextOffset = *((uint32*)(meshStart + 4));
    }
    break;
    default:
    {
    nextOffset = 0;
    }
    break;
    }
    meshStart += nextOffset;
    } while (nextOffset > 0);
    }
    }
    }
     
    //load it
    noesisModel_t *Model_KH_Load(BYTE *fileBuffer, int bufferLen, int &numMdl, noeRAPI_t *rapi)
    {
    numMdl = 0;
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + 8))
    {
    return NULL;
    }
     
    // read mobj data offset
    uint32 mobjOffset = *((uint32*)(fileBuffer + 4));
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + mobjOffset))
    {
    return NULL;
    }
     
    uint8 *mobjData = (fileBuffer + mobjOffset);
     
    CArrayList<noesisTex_t *> textures;
    CArrayList<noesisMaterial_t *> materials;
     
    // attempt to load textures
    Model_KH_LoadTextures(textures, materials, mobjData, bufferLen, rapi);
     
    int numBones = 0;
    modelBone_t *bones = NULL;
    // process joint data
    bones = Model_KH_CreateBones(mobjData, rapi, numBones);
     
    void *pgctx = rapi->rpgCreateContext();
    rapi->rpgSetEndian(false);
    rapi->rpgSetTriWinding(false);
     
    noesisMatData_t *md = rapi->Noesis_GetMatDataFromLists(materials, textures);
    rapi->rpgSetExData_Materials(md);
    rapi->rpgSetExData_Bones(bones, numBones);
     
    CArrayList<noesisModel_t *> models;
    Model_KH_LoadModel(mobjData, textures, materials, bones, numBones, rapi);
     
    #if 0 //create a procedural anim to move random bones around
    if (bones)
    {
    const int numMoveBones = 1 + rand()%(numBones-1);
    sharedPAnimParm_t *aparms = (sharedPAnimParm_t *)_alloca(sizeof(sharedPAnimParm_t)*numMoveBones);
    memset(aparms, 0, sizeof(aparms)); //it's a good idea to do this, in case future noesis versions add more meaningful fields.
    for (int i = 0; i < numMoveBones; i++)
    {
    aparms[i].angAmt = 25.0f;
    aparms[i].axis = 1; //rotate left and right
    aparms[i].boneIdx = rand()%numBones; //random bone
    aparms[i].timeScale = 0.1f; //acts as a framestep
    }
    noesisAnim_t *anim = rapi->rpgCreateProceduralAnim(bones, numBones, aparms, numMoveBones, 500);
    if (anim)
    {
    rapi->rpgSetExData_AnimsNum(anim, 1);
    }
    }
    #endif
     
    noesisModel_t *mdl = rapi->rpgConstructModel();
    if (!mdl)
    {
    //nothing could be created
    return NULL;
    }
     
    models.Append(mdl);
    rapi->rpgDestroyContext(pgctx);
     
    materials.Clear();
     
    if (models.Num() <= 0)
    {
    return NULL;
    }
     
    numMdl = models.Num();
     
    noesisModel_t *mdlList = rapi->Noesis_ModelsFromList(models, numMdl);
    models.Clear();
     
    return mdlList;
    }
     
    //called by Noesis to init the plugin
    NPLUGIN_API bool NPAPI_Init(mathImpFn_t *mathfn, noePluginFn_t *noepfn)
    {
    g_mfn = mathfn;
    g_nfn = noepfn;
     
    if (g_nfn->NPAPI_GetAPIVersion() < NOESIS_PLUGINAPI_VERSION)
    { //bad version of noesis for this plugin
    return false;
    }
     
    int fh = g_nfn->NPAPI_Register("Kingdom Hearts Model", ".mdls");
    if (fh < 0)
    {
    return false;
    }
     
    //set the data handlers for this format
    g_nfn->NPAPI_SetTypeHandler_TypeCheck(fh, Model_KH_Check);
    g_nfn->NPAPI_SetTypeHandler_LoadModel(fh, Model_KH_Load);
     
    return true;
    }
     
    //called by Noesis before the plugin is freed
    NPLUGIN_API void NPAPI_Shutdown(void)
    {
    //nothing to do in this plugin
    }
     
    NPLUGIN_API int NPAPI_GetPluginVer(void)
    {
    return NOESIS_PLUGIN_VERSION;
    }
     
    NPLUGIN_API bool NPAPI_GetPluginInfo(noePluginInfo_t *infOut)
    {
    strcpy_s(infOut->pluginName, 64, "kingdom_hearts");
    strcpy_s(infOut->pluginDesc, 512, "Kingdom Hearts model handler, by revel8n.");
    return true;
    }
     
    BOOL APIENTRY DllMain( HMODULE hModule,
                          DWORD  ul_reason_for_call,
                          LPVOID lpReserved
    )
    {
        return TRUE;
    }
    
    Post by: root670, May 23, 2013 in forum: Code Vault
  11. root670
    There isn't a way to have any sort of "active" cheats, at least if you don't have a system with CFW. Save hacks are the only option, unfortunately, but that still brings room for some interesting codes. With some work, you could crank out codes to unlock weapons, have all items, all accessories, journal stuff, etc.
    Post by: root670, May 23, 2013 in forum: Code Vault
  12. root670
    You beat me too it lol. I made a program to extract the tm2 files from title.img, but didn't realize there were more files like it (which were .bins I guess). As for modifying the TM2s, I had issues getting them to compress back to a smaller file size if I added more than some really simple, repetitious stuff. Nevertheless, Optix iMageStudio seems to be the best tool to modify them, as it's officially used by developers.
    Post by: root670, Apr 25, 2013 in forum: Code Vault
  13. root670
    Pretty much all findings/research related to the patch is being discussed publicly in this thread, so unless something is posted here, there's probably no new news to report.
    Post by: root670, Apr 19, 2013 in forum: Code Vault
  14. root670
    Here's an updated version of the "Fly Anywhere" code that SHOULD work anywhere:

    Fly Anywhere (R2 On, L2 Off)
    E003FDFF 004DD49C
    602DCAE0 00000008
    00000001 00000070
    E003FEFF 004DD49C
    602DCAE0 00000000
    00000001 00000070

    This will work with any cheat device that supports the "6" code type, such as CodeBreaker. Others might support it, but I haven't tested it with anything except CB.
    Post by: root670, Apr 18, 2013 in forum: Code Vault
  15. root670
    ARD files seem to contain 3D models (same format as MDLS models which can be viewed with Noesis), text, and maybe some other assets. At 0x100, there is a byte that represents the amount of models contained in the file. Immediately following the byte are the offsets for each model.The offsets use 0x100 as a starting point, so if you see "80 06 02" (which converts from little-endian to 0x020680), the real offset (starting from the beginning of the file) is 0x020780. I'm not sure what the stuff is at the top of ARD files, but they seem to be in a similar format of a length byte followed by offsets.

    I was able to manually copy the bytes of the first model in di01.ard and found that it was the cloth from the tree house in Destiny Island!
    [​IMG]
    Post by: root670, Apr 18, 2013 in forum: Code Vault
  16. root670
    Alright, looks like I was trying this with other versions of KH before and never actually used Final Mix lol. It does work with Final Mix, and "1D 17 00 00 01 00 00 00 DD A6 03 00" can be found at 0x0049c000. Compatibility with other versions of the game can wait I guess, since that's beyond the scope and purpose of this project.

    The next step would be to make a tool to extract (or at least find the location of) the text portion of EVM files so we can start editing them. A tool would also be needed to replace the text in these files (and any other file that contains text) with text from the US release. This shouldn't be super hard, since the assets from Final Mix seem more similar to that of the US release than the original JP release.

    Edit: Just tried out the file replacer to replace a file from Final Mix with with it's US counterpart. I copied the file into the export directory and ran IMGreplace.exe. When I type "dh01.ard", which is the file I intended to replace, it says this:

    COMPRESSOR: Compressed from 347392 to 209309 (0.6025153141120118%)!
    New filesize is more then original, even with buffer!
    Can't replace this file!

    Oddly, it's a smaller file to begin with before compression. If the compressed file is larger than the original, can't we just move all the files in the image that come after this one by how ever many sectors larger the file will be after compression? Then you would increase the sector offsets in KINGDOM.IDX by the amount of additional sectors we needed.
    Post by: root670, Apr 18, 2013 in forum: Code Vault
  17. root670
    Thanks for clarifying that. Looks like the extractor doesn't work, however. When I try the new extractor, it says "IMGFile: found IMG (BOOT2) ~ Offset: 569344" and just sits there for about a minute. After about a minute, it crashes with this error:
    "Unhandled Exception: System.InvalidCastException: Unable to cast object of type
    'System.Boolean' to type 'System.Byte[]'.
    at JScript 0.main(Object this, VsaEngine vsa Engine)
    at JScript 0.Global Code()
    at JScript Main.Main(String[] )"
    Post by: root670, Apr 17, 2013 in forum: Code Vault
  18. root670
    crazycatz00, have you taken a look at the memory management in your extractor? I saw the process jump over 2GB at one point! Not trying to be critical or anything, just putting it out there as a bug report I guess. I don't know much about C#, but is it true that you can't manually control memory allocation and deallocation? In C you could just malloc() and free(), but I guess you can't do that in C# since it has automatic garbage collection.
    Post by: root670, Apr 17, 2013 in forum: Code Vault
  19. root670
    Hmm, the imgextract.log file shouldn't be empty. Try deleting it and running the extractor again. If that still doesn't work, here's my .log from FM: http://rghost.net/private/45345590/f75a07420a993c8aec656f13718a8939
    Post by: root670, Apr 17, 2013 in forum: Code Vault
  20. root670
    When you run IMGextract, it should generate a file called imgextract.log in the same folder as the EXE. If you have already run the extractor from a different folder, copy the imgextract.log file to the folder where you have imgreplace.exe
    Post by: root670, Apr 17, 2013 in forum: Code Vault