mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
implement threaded unzipping and revert typeinfo cast (but its ugly)
This commit is contained in:
parent
877b644962
commit
777cf38df0
8 changed files with 133 additions and 37 deletions
|
@ -32,7 +32,8 @@ namespace geode {
|
||||||
LoadFailed,
|
LoadFailed,
|
||||||
EnableFailed,
|
EnableFailed,
|
||||||
MissingDependency,
|
MissingDependency,
|
||||||
PresentIncompatibility
|
PresentIncompatibility,
|
||||||
|
UnzipFailed
|
||||||
};
|
};
|
||||||
Type type;
|
Type type;
|
||||||
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;
|
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include "ItaniumCast.hpp"
|
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
struct PlatformInfo {
|
struct PlatformInfo {
|
||||||
void* m_so;
|
void* m_so;
|
||||||
|
@ -13,3 +11,11 @@ namespace geode {
|
||||||
namespace geode::base {
|
namespace geode::base {
|
||||||
/*GEODE_NOINLINE inline*/ uintptr_t get();
|
/*GEODE_NOINLINE inline*/ uintptr_t get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace geode::cast {
|
||||||
|
template <class After, class Before>
|
||||||
|
After typeinfo_cast(Before ptr) {
|
||||||
|
// yall have symbols smh
|
||||||
|
return dynamic_cast<After>(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,30 +9,38 @@ using namespace geode::prelude;
|
||||||
|
|
||||||
struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
||||||
CCLabelBMFont* m_smallLabel = nullptr;
|
CCLabelBMFont* m_smallLabel = nullptr;
|
||||||
|
CCLabelBMFont* m_smallLabel2 = nullptr;
|
||||||
int m_geodeLoadStep = 0;
|
int m_geodeLoadStep = 0;
|
||||||
|
int m_totalMods = 0;
|
||||||
|
|
||||||
void updateLoadedModsLabel() {
|
void updateLoadedModsLabel() {
|
||||||
auto allMods = Loader::get()->getAllMods();
|
auto allMods = Loader::get()->getAllMods();
|
||||||
auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
|
auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
|
||||||
return item->isEnabled();
|
return item->isEnabled();
|
||||||
});
|
});
|
||||||
auto totalCount = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
|
auto str = fmt::format("Geode: Loaded {}/{} mods", count, m_totalMods);
|
||||||
return item->shouldLoad();
|
|
||||||
});
|
|
||||||
auto str = fmt::format("Geode: Loaded {}/{} mods", count, totalCount);
|
|
||||||
this->setSmallText(str);
|
this->setSmallText(str);
|
||||||
|
auto currentMod = LoaderImpl::get()->m_currentlyLoadingMod;
|
||||||
|
auto modName = currentMod ? currentMod->getName() : "Unknown";
|
||||||
|
this->setSmallText2(modName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSmallText(std::string const& text) {
|
void setSmallText(std::string const& text) {
|
||||||
m_fields->m_smallLabel->setString(text.c_str());
|
m_fields->m_smallLabel->setString(text.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSmallText2(std::string const& text) {
|
||||||
|
m_fields->m_smallLabel2->setString(text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// hook
|
// hook
|
||||||
bool init(bool fromReload) {
|
bool init(bool fromReload) {
|
||||||
CCFileUtils::get()->updatePaths();
|
CCFileUtils::get()->updatePaths();
|
||||||
|
|
||||||
if (!LoadingLayer::init(fromReload)) return false;
|
if (!LoadingLayer::init(fromReload)) return false;
|
||||||
|
|
||||||
|
m_totalMods = Loader::get()->getAllMods().size();
|
||||||
|
|
||||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||||
|
|
||||||
m_fields->m_smallLabel = CCLabelBMFont::create("", "goldFont.fnt");
|
m_fields->m_smallLabel = CCLabelBMFont::create("", "goldFont.fnt");
|
||||||
|
@ -41,6 +49,12 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
||||||
m_fields->m_smallLabel->setID("geode-small-label");
|
m_fields->m_smallLabel->setID("geode-small-label");
|
||||||
this->addChild(m_fields->m_smallLabel);
|
this->addChild(m_fields->m_smallLabel);
|
||||||
|
|
||||||
|
m_fields->m_smallLabel2 = CCLabelBMFont::create("", "goldFont.fnt");
|
||||||
|
m_fields->m_smallLabel2->setPosition(winSize.width / 2, 15.f);
|
||||||
|
m_fields->m_smallLabel2->setScale(.45f);
|
||||||
|
m_fields->m_smallLabel2->setID("geode-small-label");
|
||||||
|
this->addChild(m_fields->m_smallLabel2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +65,7 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->continueLoadAssets();
|
this->continueLoadAssets();
|
||||||
|
this->setSmallText2("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +123,11 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
int getCurrentStep() {
|
int getCurrentStep() {
|
||||||
return m_fields->m_geodeLoadStep + m_loadStep + 1;
|
return m_fields->m_geodeLoadStep + m_loadStep + 1 + LoaderImpl::get()->m_refreshedModCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTotalStep() {
|
int getTotalStep() {
|
||||||
return 18;
|
return 18 + m_totalMods;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLoadingBar() {
|
void updateLoadingBar() {
|
||||||
|
|
|
@ -388,7 +388,7 @@ void Loader::Impl::buildModGraph() {
|
||||||
|
|
||||||
void Loader::Impl::loadModGraph(Mod* node, bool early) {
|
void Loader::Impl::loadModGraph(Mod* node, bool early) {
|
||||||
if (early && !node->needsEarlyLoad()) {
|
if (early && !node->needsEarlyLoad()) {
|
||||||
m_modsToLoad.push(node);
|
m_modsToLoad.push_back(node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,32 +402,82 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
|
||||||
|
|
||||||
if (node->isEnabled()) {
|
if (node->isEnabled()) {
|
||||||
for (auto const& dep : node->m_impl->m_dependants) {
|
for (auto const& dep : node->m_impl->m_dependants) {
|
||||||
this->loadModGraph(dep, early);
|
m_modsToLoad.push_front(dep);
|
||||||
}
|
}
|
||||||
log::popNest();
|
log::popNest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->shouldLoad()) {
|
m_currentlyLoadingMod = node;
|
||||||
log::debug("Load");
|
m_refreshingModCount += 1;
|
||||||
auto res = node->m_impl->loadBinary();
|
m_refreshedModCount += 1;
|
||||||
|
|
||||||
|
auto unzipFunction = [this, node]() {
|
||||||
|
log::debug("Unzip");
|
||||||
|
auto res = node->m_impl->unzipGeodeFile(node->getMetadata());
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto loadFunction = [this, node, early]() {
|
||||||
|
if (node->shouldLoad()) {
|
||||||
|
log::debug("Load");
|
||||||
|
auto res = node->m_impl->loadBinary();
|
||||||
|
if (!res) {
|
||||||
|
m_problems.push_back({
|
||||||
|
LoadProblem::Type::LoadFailed,
|
||||||
|
node,
|
||||||
|
res.unwrapErr()
|
||||||
|
});
|
||||||
|
log::error("Failed to load binary: {}", res.unwrapErr());
|
||||||
|
log::popNest();
|
||||||
|
m_refreshingModCount -= 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& dep : node->m_impl->m_dependants) {
|
||||||
|
m_modsToLoad.push_front(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_refreshingModCount -= 1;
|
||||||
|
|
||||||
|
log::popNest();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (early) {
|
||||||
|
auto res = unzipFunction();
|
||||||
if (!res) {
|
if (!res) {
|
||||||
m_problems.push_back({
|
m_problems.push_back({
|
||||||
LoadProblem::Type::LoadFailed,
|
LoadProblem::Type::UnzipFailed,
|
||||||
node,
|
node,
|
||||||
res.unwrapErr()
|
res.unwrapErr()
|
||||||
});
|
});
|
||||||
log::error("Failed to load binary: {}", res.unwrapErr());
|
log::error("Failed to unzip: {}", res.unwrapErr());
|
||||||
log::popNest();
|
log::popNest();
|
||||||
|
m_refreshingModCount -= 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
loadFunction();
|
||||||
for (auto const& dep : node->m_impl->m_dependants) {
|
}
|
||||||
this->loadModGraph(dep, early);
|
else {
|
||||||
}
|
std::thread([=]() {
|
||||||
|
auto res = unzipFunction();
|
||||||
|
queueInMainThread([=]() {
|
||||||
|
if (!res) {
|
||||||
|
m_problems.push_back({
|
||||||
|
LoadProblem::Type::UnzipFailed,
|
||||||
|
node,
|
||||||
|
res.unwrapErr()
|
||||||
|
});
|
||||||
|
log::error("Failed to unzip: {}", res.unwrapErr());
|
||||||
|
log::popNest();
|
||||||
|
m_refreshingModCount -= 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadFunction();
|
||||||
|
});
|
||||||
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
log::popNest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loader::Impl::findProblems() {
|
void Loader::Impl::findProblems() {
|
||||||
|
@ -568,12 +618,19 @@ void Loader::Impl::refreshModGraph() {
|
||||||
else
|
else
|
||||||
m_loadingState = LoadingState::Mods;
|
m_loadingState = LoadingState::Mods;
|
||||||
|
|
||||||
queueInMainThread([]() {
|
queueInMainThread([&]() {
|
||||||
Loader::get()->m_impl->continueRefreshModGraph();
|
this->continueRefreshModGraph();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loader::Impl::continueRefreshModGraph() {
|
void Loader::Impl::continueRefreshModGraph() {
|
||||||
|
if (m_refreshingModCount != 0) {
|
||||||
|
queueInMainThread([&]() {
|
||||||
|
this->continueRefreshModGraph();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log::info("Continuing mod graph refresh...");
|
log::info("Continuing mod graph refresh...");
|
||||||
log::pushNest();
|
log::pushNest();
|
||||||
|
|
||||||
|
@ -585,7 +642,7 @@ void Loader::Impl::continueRefreshModGraph() {
|
||||||
log::pushNest();
|
log::pushNest();
|
||||||
this->loadModGraph(m_modsToLoad.front(), false);
|
this->loadModGraph(m_modsToLoad.front(), false);
|
||||||
log::popNest();
|
log::popNest();
|
||||||
m_modsToLoad.pop();
|
m_modsToLoad.pop_front();
|
||||||
if (m_modsToLoad.empty())
|
if (m_modsToLoad.empty())
|
||||||
m_loadingState = LoadingState::Problems;
|
m_loadingState = LoadingState::Problems;
|
||||||
break;
|
break;
|
||||||
|
@ -608,8 +665,8 @@ void Loader::Impl::continueRefreshModGraph() {
|
||||||
log::info("Took {}s", static_cast<float>(time) / 1000.f);
|
log::info("Took {}s", static_cast<float>(time) / 1000.f);
|
||||||
|
|
||||||
if (m_loadingState != LoadingState::Done) {
|
if (m_loadingState != LoadingState::Done) {
|
||||||
queueInMainThread([]() {
|
queueInMainThread([&]() {
|
||||||
Loader::get()->m_impl->continueRefreshModGraph();
|
this->continueRefreshModGraph();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace geode {
|
||||||
std::vector<ghc::filesystem::path> m_modSearchDirectories;
|
std::vector<ghc::filesystem::path> m_modSearchDirectories;
|
||||||
std::vector<LoadProblem> m_problems;
|
std::vector<LoadProblem> m_problems;
|
||||||
std::unordered_map<std::string, Mod*> m_mods;
|
std::unordered_map<std::string, Mod*> m_mods;
|
||||||
std::queue<Mod*> m_modsToLoad;
|
std::deque<Mod*> m_modsToLoad;
|
||||||
std::vector<ghc::filesystem::path> m_texturePaths;
|
std::vector<ghc::filesystem::path> m_texturePaths;
|
||||||
bool m_isSetup = false;
|
bool m_isSetup = false;
|
||||||
|
|
||||||
|
@ -83,6 +83,11 @@ namespace geode {
|
||||||
std::mutex m_nextModAccessMutex;
|
std::mutex m_nextModAccessMutex;
|
||||||
Mod* m_nextMod = nullptr;
|
Mod* m_nextMod = nullptr;
|
||||||
|
|
||||||
|
Mod* m_currentlyLoadingMod = nullptr;
|
||||||
|
|
||||||
|
int m_refreshingModCount = 0;
|
||||||
|
int m_refreshedModCount = 0;
|
||||||
|
|
||||||
void provideNextMod(Mod* mod);
|
void provideNextMod(Mod* mod);
|
||||||
Mod* takeNextMod();
|
Mod* takeNextMod();
|
||||||
void releaseNextMod();
|
void releaseNextMod();
|
||||||
|
|
|
@ -568,21 +568,25 @@ Result<> Mod::Impl::createTempDir() {
|
||||||
return Err("Unable to create mod runtime directory");
|
return Err("Unable to create mod runtime directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unzip .geode file into temp dir
|
|
||||||
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_metadata.getPath()));
|
|
||||||
if (!unzip.hasEntry(m_metadata.getBinaryName())) {
|
|
||||||
return Err(
|
|
||||||
fmt::format("Unable to find platform binary under the name \"{}\"", m_metadata.getBinaryName())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
GEODE_UNWRAP(unzip.extractAllTo(tempPath));
|
|
||||||
|
|
||||||
// Mark temp dir creation as succesful
|
// Mark temp dir creation as succesful
|
||||||
m_tempDirName = tempPath;
|
m_tempDirName = tempPath;
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<> Mod::Impl::unzipGeodeFile(ModMetadata metadata) {
|
||||||
|
// Unzip .geode file into temp dir
|
||||||
|
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(metadata.getPath()));
|
||||||
|
if (!unzip.hasEntry(metadata.getBinaryName())) {
|
||||||
|
return Err(
|
||||||
|
fmt::format("Unable to find platform binary under the name \"{}\"", metadata.getBinaryName())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GEODE_UNWRAP(unzip.extractAllTo(dirs::getModRuntimeDir() / metadata.getID()));
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const {
|
ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const {
|
||||||
auto dir = dirs::getModConfigDir() / m_metadata.getID();
|
auto dir = dirs::getModConfigDir() / m_metadata.getID();
|
||||||
if (create) {
|
if (create) {
|
||||||
|
|
|
@ -75,6 +75,9 @@ namespace geode {
|
||||||
Result<> unloadPlatformBinary();
|
Result<> unloadPlatformBinary();
|
||||||
Result<> createTempDir();
|
Result<> createTempDir();
|
||||||
|
|
||||||
|
// called on a separate thread
|
||||||
|
Result<> unzipGeodeFile(ModMetadata metadata);
|
||||||
|
|
||||||
void setupSettings();
|
void setupSettings();
|
||||||
|
|
||||||
std::string getID() const;
|
std::string getID() const;
|
||||||
|
|
|
@ -87,6 +87,11 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
|
||||||
icon = "info-alert.png"_spr;
|
icon = "info-alert.png"_spr;
|
||||||
message = fmt::format("{} is incompatible with {}", cause, problem.message);
|
message = fmt::format("{} is incompatible with {}", cause, problem.message);
|
||||||
break;
|
break;
|
||||||
|
case LoadProblem::Type::UnzipFailed:
|
||||||
|
icon = "info-alert.png"_spr;
|
||||||
|
message = fmt::format("{} has failed unzipping", cause);
|
||||||
|
m_longMessage = problem.message;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_problem = std::move(problem);
|
m_problem = std::move(problem);
|
||||||
|
|
Loading…
Reference in a new issue