diff --git a/.clang-format b/.clang-format index cfe174c5..48451bcf 100644 --- a/.clang-format +++ b/.clang-format @@ -79,11 +79,12 @@ IncludeCategories: IndentAccessModifiers: false AccessModifierOffset: -4 -IndentCaseBlocks: true +IndentCaseBlocks: false IndentCaseLabels: true IndentExternBlock: Indent IndentGotoLabels: true IndentPPDirectives: BeforeHash +IndentRequiresClause: false IndentWrappedFunctionNames: false # InsertBraces: true InsertTrailingCommas: None @@ -107,6 +108,7 @@ PenaltyIndentedWhitespace: 0 QualifierAlignment: Right +RequiresClausePosition: OwnLine ReflowComments: true SeparateDefinitionBlocks: Always diff --git a/CMakeLists.txt b/CMakeLists.txt index 2056dd9f..a026eddf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,6 @@ target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp) add_subdirectory(codegen) -message(STATUS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp) add_custom_command( DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bindings/GeometryDash.bro ${CMAKE_CURRENT_SOURCE_DIR}/bindings/Cocos2d.bro @@ -106,7 +105,7 @@ elseif(EXISTS ${GEODE_PLATFORM_BIN_PATH}) ) else() message(FATAL_ERROR - "No valid loader binary to link to! Install prebuilts with `geode sdk install-prebuilts` " - "or build Geode from source." + "No valid loader binary to link to! Install prebuilts with `geode sdk install-prebuilts`, " + "or build Geode from source and add `set(GEODE_LINK_NIGHTLY On)` to your CMakeLists.txt." ) endif() diff --git a/bindings/Cocos2d.bro b/bindings/Cocos2d.bro index 961699bf..45f5bbe8 100644 --- a/bindings/Cocos2d.bro +++ b/bindings/Cocos2d.bro @@ -140,6 +140,8 @@ class cocos2d::CCDrawNode { static cocos2d::CCDrawNode* create() = mac 0x378d00; auto drawPolygon(cocos2d::CCPoint*, unsigned int, cocos2d::_ccColor4F const&, float, cocos2d::_ccColor4F const&) = mac 0x3797f0; auto drawSegment(cocos2d::CCPoint const&, cocos2d::CCPoint const&, float, cocos2d::_ccColor4F const&) = mac 0x3792d0; + auto drawDot(cocos2d::CCPoint const&, float, cocos2d::_ccColor4F const&) = mac 0x379100; + auto getBlendFunc() const = mac 0x379ea0; auto init() = mac 0x378e00; auto setBlendFunc(cocos2d::_ccBlendFunc const&) = mac 0x379eb0; @@ -262,9 +264,8 @@ class cocos2d::CCLabelBMFont { static cocos2d::CCLabelBMFont* create(char const*, char const*) = mac 0x347660; auto limitLabelWidth(float, float, float) = mac 0x34a6e0, ios 0x21b740; - virtual ~CCLabelBMFont() = mac 0x347e80, ios 0x219afc; - virtual auto init() = mac 0x347b10, ios 0x2198e0; + bool initWithString(const char* str, const char* fnt, float width, cocos2d::CCTextAlignment align, cocos2d::CCPoint offset); virtual auto setScaleX(float) = mac 0x34a5b0, ios 0x21b6e8; virtual auto setScaleY(float) = mac 0x34a5d0, ios 0x21b714; virtual auto setScale(float) = mac 0x34a590, ios 0x21b6bc; @@ -292,6 +293,7 @@ class cocos2d::CCLabelBMFont { virtual auto isCascadeColorEnabled() = mac 0x3493c0, ios 0x21aa3c; virtual auto setCascadeColorEnabled(bool) = mac 0x3493e0, ios 0x21aa4c; virtual auto setString(unsigned short*, bool) = mac 0x348a60, ios 0x21a4b4; + virtual ~CCLabelBMFont() = mac 0x347e80; } class cocos2d::CCLabelTTF { @@ -657,6 +659,7 @@ class cocos2d::CCRenderTexture { auto end() = mac 0x35d2c0; static cocos2d::CCRenderTexture* create(int, int, cocos2d::CCTexture2DPixelFormat) = mac 0x35c720; auto newCCImage(bool) = mac 0x35d7d0; + auto saveToFile(char const*) = mac 0x35dab0; } class cocos2d::CCRepeat { diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 64e5ad65..1238ed3f 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -1,4 +1,5 @@ // geode additions to make stl containers easier +// clang-format off class GDString { void winDtor() = win 0xf6e0; char const* winCStr() = win 0xf710; @@ -16,7 +17,6 @@ class GDString { void macDestroy() = mac 0x489f78; } - class AchievementBar : cocos2d::CCNodeRGBA { static AchievementBar* create(const char* title, const char* desc, const char* icon, bool quest) = mac 0x379f80, win 0x3b120, ios 0x1a4784; @@ -1104,6 +1104,17 @@ class EditorOptionsLayer { } class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol { + static EditorPauseLayer* get() { + if (!EditorUI::get()) return nullptr; + + auto editor = LevelEditorLayer::get(); + for (auto i = 0; i < editor->getChildrenCount(); ++i) { + if (auto layer = cast::safe_cast(editor->getChildren()->objectAtIndex(i))) { + return layer; + } + } + return nullptr; + } static EditorPauseLayer* create(LevelEditorLayer* editor) { auto pRet = new EditorPauseLayer(); if (pRet && pRet->init(editor)) { @@ -2105,6 +2116,14 @@ class GJGameLevel : cocos2d::CCNode { GJDifficulty getAverageDifficulty() = win 0xbd9b0; gd::string getUnpackedLevelDescription() = win 0xbf890; + static GJGameLevel* getCurrent() { + auto playLayer = PlayLayer::get(); + if (playLayer) return playLayer->m_level; + auto editorLayer = LevelEditorLayer::get(); + if (editorLayer) return editorLayer->m_level; + return nullptr; + } + cocos2d::CCDictionary* m_lastBuildSave; int m_levelIDRand; int m_levelIDSeed; @@ -3550,10 +3569,10 @@ class LevelCell : TableViewCell { } class LevelCommentDelegate { - virtual void loadCommentsFinished(cocos2d::CCArray *, const char*) {} - virtual void loadCommentsFailed(const char*) {} + virtual void loadCommentsFinished(cocos2d::CCArray*, char const*) {} + virtual void loadCommentsFailed(char const*) {} virtual void updateUserScoreFinished() {} - virtual void setupPageInfo(gd::string, const char*) {} + virtual void setupPageInfo(gd::string, char const*) {} } class LevelDeleteDelegate { @@ -3855,6 +3874,12 @@ class LevelSettingsObject : cocos2d::CCNode { static LevelSettingsObject* objectFromString(gd::string) = mac 0x945a0, win 0x16f440; void setupColorsFromLegacyMode(cocos2d::CCDictionary*) = mac 0xa6a30, win 0x170050; + static LevelSettingsObject* get() { + auto baseLayer = GJBaseGameLayer::get(); + if (baseLayer) return baseLayer->m_levelSettings; + return nullptr; + } + gd::string getSaveString() = mac 0x979c0, win 0x16ebf0; GJEffectManager* m_effectManager; @@ -4035,7 +4060,7 @@ class MusicDownloadManager : cocos2d::CCNode, PlatformDownloadDelegate { cocos2d::CCDictionary* m_unknownDict; cocos2d::CCArray* m_handlers; cocos2d::CCDictionary* m_songsDict; - int m_unknown; + int m_priority; } class NumberInputDelegate { @@ -5190,6 +5215,19 @@ class TableView : CCScrollLayerExt, CCScrollLayerExtDelegate { static TableView* create(TableViewDelegate*, TableViewDataSource*, cocos2d::CCRect) = mac 0x37eb30, win 0x30ed0; void reloadData() = mac 0x37f970, win 0x317e0; + virtual void onEnter() = mac 0x37ff30, ios 0x21dcac; + virtual void onExit() = mac 0x37ff40, ios 0x21dcb0; + virtual bool ccTouchBegan(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x380120, ios 0x21de24, win 0x31de0; + virtual void ccTouchMoved(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x380be0, ios 0x21e5e8; + virtual void ccTouchEnded(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x3809a0, ios 0x21e46c; + virtual void ccTouchCancelled(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x380b20, ios 0x21e580; + virtual void registerWithTouchDispatcher() = mac 0x37ff50, ios 0x21dcb4; + virtual void scrollWheel(float, float) = mac 0x380cd0, ios 0x21e6b4; + virtual void scrllViewWillBeginDecelerating(CCScrollLayerExt*) = mac 0x3818a0, ios 0x21efd4; + virtual void scrollViewDidEndDecelerating(CCScrollLayerExt*) = mac 0x3818c0, ios 0x21efdc; + virtual void scrollViewTouchMoving(CCScrollLayerExt*) = mac 0x3818e0, ios 0x21efe4; + virtual void scrollViewDidEndMoving(CCScrollLayerExt*) = mac 0x381900, ios 0x21efec; + bool m_touchOutOfBoundary; cocos2d::CCTouch* m_touchStart; cocos2d::CCPoint m_touchStartPosition2; @@ -5261,7 +5299,7 @@ class TeleportPortalObject : GameObject { bool m_teleportEase; } -class TextAlertPopup { +class TextAlertPopup : cocos2d::CCNode { static TextAlertPopup* create(gd::string const& text, float time, float scale) = win 0x1450b0; } @@ -5372,4 +5410,4 @@ class VideoOptionsLayer : FLAlertLayer { class LevelTools { static gd::string base64DecodeString(gd::string) = mac 0x294510, win 0x18b3b0; } - +// clang-format on diff --git a/codegen/src/ModifyGen.cpp b/codegen/src/ModifyGen.cpp index b36dcf70..f3bb38f3 100644 --- a/codegen/src/ModifyGen.cpp +++ b/codegen/src/ModifyGen.cpp @@ -1,25 +1,27 @@ #include "Shared.hpp" #include "TypeOpt.hpp" + #include #include -namespace { namespace format_strings { - char const* wrap_start = R"GEN( +namespace { + namespace format_strings { + char const* wrap_start = R"GEN( namespace wrap { )GEN"; - char const* wrap_declare_identifier = R"GEN( + char const* wrap_declare_identifier = R"GEN( #ifndef GEODE_WRAP_{function_name} #define GEODE_WRAP_{function_name} GEODE_WRAPPER_FOR_IDENTIFIER({function_name}) #endif )GEN"; - char const* wrap_end = R"GEN( + char const* wrap_end = R"GEN( } )GEN"; - // requires: class_name - char const* modify_start = R"GEN(#pragma once + // requires: class_name + char const* modify_start = R"GEN(#pragma once #include #include #include @@ -28,100 +30,89 @@ using namespace geode::modifier; namespace geode::modifier {{ {wrap} template - struct Modify : ModifyBase> {{ - using ModifyBase>::ModifyBase; + struct ModifyDerive : ModifyBase> {{ + using ModifyBase>::ModifyBase; using Base = {class_name}; static void apply() {{ using namespace geode::core::meta; )GEN"; - // requires: index, class_name, arg_types, function_name, raw_arg_types, non_virtual - char const* apply_function = R"GEN( + // requires: index, class_name, arg_types, function_name, raw_arg_types, non_virtual + char const* apply_function = R"GEN( GEODE_APPLY_MODIFY_FOR_FUNCTION({addr_index}, {pure_index}, {function_convention}, {class_name}, {function_name}))GEN"; - char const* modify_end = R"GEN( + char const* modify_end = R"GEN( } }; } )GEN"; - char const* modify_include = R"GEN(#include "modify/{file_name}" + char const* modify_include = R"GEN(#include "modify/{file_name}" )GEN"; -}} - + } +} std::string generateModifyHeader(Root& root, ghc::filesystem::path const& singleFolder) { - std::string output; + std::string output; - TypeBank bank; - bank.loadFrom(root); + TypeBank bank; + bank.loadFrom(root); - for (auto c : root.classes) { - if (c.name == "cocos2d") - continue; + for (auto c : root.classes) { + if (c.name == "cocos2d") continue; - std::string filename = (codegen::getUnqualifiedClassName(c.name) + ".hpp"); - output += fmt::format(format_strings::modify_include, - fmt::arg("file_name", filename) - ); + std::string filename = (codegen::getUnqualifiedClassName(c.name) + ".hpp"); + output += fmt::format(format_strings::modify_include, fmt::arg("file_name", filename)); - std::string single_output; - std::string wrap; + std::string single_output; + std::string wrap; - // wrap - wrap += format_strings::wrap_start; - std::set used; - for (auto& f : c.fields) { - if (auto fn = f.get_fn()) { - if (fn->type == FunctionType::Normal && !used.count(fn->name)) { - used.insert(fn->name); - wrap += fmt::format(format_strings::wrap_declare_identifier, - fmt::arg("function_name", fn->name) - ); - } - } - } - wrap += format_strings::wrap_end; + // wrap + wrap += format_strings::wrap_start; + std::set used; + for (auto& f : c.fields) { + if (auto fn = f.get_fn()) { + if (fn->type == FunctionType::Normal && !used.count(fn->name)) { + used.insert(fn->name); + wrap += fmt::format( + format_strings::wrap_declare_identifier, fmt::arg("function_name", fn->name) + ); + } + } + } + wrap += format_strings::wrap_end; - single_output += fmt::format(format_strings::modify_start, - fmt::arg("class_name", c.name), - fmt::arg("wrap", wrap) - ); + single_output += fmt::format( + format_strings::modify_start, fmt::arg("class_name", c.name), fmt::arg("wrap", wrap) + ); - // modify - for (auto& f : c.fields) { - if (codegen::getStatus(f) != BindStatus::Unbindable) { - auto begin = f.get_fn(); + // modify + for (auto& f : c.fields) { + if (codegen::getStatus(f) != BindStatus::Unbindable) { + auto begin = f.get_fn(); - std::string function_name; + std::string function_name; - switch (begin->type) { - case FunctionType::Normal: - function_name = begin->name; - break; - case FunctionType::Ctor: - function_name = "constructor"; - break; - case FunctionType::Dtor: - function_name = "destructor"; - break; - } + switch (begin->type) { + case FunctionType::Normal: function_name = begin->name; break; + case FunctionType::Ctor: function_name = "constructor"; break; + case FunctionType::Dtor: function_name = "destructor"; break; + } - single_output += fmt::format(format_strings::apply_function, - fmt::arg("addr_index", f.field_id), - fmt::arg("pure_index", bank.getPure(*begin, c.name)), - fmt::arg("class_name", c.name), - fmt::arg("function_name", function_name), - fmt::arg("function_convention", codegen::getConvention(f)) - ); - } - } + single_output += fmt::format( + format_strings::apply_function, fmt::arg("addr_index", f.field_id), + fmt::arg("pure_index", bank.getPure(*begin, c.name)), + fmt::arg("class_name", c.name), fmt::arg("function_name", function_name), + fmt::arg("function_convention", codegen::getConvention(f)) + ); + } + } - single_output += format_strings::modify_end; + single_output += format_strings::modify_end; - writeFile(singleFolder / filename, single_output); - } + writeFile(singleFolder / filename, single_output); + } - return output; + return output; } diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index 15cee94b..016a434c 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -10,30 +10,84 @@ namespace geode { class Mod; class Event; - enum class PassThrough : bool { + enum class ListenerResult { Propagate, - Stop, + Stop }; - struct GEODE_DLL BasicEventHandler { - virtual PassThrough passThrough(Event*) = 0; + struct GEODE_DLL EventListenerProtocol { + virtual void enable(); + virtual void disable(); + virtual ListenerResult passThrough(Event*) = 0; + }; - virtual ~BasicEventHandler(); - - void listen(); - void unlisten(); + template + struct to_member; + + template + struct to_member { + using value = R(C::*)(Args...); + }; + + template + concept is_event = std::is_base_of_v; + + template + class EventFilter { + public: + using Callback = ListenerResult(T*); + using Event = T; + + ListenerResult handle(std::function fn, T* e) { + return fn(e); + } + }; + + template + concept is_filter = + std::is_base_of_v, T> && + requires(T a) { + a.handle(std::declval(), std::declval()); + }; + + template + class EventListener : public EventListenerProtocol { + public: + using Callback = typename T::Callback; + template requires std::is_class_v + using MemberFn = typename to_member::value; + + ListenerResult passThrough(Event* e) override { + if (auto myev = dynamic_cast(e)) { + return m_filter.handle(m_callback, myev); + } + return ListenerResult::Propagate; + } + + EventListener(T filter = T()) {} + EventListener(std::function fn, T filter = T()) : m_callback(fn), m_filter(filter) {} + EventListener(Callback* fnptr, T filter = T()) : m_callback(fnptr), m_filter(filter) {} + + template + EventListener(C* cls, MemberFn fn, T filter = T()) : EventListener(std::bind(fn, cls, std::placeholders::_1), filter) {} + + void bind(std::function fn) { + m_callback = fn; + } + template + void bind(C* cls, MemberFn fn) { + m_callback = std::bind(fn, cls, std::placeholders::_1); + } + protected: + std::function m_callback; + T m_filter; }; class GEODE_DLL Event { - static std::unordered_set s_handlers; - - friend BasicEventHandler; - + static std::unordered_set s_listeners; Mod* m_sender; - + friend EventListenerProtocol; public: - static std::unordered_set const& getHandlers(); - void postFrom(Mod* sender); inline void post() { @@ -44,21 +98,4 @@ namespace geode { virtual ~Event(); }; - - template - class EventHandler : public BasicEventHandler { - public: - virtual PassThrough handle(T*) = 0; - - PassThrough passThrough(Event* ev) override { - if (auto myev = dynamic_cast(ev)) { - return handle(myev); - } - return PassThrough::Propagate; - } - - EventHandler() { - listen(); - } - }; } diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index c5934d21..6adaf4db 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -34,6 +34,7 @@ namespace geode { static constexpr std::string_view GEODE_CONFIG_DIRECTORY = "config"; static constexpr std::string_view GEODE_TEMP_DIRECTORY = "temp"; static constexpr std::string_view GEODE_MOD_EXTENSION = ".geode"; + static constexpr std::string_view GEODE_INDEX_DIRECTORY = "index"; class Mod; class Hook; @@ -41,7 +42,7 @@ namespace geode { class VersionInfo; namespace modifier { - template + template class FieldIntermediate; } } @@ -101,7 +102,7 @@ namespace geode { size_t getFieldIndexForClass(size_t hash); - template + template friend class modifier::FieldIntermediate; void updateModResources(Mod* mod); diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp index 3912dd26..9cb1da57 100644 --- a/loader/include/Geode/loader/Setting.hpp +++ b/loader/include/Geode/loader/Setting.hpp @@ -468,11 +468,19 @@ namespace geode { } \ } + // clang-format off + template T getBuiltInSettingValue(const std::shared_ptr setting) { GEODE_INT_BUILTIN_SETTING_IF(Bool, getValue(), std::is_same_v) - else GEODE_INT_BUILTIN_SETTING_IF(Float, getValue(), std::is_floating_point_v) else GEODE_INT_BUILTIN_SETTING_IF(Int, getValue(), std::is_integral_v) else GEODE_INT_BUILTIN_SETTING_IF(String, getValue(), std::is_same_v) else { - static_assert(!std::is_same_v, "todo: implement"); + else GEODE_INT_BUILTIN_SETTING_IF(Float, getValue(), std::is_floating_point_v) + else GEODE_INT_BUILTIN_SETTING_IF(Int, getValue(), std::is_integral_v) + else GEODE_INT_BUILTIN_SETTING_IF(String, getValue(), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(File, getValue(), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(Color, getValue(), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(ColorAlpha, getValue(), std::is_same_v) + else { + static_assert(!std::is_same_v, "Unsupported type for getting setting value!"); } return T(); } @@ -480,10 +488,17 @@ namespace geode { template void setBuiltInSettingValue(const std::shared_ptr setting, T const& value) { GEODE_INT_BUILTIN_SETTING_IF(Bool, setValue(value), std::is_same_v) - else GEODE_INT_BUILTIN_SETTING_IF(Float, setValue(value), std::is_floating_point_v) else GEODE_INT_BUILTIN_SETTING_IF(Int, setValue(value), std::is_integral_v) else GEODE_INT_BUILTIN_SETTING_IF(String, setValue(value), std::is_same_v) else { - static_assert(!std::is_same_v, "todo: implement"); + else GEODE_INT_BUILTIN_SETTING_IF(Float, setValue(value), std::is_floating_point_v) + else GEODE_INT_BUILTIN_SETTING_IF(Int, setValue(value), std::is_integral_v) + else GEODE_INT_BUILTIN_SETTING_IF(String, setValue(value), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(File, setValue(value), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(Color, setValue(value), std::is_same_v) + else GEODE_INT_BUILTIN_SETTING_IF(ColorAlpha, setValue(value), std::is_same_v) + else { + static_assert(!std::is_same_v, "Unsupported type for getting setting value!"); } } + // clang-format on } #pragma warning(pop) diff --git a/loader/include/Geode/loader/SettingEvent.hpp b/loader/include/Geode/loader/SettingEvent.hpp index 0a5576ef..311afeac 100644 --- a/loader/include/Geode/loader/SettingEvent.hpp +++ b/loader/include/Geode/loader/SettingEvent.hpp @@ -18,41 +18,37 @@ namespace geode { std::shared_ptr getSetting() const; }; - template - class SettingChangedEventHandler : public EventHandler { + template >> + class SettingChangedFilter : public EventFilter { public: - using Consumer = void (*)(std::shared_ptr); + using Callback = void(std::shared_ptr); + using Event = SettingChangedEvent; - static_assert(std::is_base_of_v, "Setting must inherit from the Setting class"); - - protected: - Consumer m_consumer; - std::string m_modID; - std::optional m_targetKey; - - public: - PassThrough handle(SettingChangedEvent* event) override { + ListenerResult handle(std::function fn, SettingChangedEvent* event) { if (m_modID == event->getModID() && (!m_targetKey || m_targetKey.value() == event->getSetting()->getKey())) { - m_consumer(std::static_pointer_cast(event->getSetting())); + fn(std::static_pointer_cast(event->getSetting())); } - return PassThrough::Propagate; + return ListenerResult::Propagate; } /** * Listen to changes on a specific setting */ - SettingChangedEventHandler( - std::string const& modID, std::string const& settingID, Consumer handler + SettingChangedFilter( + std::string const& modID, std::string const& settingID ) : m_modID(modID), - m_targetKey(settingID), m_consumer(handler) {} + m_targetKey(settingID) {} /** * Listen to changes on all of a mods' settings */ - SettingChangedEventHandler(std::string const& modID, Consumer handler) : - m_modID(modID), m_targetKey(std::nullopt), m_consumer(handler) {} + SettingChangedFilter(std::string const& modID) : + m_modID(modID), m_targetKey(std::nullopt) {} + protected: + std::string m_modID; + std::optional m_targetKey; }; template @@ -61,14 +57,14 @@ namespace geode { std::string const& settingID, void (*callback)(std::shared_ptr) ) { Loader::get()->scheduleOnModLoad(getMod(), [=]() { - static SettingChangedEventHandler _(getMod()->getID(), settingID, callback); + static auto _ = EventListener(callback, SettingChangedFilter(getMod()->getID(), settingID)); }); return std::monostate(); } static std::monostate listenForAllSettingChanges(void (*callback)(std::shared_ptr)) { Loader::get()->scheduleOnModLoad(getMod(), [=]() { - static SettingChangedEventHandler _(getMod()->getID(), callback); + static auto _ = EventListener(callback, SettingChangedFilter(getMod()->getID())); }); return std::monostate(); } diff --git a/loader/include/Geode/modify/Field.hpp b/loader/include/Geode/modify/Field.hpp index 2b02cf4e..10fd778d 100644 --- a/loader/include/Geode/modify/Field.hpp +++ b/loader/include/Geode/modify/Field.hpp @@ -42,7 +42,7 @@ namespace geode::modifier { } }; - template + template class FieldIntermediate { // Padding used for guaranteeing any member of parents // will be in between sizeof(Intermediate) and sizeof(Parent) @@ -54,22 +54,22 @@ namespace geode::modifier { auto parent = new (parentContainer.data()) Parent(); - parent->Intermediate::~Intermediate(); + parent->Base::~Base(); std::memcpy( - offsetField, std::launder(&parentContainer[sizeof(Intermediate)]), - sizeof(Parent) - sizeof(Intermediate) + offsetField, std::launder(&parentContainer[sizeof(Base)]), + sizeof(Parent) - sizeof(Base) ); } static void fieldDestructor(void* offsetField) { std::array parentContainer; - auto parent = new (parentContainer.data()) Intermediate(); + auto parent = new (parentContainer.data()) Base(); std::memcpy( - std::launder(&parentContainer[sizeof(Intermediate)]), offsetField, - sizeof(Parent) - sizeof(Intermediate) + std::launder(&parentContainer[sizeof(Base)]), offsetField, + sizeof(Parent) - sizeof(Base) ); static_cast(parent)->Parent::~Parent(); @@ -87,15 +87,14 @@ namespace geode::modifier { auto offsetField = container->getField(index); if (!offsetField) { offsetField = container->setField( - index, sizeof(Parent) - sizeof(Intermediate), - &FieldIntermediate::fieldDestructor + index, sizeof(Parent) - sizeof(Base), &FieldIntermediate::fieldDestructor ); FieldIntermediate::fieldConstructor(offsetField); } return reinterpret_cast( - reinterpret_cast(offsetField) - sizeof(Intermediate) + reinterpret_cast(offsetField) - sizeof(Base) ); } }; diff --git a/loader/include/Geode/modify/InternalMacros.hpp b/loader/include/Geode/modify/InternalMacros.hpp index 9635559a..90ad0975 100644 --- a/loader/include/Geode/modify/InternalMacros.hpp +++ b/loader/include/Geode/modify/InternalMacros.hpp @@ -8,15 +8,9 @@ * struct hook0 {}; * namespace { * struct hook0Parent {}; - * Modify, MenuLayer> hook0Apply; - * struct GEODE_HIDDEN hook0Intermediate: public MenuLayer { - * geode::modifier::FieldIntermediate, hook0 - * > m_fields; - * }; * } * template<> - * struct GEODE_HIDDEN hook0: hook0Intermediate { + * struct GEODE_HIDDEN hook0 : Modify, MenuLayer> { * // code stuff idk * }; * @@ -24,33 +18,19 @@ * I am bad at this stuff */ -#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \ - derived##Dummy; \ - template \ - struct derived {}; \ - namespace { \ - struct derived##Parent {}; \ - Modify, base> derived##Apply; \ - struct GEODE_HIDDEN derived##Intermediate : base { \ - mutable geode::modifier::FieldIntermediate< \ - base, derived##Intermediate, derived> \ - m_fields; \ - }; \ - } \ - template <> \ - struct GEODE_HIDDEN derived : derived##Intermediate +#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \ + derived##Dummy; \ + template \ + struct derived {}; \ + namespace { \ + struct derived##Parent {}; \ + } \ + template <> \ + struct GEODE_HIDDEN derived : geode::Modify, base> -#define GEODE_MODIFY_DECLARE(base, derived) \ - derived##Dummy; \ - struct derived; \ - namespace { \ - Modify derived##Apply; \ - struct GEODE_HIDDEN derived##Intermediate : base { \ - mutable geode::modifier::FieldIntermediate \ - m_fields; \ - }; \ - } \ - struct GEODE_HIDDEN derived : derived##Intermediate +#define GEODE_MODIFY_DECLARE(base, derived) \ + derived##Dummy; \ + struct GEODE_HIDDEN derived : geode::Modify #define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived) #define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) diff --git a/loader/include/Geode/modify/Modify.hpp b/loader/include/Geode/modify/Modify.hpp index a9cd033b..d4b1c30c 100644 --- a/loader/include/Geode/modify/Modify.hpp +++ b/loader/include/Geode/modify/Modify.hpp @@ -1,6 +1,7 @@ #pragma once #include "../meta/meta.hpp" #include "Addresses.hpp" +#include "Field.hpp" #include "Types.hpp" #include "Wrapper.hpp" @@ -22,7 +23,7 @@ namespace geode::modifier { template - class Modify; + class ModifyDerive; template class ModifyBase { @@ -34,15 +35,29 @@ namespace geode::modifier { }); } template - friend class Modify; + friend class ModifyDerive; // explicit Modify(Property property) idea }; template - class Modify { + class ModifyDerive { public: - Modify() { + ModifyDerive() { static_assert(core::meta::always_false, "Custom Modify not implemented."); } }; } + +namespace geode { + + template + class Modify : public Base { + private: + static inline modifier::ModifyDerive s_apply; + // because for some reason we need it + static inline auto s_applyRef = &Modify::s_apply; + + public: + modifier::FieldIntermediate m_fields; + }; +} diff --git a/loader/include/Geode/utils/Ref.hpp b/loader/include/Geode/utils/Ref.hpp index d26ab030..f8d01cf7 100644 --- a/loader/include/Geode/utils/Ref.hpp +++ b/loader/include/Geode/utils/Ref.hpp @@ -101,9 +101,32 @@ namespace geode { bool operator==(T* other) const { return m_obj == other; } - bool operator==(Ref const& other) const { return m_obj == other.m_obj; } + + bool operator!=(T* other) const { + return m_obj != other; + } + bool operator!=(Ref const& other) const { + return m_obj != other.m_obj; + } + + // for containers + bool operator<(Ref const& other) const { + return m_obj < other.m_obj; + } + bool operator>(Ref const& other) const { + return m_obj > other.m_obj; + } + }; +} + +namespace std { + template + struct hash> { + size_t operator()(geode::Ref const& ref) const { + return std::hash()(ref.data()); + } }; } diff --git a/loader/include/Geode/utils/VersionInfo.hpp b/loader/include/Geode/utils/VersionInfo.hpp index 28dcbdd0..365e6d77 100644 --- a/loader/include/Geode/utils/VersionInfo.hpp +++ b/loader/include/Geode/utils/VersionInfo.hpp @@ -60,4 +60,9 @@ namespace geode { std::string toString() const; }; + + inline std::ostream& operator<<(std::ostream& stream, VersionInfo const& version) { + stream << version.toString(); + return stream; + } } diff --git a/loader/include/Geode/utils/casts.hpp b/loader/include/Geode/utils/casts.hpp index a98ee800..d49fcd41 100644 --- a/loader/include/Geode/utils/casts.hpp +++ b/loader/include/Geode/utils/casts.hpp @@ -9,7 +9,7 @@ namespace geode::cast { /** * Alias for static_cast */ - template + template static constexpr T as(F const v) { return static_cast(v); } @@ -18,8 +18,8 @@ namespace geode::cast { * Cast from anything to anything else, * provided they are the same size */ - template - static constexpr T union_cast(F v) { + template + static constexpr T union_cast(F const v) { static_assert(sizeof(F) == sizeof(T), "union_cast: R and T don't match in size!"); union { @@ -36,27 +36,40 @@ namespace geode::cast { * cast but uses reference syntactic sugar to * look cleaner. */ - template + template static constexpr T reference_cast(F v) { return reinterpret_cast(v); } /** - * Cast an adjusted this pointer to it's base pointer + * Cast based on RTTI. Casts an adjusted this pointer + * to it's non offset form. */ - template - static constexpr T base_cast(F obj) { - return reinterpret_cast(dynamic_cast(obj)); + template + static constexpr T base_cast(F const obj) { + return static_cast(dynamic_cast(obj)); } /** - * Cast based on RTTI. This is a replacement for - * dynamic_cast, since it doesn't work for gd. + * Cast based on RTTI. This is used to check + * if an object is exactly the class needed. Returns + * nullptr on failure. */ - template - static T typeid_cast(F obj) { - if (std::string(typeid(*obj).name()) == typeid(std::remove_pointer_t).name()) - return reinterpret_cast(obj); - else return nullptr; + template + static T exact_cast(F const obj) { + if (std::strcmp(typeid(*obj).name(), typeid(std::remove_pointer_t).name()) == 0) { + return base_cast(obj); + } + return nullptr; + } + + /** + * Cast based on RTTI. This behaves as a replacement + * of dynamic_cast for cocos and gd classes, + * and must be used for expected results. + */ + template + static T safe_cast(F const obj) { + return typeinfo_cast(obj); } } diff --git a/loader/include/Geode/utils/fetch.hpp b/loader/include/Geode/utils/fetch.hpp index 2582cd81..b9fd6f60 100644 --- a/loader/include/Geode/utils/fetch.hpp +++ b/loader/include/Geode/utils/fetch.hpp @@ -86,6 +86,7 @@ namespace geode::utils::web { mutable std::mutex m_mutex; std::variant m_target = std::monostate(); + std::vector m_httpHeaders; template friend class AsyncWebResult; @@ -134,6 +135,7 @@ namespace geode::utils::web { AsyncCancelled m_cancelled = nullptr; bool m_sent = false; std::variant m_target; + std::vector m_httpHeaders; template friend class AsyncWebResult; @@ -159,6 +161,12 @@ namespace geode::utils::web { * @returns Same AsyncWebRequest */ AsyncWebRequest& join(std::string const& requestID); + + /** + * In order to specify a http header to the request, give it here. + * Can be called more than once. + */ + AsyncWebRequest& header(std::string const& header); /** * URL to fetch from the internet asynchronously * @param url URL of the data to download. Redirects will be diff --git a/loader/include/Geode/utils/operators.hpp b/loader/include/Geode/utils/operators.hpp index 5354fbf6..ea9c43ff 100644 --- a/loader/include/Geode/utils/operators.hpp +++ b/loader/include/Geode/utils/operators.hpp @@ -28,6 +28,15 @@ namespace geode { return rect; } + static cocos2d::CCRect operator*(cocos2d::CCRect const& rect, float mul) { + return { + rect.origin.x * mul, + rect.origin.y * mul, + rect.size.width * mul, + rect.size.height * mul, + }; + } + static cocos2d::CCPoint operator/=(cocos2d::CCPoint& pos, float div) { pos.x /= div; pos.y /= div; diff --git a/loader/include/Geode/utils/ranges.hpp b/loader/include/Geode/utils/ranges.hpp index 28afbc75..1cd6e431 100644 --- a/loader/include/Geode/utils/ranges.hpp +++ b/loader/include/Geode/utils/ranges.hpp @@ -4,6 +4,9 @@ #include #include +#undef min +#undef max + namespace geode::utils::ranges { template concept ValidConstContainer = requires(C const& c) { @@ -205,4 +208,57 @@ namespace geode::utils::ranges { std::transform(from.begin(), from.end(), res.end(), mapper); return res; } + + template + typename C::value_type min(C const& container) { + auto it = std::min_element(container.begin(), container.end()); + if (it == container.end()) { + return C::value_type(); + } + return *it; + } + + template Member> + requires requires(T a, T b) { + a < b; + } + T min(C const& container, Member member) { + auto it = std::min_element( + container.begin(), container.end(), + [member](auto const& a, auto const& b) -> bool { + return member(a) < member(b); + } + ); + if (it == container.end()) { + return T(); + } + return member(*it); + } + + template + typename C::value_type max(C const& container) { + auto it = std::max_element(container.begin(), container.end()); + if (it == container.end()) { + return C::value_type(); + } + return *it; + } + + template Member> + requires requires(T a, T b) { + a < b; + T(); + } + T max(C const& container, Member member) { + auto it = std::max_element( + container.begin(), container.end(), + [member](auto const& a, auto const& b) -> bool { + return member(a) < member(b); + } + ); + if (it == container.end()) { + return T(); + } + return member(*it); + } } diff --git a/loader/resources/mod.json.in b/loader/resources/mod.json.in index 8b43d59f..a0f5d1f6 100644 --- a/loader/resources/mod.json.in +++ b/loader/resources/mod.json.in @@ -1,7 +1,7 @@ { - "geode": "v@PROJECT_VERSION@", + "geode": "@PROJECT_VERSION@", "id": "geode.loader", - "version": "v@PROJECT_VERSION@", + "version": "@PROJECT_VERSION@", "name": "Geode", "developer": "Geode Team", "description": "The Geode mod loader", diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index f23ebd58..93941e77 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -68,7 +68,7 @@ public: // proxy forwards // clang-format off #include -class $modify(ProxyCCNode, CCNode) { +struct ProxyCCNode : Modify { virtual CCObject* getUserObject() { return GeodeNodeMetadata::set(this)->m_userObject; } diff --git a/loader/src/hooks/LevelSearchLayer.cpp b/loader/src/hooks/LevelSearchLayer.cpp index 65d1a307..d54cf2ee 100644 --- a/loader/src/hooks/LevelSearchLayer.cpp +++ b/loader/src/hooks/LevelSearchLayer.cpp @@ -9,9 +9,10 @@ USE_GEODE_NAMESPACE(); #pragma warning(disable : 4217) -template -requires std::is_base_of_v T* setIDSafe(CCNode* node, int index, char const* id) { +template +requires std::is_base_of_v +T* setIDSafe(CCNode* node, int index, char const* id) { if constexpr (std::is_same_v) { if (auto child = getChild(node, index)) { child->setID(id); @@ -29,7 +30,7 @@ requires std::is_base_of_v T* setIDSafe(CCNode* node, int index, char // clang-format off #include -class $modify(LevelSearchLayer) { +struct LevelSearchLayerIDs : Modify { bool init() { if (!LevelSearchLayer::init()) return false; @@ -99,4 +100,5 @@ class $modify(LevelSearchLayer) { return true; } }; + // clang-format on diff --git a/loader/src/hooks/LoadingLayer.cpp b/loader/src/hooks/LoadingLayer.cpp index 5eaef33d..33e2fd6f 100644 --- a/loader/src/hooks/LoadingLayer.cpp +++ b/loader/src/hooks/LoadingLayer.cpp @@ -3,26 +3,23 @@ USE_GEODE_NAMESPACE(); -// clang-format off #include -class $modify(CustomLoadingLayer, LoadingLayer) { + +struct CustomLoadingLayer : Modify { bool m_updatingResources; CustomLoadingLayer() : m_updatingResources(false) {} bool init(bool fromReload) { - if (!LoadingLayer::init(fromReload)) - return false; + if (!LoadingLayer::init(fromReload)) return false; auto winSize = CCDirector::sharedDirector()->getWinSize(); auto count = Loader::get()->getAllMods().size(); auto label = CCLabelBMFont::create( - CCString::createWithFormat( - "Geode: Loaded %lu mods", - static_cast(count) - )->getCString(), + CCString::createWithFormat("Geode: Loaded %lu mods", static_cast(count)) + ->getCString(), "goldFont.fnt" ); label->setPosition(winSize.width / 2, 30.f); @@ -31,13 +28,10 @@ class $modify(CustomLoadingLayer, LoadingLayer) { this->addChild(label); // verify loader resources - if (!InternalLoader::get()->verifyLoaderResources( - std::bind( - &CustomLoadingLayer::updateResourcesProgress, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3 - ) - )) { + if (!InternalLoader::get()->verifyLoaderResources(std::bind( + &CustomLoadingLayer::updateResourcesProgress, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3 + ))) { // auto bg = CCScale9Sprite::create( // "square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f } // ); @@ -73,17 +67,10 @@ class $modify(CustomLoadingLayer, LoadingLayer) { // ); } - void updateResourcesProgress( - UpdateStatus status, - std::string const& info, - uint8_t progress - ) { + void updateResourcesProgress(UpdateStatus status, std::string const& info, uint8_t progress) { switch (status) { case UpdateStatus::Progress: { - this->setUpdateText( - "Downloading Resources: " + - std::to_string(progress) + "%" - ); + this->setUpdateText("Downloading Resources: " + std::to_string(progress) + "%"); } break; case UpdateStatus::Finished: { @@ -95,9 +82,10 @@ class $modify(CustomLoadingLayer, LoadingLayer) { case UpdateStatus::Failed: { InternalLoader::platformMessageBox( "Error updating resources", - "Unable to update Geode resources: " + info + ".\n" - "The game will be loaded as normal, but please be aware " - "that it may very likely crash." + "Unable to update Geode resources: " + info + + ".\n" + "The game will be loaded as normal, but please be aware " + "that it may very likely crash." ); this->setUpdateText("Resource Download Failed"); m_fields->m_updatingResources = false; @@ -106,12 +94,10 @@ class $modify(CustomLoadingLayer, LoadingLayer) { } } - void loadAssets() { - if (m_fields->m_updatingResources) { + void loadAssets() { + if (m_fields->m_updatingResources) { return; - } - LoadingLayer::loadAssets(); - } + } + LoadingLayer::loadAssets(); + } }; - -// clang-format on \ No newline at end of file diff --git a/loader/src/hooks/MenuLayer.cpp b/loader/src/hooks/MenuLayer.cpp index 8986fb65..e5319d5f 100644 --- a/loader/src/hooks/MenuLayer.cpp +++ b/loader/src/hooks/MenuLayer.cpp @@ -64,7 +64,7 @@ static void updateIndexProgress(UpdateStatus status, std::string const& info, ui } #include -class $modify(CustomMenuLayer, MenuLayer) { +class CustomMenuLayer : Modify { void destructor() { g_geodeButton = nullptr; MenuLayer::~MenuLayer(); @@ -160,4 +160,3 @@ class $modify(CustomMenuLayer, MenuLayer) { ModListLayer::scene(); } }; -// clang-format on diff --git a/loader/src/hooks/TouchDispatcherFix.cpp b/loader/src/hooks/TouchDispatcherFix.cpp index b3efdf8c..7a3c6264 100644 --- a/loader/src/hooks/TouchDispatcherFix.cpp +++ b/loader/src/hooks/TouchDispatcherFix.cpp @@ -1,15 +1,15 @@ USE_GEODE_NAMESPACE(); -// clang-format off #include -class $modify(CCTouchDispatcher) { - void addTargetedDelegate(CCTouchDelegate *delegate, int priority, bool swallowsTouches) { + +struct ForcePrioRevert : Modify { + void addTargetedDelegate(CCTouchDelegate* delegate, int priority, bool swallowsTouches) { m_bForcePrio = false; if (m_pTargetedHandlers->count() > 0) { auto handler = static_cast(m_pTargetedHandlers->objectAtIndex(0)); priority = handler->getPriority() - 2; } - + CCTouchDispatcher::addTargetedDelegate(delegate, priority, swallowsTouches); } @@ -21,4 +21,3 @@ class $modify(CCTouchDispatcher) { m_bForcePrio = false; } }; -// clang-format on diff --git a/loader/src/hooks/handler_fixes.cpp b/loader/src/hooks/handler_fixes.cpp index 696df649..ec872713 100644 --- a/loader/src/hooks/handler_fixes.cpp +++ b/loader/src/hooks/handler_fixes.cpp @@ -1,14 +1,12 @@ // this is the fix for the dynamic_cast problems // TODO: completely replace dynamic_cast on macos - -using namespace cocos2d; -using namespace geode::modifier; +#include #if defined(GEODE_IS_IOS) || defined(GEODE_IS_MACOS) -using namespace geode::cast; +USE_GEODE_NAMESPACE(); #define HandlerFixFor(CCUtility) \ - class $modify(CCUtility##HandlerTypeinfoFix, CCUtility##Handler) { \ + struct CCUtility##HandlerFix : Modify { \ void destructor() { \ if (m_pDelegate) { \ cocos2d::CCObject* pObject = base_cast(m_pDelegate); \ @@ -55,7 +53,7 @@ HandlerFixFor(CCKeyboard); HandlerFixFor(CCMouse); #include -class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) { +struct CCTargetedTouchHandlerFix : Modify { void destructor() { if (m_pDelegate) { cocos2d::CCObject* pObject = base_cast(m_pDelegate); @@ -101,7 +99,7 @@ class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) { }; #include -class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) { +struct CCStandardTouchHandlerFix : Modify { void destructor() { if (m_pDelegate) { cocos2d::CCObject* pObject = base_cast(m_pDelegate); @@ -140,6 +138,7 @@ class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) { return pHandler; } }; + // clang-format on #endif diff --git a/loader/src/hooks/persist.cpp b/loader/src/hooks/persist.cpp index 92dfbe03..643aea0c 100644 --- a/loader/src/hooks/persist.cpp +++ b/loader/src/hooks/persist.cpp @@ -2,12 +2,11 @@ USE_GEODE_NAMESPACE(); -// clang-format off #include -class $modify(AchievementNotifier) { + +struct SceneSwitch : Modify { void willSwitchToScene(CCScene* scene) { AchievementNotifier::willSwitchToScene(scene); SceneManager::get()->willSwitchToScene(scene); } }; -// clang-format on \ No newline at end of file diff --git a/loader/src/hooks/save.cpp b/loader/src/hooks/save.cpp index b9252d50..6c67759f 100644 --- a/loader/src/hooks/save.cpp +++ b/loader/src/hooks/save.cpp @@ -2,9 +2,9 @@ USE_GEODE_NAMESPACE(); -// clang-format off #include -class $modify(AppDelegate) { + +struct SaveLoader : Modify { void trySaveGame() { log::log(Severity::Info, Loader::getInternalMod(), "Saving..."); @@ -14,8 +14,7 @@ class $modify(AppDelegate) { } log::log(Severity::Info, Loader::getInternalMod(), "Saved"); - + return AppDelegate::trySaveGame(); } -}; -// clang-format on +}; \ No newline at end of file diff --git a/loader/src/hooks/update.cpp b/loader/src/hooks/update.cpp index 4ce1dcb4..b3c923c5 100644 --- a/loader/src/hooks/update.cpp +++ b/loader/src/hooks/update.cpp @@ -1,12 +1,12 @@ #include USE_GEODE_NAMESPACE(); -// clang-format off + #include -class $modify(CCScheduler) { + +struct FunctionQueue : Modify { void update(float dt) { InternalLoader::get()->executeGDThreadQueue(); return CCScheduler::update(dt); } -}; -// clang-format on \ No newline at end of file +}; \ No newline at end of file diff --git a/loader/src/hooks/updateResources.cpp b/loader/src/hooks/updateResources.cpp index 3b312e16..a6788b43 100644 --- a/loader/src/hooks/updateResources.cpp +++ b/loader/src/hooks/updateResources.cpp @@ -4,21 +4,12 @@ USE_GEODE_NAMESPACE(); -class $modify(GameManager) { - void reloadAllStep2() { - GameManager::reloadAllStep2(); - Loader::get()->updateResourcePaths(); - } +struct ResourcesUpdate : Modify { + void loadAssets() { + LoadingLayer::loadAssets(); + // this is in case the user refreshes texture quality at runtime + if (this->m_loadStep == 10) { + Loader::get()->updateResources(); + } + } }; - -class $modify(LoadingLayer) { - bool init(bool fromReload) { - // this is in case the user refreshes texture quality at runtime - // resources are loaded first so things like texture packs override - // the GD textures - Loader::get()->waitForModsToBeLoaded(); - Loader::get()->updateResources(); - return LoadingLayer::init(fromReload); - } -}; -// clang-format on \ No newline at end of file diff --git a/loader/src/index/Index.cpp b/loader/src/index/Index.cpp index c0ff6a51..ced6e9a7 100644 --- a/loader/src/index/Index.cpp +++ b/loader/src/index/Index.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -86,7 +87,7 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) { // create directory for the local clone of // the index - auto indexDir = Loader::get()->getGeodeDirectory() / "index"; + auto indexDir = Loader::get()->getGeodeSaveDirectory() / GEODE_INDEX_DIRECTORY; ghc::filesystem::create_directories(indexDir); #if GITHUB_DONT_RATE_LIMIT_ME_PLS == 1 @@ -104,39 +105,32 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) { #endif + // read sha of currently installed commit + std::string currentCommitSHA = ""; + if (ghc::filesystem::exists(indexDir / "current")) { + auto data = utils::file::readString(indexDir / "current"); + if (data) { + currentCommitSHA = data.value(); + } + } + web::AsyncWebRequest() .join("index-update") - .fetch("https://api.github.com/repos/geode-sdk/mods/commits") - .json() - .then([this, force, callback](nlohmann::json const& json) { - auto indexDir = Loader::get()->getGeodeDirectory() / "index"; + .header(fmt::format("If-None-Match: \"{}\"", currentCommitSHA)) + .header("Accept: application/vnd.github.sha") + .fetch("https://api.github.com/repos/geode-sdk/mods/commits/main") + .text() + .then([this, force, callback, currentCommitSHA](std::string const& upcomingCommitSHA) { + auto indexDir = Loader::get()->getGeodeSaveDirectory() / GEODE_INDEX_DIRECTORY; - // check if rate-limited (returns object) - JsonChecker checkerObj(json); - auto obj = checkerObj.root("[geode-sdk/mods/commits]").obj(); - if (obj.has("documentation_url") && obj.has("message")) { - RETURN_ERROR(obj.has("message").get()); - } + // gee i sure hope no one does 60 commits to the mod index an hour and download every + // single one of them + if (upcomingCommitSHA == "") { + m_upToDate = true; + m_updating = false; - // get sha of latest commit - JsonChecker checker(json); - auto root = checker.root("[geode-sdk/mods/commits]").array(); - - std::string upcomingCommitSHA; - if (auto first = root.at(0).obj().needs("sha")) { - upcomingCommitSHA = first.get(); - } - else { - RETURN_ERROR("Unable to get hash from latest commit: " + checker.getError()); - } - - // read sha of currently installed commit - std::string currentCommitSHA = ""; - if (ghc::filesystem::exists(indexDir / "current")) { - auto data = utils::file::readString(indexDir / "current"); - if (data) { - currentCommitSHA = data.value(); - } + if (callback) callback(UpdateStatus::Finished, "", 100); + return; } // update if forced or latest commit has @@ -224,16 +218,34 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) { return; } - auto info = ModInfo::createFromFile(dir / "mod.json"); - if (!info) { - log::warn("{}: {}, skipping", dir, info.error()); + auto infoRes = ModInfo::createFromFile(dir / "mod.json"); + if (!infoRes) { + log::warn("{}: {}, skipping", dir, infoRes.error()); return; } + auto info = infoRes.value(); + + // make sure only latest version is present in index + auto old = std::find_if(m_items.begin(), m_items.end(), [info](IndexItem const& item) { + return item.m_info.m_id == info.m_id; + }); + if (old != m_items.end()) { + // this one is newer + if (old->m_info.m_version < info.m_version) { + m_items.erase(old); + } else { + log::warn( + "Found older version of ({} < {}) of {}, skipping", + info.m_version, old->m_info.m_version, info.m_id + ); + return; + } + } IndexItem item; item.m_path = dir; - item.m_info = info.value(); + item.m_info = info; if (!json.contains("download") || !json["download"].is_object()) { log::warn("[index.json].download is not an object, skipping"); @@ -284,7 +296,7 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) { Result<> Index::updateIndexFromLocalCache() { m_items.clear(); - auto baseIndexDir = Loader::get()->getGeodeDirectory() / "index"; + auto baseIndexDir = Loader::get()->getGeodeSaveDirectory() / GEODE_INDEX_DIRECTORY; // load geode.json (index settings) if (auto baseIndexJson = readJSON(baseIndexDir / "geode.json")) { @@ -529,7 +541,7 @@ void InstallItems::error(std::string const& info) { void InstallItems::finish(bool replaceFiles) { // move files from temp dir to geode directory - auto tempDir = Loader::get()->getGeodeDirectory() / "index" / "temp"; + auto tempDir = Loader::get()->getGeodeSaveDirectory() / GEODE_INDEX_DIRECTORY / "temp"; for (auto& file : ghc::filesystem::directory_iterator(tempDir)) { try { auto modDir = Loader::get()->getGeodeDirectory() / "mods"; @@ -605,7 +617,7 @@ InstallItems::CallbackID InstallItems::start(ItemInstallCallback callback, bool // by virtue of running this function we know item must be valid auto item = Index::get()->getKnownItem(inst); - auto indexDir = Loader::get()->getGeodeDirectory() / "index"; + auto indexDir = Loader::get()->getGeodeSaveDirectory() / GEODE_INDEX_DIRECTORY; (void)file::createDirectoryAll(indexDir / "temp"); auto tempFile = indexDir / "temp" / item.m_download.m_filename; diff --git a/loader/src/internal/InternalLoader.cpp b/loader/src/internal/InternalLoader.cpp index 64095e84..c9de6c10 100644 --- a/loader/src/internal/InternalLoader.cpp +++ b/loader/src/internal/InternalLoader.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -95,67 +96,38 @@ void InternalLoader::downloadLoaderResources(IndexUpdateCallback callback) { web::AsyncWebRequest() .join("update-geode-loader-resources") - .fetch("https://api.github.com/repos/geode-sdk/geode/releases/tags/" + version) - .json() - .then([tempResourcesZip, resourcesDir, callback](nlohmann::json const& json) { - auto checker = JsonChecker(json); - auto root = checker.root("[matching geode release]").obj(); - - // find resources.zip and download it - for (auto asset : root.needs("assets").iterate()) { - auto obj = asset.obj(); - if (obj.needs("name").get() == "resources.zip") { - auto url = obj.needs("browser_download_url").get(); - if (url.size()) { - web::AsyncWebRequest() - .fetch(url) - .into(tempResourcesZip) - .then([tempResourcesZip, resourcesDir, callback](auto) { - // unzip resources zip - auto unzip = file::unzipTo(tempResourcesZip, resourcesDir); - if (!unzip) { - if (callback) - callback( - UpdateStatus::Failed, - "Unable to unzip new resources: " + unzip.error(), 0 - ); - return; - } - // delete resources zip - try { - ghc::filesystem::remove(tempResourcesZip); - } - catch (...) { - } - - Loader::get()->updateResources(); - - if (callback) callback( - UpdateStatus::Finished, - "Resources updated", - 100 - ); - }) - .expect([callback](std::string const& info) { - if (callback) callback(UpdateStatus::Failed, info, 0); - }) - .progress([callback](auto&, double now, double total) { - if (callback) - callback( - UpdateStatus::Progress, "Downloading resources", - static_cast(now / total * 100.0) - ); - }); - } - } + .fetch(fmt::format( + "https://github.com/geode-sdk/geode/releases/download/{}/resources.zip", version + )) + .into(tempResourcesZip) + .then([tempResourcesZip, resourcesDir, callback](auto) { + // unzip resources zip + auto unzip = file::unzipTo(tempResourcesZip, resourcesDir); + if (!unzip) { + if (callback) + callback( + UpdateStatus::Failed, "Unable to unzip new resources: " + unzip.error(), 0 + ); + return; + } + // delete resources zip + try { + ghc::filesystem::remove(tempResourcesZip); + } + catch (...) { } - if (checker.isError()) { - if (callback) callback(UpdateStatus::Failed, checker.getError(), 0); - } + if (callback) callback(UpdateStatus::Finished, "Resources updated", 100); }) .expect([callback](std::string const& info) { if (callback) callback(UpdateStatus::Failed, info, 0); + }) + .progress([callback](auto&, double now, double total) { + if (callback) + callback( + UpdateStatus::Progress, "Downloading resources", + static_cast(now / total * 100.0) + ); }); } diff --git a/loader/src/load/Event.cpp b/loader/src/load/Event.cpp index b1dca1d9..8f7ba286 100644 --- a/loader/src/load/Event.cpp +++ b/loader/src/load/Event.cpp @@ -3,14 +3,14 @@ USE_GEODE_NAMESPACE(); -std::unordered_set Event::s_handlers = {}; +std::unordered_set Event::s_listeners = {}; -void BasicEventHandler::listen() { - Event::s_handlers.insert(this); +void EventListenerProtocol::enable() { + Event::s_listeners.insert(this); } -void BasicEventHandler::unlisten() { - Event::s_handlers.erase(this); +void EventListenerProtocol::disable() { + Event::s_listeners.erase(this); } BasicEventHandler::~BasicEventHandler() { @@ -22,8 +22,8 @@ Event::~Event() {} void Event::postFrom(Mod* m) { if (m) m_sender = m; - for (auto h : Event::s_handlers) { - if (h->passThrough(this) == PassThrough::Stop) { + for (auto h : Event::s_listeners) { + if (h->passThrough(this) == ListenerResult::Stop) { break; } } @@ -32,7 +32,3 @@ void Event::postFrom(Mod* m) { Mod* Event::getSender() { return m_sender; } - -std::unordered_set const& Event::getHandlers() { - return Event::s_handlers; -} diff --git a/loader/src/load/Loader.cpp b/loader/src/load/Loader.cpp index 427d38d7..d328e50d 100644 --- a/loader/src/load/Loader.cpp +++ b/loader/src/load/Loader.cpp @@ -37,6 +37,10 @@ void Loader::createDirectories() { auto tempDir = this->getGeodeDirectory() / GEODE_TEMP_DIRECTORY; auto confDir = this->getGeodeDirectory() / GEODE_CONFIG_DIRECTORY; + #ifdef GEODE_IS_MACOS + ghc::filesystem::create_directory(this->getSaveDirectory()); + #endif + ghc::filesystem::create_directories(resDir); ghc::filesystem::create_directory(confDir); ghc::filesystem::create_directory(modDir); @@ -465,7 +469,12 @@ ghc::filesystem::path Loader::getGameDirectory() const { } ghc::filesystem::path Loader::getSaveDirectory() const { + // not using ~/Library/Caches + #ifdef GEODE_IS_MACOS + return ghc::filesystem::path("/Users/Shared/Geode"); + #else return ghc::filesystem::path(CCFileUtils::sharedFileUtils()->getWritablePath().c_str()); + #endif } ghc::filesystem::path Loader::getGeodeDirectory() const { diff --git a/loader/src/ui/nodes/TextRenderer.cpp b/loader/src/ui/nodes/TextRenderer.cpp index 7d347ba3..813f7174 100644 --- a/loader/src/ui/nodes/TextRenderer.cpp +++ b/loader/src/ui/nodes/TextRenderer.cpp @@ -507,45 +507,33 @@ float TextRenderer::adjustLineAlignment() { auto anchor = node->getAnchorPoint().y; switch (this->getCurrentVerticalAlign()) { case TextAlignment::Begin: - default: - { - node->setPositionY(m_cursor.y - height * (1.f - anchor)); - } - break; + default: { + node->setPositionY(m_cursor.y - height * (1.f - anchor)); + } break; - case TextAlignment::Center: - { - node->setPositionY(m_cursor.y - maxHeight / 2 + height * (.5f - anchor)); - } - break; + case TextAlignment::Center: { + node->setPositionY(m_cursor.y - maxHeight / 2 + height * (.5f - anchor)); + } break; - case TextAlignment::End: - { - node->setPositionY(m_cursor.y - maxHeight + height * anchor); - } - break; + case TextAlignment::End: { + node->setPositionY(m_cursor.y - maxHeight + height * anchor); + } break; } switch (this->getCurrentHorizontalAlign()) { case TextAlignment::Begin: - default: - { - // already correct - } - break; + default: { + // already correct + } break; - case TextAlignment::Center: - { - node->setPositionX(node->getPositionX() + (m_size.width - maxWidth) / 2); - } - break; + case TextAlignment::Center: { + node->setPositionX(node->getPositionX() + (m_size.width - maxWidth) / 2); + } break; - case TextAlignment::End: - { - node->setPositionX( - node->getPositionX() + m_size.width - maxWidth - this->getCurrentIndent() - ); - } - break; + case TextAlignment::End: { + node->setPositionX( + node->getPositionX() + m_size.width - maxWidth - this->getCurrentIndent() + ); + } break; } } return maxHeight; diff --git a/loader/src/utils/convert.cpp b/loader/src/utils/convert.cpp index 84ef0cdc..5a68c093 100644 --- a/loader/src/utils/convert.cpp +++ b/loader/src/utils/convert.cpp @@ -126,37 +126,29 @@ Result geode::cocos::cc3bFromHexString(std::string const& hexValue) { return Err("Invalid hex value"); } switch (hexValue.size()) { - case 6: - { - auto r = static_cast((numValue & 0xFF0000) >> 16); - auto g = static_cast((numValue & 0x00FF00) >> 8); - auto b = static_cast((numValue & 0x0000FF)); - return Ok(ccc3(r, g, b)); - } - break; + case 6: { + auto r = static_cast((numValue & 0xFF0000) >> 16); + auto g = static_cast((numValue & 0x00FF00) >> 8); + auto b = static_cast((numValue & 0x0000FF)); + return Ok(ccc3(r, g, b)); + } break; - case 3: - { - auto r = static_cast(((numValue & 0xF00) >> 8) * 17); - auto g = static_cast(((numValue & 0x0F0) >> 4) * 17); - auto b = static_cast(((numValue & 0x00F)) * 17); - return Ok(ccc3(r, g, b)); - } - break; + case 3: { + auto r = static_cast(((numValue & 0xF00) >> 8) * 17); + auto g = static_cast(((numValue & 0x0F0) >> 4) * 17); + auto b = static_cast(((numValue & 0x00F)) * 17); + return Ok(ccc3(r, g, b)); + } break; - case 2: - { - auto num = static_cast(numValue); - return Ok(ccc3(num, num, num)); - } - break; + case 2: { + auto num = static_cast(numValue); + return Ok(ccc3(num, num, num)); + } break; - case 1: - { - auto num = static_cast(numValue) * 17; - return Ok(ccc3(num, num, num)); - } - break; + case 1: { + auto num = static_cast(numValue) * 17; + return Ok(ccc3(num, num, num)); + } break; default: return Err("Invalid hex size, expected 1, 2, 3, or 6"); } @@ -177,57 +169,45 @@ Result geode::cocos::cc4bFromHexString(std::string const& hexValue) { return Err("Invalid hex value"); } switch (hexValue.size()) { - case 8: - { - auto r = static_cast((numValue & 0xFF000000) >> 24); - auto g = static_cast((numValue & 0x00FF0000) >> 16); - auto b = static_cast((numValue & 0x0000FF00) >> 8); - auto a = static_cast((numValue & 0x000000FF)); - return Ok(ccc4(r, g, b, a)); - } - break; + case 8: { + auto r = static_cast((numValue & 0xFF000000) >> 24); + auto g = static_cast((numValue & 0x00FF0000) >> 16); + auto b = static_cast((numValue & 0x0000FF00) >> 8); + auto a = static_cast((numValue & 0x000000FF)); + return Ok(ccc4(r, g, b, a)); + } break; - case 6: - { - auto r = static_cast((numValue & 0xFF0000) >> 16); - auto g = static_cast((numValue & 0x00FF00) >> 8); - auto b = static_cast((numValue & 0x0000FF)); - return Ok(ccc4(r, g, b, 255)); - } - break; + case 6: { + auto r = static_cast((numValue & 0xFF0000) >> 16); + auto g = static_cast((numValue & 0x00FF00) >> 8); + auto b = static_cast((numValue & 0x0000FF)); + return Ok(ccc4(r, g, b, 255)); + } break; - case 4: - { - auto r = static_cast(((numValue & 0xF000) >> 12) * 17); - auto g = static_cast(((numValue & 0x0F00) >> 8) * 17); - auto b = static_cast(((numValue & 0x00F0) >> 4) * 17); - auto a = static_cast(((numValue & 0x000F)) * 17); - return Ok(ccc4(r, g, b, a)); - } - break; + case 4: { + auto r = static_cast(((numValue & 0xF000) >> 12) * 17); + auto g = static_cast(((numValue & 0x0F00) >> 8) * 17); + auto b = static_cast(((numValue & 0x00F0) >> 4) * 17); + auto a = static_cast(((numValue & 0x000F)) * 17); + return Ok(ccc4(r, g, b, a)); + } break; - case 3: - { - auto r = static_cast(((numValue & 0xF00) >> 8) * 17); - auto g = static_cast(((numValue & 0x0F0) >> 4) * 17); - auto b = static_cast(((numValue & 0x00F)) * 17); - return Ok(ccc4(r, g, b, 255)); - } - break; + case 3: { + auto r = static_cast(((numValue & 0xF00) >> 8) * 17); + auto g = static_cast(((numValue & 0x0F0) >> 4) * 17); + auto b = static_cast(((numValue & 0x00F)) * 17); + return Ok(ccc4(r, g, b, 255)); + } break; - case 2: - { - auto num = static_cast(numValue); - return Ok(ccc4(num, num, num, 255)); - } - break; + case 2: { + auto num = static_cast(numValue); + return Ok(ccc4(num, num, num, 255)); + } break; - case 1: - { - auto num = static_cast(numValue) * 17; - return Ok(ccc4(num, num, num, 255)); - } - break; + case 1: { + auto num = static_cast(numValue) * 17; + return Ok(ccc4(num, num, num, 255)); + } break; default: return Err("Invalid hex size, expected 1, 2, 3, 4, 6, or 8"); } diff --git a/loader/src/utils/fetch.cpp b/loader/src/utils/fetch.cpp index dd9b942e..c1416660 100644 --- a/loader/src/utils/fetch.cpp +++ b/loader/src/utils/fetch.cpp @@ -127,7 +127,7 @@ static std::unordered_map RUNNING_REQUES static std::mutex RUNNING_REQUESTS_MUTEX; SentAsyncWebRequest::SentAsyncWebRequest(AsyncWebRequest const& req, std::string const& id) : - m_id(id), m_url(req.m_url), m_target(req.m_target) { + m_id(id), m_url(req.m_url), m_target(req.m_target), m_httpHeaders(req.m_httpHeaders) { #define AWAIT_RESUME() \ while (m_paused) {} \ if (m_cancelled) { \ @@ -178,6 +178,12 @@ SentAsyncWebRequest::SentAsyncWebRequest(AsyncWebRequest const& req, std::string curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_slist* headers = nullptr; + for (auto& header : m_httpHeaders) { + headers = curl_slist_append(headers, header.c_str()); + } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ProgressData { SentAsyncWebRequest* self; std::ofstream* file; @@ -293,6 +299,11 @@ AsyncWebRequest& AsyncWebRequest::join(std::string const& requestID) { return *this; } +AsyncWebRequest& AsyncWebRequest::header(std::string const& header) { + m_httpHeaders.push_back(header); + return *this; +} + AsyncWebResponse AsyncWebRequest::fetch(std::string const& url) { m_url = url; return AsyncWebResponse(*this); diff --git a/loader/src/utils/version.cpp b/loader/src/utils/version.cpp index 4cfadbbe..cd72a00a 100644 --- a/loader/src/utils/version.cpp +++ b/loader/src/utils/version.cpp @@ -15,16 +15,15 @@ USE_GEODE_NAMESPACE(); #endif VersionInfo::VersionInfo(char const* versionString) { - if (!THE_SSCANF(versionString, "v%d.%d.%d", &this->m_major, &this->m_minor, &this->m_patch)) - if (!THE_SSCANF(versionString, "%d.%d.%d", &this->m_major, &this->m_minor, &this->m_patch)) - THE_SSCANF(versionString, "%d %d %d", &this->m_major, &this->m_minor, &this->m_patch); + if (!THE_SSCANF(versionString, "v%d.%d.%d", &this->m_major, &this->m_minor, &this->m_patch)) { + THE_SSCANF(versionString, "%d.%d.%d", &this->m_major, &this->m_minor, &this->m_patch); + } } bool VersionInfo::validate(std::string const& string) { int buf0, buf1, buf2; if (THE_SSCANF(string.c_str(), "v%d.%d.%d", &buf0, &buf1, &buf2)) return true; if (THE_SSCANF(string.c_str(), "%d.%d.%d", &buf0, &buf1, &buf2)) return true; - if (THE_SSCANF(string.c_str(), "%d %d %d", &buf0, &buf1, &buf2)) return true; return false; } diff --git a/loader/test/dependency/main.cpp b/loader/test/dependency/main.cpp index 1fadbb82..3904d2ee 100644 --- a/loader/test/dependency/main.cpp +++ b/loader/test/dependency/main.cpp @@ -3,31 +3,26 @@ USE_GEODE_NAMESPACE(); #include -class $modify(MenuLayer) { - void onMoreGames(CCObject*) { - if (Mod::get()->getSettingValue("its-raining-after-all")) { - FLAlertLayer::create( - "Damn", - ":(", - "OK" - )->show(); - } else { - FLAlertLayer::create( - "Yay", - "The weather report said it wouldn't rain today :)", - "OK" - )->show(); - } - } + +struct MyMenuLayer : Modify { + void onMoreGames(CCObject*) { + if (Mod::get()->getSettingValue("its-raining-after-all")) { + FLAlertLayer::create("Damn", ":(", "OK")->show(); + } + else { + FLAlertLayer::create("Yay", "The weather report said it wouldn't rain today :)", "OK") + ->show(); + } + } }; GEODE_API bool GEODE_CALL geode_load(Mod*) { - // Dispatcher::get()->addFunction("test-garage-open", [](GJGarageLayer* gl) { - // auto label = CCLabelBMFont::create("Dispatcher works!", "bigFont.fnt"); - // label->setPosition(100, 80); - // label->setScale(.4f); - // label->setZOrder(99999); - // gl->addChild(label); - // }); - return true; + // Dispatcher::get()->addFunction("test-garage-open", [](GJGarageLayer* + // gl) { auto label = CCLabelBMFont::create("Dispatcher works!", "bigFont.fnt"); + // label->setPosition(100, 80); + // label->setScale(.4f); + // label->setZOrder(99999); + // gl->addChild(label); + // }); + return true; } diff --git a/loader/test/dependency/mod.json b/loader/test/dependency/mod.json index 3e6d7a31..0b373132 100644 --- a/loader/test/dependency/mod.json +++ b/loader/test/dependency/mod.json @@ -1,6 +1,6 @@ { - "geode": "v0.4.1", - "version": "v1.0.0", + "geode": "0.4.1", + "version": "1.0.0", "id": "geode.testdep", "name": "Geode Test Dependency", "developer": "Geode Team", diff --git a/loader/test/main/main.cpp b/loader/test/main/main.cpp index 33b12350..71d7a6aa 100644 --- a/loader/test/main/main.cpp +++ b/loader/test/main/main.cpp @@ -2,90 +2,91 @@ USE_GEODE_NAMESPACE(); -auto test = [](){ +auto test = []() { log::info("Static logged"); return 0; }; // Exported functions GEODE_API bool GEODE_CALL geode_enable() { - log::info("Enabled"); - return true; + log::info("Enabled"); + return true; } GEODE_API bool GEODE_CALL geode_disable() { - log::info("Disabled"); - return true; + log::info("Disabled"); + return true; } GEODE_API bool GEODE_CALL geode_load(Mod*) { - log::info("Loaded"); - return true; + log::info("Loaded"); + return true; } GEODE_API bool GEODE_CALL geode_unload() { - log::info("Unloaded"); - return true; + log::info("Unloaded"); + return true; } // Modify #include -class $modify(GJGarageLayerTest, GJGarageLayer) { - GJGarageLayerTest() : - myValue(1907) {} - int myValue; - std::string myString = "yeah have fun finding a better thing for this"; - bool init() { - if (!GJGarageLayer::init()) return false; +struct GJGarageLayerTest : Modify { + GJGarageLayerTest() : myValue(1907) {} - auto label = CCLabelBMFont::create("Modify works!", "bigFont.fnt"); - label->setPosition(100, 110); - label->setScale(.4f); - label->setZOrder(99999); - addChild(label); + int myValue; + std::string myString = "yeah have fun finding a better thing for this"; - if (m_fields->myValue == 1907 && m_fields->myString != "") { - auto label = CCLabelBMFont::create("Field default works!", "bigFont.fnt"); - label->setPosition(100, 100); - label->setScale(.4f); - label->setZOrder(99999); - addChild(label); - } + bool init() { + if (!GJGarageLayer::init()) return false; - // Data Store - auto ds = Mod::get()->getDataStore(); - int out = ds["times-opened"]; - ds["times-opened"] = out + 1; + auto label = CCLabelBMFont::create("Modify works!", "bigFont.fnt"); + label->setPosition(100, 110); + label->setScale(.4f); + label->setZOrder(99999); + addChild(label); - std::string text = std::string("Times opened: ") + std::to_string(out); + if (m_fields->myValue == 1907 && m_fields->myString != "") { + auto label = CCLabelBMFont::create("Field default works!", "bigFont.fnt"); + label->setPosition(100, 100); + label->setScale(.4f); + label->setZOrder(99999); + addChild(label); + } - auto label2 = CCLabelBMFont::create(text.c_str(), "bigFont.fnt"); - label2->setPosition(100, 90); - label2->setScale(.4f); - label2->setZOrder(99999); - addChild(label2); + // Data Store + auto ds = Mod::get()->getDataStore(); + int out = ds["times-opened"]; + ds["times-opened"] = out + 1; - // Dispatch system pt. 1 - // auto fn = Dispatcher::get()->getFunction("test-garage-open"); - // fn(this); + std::string text = std::string("Times opened: ") + std::to_string(out); - return true; - } + auto label2 = CCLabelBMFont::create(text.c_str(), "bigFont.fnt"); + label2->setPosition(100, 90); + label2->setScale(.4f); + label2->setZOrder(99999); + addChild(label2); + + // Dispatch system pt. 1 + // auto fn = Dispatcher::get()->getFunction("test-garage-open"); + // fn(this); + + return true; + } }; /*// Event system pt. 2 int a = (0, []() { - Dispatcher::get()->addSelector("test-garage-open", [](GJGarageLayer* gl) { - auto label = CCLabelBMFont::create("EventCenter works!", "bigFont.fnt"); - label->setPosition(100, 80); - label->setScale(.4f); - label->setZOrder(99999); - gl->addChild(label); + Dispatcher::get()->addSelector("test-garage-open", [](GJGarageLayer* gl) { + auto label = CCLabelBMFont::create("EventCenter works!", "bigFont.fnt"); + label->setPosition(100, 80); + label->setScale(.4f); + label->setZOrder(99999); + gl->addChild(label); - TestDependency::depTest(gl); - }); + TestDependency::depTest(gl); + }); // Event system pt. 2 // $observe("test-garage-open", GJGarageLayer*, evt) { @@ -99,6 +100,5 @@ int a = (0, []() { // // API pt. 2 // TestDependency::depTest(gl); // } - return 0; + return 0; }());*/ - diff --git a/loader/test/main/mod.json b/loader/test/main/mod.json index 0f0c2ebb..6d9aeb0c 100644 --- a/loader/test/main/mod.json +++ b/loader/test/main/mod.json @@ -1,6 +1,6 @@ { - "geode": "v0.4.1", - "version": "v1.0.0", + "geode": "0.4.1", + "version": "1.0.0", "id": "geode.test", "name": "Geode Test", "developer": "Geode Team", @@ -11,7 +11,7 @@ "dependencies": [ { "id": "geode.testdep", - "version": "v1.0.*", + "version": "1.0.*", "required": true } ]