Skip to content

Commit fc617e5

Browse files
committed
Add TFC support for Smite
1 parent c444911 commit fc617e5

File tree

10 files changed

+468
-1
lines changed

10 files changed

+468
-1
lines changed

UmodelTool/umodel.project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ sources(MAIN) = {
4444
!message NO EXE_NAME
4545
!endif
4646

47-
target(executable, $EXE_NAME, MAIN + COMP_LIBS + UE4_LIBS + IMG_LIBS + NV_LIBS + MOBILE_LIBS, MAIN)
47+
target(executable, $EXE_NAME, MAIN + COMP_LIBS + UE4_LIBS + IMG_LIBS + NV_LIBS + MOBILE_LIBS + MD5_LIBS, MAIN)

Unreal/FileSystem/GameFileSystem.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Core.h"
22
#include "UnCore.h"
33
#include "GameFileSystem.h"
4+
#include "GameFileSystemSmite.h"
45

56
#include "UnArchiveObb.h"
67
#include "UnArchivePak.h"
@@ -816,6 +817,20 @@ void appSetRootDirectory(const char *dir, bool recurse)
816817
}
817818
#endif // GEARS4
818819

820+
#if SMITE
821+
if(GForceGame == GAME_Smite) {
822+
const CGameFileInfo* manifest = CGameFileInfo::Find("MergedFileIndexCache.bin");
823+
if (manifest)
824+
{
825+
LoadSmiteManifest(manifest);
826+
}
827+
else
828+
{
829+
appNotify("Smite: missing MergedFileIndexCache.bin file.");
830+
}
831+
}
832+
#endif
833+
819834
appPrintf("Found %d game files (%d skipped) in %d folders at path \"%s\"\n", GameFiles.Num(), GNumForeignFiles, GameFolders.Num() ? GameFolders.Num()-1 : 0, dir);
820835

821836
#if UNREAL4
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "Core.h"
2+
#include "UnCore.h"
3+
#include "GameFileSystem.h"
4+
#include "GameFileSystemSmite.h"
5+
6+
#if SMITE
7+
static FSmiteManifest* GSmiteManifest = NULL;
8+
9+
void LoadSmiteManifest(const CGameFileInfo* info) {
10+
guard(LoadSmiteManifest);
11+
12+
appPrintf("Loading Smite manifest %s...\n", *info->GetRelativeName());
13+
14+
FArchive* loader = info->CreateReader();
15+
assert(loader);
16+
loader->Game = GAME_Smite;
17+
if(GSmiteManifest != nullptr) {
18+
delete GSmiteManifest;
19+
}
20+
GSmiteManifest = new FSmiteManifest;
21+
GSmiteManifest->Serialize(*loader);
22+
delete loader;
23+
24+
unguard
25+
}
26+
27+
28+
FArchive* GetSmiteBlob(const FGuid& guid, int level, const char* ext) {
29+
guard(GetSmiteBlob);
30+
31+
if(GSmiteManifest == nullptr) {
32+
return nullptr;
33+
}
34+
35+
TArray<FSmiteFile>* item = GSmiteManifest->Files.Find(guid);
36+
if(item == nullptr) {
37+
return nullptr;
38+
}
39+
40+
int i;
41+
for(i = 0; i < item->Num(); i++) {
42+
FSmiteFile* entry = item->GetData() + i;
43+
if(entry->tier == level) {
44+
FString* bulk = GSmiteManifest->BulkFiles.Find(entry->guid);
45+
char filename[512];
46+
appSprintf(ARRAY_ARG(filename), "%s.%s", bulk->GetDataArray().GetData(), ext);
47+
const CGameFileInfo* info = CGameFileInfo::Find(filename);
48+
if(info == nullptr) {
49+
return nullptr;
50+
}
51+
52+
FArchive* Ar = info->CreateReader();
53+
Ar->Game = GAME_Smite;
54+
Ar->Seek(entry->offset);
55+
byte *data = (byte*)appMalloc(entry->blob_size);
56+
Ar->Serialize(data, entry->blob_size);
57+
delete Ar;
58+
Ar = new FMemReader(data, entry->blob_size);
59+
Ar->Game = GAME_Smite;
60+
return Ar;
61+
}
62+
}
63+
unguard
64+
65+
return nullptr;
66+
}
67+
#endif // SMITE
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "Core.h"
2+
#include "UnCore.h"
3+
4+
#if SMITE
5+
struct FSmiteFile {
6+
int32 tier;
7+
int32 size;
8+
int32 offset;
9+
int32 blob_size;
10+
FGuid guid;
11+
12+
friend FArchive& operator<<(FArchive &Ar, FSmiteFile &H)
13+
{
14+
return Ar << H.tier << H.size << H.offset << H.blob_size << H.guid;
15+
}
16+
};
17+
18+
struct FSmiteManifest
19+
{
20+
TMap<FGuid, TArray<FSmiteFile>> Files;
21+
TMap<FGuid, FString> BulkFiles;
22+
23+
void Serialize(FArchive& Ar)
24+
{
25+
Ar << Files;
26+
Ar << BulkFiles;
27+
}
28+
};
29+
30+
void LoadSmiteManifest(const CGameFileInfo* info);
31+
32+
FArchive* GetSmiteBlob(const FGuid& guid, int level, const char* ext);
33+
34+
#endif // SMITE

Unreal/UnCore.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,13 @@ class FMemReader : public FArchive
10271027
return DataSize;
10281028
}
10291029

1030+
void Free() {
1031+
appFree((void*)DataPtr);
1032+
DataPtr = nullptr;
1033+
DataSize = 0;
1034+
ArPos = 0;
1035+
}
1036+
10301037
protected:
10311038
const byte *DataPtr;
10321039
int DataSize;
@@ -2555,6 +2562,11 @@ void appReadCompressedChunk(FArchive &Ar, byte *Buffer, int Size, int Compressio
25552562
#define BULKDATA_SeparateData 0x40 // unknown name - bulk stored in a different place in the same file
25562563
#define BULKDATA_CompressedLzx 0x80 // unknown name
25572564

2565+
#if SMITE
2566+
#define BULKDATA_Unkn 0x100 // ??? on mip 1+ if in tfc
2567+
#define BULKDATA_CompressedOodle_SMITE 0x200 // oodle
2568+
#endif
2569+
25582570
#if BLADENSOUL
25592571
#define BULKDATA_CompressedLzoEncr 0x100 // encrypted LZO
25602572
#endif

Unreal/UnrealMaterial/UnTexture3.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,76 @@ static int GetRealTextureOffset_MH(const UTexture2D *Obj, int MipIndex)
643643

644644
#endif // MARVEL_HEROES
645645

646+
#if SMITE
647+
#include <md5/md5.h>
648+
#include "../FileSystem/GameFileSystemSmite.h"
649+
#include "../UnrealPackage/UnPackageUE3Reader.h"
650+
651+
static bool LoadBulkTextureSMITE(const UTexture2D* texture, const TArray<FTexture2DMipMap> &MipsArray, int MipIndex, bool verbose) {
652+
static char buf[2048];
653+
texture->GetFullName(ARRAY_ARG(buf), true, true, true); char *s = buf;
654+
int len = 0;
655+
if(verbose) {
656+
appPrintf("Smite: Finding %s (Mip %d) in MergedFileIndexCache\n", buf, MipIndex);
657+
}
658+
while (*s) {
659+
*s = toupper((unsigned char) *s);
660+
len++;
661+
s++;
662+
}
663+
MD5Context ctx;
664+
md5Init(&ctx);
665+
md5Update(&ctx, (unsigned char*)buf, len);
666+
md5Finalize(&ctx);
667+
668+
const FTexture2DMipMap &Mip = MipsArray[MipIndex];
669+
FArchive* Ar = GetSmiteBlob(*reinterpret_cast<FGuid*>(ctx.digest), MipIndex, "tfc");
670+
if(Ar == NULL) {
671+
appPrintf("Smite: unable to find %s (Mip %d) in MergedFileIndexCache\n", buf, MipIndex);
672+
return false;
673+
}
674+
FArchive* free = Ar;
675+
676+
FCompressedChunkHeader H;
677+
*Ar << H;
678+
TArray<FCompressedChunk> Chunks;
679+
FCompressedChunk *Chunk = new (Chunks) FCompressedChunk;
680+
Chunk->UncompressedOffset = 0;
681+
Chunk->UncompressedSize = H.Sum.UncompressedSize;
682+
Chunk->CompressedOffset = 0;
683+
Chunk->CompressedSize = H.Sum.CompressedSize;
684+
FByteBulkData *Bulk = const_cast<FByteBulkData*>(&Mip.Data);
685+
int flags = 0;
686+
if (Bulk->BulkDataFlags & BULKDATA_CompressedOodle_SMITE) flags = COMPRESS_OODLE;
687+
else if (Bulk->BulkDataFlags & BULKDATA_CompressedZlib) flags = COMPRESS_ZLIB;
688+
else if (Bulk->BulkDataFlags & BULKDATA_CompressedLzo) flags = COMPRESS_LZO;
689+
else if (Bulk->BulkDataFlags & BULKDATA_CompressedLzx) flags = COMPRESS_LZX;
690+
691+
if(flags > 0) {
692+
FUE3ArchiveReader* UE3Loader = new FUE3ArchiveReader(Ar, flags, Chunks);
693+
UE3Loader->IsFullyCompressed = true;
694+
Ar = UE3Loader;
695+
}
696+
697+
if (verbose)
698+
{
699+
appPrintf("Reading %s mip level %d (%dx%d) from TFC\n", texture->Name, MipIndex, Mip.SizeX, Mip.SizeY);
700+
}
701+
702+
Bulk->BulkDataSizeOnDisk = H.Sum.UncompressedSize;
703+
Bulk->ElementCount = H.Sum.UncompressedSize;
704+
Bulk->BulkDataOffsetInFile = 0;
705+
int backup = Bulk->BulkDataFlags;
706+
Bulk->BulkDataFlags = 0; // wipe compression flags temporarily
707+
Bulk->SerializeData(*Ar);
708+
Bulk->BulkDataFlags = backup;
709+
710+
reinterpret_cast<FMemReader*>(free)->Free();
711+
delete Ar;
712+
return true;
713+
}
714+
#endif // SMITE
715+
646716

647717
bool UTexture2D::LoadBulkTexture(const TArray<FTexture2DMipMap> &MipsArray, int MipIndex, const char* tfcSuffix, bool verbose) const
648718
{
@@ -656,6 +726,13 @@ bool UTexture2D::LoadBulkTexture(const TArray<FTexture2DMipMap> &MipsArray, int
656726
FStaticString<MAX_PACKAGE_PATH> bulkFileName;
657727
if (TextureFileCacheName != "None")
658728
{
729+
#if SMITE
730+
if(GForceGame == GAME_Smite) {
731+
if(LoadBulkTextureSMITE(this, MipsArray, MipIndex, verbose)) {
732+
return true;
733+
}
734+
}
735+
#endif
659736
// TFC file is assigned
660737
bulkFileName = *TextureFileCacheName;
661738

common.project

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ sources(UE4_LIBS) = {
189189
$R/libs/rijndael/*.c
190190
}
191191

192+
LIBINCLUDES += $R/libs/md5
193+
sources(MD5_LIBS) = {
194+
$R/libs/md5/*.c
195+
}
192196

193197
#------------------------------------------------
194198
# Project-specific options

libs/md5/SOURCE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/Zunawe/md5-c

0 commit comments

Comments
 (0)