Skip to content

Commit 5e9bdc6

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

File tree

10 files changed

+499
-1
lines changed

10 files changed

+499
-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: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "Core.h"
2+
#include "UnCore.h"
3+
#include "GameFileSystem.h"
4+
#include "GameFileSystemSmite.h"
5+
#include <md5/md5.h>
6+
7+
#if SMITE
8+
static FSmiteManifest* GSmiteManifest = NULL;
9+
10+
void LoadSmiteManifest(const CGameFileInfo* info) {
11+
guard(LoadSmiteManifest);
12+
13+
appPrintf("Loading Smite manifest %s...\n", *info->GetRelativeName());
14+
15+
FArchive* loader = info->CreateReader();
16+
assert(loader);
17+
loader->Game = GAME_Smite;
18+
if(GSmiteManifest != nullptr) {
19+
delete GSmiteManifest;
20+
}
21+
GSmiteManifest = new FSmiteManifest;
22+
GSmiteManifest->Serialize(*loader);
23+
delete loader;
24+
25+
unguard;
26+
}
27+
28+
29+
FMemReader* GetSmiteBlob(const char* name, int name_len, int level, const char* ext) {
30+
guard(GetSmiteBlob);
31+
32+
if(GSmiteManifest == nullptr) {
33+
return nullptr;
34+
}
35+
36+
MD5Context ctx;
37+
md5Init(&ctx);
38+
md5Update(&ctx, (unsigned char*)name, name_len);
39+
md5Finalize(&ctx);
40+
41+
TArray<FSmiteFile>* item = GSmiteManifest->Files.Find(*reinterpret_cast<FGuid*>(ctx.digest));
42+
if(item == nullptr) {
43+
return nullptr;
44+
}
45+
46+
int i;
47+
for(i = 0; i < item->Num(); i++) {
48+
FSmiteFile* entry = item->GetData() + i;
49+
if(entry->tier == level) {
50+
FString* bulk = GSmiteManifest->BulkFiles.Find(entry->guid);
51+
char filename[512];
52+
appSprintf(ARRAY_ARG(filename), "%s.%s", bulk->GetDataArray().GetData(), ext);
53+
const CGameFileInfo* info = CGameFileInfo::Find(filename);
54+
if(info == nullptr) {
55+
appNotify("Smite: can't find tfc %s for %s", filename, name);
56+
return nullptr;
57+
}
58+
59+
FArchive* Ar = info->CreateReader();
60+
Ar->Game = GAME_Smite;
61+
Ar->Seek(entry->offset);
62+
byte *data = (byte*)appMalloc(entry->blob_size);
63+
Ar->Serialize(data, entry->blob_size);
64+
delete Ar;
65+
FMemReader* MemAr = new FMemReader(data, entry->blob_size);
66+
MemAr->Game = GAME_Smite;
67+
return MemAr;
68+
}
69+
}
70+
unguard;
71+
72+
return nullptr;
73+
}
74+
#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+
FMemReader* GetSmiteBlob(const char* name, int name_len, 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: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,97 @@ static int GetRealTextureOffset_MH(const UTexture2D *Obj, int MipIndex)
643643

644644
#endif // MARVEL_HEROES
645645

646+
#if SMITE
647+
#include "../FileSystem/GameFileSystemSmite.h"
648+
#include "../UnrealPackage/UnPackageUE3Reader.h"
649+
650+
static bool LoadBulkTextureSMITE(const UTexture2D* texture, const TArray<FTexture2DMipMap> &MipsArray, int MipIndex, bool verbose) {
651+
FMemReader* MemAr = nullptr;
652+
const FTexture2DMipMap &Mip = MipsArray[MipIndex];
653+
654+
int i;
655+
static char buf[2048];
656+
for(i = 0; i < 4; ++i) {
657+
static char tmp[2048];
658+
texture->GetFullName(ARRAY_ARG(tmp), true, true, false);
659+
switch(i) {
660+
case 0:
661+
appSprintf(ARRAY_ARG(buf), "%s", tmp);
662+
break;
663+
case 1:
664+
if(texture->Package == nullptr) {
665+
continue;
666+
}
667+
appSprintf(ARRAY_ARG(buf), "%s.%s", texture->Package->Name, tmp);
668+
break;
669+
case 2:
670+
appSprintf(ARRAY_ARG(buf), "Textures.%s", tmp);
671+
break;
672+
case 3:
673+
if(texture->Package == nullptr) {
674+
continue;
675+
}
676+
appSprintf(ARRAY_ARG(buf), "%s.Textures.%s", texture->Package->Name, tmp);
677+
break;
678+
}
679+
char *s = buf;
680+
int len = 0;
681+
if(verbose) {
682+
appPrintf("Smite: Finding %s (Mip %d) in MergedFileIndexCache\n", buf, MipIndex);
683+
}
684+
while (*s) {
685+
*s = toupper((unsigned char) *s);
686+
len++;
687+
s++;
688+
}
689+
690+
MemAr = GetSmiteBlob(buf, len, MipIndex, "tfc");
691+
if(MemAr != NULL) {
692+
break;
693+
}
694+
}
695+
696+
if(MemAr == NULL) {
697+
appPrintf("Smite: unable to find %s (Mip %d) in MergedFileIndexCache\n", texture->Name, MipIndex);
698+
return false;
699+
}
700+
701+
FCompressedChunkHeader H;
702+
*MemAr << H;
703+
TArray<FCompressedChunk> Chunks;
704+
FCompressedChunk *Chunk = new (Chunks) FCompressedChunk;
705+
Chunk->UncompressedOffset = 0;
706+
Chunk->UncompressedSize = H.Sum.UncompressedSize;
707+
Chunk->CompressedOffset = 0;
708+
Chunk->CompressedSize = H.Sum.CompressedSize;
709+
FByteBulkData *Bulk = const_cast<FByteBulkData*>(&Mip.Data);
710+
int flags = COMPRESS_LZO;
711+
if (Bulk->BulkDataFlags & BULKDATA_CompressedOodle_SMITE) flags = COMPRESS_OODLE;
712+
else if (Bulk->BulkDataFlags & BULKDATA_CompressedZlib) flags = COMPRESS_ZLIB;
713+
else if (Bulk->BulkDataFlags & BULKDATA_CompressedLzx) flags = COMPRESS_LZX;
714+
715+
FUE3ArchiveReader* Ar = new FUE3ArchiveReader(MemAr, flags, Chunks);
716+
Ar->IsFullyCompressed = true;
717+
718+
if (verbose)
719+
{
720+
appPrintf("Reading %s mip level %d (%dx%d) from TFC\n", texture->Name, MipIndex, Mip.SizeX, Mip.SizeY);
721+
}
722+
723+
Bulk->BulkDataSizeOnDisk = H.Sum.UncompressedSize;
724+
Bulk->ElementCount = H.Sum.UncompressedSize;
725+
Bulk->BulkDataOffsetInFile = 0;
726+
int backup = Bulk->BulkDataFlags;
727+
Bulk->BulkDataFlags = 0; // wipe compression flags temporarily
728+
Bulk->SerializeData(*Ar);
729+
Bulk->BulkDataFlags = backup;
730+
731+
MemAr->Free();
732+
delete Ar;
733+
return true;
734+
}
735+
#endif // SMITE
736+
646737

647738
bool UTexture2D::LoadBulkTexture(const TArray<FTexture2DMipMap> &MipsArray, int MipIndex, const char* tfcSuffix, bool verbose) const
648739
{
@@ -656,6 +747,11 @@ bool UTexture2D::LoadBulkTexture(const TArray<FTexture2DMipMap> &MipsArray, int
656747
FStaticString<MAX_PACKAGE_PATH> bulkFileName;
657748
if (TextureFileCacheName != "None")
658749
{
750+
#if SMITE
751+
if(Package && Package->Game == GAME_Smite) {
752+
return LoadBulkTextureSMITE(this, MipsArray, MipIndex, verbose);
753+
}
754+
#endif
659755
// TFC file is assigned
660756
bulkFileName = *TextureFileCacheName;
661757

@@ -1014,6 +1110,11 @@ bool UTexture2D::GetTextureData(CTextureData &TexData) const
10141110
//?? Separate this function ?
10151111
//!! * -notfc cmdline switch
10161112
//!! * material viewer: support switching mip levels (for xbox decompression testing)
1113+
#if SMITE
1114+
if(Package && Package->Game == GAME_Smite) {
1115+
bulkFailed = false;
1116+
} else
1117+
#endif
10171118
if (Bulk.BulkDataFlags & BULKDATA_Unused) continue; // mip level is stripped
10181119
if (!(Bulk.BulkDataFlags & BULKDATA_StoreInSeparateFile)) continue; // equals to BULKDATA_PayloadAtEndOfFile for UE4
10191120
// some optimization in a case of missing bulk file

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)