Skip to content

Commit

Permalink
i ain't dealing with this no more
Browse files Browse the repository at this point in the history
  • Loading branch information
hiimjustin000 committed Aug 31, 2024
1 parent 14a8d55 commit e7101c7
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 72 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

project(IntegratedDemonlist VERSION 1.5.8)
project(IntegratedDemonlist VERSION 1.5.9)

add_library(${PROJECT_NAME} SHARED
src/IDListLayer.cpp
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A mod that integrates [aredl.net](https://aredl.net) and [pemonlist.com](https:/
- A new button in the level/list search screen that opens the demon list.
- A search box that allows you to search for a demon in the list by name.
- Page navigation buttons that allow you to navigate through the list.
- A button that allows you to switch between the AREDL (For classic demons) and the Pemonlist (For platformer demons).
- Buttons that allow you to switch between the AREDL (For classic demons) and the Pemonlist (For platformer demons).
- If on the list, and if enabled, there will be text on the demon's search box that states its position on the list.

# Gallery
Expand Down
6 changes: 3 additions & 3 deletions about.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ A mod that integrates [aredl.net](https://aredl.net) and [pemonlist.com](https:/
- A new button in the level/list search screen that opens the demon list.
- A search box that allows you to search for a demon in the list by name.
- Page navigation buttons that allow you to navigate through the list.
- A button that allows you to switch between the AREDL (For classic demons) and the Pemonlist (For platformer demons).
- Buttons that allow you to switch between the AREDL (For classic demons) and the Pemonlist (For platformer demons).
- If on the list, and if enabled, there will be text on the demon's search box that states its position on the list.

# Gallery
![AREDL](hiimjustin000.integrated_demonlist/aredl.png?scale=0.6)\
![Pemonlist](hiimjustin000.integrated_demonlist/pemonlist.png?scale=0.6)
![AREDL](hiimjustin000.integrated_demonlist/aredl.png?scale=0.625)\
![Pemonlist](hiimjustin000.integrated_demonlist/pemonlist.png?scale=0.625)
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Integrated Demonlist Changelog
## v1.5.9 (2024-08-30)
- Moved the "Failed to load" notifications to log messages
- Added the status code to the "Load Failed" popup
- Split the AREDL/Pemonlist button into two separate buttons
- Fixed the loading symbol only showing after loading the demonlist

## v1.5.8 (2024-08-22)
- Fixed the source link on the mod info page

Expand Down
2 changes: 1 addition & 1 deletion mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"win": "2.206",
"mac": "2.206"
},
"version": "v1.5.8",
"version": "v1.5.9",
"id": "hiimjustin000.integrated_demonlist",
"name": "Integrated Demonlist",
"developer": "hiimjustin000",
Expand Down
Binary file modified resources/ID_findBtnOn_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 56 additions & 40 deletions src/IDListLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,50 @@ bool IDListLayer::init() {
auto refreshBtnSpr = CCSprite::createWithSpriteFrameName("GJ_updateBtn_001.png");
auto& refreshBtnSize = refreshBtnSpr->getContentSize();
auto refreshButton = CCMenuItemExt::createSpriteExtra(refreshBtnSpr, [this](auto) {
if (PEMONLIST) IntegratedDemonlist::loadPemonlist(std::move(m_listener), [this] { populateList(m_query); });
else IntegratedDemonlist::loadAREDL(std::move(m_listener), [this] { populateList(m_query); });
showLoading();
if (PEMONLIST) IntegratedDemonlist::loadPemonlist(std::move(m_pemonlistListener), std::move(m_pemonlistOkListener),
m_loadingCircle, [this] { populateList(m_query); });
else IntegratedDemonlist::loadAREDL(std::move(m_aredlListener), std::move(m_aredlOkListener),
m_loadingCircle, [this] { populateList(m_query); });
});
refreshButton->setPosition(winSize.width - refreshBtnSize.width / 2 - 4.0f, refreshBtnSize.height / 2 + 4.0f);
menu->addChild(refreshButton, 2);

auto listToggler = CCMenuItemExt::createTogglerWithFrameName("GJ_moonsIcon_001.png", "GJ_starsIcon_001.png", 1.1f, [this](auto) {
PEMONLIST = !PEMONLIST;
if (PEMONLIST) {
IntegratedDemonlist::loadPemonlist(std::move(m_listener), [this] { page(0); });
m_infoButton->m_title = "Pemonlist";
m_infoButton->m_description = PEMONLIST_INFO;
m_starToggle = CCMenuItemExt::createSpriteExtraWithFrameName("GJ_starsIcon_001.png", 1.1f, [this](auto) {
if (!PEMONLIST) return;
PEMONLIST = false;
m_starToggle->setColor({ 255, 255, 255 });
m_moonToggle->setColor({ 125, 125, 125 });
showLoading();
if (auto listTitle = static_cast<CCLabelBMFont*>(m_list->getChildByID("title"))) {
listTitle->setString("All Rated Extreme Demons List");
listTitle->limitLabelWidth(280.0f, 0.8f, 0.0f);
}
else {
IntegratedDemonlist::loadAREDL(std::move(m_listener), [this] { page(0); });
m_infoButton->m_title = "All Rated Extreme Demons List";
m_infoButton->m_description = AREDL_INFO;
m_infoButton->m_title = "All Rated Extreme Demons List";
m_infoButton->m_description = AREDL_INFO;
IntegratedDemonlist::loadAREDL(std::move(m_aredlListener), std::move(m_aredlOkListener), m_loadingCircle, [this] { page(0); });
});
m_starToggle->setPosition(30.0f, 60.0f);
m_starToggle->setColor(PEMONLIST ? ccColor3B { 125, 125, 125 } : ccColor3B { 255, 255, 255 });
menu->addChild(m_starToggle, 2);

m_moonToggle = CCMenuItemExt::createSpriteExtraWithFrameName("GJ_moonsIcon_001.png", 1.1f, [this](auto) {
if (PEMONLIST) return;
PEMONLIST = true;
m_starToggle->setColor({ 125, 125, 125 });
m_moonToggle->setColor({ 255, 255, 255 });
showLoading();
if (auto listTitle = static_cast<CCLabelBMFont*>(m_list->getChildByID("title"))) {
listTitle->setString("Pemonlist");
listTitle->limitLabelWidth(280.0f, 0.8f, 0.0f);
}
m_infoButton->m_title = "Pemonlist";
m_infoButton->m_description = PEMONLIST_INFO;
IntegratedDemonlist::loadPemonlist(std::move(m_pemonlistListener), std::move(m_pemonlistOkListener), m_loadingCircle, [this] { page(0); });
});
listToggler->toggle(PEMONLIST);
listToggler->setPosition(30.0f, 60.0f);
menu->addChild(listToggler, 2);
m_moonToggle->setPosition(60.0f, 60.0f);
m_moonToggle->setColor(PEMONLIST ? ccColor3B { 255, 255, 255 } : ccColor3B { 125, 125, 125 });
menu->addChild(m_moonToggle, 2);

auto pageBtnSpr = CCSprite::create("GJ_button_02.png");
pageBtnSpr->setScale(0.7f);
Expand All @@ -112,7 +134,7 @@ bool IDListLayer::init() {
m_pageLabel->setPosition(pageBtnSpr->getContentSize() / 2);
pageBtnSpr->addChild(m_pageLabel);
m_pageButton = CCMenuItemExt::createSpriteExtra(pageBtnSpr, [this](auto) {
auto popup = SetIDPopup::create(m_page + 1, 1, getMaxPage() + 1, "Go to Page", "Go", true, 1, 60.0f, false, false);
auto popup = SetIDPopup::create(m_page + 1, 1, (m_fullSearchResults.size() + 9) / 10, "Go to Page", "Go", true, 1, 60.0f, false, false);
popup->m_delegate = this;
popup->show();
});
Expand All @@ -121,7 +143,7 @@ bool IDListLayer::init() {
// Sprite by Cvolton
m_randomButton = CCMenuItemExt::createSpriteExtraWithFilename("BI_randomBtn_001.png"_spr, 0.9f, [this](auto) {
static std::mt19937 mt(std::random_device{}());
page(std::uniform_int_distribution<int>(0, getMaxPage())(mt));
page(std::uniform_int_distribution<int>(0, (m_fullSearchResults.size() - 1) / 10)(mt));
});
m_randomButton->setPositionY(m_pageButton->getPositionY() - m_pageButton->getContentSize().height / 2 - m_randomButton->getContentSize().height / 2 - 5.0f);
menu->addChild(m_randomButton);
Expand All @@ -133,7 +155,7 @@ bool IDListLayer::init() {
otherLastArrow->setFlipX(true);
lastArrow->addChild(otherLastArrow);
lastArrow->setScale(0.4f);
m_lastButton = CCMenuItemExt::createSpriteExtra(lastArrow, [this](auto) { page(getMaxPage()); });
m_lastButton = CCMenuItemExt::createSpriteExtra(lastArrow, [this](auto) { page((m_fullSearchResults.size() - 1) / 10); });
m_lastButton->setPositionY(m_randomButton->getPositionY() - m_randomButton->getContentSize().height / 2 - m_lastButton->getContentSize().height / 2 - 5.0f);
menu->addChild(m_lastButton);
auto x = winSize.width - m_randomButton->getContentSize().width / 2 - 3.0f;
Expand All @@ -154,23 +176,16 @@ bool IDListLayer::init() {
m_loadingCircle->setParentLayer(this);
m_loadingCircle->retain();
m_loadingCircle->show();
m_loadingCircle->setVisible(false);

m_searchBarMenu->setVisible(false);
m_leftButton->setVisible(false);
m_rightButton->setVisible(false);
m_firstButton->setVisible(false);
m_lastButton->setVisible(false);
m_pageButton->setVisible(false);
m_randomButton->setVisible(false);

showLoading();
setKeyboardEnabled(true);

if (PEMONLIST) {
if (!IntegratedDemonlist::PEMONLIST.empty()) populateList("");
else IntegratedDemonlist::loadPemonlist(std::move(m_listener), [this] { populateList(""); });
else IntegratedDemonlist::loadPemonlist(std::move(m_pemonlistListener), std::move(m_pemonlistOkListener), m_loadingCircle, [this] { populateList(""); });
}
else if (!IntegratedDemonlist::AREDL.empty()) populateList("");
else IntegratedDemonlist::loadAREDL(std::move(m_listener), [this] { populateList(""); });
else IntegratedDemonlist::loadAREDL(std::move(m_aredlListener), std::move(m_aredlOkListener), m_loadingCircle, [this] { populateList(""); });

return true;
}
Expand Down Expand Up @@ -206,7 +221,7 @@ void IDListLayer::addSearchBar() {
m_searchBarMenu->addChild(m_searchBar);
}

void IDListLayer::populateList(std::string query) {
void IDListLayer::showLoading() {
m_pageLabel->setString(std::to_string(m_page + 1).c_str());
m_loadingCircle->setVisible(true);
m_list->m_listView->setVisible(false);
Expand All @@ -218,6 +233,9 @@ void IDListLayer::populateList(std::string query) {
m_lastButton->setVisible(false);
m_pageButton->setVisible(false);
m_randomButton->setVisible(false);
}

void IDListLayer::populateList(std::string query) {
m_fullSearchResults.clear();

auto& list = PEMONLIST ? IntegratedDemonlist::PEMONLIST : IntegratedDemonlist::AREDL;
Expand Down Expand Up @@ -253,11 +271,6 @@ void IDListLayer::populateList(std::string query) {
}
}

int IDListLayer::getMaxPage() {
auto size = m_fullSearchResults.size();
return (size != 0 ? size % 10 == 0 ? size : size + (10 - (size % 10)) : 10) / 10 - 1;
}

void IDListLayer::loadLevelsFinished(CCArray* levels, const char*) {
auto winSize = CCDirector::sharedDirector()->getWinSize();
if (m_list->getParent() == this) removeChild(m_list);
Expand All @@ -271,7 +284,7 @@ void IDListLayer::loadLevelsFinished(CCArray* levels, const char*) {
m_countLabel->setVisible(true);
m_loadingCircle->setVisible(false);
if (m_fullSearchResults.size() > 10) {
auto maxPage = getMaxPage();
auto maxPage = (m_fullSearchResults.size() - 1) / 10;
m_leftButton->setVisible(m_page > 0);
m_rightButton->setVisible(m_page < maxPage);
m_firstButton->setVisible(m_page > 0);
Expand All @@ -296,20 +309,22 @@ void IDListLayer::setupPageInfo(gd::string, const char*) {

void IDListLayer::search() {
if (m_query != m_searchBarText) {
if (PEMONLIST) IntegratedDemonlist::loadPemonlist(std::move(m_listener), [this] {
showLoading();
if (PEMONLIST) IntegratedDemonlist::loadPemonlist(std::move(m_pemonlistListener), std::move(m_pemonlistOkListener), m_loadingCircle, [this] {
m_page = 0;
populateList(m_searchBarText);
});
else IntegratedDemonlist::loadAREDL(std::move(m_listener), [this] {
else IntegratedDemonlist::loadAREDL(std::move(m_aredlListener), std::move(m_aredlOkListener),m_loadingCircle, [this] {
m_page = 0;
populateList(m_searchBarText);
});
}
}

void IDListLayer::page(int page) {
auto maxPage = getMaxPage() + 1;
auto maxPage = (m_fullSearchResults.size() + 9) / 10;
m_page = (maxPage + (page % maxPage)) % maxPage;
showLoading();
populateList(m_query);
}

Expand Down Expand Up @@ -339,7 +354,8 @@ void IDListLayer::keyBackClicked() {
}

void IDListLayer::setIDPopupClosed(SetIDPopup*, int page) {
m_page = std::min(std::max(page - 1, 0), getMaxPage());
m_page = std::min(std::max(page - 1, 0), ((int)m_fullSearchResults.size() - 1) / 10);
showLoading();
populateList(m_query);
}

Expand Down
11 changes: 8 additions & 3 deletions src/IDListLayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ class IDListLayer : public CCLayer, SetIDPopupDelegate, LevelManagerDelegate {
void keyDown(enumKeyCodes) override;
void keyBackClicked() override;

~IDListLayer();
~IDListLayer() override;
protected:
EventListener<web::WebTask> m_listener;
EventListener<web::WebTask> m_aredlListener;
EventListener<web::WebTask> m_aredlOkListener;
EventListener<web::WebTask> m_pemonlistListener;
EventListener<web::WebTask> m_pemonlistOkListener;
GJListLayer* m_list;
CCLabelBMFont* m_listLabel;
LoadingCircle* m_loadingCircle;
Expand All @@ -36,15 +39,17 @@ class IDListLayer : public CCLayer, SetIDPopupDelegate, LevelManagerDelegate {
CCMenuItemSpriteExtra* m_randomButton;
CCMenuItemSpriteExtra* m_firstButton;
CCMenuItemSpriteExtra* m_lastButton;
CCMenuItemSpriteExtra* m_starToggle;
CCMenuItemSpriteExtra* m_moonToggle;
int m_page = 0;
std::string m_query = "";
std::string m_searchBarText = "";
std::vector<std::string> m_fullSearchResults;

bool init() override;
void addSearchBar();
void showLoading();
void populateList(std::string query);
int getMaxPage();
void loadLevelsFinished(CCArray*, const char*) override;
void loadLevelsFailed(const char*) override;
void loadLevelsFinished(CCArray* levels, const char* key, int) override {
Expand Down
78 changes: 61 additions & 17 deletions src/IntegratedDemonlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,98 @@ void IntegratedDemonlist::initializeDemons(web::WebResponse* res, bool pemonlist
}
}

void IntegratedDemonlist::loadAREDL() {
void IntegratedDemonlist::isOk(std::string const& url, utils::MiniFunction<void(bool, int)> callback) {
static std::optional<web::WebTask> task = std::nullopt;
task = web::WebRequest().get("https://api.aredl.net/api/aredl/levels").map([](web::WebResponse* res) {
if (res->ok()) initializeDemons(res, false);
else Notification::create("Failed to load AREDL", NotificationIcon::Error)->show();

task = web::WebRequest().send("HEAD", url).map([callback](web::WebResponse* res) {
callback(res->ok(), res->code());
task = std::nullopt;
return *res;
});
}

void IntegratedDemonlist::loadAREDL(EventListener<web::WebTask>&& listenerRef, utils::MiniFunction<void()> callback) {
void IntegratedDemonlist::isOk(std::string const& url, EventListener<web::WebTask>&& listenerRef, utils::MiniFunction<void(bool, int)> callback) {
auto&& listener = std::move(listenerRef);
listener.bind([callback](web::WebTask::Event* e) {
if (auto res = e->getValue()) callback(res->ok(), res->code());
});
listenerRef.setFilter(web::WebRequest().send("HEAD", url));
}

void IntegratedDemonlist::loadAREDL() {
static std::optional<web::WebTask> task = std::nullopt;
isOk("https://api.aredl.net/api/aredl/levels", [](bool ok, int code) {
if (!ok) {
log::error("Failed to load AREDL with status code {}", code);
return;
}

task = web::WebRequest().get("https://api.aredl.net/api/aredl/levels").map([](web::WebResponse* res) {
if (res->ok()) initializeDemons(res, false);

task = std::nullopt;
return *res;
});
});
}

void IntegratedDemonlist::loadAREDL(
EventListener<web::WebTask>&& listenerRef, EventListener<web::WebTask>&& okListener,
LoadingCircle* circle, utils::MiniFunction<void()> callback
) {
auto&& listener = std::move(listenerRef);
listener.bind([callback](web::WebTask::Event* e) {
if (auto res = e->getValue()) {
if (res->ok()) {
initializeDemons(res, false);
callback();
}
else FLAlertLayer::create("Load Failed", "Failed to load AREDL. Please try again later.", "OK")->show();
}
});

listener.setFilter(web::WebRequest().get("https://api.aredl.net/api/aredl/levels"));
isOk("https://api.aredl.net/api/aredl/levels", std::move(okListener), [&listener, circle](bool ok, int code) {
if (ok) listener.setFilter(web::WebRequest().get("https://api.aredl.net/api/aredl/levels"));
else Loader::get()->queueInMainThread([circle, code] {
FLAlertLayer::create(fmt::format("Load Failed ({})", code).c_str(), "Failed to load AREDL. Please try again later.", "OK")->show();
circle->setVisible(false);
});
});
}

void IntegratedDemonlist::loadPemonlist() {
static std::optional<web::WebTask> task = std::nullopt;
task = web::WebRequest().get("https://pemonlist.com/api/list").map([](web::WebResponse* res) {
if (res->ok()) initializeDemons(res, true);
else Notification::create("Failed to load Pemonlist", NotificationIcon::Error)->show();
isOk("https://pemonlist.com/api/list", [](bool ok, int code) {
if (!ok) {
log::error("Failed to load Pemonlist with status code {}", code);
return;
}

task = std::nullopt;
return *res;
task = web::WebRequest().get("https://pemonlist.com/api/list").map([](web::WebResponse* res) {
if (res->ok()) initializeDemons(res, true);

task = std::nullopt;
return *res;
});
});
}

void IntegratedDemonlist::loadPemonlist(EventListener<web::WebTask>&& listenerRef, utils::MiniFunction<void()> callback) {
void IntegratedDemonlist::loadPemonlist(
EventListener<web::WebTask>&& listenerRef, EventListener<web::WebTask>&& okListener,
LoadingCircle* circle, utils::MiniFunction<void()> callback
) {
auto&& listener = std::move(listenerRef);
listener.bind([callback](web::WebTask::Event* e) {
if (auto res = e->getValue()) {
if (res->ok()) {
initializeDemons(res, true);
callback();
}
else FLAlertLayer::create("Load Failed", "Failed to load Pemonlist. Please try again later.", "OK")->show();
}
});

listener.setFilter(web::WebRequest().get("https://pemonlist.com/api/list"));
isOk("https://pemonlist.com/api/list", std::move(okListener), [&listener, circle](bool ok, int code) {
if (ok) listener.setFilter(web::WebRequest().get("https://pemonlist.com/api/list"));
else Loader::get()->queueInMainThread([circle, code] {
FLAlertLayer::create(fmt::format("Load Failed ({})", code).c_str(), "Failed to load Pemonlist. Please try again later.", "OK")->show();
circle->setVisible(false);
});
});
}
Loading

0 comments on commit e7101c7

Please sign in to comment.