Refactor some stuff in Loader (#420)

* move console stuff from loader

* compile platform sources only per platform

* move ipc from loader

* move updater from loader

* remove Loader::didLastLaunchCrash

* remove platformdata from loader

* move updaters events and filters too
This commit is contained in:
ConfiG 2024-01-14 14:23:34 +03:00 committed by GitHub
parent 05064eb4d5
commit be7ee3ef18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 710 additions and 811 deletions

View file

@ -60,9 +60,6 @@ file(GLOB SOURCES CONFIGURE_DEPENDS
src/hooks/*.cpp src/hooks/*.cpp
src/ids/*.cpp src/ids/*.cpp
src/internal/*.cpp src/internal/*.cpp
src/platform/mac/*.cpp
src/platform/ios/*.cpp
src/platform/android/*.cpp
src/loader/*.cpp src/loader/*.cpp
src/load.cpp src/load.cpp
src/utils/*.cpp src/utils/*.cpp

View file

@ -4,9 +4,9 @@
#include "Loader.hpp" #include "Loader.hpp"
#include <matjson.hpp> #include <matjson.hpp>
namespace geode { namespace geode::ipc {
#ifdef GEODE_IS_WINDOWS #ifdef GEODE_IS_WINDOWS
constexpr char const* IPC_PIPE_NAME = "\\\\.\\pipe\\GeodeIPCPipe"; constexpr char const* IPC_PIPE_NAME = R"(\\.\pipe\GeodeIPCPipe)";
#endif #endif
#ifdef GEODE_IS_MACOS #ifdef GEODE_IS_MACOS
@ -64,5 +64,5 @@ namespace geode {
IPCFilter(IPCFilter const&) = default; IPCFilter(IPCFilter const&) = default;
}; };
std::monostate listenForIPC(std::string const& messageID, matjson::Value(*callback)(IPCEvent*)); std::monostate listen(std::string const& messageID, matjson::Value(*callback)(IPCEvent*));
} }

View file

@ -85,8 +85,6 @@ namespace geode {
void queueInMainThread(ScheduledFunction func); void queueInMainThread(ScheduledFunction func);
bool didLastLaunchCrash() const;
friend class LoaderImpl; friend class LoaderImpl;
friend Mod* takeNextLoaderMod(); friend Mod* takeNextLoaderMod();

View file

@ -1,10 +1,11 @@
#include <Geode/modify/LoadingLayer.hpp> #include <Geode/modify/LoadingLayer.hpp>
#include <Geode/modify/CCLayer.hpp> #include <Geode/modify/CCLayer.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <array> #include <array>
#include <fmt/format.h> #include <fmt/format.h>
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#include <loader/console.hpp>
#include <loader/updater.hpp>
using namespace geode::prelude; using namespace geode::prelude;
@ -77,23 +78,23 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
this->setSmallText("Verifying Loader Resources"); this->setSmallText("Verifying Loader Resources");
// verify loader resources // verify loader resources
Loader::get()->queueInMainThread([&]() { Loader::get()->queueInMainThread([&]() {
if (!LoaderImpl::get()->verifyLoaderResources()) { if (!updater::verifyLoaderResources()) {
log::debug("Downloading Loader Resources"); log::debug("Downloading Loader Resources");
this->setSmallText("Downloading Loader Resources"); this->setSmallText("Downloading Loader Resources");
this->addChild(EventListenerNode<ResourceDownloadFilter>::create( this->addChild(EventListenerNode<updater::ResourceDownloadFilter>::create(
this, &CustomLoadingLayer::updateResourcesProgress this, &CustomLoadingLayer::updateResourcesProgress
)); ));
} }
else { else {
log::debug("Loading Loader Resources"); log::debug("Loading Loader Resources");
this->setSmallText("Loading Loader Resources"); this->setSmallText("Loading Loader Resources");
LoaderImpl::get()->updateSpecialFiles(); updater::updateSpecialFiles();
this->continueLoadAssets(); this->continueLoadAssets();
} }
}); });
} }
void updateResourcesProgress(ResourceDownloadEvent* event) { void updateResourcesProgress(updater::ResourceDownloadEvent* event) {
std::visit(makeVisitor { std::visit(makeVisitor {
[&](UpdateProgress const& progress) { [&](UpdateProgress const& progress) {
this->setSmallText(fmt::format( this->setSmallText(fmt::format(
@ -107,7 +108,7 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
}, },
[&](UpdateFailed const& error) { [&](UpdateFailed const& error) {
log::debug("Failed Loader Resources"); log::debug("Failed Loader Resources");
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Error updating resources", "Error updating resources",
error + ".\n" error + ".\n"
"You will have to install resources manually by downloading resources.zip " "You will have to install resources manually by downloading resources.zip "

View file

@ -1,4 +1,3 @@
#include "../ui/internal/list/ModListLayer.hpp" #include "../ui/internal/list/ModListLayer.hpp"
#include <Geode/loader/Index.hpp> #include <Geode/loader/Index.hpp>
@ -7,13 +6,13 @@
#include <Geode/modify/IDManager.hpp> #include <Geode/modify/IDManager.hpp>
#include <Geode/utils/NodeIDs.hpp> #include <Geode/utils/NodeIDs.hpp>
#include <Geode/ui/BasedButtonSprite.hpp> #include <Geode/ui/BasedButtonSprite.hpp>
#include <Geode/ui/GeodeUI.hpp>
#include <Geode/ui/Notification.hpp> #include <Geode/ui/Notification.hpp>
#include <Geode/ui/Popup.hpp> #include <Geode/ui/Popup.hpp>
#include <Geode/ui/MDPopup.hpp> #include <Geode/ui/MDPopup.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <loader/ModImpl.hpp> #include <loader/ModImpl.hpp>
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#include <loader/updater.hpp>
using namespace geode::prelude; using namespace geode::prelude;
@ -129,7 +128,7 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
// show auto update message // show auto update message
static bool shownUpdateInfo = false; static bool shownUpdateInfo = false;
if (LoaderImpl::get()->isNewUpdateDownloaded() && !shownUpdateInfo) { if (updater::isNewUpdateDownloaded() && !shownUpdateInfo) {
shownUpdateInfo = true; shownUpdateInfo = true;
auto popup = FLAlertLayer::create( auto popup = FLAlertLayer::create(
"Update downloaded", "Update downloaded",
@ -147,7 +146,7 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
// show crash info // show crash info
static bool shownLastCrash = false; static bool shownLastCrash = false;
if ( if (
Loader::get()->didLastLaunchCrash() && crashlog::didLastLaunchCrash() &&
!shownLastCrash && !shownLastCrash &&
!Mod::get()->template getSettingValue<bool>("disable-last-crashed-popup") !Mod::get()->template getSettingValue<bool>("disable-last-crashed-popup")
) { ) {

View file

@ -1,4 +1,7 @@
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#include <loader/console.hpp>
#include <loader/IPC.hpp>
#include <loader/updater.hpp>
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
#include <Geode/loader/Loader.hpp> #include <Geode/loader/Loader.hpp>
@ -18,22 +21,22 @@ using namespace geode::prelude;
$execute { $execute {
listenForSettingChanges("show-platform-console", +[](bool value) { listenForSettingChanges("show-platform-console", +[](bool value) {
if (value) { if (value) {
LoaderImpl::get()->openPlatformConsole(); console::open();
} }
else { else {
LoaderImpl::get()->closePlatformConsole(); console::close();
} }
}); });
listenForIPC("ipc-test", [](IPCEvent* event) -> matjson::Value { ipc::listen("ipc-test", [](ipc::IPCEvent* event) -> matjson::Value {
return "Hello from Geode!"; return "Hello from Geode!";
}); });
listenForIPC("loader-info", [](IPCEvent* event) -> matjson::Value { ipc::listen("loader-info", [](ipc::IPCEvent* event) -> matjson::Value {
return Mod::get()->getMetadata(); return Mod::get()->getMetadata();
}); });
listenForIPC("list-mods", [](IPCEvent* event) -> matjson::Value { ipc::listen("list-mods", [](ipc::IPCEvent* event) -> matjson::Value {
std::vector<matjson::Value> res; std::vector<matjson::Value> res;
auto args = *event->messageData; auto args = *event->messageData;
@ -76,7 +79,7 @@ void tryShowForwardCompat() {
return; return;
// TODO: change text later // TODO: change text later
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Forward Compatibility Warning", "Forward Compatibility Warning",
"Geode is running in a newer version of GD than Geode targets.\n" "Geode is running in a newer version of GD than Geode targets.\n"
"UI is going to be disabled, platform console is forced on and crashes can be more common.\n" "UI is going to be disabled, platform console is forced on and crashes can be more common.\n"
@ -116,7 +119,7 @@ int geodeEntry(void* platformData) {
auto internalSetupRes = LoaderImpl::get()->setupInternalMod(); auto internalSetupRes = LoaderImpl::get()->setupInternalMod();
log::popNest(); log::popNest();
if (!internalSetupRes) { if (!internalSetupRes) {
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Unable to Load Geode!", "Unable to Load Geode!",
"There was a fatal error setting up " "There was a fatal error setting up "
"the internal mod and Geode can not be loaded: " + internalSetupRes.unwrapErr() "the internal mod and Geode can not be loaded: " + internalSetupRes.unwrapErr()
@ -131,7 +134,7 @@ int geodeEntry(void* platformData) {
if (LoaderImpl::get()->isForwardCompatMode() || if (LoaderImpl::get()->isForwardCompatMode() ||
Mod::get()->getSettingValue<bool>("show-platform-console")) { Mod::get()->getSettingValue<bool>("show-platform-console")) {
log::debug("Opening console"); log::debug("Opening console");
LoaderImpl::get()->openPlatformConsole(); console::open();
} }
// set up loader, load mods, etc. // set up loader, load mods, etc.
@ -140,7 +143,7 @@ int geodeEntry(void* platformData) {
auto setupRes = LoaderImpl::get()->setup(); auto setupRes = LoaderImpl::get()->setup();
log::popNest(); log::popNest();
if (!setupRes) { if (!setupRes) {
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Unable to Load Geode!", "Unable to Load Geode!",
"There was an unknown fatal error setting up " "There was an unknown fatal error setting up "
"the loader and Geode can not be loaded. " "the loader and Geode can not be loaded. "
@ -152,12 +155,15 @@ int geodeEntry(void* platformData) {
crashlog::setupPlatformHandlerPost(); crashlog::setupPlatformHandlerPost();
log::info("Set up loader"); log::debug("Setting up IPC");
log::pushNest();
ipc::setup();
log::popNest();
// download and install new loader update in the background // download and install new loader update in the background
if (Mod::get()->getSettingValue<bool>("auto-check-updates")) { if (Mod::get()->getSettingValue<bool>("auto-check-updates")) {
log::info("Starting loader update check"); log::info("Starting loader update check");
LoaderImpl::get()->checkForLoaderUpdates(); updater::checkForLoaderUpdates();
} }
else { else {
log::info("Skipped loader update check"); log::info("Skipped loader update check");

View file

@ -1,16 +1,17 @@
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
#include "IPC.hpp"
#include <matjson.hpp> #include <matjson.hpp>
using namespace geode::prelude; using namespace geode::prelude;
std::monostate geode::listenForIPC(std::string const& messageID, matjson::Value(*callback)(IPCEvent*)) { std::monostate ipc::listen(std::string const& messageID, matjson::Value(*callback)(IPCEvent*)) {
(void) new EventListener( (void) new EventListener(
callback, IPCFilter(getMod()->getID(), messageID) callback, IPCFilter(getMod()->getID(), messageID)
); );
return std::monostate(); return std::monostate();
} }
IPCEvent::IPCEvent( ipc::IPCEvent::IPCEvent(
void* rawPipeHandle, void* rawPipeHandle,
std::string const& targetModID, std::string const& targetModID,
std::string const& messageID, std::string const& messageID,
@ -22,9 +23,9 @@ IPCEvent::IPCEvent(
replyData(replyData), replyData(replyData),
messageData(std::make_unique<matjson::Value>(messageData)) {} messageData(std::make_unique<matjson::Value>(messageData)) {}
IPCEvent::~IPCEvent() {} ipc::IPCEvent::~IPCEvent() {}
ListenerResult IPCFilter::handle(utils::MiniFunction<Callback> fn, IPCEvent* event) { ListenerResult ipc::IPCFilter::handle(utils::MiniFunction<Callback> fn, IPCEvent* event) {
if (event->targetModID == m_modID && event->messageID == m_messageID) { if (event->targetModID == m_modID && event->messageID == m_messageID) {
event->replyData = fn(event); event->replyData = fn(event);
return ListenerResult::Stop; return ListenerResult::Stop;
@ -32,5 +33,34 @@ ListenerResult IPCFilter::handle(utils::MiniFunction<Callback> fn, IPCEvent* eve
return ListenerResult::Propagate; return ListenerResult::Propagate;
} }
IPCFilter::IPCFilter(std::string const& modID, std::string const& messageID) : ipc::IPCFilter::IPCFilter(std::string const& modID, std::string const& messageID) :
m_modID(modID), m_messageID(messageID) {} m_modID(modID), m_messageID(messageID) {}
matjson::Value ipc::processRaw(void* rawHandle, std::string const& buffer) {
matjson::Value reply;
matjson::Value json;
try {
json = matjson::parse(buffer);
} catch (...) {
log::warn("Received IPC message that isn't valid JSON");
return reply;
}
if (!json.contains("mod") || !json["mod"].is_string()) {
log::warn("Received IPC message without 'mod' field");
return reply;
}
if (!json.contains("message") || !json["message"].is_string()) {
log::warn("Received IPC message without 'message' field");
return reply;
}
matjson::Value data;
if (json.contains("data")) {
data = json["data"];
}
// log::debug("Posting IPC event");
// ! warning: if the event system is ever made asynchronous this will break!
IPCEvent(rawHandle, json["mod"].as_string(), json["message"].as_string(), data, reply).post();
return reply;
}

View file

@ -0,0 +1,9 @@
#pragma once
#include <string>
#include <matjson.hpp>
namespace geode::ipc {
void setup();
matjson::Value processRaw(void* rawHandle, std::string const& buffer);
}

View file

@ -73,10 +73,6 @@ void Loader::queueInMainThread(ScheduledFunction func) {
return m_impl->queueInMainThread(std::move(func)); return m_impl->queueInMainThread(std::move(func));
} }
bool Loader::didLastLaunchCrash() const {
return m_impl->didLastLaunchCrash();
}
Mod* Loader::takeNextMod() { Mod* Loader::takeNextMod() {
return m_impl->takeNextMod(); return m_impl->takeNextMod();
} }

View file

@ -4,6 +4,7 @@
#include "ModImpl.hpp" #include "ModImpl.hpp"
#include "ModMetadataImpl.hpp" #include "ModMetadataImpl.hpp"
#include "LogImpl.hpp" #include "LogImpl.hpp"
#include "console.hpp"
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
@ -82,11 +83,6 @@ Result<> Loader::Impl::setup() {
} }
log::popNest(); log::popNest();
log::debug("Setting up IPC");
log::pushNest();
this->setupIPC();
log::popNest();
log::debug("Setting up directories"); log::debug("Setting up directories");
log::pushNest(); log::pushNest();
this->createDirectories(); this->createDirectories();
@ -663,12 +659,8 @@ std::vector<LoadProblem> Loader::Impl::getProblems() const {
return m_problems; return m_problems;
} }
bool Loader::Impl::didLastLaunchCrash() const {
return crashlog::didLastLaunchCrash();
}
void Loader::Impl::forceReset() { void Loader::Impl::forceReset() {
this->closePlatformConsole(); console::close();
for (auto& [_, mod] : m_mods) { for (auto& [_, mod] : m_mods) {
delete mod; delete mod;
} }
@ -719,356 +711,6 @@ void Loader::Impl::executeGDThreadQueue() {
} }
} }
void Loader::Impl::logConsoleMessage(std::string const& msg) {
if (m_platformConsoleOpen) {
// TODO: make flushing optional
std::cout << msg << '\n' << std::flush;
}
}
bool Loader::Impl::platformConsoleOpen() const {
return m_platformConsoleOpen;
}
void Loader::Impl::fetchLatestGithubRelease(
utils::MiniFunction<void(matjson::Value const&)> then,
utils::MiniFunction<void(std::string const&)> expect
) {
if (m_latestGithubRelease) {
return then(m_latestGithubRelease.value());
}
// TODO: add header to not get rate limited
web::AsyncWebRequest()
.join("loader-auto-update-check")
.userAgent("github_api/1.0")
.fetch("https://api.github.com/repos/geode-sdk/geode/releases/latest")
.json()
.then([this, then](matjson::Value const& json) {
m_latestGithubRelease = json;
then(json);
})
.expect(expect);
}
void Loader::Impl::tryDownloadLoaderResources(
std::string const& url,
bool tryLatestOnError
) {
auto tempResourcesZip = dirs::getTempDir() / "new.zip";
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
web::AsyncWebRequest()
// use the url as a join handle
.join(url)
.fetch(url)
.into(tempResourcesZip)
.then([tempResourcesZip, resourcesDir, this](auto) {
// unzip resources zip
auto unzip = file::Unzip::intoDir(tempResourcesZip, resourcesDir, true);
if (!unzip) {
ResourceDownloadEvent(
UpdateFailed("Unable to unzip new resources: " + unzip.unwrapErr())
).post();
return;
}
this->updateSpecialFiles();
ResourceDownloadEvent(UpdateFinished()).post();
})
.expect([this, tryLatestOnError](std::string const& info, int code) {
// if the url was not found, try downloading latest release instead
// (for development versions)
if (code == 404) {
log::warn("Unable to download resources: {}", info);
}
ResourceDownloadEvent(
UpdateFailed("Unable to download resources: " + info)
).post();
})
.progress([](auto&, double now, double total) {
ResourceDownloadEvent(
UpdateProgress(
static_cast<uint8_t>(now / total * 100.0),
"Downloading resources"
)
).post();
});
}
void Loader::Impl::updateSpecialFiles() {
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
auto res = ModMetadataImpl::getImpl(ModImpl::get()->m_metadata).addSpecialFiles(resourcesDir);
if (res.isErr()) {
log::warn("Unable to add special files: {}", res.unwrapErr());
}
}
void Loader::Impl::downloadLoaderResources(bool useLatestRelease) {
web::AsyncWebRequest()
.join("loader-tag-exists-check")
.userAgent("github_api/1.0")
.fetch(fmt::format(
"https://api.github.com/repos/geode-sdk/geode/git/ref/tags/{}",
this->getVersion().toString()
))
.json()
.then([this](matjson::Value const& json) {
this->tryDownloadLoaderResources(fmt::format(
"https://github.com/geode-sdk/geode/releases/download/{}/resources.zip",
this->getVersion().toString()
), true);
})
.expect([=, this](std::string const& info, int code) {
if (code == 404) {
if (useLatestRelease) {
log::debug("Loader version {} does not exist on Github, downloading latest resources", this->getVersion().toString());
fetchLatestGithubRelease(
[this](matjson::Value const& raw) {
auto json = raw;
JsonChecker checker(json);
auto root = checker.root("[]").obj();
// find release asset
for (auto asset : root.needs("assets").iterate()) {
auto obj = asset.obj();
if (obj.needs("name").template get<std::string>() == "resources.zip") {
this->tryDownloadLoaderResources(
obj.needs("browser_download_url").template get<std::string>(),
false
);
return;
}
}
ResourceDownloadEvent(
UpdateFailed("Unable to find resources in latest GitHub release")
).post();
},
[this](std::string const& info) {
ResourceDownloadEvent(
UpdateFailed("Unable to download resources: " + info)
).post();
}
);
return;
}
else {
log::debug("Loader version {} does not exist on Github, not downloading the resources", this->getVersion().toString());
}
ResourceDownloadEvent(
UpdateFinished()
).post();
}
else {
ResourceDownloadEvent(
UpdateFailed("Unable to check if tag exists: " + info)
).post();
}
});
}
bool Loader::Impl::verifyLoaderResources() {
static std::optional<bool> CACHED = std::nullopt;
if (CACHED.has_value()) {
return CACHED.value();
}
// geode/resources/geode.loader
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
// if the resources dir doesn't exist, then it's probably incorrect
if (!(
ghc::filesystem::exists(resourcesDir) &&
ghc::filesystem::is_directory(resourcesDir)
)) {
log::debug("Resources directory does not exist");
this->downloadLoaderResources(true);
return false;
}
// TODO: actually have a proper way to disable checking resources
// for development builds
if (ghc::filesystem::exists(resourcesDir / "dont-update.txt")) {
// this is kind of a hack, but it's the easiest way to prevent
// auto update while developing
log::debug("Not updating resources since dont-update.txt exists");
return true;
}
// make sure every file was covered
size_t coverage = 0;
// verify hashes
for (auto& file : ghc::filesystem::directory_iterator(resourcesDir)) {
auto name = file.path().filename().string();
// skip unknown files
if (!LOADER_RESOURCE_HASHES.count(name)) {
continue;
}
// verify hash
auto hash = calculateSHA256(file.path());
auto expected = LOADER_RESOURCE_HASHES.at(name);
if (hash != expected) {
log::debug("Resource hash mismatch: {} ({}, {})", name, hash.substr(0, 7), expected.substr(0, 7));
this->downloadLoaderResources();
return false;
}
coverage += 1;
}
// make sure every file was found
if (coverage != LOADER_RESOURCE_HASHES.size()) {
log::debug("Resource coverage mismatch");
this->downloadLoaderResources();
return false;
}
return true;
}
void Loader::Impl::downloadLoaderUpdate(std::string const& url) {
auto updateZip = dirs::getTempDir() / "loader-update.zip";
auto targetDir = dirs::getGeodeDir() / "update";
web::AsyncWebRequest()
.join("loader-update-download")
.fetch(url)
.into(updateZip)
.then([this, updateZip, targetDir](auto) {
// unzip resources zip
auto unzip = file::Unzip::intoDir(updateZip, targetDir, true);
if (!unzip) {
LoaderUpdateEvent(
UpdateFailed("Unable to unzip update: " + unzip.unwrapErr())
).post();
return;
}
m_isNewUpdateDownloaded = true;
LoaderUpdateEvent(UpdateFinished()).post();
})
.expect([](std::string const& info) {
LoaderUpdateEvent(
UpdateFailed("Unable to download update: " + info)
).post();
})
.progress([](auto&, double now, double total) {
LoaderUpdateEvent(
UpdateProgress(
static_cast<uint8_t>(now / total * 100.0),
"Downloading update"
)
).post();
});
}
void Loader::Impl::checkForLoaderUpdates() {
// Check for updates in the background
fetchLatestGithubRelease(
[this](matjson::Value const& raw) {
auto json = raw;
JsonChecker checker(json);
auto root = checker.root("[]").obj();
VersionInfo ver { 0, 0, 0 };
root.needs("tag_name").into(ver);
// make sure release is newer
if (ver <= this->getVersion()) {
return;
}
// don't auto-update major versions
if (ver.getMajor() > this->getVersion().getMajor()) {
return;
}
// find release asset
for (auto asset : root.needs("assets").iterate()) {
auto obj = asset.obj();
if (string::endsWith(
obj.needs("name").template get<std::string>(),
GEODE_PLATFORM_SHORT_IDENTIFIER ".zip"
)) {
this->downloadLoaderUpdate(
obj.needs("browser_download_url").template get<std::string>()
);
return;
}
}
LoaderUpdateEvent(
UpdateFailed("Unable to find release asset for " GEODE_PLATFORM_NAME)
).post();
},
[](std::string const& info) {
LoaderUpdateEvent(
UpdateFailed("Unable to check for updates: " + info)
).post();
}
);
}
bool Loader::Impl::isNewUpdateDownloaded() const {
return m_isNewUpdateDownloaded;
}
matjson::Value Loader::Impl::processRawIPC(void* rawHandle, std::string const& buffer) {
matjson::Value reply;
matjson::Value json;
try {
json = matjson::parse(buffer);
} catch (...) {
log::warn("Received IPC message that isn't valid JSON");
return reply;
}
if (!json.contains("mod") || !json["mod"].is_string()) {
log::warn("Received IPC message without 'mod' field");
return reply;
}
if (!json.contains("message") || !json["message"].is_string()) {
log::warn("Received IPC message without 'message' field");
return reply;
}
matjson::Value data;
if (json.contains("data")) {
data = json["data"];
}
// log::debug("Posting IPC event");
// ! warning: if the event system is ever made asynchronous this will break!
IPCEvent(rawHandle, json["mod"].as_string(), json["message"].as_string(), data, reply).post();
return reply;
}
ResourceDownloadEvent::ResourceDownloadEvent(
UpdateStatus const& status
) : status(status) {}
ListenerResult ResourceDownloadFilter::handle(
utils::MiniFunction<Callback> fn,
ResourceDownloadEvent* event
) {
fn(event);
return ListenerResult::Propagate;
}
ResourceDownloadFilter::ResourceDownloadFilter() {}
LoaderUpdateEvent::LoaderUpdateEvent(
UpdateStatus const& status
) : status(status) {}
ListenerResult LoaderUpdateFilter::handle(
utils::MiniFunction<Callback> fn,
LoaderUpdateEvent* event
) {
fn(event);
return ListenerResult::Propagate;
}
LoaderUpdateFilter::LoaderUpdateFilter() {}
void Loader::Impl::provideNextMod(Mod* mod) { void Loader::Impl::provideNextMod(Mod* mod) {
m_nextModLock.lock(); m_nextModLock.lock();
if (mod) { if (mod) {

View file

@ -25,32 +25,6 @@
// TODO: Find a file convention for impl headers // TODO: Find a file convention for impl headers
namespace geode { namespace geode {
struct ResourceDownloadEvent : public Event {
const UpdateStatus status;
ResourceDownloadEvent(UpdateStatus const& status);
};
class ResourceDownloadFilter : public EventFilter<ResourceDownloadEvent> {
public:
using Callback = void(ResourceDownloadEvent*);
ListenerResult handle(utils::MiniFunction<Callback> fn, ResourceDownloadEvent* event);
ResourceDownloadFilter();
};
struct LoaderUpdateEvent : public Event {
const UpdateStatus status;
LoaderUpdateEvent(UpdateStatus const& status);
};
class LoaderUpdateFilter : public EventFilter<LoaderUpdateEvent> {
public:
using Callback = void(LoaderUpdateEvent*);
ListenerResult handle(utils::MiniFunction<Callback> fn, LoaderUpdateEvent* event);
LoaderUpdateFilter();
};
class Loader::Impl { class Loader::Impl {
public: public:
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
@ -66,11 +40,6 @@ namespace geode {
std::vector<ghc::filesystem::path> m_texturePaths; std::vector<ghc::filesystem::path> m_texturePaths;
bool m_isSetup = false; bool m_isSetup = false;
// cache for the json of the latest github release to avoid hitting
// the github api too much
std::optional<matjson::Value> m_latestGithubRelease;
bool m_isNewUpdateDownloaded = false;
LoadingState m_loadingState; LoadingState m_loadingState;
std::vector<utils::MiniFunction<void(void)>> m_mainThreadQueue; std::vector<utils::MiniFunction<void(void)>> m_mainThreadQueue;
@ -78,9 +47,6 @@ namespace geode {
std::vector<std::pair<Hook*, Mod*>> m_uninitializedHooks; std::vector<std::pair<Hook*, Mod*>> m_uninitializedHooks;
bool m_readyToHook = false; bool m_readyToHook = false;
bool m_platformConsoleOpen = false;
void* m_platformData = nullptr;
std::mutex m_nextModMutex; std::mutex m_nextModMutex;
std::unique_lock<std::mutex> m_nextModLock = std::unique_lock<std::mutex>(m_nextModMutex, std::defer_lock); std::unique_lock<std::mutex> m_nextModLock = std::unique_lock<std::mutex>(m_nextModMutex, std::defer_lock);
std::condition_variable m_nextModCV; std::condition_variable m_nextModCV;
@ -109,17 +75,7 @@ namespace geode {
Result<tulip::hook::HandlerHandle> getHandler(void* address); Result<tulip::hook::HandlerHandle> getHandler(void* address);
Result<> removeHandler(void* address); Result<> removeHandler(void* address);
void updateSpecialFiles();
void tryDownloadLoaderResources(std::string const& url, bool tryLatestOnError = true);
void downloadLoaderResources(bool useLatestRelease = false);
void downloadLoaderUpdate(std::string const& url);
void fetchLatestGithubRelease(
utils::MiniFunction<void(matjson::Value const&)> then,
utils::MiniFunction<void(std::string const&)> expect
);
bool loadHooks(); bool loadHooks();
void setupIPC();
Impl(); Impl();
~Impl(); ~Impl();
@ -157,25 +113,9 @@ namespace geode {
void updateResources(bool forceReload); void updateResources(bool forceReload);
bool didLastLaunchCrash() const;
matjson::Value processRawIPC(void* rawHandle, std::string const& buffer);
void queueInMainThread(ScheduledFunction func); void queueInMainThread(ScheduledFunction func);
void executeGDThreadQueue(); void executeGDThreadQueue();
void logConsoleMessage(std::string const& msg);
void logConsoleMessageWithSeverity(std::string const& msg, Severity severity);
bool platformConsoleOpen() const;
void openPlatformConsole();
void closePlatformConsole();
void platformMessageBox(char const* title, std::string const& info, Severity severity = Severity::Error);
bool verifyLoaderResources();
void checkForLoaderUpdates();
bool isNewUpdateDownloaded() const;
bool isReadyToHook() const; bool isReadyToHook() const;
void addUninitializedHook(Hook* hook, Mod* mod); void addUninitializedHook(Hook* hook, Mod* mod);

View file

@ -1,4 +1,4 @@
#include "LoaderImpl.hpp" #include "console.hpp"
#include "LogImpl.hpp" #include "LogImpl.hpp"
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
@ -198,7 +198,7 @@ void Logger::push(Severity sev, Mod* mod, std::string&& content) {
auto& log = m_logs.emplace_back(sev, mod, std::move(content)); auto& log = m_logs.emplace_back(sev, mod, std::move(content));
auto const logStr = log.toString(true, m_nestLevel); auto const logStr = log.toString(true, m_nestLevel);
LoaderImpl::get()->logConsoleMessageWithSeverity(logStr, log.getSeverity()); console::log(logStr, log.getSeverity());
m_logStream << logStr << std::endl; m_logStream << logStr << std::endl;
} }
} }

View file

@ -2,6 +2,7 @@
#include "LoaderImpl.hpp" #include "LoaderImpl.hpp"
#include "ModMetadataImpl.hpp" #include "ModMetadataImpl.hpp"
#include "about.hpp" #include "about.hpp"
#include "console.hpp"
#include <hash/hash.hpp> #include <hash/hash.hpp>
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
@ -686,7 +687,7 @@ Mod* Loader::Impl::getInternalMod() {
} }
auto infoRes = getModImplInfo(); auto infoRes = getModImplInfo();
if (!infoRes) { if (!infoRes) {
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Fatal Internal Error", "Fatal Internal Error",
"Unable to create internal mod info: \"" + infoRes.unwrapErr() + "Unable to create internal mod info: \"" + infoRes.unwrapErr() +
"\"\n" "\"\n"

View file

@ -0,0 +1,10 @@
#pragma once
#include <string>
namespace geode::console {
void open();
void close();
void log(std::string const& msg, Severity severity);
void messageBox(char const* title, std::string const& info, Severity severity = Severity::Error);
}

View file

@ -0,0 +1,325 @@
#include "updater.hpp"
#include <Geode/utils/web.hpp>
#include <Geode/loader/Index.hpp>
#include <resources.hpp>
#include <hash.hpp>
#include <utility>
#include "LoaderImpl.hpp"
#include "ModMetadataImpl.hpp"
using namespace geode::prelude;
updater::ResourceDownloadEvent::ResourceDownloadEvent(
UpdateStatus status
) : status(std::move(status)) {}
ListenerResult updater::ResourceDownloadFilter::handle(
const utils::MiniFunction<Callback>& fn,
ResourceDownloadEvent* event
) {
fn(event);
return ListenerResult::Propagate;
}
updater::ResourceDownloadFilter::ResourceDownloadFilter() = default;
updater::LoaderUpdateEvent::LoaderUpdateEvent(
UpdateStatus status
) : status(std::move(status)) {}
ListenerResult updater::LoaderUpdateFilter::handle(
const utils::MiniFunction<Callback>& fn,
LoaderUpdateEvent* event
) {
fn(event);
return ListenerResult::Propagate;
}
updater::LoaderUpdateFilter::LoaderUpdateFilter() = default;
// cache for the json of the latest github release to avoid hitting
// the github api too much
std::optional<matjson::Value> s_latestGithubRelease;
bool s_isNewUpdateDownloaded = false;
void updater::fetchLatestGithubRelease(
const utils::MiniFunction<void(matjson::Value const&)>& then,
utils::MiniFunction<void(std::string const&)> expect
) {
if (s_latestGithubRelease) {
return then(s_latestGithubRelease.value());
}
// TODO: add header to not get rate limited
web::AsyncWebRequest()
.join("loader-auto-update-check")
.userAgent("github_api/1.0")
.fetch("https://api.github.com/repos/geode-sdk/geode/releases/latest")
.json()
.then([then](matjson::Value const& json) {
s_latestGithubRelease = json;
then(json);
})
.expect(std::move(expect));
}
void updater::tryDownloadLoaderResources(
std::string const& url,
bool tryLatestOnError
) {
auto tempResourcesZip = dirs::getTempDir() / "new.zip";
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
web::AsyncWebRequest()
// use the url as a join handle
.join(url)
.fetch(url)
.into(tempResourcesZip)
.then([tempResourcesZip, resourcesDir](auto) {
// unzip resources zip
auto unzip = file::Unzip::intoDir(tempResourcesZip, resourcesDir, true);
if (!unzip) {
ResourceDownloadEvent(
UpdateFailed("Unable to unzip new resources: " + unzip.unwrapErr())
).post();
return;
}
updater::updateSpecialFiles();
ResourceDownloadEvent(UpdateFinished()).post();
})
.expect([tryLatestOnError](std::string const& info, int code) {
// if the url was not found, try downloading latest release instead
// (for development versions)
if (code == 404) {
log::warn("Unable to download resources: {}", info);
}
ResourceDownloadEvent(
UpdateFailed("Unable to download resources: " + info)
).post();
})
.progress([](auto&, double now, double total) {
ResourceDownloadEvent(
UpdateProgress(
static_cast<uint8_t>(now / total * 100.0),
"Downloading resources"
)
).post();
});
}
void updater::updateSpecialFiles() {
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
auto res = ModMetadataImpl::getImpl(ModImpl::get()->m_metadata).addSpecialFiles(resourcesDir);
if (res.isErr()) {
log::warn("Unable to add special files: {}", res.unwrapErr());
}
}
void updater::downloadLoaderResources(bool useLatestRelease) {
web::AsyncWebRequest()
.join("loader-tag-exists-check")
.userAgent("github_api/1.0")
.fetch(fmt::format(
"https://api.github.com/repos/geode-sdk/geode/git/ref/tags/{}",
Loader::get()->getVersion().toString()
))
.json()
.then([](matjson::Value const& json) {
updater::tryDownloadLoaderResources(fmt::format(
"https://github.com/geode-sdk/geode/releases/download/{}/resources.zip",
Loader::get()->getVersion().toString()
), true);
})
.expect([=](std::string const& info, int code) {
if (code == 404) {
if (useLatestRelease) {
log::debug("Loader version {} does not exist on Github, downloading latest resources", Loader::get()->getVersion().toString());
fetchLatestGithubRelease(
[](matjson::Value const& raw) {
auto json = raw;
JsonChecker checker(json);
auto root = checker.root("[]").obj();
// find release asset
for (auto asset : root.needs("assets").iterate()) {
auto obj = asset.obj();
if (obj.needs("name").template get<std::string>() == "resources.zip") {
updater::tryDownloadLoaderResources(
obj.needs("browser_download_url").template get<std::string>(),
false
);
return;
}
}
ResourceDownloadEvent(
UpdateFailed("Unable to find resources in latest GitHub release")
).post();
},
[](std::string const& info) {
ResourceDownloadEvent(
UpdateFailed("Unable to download resources: " + info)
).post();
}
);
return;
}
else {
log::debug("Loader version {} does not exist on GitHub, not downloading the resources", Loader::get()->getVersion().toString());
}
ResourceDownloadEvent(
UpdateFinished()
).post();
}
else {
ResourceDownloadEvent(
UpdateFailed("Unable to check if tag exists: " + info)
).post();
}
});
}
bool updater::verifyLoaderResources() {
static std::optional<bool> CACHED = std::nullopt;
if (CACHED.has_value()) {
return CACHED.value();
}
// geode/resources/geode.loader
auto resourcesDir = dirs::getGeodeResourcesDir() / Mod::get()->getID();
// if the resources dir doesn't exist, then it's probably incorrect
if (!(
ghc::filesystem::exists(resourcesDir) &&
ghc::filesystem::is_directory(resourcesDir)
)) {
log::debug("Resources directory does not exist");
updater::downloadLoaderResources(true);
return false;
}
// TODO: actually have a proper way to disable checking resources
// for development builds
if (ghc::filesystem::exists(resourcesDir / "dont-update.txt")) {
// this is kind of a hack, but it's the easiest way to prevent
// auto update while developing
log::debug("Not updating resources since dont-update.txt exists");
return true;
}
// make sure every file was covered
size_t coverage = 0;
// verify hashes
for (auto& file : ghc::filesystem::directory_iterator(resourcesDir)) {
auto name = file.path().filename().string();
// skip unknown files
if (!LOADER_RESOURCE_HASHES.count(name)) {
continue;
}
// verify hash
auto hash = calculateSHA256(file.path());
const auto& expected = LOADER_RESOURCE_HASHES.at(name);
if (hash != expected) {
log::debug("Resource hash mismatch: {} ({}, {})", name, hash.substr(0, 7), expected.substr(0, 7));
updater::downloadLoaderResources();
return false;
}
coverage += 1;
}
// make sure every file was found
if (coverage != LOADER_RESOURCE_HASHES.size()) {
log::debug("Resource coverage mismatch");
updater::downloadLoaderResources();
return false;
}
return true;
}
void updater::downloadLoaderUpdate(std::string const& url) {
auto updateZip = dirs::getTempDir() / "loader-update.zip";
auto targetDir = dirs::getGeodeDir() / "update";
web::AsyncWebRequest()
.join("loader-update-download")
.fetch(url)
.into(updateZip)
.then([updateZip, targetDir](auto) {
// unzip resources zip
auto unzip = file::Unzip::intoDir(updateZip, targetDir, true);
if (!unzip) {
LoaderUpdateEvent(
UpdateFailed("Unable to unzip update: " + unzip.unwrapErr())
).post();
return;
}
s_isNewUpdateDownloaded = true;
LoaderUpdateEvent(UpdateFinished()).post();
})
.expect([](std::string const& info) {
LoaderUpdateEvent(
UpdateFailed("Unable to download update: " + info)
).post();
})
.progress([](auto&, double now, double total) {
LoaderUpdateEvent(
UpdateProgress(
static_cast<uint8_t>(now / total * 100.0),
"Downloading update"
)
).post();
});
}
void updater::checkForLoaderUpdates() {
// Check for updates in the background
fetchLatestGithubRelease(
[](matjson::Value const& raw) {
auto json = raw;
JsonChecker checker(json);
auto root = checker.root("[]").obj();
VersionInfo ver { 0, 0, 0 };
root.needs("tag_name").into(ver);
// make sure release is newer
if (ver <= Loader::get()->getVersion()) {
return;
}
// don't auto-update major versions
if (ver.getMajor() > Loader::get()->getVersion().getMajor()) {
return;
}
// find release asset
for (auto asset : root.needs("assets").iterate()) {
auto obj = asset.obj();
if (string::endsWith(
obj.needs("name").template get<std::string>(),
GEODE_PLATFORM_SHORT_IDENTIFIER ".zip"
)) {
updater::downloadLoaderUpdate(
obj.needs("browser_download_url").template get<std::string>()
);
return;
}
}
LoaderUpdateEvent(
UpdateFailed("Unable to find release asset for " GEODE_PLATFORM_NAME)
).post();
},
[](std::string const& info) {
LoaderUpdateEvent(
UpdateFailed("Unable to check for updates: " + info)
).post();
}
);
}
bool updater::isNewUpdateDownloaded() {
return s_isNewUpdateDownloaded;
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <string>
#include <Geode/utils/MiniFunction.hpp>
#include <Geode/loader/Index.hpp>
namespace geode::updater {
struct ResourceDownloadEvent : public Event {
const UpdateStatus status;
explicit ResourceDownloadEvent(UpdateStatus status);
};
class ResourceDownloadFilter : public EventFilter<ResourceDownloadEvent> {
public:
using Callback = void(ResourceDownloadEvent*);
static ListenerResult handle(const utils::MiniFunction<Callback>& fn, ResourceDownloadEvent* event);
ResourceDownloadFilter();
};
struct LoaderUpdateEvent : public Event {
const UpdateStatus status;
explicit LoaderUpdateEvent(UpdateStatus status);
};
class LoaderUpdateFilter : public EventFilter<LoaderUpdateEvent> {
public:
using Callback = void(LoaderUpdateEvent*);
static ListenerResult handle(const utils::MiniFunction<Callback>& fn, LoaderUpdateEvent* event);
LoaderUpdateFilter();
};
void updateSpecialFiles();
void tryDownloadLoaderResources(std::string const& url, bool tryLatestOnError = true);
void downloadLoaderResources(bool useLatestRelease = false);
void downloadLoaderUpdate(std::string const& url);
void fetchLatestGithubRelease(
const utils::MiniFunction<void(matjson::Value const&)>& then,
utils::MiniFunction<void(std::string const&)> expect
);
bool verifyLoaderResources();
void checkForLoaderUpdates();
bool isNewUpdateDownloaded();
}

View file

@ -1,7 +1,5 @@
#include <FileWatcher.hpp> #include <FileWatcher.hpp>
#ifdef GEODE_IS_ANDROID
FileWatcher::FileWatcher( FileWatcher::FileWatcher(
ghc::filesystem::path const& file, FileWatchCallback callback, ErrorCallback error ghc::filesystem::path const& file, FileWatchCallback callback, ErrorCallback error
) { ) {
@ -23,5 +21,3 @@ void FileWatcher::watch() {
bool FileWatcher::watching() const { bool FileWatcher::watching() const {
return false; return false;
} }
#endif

View file

@ -0,0 +1,7 @@
#include <loader/IPC.hpp>
using namespace geode::prelude;
void ipc::setup() {
log::debug("IPC is not supported on this platform!");
}

View file

@ -1,29 +1,9 @@
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
#include <Geode/loader/Log.hpp>
#include <loader/ModImpl.hpp>
#include <iostream>
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#include <Geode/utils/string.hpp> #include <Geode/cocos/platform/android/jni/JniHelper.h>
using namespace geode::prelude; using namespace geode::prelude;
#ifdef GEODE_IS_ANDROID
#include <Geode/cocos/platform/android/jni/JniHelper.h>
#include <android/log.h>
namespace {
android_LogPriority getLogSeverityForSeverity(Severity severity) {
switch (severity) {
case Severity::Debug: return ANDROID_LOG_DEBUG;
case Severity::Info: return ANDROID_LOG_INFO;
case Severity::Warning: return ANDROID_LOG_WARN;
case Severity::Error: return ANDROID_LOG_ERROR;
default: return ANDROID_LOG_DEFAULT;
}
}
}
std::string Loader::Impl::getGameVersion() { std::string Loader::Impl::getGameVersion() {
if (m_gdVersion.empty()) { if (m_gdVersion.empty()) {
/* /*
@ -49,33 +29,6 @@ std::string Loader::Impl::getGameVersion() {
return m_gdVersion; return m_gdVersion;
} }
void Loader::Impl::platformMessageBox(char const* title, std::string const& info, Severity severity) {
cocos2d::CCMessageBox(info.c_str(), title);
}
void Loader::Impl::logConsoleMessageWithSeverity(std::string const& msg, Severity severity) {
__android_log_print(
getLogSeverityForSeverity(severity),
"Geode",
"%s",
msg.c_str()
);
}
void Loader::Impl::openPlatformConsole() {
return;
}
void Loader::Impl::closePlatformConsole() {
return;
}
void Loader::Impl::setupIPC() {
log::warn("IPC is not supported on this platform!");
}
bool Loader::Impl::userTriedToLoadDLLs() const { bool Loader::Impl::userTriedToLoadDLLs() const {
return false; return false;
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_ANDROID
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <loader/ModImpl.hpp> #include <loader/ModImpl.hpp>
@ -34,5 +32,3 @@ Result<> Mod::Impl::unloadPlatformBinary() {
return Err("Unable to free library"); return Err("Unable to free library");
} }
} }
#endif

View file

@ -0,0 +1,39 @@
#include <loader/console.hpp>
#include <iostream>
#include <Geode/loader/Log.hpp>
#include <android/log.h>
using namespace geode::prelude;
namespace {
android_LogPriority getLogSeverityForSeverity(Severity severity) {
switch (severity) {
case Severity::Debug: return ANDROID_LOG_DEBUG;
case Severity::Info: return ANDROID_LOG_INFO;
case Severity::Warning: return ANDROID_LOG_WARN;
case Severity::Error: return ANDROID_LOG_ERROR;
default: return ANDROID_LOG_DEFAULT;
}
}
}
void console::open() {
return;
}
void console::close() {
return;
}
void console::log(std::string const& msg, Severity severity) {
__android_log_print(
getLogSeverityForSeverity(severity),
"Geode",
"%s",
msg.c_str()
);
}
void console::messageBox(char const* title, std::string const& info, Severity severity) {
cocos2d::CCMessageBox(info.c_str(), title);
}

View file

@ -1,7 +1,5 @@
#include <crashlog.hpp> #include <crashlog.hpp>
#ifdef GEODE_IS_ANDROID
using namespace geode::prelude; using namespace geode::prelude;
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
@ -302,5 +300,3 @@ void crashlog::setupPlatformHandlerPost() {
bool crashlog::didLastLaunchCrash() { bool crashlog::didLastLaunchCrash() {
return s_lastLaunchCrashed; return s_lastLaunchCrashed;
} }
#endif

View file

@ -1,8 +1,6 @@
#include <Geode/c++stl/gdstdlib.hpp> #include <Geode/c++stl/gdstdlib.hpp>
#include "../../c++stl/string-impl.hpp" #include "../../c++stl/string-impl.hpp"
#ifdef GEODE_IS_ANDROID
#if defined(GEODE_IS_ANDROID32) #if defined(GEODE_IS_ANDROID32)
static auto constexpr NEW_SYM = "_Znwj"; static auto constexpr NEW_SYM = "_Znwj";
@ -119,5 +117,3 @@ namespace geode::stl {
// TODO: implement this, remember its copy-on-write... // TODO: implement this, remember its copy-on-write...
} }
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#if defined(GEODE_IS_ANDROID)
#include "../load.hpp" #include "../load.hpp"
#include <jni.h> #include <jni.h>
@ -30,5 +28,3 @@ extern "C" [[gnu::visibility("default")]] jint JNI_OnLoad(JavaVM* vm, void* rese
extern "C" [[gnu::visibility("default")]] void emptyFunction(void*) { extern "C" [[gnu::visibility("default")]] void emptyFunction(void*) {
// empty // empty
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_ANDROID
using namespace geode::prelude; using namespace geode::prelude;
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
@ -279,5 +277,3 @@ void geode::utils::game::restart() {
nullptr nullptr
), CCDirector::get()->getRunningScene(), false); ), CCDirector::get()->getRunningScene(), false);
} }
#endif

View file

@ -1,7 +1,5 @@
#include <FileWatcher.hpp> #include <FileWatcher.hpp>
#ifdef GEODE_IS_IOS
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
@ -52,5 +50,3 @@ void FileWatcher::watch() {
bool FileWatcher::watching() const { bool FileWatcher::watching() const {
return m_platformHandle != NULL; return m_platformHandle != NULL;
} }
#endif

View file

@ -1,15 +1,13 @@
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#ifdef GEODE_IS_IOS #include <Geode/loader/Dirs.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Log.hpp>
#include <Geode/loader/Loader.hpp> #include <loader/ModImpl.hpp>
#include <Geode/loader/Log.hpp> #include <iostream>
#include <loader/ModImpl.hpp> #include <pwd.h>
#include <iostream> #include <sys/types.h>
#include <pwd.h> #include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
void Loader::Impl::platformMessageBox(char const* title, std::string const& info) { void Loader::Impl::platformMessageBox(char const* title, std::string const& info) {
std::cout << title << ": " << info << std::endl; std::cout << title << ": " << info << std::endl;
@ -41,5 +39,3 @@ void Loader::Impl::setupIPC() {
bool Loader::Impl::userTriedToLoadDLLs() const { bool Loader::Impl::userTriedToLoadDLLs() const {
return false; return false;
} }
#endif

View file

@ -1,10 +1,8 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_IOS #include <Geode/loader/Mod.hpp>
#include <loader/ModImpl.hpp>
#include <Geode/loader/Mod.hpp> #include <dlfcn.h>
#include <loader/ModImpl.hpp>
#include <dlfcn.h>
using namespace geode::prelude; using namespace geode::prelude;
@ -43,5 +41,3 @@ Result<> Mod::Impl::unloadPlatformBinary() {
return Err("Unable to free library"); return Err("Unable to free library");
} }
} }
#endif

View file

@ -1,7 +1,5 @@
#include <crashlog.hpp> #include <crashlog.hpp>
#ifdef GEODE_IS_IOS
bool crashlog::setupPlatformHandler() { bool crashlog::setupPlatformHandler() {
return false; return false;
} }
@ -13,5 +11,3 @@ bool crashlog::didLastLaunchCrash() {
ghc::filesystem::path crashlog::getCrashLogDirectory() { ghc::filesystem::path crashlog::getCrashLogDirectory() {
return ""; return "";
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#if defined(GEODE_IS_IOS)
#include "../load.hpp" #include "../load.hpp"
#include <dlfcn.h> #include <dlfcn.h>
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
@ -43,5 +41,3 @@ extern "C" __attribute__((visibility("default"))) void dynamicTrigger() {
// remove when we can figure out how to not remove it // remove when we can figure out how to not remove it
auto dynamicTriggerRef = &dynamicTrigger; auto dynamicTriggerRef = &dynamicTrigger;
#endif

View file

@ -1,9 +1,7 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_IOS
using namespace geode::prelude; using namespace geode::prelude;
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
#include <UIKit/UIKit.h> #include <UIKit/UIKit.h>
#include <iostream> #include <iostream>
@ -36,5 +34,3 @@ ghc::filesystem::path dirs::getGameDir() {
ghc::filesystem::path dirs::getSaveDir() { ghc::filesystem::path dirs::getSaveDir() {
return weaklyCanonical(CCFileUtils::sharedFileUtils()->getWritablePath().c_str()); return weaklyCanonical(CCFileUtils::sharedFileUtils()->getWritablePath().c_str());
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_MACOS
#include <cocos2d.h> #include <cocos2d.h>
using namespace cocos2d; using namespace cocos2d;
@ -815,5 +813,3 @@ void CCArray::acceptVisitor(CCDataVisitor &visitor)
{ {
visitor.visit(this); visitor.visit(this);
} }
#endif

View file

@ -1,10 +1,8 @@
#include <FileWatcher.hpp> #include <FileWatcher.hpp>
#ifdef GEODE_IS_MACOS #import <Cocoa/Cocoa.h>
#include <fcntl.h>
#import <Cocoa/Cocoa.h> #include <iostream>
#include <fcntl.h>
#include <iostream>
// static constexpr const auto notifyAttributes = FILE_NOTIFY_CHANGE_LAST_WRITE | // static constexpr const auto notifyAttributes = FILE_NOTIFY_CHANGE_LAST_WRITE |
// FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE; // FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE;
@ -52,5 +50,3 @@ void FileWatcher::watch() {
bool FileWatcher::watching() const { bool FileWatcher::watching() const {
return m_platformHandle != NULL; return m_platformHandle != NULL;
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_MACOS
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <loader/ModImpl.hpp> #include <loader/ModImpl.hpp>
#include <dlfcn.h> #include <dlfcn.h>
@ -43,5 +41,3 @@ Result<> Mod::Impl::unloadPlatformBinary() {
return Err("Unable to free library"); return Err("Unable to free library");
} }
} }
#endif

View file

@ -1,7 +1,5 @@
#include <crashlog.hpp> #include <crashlog.hpp>
#ifdef GEODE_IS_MACOS
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
#include <array> #include <array>
#include <thread> #include <thread>
@ -391,6 +389,3 @@ bool crashlog::didLastLaunchCrash() {
ghc::filesystem::path crashlog::getCrashLogDirectory() { ghc::filesystem::path crashlog::getCrashLogDirectory() {
return dirs::getGeodeDir() / "crashlogs"; return dirs::getGeodeDir() / "crashlogs";
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/c++stl/gdstdlib.hpp> #include <Geode/c++stl/gdstdlib.hpp>
#ifdef GEODE_IS_MACOS
namespace gd { namespace gd {
namespace { namespace {
static inline auto emptyInternalString() { static inline auto emptyInternalString() {
@ -57,5 +55,3 @@ namespace gd {
return std::string(*this) == std::string(other); return std::string(*this) == std::string(other);
} }
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#if defined(GEODE_IS_MACOS)
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "../load.hpp" #include "../load.hpp"
#include <dlfcn.h> #include <dlfcn.h>
@ -151,5 +149,3 @@ __attribute__((constructor)) void _entry() {
if (!loadGeode()) if (!loadGeode())
return; return;
} }
#endif

View file

@ -1,8 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_MACOS
using namespace geode::prelude; using namespace geode::prelude;
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
@ -304,5 +301,3 @@ Result<void*> geode::hook::getObjcMethodImp(std::string const& className, std::s
return Ok((void*)method_getImplementation(method)); return Ok((void*)method_getImplementation(method));
} }
#endif

View file

@ -2,8 +2,6 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#ifdef GEODE_IS_WINDOWS
static constexpr auto const notifyAttributes = static constexpr auto const notifyAttributes =
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE; FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE;
@ -100,5 +98,3 @@ bool FileWatcher::watching() const {
HANDLE handle = (HANDLE)m_platformHandle; HANDLE handle = (HANDLE)m_platformHandle;
return handle != INVALID_HANDLE_VALUE && handle != nullptr; return handle != INVALID_HANDLE_VALUE && handle != nullptr;
} }
#endif

View file

@ -0,0 +1,75 @@
#include <Geode/loader/IPC.hpp>
#include <loader/IPC.hpp>
#include <thread>
#include <optional>
#include <string>
using namespace geode::prelude;
static constexpr auto IPC_BUFFER_SIZE = 512;
void ipcPipeThread(HANDLE pipe) {
char buffer[IPC_BUFFER_SIZE * sizeof(TCHAR)];
DWORD read;
std::optional<std::string> replyID;
// log::debug("Waiting for I/O");
if (ReadFile(pipe, buffer, sizeof(buffer) - 1, &read, nullptr)) {
buffer[read] = '\0';
std::string reply = ipc::processRaw((void*)pipe, buffer).dump();
DWORD written;
WriteFile(pipe, reply.c_str(), reply.size(), &written, nullptr);
}
// log::debug("Connection done");
FlushFileBuffers(pipe);
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
// log::debug("Disconnected pipe");
}
void ipc::setup() {
std::thread ipcThread([]() {
while (true) {
auto pipe = CreateNamedPipeA(
ipc::IPC_PIPE_NAME,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
IPC_BUFFER_SIZE,
IPC_BUFFER_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
nullptr
);
if (pipe == INVALID_HANDLE_VALUE) {
// todo: Rn this quits IPC, but we might wanna change that later
// to just continue trying. however, I'm assuming that if
// CreateNamedPipeA fails, then it will probably fail again if
// you try right after, so changing the break; to continue; might
// just result in the console getting filled with error messages
log::warn("Unable to create pipe, quitting IPC");
break;
}
// log::debug("Waiting for pipe connections");
if (ConnectNamedPipe(pipe, nullptr)) {
// log::debug("Got connection, creating thread");
std::thread pipeThread(&ipcPipeThread, pipe);
// SetThreadDescription(pipeThread.native_handle(), L"Geode IPC Pipe");
pipeThread.detach();
}
else {
// log::debug("No connection, cleaning pipe");
CloseHandle(pipe);
}
}
});
// SetThreadDescription(ipcThread.native_handle(), L"Geode Main IPC");
ipcThread.detach();
log::debug("IPC set up");
}

View file

@ -1,19 +1,13 @@
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
#include <Geode/loader/Log.hpp> #include <Geode/loader/Log.hpp>
#include <loader/ModImpl.hpp> #include <loader/ModImpl.hpp>
#include <iostream>
#include <loader/LoaderImpl.hpp> #include <loader/LoaderImpl.hpp>
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
#include <loader/LogImpl.hpp>
using namespace geode::prelude; using namespace geode::prelude;
#ifdef GEODE_IS_WINDOWS
#include <Psapi.h> #include <Psapi.h>
static constexpr auto IPC_BUFFER_SIZE = 512;
#include "gdTimestampMap.hpp" #include "gdTimestampMap.hpp"
std::string Loader::Impl::getGameVersion() { std::string Loader::Impl::getGameVersion() {
if (m_gdVersion.empty()) { if (m_gdVersion.empty()) {
@ -25,161 +19,6 @@ std::string Loader::Impl::getGameVersion() {
return m_gdVersion; return m_gdVersion;
} }
void Loader::Impl::platformMessageBox(char const* title, std::string const& info, Severity severity) {
unsigned int icon;
switch (severity) {
case Severity::Debug:
case Severity::Info:
case Severity::Notice:
icon = MB_ICONINFORMATION;
break;
case Severity::Warning:
icon = MB_ICONWARNING;
break;
default:
icon = MB_ICONERROR;
break;
}
MessageBoxA(nullptr, info.c_str(), title, icon);
}
bool hasAnsiColorSupport = false;
void Loader::Impl::logConsoleMessageWithSeverity(std::string const& msg, Severity severity) {
if (!m_platformConsoleOpen)
return;
if (!hasAnsiColorSupport) {
std::cout << msg << "\n" << std::flush;
return;
}
int color = 0;
switch (severity) {
case Severity::Debug:
color = 243;
break;
case Severity::Info:
color = 33;
break;
case Severity::Warning:
color = 229;
break;
case Severity::Error:
color = 9;
break;
default:
color = 7;
break;
}
auto const colorStr = fmt::format("\x1b[38;5;{}m", color);
auto const newMsg = fmt::format("{}{}\x1b[0m{}", colorStr, msg.substr(0, 12),
msg.substr(12));
std::cout << newMsg << "\n" << std::flush;
}
void Loader::Impl::openPlatformConsole() {
if (m_platformConsoleOpen) return;
if (AllocConsole() == 0) return;
SetConsoleCP(CP_UTF8);
// redirect console output
freopen_s(reinterpret_cast<FILE**>(stdout), "CONOUT$", "w", stdout);
freopen_s(reinterpret_cast<FILE**>(stdin), "CONIN$", "r", stdin);
// Set output mode to handle ansi color sequences
auto handleStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD consoleMode = 0;
if (GetConsoleMode(handleStdout, &consoleMode)) {
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (SetConsoleMode(handleStdout, consoleMode)) {
hasAnsiColorSupport = true;
}
}
m_platformConsoleOpen = true;
for (auto const& log : log::Logger::get()->list()) {
this->logConsoleMessageWithSeverity(log.toString(true), log.getSeverity());
}
}
void Loader::Impl::closePlatformConsole() {
if (!m_platformConsoleOpen) return;
fclose(stdin);
fclose(stdout);
FreeConsole();
m_platformConsoleOpen = false;
}
void ipcPipeThread(HANDLE pipe) {
char buffer[IPC_BUFFER_SIZE * sizeof(TCHAR)];
DWORD read;
std::optional<std::string> replyID = std::nullopt;
// log::debug("Waiting for I/O");
if (ReadFile(pipe, buffer, sizeof(buffer) - 1, &read, nullptr)) {
buffer[read] = '\0';
std::string reply = LoaderImpl::get()->processRawIPC((void*)pipe, buffer).dump();
DWORD written;
WriteFile(pipe, reply.c_str(), reply.size(), &written, nullptr);
}
// log::debug("Connection done");
FlushFileBuffers(pipe);
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
// log::debug("Disconnected pipe");
}
void Loader::Impl::setupIPC() {
std::thread ipcThread([]() {
while (true) {
auto pipe = CreateNamedPipeA(
IPC_PIPE_NAME,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
IPC_BUFFER_SIZE,
IPC_BUFFER_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
nullptr
);
if (pipe == INVALID_HANDLE_VALUE) {
// todo: Rn this quits IPC, but we might wanna change that later
// to just continue trying. however, I'm assuming that if
// CreateNamedPipeA fails, then it will probably fail again if
// you try right after, so changing the break; to continue; might
// just result in the console getting filled with error messages
log::warn("Unable to create pipe, quitting IPC");
break;
}
// log::debug("Waiting for pipe connections");
if (ConnectNamedPipe(pipe, nullptr)) {
// log::debug("Got connection, creating thread");
std::thread pipeThread(&ipcPipeThread, pipe);
// SetThreadDescription(pipeThread.native_handle(), L"Geode IPC Pipe");
pipeThread.detach();
}
else {
// log::debug("No connection, cleaning pipe");
CloseHandle(pipe);
}
}
});
// SetThreadDescription(ipcThread.native_handle(), L"Geode Main IPC");
ipcThread.detach();
log::debug("IPC set up");
}
bool Loader::Impl::userTriedToLoadDLLs() const { bool Loader::Impl::userTriedToLoadDLLs() const {
static std::unordered_set<std::string> KNOWN_MOD_DLLS { static std::unordered_set<std::string> KNOWN_MOD_DLLS {
"betteredit-v4.0.5.dll", "betteredit-v4.0.5.dll",
@ -235,5 +74,3 @@ bool Loader::Impl::userTriedToLoadDLLs() const {
return triedToLoadDLLs; return triedToLoadDLLs;
} }
#endif

View file

@ -1,7 +1,5 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_WINDOWS
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <loader/ModImpl.hpp> #include <loader/ModImpl.hpp>
@ -81,5 +79,3 @@ Result<> Mod::Impl::unloadPlatformBinary() {
return Err("Unable to free the DLL: " + getLastWinError()); return Err("Unable to free the DLL: " + getLastWinError());
} }
} }
#endif

View file

@ -0,0 +1,96 @@
#include <loader/console.hpp>
#include <loader/LogImpl.hpp>
#include <iostream>
using namespace geode::prelude;
bool s_isOpen = false;
bool s_hasAnsiColorSupport = false;
void console::open() {
if (s_isOpen) return;
if (AllocConsole() == 0) return;
SetConsoleCP(CP_UTF8);
// redirect console output
freopen_s(reinterpret_cast<FILE**>(stdout), "CONOUT$", "w", stdout);
freopen_s(reinterpret_cast<FILE**>(stdin), "CONIN$", "r", stdin);
// Set output mode to handle ansi color sequences
auto handleStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD consoleMode = 0;
if (GetConsoleMode(handleStdout, &consoleMode)) {
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (SetConsoleMode(handleStdout, consoleMode)) {
s_hasAnsiColorSupport = true;
}
}
s_isOpen = true;
for (auto const& log : log::Logger::get()->list()) {
console::log(log.toString(true), log.getSeverity());
}
}
void console::close() {
if (!s_isOpen) return;
fclose(stdin);
fclose(stdout);
FreeConsole();
s_isOpen = false;
}
void console::log(std::string const& msg, Severity severity) {
if (!s_isOpen)
return;
if (!s_hasAnsiColorSupport) {
std::cout << msg << "\n" << std::flush;
return;
}
int color = 0;
switch (severity) {
case Severity::Debug:
color = 243;
break;
case Severity::Info:
color = 33;
break;
case Severity::Warning:
color = 229;
break;
case Severity::Error:
color = 9;
break;
default:
color = 7;
break;
}
auto const colorStr = fmt::format("\x1b[38;5;{}m", color);
auto const newMsg = fmt::format("{}{}\x1b[0m{}", colorStr, msg.substr(0, 12),
msg.substr(12));
std::cout << newMsg << "\n" << std::flush;
}
void console::messageBox(char const* title, std::string const& info, Severity severity) {
unsigned int icon;
switch (severity) {
case Severity::Debug:
case Severity::Info:
case Severity::Notice:
icon = MB_ICONINFORMATION;
break;
case Severity::Warning:
icon = MB_ICONWARNING;
break;
default:
icon = MB_ICONERROR;
break;
}
MessageBoxA(nullptr, info.c_str(), title, icon);
}

View file

@ -2,8 +2,6 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_WINDOWS
#include <crashlog.hpp> #include <crashlog.hpp>
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
#include <Geode/loader/Loader.hpp> #include <Geode/loader/Loader.hpp>
@ -301,5 +299,3 @@ void crashlog::setupPlatformHandlerPost() {}
ghc::filesystem::path crashlog::getCrashLogDirectory() { ghc::filesystem::path crashlog::getCrashLogDirectory() {
return dirs::getGeodeDir() / "crashlogs"; return dirs::getGeodeDir() / "crashlogs";
} }
#endif

View file

@ -1,7 +1,5 @@
#include "../../c++stl/string-impl.hpp" #include "../../c++stl/string-impl.hpp"
#ifdef GEODE_IS_WINDOWS
namespace geode::stl { namespace geode::stl {
void StringImpl::setEmpty() { void StringImpl::setEmpty() {
data.m_size = 0; data.m_size = 0;
@ -43,5 +41,3 @@ namespace geode::stl {
data.m_capacity = cap; data.m_capacity = cap;
} }
} }
#endif

View file

@ -1,11 +1,11 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#if defined(GEODE_IS_WINDOWS)
#include "../load.hpp" #include "../load.hpp"
#include <Windows.h> #include <Windows.h>
#include "loader/LoaderImpl.hpp" #include "loader/LoaderImpl.hpp"
#include "loader/console.hpp"
using namespace geode::prelude; using namespace geode::prelude;
void updateGeode() { void updateGeode() {
@ -38,7 +38,7 @@ int WINAPI gdMainHook(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
updateGeode(); updateGeode();
if (versionToTimestamp(GEODE_STR(GEODE_GD_VERSION)) > gdTimestamp) { if (versionToTimestamp(GEODE_STR(GEODE_GD_VERSION)) > gdTimestamp) {
LoaderImpl::get()->platformMessageBox( console::messageBox(
"Unable to Load Geode!", "Unable to Load Geode!",
fmt::format( fmt::format(
"This version of Geode is made for Geometry Dash {} " "This version of Geode is made for Geometry Dash {} "
@ -142,7 +142,7 @@ void earlyError(std::string message) {
std::ofstream fout("_geode_early_error.txt"); std::ofstream fout("_geode_early_error.txt");
fout << message; fout << message;
fout.close(); fout.close();
LoaderImpl::get()->platformMessageBox("Unable to Load Geode!", message); console::messageBox("Unable to Load Geode!", message);
} }
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) { BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) {
@ -176,5 +176,3 @@ BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) {
return TRUE; return TRUE;
} }
#endif

View file

@ -1,8 +1,6 @@
#include "nfdwin.hpp" #include "nfdwin.hpp"
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
#ifdef GEODE_IS_WINDOWS
using Path = ghc::filesystem::path; using Path = ghc::filesystem::path;
using Paths = std::vector<ghc::filesystem::path>; using Paths = std::vector<ghc::filesystem::path>;
@ -296,5 +294,3 @@ Result<> nfdPick(
return Err("Unknown error"); return Err("Unknown error");
} }
#endif

View file

@ -10,8 +10,6 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_WINDOWS
#ifdef __MINGW32__ #ifdef __MINGW32__
// Explicitly setting NTDDI version, this is necessary for the MinGW compiler // Explicitly setting NTDDI version, this is necessary for the MinGW compiler
#define NTDDI_VERSION NTDDI_VISTA #define NTDDI_VERSION NTDDI_VISTA
@ -58,5 +56,3 @@ Result<> nfdPick(
file::FilePickOptions const& options, file::FilePickOptions const& options,
void* result void* result
); );
#endif

View file

@ -1,9 +1,7 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_WINDOWS
using namespace geode::prelude; using namespace geode::prelude;
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
#include "nfdwin.hpp" #include "nfdwin.hpp"
#include <ghc/fs_fwd.hpp> #include <ghc/fs_fwd.hpp>
@ -265,5 +263,3 @@ Result<> geode::hook::addObjcMethod(std::string const& className, std::string co
Result<void*> geode::hook::getObjcMethodImp(std::string const& className, std::string const& selectorName) { Result<void*> geode::hook::getObjcMethodImp(std::string const& className, std::string const& selectorName) {
return Err("Wrong platform"); return Err("Wrong platform");
} }
#endif