Merge branch 'geode-sdk:main' into altalk

This commit is contained in:
alk 2022-11-28 23:22:49 +03:00 committed by GitHub
commit 079daafd55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
209 changed files with 4649 additions and 3041 deletions

View file

@ -67,13 +67,19 @@ jobs:
echo "${{ github.workspace }}/cli" >> $GITHUB_PATH
- name: Configure CMake
run: |
${{ matrix.config.prefixes }} cmake -B ${{ github.workspace }}/build ${{ matrix.config.extra_flags }} -DGEODE_DISABLE_CLI_CALLS=ON -DCLI_PATH="${{ github.workspace }}/cli"
run: >
${{ matrix.config.prefixes }} cmake -B
${{ github.workspace }}/build
${{ matrix.config.extra_flags }}
-DGEODE_DISABLE_CLI_CALLS=ON
-DCLI_PATH="${{ github.workspace }}/cli"
-D CMAKE_C_COMPILER_LAUNCHER=ccache
-D CMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: |
cd build
cmake --build . --config RelWithDebInfo
cmake --build . --config RelWithDebInfo --parallel
- name: Move to output folder
shell: bash

View file

@ -81,8 +81,8 @@ target_link_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lo
add_definitions(-DFMT_CONSTEVAL=)
add_subdirectory(filesystem)
add_subdirectory(fmt)
add_subdirectory(loader/include/Geode/external/filesystem)
add_subdirectory(loader/include/Geode/external/fmt)
target_link_libraries(${PROJECT_NAME} INTERFACE filesystem fmt)

View file

@ -26,24 +26,24 @@ class cocos2d::CCApplication {
}
class cocos2d::CCArray {
auto addObject(cocos2d::CCObject*) = mac 0x419f90, ios 0x16504c;
// auto addObject(cocos2d::CCObject*) = mac 0x419f90, ios 0x16504c;
auto addObjectNew(cocos2d::CCObject*) = mac 0x41a450;
auto addObjectsFromArray(cocos2d::CCArray*) = mac 0x41a2d0;
auto containsObject(cocos2d::CCObject*) const = mac 0x41a3e0;
auto count() const = mac 0x41a2f0, ios 0x1650e8;
static cocos2d::CCArray* create() = mac 0x419cb0, ios 0x164ec8;
static auto createWithObject(cocos2d::CCObject*) = mac 0x419d50;
auto fastRemoveObject(cocos2d::CCObject*) = mac 0x41a520;
auto fastRemoveObjectAtIndex(unsigned int) = mac 0x41a500;
// auto addObjectsFromArray(cocos2d::CCArray*) = mac 0x41a2d0;
// auto containsObject(cocos2d::CCObject*) const = mac 0x41a3e0;
// auto count() const = mac 0x41a2f0, ios 0x1650e8;
// static cocos2d::CCArray* create() = mac 0x419cb0, ios 0x164ec8;
// static auto createWithObject(cocos2d::CCObject*) = mac 0x419d50;
// auto fastRemoveObject(cocos2d::CCObject*) = mac 0x41a520;
// auto fastRemoveObjectAtIndex(unsigned int) = mac 0x41a500;
auto fastRemoveObjectAtIndexNew(unsigned int) = mac 0x41a510;
auto insertObject(cocos2d::CCObject*, unsigned int) = mac 0x41a460;
auto lastObject() = mac 0x41a360;
auto objectAtIndex(unsigned int) = mac 0x41a340, ios 0x16510c;
auto removeAllObjects() = mac 0x41a4f0, ios 0x1651f0;
auto removeLastObject(bool) = mac 0x41a470;
auto removeObject(cocos2d::CCObject*, bool) = mac 0x41a490;
auto removeObjectAtIndex(unsigned int, bool) = mac 0x41a4b0;
auto stringAtIndex(unsigned int) = mac 0x41a320;
// auto insertObject(cocos2d::CCObject*, unsigned int) = mac 0x41a460;
// auto lastObject() = mac 0x41a360;
// auto objectAtIndex(unsigned int) = mac 0x41a340, ios 0x16510c;
// auto removeAllObjects() = mac 0x41a4f0, ios 0x1651f0;
// auto removeLastObject(bool) = mac 0x41a470;
// auto removeObject(cocos2d::CCObject*, bool) = mac 0x41a490;
// auto removeObjectAtIndex(unsigned int, bool) = mac 0x41a4b0;
// auto stringAtIndex(unsigned int) = mac 0x41a320;
}
class cocos2d::CCBezierTo {

View file

@ -483,6 +483,7 @@ class CCScrollLayerExt : cocos2d::CCLayer {
void moveToTopWithOffset(float) = mac 0x2357d0, win 0x1b420;
CCScrollLayerExt(cocos2d::CCRect rect) = mac 0x235130, win 0x1b020, ios 0x21f05c;
void scrollLayer(float scroll) = mac 0x236490, win 0x1be20;
void updateIndicators(float unknown) = win 0x1b710;
cocos2d::CCTouch* m_touch;
cocos2d::CCPoint m_touchPosition;
@ -1204,7 +1205,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
cocos2d::CCPoint getTouchPoint(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) = win 0x90620;
void onSelectBuildTab(cocos2d::CCObject* sender) = win 0x887f0;
void onCreateButton(cocos2d::CCObject* sender) = win 0x854f0;
CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = win 0x78bf0;
CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = mac 0xb500, win 0x78bf0;
cocos2d::CCPoint offsetForKey(int objID) = win 0x92310;
void updateDeleteMenu() = win 0x7c5d0;
void updateCreateMenu(bool updateTab) = mac 0x1e960, win 0x85530;
@ -1257,6 +1258,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void editColor(cocos2d::CCObject* sender) = mac 0x19190, win 0x8d3c0;
void alignObjects(cocos2d::CCArray* objs, bool alignY) = win 0x8f320;
virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;
void createMoveMenu() = mac 0x275e0, win 0x8c0d0;
EditButtonBar* m_buttonBar;
PAD = mac 0x8, win 0x4;
@ -1514,9 +1516,9 @@ class FLAlertLayer : cocos2d::CCLayerColor {
bool scrollable,
float height
) = mac 0x25e1b0, win 0x228e0;
static FLAlertLayer* create(FLAlertLayerProtocol*, char const*, gd::string, char const*, char const*) = mac 0x25de00, win 0x22680;
static FLAlertLayer* create(FLAlertLayerProtocol*, char const*, gd::string, char const*, char const*, float) = mac 0x25e0e0, win 0x22730, ios 0x1fe374;
static FLAlertLayer* create(FLAlertLayerProtocol*, char const*, gd::string, char const*, char const*, float, bool, float) = mac 0x25dec0, win 0x227e0;
static FLAlertLayer* create(FLAlertLayerProtocol* protocol, char const* title, gd::string content, char const* btn1, char const* btn2) = mac 0x25de00, win 0x22680;
static FLAlertLayer* create(FLAlertLayerProtocol* protocol, char const* title, gd::string content, char const* btn1, char const* btn2, float width) = mac 0x25e0e0, win 0x22730, ios 0x1fe374;
static FLAlertLayer* create(FLAlertLayerProtocol* protocol, char const* title, gd::string content, char const* btn1, char const* btn2, float width, bool scrollable, float height) = mac 0x25dec0, win 0x227e0;
void onBtn1(cocos2d::CCObject*) = mac 0x25ec20, win 0x23340;
void onBtn2(cocos2d::CCObject*) = mac 0x25ec80, win 0x23380;
@ -2025,7 +2027,9 @@ class GJEffectManager : cocos2d::CCNode {
void stopActionsForTrigger(EffectGameObject*) = mac 0x183150;
void stopMoveActionsForGroup(int) = mac 0x1830e0;
void storeTriggeredID(int) = mac 0x185380;
void toggleGroup(int, bool) = mac 0x182c80;
void toggleGroup(int item, bool value) { // mac 0x182c80;
m_groupToggled[item] = value;
}
void traverseInheritanceChain(InheritanceNode*) = mac 0x181850, win 0x11caf0;
void updateActiveOpacityEffects() = mac 0x1847e0;
void updateColorAction(ColorAction*) = mac 0x184560;
@ -2897,7 +2901,9 @@ class GameManager : GManager {
bool m_likedFacebook;
bool m_followedTwitter;
bool m_subbedYoutube;
int m_unknownInt;
// there are 4 bytes too many between m_timeOffset and m_playerFrameRand1
// and i'm guessing it's this one
// int m_unknownInt;
double m_socialsDuration;
bool m_showedAd;
bool m_unknownBool;
@ -3786,7 +3792,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDelegate, RateLevelDelegate, LikeItemDelegate, FLAlertLayerProtocol, LevelDeleteDelegate, NumberInputDelegate, SetIDPopupDelegate {
static LevelInfoLayer* create(GJGameLevel* level) = mac 0x15f290, win 0x175d50;
bool init(GJGameLevel* level) = win 0x175DF0;
bool init(GJGameLevel* level) = win 0x175df0, mac 0x15f520;
void onGarage(cocos2d::CCObject* sender) = win 0x177c10;
void onViewProfile(cocos2d::CCObject* sender) = win 0x17ac90;
void onLevelInfo(cocos2d::CCObject* sender) = win 0x17acf0;
@ -4007,7 +4013,7 @@ class MenuLayer : cocos2d::CCLayer, FLAlertLayerProtocol, GooglePlayDelegate {
void onTwitter(cocos2d::CCObject*) = win 0x191980;
void onYouTube(cocos2d::CCObject*) = win 0x1919A0;
static cocos2d::CCScene* scene(bool) = mac 0x1d12d0, win 0x190720, ios 0x19e57c;
MenuLayer* node() = win 0x190550;
static MenuLayer* node() = win 0x190550;
cocos2d::CCSprite* m_googlePlaySprite;
cocos2d::CCSprite* m_viewProfileInfoText;
@ -5212,18 +5218,22 @@ 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 void onEnter() {
CCLayer::onEnter();
}
virtual void onExit() {
CCLayer::onExit();
}
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;
virtual void ccTouchMoved(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x380be0, ios 0x21e5e8, win 0x31f30;
virtual void ccTouchEnded(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x3809a0, ios 0x21e46c, win 0x31e80;
virtual void ccTouchCancelled(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x380b20, ios 0x21e580, win 0x31ed0;
virtual void registerWithTouchDispatcher() = mac 0x37ff50, ios 0x21dcb4, win 0x12aa0;
virtual void scrollWheel(float, float) = mac 0x380cd0, ios 0x21e6b4, win 0x320a0;
virtual void scrllViewWillBeginDecelerating(CCScrollLayerExt*) {}
virtual void scrollViewDidEndDecelerating(CCScrollLayerExt*) {}
virtual void scrollViewTouchMoving(CCScrollLayerExt*) {}
virtual void scrollViewDidEndMoving(CCScrollLayerExt*) {}
bool m_touchOutOfBoundary;
cocos2d::CCTouch* m_touchStart;
@ -5308,7 +5318,7 @@ class TextArea : cocos2d::CCSprite {
virtual void draw() {}
virtual void setOpacity(unsigned char) = mac 0x19f760, win 0x33800;
bool init(gd::string str, char const* font, float width, float height, cocos2d::CCPoint anchor, float scale, bool disableColor) = mac 0x19ec70, win 0x33370, ios 0x92444;
static TextArea* create(gd::string str, char const* font, float scale, float width, cocos2d::CCPoint anchor, float height, bool disableColor) = mac 0x19eb40, win 0x33270;
static TextArea* create(gd::string str, char const* font, float width, float height, cocos2d::CCPoint anchor, float scale, bool disableColor) = mac 0x19eb40, win 0x33270;
void colorAllCharactersTo(cocos2d::ccColor3B color) = win 0x33830;
void setString(gd::string str) = mac 0x19eda0, win 0x33480;

View file

@ -4,8 +4,8 @@ project(Codegen LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(Broma)
add_subdirectory(../fmt ${CMAKE_CURRENT_BINARY_DIR}/fmt)
add_subdirectory(../filesystem ${CMAKE_CURRENT_BINARY_DIR}/fs)
add_subdirectory(../loader/include/Geode/external/fmt ${CMAKE_CURRENT_BINARY_DIR}/fmt)
add_subdirectory(../loader/include/Geode/external/filesystem ${CMAKE_CURRENT_BINARY_DIR}/fs)
file(GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp

View file

@ -35,6 +35,7 @@ namespace geode::modifier {{
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

View file

@ -1,197 +0,0 @@
# History of Interface Classes
### 1a07998694824abc492eb6b9d98591d0c0dc26e5
This version had the problem that you could only hook a single class inside a mod container, and it only supported virtual functions
Also the first version of the interface / cackit classes
```cpp
class: public $EditorUI {
void undoLastAction() override {
std::cout << "We have " << cac_this->getSelectedObjects()->count() << " objects elected\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
```
### 781465559ec779e295d1b25a511bbe1d277dd702
This version allowed for multiple classes, though the classes still needed to be inside the same source file and between the two macros `CAC_HOOKS` and `END_CAC_HOOKS`
My personal second least favorite
```cpp
CAC_HOOKS
class: public $EditorUI {
void undoLastAction() override {
std::cout << "Undo!\n";
}
} MyEditorUIHook;
END_CAC_HOOKS
```
### e577a57317681332d4974e1e299159c2f6e307af
This version is the first one that utilized the CRTP system, which eventually became the heart of the interface classes
```cpp
CAC_HOOKS
class EditorUIHook: public $EditorUI<EditorUIHook> {
void undoLastAction() override {
std::cout << "Undo!\n";
}
} MyEditorUIHook;
END_CAC_HOOKS
```
### 4c10edc67ac8893136dbc97df30fe04996d69001
This version ditched the the macros that put the hooks inside an anonymous function for a static global variable approach. `APPLY_HOOKS` macro is exactly that.
```cpp
class EditorUIHook: public $EditorUI<EditorUIHook> {
public:
void undoLastAction() override {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
APPLY_HOOKS();
```
### c9f090d539b6b74742f2bab793c4cc88991f981a
This version removed the CRTP system, not needing to get the address of the virtual with the derived
```cpp
class: public $EditorUI {
public:
void undoLastAction() override {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
APPLY_HOOKS();
```
### 37c7ec8df248a02254de6d84daecca444a484384
This version removed the need for the public storage access, for the same reason as above
```cpp
class: public $EditorUI {
void undoLastAction() override {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
APPLY_HOOKS();
```
### de5eee71b18aa50c225a76667861610049c00b21
This version brang back both CRTP system (but this time wrapped inside a macro) and the public access. Now it also supported all types of functions, and not just virtual functions
```cpp
class REDIRECT($EditorUI) {
public:
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
APPLY_HOOKS();
```
### f18c2f73ae1e1cc1662dbcbe54f36e657a699723
This version renamed the macros to the more Geode familiar syntax with the $ prefixes
```cpp
class $redirect(EditorUI) {
public:
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
$apply();
```
### 4027f1e82a1461fad30ef6e51b6dfc1b887479a8
This version ditched redirect for implement because I was dumb and I misinterpreted something and all
IIRC it was related to the constructors
My personal least favorite
```cpp
class $implement(EditorUI, MyEditorUIHook) {
public:
void undoLastAction(CCObject* p0) {
std::cout << "Undo!" << std::endl;
$EditorUI::undoLastAction(p0);
}
} endImplement(MyEditorUIHook);
$apply();
```
### b32b9f0783b9079269685260ca7188d557f9307e
Thankfully this version reverted that while fixing the problem too
```cpp
class $redirect(EditorUI) {
public:
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
$apply();
```
### 7531b2ae915447df8eb9ce825ee7755303396812
This version removed the need for the `$apply` macro
```cpp
class $redirect(EditorUI) {
public:
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
} MyEditorUIHook;
```
### e6ec14774b94f8b5cdc30a246ed48d46674bce95
This version removed the need for both the variable initializer and the public specifier, using some macro stuff
My personal second favorite
```cpp
class $redirect(EditorUI) {
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
};
```
### f361adca95c6e3c07e0fde654fd7c8c1a59d3b2f
This version combined the two macros to create the ultimate macro `$`
My personal favorite
```cpp
class $(EditorUI) {
void undoLastAction() {
std::cout << "Undo!\n";
$EditorUI::undoLastAction();
}
};
```
### de74c1ffa4a3a7f72ac2394fbfb4a1262fbe470b
This version allowed for the creation of fields, which let you effectively add extra fields to classes
You can access them with the special c++ operator ->*
```cpp
class $(EditorUI) {
member_t<int> number_of_undos;
void undoLastAction() {
std::cout << "You have pressed undo " << ++this->*number_of_undos << " times!\n";
$EditorUI::undoLastAction();
}
};
```
### 5f5bead640bc2a52c087f41c49c3354073809f46
This version added the ability to use the `$orig` macro to call the original function, instead of needing to type it out manually.
```cpp
class $(EditorUI) {
void undoLastAction() {
std::cout << "Undo!\n";
$orig();
}
};
```

View file

@ -10,22 +10,21 @@ file(READ resources/about.md LOADER_ABOUT_MD)
configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp)
# Source files
file(GLOB CORE_SOURCES
file(GLOB SOURCES CONFIGURE_DEPENDS
src/cocos2d-ext/*.cpp
src/cocos2d-ext/zip/*.cpp
src/core/*.cpp
src/hooks/*.cpp
src/ids/*.cpp
src/internal/*.cpp
src/internal/windows/*.cpp
src/internal/mac/*.cpp
src/internal/ios/*.cpp
src/platform/mac/*.cpp
src/platform/ios/*.cpp
src/load/*.cpp
src/load/windows/*.cpp
src/load/mac/*.cpp
src/mac/*.cpp
src/main.cpp
src/utils/*.cpp
src/utils/windows/*.cpp
src/utils/zip/*.cpp
src/index/*.cpp
src/ui/nodes/*.cpp
src/ui/internal/*.cpp
@ -36,25 +35,50 @@ file(GLOB CORE_SOURCES
src/ui/internal/settings/*.cpp
)
# Obj-c sources
file(GLOB OBJC_SOURCES
src/internal/ios/*.mm
src/internal/mac/*.mm
src/platform/ios/*.mm
src/platform/mac/*.mm
src/load/ios/*.mm
src/load/mac/*.mm
src/utils/ios/*.mm
src/utils/mac/*.mm
)
set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
# Add platform sources
if (WIN32)
file(GLOB WIN_SOURCES CONFIGURE_DEPENDS
src/platform/windows/*.cpp
)
list(APPEND SOURCES ${WIN_SOURCES})
elseif(IOS)
file(GLOB IOS_SOURCES CONFIGURE_DEPENDS
src/platform/ios/*.cpp
)
list(APPEND SOURCES ${IOS_SOURCES})
list(APPEND SOURCES ${OBJC_SOURCES})
elseif(APPLE)
file(GLOB MAC_SOURCES CONFIGURE_DEPENDS
src/platform/mac/*.cpp
)
list(APPEND SOURCES ${MAC_SOURCES})
list(APPEND SOURCES ${OBJC_SOURCES})
endif()
# Embed version info in binary
if (WIN32)
configure_file(src/internal/windows/info.rc.in info.rc)
set(CORE_SOURCES ${CORE_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/info.rc)
configure_file(src/platform/windows/info.rc.in info.rc)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/info.rc)
endif()
add_library(${PROJECT_NAME} SHARED
${CORE_SOURCES}
${OBJC_SOURCES}
)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
make_directory("${GEODE_BIN_PATH}/nightly")
@ -113,7 +137,6 @@ add_subdirectory(lilac)
target_link_libraries(${PROJECT_NAME} z lilac_hook geode-sdk)
# Use precompiled headers for faster builds
set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
target_precompile_headers(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/DefaultInclude.hpp"
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Utils.hpp"

View file

@ -1 +0,0 @@
#include "loader/cgeode.h"

View file

@ -1,15 +1,19 @@
#pragma once
#include "ui/BasedButton.hpp"
#include "ui/ColorPickPopup.hpp"
#include "ui/EnterLayerEvent.hpp"
#include "ui/BasedButtonSprite.hpp"
#include "ui/IconButtonSprite.hpp"
#include "ui/InputNode.hpp"
#include "ui/LayerBG.hpp"
#include "ui/ListView.hpp"
#include "ui/MDPopup.hpp"
#include "ui/MDTextArea.hpp"
#include "ui/Notification.hpp"
#include "ui/Popup.hpp"
#include "ui/SceneManager.hpp"
#include "ui/ScrollLayer.hpp"
#include "ui/SelectList.hpp"
#include "ui/Scrollbar.hpp"
#include "ui/TextRenderer.hpp"

View file

@ -1,17 +1,12 @@
#pragma once
#include "utils/Ref.hpp"
#include "DefaultInclude.hpp"
#include "utils/Result.hpp"
#include "utils/VersionInfo.hpp"
#include "utils/casts.hpp"
#include "utils/cocos.hpp"
#include "utils/convert.hpp"
#include "utils/ext.hpp"
#include "utils/map.hpp"
#include "utils/string.hpp"
#include "utils/file.hpp"
#include "utils/general.hpp"
#include "utils/json.hpp"
#include "utils/operators.hpp"
#include "utils/platform.hpp"
#include "utils/timer.hpp"
#include "utils/types.hpp"
#include <Geode/DefaultInclude.hpp>

View file

@ -330,6 +330,14 @@ namespace gd {
m_capacity_end = m_start + input.size();
std::copy(input.begin(), input.end(), tmp);
}
void clear() {
delete[] m_start;
auto tmp = new T[0];
m_start = tmp;
m_finish = m_start;
m_capacity_end = m_start;
}
T& front() {
return *m_start;
@ -448,12 +456,12 @@ namespace gd {
}
}
operator std::vector<bool>() {
std::vector<bool> out;
for (auto i = m_start; i != m_end; ++i) {
out.push_back(*i);
}
return out;
vector(vector<bool> const& lol) : vector(std::vector<bool>(lol)) {}
vector() : vector(std::vector<bool>()) {}
~vector() {
delete[] m_start.m_bitptr;
}
operator std::vector<bool>() const {
@ -464,12 +472,14 @@ namespace gd {
return out;
}
vector(vector<bool> const& lol) : vector(std::vector<bool>(lol)) {}
_bit_reference operator[](size_t index) {
const auto real_index = index / sizeof(uintptr_t);
const auto offset = index % sizeof(uintptr_t);
return _bit_reference(&m_start.m_bitptr[real_index], 1UL << offset);
}
vector() : vector(std::vector<bool>()) {}
~vector() {
delete[] m_start.m_bitptr;
bool operator[](size_t index) const {
return const_cast<vector&>(*this)[index];
}
};
};

View file

@ -37,6 +37,8 @@
#include "../kazmath/include/kazmath/kazmath.h"
#include "../script_support/CCScriptSupport.h"
#include "../include/CCProtocols.h"
#include "Layout.hpp"
#include <any>
NS_CC_BEGIN
@ -847,6 +849,7 @@ public:
friend class geode::modifier::FieldContainer;
geode::modifier::FieldContainer* getFieldContainer();
std::optional<std::any> getAttributeInternal(std::string const& attribute);
public:
/**
@ -858,7 +861,8 @@ public:
* Set the string ID of this node. String IDs are a Geode addition
* that are much safer to use to get nodes than absolute indexes
* @param id The ID of the node, recommended to be in kebab case
* without any spaces or uppercase letters
* without any spaces or uppercase letters. If the node is added
* by a mod, use the _spr literal to append the mod ID to it
*/
void setID(std::string const& id);
@ -875,6 +879,28 @@ public:
* @returns The child, or nullptr if none was found
*/
CCNode* getChildByIDRecursive(std::string const& id);
void setAttribute(std::string const& attribute, std::any value);
template<class T>
std::optional<T> getAttribute(std::string const& attribute) {
if (auto value = this->getAttributeInternal(attribute)) {
try {
return std::any_cast<T>(value.value());
} catch(...) {
return std::nullopt;
}
}
return std::nullopt;
}
void setLayout(Layout* layout, bool apply = true);
Layout* getLayout();
void updateLayout();
void setPositionHint(PositionHint hint);
PositionHint getPositionHint();
void swapChildIndices(CCNode* first, CCNode* second);
);
/// @{

View file

@ -0,0 +1,153 @@
#pragma once
#include "../include/ccMacros.h"
#include "../cocoa/CCAffineTransform.h"
#include "../cocoa/CCArray.h"
#include <Geode/platform/platform.hpp>
#include <optional>
#include <unordered_map>
NS_CC_BEGIN
class CCNode;
/**
* Layouts automatically handle the positioning of nodes. Use CCNode::setLayout
* to apply a layout to a node, and then use CCNode::updateLayout to apply
* the layout's positioning. Geode comes with a few default layouts like
* RowLayout, ColumnLayout, and GridLayout, but if you need a different kind
* of layout you can inherit from the Layout class.
*/
class Layout {
public:
/**
* Automatically apply the layout's positioning on a set of nodes
* @param nodes Nodes to position
* @param availableSize Give hints to the layout about how much space is
* available. Note that the layout may still overflow
*/
virtual void apply(CCArray* nodes, CCSize const& availableSize) = 0;
};
/**
* Determines how a node should be positioned within its parent, if that
* parent has an automatically positioning layout
*/
enum class PositionHint {
// The container can determine the best position
// for this node
Default,
// The container's layout should not affect the
// position of this node
Absolute,
};
/**
* Specifies the alignment of something
*/
enum class Alignment {
Begin,
Center,
End,
};
/**
* Simple layout for arranging nodes in a row (horizontal line)
*/
class GEODE_DLL RowLayout : public Layout {
protected:
Alignment m_alignment = Alignment::Center;
std::optional<float> m_alignVertically;
float m_gap;
public:
void apply(CCArray* nodes, CCSize const& availableSize) override;
/**
* Create a new RowLayout. Note that this class is not automatically
* managed by default, so you must assign it to a CCNode or manually
* manage the memory yourself.
* @param gap Space between nodes
* @param alignVertically Whether to align the nodes vertically, and if so,
* what Y position to align them at
* @returns Created RowLayout
*/
static RowLayout* create(
float gap = 5.f,
std::optional<float> alignVertically = std::nullopt
);
RowLayout* setAlignment(Alignment align);
RowLayout* setGap(float gap);
RowLayout* setAlignVertically(std::optional<float> align);
};
/**
* Simple layout for arranging nodes in a column (vertical line)
*/
class GEODE_DLL ColumnLayout : public Layout {
protected:
Alignment m_alignment = Alignment::Center;
std::optional<float> m_alignHorizontally;
float m_gap;
public:
void apply(CCArray* nodes, CCSize const& availableSize) override;
static ColumnLayout* create(
float gap = 5.f,
std::optional<float> alignHorizontally = std::nullopt
);
ColumnLayout* setAlignment(Alignment align);
ColumnLayout* setGap(float gap);
ColumnLayout* setAlignHorizontally(std::optional<float> align);
};
/**
* Grid direction; which direction the grid should add its next row to if the
* current row is full
*/
enum class GridDirection {
// Downward
Column,
// Upward
ReverseColumn,
// Right
Row,
// Left
ReverseRow,
};
/**
* Grid alignment; same as normal Alignment but also features the "Stretch"
* option which will stretch the row out to be the same size as the others
*/
enum class GridAlignment {
Begin,
Center,
Stretch,
End,
};
class GEODE_DLL GridLayout : public Layout {
protected:
GridDirection m_direction = GridDirection::Column;
GridAlignment m_alignment = GridAlignment::Center;
std::optional<size_t> m_rowSize;
public:
void apply(CCArray* nodes, CCSize const& availableSize) override;
static GridLayout* create(
std::optional<size_t> rowSize,
GridAlignment alignment = GridAlignment::Center,
GridDirection direction = GridDirection::Column
);
GridLayout* setDirection(GridDirection direction);
GridLayout* setAlignment(GridAlignment alignment);
GridLayout* setRowSize(std::optional<size_t> rowSize);
};
NS_CC_END

View file

@ -152,6 +152,9 @@ public:
* @js getInstance
*/
static CCSpriteFrameCache* sharedSpriteFrameCache(void);
GEODE_ADD(
static CCSpriteFrameCache* get();
);
/** Purges the cache. It releases all the Sprite Frames and the retained instance. */
static void purgeSharedSpriteFrameCache(void);

View file

@ -91,6 +91,9 @@ public:
* @js getInstance
*/
static CCTextureCache * sharedTextureCache();
GEODE_ADD(
static CCTextureCache* get();
);
/** purges the cache. It releases the retained instance.
@since v0.99.0

View file

@ -47,7 +47,7 @@ namespace geode::core {
inline Result<> remove(HookHandle const& handle) {
impl::removeHook(handle);
return Ok<>();
return Ok();
}
}
}

View file

@ -19,6 +19,7 @@ namespace geode {
virtual void enable();
virtual void disable();
virtual ListenerResult passThrough(Event*) = 0;
virtual ~EventListenerProtocol();
};
template <typename C, typename T>
@ -64,12 +65,20 @@ namespace geode {
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) {}
EventListener(T filter = T()) {
this->enable();
}
EventListener(std::function<Callback> fn, T filter = T()) : m_callback(fn), m_filter(filter) {
this->enable();
}
EventListener(Callback* fnptr, T filter = T()) : m_callback(fnptr), m_filter(filter) {
this->enable();
}
template <class C>
EventListener(C* cls, MemberFn<C> fn, T filter = T()) : EventListener(std::bind(fn, cls, std::placeholders::_1), filter) {}
EventListener(C* cls, MemberFn<C> fn, T filter = T()) : EventListener(std::bind(fn, cls, std::placeholders::_1), filter) {
this->enable();
}
void bind(std::function<Callback> fn) {
m_callback = fn;

View file

@ -1,8 +1,9 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include <Geode/hook-core/Hook.hpp>
#include <Geode/utils/types.hpp>
#include "../DefaultInclude.hpp"
#include "../hook-core/Hook.hpp"
#include "../utils/general.hpp"
#include "../external/json/json.hpp"
#include <inttypes.h>
#include <string_view>
@ -77,6 +78,12 @@ namespace geode {
Mod* getOwner() const {
return m_owner;
}
/**
* Get info about the hook as JSON
* @note For IPC
*/
nlohmann::json getRuntimeInfo() const;
};
class GEODE_DLL Patch {
@ -128,5 +135,11 @@ namespace geode {
Mod* getOwner() const {
return m_owner;
}
/**
* Get info about the patch as JSON
* @note For IPC
*/
nlohmann::json getRuntimeInfo() const;
};
}

View file

@ -0,0 +1,90 @@
#pragma once
#include "Event.hpp"
#include "Loader.hpp"
namespace geode {
#ifdef GEODE_IS_WINDOWS
constexpr const char* IPC_PIPE_NAME = "\\\\.\\pipe\\GeodeIPCPipe";
#endif
class IPCFilter;
// IPC (Inter-Process Communication) provides a way for Geode mods to talk
// to other programs on the user's computer. If you have, for example, a
// debugger, or an external modding UI, that application can open up the
// platform-specific pipe and start sending messages to mods. Mods can
// listen for messages using the listenForIPC function, and reply to
// messages the get by using the reply method on the event provided. For
// example, an external application can query what mods are loaded in Geode
// by sending the `list-mods` message to `geode.loader`.
class GEODE_DLL IPCEvent : public Event {
protected:
void* m_rawPipeHandle;
std::string m_targetModID;
std::optional<std::string> m_replyID;
std::string m_messageID;
nlohmann::json m_messageData;
bool m_replied = false;
/**
* Reply to the message. Will post a message back to the application
* the sent this message with the reply ID and provided data.
* You can only reply once; after the other application has received
* the reply, it can assume the reply ID can be freed and reused for
* other messages. Calling reply again on this message will not cause
* a new response to be sent.
* If reply is not explicitly called, a default response of null will
* be posted back.
* @param data The data to send back; will be the under the "data" key
* in the response JSON. The structure may be anything; however, you
* should document what kind of JSON structures applications may expect
* from your mod.
*/
void reply(nlohmann::json const& data);
friend class IPCFilter;
public:
IPCEvent(
void* rawPipeHandle,
std::string const& targetModID,
std::string const& messageID,
std::optional<std::string> const& replyID,
nlohmann::json const& messageData
);
virtual ~IPCEvent();
std::optional<std::string> getReplyID() const;
std::string getTargetModID() const;
std::string getMessageID() const;
nlohmann::json getMessageData() const;
};
class GEODE_DLL IPCFilter : public EventFilter<IPCEvent> {
public:
using Callback = nlohmann::json(IPCEvent*);
protected:
std::string m_modID;
std::string m_messageID;
public:
ListenerResult handle(std::function<Callback> fn, IPCEvent* event);
IPCFilter(
std::string const& modID,
std::string const& messageID
);
};
template<class = void>
std::monostate listenForIPC(std::string const& messageID, nlohmann::json(*callback)(IPCEvent*)) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
new EventListener(
callback, IPCFilter(getMod()->getID(), messageID)
);
});
return std::monostate();
}
}

View file

@ -11,7 +11,18 @@
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <fs/filesystem.hpp>
#include "Log.hpp"
#include <mutex>
// for some reason std::filesystem::path doesn't have std::hash defined in C++17
// and ghc seems to have inherited this limitation
template<>
struct std::hash<ghc::filesystem::path> {
std::size_t operator()(ghc::filesystem::path const& path) const noexcept {
return ghc::filesystem::hash_value(path);
}
};
namespace geode {
#pragma warning(disable : 4251)
@ -46,6 +57,7 @@ namespace geode {
class GEODE_DLL Loader {
public:
struct FailedModInfo {
// todo: change to path
std::string m_file;
std::string m_reason;
};
@ -57,6 +69,8 @@ namespace geode {
};
std::unordered_map<std::string, ModSettings> m_mods;
// todo: in v1.0.0, make this a customizable option in mod.json
std::unordered_set<ghc::filesystem::path> m_earlyLoadMods;
};
using ScheduledFunction = std::function<void GEODE_CALL(void)>;
@ -70,7 +84,8 @@ namespace geode {
std::vector<ghc::filesystem::path> m_texturePaths;
LoaderSettings m_loadedSettings;
bool m_isSetup = false;
static bool s_unloading;
static std::atomic_bool s_unloading;
mutable std::mutex m_modLoadMutex;
Result<std::string> createTempDirectoryForMod(ModInfo const& info);
Result<Mod*> loadModFromFile(std::string const& file);
@ -87,8 +102,7 @@ namespace geode {
template <class, class>
friend class modifier::FieldIntermediate;
void updateResourcePaths();
void updateModResources(Mod* mod);
// used internally in geode_implicit_load
@ -110,7 +124,9 @@ namespace geode {
Result<> saveSettings();
Result<> loadSettings();
Result<> saveData();
Result<> loadData();
bool didLastLaunchCrash() const;
ghc::filesystem::path getCrashLogDirectory() const;
@ -180,12 +196,17 @@ namespace geode {
void clearLogs();
/**
* Do not call manually unless you know what you're doing.
*/
void updateResourcePaths();
/**
* Do not call manually unless you know what you're doing.
*/
void updateResources();
void addTexturePath(ghc::filesystem::path const& path);
void removeTexturePath(ghc::filesystem::path const& path);
std::vector<ghc::filesystem::path> getTexturePaths() const;
/**
* Check if a mod with an ID is installed. Any
@ -267,5 +288,9 @@ namespace geode {
* Close the platform-specific external console (if one exists)
*/
static void closePlatfromConsole();
void waitForModsToBeLoaded();
void setEarlyLoadMod(Mod* mod, bool enabled);
bool shouldEarlyLoadMod(Mod* mod) const;
};
}

View file

@ -4,11 +4,12 @@
#include "Setting.hpp"
#include "Types.hpp"
#include <Geode/DefaultInclude.hpp>
#include <Geode/utils/Result.hpp>
#include <Geode/utils/VersionInfo.hpp>
#include <Geode/utils/json.hpp>
#include <Geode/utils/types.hpp>
#include "../DefaultInclude.hpp"
#include "../utils/Result.hpp"
#include "../utils/VersionInfo.hpp"
#include "../external/json/json.hpp"
#include "../utils/general.hpp"
#include "../cocos/support/zip_support/ZipUtils.h"
#include <optional>
#include <string_view>
#include <type_traits>
@ -143,10 +144,6 @@ namespace geode {
* Mod spritesheet names
*/
std::vector<std::string> m_spritesheets;
/**
* Default data store values
*/
nlohmann::json m_defaultDataStore;
/**
* Mod settings
*/
@ -172,7 +169,19 @@ namespace geode {
*/
static Result<ModInfo> create(ModJson const& json);
/**
* Convert to JSON. Essentially same as getRawJSON except dynamically
* adds runtime fields like path
*/
ModJson toJSON() const;
/**
* Get the raw JSON file
*/
ModJson getRawJSON() const;
private:
ModJson m_rawJSON;
/**
* Version is passed for backwards
* compatibility if we update the mod.json
@ -186,27 +195,21 @@ namespace geode {
std::vector<std::pair<std::string, std::optional<std::string>*>> getSpecialFiles();
};
/**
* @class DataStore
* Internal class for notifying Mod
* when the datastore changes
*/
class GEODE_DLL DataStore {
nlohmann::json m_store;
// For converting ModInfo back to JSON
void GEODE_DLL to_json(nlohmann::json& json, ModInfo const& info);
template<class T>
struct HandleToSaved : public T {
Mod* m_mod;
std::string m_key;
DataStore(Mod* m, nlohmann::json& j) : m_mod(m), m_store(j) {}
friend class Mod;
public:
~DataStore();
nlohmann::json& getJson() const;
nlohmann::json& operator[](std::string const&);
DataStore& operator=(nlohmann::json&);
bool contains(std::string const&) const;
operator nlohmann::json();
HandleToSaved(std::string const& key, Mod* mod, T const& value)
: T(value),
m_key(key),
m_mod(mod) {}
HandleToSaved(HandleToSaved const&) = delete;
HandleToSaved(HandleToSaved&&) = delete;
~HandleToSaved();
};
/**
@ -293,9 +296,9 @@ namespace geode {
std::string m_loadErrorInfo = "";
/**
* Data Store object
* Saved values
*/
nlohmann::json m_dataStore;
nlohmann::json m_saved;
/**
* Load the platform binary
@ -306,8 +309,6 @@ namespace geode {
Result<> saveSettings();
Result<> loadSettings();
void postDSUpdate();
Result<> createTempDir();
static bool validateID(std::string const& id);
@ -326,7 +327,6 @@ namespace geode {
friend class Loader;
friend class ::InternalLoader;
friend struct ModInfo;
friend class DataStore;
template <class = void>
static inline GEODE_HIDDEN Mod* sharedMod = nullptr;
@ -357,6 +357,10 @@ namespace geode {
ModInfo getModInfo() const;
ghc::filesystem::path getTempDir() const;
ghc::filesystem::path getBinaryPath() const;
Result<> saveData();
Result<> loadData();
/**
* Get the mod's save directory path
*/
@ -364,7 +368,7 @@ namespace geode {
/**
* Get the mod's config directory path
*/
ghc::filesystem::path getConfigDir() const;
ghc::filesystem::path getConfigDir(bool create = true) const;
bool hasSettings() const;
decltype(ModInfo::m_settings) getSettings() const;
@ -388,6 +392,50 @@ namespace geode {
return false;
}
template<class T>
T getSavedValue(std::string const& key) {
if (m_saved.count(key)) {
try {
// json -> T may fail
return m_saved.at(key);
} catch(...) {}
}
return T();
}
template<class T>
T getSavedValue(std::string const& key, T const& defaultValue) {
if (m_saved.count(key)) {
try {
// json -> T may fail
return m_saved.at(key);
} catch(...) {}
}
m_saved[key] = defaultValue;
return defaultValue;
}
template<class T>
HandleToSaved<T> getSavedMutable(std::string const& key) {
return HandleToSaved(key, this, this->getSavedValue<T>(key));
}
template<class T>
HandleToSaved<T> getSavedMutable(std::string const& key, T const& defaultValue) {
return HandleToSaved(key, this, this->getSavedValue<T>(key, defaultValue));
}
/**
* Set the value of an automatically saved variable. When the game is
* closed, the value is automatically saved under the key
* @param key Key of the saved value
* @param value Value
*/
template<class T>
void setSavedValue(std::string const& key, T const& value) {
m_saved[key] = value;
}
/**
* Get the mod container stored in the Interface
* @returns nullptr if Interface is not initialized,
@ -517,19 +565,6 @@ namespace geode {
Result<> uninstall();
bool isUninstalled() const;
/**
* Return the data store object
* @returns DataStore object
* store
*/
DataStore getDataStore();
/**
* Reset the data store to the
* default value
*/
Result<> resetDataStore();
/**
* Check whether or not this Mod
* depends on another mod
@ -562,8 +597,19 @@ namespace geode {
std::vector<Dependency> getUnresolvedDependencies();
char const* expandSpriteName(char const* name);
/**
* Get info about the mod as JSON
* @note For IPC
*/
ModJson getRuntimeInfo() const;
};
template<class T>
HandleToSaved<T>::~HandleToSaved() {
m_mod->setSavedValue(m_key, static_cast<T>(*this));
}
/**
* To bypass the need for cyclic dependencies,
* this function does the exact same as Mod::get()
@ -578,3 +624,6 @@ namespace geode {
inline char const* operator"" _spr(char const* str, size_t) {
return geode::Mod::get()->expandSpriteName(str);
}
// this header uses Mod
#include "ModEvent.hpp"

View file

@ -0,0 +1,57 @@
#pragma once
#include "Event.hpp"
#include <optional>
#include "Mod.hpp"
namespace geode {
enum class ModEventType {
Loaded,
Unloaded,
Enabled,
Disabled,
DataLoaded,
DataSaved,
};
class GEODE_DLL ModStateEvent : public Event {
protected:
ModEventType m_type;
Mod* m_mod;
public:
ModStateEvent(Mod* mod, ModEventType type);
ModEventType getType() const;
Mod* getMod() const;
};
class GEODE_DLL ModStateFilter : public EventFilter<ModStateEvent> {
public:
using Callback = void(ModStateEvent*);
protected:
ModEventType m_type;
Mod* m_mod;
public:
ListenerResult handle(std::function<Callback> fn, ModStateEvent* event);
ModStateFilter(Mod* mod, ModEventType type);
};
}
#define $on_mod(type) \
template<class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(ModStateEvent*); \
namespace { \
struct GEODE_CONCAT(ExecFuncUnique, __LINE__) {}; \
} \
static inline auto GEODE_CONCAT(Exec, __LINE__) = (geode::Loader::get()->scheduleOnModLoad(\
geode::Mod::get(), []() { \
static auto _ = geode::EventListener( \
&GEODE_CONCAT(geodeExecFunction, __LINE__)<GEODE_CONCAT(ExecFuncUnique, __LINE__)>,\
geode::ModStateFilter(geode::Mod::get(), geode::ModEventType::type)\
); \
} \
), 0); \
template<class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(ModStateEvent*)

View file

@ -1,13 +1,12 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include <Geode/utils/JsonValidation.hpp>
#include <Geode/utils/Result.hpp>
#include <Geode/utils/container.hpp>
#include <Geode/utils/convert.hpp>
#include <Geode/utils/json.hpp>
#include <Geode/utils/platform.hpp>
#include <Geode/utils/ranges.hpp>
#include "../DefaultInclude.hpp"
#include "../utils/JsonValidation.hpp"
#include "../utils/Result.hpp"
#include "../external/json/json.hpp"
#include "../utils/file.hpp"
#include "../utils/ranges.hpp"
#include "../utils/cocos.hpp"
#include <optional>
#include <regex>
#include <unordered_set>
@ -81,7 +80,7 @@ namespace geode {
#define GEODE_INT_PARSE_SETTING_IMPL(obj, func, ...) \
if constexpr (std::is_base_of_v<__VA_ARGS__, Class>) { \
auto r = std::static_pointer_cast<Class>(res)->func(obj); \
if (!r) return Err(r.error()); \
if (!r) return Err(r.unwrapErr()); \
}
#define GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(func, ...) \

View file

@ -52,19 +52,23 @@ namespace geode {
};
template <class T>
requires std::is_base_of_v<Setting, T> std::monostate listenForSettingChanges(
requires std::is_base_of_v<Setting, T>
std::monostate listenForSettingChanges(
std::string const& settingID, void (*callback)(T*)
) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
static auto _ = EventListener(callback, SettingChangedFilter<T>(getMod()->getID(), settingID));
new EventListener(
callback, SettingChangedFilter<T>(getMod()->getID(), settingID)
);
});
return std::monostate();
}
static std::monostate listenForAllSettingChanges(void (*callback)(Setting*)) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
static auto _ = EventListener(callback, SettingChangedFilter(getMod()->getID()));
new EventListener(
callback, SettingChangedFilter(getMod()->getID())
);
});
return std::monostate();
}

View file

@ -148,18 +148,22 @@ namespace geode {
Disabled,
};
/**
* Default Geode load method for C++
* mods: The mod receive a pointer to
* its allocated Mod instance. Return
* true on a succesful load,
* return false on error.
*/
typedef bool(GEODE_CALL* geode_load)(Mod*);
typedef void(GEODE_CALL* geode_unload)();
typedef bool(GEODE_CALL* geode_enable)();
typedef bool(GEODE_CALL* geode_disable)();
typedef bool(GEODE_CALL* geode_save_data)(char const*);
typedef bool(GEODE_CALL* geode_load_data)(char const*);
typedef void(GEODE_CALL* geode_setting_updated)(char const*, Setting*);
/**
* These methods will be removed in v1.0.0 and replaced with events
*/
/**
* Default Geode load method for C++
* mods: The mod receive a pointer to
* its allocated Mod instance. Return
* true on a succesful load,
* return false on error.
*/
typedef bool(GEODE_CALL* geode_load)(Mod*);
typedef void(GEODE_CALL* geode_unload)();
typedef bool(GEODE_CALL* geode_enable)();
typedef bool(GEODE_CALL* geode_disable)();
typedef bool(GEODE_CALL* geode_save_data)(const char*);
typedef bool(GEODE_CALL* geode_load_data)(const char*);
typedef void(GEODE_CALL* geode_setting_updated)(const char*, Setting*);
}

View file

@ -1,19 +0,0 @@
#pragma once
#include <Geode/platform/cplatform.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void GEODE_C_DLL geode_mod_log(void* mod, char const* message);
bool GEODE_C_DLL geode_mod_add_hook(void* mod, void* address, void* detour);
bool GEODE_C_DLL geode_get_last_error(char* buffer, size_t bufferSize);
#ifdef __cplusplus
}
#endif

View file

@ -1,9 +0,0 @@
#pragma once
namespace geode {
using dylib_t = void*;
struct PlatformInfo {
dylib_t m_dylib;
};
}

View file

@ -0,0 +1,70 @@
#pragma once
#include "../DefaultInclude.hpp"
#include "../ui/EnterLayerEvent.hpp"
namespace cocos2d {
class CCNode;
}
namespace geode {
template<class T>
concept IDProvidable = std::is_base_of_v<cocos2d::CCNode, T> && requires {
{ T::CLASS_NAME } -> std::convertible_to<const char*>;
};
class GEODE_DLL NodeIDs {
public:
template<class T>
using Provider = void(GEODE_CALL*)(T*);
protected:
std::unordered_map<std::string, Provider<cocos2d::CCNode>> m_providers;
public:
static NodeIDs* get();
template<IDProvidable T>
void registerProvider(void(GEODE_CALL* fun)(T*)) {
m_providers.insert({
T::CLASS_NAME,
reinterpret_cast<Provider<cocos2d::CCNode>>(fun)
});
}
template<IDProvidable T>
bool provide(T* layer) const {
if (m_providers.count(T::CLASS_NAME)) {
m_providers.at(T::CLASS_NAME)(layer);
return true;
}
return false;
}
// @note Because NodeIDs::provideFor(this) looks really neat
template<IDProvidable T>
static bool provideFor(T* layer) {
return NodeIDs::get()->provide(layer);
}
};
template<IDProvidable For>
void GEODE_CALL geodeInternalProvideIDsFor(For* cls) {
if (cls->getID() != For::CLASS_NAME) {
cls->setID(For::CLASS_NAME);
cls->provide();
EnterLayerEvent(For::CLASS_NAME, cls).post();
}
}
}
#define $register_ids(Layer_) \
struct GEODE_CONCAT(ProvideIDsFor, Layer_) : public Layer_ {\
void provide();\
};\
$execute {\
NodeIDs::get()->registerProvider(\
&geodeInternalProvideIDsFor<GEODE_CONCAT(ProvideIDsFor, Layer_)>\
);\
};\
void GEODE_CONCAT(ProvideIDsFor, Layer_)::provide()

View file

@ -56,16 +56,20 @@
*/
#define $cls std::remove_pointer<decltype(this)>::type
#define GEODE_EXECUTE_FUNC(Line_) \
template <class> \
void _##Line_##Function(); \
namespace { \
struct _##Line_##Unique {}; \
} \
static inline auto _line = \
(Loader::get()->scheduleOnModLoad(nullptr, &_##Line_##Function<_##Line_##Unique>), 0); \
template <class> \
void _##Line_##Function()
#define GEODE_ONLY_FIELD(type, field_, default_) private: field<type> field_ = default_; public:
#define GEODE_INTERNAL_FIELD(type, field, name) inline type& name() { return this->*field; }
//#define GEODE_EXTERNAL_FIELD(type, field, name) static inline type& name##From(void* self) { return reinterpret_cast<decltype(this)>(self)->*field; }
#define GEODE_FIELD(type, field, name, default_) GEODE_ONLY_FIELD(type, field, default_) GEODE_INTERNAL_FIELD(type, field, name) //GEODE_EXTERNAL_FIELD(type, field, name)
#define GEODE_EXECUTE_FUNC1(Line_) GEODE_EXECUTE_FUNC(Line_)
#define $execute GEODE_EXECUTE_FUNC1(__LINE__)
#define $execute \
template<class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(); \
namespace { \
struct GEODE_CONCAT(ExecFuncUnique, __LINE__) {}; \
} \
static inline auto GEODE_CONCAT(Exec, __LINE__) = (Loader::get()->scheduleOnModLoad(\
nullptr, &GEODE_CONCAT(geodeExecFunction, __LINE__)<GEODE_CONCAT(ExecFuncUnique, __LINE__)> \
), 0); \
template<class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)()

View file

@ -8,6 +8,7 @@
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Mod.hpp>
#include <iostream>
#include "IDManager.hpp"
#define GEODE_APPLY_MODIFY_FOR_FUNCTION( \
addr_index, pure_index, convention, className, functionName \

View file

@ -1,8 +1,5 @@
#pragma once
#define GEODE_C_DLL
#define GEODE_C_API
#ifdef _MSC_VER
#pragma warning(disable : 4099) // type first seen as class
#pragma warning(default : 4067)
@ -20,16 +17,6 @@
#define GEODE_CALL __stdcall
#define GEODE_PLATFORM_EXTENSION ".dll"
#define GEODE_PLATFORM_SHORT_IDENTIFIER "win"
#ifdef GEODE_EXPORTING
#undef GEODE_C_DLL
#define GEODE_C_DLL __declspec(dllexport)
#else
#undef GEODE_C_DLL
#define GEODE_C_DLL __declspec(dllimport)
#endif
#undef GEODE_C_API
#define GEODE_C_API __declspec(dllexport) __stdcall
#else
#define GEODE_WINDOWS(...)
#endif

View file

@ -1,3 +1,6 @@
#pragma once
#include "Popup.hpp"
#include "InputNode.hpp"
#include "Popup.hpp"

View file

@ -0,0 +1,47 @@
#pragma once
#include "../DefaultInclude.hpp"
#include "../loader/Mod.hpp"
#include <cocos2d.h>
namespace geode {
// Credit to https://github.com/Ikszyon/UI-Recolor for many of these addresses!
/**
* Hardcoded GD colors
*/
enum class GDColor {
NormalModeProgressBar,
PracticeModeProgressBar,
ProfilePostBG,
};
class GEODE_DLL ColorManager {
protected:
struct Value {
cocos2d::ccColor3B value;
Mod* setter;
};
std::unordered_map<GDColor, std::vector<Value>> m_colors;
ColorManager();
public:
static ColorManager* get();
cocos2d::ccColor3B getColor(GDColor color) const;
void setColor(GDColor color, Mod* setter, cocos2d::ccColor3B const& value);
void resetColor(GDColor color, Mod* setter);
template<class = void>
void setColor(GDColor color, cocos2d::ccColor3B const& value) {
this->setColor(color, Mod::get(), value);
}
template<class = void>
void resetColor(GDColor color) {
this->resetColor(color, Mod::get());
}
};
}

View file

@ -0,0 +1,80 @@
#pragma once
#include "../loader/Event.hpp"
namespace cocos2d {
class CCNode;
}
namespace geode {
template<class T>
concept InheritsCCNode = std::is_base_of_v<cocos2d::CCNode, T>;
// Base class; exists so event listeners can be placed dynamically at runtime
class GEODE_DLL AEnterLayerEvent : public Event {
protected:
std::string m_layerID;
cocos2d::CCNode* m_layer;
public:
AEnterLayerEvent(
std::string const& layerID,
cocos2d::CCNode* layer
);
std::string getID() const;
cocos2d::CCNode* getLayer() const;
};
class GEODE_DLL AEnterLayerFilter : public EventFilter<AEnterLayerEvent> {
public:
using Callback = std::function<void(AEnterLayerEvent*)>;
protected:
std::optional<std::string> m_targetID;
public:
ListenerResult handle(Callback fn, AEnterLayerEvent* event);
AEnterLayerFilter(
std::optional<std::string> const& id
);
};
template<InheritsCCNode T>
class EnterLayerEvent : public AEnterLayerEvent {
public:
EnterLayerEvent(
std::string const& layerID,
T* layer
) : AEnterLayerEvent(layerID, layer) {}
T* getLayer() const {
return static_cast<T*>(m_layer);
}
};
template<class T, class N>
concept InheritsEnterLayer = std::is_base_of_v<EnterLayerEvent<N>, T>;
template<class N, InheritsEnterLayer<N> T>
class EnterLayerFilter : public EventFilter<EnterLayerEvent<N>> {
public:
using Callback = void(T*);
protected:
std::optional<std::string> m_targetID;
public:
ListenerResult handle(std::function<Callback> fn, EnterLayerEvent<N>* event) {
if (m_targetID == event->getID()) {
fn(static_cast<T*>(event));
}
return ListenerResult::Propagate;
}
EnterLayerFilter(
std::optional<std::string> const& id
) : m_targetID(id) {}
};
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "../utils/Ref.hpp"
#include "../utils/cocos.hpp"
#include "SceneManager.hpp"
#include <chrono>

View file

@ -68,15 +68,16 @@ namespace geode {
}
void setTitle(
char const* title, char const* font = "goldFont.fnt", float scale = .7f,
std::string const& title,
const char* font = "goldFont.fnt",
float scale = .7f,
float offset = 20.f
) {
if (m_title) {
m_title->setString(title);
}
else {
m_title->setString(title.c_str());
} else {
auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize();
m_title = cocos2d::CCLabelBMFont::create(title, font);
m_title = cocos2d::CCLabelBMFont::create(title.c_str(), font);
m_title->setPosition(
winSize.width / 2, winSize.height / 2 + m_size.height / 2 - offset
);

View file

@ -1,7 +1,7 @@
#pragma once
#include "../loader/Log.hpp"
#include "json.hpp"
#include "../external/json/json.hpp"
#include <set>
#include <variant>

View file

@ -1,277 +0,0 @@
#pragma once
#include "../DefaultInclude.hpp"
#include <string>
#include <string_view>
#include <variant>
namespace geode {
namespace {
struct AnyType {
explicit AnyType() = delete;
};
template <class V, class RV>
concept ConvertibleToResult =
std::is_convertible_v<std::remove_reference_t<V>, std::remove_reference_t<RV>> ||
std::is_same_v<std::remove_reference_t<V>, std::remove_reference_t<RV>>;
using DefaultValue = std::monostate;
using DefaultError = std::string;
}
template <class T = DefaultValue, class E = DefaultError>
class [[nodiscard]] NewResult {
public:
using value_type = std::remove_reference_t<T>;
using error_type = std::remove_reference_t<E>;
// for some reason doing requires causes errors with pch...
static_assert(
std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
"T must be copiable or movable!"
);
static_assert(
std::is_copy_constructible_v<error_type> || std::is_move_constructible_v<error_type>,
"E must be copiable or movable!"
);
protected:
std::variant<value_type, error_type> m_value;
public:
bool isOk() const {
return std::holds_alternative<value_type>(m_value);
}
bool isErr() const {
return std::holds_alternative<error_type>(m_value);
}
explicit NewResult(value_type const& value
) requires std::is_copy_constructible_v<value_type> : m_value(value) {}
explicit NewResult(value_type&& value) requires std::is_move_constructible_v<value_type> :
m_value(std::forward<value_type>(value)) {}
explicit NewResult(error_type const& value
) requires std::is_copy_constructible_v<error_type> : m_value(value) {}
explicit NewResult(error_type&& value) requires std::is_move_constructible_v<error_type> :
m_value(std::forward<error_type>(value)) {}
NewResult(NewResult<T, E> const& other) requires std::is_copy_constructible_v<value_type> &&
std::is_copy_constructible_v<error_type>
= default;
NewResult(NewResult<T, E>&& other
) requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) =
default;
template <class T2, class E2>
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> NewResult(
NewResult<T2, E2> const& other
)
requires std::is_copy_constructible_v<value_type> &&
std::is_copy_constructible_v<error_type> :
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
template <class T2, class E2>
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> NewResult(
NewResult<T2, E2>&& other
)
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
template <class T2>
requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType> const& other)
requires std::is_copy_constructible_v<value_type> &&
std::is_copy_constructible_v<error_type> : NewResult(value_type(other.unwrap())) {}
template <class E2>
requires ConvertibleToResult<E2, E> NewResult(NewResult<AnyType, E2> const& other)
requires std::is_copy_constructible_v<value_type> &&
std::is_copy_constructible_v<error_type> :
m_value(std::forward<E2>(other.unwrapErr())) {}
template <class T2>
requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType>&& other)
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
m_value(other.unwrap()) {}
template <class E2>
requires ConvertibleToResult<E2, E> NewResult(NewResult<AnyType, E2>&& other)
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
NewResult(std::forward<error_type>(other.unwrapErr())) {}
value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
return std::get<value_type>(m_value);
}
value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
return std::move(std::get<value_type>(m_value));
}
error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
return std::get<error_type>(m_value);
}
error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
return std::move(std::get<error_type>(m_value));
}
explicit operator bool() const
requires(!std::is_same_v<T, bool> && !std::is_same_v<E, bool>) {
return this->isOk();
}
};
template <class T>
class [[nodiscard]] NewResult<T, T> {
public:
using value_type = std::remove_reference_t<T>;
using error_type = std::remove_reference_t<T>;
// for some reason doing requires causes errors with pch...
static_assert(
std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
"T must be copiable or movable!"
);
protected:
bool m_success;
value_type m_value;
public:
bool isOk() const {
return m_success;
}
bool isErr() const {
return !m_success;
}
explicit NewResult(value_type const& value, bool success) requires
std::is_copy_constructible_v<value_type> :
m_value(value),
m_success(success) {}
explicit NewResult(value_type&& value, bool success) requires
std::is_move_constructible_v<value_type> :
m_value(std::forward<value_type>(value)),
m_success(success) {}
NewResult(NewResult<T, T> const& other) requires std::is_copy_constructible_v<value_type>
= default;
NewResult(NewResult<T, T>&& other
) requires(!std::is_copy_constructible_v<value_type>) = default;
template <class T2, class E2>
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> NewResult(
NewResult<T2, E2> const& other
)
requires std::is_copy_constructible_v<value_type> :
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
m_success(other.isOk()) {}
template <class T2, class E2>
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> NewResult(
NewResult<T2, E2>&& other
)
requires(!std::is_copy_constructible_v<value_type>) :
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {}
template <class T2>
requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType> const& other)
requires std::is_copy_constructible_v<value_type> :
NewResult(value_type(other.unwrap()), true) {}
template <class T2>
requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType>&& other)
requires(!std::is_copy_constructible_v<value_type>) :
NewResult(std::forward<value_type>(other.unwrap()), true) {}
template <class E2>
requires ConvertibleToResult<E2, T> NewResult(NewResult<AnyType, E2> const& other)
requires std::is_copy_constructible_v<value_type> :
NewResult(error_type(other.unwrapErr()), false) {}
template <class E2>
requires ConvertibleToResult<E2, T> NewResult(NewResult<AnyType, E2>&& other)
requires(!std::is_copy_constructible_v<value_type>) :
NewResult(std::forward<error_type>(other.unwrapErr()), false) {}
value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
return m_value;
}
value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
return std::move(m_value);
}
error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
return m_value;
}
error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
return std::move(m_value);
}
explicit operator bool() const requires(!std::is_same_v<T, bool>) {
return this->isOk();
}
};
template <class T = DefaultValue, class E = AnyType>
requires std::is_copy_constructible_v<T> NewResult<T, E> NewOk(T value = T()) {
return NewResult<T, E>(value);
}
template <class T = DefaultValue, class E = AnyType>
requires(!std::is_copy_constructible_v<T>) NewResult<T, E> NewOk(T&& value) {
return NewResult<T, E>(std::forward<T>(value));
}
template <class E = DefaultError, class T = AnyType>
requires std::is_copy_constructible_v<E> NewResult<T, E> NewErr(E error = E()) {
return NewResult<T, E>(error);
}
template <class E = DefaultError, class T = AnyType>
requires(!std::is_copy_constructible_v<E>) NewResult<T, E> NewErr(E&& error) {
return NewResult<T, E>(std::forward<E>(error));
}
#define GEODE_UNWRAP_INTO(into, ...) \
auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__); \
if (GEODE_CONCAT(res_, __LINE__).isErr()) { \
return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr())); \
} \
into = std::move(GEODE_CONCAT(res_, __LINE__).unwrap())
#define GEODE_UNWRAP(...) \
{ \
auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__); \
if (GEODE_CONCAT(res_, __LINE__).isErr()) { \
return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr())); \
} \
}
}

Some files were not shown because too many files have changed in this diff Show more