mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
Merge branch 'main' into layout
This commit is contained in:
commit
61c0f1b274
41 changed files with 714 additions and 588 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<EditorPauseLayer*>(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
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
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 <Geode/modify/Modify.hpp>
|
||||
#include <Geode/modify/Field.hpp>
|
||||
#include <Geode/modify/InternalMacros.hpp>
|
||||
|
@ -28,100 +30,89 @@ using namespace geode::modifier;
|
|||
namespace geode::modifier {{
|
||||
{wrap}
|
||||
template<class Derived>
|
||||
struct Modify<Derived, {class_name}> : ModifyBase<Modify<Derived, {class_name}>> {{
|
||||
using ModifyBase<Modify<Derived, {class_name}>>::ModifyBase;
|
||||
struct ModifyDerive<Derived, {class_name}> : ModifyBase<ModifyDerive<Derived, {class_name}>> {{
|
||||
using ModifyBase<ModifyDerive<Derived, {class_name}>>::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<std::string> 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<std::string> 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;
|
||||
}
|
||||
|
|
|
@ -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 <typename C, typename T>
|
||||
struct to_member;
|
||||
|
||||
template <typename C, typename R, typename ...Args>
|
||||
struct to_member<C, R(Args...)> {
|
||||
using value = R(C::*)(Args...);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept is_event = std::is_base_of_v<Event, T>;
|
||||
|
||||
template <is_event T>
|
||||
class EventFilter {
|
||||
public:
|
||||
using Callback = ListenerResult(T*);
|
||||
using Event = T;
|
||||
|
||||
ListenerResult handle(std::function<Callback> fn, T* e) {
|
||||
return fn(e);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept is_filter =
|
||||
std::is_base_of_v<EventFilter<typename T::Event>, T> &&
|
||||
requires(T a) {
|
||||
a.handle(std::declval<typename T::Callback>(), std::declval<typename T::Event*>());
|
||||
};
|
||||
|
||||
template <is_filter T>
|
||||
class EventListener : public EventListenerProtocol {
|
||||
public:
|
||||
using Callback = typename T::Callback;
|
||||
template <typename C> requires std::is_class_v<C>
|
||||
using MemberFn = typename to_member<C, Callback>::value;
|
||||
|
||||
ListenerResult passThrough(Event* e) override {
|
||||
if (auto myev = dynamic_cast<typename T::Event*>(e)) {
|
||||
return m_filter.handle(m_callback, myev);
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
EventListener(T filter = T()) {}
|
||||
EventListener(std::function<Callback> fn, T filter = T()) : m_callback(fn), m_filter(filter) {}
|
||||
EventListener(Callback* fnptr, T filter = T()) : m_callback(fnptr), m_filter(filter) {}
|
||||
|
||||
template <class C>
|
||||
EventListener(C* cls, MemberFn<C> fn, T filter = T()) : EventListener(std::bind(fn, cls, std::placeholders::_1), filter) {}
|
||||
|
||||
void bind(std::function<Callback> fn) {
|
||||
m_callback = fn;
|
||||
}
|
||||
template <typename C>
|
||||
void bind(C* cls, MemberFn<C> fn) {
|
||||
m_callback = std::bind(fn, cls, std::placeholders::_1);
|
||||
}
|
||||
protected:
|
||||
std::function<Callback> m_callback;
|
||||
T m_filter;
|
||||
};
|
||||
|
||||
class GEODE_DLL Event {
|
||||
static std::unordered_set<BasicEventHandler*> s_handlers;
|
||||
|
||||
friend BasicEventHandler;
|
||||
|
||||
static std::unordered_set<EventListenerProtocol*> s_listeners;
|
||||
Mod* m_sender;
|
||||
|
||||
friend EventListenerProtocol;
|
||||
public:
|
||||
static std::unordered_set<BasicEventHandler*> const& getHandlers();
|
||||
|
||||
void postFrom(Mod* sender);
|
||||
|
||||
inline void post() {
|
||||
|
@ -44,21 +98,4 @@ namespace geode {
|
|||
|
||||
virtual ~Event();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class EventHandler : public BasicEventHandler {
|
||||
public:
|
||||
virtual PassThrough handle(T*) = 0;
|
||||
|
||||
PassThrough passThrough(Event* ev) override {
|
||||
if (auto myev = dynamic_cast<T*>(ev)) {
|
||||
return handle(myev);
|
||||
}
|
||||
return PassThrough::Propagate;
|
||||
}
|
||||
|
||||
EventHandler() {
|
||||
listen();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 <class, class, class>
|
||||
template <class, class>
|
||||
class FieldIntermediate;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +102,7 @@ namespace geode {
|
|||
|
||||
size_t getFieldIndexForClass(size_t hash);
|
||||
|
||||
template <class, class, class>
|
||||
template <class, class>
|
||||
friend class modifier::FieldIntermediate;
|
||||
|
||||
void updateModResources(Mod* mod);
|
||||
|
|
|
@ -468,11 +468,19 @@ namespace geode {
|
|||
} \
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
template <class T>
|
||||
T getBuiltInSettingValue(const std::shared_ptr<Setting> setting) {
|
||||
GEODE_INT_BUILTIN_SETTING_IF(Bool, getValue(), std::is_same_v<T, bool>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Float, getValue(), std::is_floating_point_v<T>) else GEODE_INT_BUILTIN_SETTING_IF(Int, getValue(), std::is_integral_v<T>) else GEODE_INT_BUILTIN_SETTING_IF(String, getValue(), std::is_same_v<T, std::string>) else {
|
||||
static_assert(!std::is_same_v<T, T>, "todo: implement");
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Float, getValue(), std::is_floating_point_v<T>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Int, getValue(), std::is_integral_v<T>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(String, getValue(), std::is_same_v<T, std::string>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(File, getValue(), std::is_same_v<T, ghc::filesystem::path>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Color, getValue(), std::is_same_v<T, cocos2d::ccColor3B>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(ColorAlpha, getValue(), std::is_same_v<T, cocos2d::ccColor4B>)
|
||||
else {
|
||||
static_assert(!std::is_same_v<T, T>, "Unsupported type for getting setting value!");
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
@ -480,10 +488,17 @@ namespace geode {
|
|||
template <class T>
|
||||
void setBuiltInSettingValue(const std::shared_ptr<Setting> setting, T const& value) {
|
||||
GEODE_INT_BUILTIN_SETTING_IF(Bool, setValue(value), std::is_same_v<T, bool>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Float, setValue(value), std::is_floating_point_v<T>) else GEODE_INT_BUILTIN_SETTING_IF(Int, setValue(value), std::is_integral_v<T>) else GEODE_INT_BUILTIN_SETTING_IF(String, setValue(value), std::is_same_v<T, std::string>) else {
|
||||
static_assert(!std::is_same_v<T, T>, "todo: implement");
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Float, setValue(value), std::is_floating_point_v<T>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Int, setValue(value), std::is_integral_v<T>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(String, setValue(value), std::is_same_v<T, std::string>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(File, setValue(value), std::is_same_v<T, ghc::filesystem::path>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(Color, setValue(value), std::is_same_v<T, cocos2d::ccColor3B>)
|
||||
else GEODE_INT_BUILTIN_SETTING_IF(ColorAlpha, setValue(value), std::is_same_v<T, cocos2d::ccColor4B>)
|
||||
else {
|
||||
static_assert(!std::is_same_v<T, T>, "Unsupported type for getting setting value!");
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
|
|
@ -18,41 +18,37 @@ namespace geode {
|
|||
std::shared_ptr<Setting> getSetting() const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SettingChangedEventHandler : public EventHandler<SettingChangedEvent> {
|
||||
template <typename T = Setting, typename = std::enable_if_t<std::is_base_of_v<Setting, T>>>
|
||||
class SettingChangedFilter : public EventFilter<SettingChangedEvent> {
|
||||
public:
|
||||
using Consumer = void (*)(std::shared_ptr<T>);
|
||||
using Callback = void(std::shared_ptr<T>);
|
||||
using Event = SettingChangedEvent;
|
||||
|
||||
static_assert(std::is_base_of_v<Setting, T>, "Setting must inherit from the Setting class");
|
||||
|
||||
protected:
|
||||
Consumer m_consumer;
|
||||
std::string m_modID;
|
||||
std::optional<std::string> m_targetKey;
|
||||
|
||||
public:
|
||||
PassThrough handle(SettingChangedEvent* event) override {
|
||||
ListenerResult handle(std::function<Callback> fn, SettingChangedEvent* event) {
|
||||
if (m_modID == event->getModID() &&
|
||||
(!m_targetKey || m_targetKey.value() == event->getSetting()->getKey())) {
|
||||
m_consumer(std::static_pointer_cast<T>(event->getSetting()));
|
||||
fn(std::static_pointer_cast<T>(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<std::string> m_targetKey;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -61,14 +57,14 @@ namespace geode {
|
|||
std::string const& settingID, void (*callback)(std::shared_ptr<T>)
|
||||
) {
|
||||
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
|
||||
static SettingChangedEventHandler<T> _(getMod()->getID(), settingID, callback);
|
||||
static auto _ = EventListener(callback, SettingChangedFilter<T>(getMod()->getID(), settingID));
|
||||
});
|
||||
return std::monostate();
|
||||
}
|
||||
|
||||
static std::monostate listenForAllSettingChanges(void (*callback)(std::shared_ptr<Setting>)) {
|
||||
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
|
||||
static SettingChangedEventHandler<Setting> _(getMod()->getID(), callback);
|
||||
static auto _ = EventListener(callback, SettingChangedFilter(getMod()->getID()));
|
||||
});
|
||||
return std::monostate();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace geode::modifier {
|
|||
}
|
||||
};
|
||||
|
||||
template <class Base, class Intermediate, class Parent>
|
||||
template <class Parent, class Base>
|
||||
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<std::byte, sizeof(Parent)> 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::~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<Parent*>(
|
||||
reinterpret_cast<std::byte*>(offsetField) - sizeof(Intermediate)
|
||||
reinterpret_cast<std::byte*>(offsetField) - sizeof(Base)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,15 +8,9 @@
|
|||
* struct hook0 {};
|
||||
* namespace {
|
||||
* struct hook0Parent {};
|
||||
* Modify<hook0<hook0Parent>, MenuLayer> hook0Apply;
|
||||
* struct GEODE_HIDDEN hook0Intermediate: public MenuLayer {
|
||||
* geode::modifier::FieldIntermediate<MenuLayer,
|
||||
* hook0<hook0Intermediate>, hook0<hook0Parent>
|
||||
* > m_fields;
|
||||
* };
|
||||
* }
|
||||
* template<>
|
||||
* struct GEODE_HIDDEN hook0<hook0Parent>: hook0Intermediate {
|
||||
* struct GEODE_HIDDEN hook0<hook0Parent> : Modify<hook0<hook0Parent>, MenuLayer> {
|
||||
* // code stuff idk
|
||||
* };
|
||||
*
|
||||
|
@ -24,33 +18,19 @@
|
|||
* I am bad at this stuff
|
||||
*/
|
||||
|
||||
#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \
|
||||
derived##Dummy; \
|
||||
template <class> \
|
||||
struct derived {}; \
|
||||
namespace { \
|
||||
struct derived##Parent {}; \
|
||||
Modify<derived<derived##Parent>, base> derived##Apply; \
|
||||
struct GEODE_HIDDEN derived##Intermediate : base { \
|
||||
mutable geode::modifier::FieldIntermediate< \
|
||||
base, derived##Intermediate, derived<derived##Parent>> \
|
||||
m_fields; \
|
||||
}; \
|
||||
} \
|
||||
template <> \
|
||||
struct GEODE_HIDDEN derived<derived##Parent> : derived##Intermediate
|
||||
#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \
|
||||
derived##Dummy; \
|
||||
template <class> \
|
||||
struct derived {}; \
|
||||
namespace { \
|
||||
struct derived##Parent {}; \
|
||||
} \
|
||||
template <> \
|
||||
struct GEODE_HIDDEN derived<derived##Parent> : geode::Modify<derived<derived##Parent>, base>
|
||||
|
||||
#define GEODE_MODIFY_DECLARE(base, derived) \
|
||||
derived##Dummy; \
|
||||
struct derived; \
|
||||
namespace { \
|
||||
Modify<derived, base> derived##Apply; \
|
||||
struct GEODE_HIDDEN derived##Intermediate : base { \
|
||||
mutable geode::modifier::FieldIntermediate<base, derived##Intermediate, derived> \
|
||||
m_fields; \
|
||||
}; \
|
||||
} \
|
||||
struct GEODE_HIDDEN derived : derived##Intermediate
|
||||
#define GEODE_MODIFY_DECLARE(base, derived) \
|
||||
derived##Dummy; \
|
||||
struct GEODE_HIDDEN derived : geode::Modify<derived, base>
|
||||
|
||||
#define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived)
|
||||
#define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived)
|
||||
|
|
|
@ -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 Derived, class Base>
|
||||
class Modify;
|
||||
class ModifyDerive;
|
||||
|
||||
template <class Derived>
|
||||
class ModifyBase {
|
||||
|
@ -34,15 +35,29 @@ namespace geode::modifier {
|
|||
});
|
||||
}
|
||||
template <class, class>
|
||||
friend class Modify;
|
||||
friend class ModifyDerive;
|
||||
// explicit Modify(Property property) idea
|
||||
};
|
||||
|
||||
template <class Derived, class Base>
|
||||
class Modify {
|
||||
class ModifyDerive {
|
||||
public:
|
||||
Modify() {
|
||||
ModifyDerive() {
|
||||
static_assert(core::meta::always_false<Derived>, "Custom Modify not implemented.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace geode {
|
||||
|
||||
template <class Derived, class Base>
|
||||
class Modify : public Base {
|
||||
private:
|
||||
static inline modifier::ModifyDerive<Derived, Base> s_apply;
|
||||
// because for some reason we need it
|
||||
static inline auto s_applyRef = &Modify::s_apply;
|
||||
|
||||
public:
|
||||
modifier::FieldIntermediate<Derived, Base> m_fields;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -101,9 +101,32 @@ namespace geode {
|
|||
bool operator==(T* other) const {
|
||||
return m_obj == other;
|
||||
}
|
||||
|
||||
bool operator==(Ref<T> const& other) const {
|
||||
return m_obj == other.m_obj;
|
||||
}
|
||||
|
||||
bool operator!=(T* other) const {
|
||||
return m_obj != other;
|
||||
}
|
||||
bool operator!=(Ref<T> const& other) const {
|
||||
return m_obj != other.m_obj;
|
||||
}
|
||||
|
||||
// for containers
|
||||
bool operator<(Ref<T> const& other) const {
|
||||
return m_obj < other.m_obj;
|
||||
}
|
||||
bool operator>(Ref<T> const& other) const {
|
||||
return m_obj > other.m_obj;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<class T>
|
||||
struct hash<geode::Ref<T>> {
|
||||
size_t operator()(geode::Ref<T> const& ref) const {
|
||||
return std::hash<T*>()(ref.data());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace geode::cast {
|
|||
/**
|
||||
* Alias for static_cast
|
||||
*/
|
||||
template <typename T, typename F>
|
||||
template <class T, class F>
|
||||
static constexpr T as(F const v) {
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ namespace geode::cast {
|
|||
* Cast from anything to anything else,
|
||||
* provided they are the same size
|
||||
*/
|
||||
template <typename T, typename F>
|
||||
static constexpr T union_cast(F v) {
|
||||
template <class T, class F>
|
||||
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 <typename T, typename F>
|
||||
template <class T, class F>
|
||||
static constexpr T reference_cast(F v) {
|
||||
return reinterpret_cast<T&>(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 <typename T, typename F>
|
||||
static constexpr T base_cast(F obj) {
|
||||
return reinterpret_cast<T>(dynamic_cast<void*>(obj));
|
||||
template <class T, class F>
|
||||
static constexpr T base_cast(F const obj) {
|
||||
return static_cast<T>(dynamic_cast<void*>(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 <typename T, typename F>
|
||||
static T typeid_cast(F obj) {
|
||||
if (std::string(typeid(*obj).name()) == typeid(std::remove_pointer_t<T>).name())
|
||||
return reinterpret_cast<T>(obj);
|
||||
else return nullptr;
|
||||
template <class T, class F>
|
||||
static T exact_cast(F const obj) {
|
||||
if (std::strcmp(typeid(*obj).name(), typeid(std::remove_pointer_t<T>).name()) == 0) {
|
||||
return base_cast<T>(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 <class T, class F>
|
||||
static T safe_cast(F const obj) {
|
||||
return typeinfo_cast<T>(obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ namespace geode::utils::web {
|
|||
mutable std::mutex m_mutex;
|
||||
std::variant<std::monostate, std::ostream*, ghc::filesystem::path> m_target =
|
||||
std::monostate();
|
||||
std::vector<std::string> m_httpHeaders;
|
||||
|
||||
template <class T>
|
||||
friend class AsyncWebResult;
|
||||
|
@ -134,6 +135,7 @@ namespace geode::utils::web {
|
|||
AsyncCancelled m_cancelled = nullptr;
|
||||
bool m_sent = false;
|
||||
std::variant<std::monostate, std::ostream*, ghc::filesystem::path> m_target;
|
||||
std::vector<std::string> m_httpHeaders;
|
||||
|
||||
template <class T>
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace geode::utils::ranges {
|
||||
template <class C>
|
||||
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 <ValidConstContainer C>
|
||||
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 <class T, ValidConstContainer C, ValidIntoConverter<typename C::value_type, T> 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 <ValidConstContainer C>
|
||||
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 <class T, ValidConstContainer C, ValidIntoConverter<typename C::value_type, T> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
// proxy forwards
|
||||
// clang-format off
|
||||
#include <Geode/modify/CCNode.hpp>
|
||||
class $modify(ProxyCCNode, CCNode) {
|
||||
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
|
||||
virtual CCObject* getUserObject() {
|
||||
return GeodeNodeMetadata::set(this)->m_userObject;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
USE_GEODE_NAMESPACE();
|
||||
|
||||
#pragma warning(disable : 4217)
|
||||
template <class T = CCNode>
|
||||
|
||||
requires std::is_base_of_v<CCNode, T> T* setIDSafe(CCNode* node, int index, char const* id) {
|
||||
template <class T = CCNode>
|
||||
requires std::is_base_of_v<CCNode, T>
|
||||
T* setIDSafe(CCNode* node, int index, char const* id) {
|
||||
if constexpr (std::is_same_v<CCNode, T>) {
|
||||
if (auto child = getChild(node, index)) {
|
||||
child->setID(id);
|
||||
|
@ -29,7 +30,7 @@ requires std::is_base_of_v<CCNode, T> T* setIDSafe(CCNode* node, int index, char
|
|||
|
||||
// clang-format off
|
||||
#include <Geode/modify/LevelSearchLayer.hpp>
|
||||
class $modify(LevelSearchLayer) {
|
||||
struct LevelSearchLayerIDs : Modify<LevelSearchLayerIDs, LevelSearchLayer> {
|
||||
bool init() {
|
||||
if (!LevelSearchLayer::init())
|
||||
return false;
|
||||
|
@ -99,4 +100,5 @@ class $modify(LevelSearchLayer) {
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
|
|
@ -3,26 +3,23 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// clang-format off
|
||||
#include <Geode/modify/LoadingLayer.hpp>
|
||||
class $modify(CustomLoadingLayer, LoadingLayer) {
|
||||
|
||||
struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
|
||||
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<unsigned long>(count)
|
||||
)->getCString(),
|
||||
CCString::createWithFormat("Geode: Loaded %lu mods", static_cast<unsigned long>(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
|
|
@ -64,7 +64,7 @@ static void updateIndexProgress(UpdateStatus status, std::string const& info, ui
|
|||
}
|
||||
|
||||
#include <Geode/modify/MenuLayer.hpp>
|
||||
class $modify(CustomMenuLayer, MenuLayer) {
|
||||
class CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
|
||||
void destructor() {
|
||||
g_geodeButton = nullptr;
|
||||
MenuLayer::~MenuLayer();
|
||||
|
@ -160,4 +160,3 @@ class $modify(CustomMenuLayer, MenuLayer) {
|
|||
ModListLayer::scene();
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// clang-format off
|
||||
#include <Geode/modify/CCTouchDispatcher.hpp>
|
||||
class $modify(CCTouchDispatcher) {
|
||||
void addTargetedDelegate(CCTouchDelegate *delegate, int priority, bool swallowsTouches) {
|
||||
|
||||
struct ForcePrioRevert : Modify<ForcePrioRevert, CCTouchDispatcher> {
|
||||
void addTargetedDelegate(CCTouchDelegate* delegate, int priority, bool swallowsTouches) {
|
||||
m_bForcePrio = false;
|
||||
if (m_pTargetedHandlers->count() > 0) {
|
||||
auto handler = static_cast<CCTouchHandler*>(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
|
||||
|
|
|
@ -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 <Geode/DefaultInclude.hpp>
|
||||
|
||||
#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<CCUtility##HandlerFix, CCUtility##Handler> { \
|
||||
void destructor() { \
|
||||
if (m_pDelegate) { \
|
||||
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate); \
|
||||
|
@ -55,7 +53,7 @@ HandlerFixFor(CCKeyboard);
|
|||
HandlerFixFor(CCMouse);
|
||||
|
||||
#include <Geode/modify/CCTargetedTouchHandler.hpp>
|
||||
class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) {
|
||||
struct CCTargetedTouchHandlerFix : Modify<CCTargetedTouchHandlerFix, CCTargetedTouchHandler> {
|
||||
void destructor() {
|
||||
if (m_pDelegate) {
|
||||
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate);
|
||||
|
@ -101,7 +99,7 @@ class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) {
|
|||
};
|
||||
|
||||
#include <Geode/modify/CCStandardTouchHandler.hpp>
|
||||
class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) {
|
||||
struct CCStandardTouchHandlerFix : Modify<CCStandardTouchHandlerFix, CCStandardTouchHandler> {
|
||||
void destructor() {
|
||||
if (m_pDelegate) {
|
||||
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate);
|
||||
|
@ -140,6 +138,7 @@ class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) {
|
|||
return pHandler;
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// clang-format off
|
||||
#include <Geode/modify/AchievementNotifier.hpp>
|
||||
class $modify(AchievementNotifier) {
|
||||
|
||||
struct SceneSwitch : Modify<SceneSwitch, AchievementNotifier> {
|
||||
void willSwitchToScene(CCScene* scene) {
|
||||
AchievementNotifier::willSwitchToScene(scene);
|
||||
SceneManager::get()->willSwitchToScene(scene);
|
||||
}
|
||||
};
|
||||
// clang-format on
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// clang-format off
|
||||
#include <Geode/modify/AppDelegate.hpp>
|
||||
class $modify(AppDelegate) {
|
||||
|
||||
struct SaveLoader : Modify<SaveLoader, AppDelegate> {
|
||||
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
|
||||
};
|
|
@ -1,12 +1,12 @@
|
|||
#include <InternalLoader.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
// clang-format off
|
||||
|
||||
#include <Geode/modify/CCScheduler.hpp>
|
||||
class $modify(CCScheduler) {
|
||||
|
||||
struct FunctionQueue : Modify<FunctionQueue, CCScheduler> {
|
||||
void update(float dt) {
|
||||
InternalLoader::get()->executeGDThreadQueue();
|
||||
return CCScheduler::update(dt);
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
};
|
|
@ -4,21 +4,12 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
class $modify(GameManager) {
|
||||
void reloadAllStep2() {
|
||||
GameManager::reloadAllStep2();
|
||||
Loader::get()->updateResourcePaths();
|
||||
}
|
||||
struct ResourcesUpdate : Modify<ResourcesUpdate, LoadingLayer> {
|
||||
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
|
|
@ -12,6 +12,7 @@
|
|||
#include <Geode/utils/ranges.hpp>
|
||||
#include <Geode/utils/string.hpp>
|
||||
#include <Geode/utils/vector.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <hash.hpp>
|
||||
#include <thread>
|
||||
|
||||
|
@ -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<std::string>());
|
||||
}
|
||||
// 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<std::string>();
|
||||
}
|
||||
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;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/utils/fetch.hpp>
|
||||
#include <Geode/utils/file.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <hash.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@ -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<std::string>() == "resources.zip") {
|
||||
auto url = obj.needs("browser_download_url").get<std::string>();
|
||||
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<uint8_t>(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<uint8_t>(now / total * 100.0)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
std::unordered_set<BasicEventHandler*> Event::s_handlers = {};
|
||||
std::unordered_set<EventListenerProtocol*> 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<BasicEventHandler*> const& Event::getHandlers() {
|
||||
return Event::s_handlers;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -126,37 +126,29 @@ Result<ccColor3B> geode::cocos::cc3bFromHexString(std::string const& hexValue) {
|
|||
return Err("Invalid hex value");
|
||||
}
|
||||
switch (hexValue.size()) {
|
||||
case 6:
|
||||
{
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc3(r, g, b));
|
||||
}
|
||||
break;
|
||||
case 6: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc3(r, g, b));
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc3(r, g, b));
|
||||
}
|
||||
break;
|
||||
case 3: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc3(r, g, b));
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc3(num, num, num));
|
||||
}
|
||||
break;
|
||||
case 2: {
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc3(num, num, num));
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
auto num = static_cast<uint8_t>(numValue) * 17;
|
||||
return Ok(ccc3(num, num, num));
|
||||
}
|
||||
break;
|
||||
case 1: {
|
||||
auto num = static_cast<uint8_t>(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<ccColor4B> geode::cocos::cc4bFromHexString(std::string const& hexValue) {
|
|||
return Err("Invalid hex value");
|
||||
}
|
||||
switch (hexValue.size()) {
|
||||
case 8:
|
||||
{
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF000000) >> 24);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF0000) >> 16);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF00) >> 8);
|
||||
auto a = static_cast<uint8_t>((numValue & 0x000000FF));
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
}
|
||||
break;
|
||||
case 8: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF000000) >> 24);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF0000) >> 16);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF00) >> 8);
|
||||
auto a = static_cast<uint8_t>((numValue & 0x000000FF));
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
} break;
|
||||
|
||||
case 6:
|
||||
{
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
}
|
||||
break;
|
||||
case 6: {
|
||||
auto r = static_cast<uint8_t>((numValue & 0xFF0000) >> 16);
|
||||
auto g = static_cast<uint8_t>((numValue & 0x00FF00) >> 8);
|
||||
auto b = static_cast<uint8_t>((numValue & 0x0000FF));
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF000) >> 12) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F00) >> 8) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F0) >> 4) * 17);
|
||||
auto a = static_cast<uint8_t>(((numValue & 0x000F)) * 17);
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
}
|
||||
break;
|
||||
case 4: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF000) >> 12) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F00) >> 8) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F0) >> 4) * 17);
|
||||
auto a = static_cast<uint8_t>(((numValue & 0x000F)) * 17);
|
||||
return Ok(ccc4(r, g, b, a));
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
}
|
||||
break;
|
||||
case 3: {
|
||||
auto r = static_cast<uint8_t>(((numValue & 0xF00) >> 8) * 17);
|
||||
auto g = static_cast<uint8_t>(((numValue & 0x0F0) >> 4) * 17);
|
||||
auto b = static_cast<uint8_t>(((numValue & 0x00F)) * 17);
|
||||
return Ok(ccc4(r, g, b, 255));
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
}
|
||||
break;
|
||||
case 2: {
|
||||
auto num = static_cast<uint8_t>(numValue);
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
auto num = static_cast<uint8_t>(numValue) * 17;
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
}
|
||||
break;
|
||||
case 1: {
|
||||
auto num = static_cast<uint8_t>(numValue) * 17;
|
||||
return Ok(ccc4(num, num, num, 255));
|
||||
} break;
|
||||
|
||||
default: return Err("Invalid hex size, expected 1, 2, 3, 4, 6, or 8");
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ static std::unordered_map<std::string, SentAsyncWebRequestHandle> 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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,31 +3,26 @@
|
|||
USE_GEODE_NAMESPACE();
|
||||
|
||||
#include <Geode/modify/MenuLayer.hpp>
|
||||
class $modify(MenuLayer) {
|
||||
void onMoreGames(CCObject*) {
|
||||
if (Mod::get()->getSettingValue<bool>("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<MyMenuLayer, MenuLayer> {
|
||||
void onMoreGames(CCObject*) {
|
||||
if (Mod::get()->getSettingValue<bool>("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<void(GJGarageLayer*)>("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<void(GJGarageLayer*)>("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;
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 <Geode/modify/GJGarageLayer.hpp>
|
||||
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, GJGarageLayer> {
|
||||
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<void(GJGarageLayer*)>("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<void(GJGarageLayer*)>("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;
|
||||
}());*/
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue