modtober integration

This commit is contained in:
HJfod 2024-10-01 13:22:38 +03:00
parent c68c31c2d8
commit 964624b974
18 changed files with 220 additions and 36 deletions

View file

@ -1 +1 @@
3.7.2 3.8.0

View file

@ -60,6 +60,9 @@
], ],
"BlankSheet": [ "BlankSheet": [
"blanks/*.png" "blanks/*.png"
],
"EventSheet": [
"modtober/*.png"
] ]
} }
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -184,21 +184,16 @@ CircleButtonSprite* createGeodeCircleButton(CCSprite* top, float scale, CircleBa
return ret; return ret;
} }
ButtonSprite* createGeodeTagLabel(std::string const& text, std::optional<std::pair<ccColor3B, ccColor3B>> const& color) { ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccColor3B> const& color) {
auto label = ButtonSprite::create(text.c_str(), "bigFont.fnt", "white-square.png"_spr, .8f); auto label = ButtonSprite::create(text.c_str(), "bigFont.fnt", "white-square.png"_spr, .8f);
if (color) { label->m_label->setColor(color.first);
label->m_label->setColor(color->first); label->m_BGSprite->setColor(color.second);
label->m_BGSprite->setColor(color->second);
}
else {
auto def = geodeTagColor(text);
label->m_label->setColor(def.first);
label->m_BGSprite->setColor(def.second);
}
return label; return label;
} }
ButtonSprite* createGeodeTagLabel(std::string_view tag) {
std::pair<ccColor3B, ccColor3B> geodeTagColor(std::string_view const& text) { return createTagLabel(geodeTagName(tag), geodeTagColors(tag));
}
std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag) {
static std::array TAG_COLORS { static std::array TAG_COLORS {
std::make_pair(ccc3(240, 233, 255), ccc3(130, 123, 163)), std::make_pair(ccc3(240, 233, 255), ccc3(130, 123, 163)),
std::make_pair(ccc3(234, 255, 245), ccc3(123, 163, 136)), std::make_pair(ccc3(234, 255, 245), ccc3(123, 163, 136)),
@ -206,7 +201,20 @@ std::pair<ccColor3B, ccColor3B> geodeTagColor(std::string_view const& text) {
std::make_pair(ccc3(255, 253, 240), ccc3(163, 157, 123)), std::make_pair(ccc3(255, 253, 240), ccc3(163, 157, 123)),
std::make_pair(ccc3(255, 242, 240), ccc3(163, 128, 123)), std::make_pair(ccc3(255, 242, 240), ccc3(163, 128, 123)),
}; };
return TAG_COLORS[hash(text) % 5932 % TAG_COLORS.size()]; if (tag == "modtober24") {
return std::make_pair(ccc3(225, 236, 245), ccc3(82, 139, 201));
}
return TAG_COLORS[hash(tag) % 5932 % TAG_COLORS.size()];
}
std::string geodeTagName(std::string_view tag) {
// todo in v4: rework tags to use a server-provided display name instead
if (tag == "modtober24") {
return "Modtober 2024";
}
// Everything else just capitalize and that's it
auto readable = std::string(tag);
readable[0] = std::toupper(readable[0]);
return readable;
} }
ListBorders* createGeodeListBorders(CCSize const& size) { ListBorders* createGeodeListBorders(CCSize const& size) {

View file

@ -80,8 +80,10 @@ ButtonSprite* createGeodeButton(std::string const& text, bool gold = false, Geod
CircleButtonSprite* createGeodeCircleButton(CCSprite* top, float scale = 1.f, CircleBaseSize size = CircleBaseSize::Medium, bool altColor = false); CircleButtonSprite* createGeodeCircleButton(CCSprite* top, float scale = 1.f, CircleBaseSize size = CircleBaseSize::Medium, bool altColor = false);
ButtonSprite* createGeodeTagLabel(std::string const& text, std::optional<std::pair<ccColor3B, ccColor3B>> const& color = std::nullopt); ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccColor3B> const& color);
std::pair<ccColor3B, ccColor3B> geodeTagColor(std::string_view const& text); ButtonSprite* createGeodeTagLabel(std::string_view tag);
std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag);
std::string geodeTagName(std::string_view tag);
ListBorders* createGeodeListBorders(CCSize const& size); ListBorders* createGeodeListBorders(CCSize const& size);

View file

@ -430,14 +430,15 @@ bool ModsLayer::init() {
// Increment touch priority so the mods in the list don't override // Increment touch priority so the mods in the list don't override
mainTabs->setTouchPriority(-150); mainTabs->setTouchPriority(-150);
for (auto item : std::initializer_list<std::tuple<const char*, const char*, ModListSource*, const char*>> { for (auto item : std::initializer_list<std::tuple<const char*, const char*, ModListSource*, const char*, bool>> {
{ "download.png"_spr, "Installed", InstalledModListSource::get(InstalledModListType::All), "installed-button" }, { "download.png"_spr, "Installed", InstalledModListSource::get(InstalledModListType::All), "installed-button", false },
{ "GJ_starsIcon_001.png", "Featured", ServerModListSource::get(ServerModListType::Featured), "featured-button" }, { "GJ_starsIcon_001.png", "Featured", ServerModListSource::get(ServerModListType::Featured), "featured-button", false },
{ "globe.png"_spr, "Download", ServerModListSource::get(ServerModListType::Download), "download-button" }, { "globe.png"_spr, "Download", ServerModListSource::get(ServerModListType::Download), "download-button", false },
{ "GJ_timeIcon_001.png", "Recent", ServerModListSource::get(ServerModListType::Recent), "recent-button" }, { "GJ_timeIcon_001.png", "Recent", ServerModListSource::get(ServerModListType::Recent), "recent-button", false },
{ "d_artCloud_03_001.png", "Modtober", ServerModListSource::get(ServerModListType::Modtober24), "modtober-button", true },
}) { }) {
auto btn = CCMenuItemSpriteExtra::create( auto btn = CCMenuItemSpriteExtra::create(
GeodeTabSprite::create(std::get<0>(item), std::get<1>(item), 120), GeodeTabSprite::create(std::get<0>(item), std::get<1>(item), 100, std::get<4>(item)),
this, menu_selector(ModsLayer::onTab) this, menu_selector(ModsLayer::onTab)
); );
btn->setUserData(std::get<2>(item)); btn->setUserData(std::get<2>(item));

View file

@ -84,12 +84,12 @@ bool ModItem::init(ModSource&& source) {
); );
m_infoContainer->addChild(m_developers); m_infoContainer->addChild(m_developers);
m_restartRequiredLabel = createGeodeTagLabel( m_restartRequiredLabel = createTagLabel(
"Restart Required", "Restart Required",
{{ {
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)), to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr)) to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
}} }
); );
m_restartRequiredLabel->setID("restart-required-label"); m_restartRequiredLabel->setID("restart-required-label");
m_restartRequiredLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(std::nullopt, .75f)); m_restartRequiredLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(std::nullopt, .75f));
@ -208,6 +208,11 @@ bool ModItem::init(ModSource&& source) {
paidModLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f)); paidModLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
m_titleContainer->addChild(paidModLabel); m_titleContainer->addChild(paidModLabel);
} }
if (metadata.tags.contains("modtober24")) {
auto modtoberLabel = CCSprite::createWithSpriteFrameName("tag-modtober.png"_spr);
modtoberLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
m_titleContainer->addChild(modtoberLabel);
}
// Show mod download count here already so people can make informed decisions // Show mod download count here already so people can make informed decisions
// on which mods to install // on which mods to install
@ -363,7 +368,10 @@ void ModItem::updateState() {
m_bg->setColor("mod-list-paid-color"_cc3b); m_bg->setColor("mod-list-paid-color"_cc3b);
m_bg->setOpacity(55); m_bg->setOpacity(55);
} }
if (metadata.tags.contains("modtober24")) {
m_bg->setColor(ccc3(63, 91, 138));
m_bg->setOpacity(85);
}
if (isGeodeTheme() && metadata.featured) { if (isGeodeTheme() && metadata.featured) {
m_bg->setColor("mod-list-featured-color"_cc3b); m_bg->setColor("mod-list-featured-color"_cc3b);
m_bg->setOpacity(65); m_bg->setOpacity(65);

View file

@ -4,6 +4,7 @@
#include "../popups/SortPopup.hpp" #include "../popups/SortPopup.hpp"
#include "../GeodeStyle.hpp" #include "../GeodeStyle.hpp"
#include "../ModsLayer.hpp" #include "../ModsLayer.hpp"
#include "../popups/ModtoberPopup.hpp"
bool ModList::init(ModListSource* src, CCSize const& size) { bool ModList::init(ModListSource* src, CCSize const& size) {
if (!CCNode::init()) if (!CCNode::init())
@ -249,6 +250,34 @@ bool ModList::init(ModListSource* src, CCSize const& size) {
m_topContainer->addChild(m_searchMenu); m_topContainer->addChild(m_searchMenu);
// Modtober banner; this can be removed after Modtober 2024 is over!
if (
auto src = typeinfo_cast<ServerModListSource*>(m_source);
src && src->getType() == ServerModListType::Modtober24
) {
auto menu = CCMenu::create();
menu->setID("modtober-banner");
menu->ignoreAnchorPointForPosition(false);
menu->setContentSize({ size.width, 30 });
auto banner = CCSprite::createWithSpriteFrameName("modtober24-banner.png"_spr);
limitNodeWidth(banner, size.width, 1.f, .1f);
menu->addChildAtPosition(banner, Anchor::Center);
auto label = CCLabelBMFont::create("Modtober 2024 is Here!", "bigFont.fnt");
label->setScale(.5f);
menu->addChildAtPosition(label, Anchor::Left, ccp(10, 0), ccp(0, .5f));
auto aboutSpr = createGeodeButton("About");
aboutSpr->setScale(.5f);
auto aboutBtn = CCMenuItemSpriteExtra::create(
aboutSpr, this, menu_selector(ModList::onModtoberInfo)
);
menu->addChildAtPosition(aboutBtn, Anchor::Right, ccp(-35, 0));
m_topContainer->addChild(menu);
}
m_topContainer->setLayout( m_topContainer->setLayout(
ColumnLayout::create() ColumnLayout::create()
->setGap(0) ->setGap(0)
@ -659,6 +688,9 @@ void ModList::onToggleErrors(CCObject*) {
void ModList::onUpdateAll(CCObject*) { void ModList::onUpdateAll(CCObject*) {
server::ModDownloadManager::get()->startUpdateAll(); server::ModDownloadManager::get()->startUpdateAll();
} }
void ModList::onModtoberInfo(CCObject*) {
ModtoberPopup::create()->show();
}
size_t ModList::getPage() const { size_t ModList::getPage() const {
return m_page; return m_page;

View file

@ -71,6 +71,7 @@ protected:
void onToggleUpdates(CCObject*); void onToggleUpdates(CCObject*);
void onToggleErrors(CCObject*); void onToggleErrors(CCObject*);
void onUpdateAll(CCObject*); void onUpdateAll(CCObject*);
void onModtoberInfo(CCObject*);
public: public:
static ModList* create(ModListSource* src, CCSize const& size); static ModList* create(ModListSource* src, CCSize const& size);

View file

@ -10,6 +10,7 @@
#include "../settings/ModSettingsPopup.hpp" #include "../settings/ModSettingsPopup.hpp"
#include "../../../internal/about.hpp" #include "../../../internal/about.hpp"
#include "../../GeodeUIEvent.hpp" #include "../../GeodeUIEvent.hpp"
#include "../popups/ModtoberPopup.hpp"
class FetchTextArea : public CCNode { class FetchTextArea : public CCNode {
public: public:
@ -300,12 +301,12 @@ bool ModPopup::setup(ModSource&& src) {
manageTitle->setOpacity(195); manageTitle->setOpacity(195);
manageContainer->addChildAtPosition(manageTitle, Anchor::Left, ccp(0, 0), ccp(0, .5f)); manageContainer->addChildAtPosition(manageTitle, Anchor::Left, ccp(0, 0), ccp(0, .5f));
m_restartRequiredLabel = createGeodeTagLabel( m_restartRequiredLabel = createTagLabel(
"Restart Required", "Restart Required",
{{ {
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)), to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr)) to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
}} }
); );
m_restartRequiredLabel->setScale(.3f); m_restartRequiredLabel->setScale(.3f);
manageContainer->addChildAtPosition(m_restartRequiredLabel, Anchor::Right, ccp(0, 0), ccp(1, .5f)); manageContainer->addChildAtPosition(m_restartRequiredLabel, Anchor::Right, ccp(0, 0), ccp(1, .5f));
@ -880,10 +881,7 @@ void ModPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<std:
m_tags->removeAllChildren(); m_tags->removeAllChildren();
for (auto& tag : data) { for (auto& tag : data) {
auto readable = tag; m_tags->addChild(createGeodeTagLabel(tag));
readable[0] = std::toupper(readable[0]);
auto colors = geodeTagColor(tag);
m_tags->addChild(createGeodeTagLabel(readable));
} }
if (data.empty()) { if (data.empty()) {
@ -891,6 +889,47 @@ void ModPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<std:
label->setOpacity(120); label->setOpacity(120);
m_tags->addChild(label); m_tags->addChild(label);
} }
// This should probably be kept even after modtober ends,
// so the banner sprite must be kept
// If the build times from the cool popup become too long then we can
// probably move that to a normal FLAlert that explains "Modtober was
// this contest blah blah this mod was made for it"
else if (data.contains("modtober24")) {
auto menu = CCMenu::create();
menu->setID("modtober-banner");
menu->ignoreAnchorPointForPosition(false);
menu->setContentSize({ m_rightColumn->getContentWidth(), 25 });
auto banner = CCSprite::createWithSpriteFrameName("modtober24-banner-2.png"_spr);
limitNodeWidth(banner, m_rightColumn->getContentWidth(), 1.f, .1f);
menu->addChildAtPosition(banner, Anchor::Center);
auto label = CCLabelBMFont::create("Entry for Modtober 2024", "bigFont.fnt");
label->setScale(.35f);
menu->addChildAtPosition(label, Anchor::Left, ccp(10, 0), ccp(0, .5f));
auto aboutSpr = createGeodeButton("About");
aboutSpr->setScale(.35f);
auto aboutBtn = CCMenuItemSpriteExtra::create(
aboutSpr, this, menu_selector(ModPopup::onModtoberInfo)
);
menu->addChildAtPosition(aboutBtn, Anchor::Right, ccp(-25, 0));
m_rightColumn->addChildAtPosition(menu, Anchor::Bottom, ccp(0, 0), ccp(.5f, 0));
m_modtoberBanner = menu;
// Force reload of all the tabs since otherwise their contents will overflow
for (auto& [_, tab] : m_tabs) {
if (tab.second && tab.second->getParent()) {
tab.second->removeFromParent();
}
tab.second = nullptr;
}
// This might cause a minor inconvenience to someone who opens the popup and
// immediately switches to changelog but is then forced back into details
this->loadTab(Tab::Details);
}
m_tags->updateLayout(); m_tags->updateLayout();
@ -920,12 +959,17 @@ void ModPopup::loadTab(ModPopup::Tab tab) {
btn.first->select(value == tab); btn.first->select(value == tab);
} }
float modtoberBannerHeight = 0;
if (m_modtoberBanner) {
modtoberBannerHeight = 30;
}
if (auto existing = m_tabs.at(tab).second) { if (auto existing = m_tabs.at(tab).second) {
m_currentTabPage = existing; m_currentTabPage = existing;
m_rightColumn->addChildAtPosition(existing, Anchor::Bottom); m_rightColumn->addChildAtPosition(existing, Anchor::Bottom, ccp(0, modtoberBannerHeight));
} }
else { else {
const auto size = (m_rightColumn->getContentSize() - ccp(0, 30)); const auto size = (m_rightColumn->getContentSize() - ccp(0, 30 + modtoberBannerHeight));
const float mdScale = .85f; const float mdScale = .85f;
switch (tab) { switch (tab) {
case Tab::Details: { case Tab::Details: {
@ -955,7 +999,7 @@ void ModPopup::loadTab(ModPopup::Tab tab) {
} break; } break;
} }
m_currentTabPage->setAnchorPoint({ .5f, .0f }); m_currentTabPage->setAnchorPoint({ .5f, .0f });
m_rightColumn->addChildAtPosition(m_currentTabPage, Anchor::Bottom); m_rightColumn->addChildAtPosition(m_currentTabPage, Anchor::Bottom, ccp(0, modtoberBannerHeight));
m_tabs.at(tab).second = m_currentTabPage; m_tabs.at(tab).second = m_currentTabPage;
} }
} }
@ -1030,6 +1074,12 @@ void ModPopup::onLink(CCObject* sender) {
void ModPopup::onSupport(CCObject*) { void ModPopup::onSupport(CCObject*) {
openSupportPopup(m_source.getMetadata()); openSupportPopup(m_source.getMetadata());
} }
void ModPopup::onModtoberInfo(CCObject*) {
// todo: if we want to get rid of the modtober popup sprite (because it's fucking massive)
// then we can just replace this with a normal FLAlert explaining
// "this mod was an entry for modtober 2024 blah blah blah"
ModtoberPopup::create()->show();
}
ModPopup* ModPopup::create(ModSource&& src) { ModPopup* ModPopup::create(ModSource&& src) {
auto ret = new ModPopup(); auto ret = new ModPopup();

View file

@ -35,6 +35,7 @@ protected:
ButtonSprite* m_restartRequiredLabel; ButtonSprite* m_restartRequiredLabel;
CCNode* m_rightColumn; CCNode* m_rightColumn;
CCNode* m_currentTabPage = nullptr; CCNode* m_currentTabPage = nullptr;
CCNode* m_modtoberBanner = nullptr;
std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs; std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs;
EventListener<server::ServerRequest<server::ServerModMetadata>> m_statsListener; EventListener<server::ServerRequest<server::ServerModMetadata>> m_statsListener;
EventListener<server::ServerRequest<std::unordered_set<std::string>>> m_tagsListener; EventListener<server::ServerRequest<std::unordered_set<std::string>>> m_tagsListener;
@ -63,6 +64,7 @@ protected:
void onSettings(CCObject*); void onSettings(CCObject*);
void onLink(CCObject*); void onLink(CCObject*);
void onSupport(CCObject*); void onSupport(CCObject*);
void onModtoberInfo(CCObject*);
public: public:
void loadTab(Tab tab); void loadTab(Tab tab);

View file

@ -0,0 +1,44 @@
#include "ModtoberPopup.hpp"
#include <Geode/utils/web.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/binding/ButtonSprite.hpp>
bool ModtoberPopup::setup() {
m_bgSprite->setVisible(false);
auto bg = CCSprite::createWithSpriteFrameName("modtober24-popup.png"_spr);
m_mainLayer->addChildAtPosition(bg, Anchor::Center);
auto supportSpr = createGeodeButton("Join");
supportSpr->setScale(.8f);
auto supportBtn = CCMenuItemSpriteExtra::create(
supportSpr, this, menu_selector(ModtoberPopup::onDiscord)
);
m_buttonMenu->addChildAtPosition(supportBtn, Anchor::BottomRight, ccp(-65, 50));
return true;
}
void ModtoberPopup::onDiscord(CCObject*) {
createQuickPopup(
"Join Modtober",
"<cf>Modtober</c> is being hosted on the <cg>GD Programming</c> <ca>Discord Server</c>.\n"
"To participate, join GDP and read the rules for the contest in <co>#modtober-2024</c>",
"Cancel", "Join Discord",
[](auto, bool btn2) {
if (btn2) {
web::openLinkInBrowser("https://discord.gg/gd-programming-646101505417674758");
}
}
);
}
ModtoberPopup* ModtoberPopup::create() {
auto ret = new ModtoberPopup();
if (ret && ret->init(410, 270)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <Geode/ui/Popup.hpp>
#include "../GeodeStyle.hpp"
using namespace geode::prelude;
class ModtoberPopup : public GeodePopup<> {
protected:
bool setup() override;
void onDiscord(CCObject*);
public:
static ModtoberPopup* create();
};

View file

@ -143,6 +143,7 @@ enum class ServerModListType {
Featured, Featured,
Trending, Trending,
Recent, Recent,
Modtober24,
}; };
class ServerModListSource : public ModListSource { class ServerModListSource : public ModListSource {
@ -165,6 +166,7 @@ public:
server::ModsQuery const& getQuery() const; server::ModsQuery const& getQuery() const;
InvalidateQueryAfter<server::ModsQuery> getQueryMut(); InvalidateQueryAfter<server::ModsQuery> getQueryMut();
bool isDefaultQuery() const override; bool isDefaultQuery() const override;
ServerModListType getType() const;
}; };
class ModPackListSource : public ModListSource { class ModPackListSource : public ModListSource {

View file

@ -23,6 +23,12 @@ void ServerModListSource::resetQuery() {
.sorting = server::ModsSort::RecentlyPublished, .sorting = server::ModsSort::RecentlyPublished,
}; };
} break; } break;
case ServerModListType::Modtober24: {
m_query = server::ModsQuery {
.tags = { "modtober24" },
};
} break;
} }
} }
@ -76,6 +82,11 @@ ServerModListSource* ServerModListSource::get(ServerModListType type) {
static auto inst = new ServerModListSource(ServerModListType::Recent); static auto inst = new ServerModListSource(ServerModListType::Recent);
return inst; return inst;
} break; } break;
case ServerModListType::Modtober24: {
static auto inst = new ServerModListSource(ServerModListType::Modtober24);
return inst;
} break;
} }
} }
@ -108,3 +119,7 @@ bool ServerModListSource::isDefaultQuery() const {
m_query.tags.empty() && m_query.tags.empty() &&
!m_query.developer.has_value(); !m_query.developer.has_value();
} }
ServerModListType ServerModListSource::getType() const {
return m_type;
}