Skip to content

Commit

Permalink
FetchFortniteAesKey now fetches mappings for latest
Browse files Browse the repository at this point in the history
Using object classes does look good, but it breaks compatibility for games other than Fortnite
  • Loading branch information
Amrsatrio committed Jan 12, 2021
1 parent 60363b3 commit b8a126a
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 88 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group 'com.tb24'
version '0.3.4'
version '0.4.0'

sourceCompatibility = 1.8
targetCompatibility = 1.8
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/tb24/blenderumap/AssetUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fun <T> getProp(properties: List<FPropertyTag>, name: String, clazz: Class<T>):
}

fun <T> getProps(properties: List<FPropertyTag>, name: String, clazz: Class<T>): Array<T?> {
val collected: MutableList<FPropertyTag> = ArrayList()
val collected = mutableListOf<FPropertyTag>()
var maxIndex = -1
for (prop in properties) {
if (prop.name.text == name) {
Expand Down
115 changes: 85 additions & 30 deletions src/main/java/com/tb24/blenderumap/FetchFortniteAesKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,110 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

import kotlin.io.FilesKt;
import me.fungames.jfortniteparse.util.DataTypeConverterKt;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class FetchFortniteAesKey {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final OkHttpClient okHttpClient = new OkHttpClient();

public static void main(String[] args) {
try {
Reader reader = new OkHttpClient().newCall(new Request.Builder().url("https://benbotfn.tk/api/v1/aes").build()).execute().body().charStream();
System.out.println("Fetched, writing...");
AesResponse response = GSON.fromJson(reader, AesResponse.class);
reader.close();
File configFile = new File("config.json");
FileReader fileReader = new FileReader(configFile);
JsonElement configTree = JsonParser.parseReader(fileReader);
fileReader.close();
JsonArray keys = configTree.getAsJsonObject().getAsJsonArray("EncryptionKeys");

while (keys.size() > 0) {
keys.remove(0);
}

JsonObject mainKey = new JsonObject();
mainKey.addProperty("Guid", "00000000000000000000000000000000");
mainKey.addProperty("Key", response.mainKey);
keys.add(mainKey);

for (Map.Entry<String, String> entry : response.dynamicKeys.entrySet()) {
JsonObject dynKey = new JsonObject();
dynKey.addProperty("FileName", entry.getKey().substring(entry.getKey().lastIndexOf('/') + 1));
dynKey.addProperty("Key", entry.getValue());
keys.add(dynKey);
}

FileWriter fileWriter = new FileWriter(configFile);
GSON.toJson(configTree, fileWriter);
fileWriter.close();
updateEncryptionKeys();
updateMappings();
System.out.println("Done");
System.exit(0);
} catch (IOException e) {
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
System.exit(1);
}
}

private static void updateEncryptionKeys() throws IOException {
System.out.println("Fetching encryption keys...");
Reader reader = okHttpClient.newCall(new Request.Builder().url("https://benbotfn.tk/api/v1/aes").build()).execute().body().charStream();
System.out.println("Updating config...");
AesResponse response = GSON.fromJson(reader, AesResponse.class);
reader.close();
File configFile = new File("config.json");
FileReader fileReader = new FileReader(configFile);
JsonElement configTree = JsonParser.parseReader(fileReader);
fileReader.close();
JsonArray keys = configTree.getAsJsonObject().getAsJsonArray("EncryptionKeys");
while (keys.size() > 0) {
keys.remove(0);
}
JsonObject mainKey = new JsonObject();
mainKey.addProperty("Guid", "00000000000000000000000000000000");
mainKey.addProperty("Key", response.mainKey);
keys.add(mainKey);
for (Map.Entry<String, String> entry : response.dynamicKeys.entrySet()) {
JsonObject dynKey = new JsonObject();
dynKey.addProperty("FileName", entry.getKey().substring(entry.getKey().lastIndexOf('/') + 1));
dynKey.addProperty("Key", entry.getValue());
keys.add(dynKey);
}
FileWriter fileWriter = new FileWriter(configFile);
GSON.toJson(configTree, fileWriter);
fileWriter.close();
}

private static void updateMappings() throws IOException, GeneralSecurityException {
System.out.println("Fetching available mappings...");
Reader reader = okHttpClient.newCall(new Request.Builder().url("https://benbotfn.tk/api/v1/mappings").build()).execute().body().charStream();
FileEntry[] response = GSON.fromJson(reader, FileEntry[].class);
FileEntry chosen = null;
for (FileEntry entry : response) {
if ("Oodle".equalsIgnoreCase(entry.meta.get("compressionMethod"))) {
chosen = entry;
break;
}
}
if (chosen == null) {
System.out.println("No mappings found. Please supply your own Oodle compressed .usmap mappings in mappings folder.");
return;
}
File mappingsFolder = new File("mappings");
File mappingsFile = new File(mappingsFolder, chosen.fileName);
if (mappingsFile.exists()) {
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
sha1.update(FilesKt.readBytes(mappingsFile));
if (Arrays.equals(sha1.digest(), DataTypeConverterKt.parseHexBinary(chosen.hash))) {
System.out.println("Mappings already up to date.");
return;
} else {
System.out.println("Integrity check failed.");
}
}
System.out.println("Downloading latest mappings...");
byte[] usmapData = okHttpClient.newCall(new Request.Builder().url(chosen.url).build()).execute().body().bytes();
System.out.println("Saving mappings to " + mappingsFile.getAbsolutePath() + "...");
if (!mappingsFolder.exists()) {
mappingsFolder.mkdir();
}
FilesKt.writeBytes(mappingsFile, usmapData);
}

public static class AesResponse {
public String version;
public String mainKey;
public Map<String, String> dynamicKeys;
}

public static class FileEntry {
public String url;
public String fileName;
public String hash;
public Long length;
public Date uploaded;
public Map<String, String> meta;
}
}
39 changes: 22 additions & 17 deletions src/main/java/com/tb24/blenderumap/JWPSerializer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package com.tb24.blenderumap

import com.google.gson.*
import me.fungames.jfortniteparse.ue4.assets.IoPackage
import me.fungames.jfortniteparse.ue4.assets.IoPackage.*
import me.fungames.jfortniteparse.ue4.assets.PakPackage
import me.fungames.jfortniteparse.ue4.assets.UProperty
import me.fungames.jfortniteparse.ue4.assets.exports.ECurveTableMode
Expand All @@ -17,6 +16,7 @@ import me.fungames.jfortniteparse.ue4.objects.core.i18n.FText
import me.fungames.jfortniteparse.ue4.objects.core.i18n.FTextHistory
import me.fungames.jfortniteparse.ue4.objects.core.math.FBox
import me.fungames.jfortniteparse.ue4.objects.core.math.FBox2D
import me.fungames.jfortniteparse.ue4.objects.core.math.FColor
import me.fungames.jfortniteparse.ue4.objects.core.misc.FGuid
import me.fungames.jfortniteparse.ue4.objects.gameplaytags.FGameplayTagContainer
import me.fungames.jfortniteparse.ue4.objects.uobject.FName
Expand Down Expand Up @@ -46,7 +46,7 @@ object JWPSerializer {
?: separateCamelCase(it.name, "_").toLowerCase(Locale.ENGLISH)
}
.registerTypeAdapter(ByteArray::class.java, ByteArraySerializer())
.registerTypeAdapter(UByte::class.java, JsonSerializer<UByte> { src, typeOfSrc, context -> JsonPrimitive(src.toShort()) })
.registerTypeAdapter(UByte::class.java, JsonSerializer<UByte> { src, typeOfSrc, context -> JsonPrimitive(src.toString()) })
.registerTypeAdapter(UShort::class.java, JsonSerializer<UShort> { src, typeOfSrc, context -> JsonPrimitive(src.toInt()) })
.registerTypeAdapter(UInt::class.java, JsonSerializer<UInt> { src, typeOfSrc, context -> JsonPrimitive(src.toLong()) })
.registerTypeAdapter(ULong::class.java, JsonSerializer<ULong> { src, typeOfSrc, context -> JsonPrimitive(BigInteger(src.toString())) })
Expand All @@ -68,6 +68,14 @@ object JWPSerializer {
add("valid", context.serialize(src.isValid))
}
})
.registerTypeAdapter(FColor::class.java, JsonSerializer<FColor> { src, typeOfSrc, context ->
JsonObject().apply {
add("r", JsonPrimitive(src.r.toShort()))
add("g", JsonPrimitive(src.g.toShort()))
add("b", JsonPrimitive(src.b.toShort()))
add("a", JsonPrimitive(src.a.toShort()))
}
})
.registerTypeAdapter(FGameplayTagContainer::class.java, JsonSerializer<FGameplayTagContainer> { src, typeOfSrc, context ->
JsonObject().apply {
add("gameplay_tags", JsonArray().apply { src.gameplayTags.forEach { add(context.serialize(it)) } })
Expand All @@ -80,27 +88,23 @@ object JWPSerializer {
.registerTypeAdapter(FPackageIndex::class.java, JsonSerializer<FPackageIndex> { src, typeOfSrc, context ->
if (src.isImport()) {
val pkg = src.owner
if (pkg is PakPackage) {
JsonArray().apply {
JsonArray().apply {
if (pkg is PakPackage) {
var current = pkg.run { src.getResource() }
while (current != null) {
add(current.objectName.text)
current = pkg.run { current!!.outerIndex.getResource() }
}
}
} else {
when (val resolved = (pkg as IoPackage).resolveObjectIndex(pkg.importMap[src.toImport()])) {
is ResolvedScriptObject -> JsonArray().apply {
var current: ResolvedObject = resolved
do {
add(current.getName().text)
} while (current.getOuter()?.also { current = it } != null)
} else {
val initial = (pkg as IoPackage).resolveObjectIndex(pkg.importMap[src.toImport()])
var current = initial
while (current != null) {
add(current.getName().text)
current = current.getOuter()
}
is ResolvedExportObject -> JsonArray().apply {
add(resolved.getName().text)
add(resolved.pkg.fileName)
if (initial is IoPackage.ResolvedExportObject) {
add(initial.pkg.name)
}
else -> null
}
}
} else {
Expand Down Expand Up @@ -188,9 +192,10 @@ object JWPSerializer {
val obj = JsonObject()
//if (sUseNonstandardFormat && src.export != null) obj.addProperty("object_name", src.export!!.objectName.text)
obj.addProperty("export_type", src.exportType)
obj.addProperty("path_name", src.getPathName(src.owner))

if (src !is UDataTable || sUseNonstandardFormat)
serializeProperties(obj, (src as UObject).properties, context)
serializeProperties(obj, src.properties, context)

if (src is UDataTable) {
if (sUseNonstandardFormat) {
Expand Down
Loading

0 comments on commit b8a126a

Please sign in to comment.