2#include "..\Private\PDBReader\PDBReader.h"
3#include "..\PluginManager\PluginManager.h"
4#include "..\Private\Offsets.h"
5#include "..\Private\Cache.h"
7#include "..\Commands.h"
9#include <Logger/Logger.h>
14#include <minizip/unzip.h>
29 nlohmann::json apiConfig = ArkBaseApi::GetConfig();
30 const nlohmann::json autoCacheConfig = apiConfig.value(
"settings", nlohmann::json::object()).value(
"AutomaticCacheDownload", nlohmann::json::object());
31 namespace fs = std::filesystem;
33 Log::GetLog()->info(
"-----------------------------------------------");
34 Log::GetLog()->info(
"ARK:SA Api V{:.2f}", GetVersion());
35 Log::GetLog()->info(
"Loading...\n");
39 std::unordered_map<std::string, intptr_t> offsets_dump;
40 std::unordered_map<std::string, BitField> bitfields_dump;
44 TCHAR buffer[MAX_PATH];
45 GetModuleFileName(NULL, buffer,
sizeof(buffer));
46 fs::path exe_path = std::filesystem::path(buffer).parent_path();
48 const fs::path filepath = fs::path(exe_path).append(
"ArkAscendedServer.pdb");
50 if (!fs::exists(fs::path(exe_path).append(ArkBaseApi::GetApiName())))
51 fs::create_directory(fs::path(exe_path).append(ArkBaseApi::GetApiName()));
53 if (!fs::exists(fs::path(exe_path).append(ArkBaseApi::GetApiName() +
"/Plugins")))
54 fs::create_directory(fs::path(exe_path).append(ArkBaseApi::GetApiName() +
"/Plugins"));
56 if (!fs::exists(fs::path(exe_path).append(ArkBaseApi::GetApiName()+
"/Cache")))
57 fs::create_directory(fs::path(exe_path).append(ArkBaseApi::GetApiName()+
"/Cache"));
59 const fs::path pdbIgnoreFile = fs::path(exe_path).append(ArkBaseApi::GetApiName() +
"/pdbignores.txt");
60 const fs::path keyCacheFile = fs::path(exe_path).append(ArkBaseApi::GetApiName()+
"/Cache/cached_key.cache");
61 const fs::path offsetsCacheFile = fs::path(exe_path).append(ArkBaseApi::GetApiName()+
"/Cache/cached_offsets.cache");
62 const fs::path bitfieldsCacheFile = fs::path(exe_path).append(ArkBaseApi::GetApiName()+
"/Cache/cached_bitfields.cache");
63 const fs::path offsetsCacheFilePlain = fs::path(exe_path).append(ArkBaseApi::GetApiName() +
"/Cache/cached_offsets.txt");
64 const std::string fileHash = Cache::calculateSHA256(filepath);
65 std::string storedHash = Cache::readFromFile(keyCacheFile);
66 std::unordered_set<std::string> pdbIgnoreSet = Cache::readFileIntoSet(pdbIgnoreFile);
68 if (autoCacheConfig.value(
"Enable",
true)
69 && autoCacheConfig.value(
"DownloadCacheURL",
"https://cdn.pelayori.com/cache/") !=
""
70 && (fileHash != storedHash || !fs::exists(offsetsCacheFile) || !fs::exists(bitfieldsCacheFile)))
72 const fs::path downloadFile = autoCacheConfig.value(
"DownloadCacheURL",
"") + fileHash +
".zip";
73 const fs::path localFile = fs::path(exe_path).append(ArkBaseApi::GetApiName() +
"/Cache/" + fileHash +
".zip");
75 if (ArkBaseApi::DownloadCacheFiles(downloadFile, localFile))
76 storedHash = Cache::readFromFile(keyCacheFile);
78 Log::GetLog()->error(
"Failed to download the Cache files.");
80 if (fs::exists(localFile))
81 fs::remove(localFile);
84 if (fileHash != storedHash || !fs::exists(offsetsCacheFile) || !fs::exists(bitfieldsCacheFile))
86 Log::GetLog()->info(
"Cache refresh required this will take 10-20 minutes to complete");
87 pdb_reader.Read(filepath, &offsets_dump, &bitfields_dump, pdbIgnoreSet);
89 Log::GetLog()->info(
"Caching offsets for faster loading next time");
90 Cache::serializeMap(offsets_dump, offsetsCacheFile);
92 Log::GetLog()->info(
"Caching bitfields for faster loading next time");
93 Cache::serializeMap(bitfields_dump, bitfieldsCacheFile);
94 Cache::saveToFile(keyCacheFile, fileHash);
95 Cache::saveToFilePlain(offsetsCacheFilePlain, offsets_dump);
99 Log::GetLog()->info(
"Cache is still valid loading existing cache");
100 Log::GetLog()->info(
"Reading cached offsets");
101 offsets_dump = Cache::deserializeMap<intptr_t>(offsetsCacheFile);
103 Log::GetLog()->info(
"Reading cached bitfields");
104 bitfields_dump = Cache::deserializeMap<BitField>(bitfieldsCacheFile);
107 catch (
const std::exception& error)
109 Log::GetLog()->critical(
"Failed to read pdb - {}", error.what());
113 Offsets::Get().Init(move(offsets_dump), move(bitfields_dump));
116 Log::GetLog()->info(
"API was successfully loaded");
117 Log::GetLog()->info(
"-----------------------------------------------\n");
125 std::ifstream file{ config_path };
129 nlohmann::json config;
138 if (API::Requests::DownloadFile(downloadFile.string(), localFile.string()))
140 std::string outputFolder = localFile.parent_path().string();
141 unzFile zf = unzOpen(localFile.string().c_str());
145 unz_global_info globalInfo;
146 if (unzGetGlobalInfo(zf, &globalInfo) != UNZ_OK)
152 char readBuffer[8192];
154 for (uLong i = 0; i < globalInfo.number_entry; ++i)
156 unz_file_info fileInfo;
158 if (unzGetCurrentFileInfo(zf, &fileInfo, filename,
sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK)
164 const size_t filenameLength = strlen(filename);
165 if (filename[filenameLength - 1] ==
'/')
169 if (unzOpenCurrentFile(zf) != UNZ_OK)
175 std::string fullPath = outputFolder +
"/" + filename;
176 std::ofstream out(fullPath, std::ios::binary);
180 unzCloseCurrentFile(zf);
187 bytesRead = unzReadCurrentFile(zf, readBuffer,
sizeof(readBuffer));
190 unzCloseCurrentFile(zf);
196 out.write(readBuffer, bytesRead);
197 }
while (bytesRead > 0);
199 unzCloseCurrentFile(zf);
203 if ((i + 1) < globalInfo.number_entry)
205 if (unzGoToNextFile(zf) != UNZ_OK)
218 Log::GetLog()->info(
"Cache files downloaded and processed successfully");
249 GetCommands()->AddConsoleCommand(
"plugins.load", &LoadPluginCmd);
250 GetCommands()->AddConsoleCommand(
"plugins.unload", &UnloadPluginCmd);
251 GetCommands()->AddRconCommand(
"plugins.load", &LoadPluginRcon);
252 GetCommands()->AddRconCommand(
"plugins.unload", &UnloadPluginRcon);
253 GetCommands()->AddRconCommand(
"map.setserverid", &SetServerID);
258 TArray<FString> parsed;
259 cmd->ParseIntoArray(parsed, L" ",
true);
261 if (parsed.IsValidIndex(1))
263 const std::string plugin_name = parsed[1].ToString();
269 catch (
const std::exception& error)
271 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
272 return FString::Format(
"Failed to load plugin - {}", error.what());
275 Log::GetLog()->info(
"Loaded plugin - {}", plugin_name.c_str());
277 return "Successfully loaded plugin";
280 return "Plugin not found";
285 TArray<FString> parsed;
286 cmd->ParseIntoArray(parsed, L" ",
true);
288 if (parsed.IsValidIndex(1))
290 const std::string plugin_name = parsed[1].ToString();
296 catch (
const std::exception& error)
298 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
299 return *FString::Format(
"Failed to unload plugin - {}", error.what());
302 Log::GetLog()->info(
"Unloaded plugin - {}", plugin_name.c_str());
304 return L"Successfully unloaded plugin";
307 return L"Plugin not found";
340 FString reply =
"Set new server id";
341 TArray<FString> parsed;
342 rcon_packet->Body.ParseIntoArray(parsed, L" ",
true);
344 if (parsed.IsValidIndex(1))
346 int new_server_id = std::stoi(parsed[1].ToString());
350 const auto& actors = AsaApi::GetApiUtils().GetWorld()->PersistentLevelField().Get()->ActorsField();
351 for (
auto actor : actors)
353 FString bp = AsaApi::GetApiUtils().GetBlueprint(actor);
354 if (bp.Equals(
"Blueprint'/Script/ShooterGame.PrimalPersistentWorldData'"))
356 actor->TargetingTeamField() = new_server_id;
358 AsaApi::GetApiUtils().GetShooterGameMode()->MyServerIdField() = FString(std::to_string(new_server_id));
359 AsaApi::GetApiUtils().GetShooterGameMode()->ServerIDField() = new_server_id;
360 Log::GetLog()->info(
"SERVER ID: {}", new_server_id);
361 Log::GetLog()->info(
"Forcing world save to lock-in new server id");
362 AsaApi::GetApiUtils().GetShooterGameMode()->SaveWorld(
false,
true);
368 catch (
const std::exception& error)
370 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
371 reply =
FString::Format(
"Failed to set server id - {}", error.what());
375 reply = L"You must specify a unique server id.";
static void SetServerID(RCONClientConnection *, RCONPacket *, UWorld *)
std::string GetApiName() override
bool DownloadCacheFiles(const std::filesystem::path downloadFile, const std::filesystem::path localFile)
std::unique_ptr< AsaApi::IApiUtils > & GetApiUtils() override
static void LoadPluginCmd(APlayerController *, FString *, bool)
void RegisterCommands() override
float GetVersion() override
static FString LoadPlugin(FString *cmd)
static void UnloadPluginRcon(RCONClientConnection *, RCONPacket *, UWorld *)
nlohmann::json GetConfig()
static void UnloadPluginCmd(APlayerController *, FString *, bool)
static void LoadPluginRcon(RCONClientConnection *, RCONPacket *, UWorld *)
static FString UnloadPlugin(FString *cmd)
std::unique_ptr< AsaApi::ICommands > & GetCommands() override
std::unique_ptr< AsaApi::IHooks > & GetHooks() override
static PluginManager & Get()
std::shared_ptr< Plugin > & LoadPlugin(const std::string &plugin_name) noexcept(false)
Load plugin by it's name.
void UnloadPlugin(const std::string &plugin_name) noexcept(false)
Unload plugin by it's name. Plugin must free all used resources.
static const FColor Green
UE_NODISCARD FORCEINLINE const TCHAR * operator*() const UE_LIFETIMEBOUND
constexpr float api_version
IApiUtils & GetApiUtils()
void SendMessageW(int Id, int Type, FString *OutGoingMessage)