implement threaded unzipping and revert typeinfo cast (but its ugly)

This commit is contained in:
altalk23 2023-10-02 13:37:09 +03:00
parent 877b644962
commit 777cf38df0
8 changed files with 133 additions and 37 deletions

View file

@ -32,7 +32,8 @@ namespace geode {
LoadFailed,
EnableFailed,
MissingDependency,
PresentIncompatibility
PresentIncompatibility,
UnzipFailed
};
Type type;
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;

View file

@ -2,8 +2,6 @@
#include <dlfcn.h>
#include "ItaniumCast.hpp"
namespace geode {
struct PlatformInfo {
void* m_so;
@ -13,3 +11,11 @@ namespace geode {
namespace geode::base {
/*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);
}
}

View file

@ -9,30 +9,38 @@ using namespace geode::prelude;
struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
CCLabelBMFont* m_smallLabel = nullptr;
CCLabelBMFont* m_smallLabel2 = nullptr;
int m_geodeLoadStep = 0;
int m_totalMods = 0;
void updateLoadedModsLabel() {
auto allMods = Loader::get()->getAllMods();
auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
return item->isEnabled();
});
auto totalCount = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
return item->shouldLoad();
});
auto str = fmt::format("Geode: Loaded {}/{} mods", count, totalCount);
auto str = fmt::format("Geode: Loaded {}/{} mods", count, m_totalMods);
this->setSmallText(str);
auto currentMod = LoaderImpl::get()->m_currentlyLoadingMod;
auto modName = currentMod ? currentMod->getName() : "Unknown";
this->setSmallText2(modName);
}
void setSmallText(std::string const& text) {
m_fields->m_smallLabel->setString(text.c_str());
}
void setSmallText2(std::string const& text) {
m_fields->m_smallLabel2->setString(text.c_str());
}
// hook
bool init(bool fromReload) {
CCFileUtils::get()->updatePaths();
if (!LoadingLayer::init(fromReload)) return false;
m_totalMods = Loader::get()->getAllMods().size();
auto winSize = CCDirector::sharedDirector()->getWinSize();
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");
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;
}
@ -51,6 +65,7 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
}
else {
this->continueLoadAssets();
this->setSmallText2("");
}
}
@ -108,11 +123,11 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
}
int getCurrentStep() {
return m_fields->m_geodeLoadStep + m_loadStep + 1;
return m_fields->m_geodeLoadStep + m_loadStep + 1 + LoaderImpl::get()->m_refreshedModCount;
}
int getTotalStep() {
return 18;
return 18 + m_totalMods;
}
void updateLoadingBar() {

View file

@ -388,7 +388,7 @@ void Loader::Impl::buildModGraph() {
void Loader::Impl::loadModGraph(Mod* node, bool early) {
if (early && !node->needsEarlyLoad()) {
m_modsToLoad.push(node);
m_modsToLoad.push_back(node);
return;
}
@ -402,32 +402,82 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
if (node->isEnabled()) {
for (auto const& dep : node->m_impl->m_dependants) {
this->loadModGraph(dep, early);
m_modsToLoad.push_front(dep);
}
log::popNest();
return;
}
if (node->shouldLoad()) {
log::debug("Load");
auto res = node->m_impl->loadBinary();
m_currentlyLoadingMod = node;
m_refreshingModCount += 1;
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) {
m_problems.push_back({
LoadProblem::Type::LoadFailed,
LoadProblem::Type::UnzipFailed,
node,
res.unwrapErr()
});
log::error("Failed to load binary: {}", res.unwrapErr());
log::error("Failed to unzip: {}", res.unwrapErr());
log::popNest();
m_refreshingModCount -= 1;
return;
}
for (auto const& dep : node->m_impl->m_dependants) {
this->loadModGraph(dep, early);
}
loadFunction();
}
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() {
@ -568,12 +618,19 @@ void Loader::Impl::refreshModGraph() {
else
m_loadingState = LoadingState::Mods;
queueInMainThread([]() {
Loader::get()->m_impl->continueRefreshModGraph();
queueInMainThread([&]() {
this->continueRefreshModGraph();
});
}
void Loader::Impl::continueRefreshModGraph() {
if (m_refreshingModCount != 0) {
queueInMainThread([&]() {
this->continueRefreshModGraph();
});
return;
}
log::info("Continuing mod graph refresh...");
log::pushNest();
@ -585,7 +642,7 @@ void Loader::Impl::continueRefreshModGraph() {
log::pushNest();
this->loadModGraph(m_modsToLoad.front(), false);
log::popNest();
m_modsToLoad.pop();
m_modsToLoad.pop_front();
if (m_modsToLoad.empty())
m_loadingState = LoadingState::Problems;
break;
@ -608,8 +665,8 @@ void Loader::Impl::continueRefreshModGraph() {
log::info("Took {}s", static_cast<float>(time) / 1000.f);
if (m_loadingState != LoadingState::Done) {
queueInMainThread([]() {
Loader::get()->m_impl->continueRefreshModGraph();
queueInMainThread([&]() {
this->continueRefreshModGraph();
});
}

View file

@ -58,7 +58,7 @@ namespace geode {
std::vector<ghc::filesystem::path> m_modSearchDirectories;
std::vector<LoadProblem> m_problems;
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;
bool m_isSetup = false;
@ -83,6 +83,11 @@ namespace geode {
std::mutex m_nextModAccessMutex;
Mod* m_nextMod = nullptr;
Mod* m_currentlyLoadingMod = nullptr;
int m_refreshingModCount = 0;
int m_refreshedModCount = 0;
void provideNextMod(Mod* mod);
Mod* takeNextMod();
void releaseNextMod();

View file

@ -568,21 +568,25 @@ Result<> Mod::Impl::createTempDir() {
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
m_tempDirName = tempPath;
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 {
auto dir = dirs::getModConfigDir() / m_metadata.getID();
if (create) {

View file

@ -75,6 +75,9 @@ namespace geode {
Result<> unloadPlatformBinary();
Result<> createTempDir();
// called on a separate thread
Result<> unzipGeodeFile(ModMetadata metadata);
void setupSettings();
std::string getID() const;

View file

@ -87,6 +87,11 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
icon = "info-alert.png"_spr;
message = fmt::format("{} is incompatible with {}", cause, problem.message);
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);