mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
Remove runtime enable/disable, requires cleanup
This commit is contained in:
parent
e78eaf01e8
commit
d81774957d
6 changed files with 88 additions and 140 deletions
|
@ -33,6 +33,13 @@ namespace geode {
|
|||
~HandleToSaved();
|
||||
};
|
||||
|
||||
enum class ModRequestedAction {
|
||||
None,
|
||||
Enable,
|
||||
Disable,
|
||||
Uninstall,
|
||||
};
|
||||
|
||||
GEODE_HIDDEN Mod* takeNextLoaderMod();
|
||||
|
||||
class ModImpl;
|
||||
|
@ -337,6 +344,8 @@ namespace geode {
|
|||
Result<> uninstall();
|
||||
bool isUninstalled() const;
|
||||
|
||||
ModRequestedAction getRequestedAction() const;
|
||||
|
||||
/**
|
||||
* Check whether or not this Mod
|
||||
* depends on another mod
|
||||
|
|
|
@ -166,7 +166,6 @@ bool Loader::Impl::isModVersionSupported(VersionInfo const& version) {
|
|||
Result<> Loader::Impl::saveData() {
|
||||
// save mods' data
|
||||
for (auto& [id, mod] : m_mods) {
|
||||
Mod::get()->setSavedValue("should-load-" + id, mod->isUninstalled() || mod->isEnabled());
|
||||
auto r = mod->saveData();
|
||||
if (!r) {
|
||||
log::warn("Unable to save data for mod \"{}\": {}", mod->getID(), r.unwrapErr());
|
||||
|
@ -411,31 +410,16 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
|
|||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mod::get()->getSavedValue<bool>("should-load-" + node->getID(), true)) {
|
||||
log::debug("Enable");
|
||||
res = node->m_impl->enable();
|
||||
log::debug("Load");
|
||||
auto res = node->m_impl->loadBinary();
|
||||
if (!res) {
|
||||
node->m_impl->m_enabled = true;
|
||||
(void)node->m_impl->disable();
|
||||
m_problems.push_back({
|
||||
LoadProblem::Type::EnableFailed,
|
||||
LoadProblem::Type::LoadFailed,
|
||||
node,
|
||||
res.unwrapErr()
|
||||
});
|
||||
log::error("Failed to enable: {}", res.unwrapErr());
|
||||
log::error("Failed to load binary: {}", res.unwrapErr());
|
||||
log::popNest();
|
||||
return;
|
||||
}
|
||||
|
@ -509,19 +493,19 @@ void Loader::Impl::findProblems() {
|
|||
|
||||
Mod* myEpicMod = mod; // clang fix
|
||||
// if the mod is not loaded but there are no problems related to it
|
||||
if (!mod->isLoaded() && !std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) {
|
||||
return std::holds_alternative<ModMetadata>(item.cause) &&
|
||||
std::get<ModMetadata>(item.cause).getID() == myEpicMod->getID() ||
|
||||
std::holds_alternative<Mod*>(item.cause) &&
|
||||
std::get<Mod*>(item.cause) == myEpicMod;
|
||||
})) {
|
||||
m_problems.push_back({
|
||||
LoadProblem::Type::Unknown,
|
||||
mod,
|
||||
""
|
||||
});
|
||||
log::error("{} failed to load for an unknown reason", id);
|
||||
}
|
||||
// if (!mod->isLoaded() && !std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) {
|
||||
// return std::holds_alternative<ModMetadata>(item.cause) &&
|
||||
// std::get<ModMetadata>(item.cause).getID() == myEpicMod->getID() ||
|
||||
// std::holds_alternative<Mod*>(item.cause) &&
|
||||
// std::get<Mod*>(item.cause) == myEpicMod;
|
||||
// })) {
|
||||
// m_problems.push_back({
|
||||
// LoadProblem::Type::Unknown,
|
||||
// mod,
|
||||
// ""
|
||||
// });
|
||||
// log::error("{} failed to load for an unknown reason", id);
|
||||
// }
|
||||
|
||||
log::popNest();
|
||||
}
|
||||
|
@ -533,7 +517,7 @@ void Loader::Impl::refreshModGraph() {
|
|||
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (m_mods.size() > 1) {
|
||||
if (m_isSetup) {
|
||||
log::error("Cannot refresh mod graph after startup");
|
||||
log::popNest();
|
||||
return;
|
||||
|
@ -564,7 +548,7 @@ void Loader::Impl::refreshModGraph() {
|
|||
m_loadingState = LoadingState::EarlyMods;
|
||||
log::debug("Loading early mods");
|
||||
log::pushNest();
|
||||
for (auto const& dep : Mod::get()->m_impl->m_dependants) {
|
||||
for (auto const& dep : ModImpl::get()->m_dependants) {
|
||||
this->loadModGraph(dep, true);
|
||||
}
|
||||
log::popNest();
|
||||
|
|
|
@ -198,6 +198,10 @@ bool Mod::isUninstalled() const {
|
|||
return m_impl->isUninstalled();
|
||||
}
|
||||
|
||||
ModRequestedAction Mod::getRequestedAction() const {
|
||||
return m_impl->getRequestedAction();
|
||||
}
|
||||
|
||||
bool Mod::depends(std::string const& id) const {
|
||||
return m_impl->depends(id);
|
||||
}
|
||||
|
|
|
@ -117,23 +117,15 @@ bool Mod::Impl::isLoaded() const {
|
|||
}
|
||||
|
||||
bool Mod::Impl::supportsDisabling() const {
|
||||
return m_metadata.getID() != "geode.loader" && !m_metadata.isAPI();
|
||||
return m_metadata.getID() != "geode.loader";
|
||||
}
|
||||
|
||||
bool Mod::Impl::canDisable() const {
|
||||
auto deps = m_dependants;
|
||||
return this->supportsDisabling() &&
|
||||
(deps.empty() || std::all_of(deps.begin(), deps.end(), [&](auto& item) {
|
||||
return item->canDisable();
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::Impl::canEnable() const {
|
||||
auto deps = m_metadata.getDependencies();
|
||||
return !this->isUninstalled() &&
|
||||
(deps.empty() || std::all_of(deps.begin(), deps.end(), [&](auto& item) {
|
||||
return item.isResolved();
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::Impl::needsEarlyLoad() const {
|
||||
|
@ -343,33 +335,9 @@ Result<> Mod::Impl::loadBinary() {
|
|||
}
|
||||
m_binaryLoaded = true;
|
||||
|
||||
LoaderImpl::get()->releaseNextMod();
|
||||
|
||||
ModStateEvent(m_self, ModEventType::Loaded).post();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Mod::Impl::enable() {
|
||||
if (!m_binaryLoaded)
|
||||
return Err("Tried to enable {} but its binary is not loaded", m_metadata.getID());
|
||||
|
||||
bool enabledDependencies = true;
|
||||
for (auto const& item : m_metadata.getDependencies()) {
|
||||
if (!item.isResolved() || !item.mod)
|
||||
continue;
|
||||
auto res = item.mod->enable();
|
||||
if (!res) {
|
||||
enabledDependencies = false;
|
||||
log::error("Failed to enable {}: {}", item.id, res.unwrapErr());
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabledDependencies)
|
||||
return Err("Mod cannot be enabled because one or more of its dependencies cannot be enabled.");
|
||||
|
||||
if (!this->canEnable())
|
||||
return Err("Mod cannot be enabled because it has unresolved dependencies.");
|
||||
LoaderImpl::get()->releaseNextMod();
|
||||
|
||||
for (auto const& hook : m_hooks) {
|
||||
if (!hook) {
|
||||
|
@ -377,7 +345,10 @@ Result<> Mod::Impl::enable() {
|
|||
continue;
|
||||
}
|
||||
if (hook->getAutoEnable()) {
|
||||
GEODE_UNWRAP(this->enableHook(hook));
|
||||
auto res = this->enableHook(hook);
|
||||
if (!res) {
|
||||
log::error("Can't enable hook {} for mod {}: {}", hook->getDisplayName(), m_metadata.getID(), res.unwrapErr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,75 +360,46 @@ Result<> Mod::Impl::enable() {
|
|||
}
|
||||
|
||||
m_enabled = true;
|
||||
|
||||
ModStateEvent(m_self, ModEventType::Enabled).post();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Mod::Impl::enable() {
|
||||
if (m_requestedAction != ModRequestedAction::None) {
|
||||
return Err("Mod already has a requested action");
|
||||
}
|
||||
|
||||
m_requestedAction = ModRequestedAction::Enable;
|
||||
Mod::get()->setSavedValue("should-load-" + m_metadata.getID(), true);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Mod::Impl::disable() {
|
||||
if (!m_enabled)
|
||||
return Ok();
|
||||
|
||||
if (!this->supportsDisabling())
|
||||
return Err("Mod does not support disabling.");
|
||||
|
||||
if (!this->canDisable())
|
||||
return Err("Mod cannot be disabled because one or more of its dependants cannot be disabled.");
|
||||
|
||||
// disable dependants
|
||||
bool disabledDependants = true;
|
||||
for (auto& item : m_dependants) {
|
||||
auto res = item->disable();
|
||||
if (res)
|
||||
continue;
|
||||
disabledDependants = false;
|
||||
log::error("Failed to disable {}: {}", item->getID(), res.unwrapErr());
|
||||
if (m_requestedAction != ModRequestedAction::None) {
|
||||
return Err("Mod already has a requested action");
|
||||
}
|
||||
|
||||
if (!disabledDependants)
|
||||
return Err("Mod cannot be disabled because one or more of its dependants cannot be disabled.");
|
||||
|
||||
std::vector<std::string> errors;
|
||||
for (auto const& hook : m_hooks) {
|
||||
auto res = this->disableHook(hook);
|
||||
if (!res)
|
||||
errors.push_back(res.unwrapErr());
|
||||
}
|
||||
for (auto const& patch : m_patches) {
|
||||
auto res = this->unpatch(patch);
|
||||
if (!res)
|
||||
errors.push_back(res.unwrapErr());
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
ModStateEvent(m_self, ModEventType::Disabled).post();
|
||||
|
||||
if (!errors.empty())
|
||||
return Err(utils::string::join(errors, "\n"));
|
||||
m_requestedAction = ModRequestedAction::Disable;
|
||||
Mod::get()->setSavedValue("should-load-" + m_metadata.getID(), false);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Mod::Impl::uninstall() {
|
||||
if (supportsDisabling()) {
|
||||
GEODE_UNWRAP(this->disable());
|
||||
}
|
||||
else {
|
||||
for (auto& item : m_dependants) {
|
||||
if (!item->canDisable())
|
||||
continue;
|
||||
GEODE_UNWRAP(item->disable());
|
||||
}
|
||||
if (m_requestedAction != ModRequestedAction::None) {
|
||||
return Err("Mod already has a requested action");
|
||||
}
|
||||
|
||||
try {
|
||||
ghc::filesystem::remove(m_metadata.getPath());
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
m_requestedAction = ModRequestedAction::Uninstall;
|
||||
|
||||
std::error_code ec;
|
||||
ghc::filesystem::remove(m_metadata.getPath(), ec);
|
||||
if (ec) {
|
||||
return Err(
|
||||
"Unable to delete mod's .geode file! "
|
||||
"This might be due to insufficient permissions - "
|
||||
"try running GD as administrator."
|
||||
"Unable to delete mod's .geode file: " + ec.message()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -465,7 +407,11 @@ Result<> Mod::Impl::uninstall() {
|
|||
}
|
||||
|
||||
bool Mod::Impl::isUninstalled() const {
|
||||
return m_self != Mod::get() && !ghc::filesystem::exists(m_metadata.getPath());
|
||||
return m_requestedAction == ModRequestedAction::Uninstall;
|
||||
}
|
||||
|
||||
ModRequestedAction Mod::Impl::getRequestedAction() const {
|
||||
return m_requestedAction;
|
||||
}
|
||||
|
||||
// Dependencies
|
||||
|
@ -661,7 +607,7 @@ ModJson Mod::Impl::getRuntimeInfo() const {
|
|||
for (auto patch : m_patches) {
|
||||
obj["patches"].as_array().push_back(ModJson(patch->getRuntimeInfo()));
|
||||
}
|
||||
obj["enabled"] = m_enabled;
|
||||
// obj["enabled"] = m_enabled;
|
||||
obj["loaded"] = m_binaryLoaded;
|
||||
obj["temp-dir"] = this->getTempDir();
|
||||
obj["save-dir"] = this->getSaveDir();
|
||||
|
|
|
@ -62,6 +62,9 @@ namespace geode {
|
|||
*/
|
||||
bool m_resourcesLoaded = false;
|
||||
|
||||
|
||||
ModRequestedAction m_requestedAction = ModRequestedAction::None;
|
||||
|
||||
Impl(Mod* self, ModMetadata const& metadata);
|
||||
~Impl();
|
||||
|
||||
|
@ -122,6 +125,10 @@ namespace geode {
|
|||
Result<> disable();
|
||||
Result<> uninstall();
|
||||
bool isUninstalled() const;
|
||||
|
||||
// 1.3.0 additions
|
||||
ModRequestedAction getRequestedAction() const;
|
||||
|
||||
bool depends(std::string const& id) const;
|
||||
Result<> updateDependencies();
|
||||
bool hasUnresolvedDependencies() const;
|
||||
|
|
|
@ -227,11 +227,7 @@ void ModCell::onEnable(CCObject* sender) {
|
|||
else {
|
||||
tryOrAlert(m_mod->disable(), "Error disabling mod");
|
||||
}
|
||||
Loader::get()->queueInMainThread([this]() {
|
||||
if (m_layer) {
|
||||
m_layer->updateAllStates();
|
||||
}
|
||||
});
|
||||
m_layer->reloadList();
|
||||
}
|
||||
|
||||
void ModCell::onUnresolvedInfo(CCObject*) {
|
||||
|
@ -278,9 +274,9 @@ bool ModCell::init(
|
|||
return false;
|
||||
m_mod = mod;
|
||||
|
||||
this->setupInfo(mod->getMetadata(), false, display, m_mod->isUninstalled());
|
||||
this->setupInfo(mod->getMetadata(), false, display, mod->getRequestedAction() != ModRequestedAction::None);
|
||||
|
||||
if (mod->isUninstalled()) {
|
||||
if (mod->getRequestedAction() != ModRequestedAction::None) {
|
||||
auto restartSpr = ButtonSprite::create("Restart", "bigFont.fnt", "GJ_button_03.png", .8f);
|
||||
restartSpr->setScale(.65f);
|
||||
|
||||
|
@ -317,14 +313,16 @@ bool ModCell::init(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod->wasSuccessfullyLoaded()) {
|
||||
m_enableToggle =
|
||||
CCMenuItemToggler::createWithStandardSprites(this, menu_selector(ModCell::onEnable), .7f);
|
||||
m_enableToggle->setPosition(-45.f, 0.f);
|
||||
m_menu->addChild(m_enableToggle);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod->wasSuccessfullyLoaded() && m_mod->supportsDisabling() && !m_mod->isUninstalled()) {
|
||||
m_enableToggle =
|
||||
CCMenuItemToggler::createWithStandardSprites(this, menu_selector(ModCell::onEnable), .7f);
|
||||
m_enableToggle->setPosition(-45.f, 0.f);
|
||||
m_menu->addChild(m_enableToggle);
|
||||
}
|
||||
|
||||
|
||||
auto exMark = CCSprite::createWithSpriteFrameName("exMark_001.png");
|
||||
exMark->setScale(.5f);
|
||||
|
|
Loading…
Reference in a new issue