This commit is contained in:
altalk23 2023-04-05 23:10:23 +03:00
commit a5b1640556
58 changed files with 1212 additions and 352 deletions

1
.gitignore vendored
View file

@ -51,6 +51,7 @@ loader/src/internal/about.hpp
loader/src/internal/resources.hpp loader/src/internal/resources.hpp
loader/resources/mod.json loader/resources/mod.json
loader/resources/blanks/rename.js loader/resources/blanks/rename.js
loader/resources/changelog.md
fods-catgirl-hideout.txt fods-catgirl-hideout.txt
# krita files too because alk is funny # krita files too because alk is funny

View file

@ -1,93 +1,131 @@
# Geode Changelog # Geode Changelog
## v1.0.0-beta.12
* Fix crash when installing mods
* FMOD is now linked on MacOS
* `GEODE_DEBUG` on longer needs to be defined for `log::debug` to work
* Make Geode changelog visible in-game
* Make the changelog only be loaded once the changelog button is pressed in ModInfoPopup
* Fix the scrollbar not working for the changelog in ModInfoPopup
* Fix visual issues with scrollbars
## v1.0.0-beta.11
* New `geode::prelude` namespace to replace the old `USE_GEODE_NAMESPACE()` macro
* Add `CCNode::removeChildByID`
* Add `CCNode::hasAncestor`
* Add `CCScene::get` and `CCScheduler::get`
* Add `geode::cocos::getMousePos`
* Add `GEODE_DONT_INSTALL_MODS` option to CMake
* Add logging `std::vector` with `log::` functions
* Add `EventListener::getFilter`
* Add `AttributeSetEvent` for detecting when attributes are added to nodes
* Add `CCNode::addEventListener` (along with other related functions) as convenience methods for adding event listeners that target nodes
* Add `WeakRef` as a weak pointer alternative to `Ref` (see [the docs](https://docs.geode-sdk.org/tutorials/memory#weakref) for a tutorial)
* Add option to ignore invisible children to `Layout`
* `CCNode` attributes now use `json::Value` over `std::any` for ABI compatability
* Implement file picker on Mac
* Define `CCNode::retainCount` inline
* `Layout` now inherits from `CCObject`, allowing you to share layouts across multiple nodes
* Update TulipHook version
* Make sure mod load/enable/etc. events are only ever posted in the GD thread
* `Mod::getResourcesDir` now returns `geode/unzipped/{mod.id}/resources/{mod.id}` in conjunction with [CLI v2.1.0](https://github.com/geode-sdk/cli/releases/tag/v2.1.1)
* Give a name to `ccTouchType`
* Fix `Scrollbar` being funky sometimes
* Fix mod resources not being loaded if the mod is enabled at runtime
* Fix `EditLevelLayer` description update button ID & layout
* Fix hooking functions with unpredictable calling conventions
* Fix `setup_geode_mod` not linking to Geode if CLI calls are disabled
* Fix code editors showing a ton of warnings with `$modify`
* Fix top sprite sizes of `CircleButtonSprite` and `EditorButtonSprite`
* Fix `Mod::enableHook` error message
* Lots of bindings on both Windows & Mac (50+ commits related to bindings)
## v1.0.0-beta.10
* Fix loader minimum mod version preventing the loader itself from loading
* Fix recursive comparison in VersionTag
* `geode/unzipped` is now deleted on startup if it exists
## v1.0.0-beta.9 ## v1.0.0-beta.9
* Fix multiple modifiers not being able to have fields on same class due to having same field index (7710fa9) * Fix multiple modifiers not being able to have fields on same class due to having same field index
* Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional` (4a15afc) * Add `Result::ok` and `Result::err` for converting the `Result` into `std::optional`
## v1.0.0-beta.8 ## v1.0.0-beta.8
* Unload the mod even when first time warning pops up (63b4774) * Unload the mod even when first time warning pops up
* Error when address of a function returns nullptr when hooking (724a9d3) * Error when address of a function returns nullptr when hooking
* Add support for Geode CLI v2.0.0 (which has not been released yet) (088ac7b, deadb58) * Add support for Geode CLI v2.0.0 (which has not been released yet)
* Logging no longer causes a crash on invalid formats, but instead just warns (6aba7cf) * Logging no longer causes a crash on invalid formats, but instead just warns
* `file::pickFile` now uses the last item in the default path as the default filename to save/open (5c9ee08) * `file::pickFile` now uses the last item in the default path as the default filename to save/open
* Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr` (33a91d6) * Fix `EditorPauseLayer` crashing constantly due to some members being accidentally set to `nullptr`
## v1.0.0-beta.7 ## v1.0.0-beta.7
* Add `Mod::getResourcesDir` for getting the mod resources directory (0055032) * Add `Mod::getResourcesDir` for getting the mod resources directory
* Deprecate `file::listFiles` for `file::readDirectory` (9f60091) * Deprecate `file::listFiles` for `file::readDirectory`
* Fix getting virtual function addresses for CCFileUtils (c183a35) * Fix getting virtual function addresses for CCFileUtils
* Rename `BasedButtonSprite` sprite names to be more expressive (4d2daec) * Rename `BasedButtonSprite` sprite names to be more expressive
* Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS (d024dbb) * Fix `typeinfo_cast` causing a crash if passed a `nullptr` on MacOS
* Fix settings not getting broadcasted (7089194) * Fix settings not getting broadcasted
* Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled (3222097) * Make `Loader::getLoadedMod` and `Loader::isModLoaded` also check if mod is enabled
* Display Geode commit hash in the bottom right of the mod info layer (1dfa907) * Display Geode commit hash in the bottom right of the mod info layer
* Fix `EditorPauseLayer` info labels on the top left being too big (f5983a2) * Fix `EditorPauseLayer` info labels on the top left being too big
## v1.0.0-beta.6 ## v1.0.0-beta.6
* Reworked layouts from the ground up - see [the docs page](https://docs.geode-sdk.org/tutorials/layouts) for more information about how the new system works (#137) * Reworked layouts from the ground up - see [the docs page](https://docs.geode-sdk.org/tutorials/layouts) for more information about how the new system works (#137)
* Update the IDs for a bunch of layers, aswell as adding some predefined layouts (3f64b98, ef9e741, a78bc0c, cb1a6f1, ea037a9, f7ddf0a, ...) * Update the IDs for a bunch of layers, aswell as adding some predefined layouts (3f64b98, ef9e741, a78bc0c, cb1a6f1, ea037a9, f7ddf0a, ...)
* Add IDs & layouts to `EditorPauseLayer` (12d88ae) * Add IDs & layouts to `EditorPauseLayer`
* Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones (eb10eca, 4613af6) * Add `CCNode::insertBefore` and `CCNode::insertAfter` for adding children before/after existing ones
* Add `CCSize::aspect` convenience method * Add `CCSize::aspect` convenience method
* Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed) (0055032) * Add `Mod::getResourcesDir` for getting a mod's runtime resources directory (where `[mod.json].resources.files` are placed)
* Add `Mod::addCustomSetting` for convenience in registering custom settings (7089194) * Add `Mod::addCustomSetting` for convenience in registering custom settings
* Add `file::readDirectory` as a sanely named alternative to `file::listFiles` (9f60091) * Add `file::readDirectory` as a sanely named alternative to `file::listFiles`
* Move `GEODE_DLL` to the structs themselves in `JsonValidation` (06bc6fd) * Move `GEODE_DLL` to the structs themselves in `JsonValidation`
* Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions (bbbf332) * Versions now support tag numbers & version tags are now used in comparisons. This change does not affect old betas, which still internally report their version as just `v1.0.0-beta`, but starting with this beta the version is correctly reported as `v1.0.0-beta.6` and correctly compared against other versions
* `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled (3222097) * `Loader::getLoadedMod` and `Loader::isModLoaded` now only return if the mod is also enabled
* Geode's internal mod representation is now included in the loader's loaded mods list (4261e99) * Geode's internal mod representation is now included in the loader's loaded mods list
* Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor (7089194) * Fix settings value changes not being broadcast. This causes an API break relating to custom settings; `SettingValue` now requires the owner mod ID in its constructor
* Fix some warnings (9c9706b, f7bfa21) * Fix some warnings
* Fix `CCNode::swapChildIndices` (ba0851e) * Fix `CCNode::swapChildIndices`
* Fix `typeinfo_cast` causing a crash if passed a `nullptr` (f4a3258) * Fix `typeinfo_cast` causing a crash if passed a `nullptr`
* Fix `ranges::reverse` causing UB (ffd50eb) * Fix `ranges::reverse` causing UB
* Other fixes & improvements (cb00c21) * Other fixes & improvements
## v1.0.0-beta.5 ## v1.0.0-beta.5
- Make ModInfo Pimpl
- Make ModInfo Pimpl 51990ad89b25cecbabaf748a5bcb279227fce090 - Fix crash with event listeners
- Fix crash with event listeners 1f7d50a9b9140d02f6a9afb97734eb9761b6a0d4 - Some bindings
- Some bindings 4a9f6ba52a3d756d9bc28c1809afc92479783673 - Make mods binaries not silently fail to load
- Make mods binaries not silently fail to load 0eb5f01ca81435cb90f2bc9d8d97a86405dadd1c - Assume dependency version is >= comparison by default
- Assume dependency version is >= comparison by default 41aef57758d7b858d5fa7cb22ab1ffe603ff365f - Fix not following thunks
- Fix not following thunks 65f2cbb286cc1e5af57e43451862a2233d66453e
## v1.0.0-beta.4 ## v1.0.0-beta.4
- Add some bindings
- add some bindings - Fix macOS libzstd crash
- fix macOS libzstd crash
## v1.0.0-beta.3 ## v1.0.0-beta.3
- Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more
- Better support for dependencies with [Geode CLI v1.4.x](https://github.com/geode-sdk/cli/releases/latest): mod dependencies are now automatically installed from the mods index by simply declaring them in your `mod.json`. See [the tutorial page in docs](https://docs.geode-sdk.org/mods/dependencies/) for more (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future
- The `create_geode_file` CMake function has been replaced by `setup_geode_mod`. The old `create_geode_file` function is still available, but will be deprecated in the future (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - `Result::except` now works with non-copyable types
- `Result::except` now works with non-copyable types (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - `Zip` and `Unzip` now support in-memory ZIP extraction and creation
- `Zip` and `Unzip` now support in-memory ZIP extraction and creation (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - `ComparableVersionInfo::compare` now always returns false if the major versions are different
- `ComparableVersionInfo::compare` now always returns false if the major versions are different (f32aaa8b124bdd040a453bc25d31a4e463cf1309) - `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`)
- `ComparableVersionInfo` parsing now expects equal to be marked with a single `=` instead of two (`==v1.2.3` => `=v1.2.3`) (6d3847d9e13fdf69cea0b9a69376ebcd88e71725) - Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked
- Fix `DS_Dictionary`-related `gd::string` Cocos2d functions not being linked (ab0030136ab8c20731fe768ef5f3b16ae4245583) - `CC_DLL` no longer expands to dllexport/dllimport
- `CC_DLL` no longer expands to dllexport/dllimport (ab0030136ab8c20731fe768ef5f3b16ae4245583) - The JSON lib now default constructs to object, hopefully fixing uncaught bugs
- The JSON lib now default constructs to object, hopefully fixing uncaught bugs (30101fc0b5112317aac3c9eeea0aab888ca8b30d) - Something related to codegen and addresser? I have no clue what it does, so you probably won't have either
- Something related to codegen and addresser? I have no clue what it does, so you probably won't have either (ae1eb8bb7162342f598e047a459e3808801f731a, 1e9faac5aa5a32b0cb5e6ffaac0c5cbfc217e9cb, fea049cca069a08181ab66cacda6f2417c006a2f, ad261846919e503cc3faf75d777ab2f2882bc6bb, ...) - MacOS minimum version bumped to 10.14
- MacOS minimum version bumped to 10.14 (916f54063008c6bdf892d02f8bcd92b58606817e)
## v1.0.0-beta.2 ## v1.0.0-beta.2
* Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value
* Fixed bug where `Mod::getSavedValue` would cause a crash due to trying operator on a null JSON value (5bbd34c) * Fixed bug where loading would crash if one of the mods' binaries failed to load
* Fixed bug where loading would crash if one of the mods' binaries failed to load (ef86ae0)
## v1.0.0-beta.1 ## v1.0.0-beta.1
* Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API.
* Switched to [a new custom-built JSON library](https://github.com/geode-sdk/json) to replace `nlohmann::json` for compile-time improvements; if you were using the old JSON library, you can add & link to `nlohmann::json` in your own project, or update to use the new API. (deab672) * Fix resources not being downloaded automatically by using a fallback to latest release
* Fix resources not being downloaded automatically by using a fallback to latest release (a418828) * Add a new clear instruction popup in case downloading still fails
* Add a new clear instruction popup in case downloading still fails (30dc9ad) * String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!)
* String ID hooks now have higher priority, so they should always be applied regardless of if you call `NodeIDs::provideFor` or not (though it can still be called to absolutely ensure the IDs are there!) (b6a6e4d) * Various internal bugfixes & improvements
* Various internal bugfixes & improvements (ceb02e9, a90b3e1, b00ab40, c644b43)
## v1.0.0-alpha ## v1.0.0-alpha
- Major rework of the entire framework; most notable changes include switching to a whole new hooking framework (TulipHook), simplifying many parts of the framework, and making it production-ready. - Major rework of the entire framework; most notable changes include switching to a whole new hooking framework (TulipHook), simplifying many parts of the framework, and making it production-ready.
## v0.7.0 ## v0.7.0
@ -105,7 +143,6 @@
- Add more bindings - Add more bindings
## v0.6.0 ## v0.6.0
- Mod resource loading has been reworked again, with the intent of adding support for texture pack loaders - Mod resource loading has been reworked again, with the intent of adding support for texture pack loaders
- Added `Loader::addTexturePath` and `Loader::removeTexturePath` to work with additional resource paths - Added `Loader::addTexturePath` and `Loader::removeTexturePath` to work with additional resource paths
- Mods that work with Cocos2d search paths directly should convert to using the above functions - Mods that work with Cocos2d search paths directly should convert to using the above functions
@ -121,7 +158,6 @@
- Add IDs to `LevelSearchLayer` (thank you @Jollycistaken) - Add IDs to `LevelSearchLayer` (thank you @Jollycistaken)
## v0.5.0 ## v0.5.0
- Added `CCFileUtils::get` - Added `CCFileUtils::get`
- Fix crashes related to setting IDs in `MenuLayer` - Fix crashes related to setting IDs in `MenuLayer`
- Remove `Loader::updateModResourcePaths` and `Loader::updateResourcePaths`. The minimum mod target version is still v0.4.0 however, as you should never have been using these functions. - Remove `Loader::updateModResourcePaths` and `Loader::updateResourcePaths`. The minimum mod target version is still v0.4.0 however, as you should never have been using these functions.
@ -130,17 +166,14 @@
- Finally added a license to Geode! The framework is now licensed under BSL v1.0. - Finally added a license to Geode! The framework is now licensed under BSL v1.0.
## v0.4.8 ## v0.4.8
- CLI issues fixed in v1.0.6 so loader again verifies if loader resources are missing / corrupt on startup - CLI issues fixed in v1.0.6 so loader again verifies if loader resources are missing / corrupt on startup
- Resource download text is no longer a popup on top of the title but instead just replaces the loading text - Resource download text is no longer a popup on top of the title but instead just replaces the loading text
- Add delegates to `EditLevelLayer` - Add delegates to `EditLevelLayer`
## v0.4.7 ## v0.4.7
- Loader resources check would always fail due to CLI issues, so for now loader just checks if the resources folder exists - Loader resources check would always fail due to CLI issues, so for now loader just checks if the resources folder exists
## v0.4.6 ## v0.4.6
- Automatically checks & downloads loader resources if they are missing / corrupt on startup - Automatically checks & downloads loader resources if they are missing / corrupt on startup
- CMake rework; `GeodeFile.cmake` now checks and verifies CLI version - CMake rework; `GeodeFile.cmake` now checks and verifies CLI version
- Add optional `DONT_INSTALL` parameter to `create_geode_file` - Add optional `DONT_INSTALL` parameter to `create_geode_file`
@ -150,7 +183,6 @@
- Change `CCArrayExt` to use `Ref` - Change `CCArrayExt` to use `Ref`
## v0.4.5 ## v0.4.5
- Rework bindings and codegen to improve compile times, now individual bindings can be included with `<Geode/binding/{ClassName}.hpp>` - Rework bindings and codegen to improve compile times, now individual bindings can be included with `<Geode/binding/{ClassName}.hpp>`
- Modify has also been separated, you can now include individual modifiers with `<Geode/modify/{ClassName}.hpp>` - Modify has also been separated, you can now include individual modifiers with `<Geode/modify/{ClassName}.hpp>`
- Various other fixes to improve compile times - Various other fixes to improve compile times
@ -175,25 +207,21 @@
- Remove automatic mod updating for now, however automatic update checking for mods is still there - Remove automatic mod updating for now, however automatic update checking for mods is still there
## v0.4.4 ## v0.4.4
- New `listenForSettingChanges` API for more ergonomically listening for setting changes - New `listenForSettingChanges` API for more ergonomically listening for setting changes
- Fixed bug where GD was unopenable through Steam - Fixed bug where GD was unopenable through Steam
- Various other internal fixes - Various other internal fixes
## v0.4.3 ## v0.4.3
- Simplified the minimum and maximum loader versions, loader will now load any mod whose target version major and minor match. In practice, this means that for example mods whose target version is v0.4.8 can be loaded by loader of version v0.4.6. - Simplified the minimum and maximum loader versions, loader will now load any mod whose target version major and minor match. In practice, this means that for example mods whose target version is v0.4.8 can be loaded by loader of version v0.4.6.
- Add `Geode/ui/GeodeUI.hpp` header for exposing some access to internal Geode UI like opening a mod's settings popup - Add `Geode/ui/GeodeUI.hpp` header for exposing some access to internal Geode UI like opening a mod's settings popup
- Fix crash with settings that could have a slider control - Fix crash with settings that could have a slider control
## v0.4.2 ## v0.4.2
- Moved SDK version to its own file so CLI can query it - Moved SDK version to its own file so CLI can query it
- md4c is now linked statically on MacOS - md4c is now linked statically on MacOS
- Fix log filenames - Fix log filenames
## v0.4.1 ## v0.4.1
- Initial dev release of Geode. - Initial dev release of Geode.
--- ---
@ -201,51 +229,39 @@
Note that from here on, changes to the framework were not tracked by versions as the framework was still considered to be in heavy development and not released. Instead, major changes are listed by dates. Note that from here on, changes to the framework were not tracked by versions as the framework was still considered to be in heavy development and not released. Instead, major changes are listed by dates.
## 2022/10/10 ## 2022/10/10
- Geode released for developers - Geode released for developers
## 2022/10/08 ## 2022/10/08
- `ui` branch merged to `main` - `ui` branch merged to `main`
## 2022/10/03 ## 2022/10/03
- New CLI finished - New CLI finished
- `ui` branch finished - `ui` branch finished
## 2022/08/01 ## 2022/08/01
- CLI redesign started - CLI redesign started
## 2022/07/30 ## 2022/07/30
- `sdk`, `loader` and `api` repos all merged into one `geode` repo - `sdk`, `loader` and `api` repos all merged into one `geode` repo
## 2022/05/24 ## 2022/05/24
- Geode announced to be merging with Hyperdash, later on it turned out we were all pathological liars - Geode announced to be merging with Hyperdash, later on it turned out we were all pathological liars
## 2022/05/02 ## 2022/05/02
- Installer on Windows - Installer on Windows
## 2022/04/30 ## 2022/04/30
- Installing mods in-game works - Installing mods in-game works
## 2022/01/23 ## 2022/01/23
- CLI started - CLI started
## 2022/01/19 ## 2022/01/19
- Lilac and Cacao merged and renamed to Geode - Lilac and Cacao merged and renamed to Geode
## 2021/07/30 ## 2021/07/30
- Lilac started by Mat, HJfod and Pie - Lilac started by Mat, HJfod and Pie
## 2021/01/25 ## 2021/01/25
- CacaoSDK started by Camila, based on CappuccinoSDK - CacaoSDK started by Camila, based on CappuccinoSDK

View file

@ -67,6 +67,7 @@ target_compile_definitions(${PROJECT_NAME} INTERFACE -DPROJECT_NAME=${CMAKE_PROJ
set(GEODE_CODEGEN_PATH ${CMAKE_CURRENT_BINARY_DIR}/codegenned) set(GEODE_CODEGEN_PATH ${CMAKE_CURRENT_BINARY_DIR}/codegenned)
set(GEODE_BIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) set(GEODE_BIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(GEODE_LOADER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/loader) set(GEODE_LOADER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/loader)
set(GEODE_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include(cmake/GeodeFile.cmake) include(cmake/GeodeFile.cmake)
include(cmake/Platform.cmake) include(cmake/Platform.cmake)
@ -146,7 +147,7 @@ endif()
add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp) add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link) target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude) target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude mat-json)
target_include_directories(GeodeCodegenSources PRIVATE target_include_directories(GeodeCodegenSources PRIVATE
${GEODE_CODEGEN_PATH} ${GEODE_CODEGEN_PATH}
${GEODE_LOADER_PATH}/include ${GEODE_LOADER_PATH}/include

View file

@ -1 +1 @@
1.0.0-beta.10 1.0.0-beta.13

View file

@ -65,8 +65,18 @@ class cocos2d::CCCallFuncO {
} }
class cocos2d::CCClippingNode { class cocos2d::CCClippingNode {
CCClippingNode() {
m_pStencil = nullptr;
m_fAlphaThreshold = 1.f;
m_bInverted = false;
}
~CCClippingNode() = mac 0x4191e0;
static cocos2d::CCClippingNode* create() = mac 0x4192a0; static cocos2d::CCClippingNode* create() = mac 0x4192a0;
static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330; static cocos2d::CCClippingNode* create(cocos2d::CCNode*) = mac 0x419330;
// Inlined in create() call
auto init() = mac 0x4193e0;
// Inlined in create() call
auto init(cocos2d::CCNode* stencil) = mac 0x419400;
auto getAlphaThreshold() const = mac 0x419a10; auto getAlphaThreshold() const = mac 0x419a10;
auto getStencil() const = mac 0x4199c0; auto getStencil() const = mac 0x4199c0;
auto isInverted() const = mac 0x419a30; auto isInverted() const = mac 0x419a30;
@ -151,6 +161,31 @@ class cocos2d::CCDrawNode {
virtual ~CCDrawNode() = mac 0x378cc0; virtual ~CCDrawNode() = mac 0x378cc0;
} }
class cocos2d::CCAction {
CCAction() = mac 0x35b610;
virtual ~CCAction() = mac 0x35b6b0;
auto stop() = mac 0x35b860;
auto copyWithZone(cocos2d::CCZone* zone) = mac 0x35b7a0;
auto startWithTarget(cocos2d::CCNode* target) = mac 0x35b850;
auto step(float dt) = mac 0x35b880;
auto isDone() = mac 0x35b870;
auto update(float time) = mac 0x35b890;
}
class cocos2d::CCFiniteTimeAction {
// same as CCActionInterval::reverse i think
auto reverse() = mac 0x1f2720;
}
class cocos2d::CCActionInterval {
auto copyWithZone(cocos2d::CCZone* zone) = mac 0x1f2550;
auto isDone() = mac 0x1f2640;
auto startWithTarget(cocos2d::CCNode* pTarget) = mac 0x1f2700;
auto step(float dt) = mac 0x1f2660;
auto reverse() = mac 0x1f2720;
bool initWithDuration(float d) = mac 0x1f2510;
}
class cocos2d::CCEaseBackIn { class cocos2d::CCEaseBackIn {
static cocos2d::CCEaseBackIn* create(cocos2d::CCActionInterval*) = mac 0x2a41b0; static cocos2d::CCEaseBackIn* create(cocos2d::CCActionInterval*) = mac 0x2a41b0;
} }
@ -176,6 +211,7 @@ class cocos2d::CCEGLView {
static cocos2d::CCEGLView* sharedOpenGLView() = mac 0x295320; static cocos2d::CCEGLView* sharedOpenGLView() = mac 0x295320;
virtual void swapBuffers() = mac 0x295510; virtual void swapBuffers() = mac 0x295510;
void updateWindow(int width, int height); void updateWindow(int width, int height);
void setupWindow(cocos2d::CCRect);
void toggleFullScreen(bool fullscreen); void toggleFullScreen(bool fullscreen);
void pollEvents(); void pollEvents();
void onGLFWCharCallback(GLFWwindow* window, unsigned int entered); void onGLFWCharCallback(GLFWwindow* window, unsigned int entered);
@ -407,12 +443,12 @@ class cocos2d::CCMenu {
virtual auto registerWithTouchDispatcher() = mac 0x438cd0, ios 0x131f8c; virtual auto registerWithTouchDispatcher() = mac 0x438cd0, ios 0x131f8c;
virtual auto onExit() = mac 0x438bd0, ios 0x131ed4; virtual auto onExit() = mac 0x438bd0, ios 0x131ed4;
virtual auto removeChild(cocos2d::CCNode*, bool) = mac 0x438c20, ios 0x15e630; virtual auto removeChild(cocos2d::CCNode*, bool) = mac 0x438c20, ios 0x15e630;
auto initWithArray(cocos2d::CCArray*) = mac 0x4389f0, ios 0x131d04; bool initWithArray(cocos2d::CCArray*) = mac 0x4389f0, ios 0x131d04;
auto itemForTouch(cocos2d::CCTouch*) = mac 0x438dd0; cocos2d::CCMenuItem* itemForTouch(cocos2d::CCTouch*) = mac 0x438dd0;
} }
class cocos2d::CCMenuItem { class cocos2d::CCMenuItem {
auto initWithTarget(cocos2d::CCObject*, cocos2d::SEL_MenuHandler) = mac 0x1fb7f0; bool initWithTarget(cocos2d::CCObject*, cocos2d::SEL_MenuHandler) = mac 0x1fb7f0;
virtual ~CCMenuItem() = mac 0x1fb8e0, ios 0x2cdf4; virtual ~CCMenuItem() = mac 0x1fb8e0, ios 0x2cdf4;
virtual auto activate() = mac 0x1fba70, ios 0x2ceb0; virtual auto activate() = mac 0x1fba70, ios 0x2ceb0;
virtual auto selected() = mac 0x1fb9e0, ios 0x2ce2e; virtual auto selected() = mac 0x1fb9e0, ios 0x2ce2e;
@ -635,9 +671,6 @@ class cocos2d::CCObject {
auto isEqual(cocos2d::CCObject const*) = mac 0x250f20, ios 0x439e4; auto isEqual(cocos2d::CCObject const*) = mac 0x250f20, ios 0x439e4;
auto release() = mac 0x250ea0, ios 0x43984; auto release() = mac 0x250ea0, ios 0x43984;
auto retain() = mac 0x250ec0, ios 0x439a8; auto retain() = mac 0x250ec0, ios 0x439a8;
unsigned int retainCount() const {
return m_uReference;
}
virtual auto setTag(int) = mac 0x250f60, ios 0x43a10; virtual auto setTag(int) = mac 0x250f60, ios 0x43a10;
~CCObject() = mac 0x250d20, ios 0x6ac0; ~CCObject() = mac 0x250d20, ios 0x6ac0;
@ -701,6 +734,8 @@ class cocos2d::CCScheduler {
auto scheduleUpdateForTarget(cocos2d::CCObject*, int, bool) = mac 0x2438d0; auto scheduleUpdateForTarget(cocos2d::CCObject*, int, bool) = mac 0x2438d0;
auto unscheduleAllForTarget(cocos2d::CCObject*) = mac 0x243e40; auto unscheduleAllForTarget(cocos2d::CCObject*) = mac 0x243e40;
auto unscheduleUpdateForTarget(cocos2d::CCObject const*) = mac 0x243c60; auto unscheduleUpdateForTarget(cocos2d::CCObject const*) = mac 0x243c60;
auto resumeTargets(cocos2d::CCSet*) = mac 0x244680;
auto pauseAllTargets() = mac 0x244550;
virtual void update(float delta) = mac 0x2446d0; virtual void update(float delta) = mac 0x2446d0;
} }
@ -931,6 +966,7 @@ class cocos2d::CCTransitionFade {
class cocos2d::ZipUtils { class cocos2d::ZipUtils {
static auto compressString(gd::string, bool, int) = mac 0xe9a50; static auto compressString(gd::string, bool, int) = mac 0xe9a50;
static auto decompressString(gd::string, bool, int) = mac 0xea380; static auto decompressString(gd::string, bool, int) = mac 0xea380;
static int ccDeflateMemory(unsigned char*, unsigned int, unsigned char**) = mac 0xe9cf0;
} }
class cocos2d::extension::CCControl { class cocos2d::extension::CCControl {
@ -1042,12 +1078,24 @@ class cocos2d {
static auto ccDrawSolidRect(cocos2d::CCPoint, cocos2d::CCPoint, cocos2d::_ccColor4F) = mac 0xecf00; static auto ccDrawSolidRect(cocos2d::CCPoint, cocos2d::CCPoint, cocos2d::_ccColor4F) = mac 0xecf00;
static auto ccGLEnableVertexAttribs(unsigned int) = mac 0x1ae740; static auto ccGLEnableVertexAttribs(unsigned int) = mac 0x1ae740;
static auto ccGLBindTexture2D(GLuint) = mac 0x1ae610; static auto ccGLBindTexture2D(GLuint) = mac 0x1ae610;
static float ccpDistance(cocos2d::CCPoint const&, cocos2d::CCPoint const&) = mac 0x1aaf90;
static void ccDrawPoly(cocos2d::CCPoint const*, unsigned int, bool) = mac 0xed0a0;
static void ccDrawColor4B(GLubyte, GLubyte, GLubyte, GLubyte) = mac 0xeddd0;
} }
// class DS_Dictionary { class DS_Dictionary {
// DS_Dictionary() = mac 0xbe9a0; DS_Dictionary() = mac 0xbe9a0;
// int getIntegerForKey(char const*) = mac 0xc1610; ~DS_Dictionary() = mac 0x393c30;
// void setIntegerForKey(char const*, int) = mac 0xc26b0; bool saveRootSubDictToString() = mac 0xc09c0;
// } bool loadRootSubDictFromString(gd::string) = mac 0xbfd80;
bool stepIntoSubDictWithKey(char const*) = mac 0xc0cd0;
int getIntegerForKey(char const*) = mac 0xc1610;
void setIntegerForKey(char const*, int) = mac 0xc26b0;
}
class pugi::xml_document {
xml_document() = mac 0x393a80;
~xml_document() = mac 0x393b50;
}
// clang-format on // clang-format on

View file

@ -97,7 +97,10 @@ class AppDelegate : cocos2d::CCApplication, cocos2d::CCSceneDelegate {
void resumeSound() = win 0x3d4d0; void resumeSound() = win 0x3d4d0;
void setupGLView() = win 0x3c950; void setupGLView() = win 0x3c950;
PAD = win 0x4;
cocos2d::CCScene* m_runningScene; cocos2d::CCScene* m_runningScene;
bool m_loadingFinished;
// there's 0x18 more on Windows
} }
class ArtistCell : TableViewCell { class ArtistCell : TableViewCell {
@ -531,6 +534,10 @@ class CCScrollLayerExtDelegate {
virtual void scrollViewTouchEnd(CCScrollLayerExt*) {} virtual void scrollViewTouchEnd(CCScrollLayerExt*) {}
} }
class CCSpritePart : CCSpritePlus {
}
class CCSpritePlus : cocos2d::CCSprite { class CCSpritePlus : cocos2d::CCSprite {
bool initWithSpriteFrameName(const char*) = mac 0x248670, win 0x1c1e0; bool initWithSpriteFrameName(const char*) = mac 0x248670, win 0x1c1e0;
void setScaleX(float scale) = win 0x1c440; void setScaleX(float scale) = win 0x1c440;
@ -932,6 +939,7 @@ class CustomSongLayer : FLAlertLayer, FLAlertLayerProtocol, TextInputDelegate, G
} }
class CustomSongWidget : cocos2d::CCNode, MusicDownloadDelegate, FLAlertLayerProtocol { class CustomSongWidget : cocos2d::CCNode, MusicDownloadDelegate, FLAlertLayerProtocol {
bool init(SongInfoObject*, LevelSettingsObject*, bool, bool, bool, bool, bool hideBackground) = mac 0x37be20, win 0x685b0;
void FLAlert_Clicked(FLAlertLayer*, bool) {} void FLAlert_Clicked(FLAlertLayer*, bool) {}
void loadSongInfoFinished(SongInfoObject*) {} void loadSongInfoFinished(SongInfoObject*) {}
@ -1111,6 +1119,12 @@ class EditButtonBar : cocos2d::CCNode {
} }
void loadFromItems(cocos2d::CCArray* buttons, int rowCount, int columnCount, bool idk) = mac 0x351010, win 0x6e5e0, ios 0x2dd060; void loadFromItems(cocos2d::CCArray* buttons, int rowCount, int columnCount, bool idk) = mac 0x351010, win 0x6e5e0, ios 0x2dd060;
static EditButtonBar* create(
cocos2d::CCArray* buttons,
cocos2d::CCPoint point,
int idk, bool idk0,
int rowCount, int columnCount
) = win 0x6e450;
cocos2d::CCPoint m_position; cocos2d::CCPoint m_position;
int m_unknown; int m_unknown;
@ -1235,10 +1249,11 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
virtual void scaleChanged(float) = mac 0x25490, win 0x88df0; virtual void scaleChanged(float) = mac 0x25490, win 0x88df0;
virtual void scaleChangeEnded() = win 0x88de0; virtual void scaleChangeEnded() = win 0x88de0;
void scaleObjects(cocos2d::CCArray*, float, cocos2d::CCPoint) = mac 0x252e0, win 0x8f150; void scaleObjects(cocos2d::CCArray*, float, cocos2d::CCPoint) = mac 0x252e0, win 0x8f150;
void selectObjects(cocos2d::CCArray*, bool) = mac 0x23940, win 0x864a0; void selectObjects(cocos2d::CCArray* objs, bool ignoreFilters) = mac 0x23940, win 0x864a0;
void setupCreateMenu() = mac 0xcb50, win 0x7caf0; void setupCreateMenu() = mac 0xcb50, win 0x7caf0;
void undoLastAction(cocos2d::CCObject*) = mac 0xb830, win 0x87070; void undoLastAction(cocos2d::CCObject*) = mac 0xb830, win 0x87070;
void updateButtons() = mac 0x1a300, win 0x78280; void updateButtons() = mac 0x1a300, win 0x78280;
void updateEditMenu() = win 0x8b010;
void updateObjectInfoLabel() = mac 0x1cb10, win 0x793b0; void updateObjectInfoLabel() = mac 0x1cb10, win 0x793b0;
void updateSlider() = mac 0x18a90, win 0x78f10; void updateSlider() = mac 0x18a90, win 0x78f10;
void updateZoom(float) = mac 0x248c0, win 0x878a0; void updateZoom(float) = mac 0x248c0, win 0x878a0;
@ -1248,6 +1263,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void selectAll() = win 0x86c40; void selectAll() = win 0x86c40;
void selectAllWithDirection(bool left) = win 0x86d80; void selectAllWithDirection(bool left) = win 0x86d80;
cocos2d::CCPoint getTouchPoint(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) = win 0x90620; cocos2d::CCPoint getTouchPoint(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) = win 0x90620;
cocos2d::CCPoint getGridSnappedPos(cocos2d::CCPoint pos) = win 0x90550;
void onSelectBuildTab(cocos2d::CCObject* sender) = win 0x887f0; void onSelectBuildTab(cocos2d::CCObject* sender) = win 0x887f0;
void onCreateButton(cocos2d::CCObject* sender) = win 0x854f0; void onCreateButton(cocos2d::CCObject* sender) = win 0x854f0;
CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = mac 0xb500, win 0x78bf0; CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = mac 0xb500, win 0x78bf0;
@ -1319,6 +1335,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884; virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;
void createMoveMenu() = mac 0x275e0, win 0x8c0d0; void createMoveMenu() = mac 0x275e0, win 0x8c0d0;
void sliderChanged(cocos2d::CCObject* slider) = win 0x78cc0; void sliderChanged(cocos2d::CCObject* slider) = win 0x78cc0;
void repositionObjectsToCenter(cocos2d::CCArray* objs, cocos2d::CCPoint center, bool ignoreGroupParent) = win 0x88410;
virtual void draw() = win 0x8fbe0; virtual void draw() = win 0x8fbe0;
bool m_isPlayingMusic; bool m_isPlayingMusic;
@ -2342,7 +2359,12 @@ class GJGroundLayer : cocos2d::CCLayer {
void updateGroundWidth() = mac 0x356790, win 0x12dda0; void updateGroundWidth() = mac 0x356790, win 0x12dda0;
} }
class GJItemIcon { class GJItemIcon : cocos2d::CCSprite {
bool init(
UnlockType, int, cocos2d::ccColor3B, cocos2d::ccColor3B,
bool, bool, bool, cocos2d::ccColor3B
) = win 0x12ccf0;
GJItemIcon* createBrowserIcon(UnlockType _type, int _id) { GJItemIcon* createBrowserIcon(UnlockType _type, int _id) {
return GJItemIcon::create(_type, _id, return GJItemIcon::create(_type, _id,
{ 0xaf, 0xaf, 0xaf }, { 0xff, 0xff, 0xff }, { 0xaf, 0xaf, 0xaf }, { 0xff, 0xff, 0xff },
@ -2415,8 +2437,16 @@ class GJRobotSprite : CCAnimatedSprite {
void updateFrame(int) = mac 0x34bdd0, win 0x146700; void updateFrame(int) = mac 0x34bdd0, win 0x146700;
void hideGlow() = mac 0x34b860; void hideGlow() = mac 0x34b860;
PAD = win 0x8; cocos2d::CCArray* m_unk244;
bool m_unk248;
cocos2d::ccColor3B m_mainColor;
cocos2d::ccColor3B m_secondaryColor; cocos2d::ccColor3B m_secondaryColor;
cocos2d::CCArray* m_unk250;
cocos2d::CCSprite* m_glowSprite;
cocos2d::CCSprite* m_unk258;
PAD = win 0x4;
cocos2d::CCSprite* m_flameSprite;
CCSpritePart* m_headSpritePart;
} }
class GJRotationControl : cocos2d::CCLayer { class GJRotationControl : cocos2d::CCLayer {
@ -3162,8 +3192,8 @@ class GameObject : CCSpritePlus {
bool m_isEffectObject; bool m_isEffectObject;
bool m_randomisedAnimStart; bool m_randomisedAnimStart;
float m_animSpeed; float m_animSpeed;
bool m_blackChild; bool m_isBlackObject;
bool m_unkOutlineMaybe; bool m_isBlackObjectWithOutline;
float m_blackChildOpacity; float m_blackChildOpacity;
bool field_21C; bool field_21C;
bool m_editor; bool m_editor;
@ -3367,6 +3397,7 @@ class GameStatsManager : cocos2d::CCNode {
void storePendingUserCoin(char const*) = mac 0x42940; void storePendingUserCoin(char const*) = mac 0x42940;
void storeSecretCoin(char const*) = mac 0x42a10; void storeSecretCoin(char const*) = mac 0x42a10;
void storeUserCoin(char const*) = mac 0x42890; void storeUserCoin(char const*) = mac 0x42890;
bool isItemUnlocked(UnlockType type, int id) = win 0xfbb80;
PAD = win 0x28; PAD = win 0x28;
cocos2d::CCDictionary* m_dailyChests; cocos2d::CCDictionary* m_dailyChests;
@ -3407,6 +3438,7 @@ class GameToolbox {
static void alignItemsHorisontally(cocos2d::CCArray* array, bool idk, cocos2d::CCPoint start, float pad) = win 0x25b20; static void alignItemsHorisontally(cocos2d::CCArray* array, bool idk, cocos2d::CCPoint start, float pad) = win 0x25b20;
static cocos2d::_ccHSVValue hsvFromString(gd::string, char const*) = mac 0x28cc30, win 0x26da0; static cocos2d::_ccHSVValue hsvFromString(gd::string, char const*) = mac 0x28cc30, win 0x26da0;
static gd::map<gd::string, gd::string> stringSetupToMap(gd::string, char const*) = mac 0x28d4c0; static gd::map<gd::string, gd::string> stringSetupToMap(gd::string, char const*) = mac 0x28d4c0;
static cocos2d::ccColor3B multipliedColorValue(cocos2d::ccColor3B color1, cocos2d::ccColor3B color2, float factor) = win 0x26CE0;
} }
class GaragePage : cocos2d::CCLayer, ListButtonBarDelegate { class GaragePage : cocos2d::CCLayer, ListButtonBarDelegate {
@ -3457,7 +3489,7 @@ class HardStreak : cocos2d::CCDrawNode {
// ~HardStreak() = mac 0x5bf00; inlined on windows // ~HardStreak() = mac 0x5bf00; inlined on windows
virtual bool init() = mac 0x5c090, win 0x14e430; virtual bool init() = mac 0x5c090, win 0x14e430;
void addPoint(cocos2d::CCPoint) = mac 0x5c950, win 0x14ebc0; void addPoint(cocos2d::CCPoint) = mac 0x5c950, win 0x14ebc0;
void clearBehindXPos(float) = mac 0x5cb40; void clearBehindXPos(float) = mac 0x5cb40, win 0x14ec00;
static HardStreak* create() = mac 0x5bfd0, win 0x14e390; static HardStreak* create() = mac 0x5bfd0, win 0x14e390;
void firstSetup() = mac 0x5c160, win 0x14e490; void firstSetup() = mac 0x5c160, win 0x14e490;
double normalizeAngle(double) = mac 0x5cbe0; double normalizeAngle(double) = mac 0x5cbe0;
@ -3640,12 +3672,13 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
void getNextFreeBlockID(cocos2d::CCArray*) = mac 0x9a4e0; void getNextFreeBlockID(cocos2d::CCArray*) = mac 0x9a4e0;
int getNextFreeGroupID(cocos2d::CCArray*) = mac 0x9a1b0, win 0x164ae0; int getNextFreeGroupID(cocos2d::CCArray*) = mac 0x9a1b0, win 0x164ae0;
void getNextFreeItemID(cocos2d::CCArray*) = mac 0x9a390; void getNextFreeItemID(cocos2d::CCArray*) = mac 0x9a390;
void getObjectRect(GameObject*, bool) = mac 0x96240, win 0x1616b0; cocos2d::CCRect getObjectRect(GameObject* obj, bool updateRect) = mac 0x96240, win 0x1616b0;
void getRelativeOffset(GameObject*) = mac 0x96840; void getRelativeOffset(GameObject*) = mac 0x96840;
bool hasAction(bool) = mac 0x96ff0; bool hasAction(bool) = mac 0x96ff0;
void handleAction(bool, cocos2d::CCArray*) = mac 0x97020, win 0x162010; void handleAction(bool, cocos2d::CCArray*) = mac 0x97020, win 0x162010;
bool init(GJGameLevel*) = mac 0x91010, win 0x15EE00; bool init(GJGameLevel*) = mac 0x91010, win 0x15EE00;
void objectAtPosition(cocos2d::CCPoint) = mac 0x960c0, win 0x161300; GameObject* objectAtPosition(cocos2d::CCPoint position) = mac 0x960c0, win 0x161300;
cocos2d::CCArray* objectsAtPosition(cocos2d::CCPoint position) = win 0x1614d0;
void objectMoved(GameObject*) = mac 0x999f0, win 0x162d40; void objectMoved(GameObject*) = mac 0x999f0, win 0x162d40;
cocos2d::CCArray* objectsInRect(cocos2d::CCRect rect, bool ignoreLayer) = mac 0x95e60, win 0x161ad0; cocos2d::CCArray* objectsInRect(cocos2d::CCRect rect, bool ignoreLayer) = mac 0x95e60, win 0x161ad0;
void onPlaytest() = mac 0xa06b0, win 0x1695A0; void onPlaytest() = mac 0xa06b0, win 0x1695A0;
@ -3692,7 +3725,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
} }
void updateOptions() = mac 0x91ed0, win 0x15fcc0; void updateOptions() = mac 0x91ed0, win 0x15fcc0;
void updateToggledGroups() = mac 0x9bb10; void updateToggledGroups() = mac 0x9bb10;
void updateVisibility(float) = mac 0x92c70, win 0x1632b0; callback void updateVisibility(float delta) = mac 0x92c70, win 0x1632b0;
void groupStickyObjects(cocos2d::CCArray* objects) = mac 0x99dd0, win 0x164860; void groupStickyObjects(cocos2d::CCArray* objects) = mac 0x99dd0, win 0x164860;
void ungroupStickyObjects(cocos2d::CCArray* objects) = mac 0x99ee0, win 0x164950; void ungroupStickyObjects(cocos2d::CCArray* objects) = mac 0x99ee0, win 0x164950;
@ -4640,7 +4673,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
void convertToClosestRotation(float) = mac 0x21c860, win 0x1e9ac0; void convertToClosestRotation(float) = mac 0x21c860, win 0x1e9ac0;
void copyAttributes(PlayerObject*) = mac 0x22dc70, win 0x1f93f0; void copyAttributes(PlayerObject*) = mac 0x22dc70, win 0x1f93f0;
static PlayerObject* create(int, int, cocos2d::CCLayer*) = mac 0x217260, win 0x1e6cf0; static PlayerObject* create(int, int, cocos2d::CCLayer*) = mac 0x217260, win 0x1e6cf0;
void deactivateParticle() = mac 0x21a540; void deactivateParticle() = mac 0x21a540, win 0x1e8f50;
void deactivateStreak(bool) = mac 0x218b30; void deactivateStreak(bool) = mac 0x218b30;
void fadeOutStreak2(float) = mac 0x225890, win 0x1f9110; void fadeOutStreak2(float) = mac 0x225890, win 0x1f9110;
void flashPlayer(float, float, cocos2d::_ccColor3B, cocos2d::_ccColor3B) = mac 0x221c80; void flashPlayer(float, float, cocos2d::_ccColor3B, cocos2d::_ccColor3B) = mac 0x221c80;
@ -4662,7 +4695,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
void isSafeMode(float) = mac 0x2209b0; void isSafeMode(float) = mac 0x2209b0;
void isSafeSpiderFlip(float) = mac 0x221be0; void isSafeSpiderFlip(float) = mac 0x221be0;
void levelFlipFinished() = mac 0x21b060, win 0x1e8e70; void levelFlipFinished() = mac 0x21b060, win 0x1e8e70;
void levelFlipping() = mac 0x21a510, win 0x1f6820; bool levelFlipping() = mac 0x21a510, win 0x1f6820;
void levelWillFlip() = mac 0x21b020; void levelWillFlip() = mac 0x21b020;
void loadFromCheckpoint(PlayerCheckpoint*) = mac 0x22e420, win 0x1fa080; void loadFromCheckpoint(PlayerCheckpoint*) = mac 0x22e420, win 0x1fa080;
void lockPlayer() = mac 0x22d680; void lockPlayer() = mac 0x22d680;
@ -4732,7 +4765,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
void updateCollide(bool, int) = mac 0x220f10; void updateCollide(bool, int) = mac 0x220f10;
void updateCollideBottom(float, int) = mac 0x221790; void updateCollideBottom(float, int) = mac 0x221790;
void updateCollideTop(float, int) = mac 0x221c20; void updateCollideTop(float, int) = mac 0x221c20;
void updateDashAnimation() = mac 0x21a570; void updateDashAnimation() = mac 0x21a570, win 0x1eea80;
void updateDashArt() = mac 0x222520, win 0x1ee3c0; void updateDashArt() = mac 0x222520, win 0x1ee3c0;
void updateGlowColor() = mac 0x22cf10; void updateGlowColor() = mac 0x22cf10;
void updateJump(float) = mac 0x219680, win 0x1e8f80; void updateJump(float) = mac 0x219680, win 0x1e8f80;
@ -4845,6 +4878,8 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
bool m_hasJustHeld; bool m_hasJustHeld;
bool m_isHolding2; bool m_isHolding2;
bool m_hasJustHeld2; bool m_hasJustHeld2;
bool m_unk615;
bool m_unk616;
int m_unk618; int m_unk618;
float m_unk61C; float m_unk61C;
int m_unk620; int m_unk620;
@ -4860,6 +4895,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
bool m_isRobot; bool m_isRobot;
bool m_isSpider; bool m_isSpider;
bool m_isUpsideDown; bool m_isUpsideDown;
bool m_unk63F;
bool m_isOnGround; bool m_isOnGround;
bool m_isDashing; bool m_isDashing;
float m_vehicleSize; float m_vehicleSize;
@ -5417,7 +5453,7 @@ class TextArea : cocos2d::CCSprite {
virtual void draw() {} virtual void draw() {}
virtual void setOpacity(unsigned char) = mac 0x19f760, win 0x33800; 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; 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 scale, float width, cocos2d::CCPoint anchor, float lineHeight, bool disableColor) = mac 0x19eb40, win 0x33270;
void colorAllCharactersTo(cocos2d::ccColor3B color) = win 0x33830; void colorAllCharactersTo(cocos2d::ccColor3B color) = win 0x33830;
void setString(gd::string str) = mac 0x19eda0, win 0x33480; void setString(gd::string str) = mac 0x19eda0, win 0x33480;

View file

@ -1,13 +1,8 @@
set(GEODE_CLI_MINIMUM_VERSION 1.0.5) set(GEODE_CLI_MINIMUM_VERSION 1.0.5)
# for passing CLI through CMake arguments
if (DEFINED CLI_PATH)
list(APPEND CMAKE_PROGRAM_PATH ${CLI_PATH})
endif()
# Find Geode CLI # Find Geode CLI
if (NOT DEFINED GEODE_CLI) if (NOT DEFINED GEODE_CLI)
find_program(GEODE_CLI NAMES geode.exe geode-cli.exe geode geode-cli) find_program(GEODE_CLI NAMES geode.exe geode-cli.exe geode geode-cli PATHS ${CLI_PATH})
endif() endif()
# Check if CLI was found # Check if CLI was found
@ -53,6 +48,9 @@ function(setup_geode_mod proname)
set(multiValueArgs EXTERNALS) set(multiValueArgs EXTERNALS)
cmake_parse_arguments(SETUP_GEODE_MOD "${options}" "" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(SETUP_GEODE_MOD "${options}" "" "${multiValueArgs}" ${ARGN})
# Link Geode to the mod
target_link_libraries(${proname} geode-sdk)
if (GEODE_DISABLE_CLI_CALLS) if (GEODE_DISABLE_CLI_CALLS)
message("Skipping setting up geode mod ${proname}") message("Skipping setting up geode mod ${proname}")
return() return()
@ -109,7 +107,7 @@ function(setup_geode_mod proname)
endif() endif()
# Check if --install should be passed # Check if --install should be passed
if (SETUP_GEODE_MOD_DONT_INSTALL) if (SETUP_GEODE_MOD_DONT_INSTALL OR GEODE_DONT_INSTALL_MODS)
message(STATUS "Skipping installing ${proname}") message(STATUS "Skipping installing ${proname}")
set(INSTALL_ARG "") set(INSTALL_ARG "")
else() else()
@ -124,10 +122,6 @@ function(setup_geode_mod proname)
set(HAS_HEADERS Off) set(HAS_HEADERS Off)
endif() endif()
# Add package target + make output name the mod id
set_target_properties(${proname} PROPERTIES PREFIX "")
set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID})
# todo: figure out how to either not make cmake shit itself and print out --binary path/to/dll "" or # todo: figure out how to either not make cmake shit itself and print out --binary path/to/dll "" or
# make cli not shit itself when it sees that # make cli not shit itself when it sees that
if (HAS_HEADERS) if (HAS_HEADERS)
@ -199,8 +193,9 @@ function(setup_geode_mod proname)
endif() endif()
# Link Geode to the mod # Add package target + make output name the mod id
target_link_libraries(${proname} geode-sdk) set_target_properties(${proname} PROPERTIES PREFIX "")
set_target_properties(${proname} PROPERTIES OUTPUT_NAME ${MOD_ID})
endfunction() endfunction()

View file

@ -30,10 +30,16 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS")
APPLE_SILICON_PROCESSOR x86_64 APPLE_SILICON_PROCESSOR x86_64
) )
# this should be set globally
set(CMAKE_OSX_ARCHITECTURES "x86_64")
# only exists as a global property # only exists as a global property
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14)
target_link_libraries(${PROJECT_NAME} INTERFACE curl "-framework Cocoa") target_link_libraries(${PROJECT_NAME} INTERFACE
curl "-framework Cocoa"
${GEODE_LOADER_PATH}/include/link/libfmod.dylib
)
target_compile_options(${PROJECT_NAME} INTERFACE -fms-extensions #[[-Wno-deprecated]] -Wno-ignored-attributes -Os #[[-flto]] #[[-fvisibility=internal]]) target_compile_options(${PROJECT_NAME} INTERFACE -fms-extensions #[[-Wno-deprecated]] -Wno-ignored-attributes -Os #[[-flto]] #[[-fvisibility=internal]])
set(GEODE_PLATFORM_BINARY "Geode.dylib") set(GEODE_PLATFORM_BINARY "Geode.dylib")

View file

@ -103,7 +103,7 @@ std::string generateAddressHeader(Root& root) {
); );
} }
else if (codegen::getStatus(field) == BindStatus::NeedsBinding) { else if (codegen::getStatus(field) == BindStatus::NeedsBinding) {
if (field.parent.rfind("cocos2d::", 0) == 0 && codegen::platform == Platform::Windows) { if (is_cocos_class(field.parent) && codegen::platform == Platform::Windows) {
address_str = fmt::format("base::getCocos() + 0x{:x}", codegen::platformNumber(fn->binds)); address_str = fmt::format("base::getCocos() + 0x{:x}", codegen::platformNumber(fn->binds));
} }
else { else {

View file

@ -144,7 +144,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
std::string output; std::string output;
for (auto& cls : root.classes) { for (auto& cls : root.classes) {
if (can_find(cls.name, "cocos2d")) if (is_cocos_class(cls.name))
continue; continue;
std::string filename = (codegen::getUnqualifiedClassName(cls.name) + ".hpp"); std::string filename = (codegen::getUnqualifiedClassName(cls.name) + ".hpp");
@ -168,7 +168,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
} }
std::string supers = str_if( std::string supers = str_if(
fmt::format(" : public {}", fmt::join(cls.superclasses, ", ")), fmt::format(" : public {}", fmt::join(cls.superclasses, ", public ")),
!cls.superclasses.empty() !cls.superclasses.empty()
); );
@ -180,7 +180,7 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
// what. // what.
if (!cls.superclasses.empty()) { if (!cls.superclasses.empty()) {
single_output += fmt::format( single_output += fmt::format(
can_find(cls.superclasses[0], "cocos2d") is_cocos_class(cls.superclasses[0])
? format_strings::custom_constructor_cutoff ? format_strings::custom_constructor_cutoff
: format_strings::custom_constructor, : format_strings::custom_constructor,
fmt::arg("class_name", cls.name), fmt::arg("class_name", cls.name),

View file

@ -25,7 +25,7 @@ int main(int argc, char** argv) try {
for (auto cls : root.classes) { for (auto cls : root.classes) {
for (auto dep : cls.depends) { for (auto dep : cls.depends) {
if(!can_find(dep, "cocos2d::") && std::find(root.classes.begin(), root.classes.end(), dep) == root.classes.end()) { if(!is_cocos_class(dep) && std::find(root.classes.begin(), root.classes.end(), dep) == root.classes.end()) {
throw codegen::error("Class {} depends on unknown class {}", cls.name, dep); throw codegen::error("Class {} depends on unknown class {}", cls.name, dep);
} }
} }

View file

@ -74,7 +74,7 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
if (c.name.find("cocos2d::extension") != std::string::npos) { if (c.name.find("cocos2d::extension") != std::string::npos) {
class_include = "#include <cocos-ext.h>"; class_include = "#include <cocos-ext.h>";
} }
else if (c.name.find("cocos2d") != std::string::npos) { else if (is_cocos_class(c.name)) {
class_include = "#include <cocos2d.h>"; class_include = "#include <cocos2d.h>";
} }
else { else {

View file

@ -10,7 +10,7 @@ std::string generatePredeclareHeader(Root& root) {
std::string output("#pragma once\n"); std::string output("#pragma once\n");
for (auto& cls : root.classes) { for (auto& cls : root.classes) {
if (can_find(cls.name, "cocos2d")) if (is_cocos_class(cls.name))
continue; continue;
output += fmt::format(::format_strings::class_predeclare, output += fmt::format(::format_strings::class_predeclare,

View file

@ -51,6 +51,10 @@ inline bool can_find(std::string const& str, char const* text) {
return str.find(text) != std::string::npos; return str.find(text) != std::string::npos;
} }
inline bool is_cocos_class(std::string const& str) {
return can_find(str, "cocos2d") || can_find(str, "pugi::") || str == "DS_Dictionary";
}
enum class BindStatus { enum class BindStatus {
Binded, Binded,
NeedsBinding, NeedsBinding,
@ -112,8 +116,10 @@ namespace codegen {
if (fb->type == FunctionType::Normal) { if (fb->type == FunctionType::Normal) {
if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded; if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded;
if (field.parent.rfind("cocos2d::", 0) == 0 && p == Platform::Windows) if (
return BindStatus::Binded; (field.parent.rfind("cocos2d::", 0) == 0 || field.parent == "DS_Dictionary") &&
p == Platform::Windows
) return BindStatus::Binded;
} }
return BindStatus::Unbindable; return BindStatus::Unbindable;
@ -153,48 +159,6 @@ namespace codegen {
return fmt::format("{}", fmt::join(parameters, ", ")); return fmt::format("{}", fmt::join(parameters, ", "));
} }
inline std::string getConvention(Field& f) {
if (codegen::platform != Platform::Windows) return "DefaultConv";
if (auto fn = f.get_fn()) {
auto status = getStatus(f);
if (fn->is_static) {
if (status == BindStatus::Binded) return "x86::Cdecl";
else return "x86::Optcall";
}
else if (fn->is_virtual || fn->is_callback) {
return "x86::Thiscall";
}
else {
if (status == BindStatus::Binded) return "x86::Thiscall";
else return "x86::Membercall";
}
}
else throw codegen::error("Tried to get convention of non-function");
}
inline std::string getModifyConvention(Field& f) {
if (codegen::platform != Platform::Windows) return "tulip::hook::DefaultConvention";
if (auto fn = f.get_fn()) {
auto status = getStatus(f);
if (fn->is_static) {
if (status == BindStatus::Binded) return "tulip::hook::CdeclConvention";
else return "tulip::hook::OptcallConvention";
}
else if (fn->is_virtual) {
return "tulip::hook::ThiscallConvention";
}
else {
if (status == BindStatus::Binded) return "tulip::hook::ThiscallConvention";
else return "tulip::hook::MembercallConvention";
}
}
else throw codegen::error("Tried to get convention of non-function");
}
inline std::string getModifyConventionName(Field& f) { inline std::string getModifyConventionName(Field& f) {
if (codegen::platform != Platform::Windows) return "Default"; if (codegen::platform != Platform::Windows) return "Default";
@ -205,7 +169,7 @@ namespace codegen {
if (status == BindStatus::Binded) return "Cdecl"; if (status == BindStatus::Binded) return "Cdecl";
else return "Optcall"; else return "Optcall";
} }
else if (fn->is_virtual) { else if (fn->is_virtual || fn->is_callback) {
return "Thiscall"; return "Thiscall";
} }
else { else {
@ -216,6 +180,18 @@ namespace codegen {
else throw codegen::error("Tried to get convention of non-function"); else throw codegen::error("Tried to get convention of non-function");
} }
inline std::string getConvention(Field& f) {
if (codegen::platform != Platform::Windows) return "DefaultConv";
return std::string("x86::") + getModifyConventionName(f);
}
inline std::string getModifyConvention(Field& f) {
if (codegen::platform != Platform::Windows) return "tulip::hook::DefaultConvention";
return std::string("tulip::hook::") + getModifyConventionName(f) + "Convention";
}
inline std::string getUnqualifiedClassName(std::string const& s) { inline std::string getUnqualifiedClassName(std::string const& s) {
auto index = s.rfind("::"); auto index = s.rfind("::");
if (index == std::string::npos) return s; if (index == std::string::npos) return s;

View file

@ -126,7 +126,7 @@ std::string generateBindingSource(Root& root) {
for (auto& f : c.fields) { for (auto& f : c.fields) {
if (auto i = f.get_as<InlineField>()) { if (auto i = f.get_as<InlineField>()) {
if (codegen::platform == Platform::Mac || codegen::platform == Platform::iOS) { if (codegen::platform == Platform::Mac || codegen::platform == Platform::iOS) {
if (can_find(c.name, "cocos2d")) if (is_cocos_class(c.name))
output += i->inner + "\n"; output += i->inner + "\n";
} }
} else if (auto fn = f.get_as<OutOfLineField>()) { } else if (auto fn = f.get_as<OutOfLineField>()) {
@ -134,7 +134,7 @@ std::string generateBindingSource(Root& root) {
continue; continue;
// no cocos2d definitions on windows // no cocos2d definitions on windows
if (codegen::platform == Platform::Windows && f.parent.rfind("cocos2d::", 0) == 0) { if (codegen::platform == Platform::Windows && is_cocos_class(f.parent)) {
continue; continue;
} }
@ -166,7 +166,7 @@ std::string generateBindingSource(Root& root) {
continue; continue;
// no cocos2d definitions on windows // no cocos2d definitions on windows
if (codegen::platform == Platform::Windows && f.parent.rfind("cocos2d::", 0) == 0) { if (codegen::platform == Platform::Windows && is_cocos_class(f.parent)) {
continue; continue;
} }

View file

@ -30,6 +30,7 @@ execute_process(
configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json) configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json)
file(READ resources/mod.json LOADER_MOD_JSON) file(READ resources/mod.json LOADER_MOD_JSON)
file(READ resources/about.md LOADER_ABOUT_MD) file(READ resources/about.md LOADER_ABOUT_MD)
file(READ ${GEODE_ROOT_PATH}/CHANGELOG.md LOADER_CHANGELOG_MD)
configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp) configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp)
# Source files # Source files

View file

@ -285,6 +285,12 @@ public:
*/ */
void resumeTargets(CCSet* targetsToResume); void resumeTargets(CCSet* targetsToResume);
/**
* Get the shared scheduler from CCDirector
* @note Geode addition
*/
static GEODE_DLL CCScheduler* get();
private: private:
void removeHashElement(struct _hashSelectorEntry *pElement); void removeHashElement(struct _hashSelectorEntry *pElement);
void removeUpdateFromHash(struct _listEntry *entry); void removeUpdateFromHash(struct _listEntry *entry);

View file

@ -54,6 +54,7 @@ public:
* @js ctor * @js ctor
*/ */
CCAction(void); CCAction(void);
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCAction, CCObject);
/** /**
* @js NA * @js NA
* @lua NA * @lua NA

View file

@ -38,7 +38,8 @@
#include "../script_support/CCScriptSupport.h" #include "../script_support/CCScriptSupport.h"
#include "../include/CCProtocols.h" #include "../include/CCProtocols.h"
#include "Layout.hpp" #include "Layout.hpp"
#include <any> #include "../../loader/Event.hpp"
#include <json.hpp>
NS_CC_BEGIN NS_CC_BEGIN
@ -850,7 +851,11 @@ private:
friend class geode::modifier::FieldContainer; friend class geode::modifier::FieldContainer;
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); GEODE_DLL geode::modifier::FieldContainer* getFieldContainer();
GEODE_DLL std::optional<std::any> getAttributeInternal(std::string const& attribute); GEODE_DLL std::optional<json::Value> getAttributeInternal(std::string const& attribute);
GEODE_DLL void addEventListenerInternal(
std::string const& id,
geode::EventListenerProtocol* protocol
);
public: public:
/** /**
@ -892,6 +897,7 @@ public:
* @param before The child the node is added before of. If this is null or * @param before The child the node is added before of. If this is null or
* not a child of this node, the new child will be placed at the start of the * not a child of this node, the new child will be placed at the start of the
* child list * child list
* @note Geode addition
*/ */
GEODE_DLL void insertBefore(CCNode* child, CCNode* before); GEODE_DLL void insertBefore(CCNode* child, CCNode* before);
@ -902,9 +908,20 @@ public:
* @param after The child the node is added after of. If this is null or * @param after The child the node is added after of. If this is null or
* not a child of this node, the new child will be placed at the end of the * not a child of this node, the new child will be placed at the end of the
* child list * child list
* @note Geode addition
*/ */
GEODE_DLL void insertAfter(CCNode* child, CCNode* after); GEODE_DLL void insertAfter(CCNode* child, CCNode* after);
/**
* Check if this node's parent or its parents' parent is the given node
* @param ancestor The node whose child or subchild this node should be. If
* nullptr, returns true if the node is in the current scene, otherwise
* false.
* @returns True if ancestor is an ancestor of this node
* @note Geode addition
*/
GEODE_DLL bool hasAncestor(CCNode* ancestor);
/** /**
* Set an attribute on a node. Attributes are a system added by Geode, * Set an attribute on a node. Attributes are a system added by Geode,
* where a node may have any sort of extra data associated with it. Used * where a node may have any sort of extra data associated with it. Used
@ -917,7 +934,7 @@ public:
* @param value The value of the attribute * @param value The value of the attribute
* @note Geode addition * @note Geode addition
*/ */
GEODE_DLL void setAttribute(std::string const& attribute, std::any value); GEODE_DLL void setAttribute(std::string const& attribute, json::Value const& value);
/** /**
* Get an attribute from the node. Attributes may be anything * Get an attribute from the node. Attributes may be anything
* @param attribute The attribute key * @param attribute The attribute key
@ -929,7 +946,7 @@ public:
std::optional<T> getAttribute(std::string const& attribute) { std::optional<T> getAttribute(std::string const& attribute) {
if (auto value = this->getAttributeInternal(attribute)) { if (auto value = this->getAttributeInternal(attribute)) {
try { try {
return std::any_cast<T>(value.value()); return value.value().template as<T>();
} catch(...) { } catch(...) {
return std::nullopt; return std::nullopt;
} }
@ -987,6 +1004,32 @@ public:
*/ */
GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second); GEODE_DLL void swapChildIndices(CCNode* first, CCNode* second);
template <class Filter, class... Args>
geode::EventListenerProtocol* addEventListener(
std::string const& id,
geode::utils::MiniFunction<typename Filter::Callback> callback,
Args&&... args
) {
auto listener = new geode::EventListener<Filter>(
callback, Filter(this, std::forward<Args>(args)...)
);
this->addEventListenerInternal(id, listener);
return listener;
}
template <class Filter, class... Args>
geode::EventListenerProtocol* addEventListener(
geode::utils::MiniFunction<typename Filter::Callback> callback,
Args&&... args
) {
return this->template addEventListener<Filter, Args...>(
"", callback, std::forward<Args>(args)...
);
}
GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener);
GEODE_DLL void removeEventListener(std::string const& id);
GEODE_DLL geode::EventListenerProtocol* getEventListener(std::string const& id);
GEODE_DLL size_t getEventListenerCount();
/// @{ /// @{
/// @name Shader Program /// @name Shader Program
/** /**
@ -1690,4 +1733,27 @@ protected:
NS_CC_END NS_CC_END
namespace geode {
struct GEODE_DLL AttributeSetEvent : public Event {
cocos2d::CCNode* node;
const std::string id;
json::Value& value;
AttributeSetEvent(cocos2d::CCNode* node, std::string const& id, json::Value& value);
};
class GEODE_DLL AttributeSetFilter : public EventFilter<AttributeSetEvent> {
public:
using Callback = void(AttributeSetEvent*);
protected:
std::string m_targetID;
public:
ListenerResult handle(utils::MiniFunction<Callback> fn, AttributeSetEvent* event);
AttributeSetFilter(std::string const& id);
};
}
#endif // __PLATFORM_CCNODE_H__ #endif // __PLATFORM_CCNODE_H__

View file

@ -23,7 +23,9 @@ class CCNode;
*/ */
class GEODE_DLL Layout : public CCObject { class GEODE_DLL Layout : public CCObject {
protected: protected:
static CCArray* getNodesToPosition(CCNode* forNode); CCArray* getNodesToPosition(CCNode* forNode) const;
bool m_ignoreInvisibleChildren = false;
public: public:
/** /**
@ -35,6 +37,14 @@ public:
*/ */
virtual void apply(CCNode* on) = 0; virtual void apply(CCNode* on) = 0;
/**
* Get how much space this layout would like to take up for a given target
*/
virtual CCSize getSizeHint(CCNode* on) const = 0;
void ignoreInvisibleChildren(bool ignore);
bool isIgnoreInvisibleChildren() const;
virtual ~Layout() = default; virtual ~Layout() = default;
}; };
@ -257,6 +267,7 @@ public:
static AxisLayout* create(Axis axis = Axis::Row); static AxisLayout* create(Axis axis = Axis::Row);
void apply(CCNode* on) override; void apply(CCNode* on) override;
CCSize getSizeHint(CCNode* on) const override;
Axis getAxis() const; Axis getAxis() const;
AxisAlignment getAxisAlignment() const; AxisAlignment getAxisAlignment() const;

View file

@ -0,0 +1,59 @@
#pragma once
#include "CCNode.h"
NS_CC_BEGIN
#pragma warning(push)
#pragma warning(disable: 4275)
/**
* A node for controlling spacing in Layouts. When a Layout is applied, if
* space is left over, the remaining space is divided among all SpacerNodes in
* the Layout. The space each node gets is the proprotion between its growth
* factor and the sum of all the SpacerNodes' growth factors in the Layout
* @example
* node->addChild(SpacerNode::create(1));
* node->addChild(SpacerNode::create(2));
* node->addChild(SpacerNode::create(1));
* node->updateLayout();
* // Total SpacerNode growth sum is 1 + 2 + 1 = 4
* // So s1 and s3 get 1/4 of the remaining space and s2 gets 2/4
* @note If you want to specify a minimum width for a SpacerNode, add
* AxisLayoutOptions for it and use setLength
*/
class GEODE_DLL SpacerNode : public CCNode {
protected:
size_t m_grow;
bool init(size_t grow);
public:
/**
* Create a new spacer node. When the layout is applied,
* if there is space left over the remaining space is distributed among
* all spacer nodes in proportion to the sum of all the spacers' grow
* factors (akin to CSS flew grow)
* @param grow The grow factor for this node. Default is 1
*/
static SpacerNode* create(size_t grow = 1);
/**
* Set the grow factor for this spacer node. When the layout is applied,
* if there is space left over the remaining space is distributed among
* all spacer nodes in proportion to the sum of all the spacers' grow
* factors (akin to CSS flew grow)
* @param grow The new grow factor for this node. Default is 1
* @note Make sure to call updateLayout on the spacer's parent afterwards
*/
void setGrow(size_t grow);
/**
* Get the grow factor for this spacer node
*/
size_t getGrow() const;
};
#pragma warning(pop)
NS_CC_END

View file

@ -177,12 +177,10 @@ public:
unsigned int indexOfObject(CCObject* object) const; unsigned int indexOfObject(CCObject* object) const;
/** Returns an element with a certain index */ /** Returns an element with a certain index */
CCObject* objectAtIndex(unsigned int index); CCObject* objectAtIndex(unsigned int index);
RT_ADD(
/** /**
* Rob modification * Rob modification
* Returns an element with a certain index casted to CCString */ * Returns an element with a certain index casted to CCString */
CCString* stringAtIndex(unsigned int index); CCString* stringAtIndex(unsigned int index);
);
/** /**
* Returns first element, or null if empty * Returns first element, or null if empty
@ -202,12 +200,10 @@ public:
/** Add a certain object */ /** Add a certain object */
void addObject(CCObject* object); void addObject(CCObject* object);
RT_ADD(
/** /**
* Rob modification * Rob modification
* Add a certain object */ * Add a certain object */
void addObjectNew(CCObject* object); void addObjectNew(CCObject* object);
);
/** Add all elements of an existing array */ /** Add all elements of an existing array */
void addObjectsFromArray(CCArray* otherArray); void addObjectsFromArray(CCArray* otherArray);
/** Insert a certain object at a certain index */ /** Insert a certain object at a certain index */

View file

@ -47,14 +47,13 @@ NS_CC_BEGIN
* @{ * @{
*/ */
RT_ADD(
// please someone tell we why in higher being(s)'s name rob did this // please someone tell we why in higher being(s)'s name rob did this
enum class CCObjectType { enum class CCObjectType {
PlayLayer = 5, PlayLayer = 5,
LevelEditorLayer = 6, LevelEditorLayer = 6,
GameObject = 13,
MenuLayer = 15, MenuLayer = 15,
}; };
)
class CCZone; class CCZone;
class CCObject; class CCObject;
@ -101,16 +100,14 @@ public:
int m_nLuaID; int m_nLuaID;
protected: protected:
// the object's tag // the object's tag
RT_ADD( int m_nTag; ) int m_nTag;
// count of references // count of references
unsigned int m_uReference; unsigned int m_uReference;
// count of autorelease // count of autorelease
unsigned int m_uAutoReleaseCount; unsigned int m_uAutoReleaseCount;
RT_ADD(
CCObjectType m_eObjType; CCObjectType m_eObjType;
int m_nUnknown; int m_nUnknown;
)
public: public:
GEODE_CUSTOM_CONSTRUCTOR_BEGIN(CCObject) GEODE_CUSTOM_CONSTRUCTOR_BEGIN(CCObject)
CCObject(void); CCObject(void);
@ -124,21 +121,24 @@ public:
CCObject* autorelease(void); CCObject* autorelease(void);
CCObject* copy(void); CCObject* copy(void);
bool isSingleReference(void) const; bool isSingleReference(void) const;
inline unsigned int retainCount(void) const; inline unsigned int retainCount(void) const {
return m_uReference;
}
virtual bool isEqual(const CCObject* pObject); virtual bool isEqual(const CCObject* pObject);
virtual void acceptVisitor(CCDataVisitor &visitor); virtual void acceptVisitor(CCDataVisitor &visitor);
virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; virtual void update(float dt) {CC_UNUSED_PARAM(dt);};
RT_ADD(
virtual void encodeWithCoder(DS_Dictionary*); virtual void encodeWithCoder(DS_Dictionary*);
static CCObject* createWithCoder(DS_Dictionary*); static CCObject* createWithCoder(DS_Dictionary*);
virtual bool canEncode(); virtual bool canEncode();
CCObjectType getObjType() const; inline CCObjectType getObjType() const {
return m_eObjType;
}
virtual int getTag() const; virtual int getTag() const;
@ -147,7 +147,6 @@ public:
inline void setObjType(CCObjectType type) { inline void setObjType(CCObjectType type) {
m_eObjType = type; m_eObjType = type;
} }
)
friend class CCAutoreleasePool; friend class CCAutoreleasePool;
}; };

View file

@ -59,6 +59,7 @@ THE SOFTWARE.
// base_nodes // base_nodes
#include "../base_nodes/CCNode.h" #include "../base_nodes/CCNode.h"
#include "../base_nodes/CCAtlasNode.h" #include "../base_nodes/CCAtlasNode.h"
#include "../base_nodes/SpacerNode.hpp"
// cocoa // cocoa
#include "../cocoa/CCAffineTransform.h" #include "../cocoa/CCAffineTransform.h"

View file

@ -72,16 +72,18 @@ public:
bool init(); bool init();
static CCScene* create(void); static CCScene* create(void);
/**
* Get the running scene
* @note Geode addition
*/
static GEODE_DLL CCScene* get();
RT_ADD(
CCScene(const CCScene&); CCScene(const CCScene&);
CCScene& operator=(const CCScene&); CCScene& operator=(const CCScene&);
int getHighestChildZ(void); int getHighestChildZ(void);
CCSceneDelegate* m_pDelegate; CCSceneDelegate* m_pDelegate;
)
}; };
// end of scene group // end of scene group

View file

@ -115,6 +115,8 @@ public:
bool isInverted() const; bool isInverted() const;
void setInverted(bool bInverted); void setInverted(bool bInverted);
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCClippingNode, CCNode);
protected: protected:
CCClippingNode(); CCClippingNode();
}; };

View file

@ -42,14 +42,11 @@ public:
*/ */
virtual TargetPlatform getTargetPlatform(); virtual TargetPlatform getTargetPlatform();
RT_ADD(
virtual void openURL(const char* url); virtual void openURL(const char* url);
virtual int run(); virtual int run();
virtual void setupGLView(); virtual void setupGLView();
virtual void platformShutdown(); virtual void platformShutdown();
void toggleVerticalSync(bool); void toggleVerticalSync(bool);
bool getVerticalSyncEnabled() const;
)
/** /**
* Sets the Resource root path. * Sets the Resource root path.
@ -65,8 +62,6 @@ public:
void setStartupScriptFilename(const gd::string& startupScriptFile); void setStartupScriptFilename(const gd::string& startupScriptFile);
bool getControllerConnected() const;
const gd::string& getStartupScriptFilename(void) const gd::string& getStartupScriptFilename(void)
{ {
return m_startupScriptFilename; return m_startupScriptFilename;
@ -76,8 +71,24 @@ protected:
HINSTANCE m_hInstance; HINSTANCE m_hInstance;
HACCEL m_hAccelTable; HACCEL m_hAccelTable;
LARGE_INTEGER m_nAnimationInterval; LARGE_INTEGER m_nAnimationInterval;
gd::string m_resourceRootPath; PAD(4);
gd::string m_startupScriptFilename; std::string m_resourceRootPath;
std::string m_startupScriptFilename;
void* m_pUnknown;
bool m_bUpdateController;
CC_SYNTHESIZE_NV(bool, m_bShutdownCalled, ShutdownCalled);
INPUT m_iInput;
CCPoint m_obUnknown1;
CCPoint m_obUnknown2;
bool m_bMouseControl;
float m_fOldAnimationInterval;
float m_fAnimationInterval;
CC_SYNTHESIZE_READONLY_NV(bool, m_bVerticalSyncEnabled, VerticalSyncEnabled);
CC_SYNTHESIZE_READONLY_NV(bool, m_bControllerConnected, ControllerConnected);
CC_SYNTHESIZE_NV(bool, m_bSleepMode, SleepMode);
CC_SYNTHESIZE_NV(bool, m_bForceTimer, ForceTimer);
CC_SYNTHESIZE_NV(bool, m_bSmoothFix, SmoothFix);
CC_SYNTHESIZE_NV(bool, m_bFullscreen, Fullscreen);
static CCApplication * sm_pSharedApplication; static CCApplication * sm_pSharedApplication;
}; };

View file

@ -63,6 +63,8 @@ public:
protected: protected:
RT_REMOVE( virtual bool Create(); ) RT_REMOVE( virtual bool Create(); )
void setupWindow(cocos2d::CCRect rect);
public: public:
bool initGL(); bool initGL();
void destroyGL(); void destroyGL();

View file

@ -21,6 +21,7 @@ public:
public: public:
DS_Dictionary(); DS_Dictionary();
~DS_Dictionary(); ~DS_Dictionary();
GEODE_CUSTOM_CONSTRUCTOR_BEGIN(DS_Dictionary)
static void copyFile(const char*, const char*); static void copyFile(const char*, const char*);

View file

@ -371,6 +371,7 @@ namespace pugi
public: public:
// Default constructor. Constructs an empty node. // Default constructor. Constructs an empty node.
xml_node(); xml_node();
GEODE_CUSTOM_CONSTRUCTOR_BEGIN(xml_node);
// Constructs node from internal pointer // Constructs node from internal pointer
explicit xml_node(xml_node_struct* p); explicit xml_node(xml_node_struct* p);
@ -852,6 +853,7 @@ namespace pugi
{ {
private: private:
char_t* _buffer; char_t* _buffer;
GEODE_CUSTOM_CONSTRUCTOR_COCOS(xml_document, xml_node);
char _memory[192]; char _memory[192];

View file

@ -47,13 +47,13 @@ typedef enum
} ccTouchSelectorFlag; } ccTouchSelectorFlag;
enum { enum ccTouchType {
CCTOUCHBEGAN, CCTOUCHBEGAN = 0,
CCTOUCHMOVED, CCTOUCHMOVED = 1,
CCTOUCHENDED, CCTOUCHENDED = 2,
CCTOUCHCANCELLED, CCTOUCHCANCELLED = 3,
ccTouchMax, ccTouchMax = 4,
}; };
class CCSet; class CCSet;

View file

@ -9,42 +9,41 @@
namespace geode { namespace geode {
// Mod interoperability // Mod interoperability
// todo: update to new event system template <class... Args>
class DispatchEvent : public Event {
protected:
std::string m_id;
std::tuple<Args...> m_args;
// template <typename... Args> public:
// class DispatchEvent : public Event { DispatchEvent(std::string const& id, Args&&... args)
// std::string m_selector; : m_id(id), m_args(std::make_tuple(args...)) {}
// std::tuple<Args...> m_args;
// public: std::tuple<Args...> getArgs() const {
// DispatchEvent(std::string const& name, Args... args) : return m_args;
// m_selector(name), m_args(std::make_tuple(args...)) {} }
// std::string const& selector() { std::string getID() const {
// return m_selector; return m_id;
// } }
// }; };
// template <typename... Args> template <class... Args>
// class DispatchHandler : public EventHandler<DispatchEvent<Args...>> { class DispatchFilter : public EventFilter<DispatchEvent<Args...>> {
// std::string m_selector; protected:
// utils::MiniFunction<void(Args...)> m_callback; std::string m_id;
// DispatchHandler(std::string const& name, utils::MiniFunction<void(Args...)> callback) : public:
// m_selector(name), m_callback(callback) {} using Ev = DispatchEvent<Args...>;
using Callback = ListenerResult(Args...);
// public:
// bool handle(DispatchEvent<Args...>* ev) { ListenerResult handle(utils::MiniFunction<Callback> fn, Ev* event) {
// if (ev->name() == m_selector) { if (event->getID() == m_id) {
// std::apply(m_callback, ev->m_args); return std::apply(fn, event->getArgs());
// } }
// return true; return ListenerResult::Propagate;
// } }
// static DispatchHandler* create( DispatchFilter(std::string const& id) : m_id(id) {}
// std::string const& name, utils::MiniFunction<void(Args...)> callback };
// ) {
// return new DispatchHandler(name, callback);
// }
// };
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../utils/casts.hpp" #include "../utils/casts.hpp"
#include "../utils/MiniFunction.hpp"
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#include <type_traits> #include <type_traits>
@ -9,6 +10,7 @@
namespace geode { namespace geode {
class Mod; class Mod;
class Event; class Event;
class EventListenerProtocol;
Mod* getMod(); Mod* getMod();
@ -17,10 +19,41 @@ namespace geode {
Stop Stop
}; };
struct GEODE_DLL EventListenerProtocol { struct GEODE_DLL EventListenerPool {
virtual void enable(); virtual bool add(EventListenerProtocol* listener) = 0;
virtual void disable(); virtual void remove(EventListenerProtocol* listener) = 0;
virtual ListenerResult passThrough(Event*) = 0; virtual void handle(Event* event) = 0;
virtual ~EventListenerPool() = default;
EventListenerPool() = default;
EventListenerPool(EventListenerPool const&) = delete;
EventListenerPool(EventListenerPool&&) = delete;
};
class GEODE_DLL DefaultEventListenerPool : public EventListenerPool {
protected:
std::atomic_size_t m_locked = 0;
std::vector<EventListenerProtocol*> m_listeners;
std::vector<EventListenerProtocol*> m_toAdd;
public:
bool add(EventListenerProtocol* listener) override;
void remove(EventListenerProtocol* listener) override;
void handle(Event* event) override;
static DefaultEventListenerPool* get();
};
class GEODE_DLL EventListenerProtocol {
private:
EventListenerPool* m_pool = nullptr;
public:
bool enable();
void disable();
virtual EventListenerPool* getPool() const;
virtual ListenerResult handle(Event*) = 0;
virtual ~EventListenerProtocol(); virtual ~EventListenerProtocol();
}; };
@ -44,6 +77,10 @@ namespace geode {
ListenerResult handle(utils::MiniFunction<Callback> fn, T* e) { ListenerResult handle(utils::MiniFunction<Callback> fn, T* e) {
return fn(e); return fn(e);
} }
EventListenerPool* getPool() const {
return DefaultEventListenerPool::get();
}
}; };
template <typename T> template <typename T>
@ -60,9 +97,8 @@ namespace geode {
requires std::is_class_v<C> requires std::is_class_v<C>
using MemberFn = typename to_member<C, Callback>::value; using MemberFn = typename to_member<C, Callback>::value;
ListenerResult passThrough(Event* e) override { ListenerResult handle(Event* e) override {
if (m_callback) { if (m_callback) {
// it is so silly to use dynamic cast in an interbinary context
if (auto myev = cast::typeinfo_cast<typename T::Event*>(e)) { if (auto myev = cast::typeinfo_cast<typename T::Event*>(e)) {
return m_filter.handle(m_callback, myev); return m_filter.handle(m_callback, myev);
} }
@ -70,6 +106,10 @@ namespace geode {
return ListenerResult::Propagate; return ListenerResult::Propagate;
} }
EventListenerPool* getPool() const override {
return m_filter.getPool();
}
EventListener(T filter = T()) { EventListener(T filter = T()) {
this->enable(); this->enable();
} }
@ -119,6 +159,14 @@ namespace geode {
m_filter = filter; m_filter = filter;
} }
T getFilter() const {
return m_filter;
}
utils::MiniFunction<Callback>& getCallback() {
return m_callback;
}
protected: protected:
utils::MiniFunction<Callback> m_callback = nullptr; utils::MiniFunction<Callback> m_callback = nullptr;
T m_filter; T m_filter;
@ -126,9 +174,11 @@ namespace geode {
class GEODE_DLL [[nodiscard]] Event { class GEODE_DLL [[nodiscard]] Event {
private: private:
static std::unordered_set<EventListenerProtocol*>& listeners();
friend EventListenerProtocol; friend EventListenerProtocol;
protected:
virtual EventListenerPool* getPool() const;
public: public:
Mod* sender; Mod* sender;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Types.hpp" #include "Types.hpp"
#include "../utils/Result.hpp"
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#include <Geode/utils/ranges.hpp> #include <Geode/utils/ranges.hpp>
@ -71,6 +72,24 @@ namespace geode {
return "nullopt"; return "nullopt";
} }
template <class T>
requires requires(T t) {
parse(t);
}
std::string parse(std::vector<T> const& thing) {
std::string res = "[";
bool first = true;
for (auto& t : thing) {
if (!first) {
res += ", ";
}
first = false;
res += parse(t);
}
res += "]";
return res;
}
template <class A, class B> template <class A, class B>
requires requires(A a, B b) { requires requires(A a, B b) {
parse(a); parse(a);
@ -187,9 +206,7 @@ namespace geode {
template <typename... Args> template <typename... Args>
void debug(Args... args) { void debug(Args... args) {
#ifdef GEODE_DEBUG
internalLog(Severity::Debug, getMod(), args...); internalLog(Severity::Debug, getMod(), args...);
#endif
} }
template <typename... Args> template <typename... Args>

View file

@ -203,6 +203,7 @@ namespace geode {
CircleBaseColor color = CircleBaseColor::Green, CircleBaseColor color = CircleBaseColor::Green,
CircleBaseSize size = CircleBaseSize::Medium CircleBaseSize size = CircleBaseSize::Medium
); );
cocos2d::CCSize getMaxTopSize() const override;
}; };
/** /**

View file

@ -25,7 +25,7 @@ struct json::Serialize<cocos2d::ccColor4B> {
}; };
// operators for CC geometry // operators for CC geometry
namespace geode { namespace cocos2d {
static cocos2d::CCPoint& operator*=(cocos2d::CCPoint& pos, float mul) { static cocos2d::CCPoint& operator*=(cocos2d::CCPoint& pos, float mul) {
pos.x *= mul; pos.x *= mul;
pos.y *= mul; pos.y *= mul;
@ -356,6 +356,151 @@ namespace geode {
} }
}; };
class GEODE_DLL WeakRefPool {
std::unordered_set<cocos2d::CCObject*> m_pool;
public:
static WeakRefPool* get();
bool isManaged(cocos2d::CCObject* obj);
void manage(cocos2d::CCObject* obj);
void check(cocos2d::CCObject* obj);
};
/**
* A smart pointer to a managed CCObject-deriving class. Like Ref, except
* only holds a weak reference to the targeted object. When all non-weak
* references (Refs, manual retain() calls) to the object are dropped, so
* are all weak references.
*
* In essence, WeakRef is like a raw pointer, except that you can know if
* the pointer is still valid or not, as WeakRef::lock() returns nullptr if
* the pointed-to-object has already been freed.
*
* Note that an object pointed to by WeakRef is only released once some
* WeakRef pointing to it checks for it after all other references to the
* object have been dropped. If you store WeakRefs in a global map, you may
* want to periodically lock all of them to make sure any memory that should
* be freed is freed.
*
* @tparam T A type that inherits from CCObject.
*/
template <class T>
class WeakRef final {
static_assert(
std::is_base_of_v<cocos2d::CCObject, T>,
"WeakRef can only be used with a CCObject-inheriting class!"
);
T* m_obj = nullptr;
public:
/**
* Construct a WeakRef of an object. A weak reference is one that will
* be valid as long as the object is referenced by other strong
* references (such as Ref or manual retain calls), but once all strong
* references are dropped, so are all weak references. The object is
* freed once no strong references exist to it, and any WeakRef pointing
* to it is freed or locked
* @param obj Object to construct the WeakRef from
*/
WeakRef(T* obj) : m_obj(obj) {
WeakRefPool::get()->manage(obj);
}
WeakRef(WeakRef<T> const& other) : WeakRef(other.m_obj) {}
WeakRef(WeakRef<T>&& other) : m_obj(other.m_obj) {
other.m_obj = nullptr;
}
/**
* Construct an empty WeakRef (the object will be null)
*/
WeakRef() = default;
~WeakRef() {
WeakRefPool::get()->check(m_obj);
}
/**
* Lock the WeakRef, returning a Ref if the pointed object is valid or
* a null Ref if the object has been freed
*/
Ref<T> lock() const {
if (WeakRefPool::get()->isManaged(m_obj)) {
return Ref(m_obj);
}
return Ref<T>(nullptr);
}
/**
* Check if the WeakRef points to a valid object
*/
bool valid() const {
return WeakRefPool::get()->isManaged(m_obj);
}
/**
* Swap the managed object with another object. The managed object
* will be released, and the new object retained
* @param other The new object to swap to
*/
void swap(T* other) {
WeakRefPool::get()->check(m_obj);
m_obj = other;
WeakRefPool::get()->manage(other);
}
Ref<T> operator=(T* obj) {
this->swap(obj);
return this->lock();
}
WeakRef<T>& operator=(WeakRef<T> const& other) {
this->swap(other.m_obj);
return *this;
}
WeakRef<T>& operator=(WeakRef<T>&& other) {
this->swap(other.m_obj);
return *this;
}
explicit operator bool() const noexcept {
return this->valid();
}
bool operator==(T* other) const {
return m_obj == other;
}
bool operator==(WeakRef<T> const& other) const {
return m_obj == other.m_obj;
}
bool operator!=(T* other) const {
return m_obj != other;
}
bool operator!=(WeakRef<T> const& other) const {
return m_obj != other.m_obj;
}
// for containers
bool operator<(WeakRef<T> const& other) const {
return m_obj < other.m_obj;
}
bool operator<=(WeakRef<T> const& other) const {
return m_obj <= other.m_obj;
}
bool operator>(WeakRef<T> const& other) const {
return m_obj > other.m_obj;
}
bool operator>=(WeakRef<T> const& other) const {
return m_obj >= other.m_obj;
}
};
template <class Filter> template <class Filter>
class EventListenerNode : public cocos2d::CCNode { class EventListenerNode : public cocos2d::CCNode {
protected: protected:
@ -375,8 +520,8 @@ namespace geode {
return nullptr; return nullptr;
} }
static EventListenerNode* create(typename Filter::Callback callback) { static EventListenerNode* create(typename Filter::Callback callback, Filter filter = Filter()) {
auto ret = new EventListenerNode(EventListener<Filter>(callback)); auto ret = new EventListenerNode(EventListener<Filter>(callback, filter));
if (ret && ret->init()) { if (ret && ret->init()) {
ret->autorelease(); ret->autorelease();
return ret; return ret;
@ -385,7 +530,6 @@ namespace geode {
return nullptr; return nullptr;
} }
template <class C> template <class C>
static EventListenerNode* create( static EventListenerNode* create(
C* cls, typename EventListener<Filter>::template MemberFn<C> callback C* cls, typename EventListener<Filter>::template MemberFn<C> callback

View file

@ -65,7 +65,7 @@ namespace geode::utils::web {
* A handle to an in-progress sent asynchronous web request. Use this to * A handle to an in-progress sent asynchronous web request. Use this to
* cancel the request / query information about it * cancel the request / query information about it
*/ */
class SentAsyncWebRequest { class GEODE_DLL SentAsyncWebRequest {
private: private:
class Impl; class Impl;
std::shared_ptr<Impl> m_impl; std::shared_ptr<Impl> m_impl;

View file

@ -37,4 +37,12 @@ CCTextureCache* CCTextureCache::get() {
return CCTextureCache::sharedTextureCache(); return CCTextureCache::sharedTextureCache();
} }
CCScene* CCScene::get() {
return CCDirector::get()->getRunningScene();
}
CCScheduler* CCScheduler::get() {
return CCDirector::get()->getScheduler();
}
#pragma warning(pop) #pragma warning(pop)

View file

@ -37,11 +37,35 @@ void CCNode::insertAfter(CCNode* child, CCNode* after) {
} }
} }
CCArray* Layout::getNodesToPosition(CCNode* on) { bool CCNode::hasAncestor(CCNode* ancestor) {
if (!on->getChildren()) { if (!ancestor) {
return CCArray::create(); ancestor = CCScene::get();
} }
return on->getChildren()->shallowCopy(); if (m_pParent == ancestor) {
return true;
}
if (m_pParent) {
return m_pParent->hasAncestor(ancestor);
}
return false;
}
CCArray* Layout::getNodesToPosition(CCNode* on) const {
auto arr = CCArray::create();
for (auto child : CCArrayExt<CCNode>(on->getChildren())) {
if (!m_ignoreInvisibleChildren || child->isVisible()) {
arr->addObject(child);
}
}
return arr;
}
void Layout::ignoreInvisibleChildren(bool ignore) {
m_ignoreInvisibleChildren = ignore;
}
bool Layout::isIgnoreInvisibleChildren() const {
return m_ignoreInvisibleChildren;
} }
static AxisLayoutOptions const* axisOpts(CCNode* node) { static AxisLayoutOptions const* axisOpts(CCNode* node) {
@ -152,6 +176,32 @@ struct AxisLayout::Row : public CCObject {
{ {
this->autorelease(); this->autorelease();
} }
void accountSpacers(Axis axis, float availableLength) {
std::vector<SpacerNode*> spacers;
for (auto& node : CCArrayExt<CCNode>(nodes)) {
if (auto spacer = typeinfo_cast<SpacerNode*>(node)) {
spacers.push_back(spacer);
}
}
if (spacers.size()) {
auto unusedSpace = availableLength - this->axisLength;
size_t sum = 0;
for (auto& spacer : spacers) {
sum += spacer->getGrow();
}
for (auto& spacer : spacers) {
auto size = unusedSpace * spacer->getGrow() / static_cast<float>(sum);
if (axis == Axis::Row) {
spacer->setContentSize({ size, this->crossLength });
}
else {
spacer->setContentSize({ this->crossLength, size });
}
}
this->axisLength = availableLength;
}
}
}; };
struct AxisPosition { struct AxisPosition {
@ -171,6 +221,9 @@ static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) {
if (auto toggle = typeinfo_cast<CCMenuItemToggler*>(node)) { if (auto toggle = typeinfo_cast<CCMenuItemToggler*>(node)) {
scaledSize = toggle->m_offButton->getScaledContentSize(); scaledSize = toggle->m_offButton->getScaledContentSize();
} }
if (auto spacer = typeinfo_cast<SpacerNode*>(node)) {
scaledSize = CCSizeZero;
}
auto anchor = node->getAnchorPoint(); auto anchor = node->getAnchorPoint();
if (axis == Axis::Row) { if (axis == Axis::Row) {
return AxisPosition { return AxisPosition {
@ -587,6 +640,8 @@ void AxisLayout::tryFitLayout(
float rowEvenSpace = available.crossLength / rows->count(); float rowEvenSpace = available.crossLength / rows->count();
for (auto row : CCArrayExt<Row*>(rows)) { for (auto row : CCArrayExt<Row*>(rows)) {
row->accountSpacers(m_axis, available.axisLength);
if (m_crossAlignment == AxisAlignment::Even) { if (m_crossAlignment == AxisAlignment::Even) {
rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2; rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2;
} }
@ -732,6 +787,24 @@ void AxisLayout::apply(CCNode* on) {
); );
} }
CCSize AxisLayout::getSizeHint(CCNode* on) const {
// Ideal is single row / column with no scaling
auto nodes = getNodesToPosition(on);
float length = 0.f;
float cross = 0.f;
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
auto axis = nodeAxis(node, m_axis, 1.f);
length += axis.axisLength;
cross += axis.crossLength;
}
if (m_axis == Axis::Row) {
return { length, cross };
}
else {
return { cross, length };
}
}
AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {} AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {}
Axis AxisLayout::getAxis() const { Axis AxisLayout::getAxis() const {
@ -945,3 +1018,30 @@ AxisLayoutOptions* AxisLayoutOptions::setScalePriority(int priority) {
m_scalePriority = priority; m_scalePriority = priority;
return this; return this;
} }
bool SpacerNode::init(size_t grow) {
if (!CCNode::init())
return false;
m_grow = grow;
return true;
}
SpacerNode* SpacerNode::create(size_t grow) {
auto ret = new SpacerNode;
if (ret && ret->init(grow)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void SpacerNode::setGrow(size_t grow) {
m_grow = grow;
}
size_t SpacerNode::getGrow() const {
return m_grow;
}

View file

@ -21,7 +21,9 @@ private:
std::string m_id = ""; std::string m_id = "";
Ref<Layout> m_layout = nullptr; Ref<Layout> m_layout = nullptr;
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr; std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
std::unordered_map<std::string, std::any> m_attributes; std::unordered_map<std::string, json::Value> m_attributes;
std::unordered_set<std::unique_ptr<EventListenerProtocol>> m_eventListeners;
std::unordered_map<std::string, std::unique_ptr<EventListenerProtocol>> m_idEventListeners;
friend class ProxyCCNode; friend class ProxyCCNode;
friend class cocos2d::CCNode; friend class cocos2d::CCNode;
@ -165,11 +167,25 @@ void CCNode::updateLayout(bool updateChildOrder) {
} }
} }
void CCNode::setAttribute(std::string const& attr, std::any value) { AttributeSetEvent::AttributeSetEvent(CCNode* node, std::string const& id, json::Value& value)
GeodeNodeMetadata::set(this)->m_attributes[attr] = value; : node(node), id(id), value(value) {}
ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, AttributeSetEvent* event) {
if (event->id == m_targetID) {
fn(event);
}
return ListenerResult::Propagate;
} }
std::optional<std::any> CCNode::getAttributeInternal(std::string const& attr) { AttributeSetFilter::AttributeSetFilter(std::string const& id) : m_targetID(id) {}
void CCNode::setAttribute(std::string const& attr, json::Value const& value) {
auto meta = GeodeNodeMetadata::set(this);
meta->m_attributes[attr] = value;
AttributeSetEvent(this, attr, meta->m_attributes.at(attr)).post();
}
std::optional<json::Value> CCNode::getAttributeInternal(std::string const& attr) {
auto meta = GeodeNodeMetadata::set(this); auto meta = GeodeNodeMetadata::set(this);
if (meta->m_attributes.count(attr)) { if (meta->m_attributes.count(attr)) {
return meta->m_attributes.at(attr); return meta->m_attributes.at(attr);
@ -177,4 +193,49 @@ std::optional<std::any> CCNode::getAttributeInternal(std::string const& attr) {
return std::nullopt; return std::nullopt;
} }
void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) {
auto meta = GeodeNodeMetadata::set(this);
if (id.size()) {
if (meta->m_idEventListeners.contains(id)) {
meta->m_idEventListeners.at(id).reset(listener);
}
else {
meta->m_idEventListeners.emplace(id, listener);
}
}
else {
std::erase_if(meta->m_eventListeners, [=](auto& l) {
return l.get() == listener;
});
meta->m_eventListeners.emplace(listener);
}
}
void CCNode::removeEventListener(EventListenerProtocol* listener) {
auto meta = GeodeNodeMetadata::set(this);
std::erase_if(meta->m_eventListeners, [=](auto& l) {
return l.get() == listener;
});
std::erase_if(meta->m_idEventListeners, [=](auto& l) {
return l.second.get() == listener;
});
}
void CCNode::removeEventListener(std::string const& id) {
GeodeNodeMetadata::set(this)->m_idEventListeners.erase(id);
}
EventListenerProtocol* CCNode::getEventListener(std::string const& id) {
auto meta = GeodeNodeMetadata::set(this);
if (meta->m_idEventListeners.contains(id)) {
return meta->m_idEventListeners.at(id).get();
}
return nullptr;
}
size_t CCNode::getEventListenerCount() {
return GeodeNodeMetadata::set(this)->m_idEventListeners.size() +
GeodeNodeMetadata::set(this)->m_eventListeners.size();
}
#pragma warning(pop) #pragma warning(pop)

View file

@ -0,0 +1,40 @@
#include "AddIDs.hpp"
#include <Geode/Bindings.hpp>
#include <Geode/modify/CustomSongWidget.hpp>
#include <Geode/utils/cocos.hpp>
using namespace geode::prelude;
$register_ids(CustomSongWidget) {
setIDSafe<CCScale9Sprite>(this, 0, "bg");
setIDSafe<CCSprite>(this, 0, "loading-bar");
setIDSafe<CCLabelBMFont>(this, 0, "song-name-label");
setIDSafe<CCLabelBMFont>(this, 1, "author-name-label");
setIDSafe<CCLabelBMFont>(this, 2, "id-and-size-label");
setIDSafe<CCLabelBMFont>(this, 3, "error-label");
setIDSafe<CCMenu>(this, 0, "buttons-menu");
auto customSongWidgetMenu = this->getChildByID("buttons-menu");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 0, "download-button");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 1, "cancel-button");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 2, "use-button");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 3, "refresh-button");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 4, "play-song-button");
setIDSafe<CCMenuItemSpriteExtra>(customSongWidgetMenu, 5, "more-button");
};
struct CustomSongWidgetIDs : Modify<CustomSongWidgetIDs, CustomSongWidget> {
static void onModify(auto& self) {
if (!self.setHookPriority("CustomSongWidget::init", GEODE_ID_PRIORITY)) {
log::warn("Failed to set CustomSongWidget::init hook priority, node IDs may not work properly");
}
}
bool init(SongInfoObject* s, LevelSettingsObject* l, bool b1, bool b2, bool b3, bool b4, bool hideBackground) {
if (!CustomSongWidget::init(s, l, b1, b2, b3, b4, hideBackground)) return false;
NodeIDs::get()->provide(this);
return true;
}
};

View file

@ -31,9 +31,29 @@ $register_ids(EditLevelLayer) {
); );
auto winSize = CCDirector::get()->getWinSize(); auto winSize = CCDirector::get()->getWinSize();
auto descBG = this->getChildByID("description-background");
auto descMenu = CCMenu::create();
descMenu->setID("description-menu");
descMenu->setLayout(ColumnLayout::create());
descMenu->setPosition(
descBG->getPositionX() - descBG->getScaledContentSize().width / 2 - 35.f,
descBG->getPositionY()
);
descMenu->setContentSize({ 40.f, 80.f });
this->addChild(descMenu);
if (auto menu = this->getChildByID("level-edit-menu")) { if (auto menu = this->getChildByID("level-edit-menu")) {
setIDs(menu, 0, "edit-button", "play-button", "share-button"); setIDs(menu, 0, "edit-button", "play-button", "share-button");
if (menu->getChildrenCount() == 4) {
auto btn = static_cast<CCNode*>(menu->getChildren()->objectAtIndex(3));
btn->setID("update-desc-button");
btn->retain();
btn->removeFromParent();
descMenu->addChild(btn);
btn->release();
descMenu->updateLayout();
}
menu->setContentSize({ winSize.width - 160.f, 100.f }); menu->setContentSize({ winSize.width - 160.f, 100.f });
menu->setLayout(RowLayout::create()->setGap(25.f)); menu->setLayout(RowLayout::create()->setGap(25.f));
} }

View file

@ -3,6 +3,7 @@
#include <Geode/utils/VersionInfo.hpp> #include <Geode/utils/VersionInfo.hpp>
static constexpr const char* LOADER_ABOUT_MD = R"MD_SEPARATOR(@LOADER_ABOUT_MD@)MD_SEPARATOR"; static constexpr const char* LOADER_ABOUT_MD = R"MD_SEPARATOR(@LOADER_ABOUT_MD@)MD_SEPARATOR";
static constexpr const char* LOADER_CHANGELOG_MD = R"MD_SEPARATOR(@LOADER_CHANGELOG_MD@)MD_SEPARATOR";
static constexpr const char* LOADER_VERSION_STR = "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@"; static constexpr const char* LOADER_VERSION_STR = "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@";
static constexpr int LOADER_VERSION_MAJOR = @PROJECT_VERSION_MAJOR@; static constexpr int LOADER_VERSION_MAJOR = @PROJECT_VERSION_MAJOR@;
static constexpr int LOADER_VERSION_MINOR = @PROJECT_VERSION_MINOR@; static constexpr int LOADER_VERSION_MINOR = @PROJECT_VERSION_MINOR@;

View file

@ -1,13 +1,74 @@
#include <Geode/loader/Event.hpp> #include <Geode/loader/Event.hpp>
#include <Geode/utils/ranges.hpp>
#include <mutex>
using namespace geode::prelude; using namespace geode::prelude;
void EventListenerProtocol::enable() { bool DefaultEventListenerPool::add(EventListenerProtocol* listener) {
Event::listeners().insert(this); if (m_locked) {
m_toAdd.push_back(listener);
}
else {
m_listeners.push_back(listener);
}
return true;
}
void DefaultEventListenerPool::remove(EventListenerProtocol* listener) {
for (size_t i = 0; i < m_listeners.size(); i++) {
if (m_listeners[i] == listener) {
m_listeners[i] = nullptr;
}
}
}
void DefaultEventListenerPool::handle(Event* event) {
m_locked += 1;
for (auto h : m_listeners) {
// if an event listener gets destroyed in the middle of this loop, it
// gets set to null
if (h && h->handle(event) == ListenerResult::Stop) {
break;
}
}
m_locked -= 1;
// only mutate listeners once nothing is iterating
// (if there are recursive handle calls)
if (m_locked == 0) {
ranges::remove(m_listeners, nullptr);
for (auto listener : m_toAdd) {
m_listeners.push_back(listener);
}
m_toAdd.clear();
}
}
DefaultEventListenerPool* DefaultEventListenerPool::get() {
static auto inst = new DefaultEventListenerPool();
return inst;
}
EventListenerPool* EventListenerProtocol::getPool() const {
return DefaultEventListenerPool::get();
}
bool EventListenerProtocol::enable() {
// virtual calls from destructors always call the base class so we gotta
// store the subclass' pool in a member to be able to access it in disable
// this is actually better because now regardless of what getPool() does
// we can always be assured that whatever pool it returns this listener
// will be removed from that pool and can't be in multiple pools at once
if (m_pool || !(m_pool = this->getPool())) {
return false;
}
return m_pool->add(this);
} }
void EventListenerProtocol::disable() { void EventListenerProtocol::disable() {
Event::listeners().erase(this); if (m_pool) {
m_pool->remove(this);
m_pool = nullptr;
}
} }
EventListenerProtocol::~EventListenerProtocol() { EventListenerProtocol::~EventListenerProtocol() {
@ -16,19 +77,11 @@ EventListenerProtocol::~EventListenerProtocol() {
Event::~Event() {} Event::~Event() {}
EventListenerPool* Event::getPool() const {
return DefaultEventListenerPool::get();
}
void Event::postFrom(Mod* m) { void Event::postFrom(Mod* m) {
if (m) this->sender = m; if (m) this->sender = m;
this->getPool()->handle(this);
std::unordered_set<EventListenerProtocol*> listeners_copy = Event::listeners();
for (auto h : listeners_copy) {
if (h->passThrough(this) == ListenerResult::Stop) {
break;
}
}
}
std::unordered_set<EventListenerProtocol*>& Event::listeners() {
static std::unordered_set<EventListenerProtocol*> listeners;
return listeners;
} }

View file

@ -73,7 +73,7 @@ ghc::filesystem::path Mod::getBinaryPath() const {
} }
ghc::filesystem::path Mod::getResourcesDir() const { ghc::filesystem::path Mod::getResourcesDir() const {
return dirs::getModRuntimeDir() / this->getID() / "resources"; return dirs::getModRuntimeDir() / this->getID() / "resources" / this->getID();
} }
Result<> Mod::saveData() { Result<> Mod::saveData() {

View file

@ -116,7 +116,9 @@ std::vector<Hook*> Mod::Impl::getHooks() const {
// Settings and saved values // Settings and saved values
Result<> Mod::Impl::loadData() { Result<> Mod::Impl::loadData() {
Loader::get()->queueInGDThread([&]() {
ModStateEvent(m_self, ModEventType::DataLoaded).post(); ModStateEvent(m_self, ModEventType::DataLoaded).post();
});
// Settings // Settings
// Check if settings exist // Check if settings exist
@ -182,6 +184,7 @@ Result<> Mod::Impl::loadData() {
} }
Result<> Mod::Impl::saveData() { Result<> Mod::Impl::saveData() {
// saveData is expected to be synchronous, and always called from GD thread
ModStateEvent(m_self, ModEventType::DataSaved).post(); ModStateEvent(m_self, ModEventType::DataSaved).post();
// Data saving should be fully fail-safe // Data saving should be fully fail-safe
@ -308,9 +311,12 @@ Result<> Mod::Impl::loadBinary() {
LoaderImpl::get()->releaseNextMod(); LoaderImpl::get()->releaseNextMod();
Loader::get()->queueInGDThread([&]() {
ModStateEvent(m_self, ModEventType::Loaded).post(); ModStateEvent(m_self, ModEventType::Loaded).post();
});
Loader::get()->updateAllDependencies(); Loader::get()->updateAllDependencies();
Loader::get()->updateResources();
GEODE_UNWRAP(this->enable()); GEODE_UNWRAP(this->enable());
@ -329,7 +335,9 @@ Result<> Mod::Impl::unloadBinary() {
GEODE_UNWRAP(this->saveData()); GEODE_UNWRAP(this->saveData());
GEODE_UNWRAP(this->disable()); GEODE_UNWRAP(this->disable());
Loader::get()->queueInGDThread([&]() {
ModStateEvent(m_self, ModEventType::Unloaded).post(); ModStateEvent(m_self, ModEventType::Unloaded).post();
});
// Disabling unhooks and unpatches already // Disabling unhooks and unpatches already
for (auto const& hook : m_hooks) { for (auto const& hook : m_hooks) {
@ -367,7 +375,9 @@ Result<> Mod::Impl::enable() {
} }
} }
Loader::get()->queueInGDThread([&]() {
ModStateEvent(m_self, ModEventType::Enabled).post(); ModStateEvent(m_self, ModEventType::Enabled).post();
});
m_enabled = true; m_enabled = true;
return Ok(); return Ok();
@ -381,7 +391,9 @@ Result<> Mod::Impl::disable() {
return Err("Mod does not support disabling"); return Err("Mod does not support disabling");
} }
Loader::get()->queueInGDThread([&]() {
ModStateEvent(m_self, ModEventType::Disabled).post(); ModStateEvent(m_self, ModEventType::Disabled).post();
});
for (auto const& hook : m_hooks) { for (auto const& hook : m_hooks) {
GEODE_UNWRAP(this->disableHook(hook)); GEODE_UNWRAP(this->disableHook(hook));
@ -682,6 +694,7 @@ static ModInfo getModImplInfo() {
} }
auto info = infoRes.unwrap(); auto info = infoRes.unwrap();
info.details() = LOADER_ABOUT_MD; info.details() = LOADER_ABOUT_MD;
info.changelog() = LOADER_CHANGELOG_MD;
info.supportInfo() = SUPPORT_INFO; info.supportInfo() = SUPPORT_INFO;
info.supportsDisabling() = false; info.supportsDisabling() = false;
return info; return info;

View file

@ -112,12 +112,8 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
// changelog // changelog
if (info.changelog()) { if (info.changelog()) {
m_changelogArea = MDTextArea::create(info.changelog().value(), { 350.f, 137.5f }); // m_changelogArea is only created if the changelog button is clicked
m_changelogArea->setPosition( // because changelogs can get really long and take a while to load
-5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f
);
m_changelogArea->setVisible(false);
m_mainLayer->addChild(m_changelogArea);
auto changelogBtnOffSpr = ButtonSprite::create( auto changelogBtnOffSpr = ButtonSprite::create(
CCSprite::createWithSpriteFrameName("changelog.png"_spr), CCSprite::createWithSpriteFrameName("changelog.png"_spr),
@ -225,9 +221,19 @@ void ModInfoPopup::onInfo(CCObject*) {
} }
void ModInfoPopup::onChangelog(CCObject* sender) { void ModInfoPopup::onChangelog(CCObject* sender) {
auto toggle = static_cast<CCMenuItemToggler*>(sender);
auto winSize = CCDirector::get()->getWinSize(); auto winSize = CCDirector::get()->getWinSize();
if (!m_changelogArea) {
m_changelogArea = MDTextArea::create(Mod::get()->getModInfo().changelog().value(), { 350.f, 137.5f });
m_changelogArea->setPosition(
-5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f
);
m_changelogArea->setVisible(false);
m_mainLayer->addChild(m_changelogArea);
}
auto toggle = static_cast<CCMenuItemToggler*>(sender);
m_detailsArea->setVisible(toggle->isToggled()); m_detailsArea->setVisible(toggle->isToggled());
// as it turns out, cocos2d is stupid and still passes touch // as it turns out, cocos2d is stupid and still passes touch
// events to invisible nodes // events to invisible nodes
@ -243,6 +249,12 @@ void ModInfoPopup::onChangelog(CCObject* sender) {
!toggle->isToggled() ? winSize.width / 2 - m_changelogArea->getScaledContentSize().width / 2 : !toggle->isToggled() ? winSize.width / 2 - m_changelogArea->getScaledContentSize().width / 2 :
-5000.f -5000.f
); );
m_scrollbar->setTarget(
toggle->isToggled() ?
m_detailsArea->getScrollLayer() :
m_changelogArea->getScrollLayer()
);
} }
void ModInfoPopup::keyDown(enumKeyCodes key) { void ModInfoPopup::keyDown(enumKeyCodes key) {
@ -559,7 +571,7 @@ bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) {
void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) { void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
std::visit(makeVisitor { std::visit(makeVisitor {
[&](UpdateFinished) { [&](UpdateFinished const&) {
this->setInstallStatus(std::nullopt); this->setInstallStatus(std::nullopt);
FLAlertLayer::create( FLAlertLayer::create(

View file

@ -35,7 +35,7 @@ protected:
CCMenuItemSpriteExtra* m_infoBtn; CCMenuItemSpriteExtra* m_infoBtn;
CCLabelBMFont* m_updateVersionLabel = nullptr; CCLabelBMFont* m_updateVersionLabel = nullptr;
MDTextArea* m_detailsArea; MDTextArea* m_detailsArea;
MDTextArea* m_changelogArea; MDTextArea* m_changelogArea = nullptr;
Scrollbar* m_scrollbar; Scrollbar* m_scrollbar;
void onChangelog(CCObject*); void onChangelog(CCObject*);

View file

@ -303,6 +303,10 @@ DECL_BASED_CREATE_FUNS(Leaderboard);
DECL_BASED_CREATE_FUNS(Editor); DECL_BASED_CREATE_FUNS(Editor);
DECL_BASED_CREATE_FUNS(Category); DECL_BASED_CREATE_FUNS(Category);
CCSize CircleButtonSprite::getMaxTopSize() const {
return m_obContentSize * .65f;
}
CCSize EditorButtonSprite::getMaxTopSize() const { CCSize EditorButtonSprite::getMaxTopSize() const {
return m_obContentSize - CCSize { 8.f, 8.f }; return m_obContentSize - CCSize { 8.f, 8.f };
} }

View file

@ -6,8 +6,6 @@ using namespace geode::prelude;
bool Scrollbar::ccTouchBegan(CCTouch* touch, CCEvent* event) { bool Scrollbar::ccTouchBegan(CCTouch* touch, CCEvent* event) {
// hitbox // hitbox
auto rect = this->boundingBox(); auto rect = this->boundingBox();
// since anchor point is 0.5, 0.5 it's offset
rect.origin -= this->getScaledContentSize() / 2;
if (!m_target || !rect.containsPoint(touch->getLocation())) return false; if (!m_target || !rect.containsPoint(touch->getLocation())) return false;
// trigger scrollbar thumb move // trigger scrollbar thumb move
@ -40,7 +38,7 @@ void Scrollbar::ccTouchMoved(CCTouch* touch, CCEvent*) {
auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0; auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0;
auto posY = h * auto posY = h *
((-pos.y - targetHeight / 2 + thumbHeight / 4 - 5) / (targetHeight - thumbHeight / 2 + 10)); ((-pos.y + thumbHeight / 4 - 5) / (targetHeight - thumbHeight / 2 + 10));
if (posY > 0.0f) posY = 0.0f; if (posY > 0.0f) posY = 0.0f;
if (posY < -h) posY = -h; if (posY < -h) posY = -h;
@ -73,7 +71,7 @@ void Scrollbar::draw() {
m_track->setContentSize({ m_width / m_track->getScale(), m_track->setContentSize({ m_width / m_track->getScale(),
targetHeight / m_track->getScale() }); targetHeight / m_track->getScale() });
} }
m_track->setPosition(.0f, .0f); m_track->setPosition(m_obContentSize / 2);
this->setContentSize({ m_width, targetHeight }); this->setContentSize({ m_width, targetHeight });
@ -101,6 +99,10 @@ void Scrollbar::draw() {
auto y = m_target->m_contentLayer->getPositionY(); auto y = m_target->m_contentLayer->getPositionY();
auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0; auto thumbHeight = m_resizeThumb ? std::min(p, 1.f) * targetHeight / .4f : 0;
if (thumbHeight < 15.f) {
thumbHeight = 15.f;
}
auto thumbPosY = -targetHeight / 2 + thumbHeight / 4 - 5.0f + auto thumbPosY = -targetHeight / 2 + thumbHeight / 4 - 5.0f +
(h ? (-y) / h : 1.f) * (targetHeight - thumbHeight / 2 + 10.0f); (h ? (-y) / h : 1.f) * (targetHeight - thumbHeight / 2 + 10.0f);
@ -113,15 +115,21 @@ void Scrollbar::draw() {
if (fHeightTop() > 0.0f) { if (fHeightTop() > 0.0f) {
thumbHeight -= fHeightTop(); thumbHeight -= fHeightTop();
if (thumbHeight < 15.f) {
thumbHeight = 15.f;
}
thumbPosY -= fHeightTop(); thumbPosY -= fHeightTop();
} }
if (fHeightBottom() < 0.f) { if (fHeightBottom() < 0.f) {
thumbHeight += fHeightBottom(); thumbHeight += fHeightBottom();
if (thumbHeight < 15.f) {
thumbHeight = 15.f;
}
thumbPosY -= fHeightBottom(); thumbPosY -= fHeightBottom();
} }
m_thumb->setPosition(0.f, thumbPosY); m_thumb->setPosition(m_obContentSize / 2 + ccp(0.f, thumbPosY));
if (m_resizeThumb) { if (m_resizeThumb) {
m_thumb->setContentSize({ m_width, thumbHeight }); m_thumb->setContentSize({ m_width, thumbHeight });
} }
@ -134,6 +142,8 @@ void Scrollbar::setTarget(CCScrollLayerExt* target) {
bool Scrollbar::init(CCScrollLayerExt* target) { bool Scrollbar::init(CCScrollLayerExt* target) {
if (!this->CCLayer::init()) return false; if (!this->CCLayer::init()) return false;
this->ignoreAnchorPointForPosition(false);
m_target = target; m_target = target;
if (cocos::fileExistsInSearchPaths("scrollbar.png"_spr)) { if (cocos::fileExistsInSearchPaths("scrollbar.png"_spr)) {

View file

@ -233,6 +233,32 @@ std::string geode::cocos::cc4bToHexString(ccColor4B const& color) {
return output; return output;
} }
WeakRefPool* WeakRefPool::get() {
static auto inst = new WeakRefPool();
return inst;
}
void WeakRefPool::check(CCObject* obj) {
// if this object's only reference is the WeakRefPool aka only weak
// references exist to it, then release it
if (m_pool.contains(obj) && obj->retainCount() == 1) {
obj->release();
m_pool.erase(obj);
}
}
bool WeakRefPool::isManaged(CCObject* obj) {
this->check(obj);
return m_pool.contains(obj);
}
void WeakRefPool::manage(CCObject* obj) {
if (obj && !m_pool.contains(obj)) {
obj->retain();
m_pool.insert(obj);
}
}
CCRect geode::cocos::calculateNodeCoverage(std::vector<CCNode*> const& nodes) { CCRect geode::cocos::calculateNodeCoverage(std::vector<CCNode*> const& nodes) {
CCRect coverage; CCRect coverage;
for (auto child : nodes) { for (auto child : nodes) {
@ -302,8 +328,12 @@ void geode::cocos::limitNodeSize(cocos2d::CCNode* spr, cocos2d::CCSize const& si
} }
bool geode::cocos::nodeIsVisible(cocos2d::CCNode* node) { bool geode::cocos::nodeIsVisible(cocos2d::CCNode* node) {
if (!node->isVisible()) return false; if (!node->isVisible()) {
if (node->getParent()) return nodeIsVisible(node->getParent()); return false;
}
if (node->getParent()) {
return nodeIsVisible(node->getParent());
}
return true; return true;
} }

View file

@ -1,12 +1,25 @@
#include <Geode/Loader.hpp> #include <Geode/Loader.hpp>
using namespace geode::prelude;
#include <Geode/modify/MenuLayer.hpp> #include <Geode/modify/MenuLayer.hpp>
#include <Geode/loader/SettingNode.hpp> #include <Geode/loader/SettingNode.hpp>
#include <Geode/loader/ModJsonTest.hpp> #include <Geode/loader/ModJsonTest.hpp>
#include <Geode/binding/CCMenuItemSpriteExtra.hpp> #include <Geode/binding/CCMenuItemSpriteExtra.hpp>
#include <Geode/binding/FLAlertLayer.hpp> #include <Geode/binding/FLAlertLayer.hpp>
#include "main.hpp"
using namespace geode::prelude;
std::string TestEvent::getData() const {
return data;
}
TestEvent::TestEvent(std::string const& data) : data(data) {}
ListenerResult TestEventFilter::handle(utils::MiniFunction<Callback> fn, TestEvent* event) {
fn(event);
return ListenerResult::Propagate;
}
TestEventFilter::TestEventFilter() {}
enum class Icon { enum class Icon {
Steve, Steve,
@ -137,6 +150,7 @@ SettingNode* MySettingValue::createNode(float width) {
struct MyMenuLayer : Modify<MyMenuLayer, MenuLayer> { struct MyMenuLayer : Modify<MyMenuLayer, MenuLayer> {
void onMoreGames(CCObject*) { void onMoreGames(CCObject*) {
TestEvent("Event system works!").post();
if (Mod::get()->getSettingValue<bool>("its-raining-after-all")) { if (Mod::get()->getSettingValue<bool>("its-raining-after-all")) {
FLAlertLayer::create("Damn", ":(", "OK")->show(); FLAlertLayer::create("Damn", ":(", "OK")->show();
} }

View file

@ -0,0 +1,32 @@
#pragma once
#include <Geode/loader/Event.hpp>
using namespace geode::prelude;
#ifdef GEODE_IS_WINDOWS
#ifdef EXPORTING_MOD
#define GEODE_TESTDEP_DLL __declspec(dllexport)
#else
#define GEODE_TESTDEP_DLL __declspec(dllimport)
#endif
#else
#define GEODE_TESTDEP_DLL
#endif
class GEODE_TESTDEP_DLL TestEvent : public Event {
protected:
std::string data;
public:
std::string getData() const;
TestEvent(std::string const& data);
};
class GEODE_TESTDEP_DLL TestEventFilter : public EventFilter<TestEvent> {
public:
using Callback = void(TestEvent*);
ListenerResult handle(utils::MiniFunction<Callback> fn, TestEvent* event);
TestEventFilter();
};

View file

@ -1,5 +1,5 @@
{ {
"geode": "0.6.1", "geode": "1.0.0",
"version": "1.0.0", "version": "1.0.0",
"id": "geode.testdep", "id": "geode.testdep",
"name": "Geode Test Dependency", "name": "Geode Test Dependency",

View file

@ -9,5 +9,6 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
set(GEODE_LINK_SOURCE ON) set(GEODE_LINK_SOURCE ON)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
target_link_libraries(TestMod TestDependency)
setup_geode_mod(${PROJECT_NAME} DONT_INSTALL) setup_geode_mod(${PROJECT_NAME} DONT_INSTALL)

View file

@ -1,6 +1,7 @@
#include <Geode/Loader.hpp> #include <Geode/Loader.hpp>
#include <Geode/loader/ModJsonTest.hpp> #include <Geode/loader/ModJsonTest.hpp>
#include <Geode/loader/ModEvent.hpp> #include <Geode/loader/ModEvent.hpp>
#include "../dependency/main.hpp"
using namespace geode::prelude; using namespace geode::prelude;
@ -23,6 +24,13 @@ $on_mod(Unloaded) {
log::info("Unloaded"); log::info("Unloaded");
} }
// Events
$execute {
new EventListener<TestEventFilter>(+[](TestEvent* event) {
log::info("Received event: {}", event->getData());
});
}
// Modify // Modify
#include <Geode/modify/GJGarageLayer.hpp> #include <Geode/modify/GJGarageLayer.hpp>

View file

@ -17,6 +17,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE
target_compile_definitions(${PROJECT_NAME} PRIVATE -DGEODE_DONT_WARN_INCORRECT_MEMBERS) target_compile_definitions(${PROJECT_NAME} PRIVATE -DGEODE_DONT_WARN_INCORRECT_MEMBERS)
target_link_libraries(${PROJECT_NAME} PRIVATE ghc_filesystem) target_link_libraries(${PROJECT_NAME} PRIVATE ghc_filesystem mat-json)
add_dependencies(${PROJECT_NAME} CodegenRun) add_dependencies(${PROJECT_NAME} CodegenRun)

View file

@ -4,10 +4,13 @@
GEODE_MEMBER_CHECK(GameObject, m_effectPlistName, 0x278); GEODE_MEMBER_CHECK(GameObject, m_effectPlistName, 0x278);
GEODE_MEMBER_CHECK(GameObject, m_effectManager, 0x454); GEODE_MEMBER_CHECK(GameObject, m_effectManager, 0x454);
GEODE_MEMBER_CHECK(GameObject, m_firstPosition, 0x424);
GEODE_MEMBER_CHECK(PlayerObject, m_unk484, 0x484); GEODE_MEMBER_CHECK(PlayerObject, m_unk484, 0x484);
GEODE_MEMBER_CHECK(PlayerObject, m_ghostTrail, 0x4E4); GEODE_MEMBER_CHECK(PlayerObject, m_ghostTrail, 0x4E4);
GEODE_MEMBER_CHECK(PlayerObject, m_waveTrail, 0x514); GEODE_MEMBER_CHECK(PlayerObject, m_waveTrail, 0x514);
GEODE_MEMBER_CHECK(PlayerObject, m_isDart, 0x63b);
GEODE_MEMBER_CHECK(PlayerObject, m_isDashing, 0x641);
GEODE_MEMBER_CHECK(EditorUI, m_buttonBar, 0x134); GEODE_MEMBER_CHECK(EditorUI, m_buttonBar, 0x134);
GEODE_MEMBER_CHECK(EditorUI, m_hideableUIElementArray, 0x13c); GEODE_MEMBER_CHECK(EditorUI, m_hideableUIElementArray, 0x13c);