void UMeshAnimation::SerializeSWRCAnims(FArchive &Ar) { guard(UMeshAnimation::SerializeSWRCAnims); // serialize TArray<FSkelAnimSeq> // FSkelAnimSeq is a combined (and modified) FMeshAnimSeq and MotionChunk // count int NumAnims; Ar << AR_INDEX(NumAnims); // TArray.Num // prepare arrays Moves.Empty(NumAnims); Moves.AddZeroed(NumAnims); AnimSeqs.Empty(NumAnims); AnimSeqs.AddZeroed(NumAnims); // serialize items for (int i = 0; i < NumAnims; i++) { // serialize int f50; int f54; int f58; guard(FSkelAnimSeq<<); Ar << AnimSeqs[i]; int drop; if (Ar.ArVer < 143) Ar << drop; Ar << f50 << f54; if (Ar.ArVer >= 143) Ar << f58; Ar << Moves[i].AnimTracks; unguard; } unguard; }
FArchive& FArray::SerializeRaw(FArchive &Ar, void (*Serializer)(FArchive&, void*), int elementSize) { guard(TArray::SerializeRaw); if (Ar.ReverseBytes) // reverse bytes -> cannot use fast serializer return Serialize(Ar, Serializer, elementSize); // serialize data count int Count = DataCount; if (GameUsesFCompactIndex(Ar)) Ar << AR_INDEX(Count); else Ar << Count; if (Ar.IsLoading) { // loading array items - should prepare array Empty(Count, elementSize); DataCount = Count; } if (!Count) return Ar; // perform serialization itself Ar.Serialize(DataPtr, elementSize * Count); return Ar; unguard; }
FArchive& FArray::Serialize(FArchive &Ar, void (*Serializer)(FArchive&, void*), int elementSize) { int i = 0; guard(TArray::Serialize); //-- if (Ar.IsLoading) Empty(); -- cleanup is done in TArray serializer (do not need // -- to pass array eraser/destructor to this function) // Here: // 1) when loading: 'this' array is empty (cleared from TArray's operator<<) // 2) when saving : data is not modified by this function // serialize data count int Count = DataCount; if (GameUsesFCompactIndex(Ar)) Ar << AR_INDEX(Count); else Ar << Count; if (Ar.IsLoading) { // loading array items - should prepare array Empty(Count, elementSize); DataCount = Count; } // perform serialization itself void *ptr; for (i = 0, ptr = DataPtr; i < Count; i++, ptr = OffsetPointer(ptr, elementSize)) Serializer(Ar, ptr); return Ar; unguardf("%d/%d", i, DataCount); }
void UMeshAnimation::SerializeLineageMoves(FArchive &Ar) { guard(UMeshAnimation::SerializeLineageMoves); if (Ar.ArVer < 123 || Ar.ArLicenseeVer < 0x19) { // standard UE2 format Ar << Moves; return; } assert(Ar.IsLoading); int pos, count; // pos = global skip pos, count = data count Ar << pos << AR_INDEX(count); Moves.Empty(count); for (int i = 0; i < count; i++) { int localPos; Ar << localPos; MotionChunk *M = new(Moves) MotionChunk; Ar << *M; assert(Ar.Tell() == localPos); } assert(Ar.Tell() == pos); unguard; }
FArchive& FArray::SerializeSimple(FArchive &Ar, int NumFields, int FieldSize) { guard(TArray::SerializeSimple); //?? note: SerializeSimple() can reverse bytes on loading only, saving should //?? be done using generic serializer, or SerializeSimple should be //?? extended for this // serialize data count int Count = DataCount; if (GameUsesFCompactIndex(Ar)) Ar << AR_INDEX(Count); else Ar << Count; int elementSize = NumFields * FieldSize; if (Ar.IsLoading) { // loading array items - should prepare array Empty(Count, elementSize); DataCount = Count; } if (!Count) return Ar; // perform serialization itself Ar.Serialize(DataPtr, elementSize * Count); // reverse bytes when needed if (FieldSize > 1 && Ar.ReverseBytes) { assert(Ar.IsLoading); appReverseBytes(DataPtr, Count * NumFields, FieldSize); } return Ar; unguard; }
void USkeletalMesh::Serialize(FArchive &Ar) { guard(USkeletalMesh::Serialize); assert(Ar.Game < GAME_UE3); #if UNREAL1 if (Ar.Engine() == GAME_UE1) { SerializeSkelMesh1(Ar); return; } #endif #if BIOSHOCK if (Ar.Game == GAME_Bioshock) { SerializeBioshockMesh(Ar); return; } #endif Super::Serialize(Ar); #if SPLINTER_CELL if (Ar.Game == GAME_SplinterCell) { SerializeSCell(Ar); return; } #endif // SPLINTER_CELL #if TRIBES3 TRIBES_HDR(Ar, 4); #endif Ar << Points2; #if BATTLE_TERR if (Ar.Game == GAME_BattleTerr && Ar.ArVer >= 134) { TArray<FVector> Points3; Ar << Points3; } #endif // BATTLE_TERR Ar << RefSkeleton; #if DEBUG_SKELMESH appPrintf("RefSkeleton: %d bones\n", RefSkeleton.Num()); for (int i1 = 0; i1 < RefSkeleton.Num(); i1++) appPrintf(" [%d] n=%s p=%d\n", i1, *RefSkeleton[i1].Name, RefSkeleton[i1].ParentIndex); #endif // DEBUG_SKELMESH #if SWRC if (Ar.Game == GAME_RepCommando && Ar.ArVer >= 142) { for (int i = 0; i < RefSkeleton.Num(); i++) { FMeshBone &B = RefSkeleton[i]; B.BonePos.Orientation.X *= -1; B.BonePos.Orientation.Y *= -1; B.BonePos.Orientation.Z *= -1; } } if (Ar.Game == GAME_RepCommando && Version >= 5) { TArray<FMeshAnimLinkSWRC> Anims; Ar << Anims; if (Anims.Num() >= 1) Animation = Anims[0].Anim; } else #endif // SWRC Ar << Animation; #if AA2 if (Ar.Game == GAME_AA2 && Ar.ArLicenseeVer >= 22) { TArray<UObject*> unk230; Ar << unk230; } #endif // AA2 Ar << SkeletalDepth << WeightIndices << BoneInfluences; #if SWRC if (Ar.Game == GAME_RepCommando && Ar.ArVer >= 140) { TArray<FAttachSocketSWRC> Sockets; Ar << Sockets; //?? convert } else #endif // SWRC { Ar << AttachAliases << AttachBoneNames << AttachCoords; } if (Version <= 1) { // appNotify("SkeletalMesh of version %d\n", Version); TArray<FLODMeshSection> tmp1, tmp2; TArray<word> tmp3; Ar << tmp1 << tmp2 << tmp3; // copy and convert data from old mesh format UpgradeMesh(); } else { #if UC2 if (Ar.Engine() == GAME_UE2X && Ar.ArVer >= 136) { int f338; Ar << f338; } #endif // UC2 #if SWRC if (Ar.Game == GAME_RepCommando) { int f1C4; if (Version >= 6) Ar << f1C4; Ar << LODModels; if (Version < 5) Ar << f224; Ar << Points << Wedges << Triangles << VertInfluences; Ar << CollapseWedge << f1C8; goto skip_remaining; } #endif // SWRC #if EOS if (Ar.Game == GAME_EOS) { int unk1; UObject* unk2; UObject* unk3; if (Version >= 6) Ar << unk1 << unk2; if (Version >= 7) Ar << unk3; Ar << LODModels; goto skip_remaining; } #endif // EOS #if 0 // Shui Hu Q Zhuan 2 Online if (Ar.ArVer == 126 && Ar.ArLicenseeVer == 1) { // skip LOD models int Num; Ar << AR_INDEX(Num); for (int i = 0; i < Num; i++) { int Pos; Ar << Pos; Ar.Seek(Ar.Tell() + Pos - 4); } goto after_lods; } #endif Ar << LODModels; after_lods: Ar << f224 << Points; #if BATTLE_TERR if (Ar.Game == GAME_BattleTerr && Ar.ArVer >= 134) { TLazyArray<int> unk15C; Ar << unk15C; } #endif // BATTLE_TERR Ar << Wedges << Triangles << VertInfluences; Ar << CollapseWedge << f1C8; } #if TRIBES3 if ((Ar.Game == GAME_Tribes3 || Ar.Game == GAME_Swat4) && t3_hdrSV >= 3) { #if 0 // it looks like format of following data was chenged sinse // data was prepared, and game executeble does not load these // LazyArrays (otherwise error should occur) -- so we are // simply skipping these arrays TLazyArray<FT3Unk1> unk1; TLazyArray<FMeshWedge> unk2; TLazyArray<word> unk3; Ar << unk1 << unk2 << unk3; #else SkipLazyArray(Ar); SkipLazyArray(Ar); SkipLazyArray(Ar); #endif // nothing interesting below ... goto skip_remaining; } #endif // TRIBES3 #if BATTLE_TERR if (Ar.Game == GAME_BattleTerr) goto skip_remaining; #endif #if UC2 if (Ar.Engine() == GAME_UE2X) goto skip_remaining; #endif #if LINEAGE2 if (Ar.Game == GAME_Lineage2) { int unk1, unk3, unk4; TArray<float> unk2; if (Ar.ArVer >= 118 && Ar.ArLicenseeVer >= 3) Ar << unk1; if (Ar.ArVer >= 123 && Ar.ArLicenseeVer >= 0x12) Ar << unk2; if (Ar.ArVer >= 120) Ar << unk3; // AuthKey ? if (Ar.ArLicenseeVer >= 0x23) Ar << unk4; ConvertMesh(); return; } #endif // LINEAGE2 if (Ar.ArVer >= 120) { Ar << AuthKey; } #if LOCO if (Ar.Game == GAME_Loco) goto skip_remaining; // Loco codepath is similar to UT2004, but sometimes has different version switches #endif #if UT2 if (Ar.Game == GAME_UT2) { // UT2004 has branched version of UE2, which is slightly different // in comparison with generic UE2, which is used in all other UE2 games. if (Ar.ArVer >= 122) Ar << KarmaProps << BoundingSpheres << BoundingBoxes << f32C; if (Ar.ArVer >= 127) Ar << CollisionMesh; ConvertMesh(); return; } #endif // UT2 // generic UE2 code if (Ar.ArVer >= 124) Ar << KarmaProps << BoundingSpheres << BoundingBoxes; if (Ar.ArVer >= 125) Ar << f32C; #if XIII if (Ar.Game == GAME_XIII) goto skip_remaining; #endif #if RAGNAROK2 if (Ar.Game == GAME_Ragnarok2 && Ar.ArVer >= 131) { float unk1, unk2; Ar << unk1 << unk2; } #endif // RAGNAROK2 if (Ar.ArLicenseeVer && (Ar.Tell() != Ar.GetStopper())) { appPrintf("Serializing SkeletalMesh'%s' of unknown game: %d unreal bytes\n", Name, Ar.GetStopper() - Ar.Tell()); skip_remaining: DROP_REMAINING_DATA(Ar); } ConvertMesh(); unguard; }
void UTexture::Serialize(FArchive &Ar) { guard(UTexture::Serialize); Super::Serialize(Ar); #if BIOSHOCK TRIBES_HDR(Ar, 0x2E); if (Ar.Game == GAME_Bioshock && t3_hdrSV >= 1) Ar << CachedBulkDataSize; if (Ar.Game == GAME_Bioshock && Format == 12) // remap format; note: Bioshock used 3DC name, but real format is DXT5N Format = TEXF_DXT5N; #endif // BIOSHOCK #if SWRC if (Ar.Game == GAME_RepCommando) { if (Format == 14) Format = TEXF_CxV8U8; //?? not verified } #endif // SWRC #if VANGUARD if (Ar.Game == GAME_Vanguard && Ar.ArVer >= 128 && Ar.ArLicenseeVer >= 25) { // has some table for fast mipmap lookups Ar.Seek(Ar.Tell() + 142); // skip that table // serialize mips using AR_INDEX count (this game uses int for array counts in all other places) int Count; Ar << AR_INDEX(Count); Mips.AddDefaulted(Count); for (int i = 0; i < Count; i++) Ar << Mips[i]; return; } #endif // VANGUARD #if AA2 if (Ar.Game == GAME_AA2 && Ar.ArLicenseeVer >= 8) { int unk; // always 10619 Ar << unk; } #endif // AA2 Ar << Mips; if (Ar.Engine() == GAME_UE1) { // UE1 bMasked = false; // ignored by UE1, used surface.PolyFlags instead (but UE2 ignores PolyFlags ...) if (bHasComp) // skip compressed mipmaps { TArray<FMipmap> CompMips; Ar << CompMips; } } #if XIII if (Ar.Game == GAME_XIII) { if (Ar.ArLicenseeVer >= 42) { // serialize palette if (Format == TEXF_P8 || Format == 13) // 13 == TEXF_P4 { assert(!Palette); Palette = new UPalette; Ar << Palette->Colors; } } if (Ar.ArLicenseeVer >= 55) Ar.Seek(Ar.Tell() + 3); } #endif // XIII #if EXTEEL if (Ar.Game == GAME_Exteel) { // note: this property is serialized as UObject's property too byte MaterialType; // enum GFMaterialType Ar << MaterialType; } #endif // EXTEEL unguard; }
void USetupDefinition::ProcessCopy( FString Key, FString Value, UBOOL Selected, FInstallPoll* Poll ) { guard(USetupDefinition::ProcessCopy); BYTE Buffer[4096]; if( Selected && Key==TEXT("File") ) { // Get source and dest filenames. FFileInfo Info(*Value); if( Info.Lang==TEXT("") || Info.Lang==UObject::GetLanguage() ) { if( Info.Dest==TEXT("") ) Info.Dest = Info.Src; if( !LocateSourceFile(Info.Src) ) LocalizedFileError( TEXT("MissingInstallerFile"), Patch ? TEXT("AdviseBadDownload") : TEXT("AdviseBadMedia"), *Info.Src ); FString FullDest = DestPath * Info.Dest; FString FullSrc = Info.Ref==TEXT("") ? Info.Src : GetFullRef(*Info.Ref); FString FullPatch = FullDest + TEXT("_tmp"); // Update uninstallation log. UninstallLogAdd( TEXT("File"), *Info.Dest, 0, 1 ); // Make destination directory. if( !GFileManager->MakeDirectory( *BasePath(FullDest), 1 ) ) LocalizedFileError( TEXT("FailedMakeDir"), TEXT("AdviseBadDest"), *FullDest ); // Status display. if( !Poll->Poll(*FullDest,0,0,RunningBytes,TotalBytes) ) DidCancel(); // Copy SrcAr -> DestAr. INT CalcOldCRC = 0; guard(CopyFile); FString ThisDest = Info.Ref==TEXT("") ? FullDest : FullPatch; debugf( TEXT("Copying %s to %s"), *FullSrc, *ThisDest); FArchive* SrcAr = GFileManager->CreateFileReader( *FullSrc ); if( !SrcAr ) LocalizedFileError( TEXT("FailedOpenSource"), Patch ? TEXT("AdviseBadDownload") : TEXT("AdviseBadMedia"), *FullSrc ); INT Size = SrcAr->TotalSize(); FArchive* DestAr = GFileManager->CreateFileWriter( *ThisDest, FILEWRITE_EvenIfReadOnly ); if( !DestAr ) LocalizedFileError( TEXT("FailedOpenDest"), TEXT("AdviseBadDest"), *ThisDest ); if( FullSrc.Right(3).Caps() == TEXT(".UZ") && ThisDest.Right(3).Caps() != TEXT(".UZ")) { INT Signature; FString OrigFilename; *SrcAr << Signature; if( Signature != 5678 ) LocalizedFileError( TEXT("FailedOpenSource"), TEXT("AdviseBadMedia"), *FullSrc ); else { *SrcAr << OrigFilename; FCodecFull Codec; Codec.AddCodec(new FCodecRLE); Codec.AddCodec(new FCodecBWT); Codec.AddCodec(new FCodecMTF); Codec.AddCodec(new FCodecRLE); Codec.AddCodec(new FCodecHuffman); Codec.Decode( *SrcAr, *DestAr ); if( !Poll->Poll(*FullDest,Size,Size,RunningBytes+=Size,TotalBytes) ) { delete SrcAr; delete DestAr; DidCancel(); } } } else { for( SQWORD Pos=0; Pos<Size; Pos+=sizeof(Buffer) ) { INT Count = Min( Size-Pos, (SQWORD)sizeof(Buffer) ); SrcAr->Serialize( Buffer, Count ); if( SrcAr->IsError() ) { delete SrcAr; delete DestAr; LocalizedFileError( TEXT("FailedReadingSource"), Patch ? TEXT("AdviseBadDownload") : TEXT("AdviseBadMedia"), *FullSrc ); } if( Info.Ref!=TEXT("") ) { CalcOldCRC = appMemCrc( Buffer, Count, CalcOldCRC ); } DestAr->Serialize( Buffer, Count ); if( DestAr->IsError() ) { delete SrcAr; delete DestAr; LocalizedFileError( TEXT("FailedWritingDest"), TEXT("AdviseBadDest"), *ThisDest ); } if( !Poll->Poll(*FullDest,Pos,Size,RunningBytes+=Count,TotalBytes) ) { delete SrcAr; delete DestAr; DidCancel(); } } } delete SrcAr; if( !DestAr->Close() ) LocalizedFileError( TEXT("FailedClosingDest"), TEXT("AdviseBadDest"), *ThisDest ); delete DestAr; unguard; // Patch SrcAr + DeltaFile -> DestAr. if( Info.Ref!=TEXT("") ) { guard(PatchFile); BYTE Buffer[4096]; // Open files. FString ThisSrc = FullPatch; FArchive* SrcAr = GFileManager->CreateFileReader( *ThisSrc ); if( !SrcAr ) LocalizedFileError( TEXT("FailedOpenSource"), Patch ? TEXT("AdviseBadDownload") : TEXT("AdviseBadMedia"), *ThisSrc ); INT Size = SrcAr->TotalSize(); FArchive* DestAr = GFileManager->CreateFileWriter(*FullDest,FILEWRITE_EvenIfReadOnly); if( !DestAr ) LocalizedFileError( TEXT("FailedOpenDest"), TEXT("AdviseBadDest"), *FullDest ); // Load delta file. TArray<BYTE> Delta; FString DeltaName = Info.Src; if( !appLoadFileToArray( Delta, *DeltaName ) ) LocalizedFileError( TEXT("FailedLoadingUpdate"), TEXT("AdviseBadDownload"), *Info.Src ); debugf( TEXT("Patching %s to %s with %s"), *ThisSrc, *FullDest, *DeltaName ); // Decompress variables. INT PrevSpot=0, CountSize=0, CRC=0; INT Magic=0, OldSize=0, OldCRC=0, NewSize=0, NewCRC; FBufferReader Reader( Delta ); Reader << Magic << OldSize << OldCRC << NewSize << NewCRC; // Validate. if( Magic!=0x92f92912 ) appErrorf( LineFormat(LocalizeError("PatchCorrupt")), *DeltaName, LocalizeError("AdviseBadDownload") ); if( OldSize!=Size || OldCRC!=CalcOldCRC ) appErrorf( LocalizeError("CdFileMismatch"), *Info.Ref, *LocalProduct ); // Delta decode it. INT OldCountSize=0; while( !Reader.AtEnd() ) { INT Index; Reader << AR_INDEX(Index); if( Index<0 ) { CRC = appMemCrc( &Delta(Reader.Tell()), -Index, CRC ); DestAr->Serialize( &Delta(Reader.Tell()), -Index ); if( DestAr->IsError() ) LocalizedFileError( TEXT("FailedWritingDest"), TEXT("AdviseBadDest"), *FullDest ); Reader.Seek( Reader.Tell() - Index ); CountSize -= Index; } else { INT CopyPos; Reader << AR_INDEX(CopyPos); CopyPos += PrevSpot; check(CopyPos>=0); check(CopyPos+Index<=Size); SrcAr->Seek( CopyPos ); for( INT Base=Index; Base>0; Base-=sizeof(Buffer) ) { INT Move = Min(Base,(INT)sizeof(Buffer)); SrcAr->Serialize( Buffer, Move ); if( SrcAr->IsError() ) LocalizedFileError( TEXT("FailedReadingSource"), Patch ? TEXT("AdviseBadDownload") : TEXT("AdviseBadDownload"), *ThisSrc ); CRC = appMemCrc( Buffer, Move, CRC ); DestAr->Serialize( Buffer, Move ); if( DestAr->IsError() ) LocalizedFileError( TEXT("FailedWritingDest"), TEXT("AdviseBadDest"), *FullDest ); } CountSize += Index; PrevSpot = CopyPos + Index; } if( ((CountSize^OldCountSize)&~(sizeof(Buffer)-1)) || Reader.AtEnd() ) { if( !Poll->Poll(*FullDest,CountSize,Info.Size,RunningBytes+=(CountSize-OldCountSize),TotalBytes) ) { delete SrcAr; delete DestAr; DidCancel(); } OldCountSize = CountSize; } } if( NewSize!=CountSize || NewCRC!=CRC ) appErrorf( LineFormat(LocalizeError("PatchCorrupt")), *DeltaName, LocalizeError("AdviseBadDownload") ); delete SrcAr; if( !DestAr->Close() ) LocalizedFileError( TEXT("FailedClosingDest"), TEXT("AdviseBadDest"), *FullDest ); delete DestAr; GFileManager->Delete( *ThisSrc ); unguard; } } } unguard; }