#include "common.h" #include "patcher.h" struct rpGeometryList { RpGeometry **geometries; int32 numGeoms; }; struct rpAtomicBinary { RwInt32 frameIndex; RwInt32 geomIndex; RwInt32 flags; RwInt32 unused; }; static int32 numberGeometrys; static int32 streamPosition; static rpGeometryList gGeomList; static rwFrameList gFrameList; static RpClumpChunkInfo gClumpInfo; rpGeometryList* GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist) { int i; RwUInt32 size, version; RwInt32 numGeoms; numberGeometrys = 0; if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) return nil; assert(size == 4); if(RwStreamRead(stream, &numGeoms, 4) != 4) return nil; numberGeometrys = numGeoms/2; geomlist->numGeoms = numGeoms; if(geomlist->numGeoms > 0){ geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*)); if(geomlist->geometries == nil) return nil; memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*)); }else geomlist->geometries = nil; for(i = 0; i < numberGeometrys; i++){ if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) return nil; geomlist->geometries[i] = RpGeometryStreamRead(stream); if(geomlist->geometries[i] == nil) return nil; } return geomlist; } rpGeometryList* GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist) { int i; RwUInt32 version; for(i = numberGeometrys; i < geomlist->numGeoms; i++){ if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) return nil; geomlist->geometries[i] = RpGeometryStreamRead(stream); if(geomlist->geometries[i] == nil) return nil; } return geomlist; } void GeometryListDeinitialize(rpGeometryList *geomlist) { int i; for(i = 0; i < geomlist->numGeoms; i++) if(geomlist->geometries[i]) RpGeometryDestroy(geomlist->geometries[i]); if(geomlist->numGeoms){ RwFree(geomlist->geometries); geomlist->numGeoms = 0; } } RpAtomic* ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList) { RwUInt32 size, version; rpAtomicBinary a; RpAtomic *atomic; numberGeometrys = 0; if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) return nil; assert(size <= sizeof(rpAtomicBinary)); if(RwStreamRead(stream, &a, size) != size) return nil; atomic = RpAtomicCreate(); if(atomic == nil) return nil; RpAtomicSetFlags(atomic, a.flags); if(frmList->numFrames){ assert(a.frameIndex < frmList->numFrames); RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]); } if(geomList->numGeoms){ assert(a.geomIndex < geomList->numGeoms); RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0); }else{ RpGeometry *geom; if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){ RpAtomicDestroy(atomic); return nil; } geom = RpGeometryStreamRead(stream); if(geom == nil){ RpAtomicDestroy(atomic); return nil; } RpAtomicSetGeometry(atomic, geom, 0); RpGeometryDestroy(geom); } return atomic; } bool RpClumpGtaStreamRead1(RwStream *stream) { RwUInt32 size, version; if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) return false; if(version >= 0x33000){ assert(size == 12); if(RwStreamRead(stream, &gClumpInfo, 12) != 12) return false; }else{ assert(size == 4); if(RwStreamRead(stream, &gClumpInfo, 4) != 4) return false; } if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version)) return false; if(_rwFrameListStreamRead(stream, &gFrameList) == nil) return false; if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){ rwFrameListDeinitialize(&gFrameList); return false; } if(GeometryListStreamRead1(stream, &gGeomList) == nil){ rwFrameListDeinitialize(&gFrameList); return false; } streamPosition = stream->Type.memory.position; return true; } RpClump* RpClumpGtaStreamRead2(RwStream *stream) { int i; RwUInt32 version; RpAtomic *atomic; RpClump *clump; clump = RpClumpCreate(); if(clump == nil) return nil; RwStreamSkip(stream, streamPosition - stream->Type.memory.position); if(GeometryListStreamRead2(stream, &gGeomList) == nil){ GeometryListDeinitialize(&gGeomList); rwFrameListDeinitialize(&gFrameList); RpClumpDestroy(clump); return nil; } RpClumpSetFrame(clump, gFrameList.frames[0]); for(i = 0; i < gClumpInfo.numAtomics; i++){ if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){ GeometryListDeinitialize(&gGeomList); rwFrameListDeinitialize(&gFrameList); RpClumpDestroy(clump); return nil; } atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList); if(atomic == nil){ GeometryListDeinitialize(&gGeomList); rwFrameListDeinitialize(&gFrameList); RpClumpDestroy(clump); return nil; } RpClumpAddAtomic(clump, atomic); } GeometryListDeinitialize(&gGeomList); rwFrameListDeinitialize(&gFrameList); return clump; } void RpClumpGtaCancelStream(void) { GeometryListDeinitialize(&gGeomList); rwFrameListDeinitialize(&gFrameList); gFrameList.numFrames = 0; } STARTPATCHES InjectHook(0x526060, RpClumpGtaStreamRead1, PATCH_JUMP); InjectHook(0x526180, RpClumpGtaStreamRead2, PATCH_JUMP); InjectHook(0x5262D0, RpClumpGtaCancelStream, PATCH_JUMP); ENDPATCHES