mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-23 07:57:51 -05:00
refactor to move all ModItems to one monolithic class rather than subclasses
This commit is contained in:
parent
5e8306ac65
commit
65f6158774
9 changed files with 231 additions and 198 deletions
|
@ -2,12 +2,13 @@
|
|||
#include <Geode/ui/GeodeUI.hpp>
|
||||
#include <Geode/utils/ColorProvider.hpp>
|
||||
#include "GeodeStyle.hpp"
|
||||
#include "ModPopup.hpp"
|
||||
|
||||
bool BaseModItem::init() {
|
||||
bool ModItem::init(ModSource&& source) {
|
||||
if (!CCNode::init())
|
||||
return false;
|
||||
|
||||
auto meta = this->getMetadata();
|
||||
m_source = std::move(source);
|
||||
|
||||
m_bg = CCScale9Sprite::create("square02b_small.png");
|
||||
m_bg->setOpacity(0);
|
||||
|
@ -16,7 +17,7 @@ bool BaseModItem::init() {
|
|||
m_bg->setScale(.7f);
|
||||
this->addChild(m_bg);
|
||||
|
||||
m_logo = this->createModLogo();
|
||||
m_logo = m_source.createModLogo();
|
||||
this->addChild(m_logo);
|
||||
|
||||
m_infoContainer = CCNode::create();
|
||||
|
@ -38,7 +39,7 @@ bool BaseModItem::init() {
|
|||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
|
||||
m_titleLabel = CCLabelBMFont::create(meta.getName().c_str(), "bigFont.fnt");
|
||||
m_titleLabel = CCLabelBMFont::create(m_source.getMetadata().getName().c_str(), "bigFont.fnt");
|
||||
m_titleLabel->setAnchorPoint({ .0f, .5f });
|
||||
m_titleLabel->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
|
@ -52,7 +53,7 @@ bool BaseModItem::init() {
|
|||
m_developers->ignoreAnchorPointForPosition(false);
|
||||
m_developers->setAnchorPoint({ .0f, .5f });
|
||||
|
||||
auto by = "By " + ModMetadata::formatDeveloperDisplayString(this->getMetadata().getDevelopers());
|
||||
auto by = "By " + ModMetadata::formatDeveloperDisplayString(m_source.getMetadata().getDevelopers());
|
||||
m_developerLabel = CCLabelBMFont::create(by.c_str(), "goldFont.fnt");
|
||||
auto developersBtn = CCMenuItemSpriteExtra::create(
|
||||
m_developerLabel, this, nullptr
|
||||
|
@ -83,7 +84,8 @@ bool BaseModItem::init() {
|
|||
m_viewMenu->setScale(.55f);
|
||||
|
||||
auto viewBtn = CCMenuItemSpriteExtra::create(
|
||||
createGeodeButton("View"), this, nullptr
|
||||
createGeodeButton("View"),
|
||||
this, menu_selector(ModItem::onView)
|
||||
);
|
||||
m_viewMenu->addChild(viewBtn);
|
||||
|
||||
|
@ -95,19 +97,64 @@ bool BaseModItem::init() {
|
|||
);
|
||||
this->addChildAtPosition(m_viewMenu, Anchor::Right, ccp(-10, 0));
|
||||
|
||||
// Handle source-specific stuff
|
||||
m_source.visit(makeVisitor {
|
||||
[this](Mod* mod) {
|
||||
// Add an enable button if the mod is enablable
|
||||
if (!mod->isInternal()) {
|
||||
m_enableToggle = CCMenuItemToggler::createWithStandardSprites(
|
||||
this, menu_selector(ModItem::onEnable), 1.f
|
||||
);
|
||||
// Manually handle toggle state
|
||||
m_enableToggle->m_notClickable = true;
|
||||
m_viewMenu->addChild(m_enableToggle);
|
||||
m_viewMenu->updateLayout();
|
||||
}
|
||||
},
|
||||
[this](server::ServerModMetadata const& metadata) {
|
||||
if (metadata.featured) {
|
||||
m_checkmark = CCScale9Sprite::createWithSpriteFrameName("GJ_colorBtn_001.png");
|
||||
m_checkmark->setContentSize({ 50, 38 });
|
||||
m_checkmark->setColor({ 255, 255, 120 });
|
||||
m_checkmark->setOpacity(45);
|
||||
|
||||
auto tick = CCSprite::createWithSpriteFrameName("GJ_starsIcon_001.png");
|
||||
m_checkmark->addChildAtPosition(tick, Anchor::Center);
|
||||
|
||||
m_titleContainer->addChild(m_checkmark);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseModItem::updateState() {
|
||||
auto wantsRestart = this->wantsRestart();
|
||||
void ModItem::updateState() {
|
||||
auto wantsRestart = m_source.wantsRestart();
|
||||
m_restartRequiredLabel->setVisible(wantsRestart);
|
||||
m_developers->setVisible(!wantsRestart);
|
||||
m_infoContainer->updateLayout();
|
||||
|
||||
// Set default color to BG to start off with
|
||||
// Set default colors based on source to start off with
|
||||
// (possibly overriding later based on state)
|
||||
m_bg->setColor(to3B(m_defaultBG));
|
||||
m_bg->setOpacity(m_defaultBG.a);
|
||||
m_source.visit(makeVisitor {
|
||||
[this](Mod* mod) {
|
||||
m_bg->setColor({ 255, 255, 255 });
|
||||
m_bg->setOpacity(mod->isOrWillBeEnabled() ? 25 : 10);
|
||||
m_titleLabel->setOpacity(mod->isOrWillBeEnabled() ? 255 : 155);
|
||||
m_developerLabel->setOpacity(mod->isOrWillBeEnabled() ? 255 : 155);
|
||||
},
|
||||
[this](server::ServerModMetadata const& metadata) {
|
||||
m_bg->setColor({ 255, 255, 255 });
|
||||
m_bg->setOpacity(25);
|
||||
if (metadata.featured && m_checkmark) {
|
||||
m_bg->setColor(m_checkmark->getColor());
|
||||
m_bg->setOpacity(40);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Highlight item via BG if it wants to restart for extra UI attention
|
||||
if (wantsRestart) {
|
||||
|
@ -119,9 +166,14 @@ void BaseModItem::updateState() {
|
|||
if (m_updateParentState) {
|
||||
m_updateParentState();
|
||||
}
|
||||
|
||||
// Update enable toggle state
|
||||
if (m_enableToggle && m_source.asMod()) {
|
||||
m_enableToggle->toggle(m_source.asMod()->isOrWillBeEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
void BaseModItem::updateSize(float width, bool big) {
|
||||
void ModItem::updateSize(float width, bool big) {
|
||||
this->setContentSize({ width, big ? 40.f : 30.f });
|
||||
|
||||
m_bg->setContentSize((m_obContentSize - ccp(6, 0)) / m_bg->getScale());
|
||||
|
@ -154,135 +206,37 @@ void BaseModItem::updateSize(float width, bool big) {
|
|||
this->updateLayout();
|
||||
}
|
||||
|
||||
void BaseModItem::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
void ModItem::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
m_updateParentState = listener;
|
||||
}
|
||||
|
||||
bool InstalledModItem::init(Mod* mod) {
|
||||
m_mod = mod;
|
||||
|
||||
if (!BaseModItem::init())
|
||||
return false;
|
||||
|
||||
// Add an enable button if the mod is enablable
|
||||
if (!mod->isInternal()) {
|
||||
m_enableToggle = CCMenuItemToggler::createWithStandardSprites(
|
||||
this, menu_selector(InstalledModItem::onEnable), 1.f
|
||||
);
|
||||
// Manually handle toggle state
|
||||
m_enableToggle->m_notClickable = true;
|
||||
m_viewMenu->addChild(m_enableToggle);
|
||||
m_viewMenu->updateLayout();
|
||||
ModItem* ModItem::create(ModSource&& source) {
|
||||
auto ret = new ModItem();
|
||||
if (ret && ret->init(std::move(source))) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InstalledModItem::updateState() {
|
||||
m_defaultBG.a = m_mod->isOrWillBeEnabled() ? 25 : 10;
|
||||
m_titleLabel->setOpacity(m_mod->isOrWillBeEnabled() ? 255 : 155);
|
||||
m_developerLabel->setOpacity(m_mod->isOrWillBeEnabled() ? 255 : 155);
|
||||
|
||||
BaseModItem::updateState();
|
||||
|
||||
// Update enable toggle state
|
||||
if (m_enableToggle) {
|
||||
m_enableToggle->toggle(m_mod->isOrWillBeEnabled());
|
||||
}
|
||||
void ModItem::onView(CCObject*) {
|
||||
ModPopup::create(ModSource(m_source))->show();
|
||||
}
|
||||
|
||||
void InstalledModItem::onEnable(CCObject*) {
|
||||
// Toggle the mod state
|
||||
auto res = m_mod->isOrWillBeEnabled() ? m_mod->disable() : m_mod->enable();
|
||||
if (!res) {
|
||||
FLAlertLayer::create(
|
||||
"Error Toggling Mod",
|
||||
res.unwrapErr(),
|
||||
"OK"
|
||||
)->show();
|
||||
void ModItem::onEnable(CCObject*) {
|
||||
if (auto mod = m_source.asMod()) {
|
||||
// Toggle the mod state
|
||||
auto res = mod->isOrWillBeEnabled() ? mod->disable() : mod->enable();
|
||||
if (!res) {
|
||||
FLAlertLayer::create(
|
||||
"Error Toggling Mod",
|
||||
res.unwrapErr(),
|
||||
"OK"
|
||||
)->show();
|
||||
}
|
||||
}
|
||||
|
||||
// Update whole state of the mod item
|
||||
this->updateState();
|
||||
}
|
||||
|
||||
InstalledModItem* InstalledModItem::create(Mod* mod) {
|
||||
auto ret = new InstalledModItem();
|
||||
if (ret && ret->init(mod)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModMetadata InstalledModItem::getMetadata() const {
|
||||
return m_mod->getMetadata();
|
||||
}
|
||||
|
||||
CCNode* InstalledModItem::createModLogo() const {
|
||||
return geode::createModLogo(m_mod);
|
||||
}
|
||||
|
||||
bool InstalledModItem::wantsRestart() const {
|
||||
return m_mod->getRequestedAction() != ModRequestedAction::None;
|
||||
}
|
||||
|
||||
bool ServerModItem::init(server::ServerModMetadata const& metadata) {
|
||||
m_metadata = metadata;
|
||||
|
||||
if (!BaseModItem::init())
|
||||
return false;
|
||||
|
||||
if (metadata.featured) {
|
||||
m_checkmark = CCScale9Sprite::createWithSpriteFrameName("GJ_colorBtn_001.png");
|
||||
m_checkmark->setContentSize({ 50, 38 });
|
||||
m_checkmark->setColor({ 255, 255, 120 });
|
||||
m_checkmark->setOpacity(45);
|
||||
|
||||
auto tick = CCSprite::createWithSpriteFrameName("GJ_starsIcon_001.png");
|
||||
m_checkmark->addChildAtPosition(tick, Anchor::Center);
|
||||
|
||||
m_titleContainer->addChild(m_checkmark);
|
||||
}
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerModItem::updateState() {
|
||||
BaseModItem::updateState();
|
||||
|
||||
// Update BG color unless we want to restart (more important color to show)
|
||||
// and if the mod is featured
|
||||
if (!this->wantsRestart() && m_metadata.featured && m_checkmark) {
|
||||
m_bg->setColor(m_checkmark->getColor());
|
||||
m_bg->setOpacity(40);
|
||||
}
|
||||
}
|
||||
|
||||
ServerModItem* ServerModItem::create(server::ServerModMetadata const& metadata) {
|
||||
auto ret = new ServerModItem();
|
||||
if (ret && ret->init(metadata)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModMetadata ServerModItem::getMetadata() const {
|
||||
return m_metadata.versions.front().metadata;
|
||||
}
|
||||
|
||||
CCNode* ServerModItem::createModLogo() const {
|
||||
return createServerModLogo(m_metadata.id);
|
||||
}
|
||||
|
||||
bool ServerModItem::wantsRestart() const {
|
||||
// todo: request restart after install
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
#include <Geode/ui/General.hpp>
|
||||
#include <server/Server.hpp>
|
||||
#include "ModSource.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class BaseModItem : public CCNode {
|
||||
class ModItem : public CCNode {
|
||||
protected:
|
||||
ModSource m_source;
|
||||
CCScale9Sprite* m_bg;
|
||||
ccColor4B m_defaultBG = { 255, 255, 255, 25 };
|
||||
CCNode* m_logo;
|
||||
CCNode* m_infoContainer;
|
||||
CCNode* m_titleContainer;
|
||||
|
@ -18,65 +19,26 @@ protected:
|
|||
ButtonSprite* m_restartRequiredLabel = nullptr;
|
||||
CCMenu* m_viewMenu;
|
||||
MiniFunction<void()> m_updateParentState = nullptr;
|
||||
CCMenuItemToggler* m_enableToggle = nullptr;
|
||||
CCScale9Sprite* m_checkmark = nullptr;
|
||||
|
||||
/**
|
||||
* @warning Make sure `getMetadata` and `createModLogo` are callable
|
||||
* before calling `init`!
|
||||
*/
|
||||
bool init();
|
||||
bool init(ModSource&& source);
|
||||
|
||||
// This should never be exposed outside, so the parent can't call this and
|
||||
// cause an infinite loop during state updating
|
||||
virtual void updateState();
|
||||
void updateState();
|
||||
|
||||
void onEnable(CCObject*);
|
||||
void onView(CCObject*);
|
||||
|
||||
public:
|
||||
virtual ModMetadata getMetadata() const = 0;
|
||||
virtual CCNode* createModLogo() const = 0;
|
||||
virtual bool wantsRestart() const = 0;
|
||||
static ModItem* create(ModSource&& source);
|
||||
|
||||
virtual void updateSize(float width, bool big);
|
||||
void updateSize(float width, bool big);
|
||||
|
||||
void onUpdateParentState(MiniFunction<void()> listener);
|
||||
};
|
||||
|
||||
class InstalledModItem : public BaseModItem {
|
||||
protected:
|
||||
Mod* m_mod;
|
||||
CCMenuItemToggler* m_enableToggle = nullptr;
|
||||
|
||||
bool init(Mod* mod);
|
||||
|
||||
void onEnable(CCObject*);
|
||||
|
||||
void updateState() override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @note Make sure to call `updateSize` afterwards
|
||||
*/
|
||||
static InstalledModItem* create(Mod* mod);
|
||||
|
||||
ModMetadata getMetadata() const override;
|
||||
CCNode* createModLogo() const override;
|
||||
bool wantsRestart() const override;
|
||||
};
|
||||
|
||||
class ServerModItem : public BaseModItem {
|
||||
protected:
|
||||
server::ServerModMetadata m_metadata;
|
||||
CCScale9Sprite* m_checkmark = nullptr;
|
||||
|
||||
bool init(server::ServerModMetadata const& metadata);
|
||||
|
||||
void updateState() override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @note Make sure to call `updateSize` afterwards
|
||||
*/
|
||||
static ServerModItem* create(server::ServerModMetadata const& metadata);
|
||||
|
||||
ModMetadata getMetadata() const override;
|
||||
CCNode* createModLogo() const override;
|
||||
bool wantsRestart() const override;
|
||||
};
|
||||
|
|
|
@ -294,7 +294,7 @@ void ModList::updateSize(bool big) {
|
|||
// Update all BaseModItems that are children of the list
|
||||
// There may be non-BaseModItems there (like separators) so gotta be type-safe
|
||||
for (auto& node : CCArrayExt<CCNode*>(m_list->m_contentLayer->getChildren())) {
|
||||
if (auto item = typeinfo_cast<BaseModItem*>(node)) {
|
||||
if (auto item = typeinfo_cast<ModItem*>(node)) {
|
||||
item->updateSize(m_list->getContentWidth(), big);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,19 +70,20 @@ static std::pair<std::vector<Mod*>, size_t> getModsWithQuery(server::ModsQuery c
|
|||
) {
|
||||
result.push_back(mods.at(i).first);
|
||||
}
|
||||
// Return paged mods & total count of matching mods
|
||||
// Return paged mods and total count of matches
|
||||
return { result, mods.size() };
|
||||
}
|
||||
|
||||
static auto loadInstalledModsPage(server::ModsQuery&& query) {
|
||||
return ModListSource::ProviderPromise([query = std::move(query)](auto resolve, auto, auto, auto const&) {
|
||||
Loader::get()->queueInMainThread([query = std::move(query), resolve = std::move(resolve)] {
|
||||
auto content = ModListSource::Page();
|
||||
auto mods = getModsWithQuery(query);
|
||||
for (auto& mod : mods.first) {
|
||||
content.push_back(InstalledModItem::create(mod));
|
||||
auto content = ModListSource::ProvidedMods();
|
||||
auto paged = getModsWithQuery(query);
|
||||
for (auto& mod : std::move(paged.first)) {
|
||||
content.mods.push_back(ModSource(mod));
|
||||
}
|
||||
resolve({ content, mods.second });
|
||||
content.totalModCount = paged.second;
|
||||
resolve(content);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -91,11 +92,12 @@ static auto loadServerModsPage(server::ModsQuery&& query) {
|
|||
return ModListSource::ProviderPromise([query = std::move(query)](auto resolve, auto reject, auto progress, auto cancelled) {
|
||||
server::getMods(query)
|
||||
.then([resolve, reject](server::ServerModsList list) {
|
||||
auto content = ModListSource::Page();
|
||||
for (auto& mod : list.mods) {
|
||||
content.push_back(ServerModItem::create(mod));
|
||||
auto content = ModListSource::ProvidedMods();
|
||||
for (auto&& mod : std::move(list.mods)) {
|
||||
content.mods.push_back(ModSource(std::move(mod)));
|
||||
}
|
||||
resolve({ content, list.totalModCount });
|
||||
content.totalModCount = list.totalModCount;
|
||||
resolve(content);
|
||||
})
|
||||
.expect([reject](auto error) {
|
||||
reject(ModListSource::LoadPageError("Error loading mods", error.details));
|
||||
|
@ -130,12 +132,16 @@ typename ModListSource::PagePromise ModListSource::loadPage(size_t page, bool up
|
|||
.pageSize = PER_PAGE,
|
||||
})
|
||||
.then([page, this, resolve, reject](auto data) {
|
||||
if (data.second == 0 || data.first.empty()) {
|
||||
if (data.totalModCount == 0 || data.mods.empty()) {
|
||||
return reject(ModListSource::LoadPageError("No mods found :("));
|
||||
}
|
||||
m_cachedItemCount = data.second;
|
||||
m_cachedPages.insert({ page, data.first });
|
||||
resolve(data.first);
|
||||
auto pageData = Page();
|
||||
for (auto mod : std::move(data.mods)) {
|
||||
pageData.push_back(ModItem::create(std::move(mod)));
|
||||
}
|
||||
m_cachedItemCount = data.totalModCount;
|
||||
m_cachedPages.insert({ page, pageData });
|
||||
resolve(pageData);
|
||||
})
|
||||
.expect([this, reject = reject](auto error) {
|
||||
reject(error);
|
||||
|
|
|
@ -28,13 +28,17 @@ public:
|
|||
LoadPageError(auto msg, auto details) : message(msg), details(details) {}
|
||||
};
|
||||
|
||||
using Page = std::vector<Ref<BaseModItem>>;
|
||||
using Page = std::vector<Ref<ModItem>>;
|
||||
using PageLoadEvent = PromiseEvent<Page, LoadPageError, std::optional<uint8_t>>;
|
||||
using PageLoadEventFilter = PromiseEventFilter<Page, LoadPageError, std::optional<uint8_t>>;
|
||||
using PageLoadEventListener = EventListener<PageLoadEventFilter>;
|
||||
using PagePromise = Promise<Page, LoadPageError, std::optional<uint8_t>>;
|
||||
|
||||
using ProviderPromise = Promise<std::pair<Page, size_t>, LoadPageError, std::optional<uint8_t>>;
|
||||
struct ProvidedMods {
|
||||
std::vector<ModSource> mods;
|
||||
size_t totalModCount;
|
||||
};
|
||||
using ProviderPromise = Promise<ProvidedMods, LoadPageError, std::optional<uint8_t>>;
|
||||
|
||||
struct Provider {
|
||||
ProviderPromise(*get)(server::ModsQuery&& query) = nullptr;
|
||||
|
|
18
loader/src/ui/mods/ModPopup.cpp
Normal file
18
loader/src/ui/mods/ModPopup.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "ModPopup.hpp"
|
||||
|
||||
bool ModPopup::setup(ModSource&& src) {
|
||||
m_source = std::move(src);
|
||||
m_noElasticity = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ModPopup* ModPopup::create(ModSource&& src) {
|
||||
auto ret = new ModPopup();
|
||||
if (ret && ret->init(358.f, 250.f, std::move(src))) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
16
loader/src/ui/mods/ModPopup.hpp
Normal file
16
loader/src/ui/mods/ModPopup.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include "ModSource.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class ModPopup : public Popup<ModSource&&> {
|
||||
protected:
|
||||
ModSource m_source;
|
||||
|
||||
bool setup(ModSource&& src) override;
|
||||
|
||||
public:
|
||||
static ModPopup* create(ModSource&& src);
|
||||
};
|
46
loader/src/ui/mods/ModSource.cpp
Normal file
46
loader/src/ui/mods/ModSource.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "ModSource.hpp"
|
||||
#include <Geode/ui/GeodeUI.hpp>
|
||||
|
||||
ModSource::ModSource(Mod* mod) : m_value(mod) {}
|
||||
ModSource::ModSource(server::ServerModMetadata&& metadata) : m_value(metadata) {}
|
||||
|
||||
ModMetadata ModSource::getMetadata() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](Mod* mod) {
|
||||
return mod->getMetadata();
|
||||
},
|
||||
[](server::ServerModMetadata const& metadata) {
|
||||
// Versions should be guaranteed to have at least one item
|
||||
return metadata.versions.front().metadata;
|
||||
}
|
||||
}, m_value);
|
||||
}
|
||||
CCNode* ModSource::createModLogo() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](Mod* mod) {
|
||||
return geode::createModLogo(mod);
|
||||
},
|
||||
[](server::ServerModMetadata const& metadata) {
|
||||
return createServerModLogo(metadata.id);
|
||||
}
|
||||
}, m_value);
|
||||
}
|
||||
bool ModSource::wantsRestart() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](Mod* mod) {
|
||||
return mod->getRequestedAction() != ModRequestedAction::None;
|
||||
},
|
||||
[](server::ServerModMetadata const& metdata) {
|
||||
// todo: check if the mod has been installed
|
||||
return false;
|
||||
}
|
||||
}, m_value);
|
||||
}
|
||||
|
||||
Mod* ModSource::asMod() const {
|
||||
auto mod = std::get_if<Mod*>(&m_value);
|
||||
return mod ? *mod : nullptr;
|
||||
}
|
||||
server::ServerModMetadata const* ModSource::asServer() const {
|
||||
return std::get_if<server::ServerModMetadata>(&m_value);
|
||||
}
|
27
loader/src/ui/mods/ModSource.hpp
Normal file
27
loader/src/ui/mods/ModSource.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <server/Server.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class ModSource final {
|
||||
private:
|
||||
std::variant<Mod*, server::ServerModMetadata> m_value;
|
||||
|
||||
public:
|
||||
ModSource() = default;
|
||||
ModSource(Mod* mod);
|
||||
ModSource(server::ServerModMetadata&& metadata);
|
||||
|
||||
ModMetadata getMetadata() const;
|
||||
CCNode* createModLogo() const;
|
||||
bool wantsRestart() const;
|
||||
|
||||
auto visit(auto&& func) {
|
||||
return std::visit(func, m_value);
|
||||
}
|
||||
|
||||
Mod* asMod() const;
|
||||
server::ServerModMetadata const* asServer() const;
|
||||
};
|
Loading…
Reference in a new issue