minecraft-pi-reborn/launcher/src/client/cache.cpp
2024-05-04 20:46:15 -04:00

172 lines
4.9 KiB
C++

#include <cstdlib>
#include <string>
#include <fstream>
#include <unordered_map>
#include <sstream>
#include <sys/stat.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "launcher.h"
#include "cache.h"
// Get Cache Path
static std::string get_cache_path() {
const char *home = getenv("HOME");
if (home == nullptr) {
IMPOSSIBLE();
}
return std::string(home) + HOME_SUBDIRECTORY_FOR_GAME_DATA "/.launcher-cache";
}
// Load
launcher_cache empty_cache = {
.username = DEFAULT_USERNAME,
.render_distance = DEFAULT_RENDER_DISTANCE,
.feature_flags = {}
};
launcher_cache load_cache() {
// Log
DEBUG("Loading Launcher Cache...");
// Return Value
launcher_cache ret = empty_cache;
// Open File
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
if (!stream) {
// Fail
struct stat s;
// No Warning If File Doesn't Exist
if (stat(get_cache_path().c_str(), &s) == 0) {
WARN("Unable To Open Launcher Cache For Loading");
}
} else {
// Lock File
int lock_fd = lock_file(get_cache_path().c_str());
// Check Version
unsigned char cache_version;
stream.read((char *) &cache_version, 1);
if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) {
// Fail
if (!stream.eof()) {
WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version);
} else {
WARN("Unable To Read Launcher Cache Version");
}
stream.close();
} else {
// Load Username And Render Distance
launcher_cache cache;
std::getline(stream, cache.username, '\0');
std::getline(stream, cache.render_distance, '\0');
// Load Feature Flags
std::string flag;
while (!stream.eof() && std::getline(stream, flag, '\0')) {
if (flag.length() > 0) {
unsigned char is_enabled = 0;
stream.read((char *) &is_enabled, 1);
cache.feature_flags[flag] = is_enabled != (unsigned char) 0;
}
stream.peek();
}
// Finish
stream.close();
if (!stream) {
// Fail
WARN("Failure While Loading Launcher Cache");
} else {
// Success
ret = cache;
}
}
// Unlock File
unlock_file(get_cache_path().c_str(), lock_fd);
}
// Return
return ret;
}
// Save
#define write_env_to_stream(stream, env) \
{ \
const char *env_value = getenv(env); \
if (env == NULL) { \
IMPOSSIBLE(); \
} \
stream.write(env_value, strlen(env_value) + 1); \
}
void save_cache() {
// Log
DEBUG("Saving Launcher Cache...");
// Open File
std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary);
if (!stream) {
// Fail
WARN("Unable To Open Launcher Cache For Saving");
} else {
// Lock File
int lock_fd = lock_file(get_cache_path().c_str());
// Save Cache Version
unsigned char cache_version = (unsigned char) CACHE_VERSION;
stream.write((const char *) &cache_version, 1);
// Save Username And Render Distance
write_env_to_stream(stream, "MCPI_USERNAME");
write_env_to_stream(stream, "MCPI_RENDER_DISTANCE");
// Save Feature Flags
std::unordered_map<std::string, bool> flags;
load_available_feature_flags([&flags](std::string flag) {
std::string stripped_flag = strip_feature_flag_default(flag, NULL);
flags[stripped_flag] = false;
});
{
const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS");
if (enabled_flags == NULL) {
IMPOSSIBLE();
}
std::istringstream enabled_flags_stream(enabled_flags);
std::string flag;
while (std::getline(enabled_flags_stream, flag, '|')) {
if (flag.length() > 0) {
flags[flag] = true;
}
}
}
for (auto &it : flags) {
stream.write(it.first.c_str(), it.first.size() + 1);
unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0;
stream.write((const char *) &val, 1);
}
// Finish
stream.close();
if (!stream.good()) {
WARN("Failure While Saving Launcher Cache");
}
// Unlock File
unlock_file(get_cache_path().c_str(), lock_fd);
}
}
// Wipe Cache
void wipe_cache() {
// Log
INFO("Wiping Launcher Cache...");
// Unlink File
if (unlink(get_cache_path().c_str()) != 0) {
WARN("Failure While Wiping Cache: %s", strerror(errno));
}
}