mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
Merge branch 'main' of https://github.com/geode-sdk/geode into main
This commit is contained in:
commit
c440aaa7cc
23 changed files with 322 additions and 169 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,6 +4,3 @@
|
|||
[submodule "loader/minhook"]
|
||||
path = loader/minhook
|
||||
url = https://github.com/TsudaKageyu/minhook
|
||||
[submodule "loader/include/Geode/external/scnlib"]
|
||||
path = loader/include/Geode/external/scnlib
|
||||
url = https://github.com/eliaskosunen/scnlib
|
||||
|
|
|
@ -83,7 +83,6 @@ add_definitions(-DFMT_CONSTEVAL=)
|
|||
|
||||
add_subdirectory(loader/include/Geode/external/filesystem)
|
||||
add_subdirectory(loader/include/Geode/external/fmt)
|
||||
add_subdirectory(loader/include/Geode/external/scnlib)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE filesystem fmt)
|
||||
|
||||
|
|
|
@ -237,8 +237,8 @@ class cocos2d::CCIMEDispatcher {
|
|||
static auto sharedDispatcher() = mac 0x2773f0, ios 0x12d170;
|
||||
auto addDelegate(cocos2d::CCIMEDelegate*) = mac 0x277480, ios 0x12d204;
|
||||
auto removeDelegate(cocos2d::CCIMEDelegate*) = mac 0x2775f0, ios 0x12d2c4;
|
||||
void dispatchInsertText(const char* text, int len);
|
||||
void dispatchDeleteBackward();
|
||||
void dispatchInsertText(const char* text, int len) = mac 0x277ac0;
|
||||
void dispatchDeleteBackward() = mac 0x277af0;
|
||||
}
|
||||
|
||||
class cocos2d::CCImage {
|
||||
|
|
|
@ -129,7 +129,7 @@ target_link_libraries(${PROJECT_NAME} md4c)
|
|||
|
||||
# Lilac (hooking)
|
||||
add_subdirectory(lilac)
|
||||
target_link_libraries(${PROJECT_NAME} z lilac_hook geode-sdk scn::scn)
|
||||
target_link_libraries(${PROJECT_NAME} z lilac_hook geode-sdk)
|
||||
|
||||
# Use precompiled headers for faster builds
|
||||
target_precompile_headers(${PROJECT_NAME} PRIVATE
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "ui/BasedButtonSprite.hpp"
|
||||
#include "ui/IconButtonSprite.hpp"
|
||||
#include "ui/InputNode.hpp"
|
||||
#include "ui/LayerBG.hpp"
|
||||
#include "ui/General.hpp"
|
||||
#include "ui/ListView.hpp"
|
||||
#include "ui/MDPopup.hpp"
|
||||
#include "ui/MDTextArea.hpp"
|
||||
|
|
1
loader/include/Geode/external/scnlib
vendored
1
loader/include/Geode/external/scnlib
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit 72a4bab9e32f2b44593137fba40c54710e20a623
|
|
@ -196,7 +196,7 @@ namespace geode::core::meta::x86 {
|
|||
class Membercall<Ret, Class, Args...> {
|
||||
|
||||
protected:
|
||||
using Sequences = Membercall<Ret*, Class, Ret*, Args...>::Sequences;
|
||||
using Sequences = typename Membercall<Ret*, Class, Ret*, Args...>::Sequences;
|
||||
|
||||
// Where all the logic is actually implemented.
|
||||
template <class Class, class>
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#define GEODE_API extern "C" __declspec(dllexport)
|
||||
#define GEODE_EXPORT __declspec(dllexport)
|
||||
|
||||
static_assert(sizeof(void*) == 4, "Geode must be compiled in 32-bit for Windows!");
|
||||
|
||||
#include "windows.hpp"
|
||||
|
||||
#elif defined(GEODE_IS_MACOS)
|
||||
|
|
|
@ -10,4 +10,13 @@ namespace geode {
|
|||
* packs the ability to override this function.
|
||||
*/
|
||||
GEODE_DLL cocos2d::CCSprite* createLayerBG();
|
||||
|
||||
/**
|
||||
* Add the rounded comment borders to a node
|
||||
*/
|
||||
GEODE_DLL void addListBorders(
|
||||
cocos2d::CCNode* to,
|
||||
cocos2d::CCPoint const& center,
|
||||
cocos2d::CCSize const& size
|
||||
);
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include <string_view>
|
||||
#include "../external/json/json.hpp"
|
||||
#include <tuple>
|
||||
#include "../utils/Result.hpp"
|
||||
|
||||
namespace geode {
|
||||
enum class VersionCompare {
|
||||
|
@ -55,8 +56,8 @@ namespace geode {
|
|||
m_patch = patch;
|
||||
m_tag = tag;
|
||||
}
|
||||
VersionInfo(std::string const& versionString);
|
||||
static bool validate(std::string const& string);
|
||||
|
||||
static Result<VersionInfo> parse(std::string const& string);
|
||||
|
||||
constexpr size_t getMajor() const {
|
||||
return m_major;
|
||||
|
@ -114,8 +115,8 @@ namespace geode {
|
|||
VersionInfo const& version,
|
||||
VersionCompare const& compare
|
||||
) : m_version(version), m_compare(compare) {}
|
||||
ComparableVersionInfo(std::string const& versionString);
|
||||
static bool validate(std::string const& string);
|
||||
|
||||
static Result<ComparableVersionInfo> parse(std::string const& string);
|
||||
|
||||
constexpr bool compare(VersionInfo const& version) const {
|
||||
switch (m_compare) {
|
||||
|
|
|
@ -32,4 +32,4 @@ BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID _) {
|
|||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
|||
using nlohmann::detail::value_t;
|
||||
|
||||
root.needs("id").validate(&ModInfo::validateID).into(info.id);
|
||||
root.needs("version").validate(&VersionInfo::validate).into(info.version);
|
||||
root.needs("version").into(info.version);
|
||||
root.needs("name").into(info.name);
|
||||
root.needs("developer").into(info.developer);
|
||||
root.has("description").into(info.description);
|
||||
|
@ -62,9 +62,7 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
|||
|
||||
auto depobj = Dependency {};
|
||||
obj.needs("id").validate(&ModInfo::validateID).into(depobj.id);
|
||||
obj.needs("version")
|
||||
.validate(&ComparableVersionInfo::validate)
|
||||
.into(depobj.version);
|
||||
obj.needs("version").into(depobj.version);
|
||||
obj.has("required").into(depobj.required);
|
||||
obj.checkUnknownKeys();
|
||||
|
||||
|
@ -116,16 +114,10 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
|
|||
// Check mod.json target version
|
||||
auto schema = LOADER_VERSION;
|
||||
if (json.contains("geode") && json["geode"].is_string()) {
|
||||
auto ver = json["geode"];
|
||||
if (VersionInfo::validate(ver)) {
|
||||
schema = VersionInfo(ver);
|
||||
}
|
||||
else {
|
||||
return Err(
|
||||
"[mod.json] has no target loader version "
|
||||
"specified, or it is invalidally formatted (required: \"[v]X.X.X\")!"
|
||||
);
|
||||
}
|
||||
GEODE_UNWRAP_INTO(
|
||||
schema, VersionInfo::parse(json["geode"])
|
||||
.expect("[mod.json] has invalid target loader version: {error}")
|
||||
);
|
||||
}
|
||||
else {
|
||||
return Err(
|
||||
|
|
55
loader/src/ui/internal/info/DevProfilePopup.cpp
Normal file
55
loader/src/ui/internal/info/DevProfilePopup.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "DevProfilePopup.hpp"
|
||||
#include <Geode/ui/ListView.hpp>
|
||||
#include <Geode/loader/Index.hpp>
|
||||
#include <Geode/ui/General.hpp>
|
||||
#include "../list/ModListCell.hpp"
|
||||
#include "../list/ModListLayer.hpp"
|
||||
|
||||
bool DevProfilePopup::setup(std::string const& developer) {
|
||||
m_noElasticity = true;
|
||||
|
||||
this->setTitle("Mods by " + developer);
|
||||
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
auto items = CCArray::create();
|
||||
|
||||
// installed mods
|
||||
for (auto& mod : Loader::get()->getAllMods()) {
|
||||
if (mod->getDeveloper() == developer) {
|
||||
items->addObject(ModCell::create(
|
||||
mod, nullptr, ModListDisplay::Concise, { 358.f, 40.f }
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// index mods
|
||||
for (auto& item : Index::get()->getItemsByDeveloper(developer)) {
|
||||
if (Loader::get()->isModInstalled(item->info.id)) {
|
||||
continue;
|
||||
}
|
||||
items->addObject(IndexItemCell::create(
|
||||
item, nullptr, ModListDisplay::Concise, { 358.f, 40.f }
|
||||
));
|
||||
}
|
||||
|
||||
// mods list
|
||||
auto listSize = CCSize { 358.f, 160.f };
|
||||
auto list = ListView::create(items, 40.f, listSize.width, listSize.height);
|
||||
list->setPosition(winSize / 2 - listSize / 2);
|
||||
m_mainLayer->addChild(list);
|
||||
|
||||
addListBorders(m_mainLayer, winSize / 2, listSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DevProfilePopup* DevProfilePopup::create(std::string const& developer) {
|
||||
auto ret = new DevProfilePopup();
|
||||
if (ret && ret->init(420.f, 260.f, developer)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
13
loader/src/ui/internal/info/DevProfilePopup.hpp
Normal file
13
loader/src/ui/internal/info/DevProfilePopup.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
class DevProfilePopup : public Popup<std::string const&> {
|
||||
protected:
|
||||
bool setup(std::string const& developer) override;
|
||||
|
||||
public:
|
||||
static DevProfilePopup* create(std::string const& developer);
|
||||
};
|
|
@ -423,7 +423,9 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) {
|
|||
"need to <cg>restart</c> the game to have it fully unloaded.",
|
||||
"OK"
|
||||
)->show();
|
||||
if (m_layer) m_layer->updateAllStates(nullptr);
|
||||
if (m_layer) {
|
||||
m_layer->updateAllStates(nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (as<CCMenuItemToggler*>(sender)->isToggled()) {
|
||||
|
@ -438,7 +440,9 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) {
|
|||
FLAlertLayer::create(nullptr, "Error Disabling Mod", res.unwrapErr(), "OK", nullptr)->show();
|
||||
}
|
||||
}
|
||||
if (m_layer) m_layer->updateAllStates(nullptr);
|
||||
if (m_layer) {
|
||||
m_layer->updateAllStates(nullptr);
|
||||
}
|
||||
as<CCMenuItemToggler*>(sender)->toggle(m_mod->isEnabled());
|
||||
}
|
||||
|
||||
|
@ -477,7 +481,9 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) {
|
|||
FLAlertLayer::create("Error", "Unable to delete mod's save directory!", "OK")->show();
|
||||
}
|
||||
}
|
||||
if (m_layer) m_layer->reloadList();
|
||||
if (m_layer) {
|
||||
m_layer->reloadList();
|
||||
}
|
||||
this->onClose(nullptr);
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include "ModListCell.hpp"
|
||||
#include "ModListLayer.hpp"
|
||||
#include "../info/ModInfoPopup.hpp"
|
||||
|
||||
#include <Geode/binding/ButtonSprite.hpp>
|
||||
#include <Geode/binding/CCMenuItemSpriteExtra.hpp>
|
||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include <Geode/ui/GeodeUI.hpp>
|
||||
#include "../../../loader/LoaderImpl.hpp" // how should i include this src/loader/LoaderImpl.hpp
|
||||
#include "../info/TagNode.hpp"
|
||||
#include "../info/DevProfilePopup.hpp"
|
||||
|
||||
template <class T>
|
||||
static bool tryOrAlert(Result<T> const& res, char const* title) {
|
||||
|
@ -27,7 +28,11 @@ float ModListCell::getLogoSize() const {
|
|||
return m_height / 1.5f;
|
||||
}
|
||||
|
||||
void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
|
||||
void ModListCell::setupInfo(
|
||||
ModInfo const& info,
|
||||
bool spaceForTags,
|
||||
ModListDisplay display
|
||||
) {
|
||||
m_menu = CCMenu::create();
|
||||
m_menu->setPosition(m_width - 40.f, m_height / 2);
|
||||
this->addChild(m_menu);
|
||||
|
@ -39,7 +44,7 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
|
|||
this->addChild(logoSpr);
|
||||
|
||||
bool hasDesc =
|
||||
m_layer->getDisplay() == ModListDisplay::Expanded &&
|
||||
display == ModListDisplay::Expanded &&
|
||||
info.description.has_value();
|
||||
|
||||
auto titleLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt");
|
||||
|
@ -135,8 +140,7 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
|
|||
}
|
||||
|
||||
void ModListCell::onViewDev(CCObject*) {
|
||||
m_layer->getQuery().developer = this->getDeveloper();
|
||||
m_layer->reloadList();
|
||||
DevProfilePopup::create(this->getDeveloper())->show();
|
||||
}
|
||||
|
||||
bool ModListCell::init(ModListLayer* list, CCSize const& size) {
|
||||
|
@ -153,10 +157,11 @@ bool ModListCell::init(ModListLayer* list, CCSize const& size) {
|
|||
ModCell* ModCell::create(
|
||||
Mod* mod,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
auto ret = new ModCell();
|
||||
if (ret && ret->init(mod, list, size)) {
|
||||
if (ret && ret->init(mod, list, display, size)) {
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
|
@ -173,7 +178,9 @@ void ModCell::onEnable(CCObject* sender) {
|
|||
"need to <cg>restart</c> the game to have it fully unloaded.",
|
||||
"OK"
|
||||
)->show();
|
||||
m_layer->updateAllStates(this);
|
||||
if (m_layer) {
|
||||
m_layer->updateAllStates(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!as<CCMenuItemToggler*>(sender)->isToggled()) {
|
||||
|
@ -182,7 +189,9 @@ void ModCell::onEnable(CCObject* sender) {
|
|||
else {
|
||||
tryOrAlert(m_mod->disable(), "Error disabling mod");
|
||||
}
|
||||
m_layer->updateAllStates(this);
|
||||
if (m_layer) {
|
||||
m_layer->updateAllStates(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ModCell::onUnresolvedInfo(CCObject*) {
|
||||
|
@ -220,6 +229,7 @@ void ModCell::updateState() {
|
|||
bool ModCell::init(
|
||||
Mod* mod,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
if (!ModListCell::init(list, size))
|
||||
|
@ -227,7 +237,7 @@ bool ModCell::init(
|
|||
|
||||
m_mod = mod;
|
||||
|
||||
this->setupInfo(mod->getModInfo(), false);
|
||||
this->setupInfo(mod->getModInfo(), false, display);
|
||||
|
||||
auto viewSpr = ButtonSprite::create("View", "bigFont.fnt", "GJ_button_01.png", .8f);
|
||||
viewSpr->setScale(.65f);
|
||||
|
@ -285,10 +295,11 @@ void IndexItemCell::onInfo(CCObject*) {
|
|||
IndexItemCell* IndexItemCell::create(
|
||||
IndexItemHandle item,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
auto ret = new IndexItemCell();
|
||||
if (ret && ret->init(item, list, size)) {
|
||||
if (ret && ret->init(item, list, display, size)) {
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
|
@ -298,6 +309,7 @@ IndexItemCell* IndexItemCell::create(
|
|||
bool IndexItemCell::init(
|
||||
IndexItemHandle item,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
if (!ModListCell::init(list, size))
|
||||
|
@ -305,7 +317,7 @@ bool IndexItemCell::init(
|
|||
|
||||
m_item = item;
|
||||
|
||||
this->setupInfo(item->info, item->tags.size());
|
||||
this->setupInfo(item->info, item->tags.size(), display);
|
||||
|
||||
auto viewSpr = ButtonSprite::create(
|
||||
"View", "bigFont.fnt", "GJ_button_01.png", .8f
|
||||
|
@ -384,13 +396,16 @@ void InvalidGeodeFileCell::FLAlert_Clicked(FLAlertLayer*, bool btn2) {
|
|||
->show();
|
||||
}
|
||||
Loader::get()->refreshModsList();
|
||||
m_layer->reloadList();
|
||||
if (m_layer) {
|
||||
m_layer->reloadList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InvalidGeodeFileCell::init(
|
||||
InvalidGeodeFile const& info,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
if (!ModListCell::init(list, size))
|
||||
|
@ -431,10 +446,11 @@ bool InvalidGeodeFileCell::init(
|
|||
InvalidGeodeFileCell* InvalidGeodeFileCell::create(
|
||||
InvalidGeodeFile const& file,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
) {
|
||||
auto ret = new InvalidGeodeFileCell();
|
||||
if (ret && ret->init(file, list, size)) {
|
||||
if (ret && ret->init(file, list, display, size)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ protected:
|
|||
CCMenuItemSpriteExtra* m_unresolvedExMark;
|
||||
|
||||
bool init(ModListLayer* list, CCSize const& size);
|
||||
void setupInfo(ModInfo const& info, bool spaceForTags);
|
||||
void setupInfo(ModInfo const& info, bool spaceForTags, ModListDisplay display);
|
||||
void draw() override;
|
||||
|
||||
float getLogoSize() const;
|
||||
|
@ -47,6 +47,7 @@ protected:
|
|||
bool init(
|
||||
Mod* mod,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
@ -58,6 +59,7 @@ public:
|
|||
static ModCell* create(
|
||||
Mod* mod,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
@ -76,6 +78,7 @@ protected:
|
|||
bool init(
|
||||
IndexItemHandle item,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
@ -85,6 +88,7 @@ public:
|
|||
static IndexItemCell* create(
|
||||
IndexItemHandle item,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
@ -103,6 +107,7 @@ protected:
|
|||
bool init(
|
||||
InvalidGeodeFile const& file,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
@ -113,6 +118,7 @@ public:
|
|||
static InvalidGeodeFileCell* create(
|
||||
InvalidGeodeFile const& file,
|
||||
ModListLayer* list,
|
||||
ModListDisplay display,
|
||||
CCSize const& size
|
||||
);
|
||||
|
||||
|
|
|
@ -73,12 +73,9 @@ static std::optional<int> queryMatchKeywords(
|
|||
}
|
||||
|
||||
static std::optional<int> queryMatch(ModListQuery const& query, Mod* mod) {
|
||||
// Only checking keywords and developer makes sense for mods since their
|
||||
// Only checking keywords makes sense for mods since their
|
||||
// platform always matches, they are always visible and they don't
|
||||
// currently list their tags
|
||||
if (query.developer && query.developer.value() != mod->getDeveloper()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return queryMatchKeywords(query, mod->getModInfo());
|
||||
}
|
||||
|
||||
|
@ -88,10 +85,6 @@ static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle
|
|||
if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// make sure developer matches
|
||||
if (query.developer && query.developer.value() != item->info.developer) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// make sure all tags match
|
||||
for (auto& tag : query.tags) {
|
||||
if (!item->tags.count(tag)) {
|
||||
|
@ -127,7 +120,6 @@ static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle
|
|||
static std::optional<int> queryMatch(ModListQuery const& query, InvalidGeodeFile const& info) {
|
||||
// if any explicit filters were provided, no match
|
||||
if (
|
||||
query.developer.has_value() ||
|
||||
query.tags.size() ||
|
||||
query.keywords.has_value()
|
||||
) {
|
||||
|
@ -144,7 +136,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
|||
// failed mods first
|
||||
for (auto const& mod : Loader::get()->getFailedMods()) {
|
||||
if (!queryMatch(query, mod)) continue;
|
||||
mods->addObject(InvalidGeodeFileCell::create(mod, this, this->getCellSize()));
|
||||
mods->addObject(InvalidGeodeFileCell::create(
|
||||
mod, this, m_display, this->getCellSize()
|
||||
));
|
||||
}
|
||||
|
||||
// sort the mods by match score
|
||||
|
@ -173,7 +167,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
|||
|
||||
// add the mods sorted
|
||||
for (auto& [score, mod] : ranges::reverse(sorted)) {
|
||||
mods->addObject(ModCell::create(mod, this, this->getCellSize()));
|
||||
mods->addObject(ModCell::create(
|
||||
mod, this, m_display, this->getCellSize()
|
||||
));
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -189,7 +185,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
|||
|
||||
// add the mods sorted
|
||||
for (auto& [score, item] : ranges::reverse(sorted)) {
|
||||
mods->addObject(IndexItemCell::create(item, this, this->getCellSize()));
|
||||
mods->addObject(IndexItemCell::create(
|
||||
item, this, m_display, this->getCellSize()
|
||||
));
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -205,7 +203,9 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
|||
|
||||
// add the mods sorted
|
||||
for (auto& [score, item] : ranges::reverse(sorted)) {
|
||||
mods->addObject(IndexItemCell::create(item, this, this->getCellSize()));
|
||||
mods->addObject(IndexItemCell::create(
|
||||
item, this, m_display, this->getCellSize()
|
||||
));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -489,8 +489,7 @@ void ModListLayer::reloadList(std::optional<ModListQuery> const& query) {
|
|||
// and show visual indicator if so
|
||||
auto hasQuery =
|
||||
(m_searchInput->getString() &&
|
||||
strlen(m_searchInput->getString())) ||
|
||||
m_query.developer;
|
||||
strlen(m_searchInput->getString()));
|
||||
m_searchBtn->setVisible(!hasQuery);
|
||||
m_searchClearBtn->setVisible(hasQuery);
|
||||
|
||||
|
@ -606,8 +605,6 @@ void ModListLayer::onOpenFolder(CCObject*) {
|
|||
}
|
||||
|
||||
void ModListLayer::onResetSearch(CCObject*) {
|
||||
// todo: remove when implementing more reasonable developer view
|
||||
m_query.developer = std::nullopt;
|
||||
m_searchInput->setString("");
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,6 @@ struct ModListQuery {
|
|||
*/
|
||||
std::unordered_set<PlatformID> platforms = { GEODE_PLATFORM_TARGET };
|
||||
std::unordered_set<std::string> tags;
|
||||
/**
|
||||
* Used to filter by dev if you click their name
|
||||
*/
|
||||
std::optional<std::string> developer;
|
||||
};
|
||||
|
||||
class ModListLayer : public CCLayer, public TextInputDelegate {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <Geode/loader/Setting.hpp>
|
||||
#include <Geode/ui/ScrollLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/ui/General.hpp>
|
||||
|
||||
bool ModSettingsPopup::setup(Mod* mod) {
|
||||
m_noElasticity = true;
|
||||
|
@ -77,29 +78,7 @@ bool ModSettingsPopup::setup(Mod* mod) {
|
|||
|
||||
// layer borders
|
||||
|
||||
auto layerTopSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png");
|
||||
layerTopSpr->setPosition({ winSize.width / 2, winSize.height / 2 + layerSize.height / 2 - 5.f }
|
||||
);
|
||||
m_mainLayer->addChild(layerTopSpr);
|
||||
|
||||
auto layerBottomSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png");
|
||||
layerBottomSpr->setFlipY(true);
|
||||
layerBottomSpr->setPosition({ winSize.width / 2,
|
||||
winSize.height / 2 - layerSize.height / 2 + 5.f });
|
||||
m_mainLayer->addChild(layerBottomSpr);
|
||||
|
||||
auto layerLeftSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png");
|
||||
layerLeftSpr->setScaleY(6.3f);
|
||||
layerLeftSpr->setPosition({ winSize.width / 2 - layerSize.width / 2 - .5f, winSize.height / 2 }
|
||||
);
|
||||
m_mainLayer->addChild(layerLeftSpr);
|
||||
|
||||
auto layerRightSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png");
|
||||
layerRightSpr->setScaleY(6.3f);
|
||||
layerRightSpr->setFlipX(true);
|
||||
layerRightSpr->setPosition({ winSize.width / 2 + layerSize.width / 2 + .5f, winSize.height / 2 }
|
||||
);
|
||||
m_mainLayer->addChild(layerRightSpr);
|
||||
addListBorders(m_mainLayer, winSize / 2, layerSize);
|
||||
|
||||
// buttons
|
||||
|
||||
|
|
91
loader/src/ui/nodes/General.cpp
Normal file
91
loader/src/ui/nodes/General.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include <Geode/ui/General.hpp>
|
||||
#include <cocos-ext.h>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
CCSprite* geode::createLayerBG() {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
auto bg = CCSprite::create("GJ_gradientBG.png");
|
||||
auto bgSize = bg->getTextureRect().size;
|
||||
|
||||
bg->setAnchorPoint({ 0.0f, 0.0f });
|
||||
bg->setScaleX((winSize.width + 10.0f) / bgSize.width);
|
||||
bg->setScaleY((winSize.height + 10.0f) / bgSize.height);
|
||||
bg->setPosition({ -5.0f, -5.0f });
|
||||
bg->setColor({ 0, 102, 255 }); // todo: let mods customize this
|
||||
|
||||
return bg;
|
||||
}
|
||||
|
||||
void geode::addListBorders(CCNode* to, CCPoint const& center, CCSize const& size) {
|
||||
// if the size is 346.f, the top aligns perfectly by default :3
|
||||
if (size.width == 346.f) {
|
||||
auto layerTopSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png");
|
||||
layerTopSpr->setPosition({
|
||||
center.x,
|
||||
center.y + size.height / 2 - 5.f
|
||||
});
|
||||
to->addChild(layerTopSpr);
|
||||
|
||||
auto layerBottomSpr = CCSprite::createWithSpriteFrameName("GJ_commentTop_001.png");
|
||||
layerBottomSpr->setFlipY(true);
|
||||
layerBottomSpr->setPosition({
|
||||
center.x,
|
||||
center.y - size.height / 2 + 5.f
|
||||
});
|
||||
to->addChild(layerBottomSpr);
|
||||
}
|
||||
// otherwise stretch using CCScale9Sprite
|
||||
else {
|
||||
auto layerTopSpr = CCScale9Sprite::createWithSpriteFrameName(
|
||||
"GJ_commentTop_001.png",
|
||||
{ 0, 0, 240, 20 }
|
||||
);
|
||||
layerTopSpr->setContentSize({
|
||||
size.width + 9.f,
|
||||
layerTopSpr->getContentSize().height,
|
||||
});
|
||||
layerTopSpr->setPosition({
|
||||
center.x,
|
||||
center.y + size.height / 2 - 5.f
|
||||
});
|
||||
to->addChild(layerTopSpr);
|
||||
|
||||
auto layerBottomSpr = CCScale9Sprite::createWithSpriteFrameName(
|
||||
"GJ_commentTop_001.png",
|
||||
{ 0, 0, 240, 20 }
|
||||
);
|
||||
layerBottomSpr->setScaleY(-1);
|
||||
layerBottomSpr->setContentSize({
|
||||
size.width + 9.f,
|
||||
layerBottomSpr->getContentSize().height,
|
||||
});
|
||||
layerBottomSpr->setPosition({
|
||||
center.x,
|
||||
center.y - size.height / 2 + 5.f
|
||||
});
|
||||
to->addChild(layerBottomSpr);
|
||||
}
|
||||
|
||||
auto layerLeftSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png");
|
||||
layerLeftSpr->setScaleY(
|
||||
(size.height - 30.f) / layerLeftSpr->getScaledContentSize().height
|
||||
);
|
||||
layerLeftSpr->setPosition({
|
||||
center.x - size.width / 2 - .5f,
|
||||
center.y
|
||||
});
|
||||
to->addChild(layerLeftSpr);
|
||||
|
||||
auto layerRightSpr = CCSprite::createWithSpriteFrameName("GJ_commentSide_001.png");
|
||||
layerRightSpr->setScaleY(
|
||||
(size.height - 30.f) / layerRightSpr->getScaledContentSize().height
|
||||
);
|
||||
layerRightSpr->setFlipX(true);
|
||||
layerRightSpr->setPosition({
|
||||
center.x + size.width / 2 + .5f,
|
||||
center.y
|
||||
});
|
||||
to->addChild(layerRightSpr);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#include <Geode/ui/LayerBG.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
CCSprite* geode::createLayerBG() {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
|
||||
auto bg = CCSprite::create("GJ_gradientBG.png");
|
||||
auto bgSize = bg->getTextureRect().size;
|
||||
|
||||
bg->setAnchorPoint({ 0.0f, 0.0f });
|
||||
bg->setScaleX((winSize.width + 10.0f) / bgSize.width);
|
||||
bg->setScaleY((winSize.height + 10.0f) / bgSize.height);
|
||||
bg->setPosition({ -5.0f, -5.0f });
|
||||
bg->setColor({ 0, 102, 255 }); // todo: let mods customize this
|
||||
|
||||
return bg;
|
||||
}
|
|
@ -4,16 +4,9 @@
|
|||
|
||||
#include <Geode/utils/VersionInfo.hpp>
|
||||
#include <Geode/utils/general.hpp>
|
||||
#include <Geode/external/scnlib/include/scn/scn.h>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
#define GEODE_SSCANF sscanf_s
|
||||
#else
|
||||
#define GEODE_SSCANF sscanf
|
||||
#endif
|
||||
|
||||
// VersionTag
|
||||
|
||||
std::optional<VersionTag> geode::versionTagFromString(std::string const& str) {
|
||||
|
@ -45,37 +38,57 @@ std::string geode::versionTagToString(VersionTag tag) {
|
|||
|
||||
// VersionInfo
|
||||
|
||||
bool VersionInfo::validate(std::string const& string) {
|
||||
std::string copy = string;
|
||||
if (copy.starts_with("v")) {
|
||||
copy = string.substr(1);
|
||||
}
|
||||
|
||||
int buf0, buf1, buf2;
|
||||
std::string bufT;
|
||||
if (scn::scan(copy, "{}.{}.{}-{}", buf0, buf1, buf2, bufT)) {
|
||||
return versionTagFromString(bufT).has_value();
|
||||
}
|
||||
if (scn::scan(copy, "{}.{}.{}", buf0, buf1, buf2)) {
|
||||
return true;
|
||||
Result<VersionInfo> VersionInfo::parse(std::string const& string) {
|
||||
std::stringstream str (string);
|
||||
|
||||
// allow leading v
|
||||
if (str.peek() == 'v') {
|
||||
str.get();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
VersionInfo::VersionInfo(std::string const& string) {
|
||||
std::string copy = string;
|
||||
if (copy.starts_with("v")) {
|
||||
copy = string.substr(1);
|
||||
size_t major;
|
||||
str >> major;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse major");
|
||||
}
|
||||
std::string tag;
|
||||
scn::scan(copy, "{}.{}.{}-{}", m_major, m_minor, m_patch, tag) ||
|
||||
scn::scan(copy, "{}.{}.{}", m_major, m_minor, m_patch);
|
||||
if (tag.size()) {
|
||||
if (auto t = versionTagFromString(tag)) {
|
||||
m_tag = t;
|
||||
|
||||
if (str.get() != '.') {
|
||||
return Err("Minor version missing");
|
||||
}
|
||||
|
||||
size_t minor;
|
||||
str >> minor;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse minor");
|
||||
}
|
||||
|
||||
if (str.get() != '.') {
|
||||
return Err("Patch version missing");
|
||||
}
|
||||
|
||||
size_t patch;
|
||||
str >> patch;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse patch");
|
||||
}
|
||||
|
||||
// tag
|
||||
std::optional<VersionTag> tag;
|
||||
if (str.peek() == '-') {
|
||||
str.get();
|
||||
std::string iden;
|
||||
str >> iden;
|
||||
if (str.fail()) {
|
||||
return Err("Unable to parse tag");
|
||||
}
|
||||
if (auto t = versionTagFromString(iden)) {
|
||||
tag = t;
|
||||
}
|
||||
else {
|
||||
return Err("Invalid tag \"" + iden + "\"");
|
||||
}
|
||||
}
|
||||
return Ok(VersionInfo(major, minor, patch, tag));
|
||||
}
|
||||
|
||||
std::string VersionInfo::toString(bool includeTag) const {
|
||||
|
@ -94,7 +107,13 @@ void geode::to_json(nlohmann::json& json, VersionInfo const& info) {
|
|||
}
|
||||
|
||||
void geode::from_json(nlohmann::json const& json, VersionInfo& info) {
|
||||
info = VersionInfo(json.template get<std::string>());
|
||||
auto ver = VersionInfo::parse(json.template get<std::string>());
|
||||
if (!ver) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Invalid version format: " + ver.unwrapErr(), json
|
||||
);
|
||||
}
|
||||
info = ver.unwrap();
|
||||
}
|
||||
|
||||
std::ostream& geode::operator<<(std::ostream& stream, VersionInfo const& version) {
|
||||
|
@ -103,35 +122,23 @@ std::ostream& geode::operator<<(std::ostream& stream, VersionInfo const& version
|
|||
|
||||
// ComparableVersionInfo
|
||||
|
||||
ComparableVersionInfo::ComparableVersionInfo(std::string const& rawStr) {
|
||||
auto version = rawStr;
|
||||
if (version.starts_with("<=")) {
|
||||
m_compare = VersionCompare::LessEq;
|
||||
version.erase(0, 2);
|
||||
Result<ComparableVersionInfo> ComparableVersionInfo::parse(std::string const& rawStr) {
|
||||
VersionCompare compare;
|
||||
auto string = rawStr;
|
||||
if (string.starts_with("<=")) {
|
||||
compare = VersionCompare::LessEq;
|
||||
string.erase(0, 2);
|
||||
}
|
||||
else if (version.starts_with(">=")) {
|
||||
m_compare = VersionCompare::MoreEq;
|
||||
version.erase(0, 2);
|
||||
else if (string.starts_with(">=")) {
|
||||
compare = VersionCompare::MoreEq;
|
||||
string.erase(0, 2);
|
||||
}
|
||||
else if (version.starts_with("==")) {
|
||||
m_compare = VersionCompare::Exact;
|
||||
version.erase(0, 2);
|
||||
else if (string.starts_with("==")) {
|
||||
compare = VersionCompare::Exact;
|
||||
string.erase(0, 2);
|
||||
}
|
||||
m_version = VersionInfo(version);
|
||||
}
|
||||
|
||||
bool ComparableVersionInfo::validate(std::string const& rawStr) {
|
||||
auto version = rawStr;
|
||||
// remove prefix
|
||||
if (
|
||||
version.starts_with("<=") ||
|
||||
version.starts_with(">=") ||
|
||||
version.starts_with("==")
|
||||
) {
|
||||
version.erase(0, 2);
|
||||
}
|
||||
// otherwise there's no prefix or it's invalid
|
||||
return VersionInfo::validate(version);
|
||||
GEODE_UNWRAP_INTO(auto version, VersionInfo::parse(string));
|
||||
return Ok(ComparableVersionInfo(version, compare));
|
||||
}
|
||||
|
||||
std::string ComparableVersionInfo::toString() const {
|
||||
|
@ -149,7 +156,13 @@ void geode::to_json(nlohmann::json& json, ComparableVersionInfo const& info) {
|
|||
}
|
||||
|
||||
void geode::from_json(nlohmann::json const& json, ComparableVersionInfo& info) {
|
||||
info = ComparableVersionInfo(json.template get<std::string>());
|
||||
auto ver = ComparableVersionInfo::parse(json.template get<std::string>());
|
||||
if (!ver) {
|
||||
throw nlohmann::json::type_error::create(
|
||||
0, "Invalid version format: " + ver.unwrapErr(), json
|
||||
);
|
||||
}
|
||||
info = ver.unwrap();
|
||||
}
|
||||
|
||||
std::ostream& geode::operator<<(std::ostream& stream, ComparableVersionInfo const& version) {
|
||||
|
|
Loading…
Reference in a new issue