Merge remote-tracking branch 'refs/remotes/origin/1.4.0-dev' into 1.4.0-dev

This commit is contained in:
camila314 2023-10-13 06:18:18 -05:00
commit f1d948f682
50 changed files with 909 additions and 292 deletions

View file

@ -1,7 +1,17 @@
name: Bug Report
description: Report a bug where something is not working as expected in Geode Loader (not specific mods), which does not crash the game.
description: Report a Geode bug (not mods themselves) where something is not working as expected in Geode Loader (not mods created by others), which does not crash the game.
labels: [ "unverified", "bug" ]
body:
- type: checkboxes
attributes:
label: Geode Issue
description: |
The Geode repository is for issues of *Geode Loader*, not individual mods created by other developers.
When submitting a bug report, please make sure that the bug is *actually* related to ***Geode Loader itself*** and not to a mod or mod combination.
Failing to do this will get your issue *closed without explanation*.
options:
- label: I confirm that this bug is NOT related to a mod but directly to Geode Loader itself.
required: true
- type: dropdown
id: platform
attributes:

View file

@ -1,7 +1,18 @@
name: Crash Report
description: Report a bug that crashes the game or prevents startup caused by Geode Loader (not individual mods).
description: Report a Geode bug (not mods themselves) that crashes the game or prevents startup caused by Geode Loader (not mods created by others).
labels: [ "unverified", "crash" ]
body:
- type: input
id: geode-confirmation
attributes:
label: Geode Issue
description: |
The Geode repository is for issues of *Geode Loader*, not individual mods created by other developers.
When submitting a crash report, please make sure that the crash is *actually* related to ***Geode Loader itself*** and not to a mod or mod combination, after you do that type in "confirm" in the input field above.
Failing to do this will get your issue *closed without explanation*.
placeholder: "Please, read the text below."
validations:
required: true
- type: dropdown
id: platform
attributes:

View file

@ -146,21 +146,13 @@ jobs:
files: geode-win/XInput9_1_0.dll geode-win/Geode.dll geode-win/GeodeUpdater.exe geode-win/Geode.lib geode-win/Geode.pdb
dest: geode-${{ steps.ref.outputs.hash }}-win.zip
# TODO change in 2.0.0
- name: Zip Windows Resources
uses: vimtor/action-zip@v1.1
with:
files: geode-win/resources
dest: resources-win.zip
# This is basically a hack because of line endings. Blame windows.
- name: Zip MacOS Resources
- name: Zip Resources
uses: vimtor/action-zip@v1.1
with:
files: geode-mac/resources
dest: resources-mac.zip
dest: resources.zip
- name: Update Nightly Release
- name: Update Development Release
uses: andelf/nightly-release@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -174,5 +166,4 @@ jobs:
./geode-installer-${{ steps.ref.outputs.hash }}-win.exe
./geode-${{ steps.ref.outputs.hash }}-mac.zip
./geode-${{ steps.ref.outputs.hash }}-win.zip
./resources-win.zip
./resources-mac.zip
./resources.zip

View file

@ -28,8 +28,7 @@ jobs:
mv dev/geode-installer-*-win.exe geode-installer-v${{ steps.ref.outputs.version }}-win.exe
mv dev/geode-*-mac.zip geode-v${{ steps.ref.outputs.version }}-mac.zip
mv dev/geode-*-win.zip geode-v${{ steps.ref.outputs.version }}-win.zip
mv dev/resources-win.zip resources-win.zip
mv dev/resources-mac.zip resources-mac.zip
mv dev/resources.zip resources.zip
- name: Create Draft Release
uses: softprops/action-gh-release@v1
@ -49,5 +48,4 @@ jobs:
./geode-installer-v${{ steps.ref.outputs.version }}-win.exe
./geode-v${{ steps.ref.outputs.version }}-mac.zip
./geode-v${{ steps.ref.outputs.version }}-win.zip
./resources-win.zip
./resources-mac.zip
./resources.zip

View file

@ -3,6 +3,9 @@ name: Test Offsets
on:
workflow_dispatch:
push:
paths:
- 'bindings/**' # only when adjusting bindings
- 'loader/test/members/**'
branches:
- '**' # every branch
- '!no-build-**' # unless marked as no-build

19
.gitignore vendored
View file

@ -46,20 +46,29 @@ build2
build-docs/
bin
# Ignore docs folders
docs/**
docs
# Ignore codegenned files
loader/src/internal/about.hpp
loader/src/internal/resources.hpp
loader/resources/mod.json
loader/resources/version
loader/resources/blanks/rename.js
loader/resources/about.md
loader/resources/changelog.md
fods-catgirl-hideout.txt
test-docs.bat
# krita files too because alk is funny
**/*.kra
loader/resources/support.md
# Ignore generated files
installer/mac/*.pkg
installer/windows/*.exe
# Ignore fod's include directories which are stored in this funny file
fods-catgirl-hideout.txt
# Ignore I don't even know what that is probably fod's flash testing script
test-docs.bat
# Ignore krita files too because we don't want our project files shaking my head
**/*.kra

View file

@ -1,5 +1,30 @@
# Geode Changelog
## v1.3.5
* Follow redirect in web::utils functions (a942a45)
* Lots of bindings
* Make codegen symbols private visibility (696a2ca)
* Add deadstrip to macos (0d62940)
* Readd the nullptr check in InstallListPopup::createCells (499f256)
* Fix garagelayer ids on not logged in users (dd0179c)
## v1.3.4
* Implement string setting character filters (cf8fbba)
* Update bindings
## v1.3.3
* Reunify resources.zip (81de161)
## v1.3.2
* Fix alignment of some textures (8f39c38)
* Bring back unknown problems (0663569)
* Fix some Windows 7 incompatibility (2d2bdd1)
* Remove enabled from the crashlogs (5b7d318)
* Make index unzipping async (7c582f1)
* Fix mods by developer crashing when mod was toggled (a6a47bf)
* Fix nested lists in the markdown (2723588)
* Fix search paths (8f39c38, aa55ebe)
## v1.3.1
* Fix TulipHook not relocating RIP relative operands on MacOS (6cad19d)

View file

@ -185,7 +185,14 @@ target_include_directories(GeodeCodegenSources PRIVATE
${GEODE_LOADER_PATH}/include/Geode/cocos/extensions
${GEODE_LOADER_PATH}/include/Geode/fmod
)
set_target_properties(GeodeCodegenSources PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_compile_features(GeodeCodegenSources PUBLIC cxx_std_20)
if (APPLE)
target_compile_options(GeodeCodegenSources PUBLIC -ffunction-sections -fdata-sections)
target_link_options(GeodeCodegenSources PUBLIC -dead_strip)
endif()
if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
target_precompile_headers(GeodeCodegenSources INTERFACE
"${GEODE_LOADER_PATH}/include/Geode/Bindings.hpp"
@ -218,6 +225,11 @@ else()
set(GEODE_PLATFORM_BIN_PATH ${GEODE_BIN_PATH}/${PROJECT_VERSION}/${GEODE_PLATFORM_BINARY})
endif()
if (WIN32)
# This allows you to compile in debug mode
add_compile_definitions(_HAS_ITERATOR_DEBUGGING=0)
endif()
if (PROJECT_IS_TOP_LEVEL)
add_subdirectory(loader)

View file

@ -121,6 +121,11 @@ class cocos2d::CCClippingNode {
// void updateConnected() = win 0xc7fb0;
//}
[[link(win)]]
class cocos2d::CCConfiguration {
void gatherGPUInfo() = mac 0x2a6e10;
}
[[link(win)]]
class cocos2d::CCDelayTime {
static cocos2d::CCDelayTime* create(float) = mac 0x1f4380;
@ -318,7 +323,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo {
class cocos2d::CCGLProgram {
auto setUniformsForBuiltins() = mac 0x232c70;
auto use() = mac 0x231d70;
bool compileShader(unsigned int* shader, unsigned int type, const char* source);
bool compileShader(unsigned int* shader, unsigned int type, const char* source) = mac 0x231a30;
}
[[link(win)]]
@ -360,6 +365,7 @@ class cocos2d::CCImage {
class cocos2d::CCKeyboardDispatcher {
bool dispatchKeyboardMSG(cocos2d::enumKeyCodes, bool) = mac 0xe8190;
const char* keyToString(cocos2d::enumKeyCodes) = mac 0xe8450;
void updateModifierKeys(bool shft, bool ctrl, bool alt, bool cmd) = mac 0xe8430;
}
[[link(win)]]
@ -380,6 +386,7 @@ class cocos2d::CCKeypadHandler {
[[link(win)]]
class cocos2d::CCLabelBMFont {
CCLabelBMFont() = mac 0x347b60;
static cocos2d::CCLabelBMFont* create(char const*, char const*) = mac 0x347660;
auto limitLabelWidth(float, float, float) = mac 0x34a6e0, ios 0x21b740;
auto setFntFile(char const*) = mac 0x34a5f0;
@ -387,7 +394,7 @@ class cocos2d::CCLabelBMFont {
static auto create() = mac 0x3473f0;
virtual auto init() = mac 0x347b10, ios 0x2198e0;
bool initWithString(const char* str, const char* fnt, float width, cocos2d::CCTextAlignment align, cocos2d::CCPoint offset);
bool initWithString(const char* str, const char* fnt, float width, cocos2d::CCTextAlignment align, cocos2d::CCPoint offset) = mac 0x347710;
virtual auto setScaleX(float) = mac 0x34a5b0, ios 0x21b6e8;
virtual auto setScaleY(float) = mac 0x34a5d0, ios 0x21b714;
virtual auto setScale(float) = mac 0x34a590, ios 0x21b6bc;
@ -631,6 +638,12 @@ class cocos2d::CCNode {
virtual auto cleanup() = mac 0x123100, ios 0x15e3a4;
auto convertToNodeSpace(cocos2d::CCPoint const&) = mac 0x124750, ios 0x15f55c;
auto convertToWorldSpace(cocos2d::CCPoint const&) = mac 0x124790;
cocos2d::CCPoint convertToNodeSpaceAR(cocos2d::CCPoint const& worldPoint) {
return convertToNodeSpace(worldPoint) - getAnchorPointInPoints();
}
cocos2d::CCPoint convertToWorldSpaceAR(cocos2d::CCPoint const& nodePoint) {
return convertToWorldSpace(nodePoint + getAnchorPointInPoints());
}
static cocos2d::CCNode* create() = mac 0x1230a0;
virtual auto draw() = mac 0x123840, ios 0x15e974;
auto getActionByTag(int) = mac 0x123ee0;
@ -1129,6 +1142,7 @@ class cocos2d::CCTouchHandler {
[[link(win)]]
class cocos2d::CCTransitionFade {
static cocos2d::CCTransitionFade* create(float, cocos2d::CCScene*) = mac 0x8ea30, ios 0x12c244;
virtual bool initWithDuration(float t, cocos2d::CCScene* scene, cocos2d::ccColor3B const& color) = mac 0x8e930;
}
[[link(win)]]
@ -1251,16 +1265,30 @@ class cocos2d::extension::CCScrollView {
[[link(win)]]
class cocos2d {
static auto FNTConfigLoadFile(char const*) = mac 0x344f10;
static auto ccGLUseProgram(GLuint) = mac 0x1ae540;
static auto ccGLBlendFunc(GLenum, GLenum) = mac 0x1ae560;
static auto ccDrawSolidRect(cocos2d::CCPoint, cocos2d::CCPoint, cocos2d::_ccColor4F) = mac 0xecf00;
static auto ccGLEnableVertexAttribs(unsigned int) = mac 0x1ae740;
static auto ccGLBindTexture2D(GLuint) = mac 0x1ae610;
static auto ccGLBindTexture2DN(GLuint, GLuint) = mac 0x1ae650;
static float ccpDistance(cocos2d::CCPoint const&, cocos2d::CCPoint const&) = mac 0x1aaf90;
static auto ccDrawLine(cocos2d::CCPoint const&, cocos2d::CCPoint const&) = mac 0xeccc0;
static void ccDrawPoly(cocos2d::CCPoint const*, unsigned int, bool) = mac 0xed0a0;
static void ccDrawColor4B(GLubyte, GLubyte, GLubyte, GLubyte) = mac 0xeddd0;
static void CCMessageBox(const char* msg, const char* title) = mac 0xbabc0;
}
//uintptr_t macNumberOfDraws() {
// return geode::base::get() + 0x69ae90;
//}
//void ccIncrementGLDraws(int n) {
//#ifdef GEODE_IS_MACOS
// *reinterpret_cast<int*>(macNumberOfDraws()) += n;
//#else
// CC_INCREMENT_GL_DRAWS(n);
//#endif
//}
[[link(win)]]
class DS_Dictionary {
DS_Dictionary() = mac 0xbe9a0;

View file

@ -280,6 +280,10 @@ class CCAnimatedSprite : cocos2d::CCSprite {
class CCAnimateFrameCache : cocos2d::CCObject {
static CCAnimateFrameCache* sharedSpriteFrameCache() = mac 0x2e4df0, win 0x158f0;
void addSpriteFramesWithFile(const char* file) = win 0x159b0;
cocos2d::CCDictionary* m_unknown1;
cocos2d::CCDictionary* m_unknown2;
cocos2d::CCDictionary* m_unknown3;
}
class CCBlockLayer : cocos2d::CCLayerColor {
@ -905,6 +909,8 @@ class CommentUploadDelegate {
}
class ConfigureHSVWidget : cocos2d::CCNode {
bool init(int abs, cocos2d::ccHSVValue val) = win 0x4a3f0, mac 0x237310;
void updateLabels() = win 0x4adf0, mac 0x237df0;
cocos2d::CCLabelBMFont* m_hueLabel;
cocos2d::CCLabelBMFont* m_saturationLabel;
cocos2d::CCLabelBMFont* m_brightnessLabel;
@ -945,15 +951,15 @@ class CreateMenuItem : CCMenuItemSpriteExtra {
class CreatorLayer : cocos2d::CCLayer, cocos2d::CCSceneTransitionDelegate, DialogDelegate {
void onBack(cocos2d::CCObject*) = win 0x4fae0;
void onChallenge(cocos2d::CCObject*) = mac 0x142960, win 0x4f1b0;
void onLeaderboards(cocos2d::CCObject*) = win 0x4ed20;
void onLeaderboards(cocos2d::CCObject*) = mac 0x142920, win 0x4ed20;
void onMyLevels(cocos2d::CCObject*) = mac 0x142b70, win 0x4eaa0;
void onSavedLevels(cocos2d::CCObject*) = mac 0x142860, win 0x4ebe0;
void onDailyLevel(cocos2d::CCObject*) = win 0x4f170;
void onWeeklyLevel(cocos2d::CCObject*) = win 0x4f190;
void onFeaturedLevels(cocos2d::CCObject*) = win 0x4edf0;
void onFameLevels(cocos2d::CCObject*) = win 0x4ee70;
void onMapPacks(cocos2d::CCObject*) = win 0x4efb0;
void onOnlineLevels(cocos2d::CCObject*) = win 0x4ef60;
void onDailyLevel(cocos2d::CCObject*) = mac 0x142980, win 0x4f170;
void onWeeklyLevel(cocos2d::CCObject*) = mac 0x1429a0, win 0x4f190;
void onFeaturedLevels(cocos2d::CCObject*) = mac 0x142a20, win 0x4edf0;
void onFameLevels(cocos2d::CCObject*) = mac 0x142a80, win 0x4ee70;
void onMapPacks(cocos2d::CCObject*) = mac 0x1429c0, win 0x4efb0;
void onOnlineLevels(cocos2d::CCObject*) = mac 0x142ae0, win 0x4ef60;
void onGauntlets(cocos2d::CCObject*) = mac 0x142b20, win 0x4f0a0;
void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0;
void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540;
@ -1026,7 +1032,7 @@ class CustomizeObjectLayer : FLAlertLayer, TextInputDelegate, HSVWidgetPopupDele
void onClose(cocos2d::CCObject*) = mac 0xdf660, win 0x57ac0;
void updateSelected(int channelID) = mac 0xe0970, win 0x57850;
bool init(GameObject* target, cocos2d::CCArray* targets) = mac 0xdd560, win 0x53e00;
void onHSV(cocos2d::CCObject* sender) = win 0x567c0;
void onHSV(cocos2d::CCObject* sender) = win 0x567c0, mac 0xdfa00;
void toggleVisible() = mac 0xe1140, win 0x56fb0;
void highlightSelected(ButtonSprite* target) = mac 0xe0aa0, win 0x579d0;
void updateCustomColorLabels() = mac 0xdff40, win 0x576d0;
@ -1035,8 +1041,8 @@ class CustomizeObjectLayer : FLAlertLayer, TextInputDelegate, HSVWidgetPopupDele
// inlined in most places
void updateChannelLabel(int channel) = mac 0xe06e0, win 0x56f50;
virtual void hsvPopupClosed(HSVWidgetPopup* popup, cocos2d::ccHSVValue value) = win 0x56990;
virtual void colorSelectClosed(cocos2d::CCNode*) = mac 0xe0c70, win 0x564a0;
virtual void textChanged(CCTextInputNode* input) = mac 0xe16a0, win 0x574d0;
virtual void colorSelectClosed(cocos2d::CCNode*) = mac 0xe0610, win 0x564a0;
virtual void textChanged(CCTextInputNode* input) = mac 0xe1470, win 0x574d0;
inline CustomizeObjectLayer() {}
~CustomizeObjectLayer() = win 0x53c30;
@ -1073,7 +1079,7 @@ class CustomizeObjectLayer : FLAlertLayer, TextInputDelegate, HSVWidgetPopupDele
}
class DailyLevelPage : FLAlertLayer, FLAlertLayerProtocol, GJDailyLevelDelegate, LevelDownloadDelegate {
static DailyLevelPage* create(bool weekly) = win 0x6a860;
static DailyLevelPage* create(bool weekly) = mac 0x108ac0, win 0x6a860;
bool init(bool weekly) = mac 0x108C90, win 0x6a900;
virtual void updateTimers(float) = mac 0x109780, win 0x6bef0;
virtual void show() = mac 0x10a4b0, win 0x3f360;
@ -1136,7 +1142,7 @@ class DrawGridLayer : cocos2d::CCLayer {
}
bool init(cocos2d::CCNode* grid, LevelEditorLayer* editor) = win 0x16c4d0;
void draw() = win 0x16ce90;
virtual void draw() = win 0x16ce90, mac 0xa3c40;
virtual void update(float) = win 0x16cd80;
void clearPlayerPoints() {
m_playerNodePoints->removeAllObjects();
@ -1272,7 +1278,7 @@ class EditorPauseLayer : CCBlockLayer, FLAlertLayerProtocol {
bool init(LevelEditorLayer*) = mac 0x13c7a0, win 0x730e0, ios 0x280cb8;
void onExitEditor(cocos2d::CCObject* sender) = mac 0x13f180, win 0x75660;
void playStep2() = mac 0x13f040, win 0x75440;
void onResume(cocos2d::CCObject* sender) = win 0x74fe0;
void onResume(cocos2d::CCObject* sender) = mac 0x13e170, win 0x74fe0;
void onSaveAndPlay(cocos2d::CCObject* sender) = mac 0x13e1b0, win 0x753d0;
void onSaveAndExit(cocos2d::CCObject* sender) = mac 0x13e230, win 0x75620;
void onSave(cocos2d::CCObject* sender) = mac 0x13e290, win 0x755a0;
@ -1303,6 +1309,8 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void create(LevelEditorLayer*) = mac 0x8a80, win 0x76270;
cocos2d::CCArray* createCustomItems() = mac 0x1ddf0, win 0x7a370;
void onDeleteCustomItem(cocos2d::CCObject* pSender) = win 0x7a280, mac 0x29860;
void onNewCustomItem(cocos2d::CCObject* pSender) = win 0x79fd0, mac 0x24480;
void deselectAll() = mac 0x1f300, win 0x86af0;
void onDeselectAll(cocos2d::CCObject*) = mac 0x19cd0, win 0x86ac0;
void disableButton(CreateMenuItem*) = mac 0x1c0f0, win 0x78af0;
@ -1352,8 +1360,8 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void onCreateButton(cocos2d::CCObject* sender) = mac 0x1fd70, win 0x854f0;
CCMenuItemSpriteExtra* getSpriteButton(const char* sprite, cocos2d::SEL_MenuHandler callback, cocos2d::CCMenu* menu, float scale) = mac 0xb500, win 0x78bf0;
cocos2d::CCPoint offsetForKey(int objID) = win 0x92310;
void updateDeleteMenu() = win 0x7c5d0;
void updateCreateMenu(bool updateTab) = mac 0x1e960, win 0x85530;
void updateDeleteMenu() = win 0x7c5d0, mac 0x1e960;
void updateCreateMenu(bool updateTab) = mac 0x1ba80, win 0x85530;
void toggleMode(cocos2d::CCObject* sender) = mac 0x187b0, win 0x7ad20;
void zoomIn(cocos2d::CCObject* sender) = mac 0xc0c0, win 0x877c0;
void zoomOut(cocos2d::CCObject* sender) = mac 0xc120, win 0x87830;
@ -1421,6 +1429,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void sliderChanged(cocos2d::CCObject* slider) = mac 0xaed0, win 0x78cc0;
void repositionObjectsToCenter(cocos2d::CCArray* objs, cocos2d::CCPoint center, bool ignoreGroupParent) = mac 0x1fcd0, win 0x88410;
virtual void draw() = win 0x8fbe0;
float valueFromXPos(float val) = win 0x78e30, mac 0x1c810;
bool m_isPlayingMusic;
EditButtonBar* m_buttonBar;
@ -1628,9 +1637,12 @@ class EffectGameObject : GameObject {
PAD = mac 0x28, win 0x24;
}
class EndLevelLayer {
class EndLevelLayer : cocos2d::CCLayer {
static EndLevelLayer* create() = mac 0x2787d0, win 0x94b50;
void customSetup() = win 0x94cb0;
const char* getCoinString(void* p0) = win 0x96270;
const char* getEndText() = win 0x964A0;
void onMenu(cocos2d::CCObject* sender) = mac 0x27a500, win 0x96c10;
void onEdit(cocos2d::CCObject* sender) = mac 0x27a640, win 0x96d30;
}
@ -1755,8 +1767,8 @@ class FMODSound : cocos2d::CCNode {
class FriendRequestDelegate {}
class FriendsProfilePage : FLAlertLayer, FLAlertLayerProtocol, UploadActionDelegate, UploadPopupDelegate, UserListDelegate {
static FriendsProfilePage* create(UserListType) = win 0x9ce80;
bool init(UserListType) = win 0x9cf30;
static FriendsProfilePage* create(UserListType) = win 0x9ce80, mac 0x3a9570;
bool init(UserListType) = win 0x9cf30, mac 0x3a9770;
}
class GJAccountBackupDelegate {
@ -1785,11 +1797,16 @@ class GJAccountLoginDelegate {
class GJAccountManager : cocos2d::CCNode {
static GJAccountManager* sharedState() = mac 0x85070, win 0x107d50;
static GJAccountManager* get() {
return GJAccountManager::sharedState();
}
gd::string getGJP() = mac 0x89520, win 0x10abb0;
PAD = mac 0x8, win 0x4;
gd::string m_password;
gd::string m_username;
int m_accountID;
int m_playerID;
}
class GJAccountSyncDelegate {
@ -2281,7 +2298,7 @@ class GJGameLevel : cocos2d::CCNode {
void getLengthKey(int) = mac 0x2dbba0;
void getNormalPercent() = mac 0x2b8b20;
void levelWasAltered() = mac 0x2db530, win 0xbd550;
void savePercentage(int, bool, int, int, bool) = mac 0x2db700;
void savePercentage(int, bool, int, int, bool) = mac 0x2db700, win 0xbd5c0;
void dataLoaded(DS_Dictionary* dict) = mac 0x2dc0e0, win 0xbded0, ios 0x6fca4;
GJDifficulty getAverageDifficulty() = win 0xbd9b0;
gd::string getUnpackedLevelDescription() = mac 0x2DDB50, win 0xbf890;
@ -2581,21 +2598,21 @@ class GJScaleControl : cocos2d::CCLayer {
virtual void ccTouchMoved(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x31e60, win 0x94840;
virtual void ccTouchEnded(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x31fb0, win 0x94940;
virtual void ccTouchCancelled(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x32060, win 0x2dea0; // shared with many others
void updateLabel(float value) = win 0x94990;
void updateLabel(float value) = win 0x94990, mac 0x31c90;
void loadValues(GameObject* obj, cocos2d::CCArray* objs) = win 0x94590, mac 0x24f40;
Slider* m_slider;
unsigned int m_touchID;
float m_value;
PAD = mac 0x8, win 0x4;
bool m_shouldSnapAt1;
cocos2d::CCLabelBMFont* m_label;
GJScaleControlDelegate* m_delegate;
}
class GJScaleControlDelegate {
virtual void scaleChanged(float) {}
virtual void scaleChangeBegin() {}
virtual void scaleChangeEnded() {}
virtual void scaleChanged(float) {}
}
class GJScoreCell : TableViewCell, FLAlertLayerProtocol {
@ -3547,7 +3564,8 @@ class GameStatsManager : cocos2d::CCNode {
int getBaseCurrencyForLevel(GJGameLevel*) = mac 0x43470, win 0xf8530;
GJChallengeItem* getChallenge(int id) = mac 0x451f0, win 0xa2fb0;
void getSecretCoinKey(char const*) = mac 0x429f0;
int getStat(char const*) = mac 0x3d310, win 0xf3580;
int getStat(char const* type) = mac 0x3d310, win 0xf3580;
void setStat(char const* type, int amount) = win 0xf3690;
void hasPendingUserCoin(char const*) = mac 0x42730, win 0xf7c50;
void hasSecretCoin(char const*) = mac 0x40730, win 0xf7dc0;
void hasUserCoin(char const*) = mac 0x427e0, win 0xf7ae0;
@ -3559,6 +3577,7 @@ class GameStatsManager : cocos2d::CCNode {
void storeSecretCoin(char const*) = mac 0x42a10;
void storeUserCoin(char const*) = mac 0x42890;
bool isItemUnlocked(UnlockType type, int id) = win 0xfbb80;
void checkAchievement(char const* type) = win 0xf37c0;
PAD = mac 0x50, win 0x28;
cocos2d::CCDictionary* m_dailyChests;
@ -3595,7 +3614,7 @@ class GameToolbox {
static cocos2d::CCDictionary* stringSetupToDict(gd::string text, char const* delimeter) = mac 0x28d700, win 0x272a0;
static CCMenuItemToggler* createToggleButton(gd::string text, cocos2d::SEL_MenuHandler onToggled, bool isToggled, cocos2d::CCMenu* toggleMenu, cocos2d::CCPoint position, cocos2d::CCNode* callbackTarget, cocos2d::CCNode* labelParent, cocos2d::CCArray* toggleArray) = mac 0x28bc90, win 0x25fe0;
static CCMenuItemToggler* createToggleButton(gd::string text, cocos2d::SEL_MenuHandler onToggled, bool isToggled, cocos2d::CCMenu* toggleMenu, cocos2d::CCPoint position, cocos2d::CCNode* callbackTarget, cocos2d::CCNode* labelParent, float checkboxScale, float labelSize, float maxWidth, cocos2d::CCPoint labelOffset, const char* unknown, bool anchorHorizontally, int toggleTag, cocos2d::CCArray* toggleArray) = mac 0x28bdd0, win 0x25fe0;
static cocos2d::ccColor3B transformColor(cocos2d::ccColor3B const& src, cocos2d::ccHSVValue hsv) = win 0x26a60;
static cocos2d::ccColor3B transformColor(cocos2d::ccColor3B const& src, cocos2d::ccHSVValue hsv) = win 0x26a60, mac 0x28c950;
static void alignItemsHorisontally(cocos2d::CCArray* array, float pad, cocos2d::CCPoint start, bool idk) = win 0x25b20;
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;
@ -3634,7 +3653,7 @@ class GauntletSelectLayer {
class GhostTrailEffect {}
class HSVWidgetPopup : FLAlertLayer {
bool init(cocos2d::_ccHSVValue value, HSVWidgetPopupDelegate* delegate, gd::string title);
bool init(cocos2d::_ccHSVValue value, HSVWidgetPopupDelegate* delegate, gd::string title) = win 0x49f10, mac 0x236d30;
void onClose(cocos2d::CCObject* sender) = win 0x4a280;
ConfigureHSVWidget* m_configureWidget;
@ -3657,7 +3676,7 @@ class HardStreak : cocos2d::CCDrawNode {
void reset() = mac 0x5c930;
void resumeStroke() = mac 0x5c210;
void stopStroke() = mac 0x5c8f0, win 0x14e460;
void updateStroke(float) = mac 0x5c240, win 0x14e530;
callback void updateStroke(float) = mac 0x5c240, win 0x14e530;
cocos2d::CCArray* m_pointsArr;
cocos2d::CCPoint m_currentPoint;
@ -3753,6 +3772,7 @@ class LevelBrowserLayer : cocos2d::CCLayer, LevelManagerDelegate, FLAlertLayerPr
void updateLevelsLabel() = mac 0x255450, win 0x15c350;
void onRefresh(cocos2d::CCObject* sender) = mac 0x253090;
void onInfo(cocos2d::CCObject* sender) = mac 0x253170, win 0x15cb00;
void onNew(cocos2d::CCObject* sender) = win 0x15cbf0, mac 0x252ac0;
static LevelBrowserLayer* create(GJSearchObject* search) = mac 0x251210, win 0x159fa0, ios 0x2d0a00;
PAD = win 0x4, mac 0x8;
@ -4012,16 +4032,17 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDelegate, RateLevelDelegate, LikeItemDelegate, FLAlertLayerProtocol, LevelDeleteDelegate, NumberInputDelegate, SetIDPopupDelegate {
static LevelInfoLayer* create(GJGameLevel* level) = mac 0x15f290, win 0x175d50;
bool init(GJGameLevel* level) = win 0x175df0, mac 0x15f520;
void onGarage(cocos2d::CCObject* sender) = win 0x177c10;
void onGarage(cocos2d::CCObject* sender) = win 0x177c10, mac 0x163ac0;
void onViewProfile(cocos2d::CCObject* sender) = mac 0x1617d0, win 0x17ac90;
void onLevelInfo(cocos2d::CCObject* sender) = mac 0x163880, win 0x17acf0;
void setupProgressBars() = win 0x177fc0;
void setupProgressBars() = win 0x177fc0, mac 0x1627e0;
void setupLevelInfo() = mac 0x161C80, win 0x178680;
void downloadLevel() = win 0x177d90;
void downloadLevel() = win 0x177d90, mac 0x161b90;
void onPlay(cocos2d::CCObject* sender) = mac 0x161840, win 0x179730;
virtual void levelDownloadFinished(GJGameLevel*) = mac 0x164C00, win 0x1790C0;
virtual void levelUpdateFinished(GJGameLevel*, UpdateResponse) = mac 0x164E60, win 0x1792B0;
void showUpdateAlert(UpdateResponse) = mac 0x164ED0, win 0x179300;
void updateLabelValues() = mac 0x164090, win 0x17b170;
PAD = win 0x4, mac 0x8;
cocos2d::CCMenu* m_playBtnMenu;
@ -4031,13 +4052,13 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg
CCMenuItemSpriteExtra* m_starRateBtn;
CCMenuItemSpriteExtra* m_demonRateBtn;
PAD = win 0x4, mac 0x8;
CCMenuItemToggler* m_toggler;
cocos2d::CCLabelBMFont* m_label0;
cocos2d::CCLabelBMFont* m_label1;
cocos2d::CCLabelBMFont* m_label2;
cocos2d::CCLabelBMFont* m_label3;
cocos2d::CCLabelBMFont* m_label4;
cocos2d::CCLabelBMFont* m_label5;
CCMenuItemToggler* m_ldmToggler;
cocos2d::CCLabelBMFont* m_ldmLabel;
cocos2d::CCLabelBMFont* m_lengthLabel;
cocos2d::CCLabelBMFont* m_downloadsLabel;
cocos2d::CCLabelBMFont* m_likesLabel;
cocos2d::CCLabelBMFont* m_orbsLabel;
cocos2d::CCLabelBMFont* m_folderLabel;
CCMenuItemSpriteExtra* m_cloneBtn;
PAD = win 0x4, mac 0x8;
}
@ -4089,6 +4110,15 @@ class LevelSettingsDelegate {
virtual void levelSettingsUpdated() {}
}
class SecretLayer2 : cocos2d::CCLayer, TextInputDelegate, FLAlertLayerProtocol, DialogDelegate {
static SecretLayer2* create() = win 0x21FD70;
bool init() = win 0x21FE10, mac 0x25fe70;
bool onSubmit(cocos2d::CCObject*) = win 0x221ac0, mac 0x2611a0;
void updateSearchLabel(const char* text) = win 0x222FC0, mac 0x260e10;
void showCompletedLevel() = win 0x220C10;
}
class SecretLayer4 : cocos2d::CCLayer, TextInputDelegate, FLAlertLayerProtocol, DialogDelegate {
static SecretLayer4* create() = mac 0x1ed500;
static cocos2d::CCScene* scene() = mac 0x1ed4c0;
@ -4258,7 +4288,6 @@ class LocalLevelManager : GManager {
cocos2d::CCDictionary* getAllLevelsInDict() = mac 0x35e3d0, win 0x18d7c0;
PAD = mac 0x4, win 0x1C;
cocos2d::CCDictionary* m_loadData;
cocos2d::CCDictionary* m_levelData;
cocos2d::CCArray* m_localLevels;
@ -4320,7 +4349,7 @@ class MoreOptionsLayer : FLAlertLayer, TextInputDelegate, GooglePlayDelegate {
static MoreOptionsLayer* create() = win 0x1de850;
virtual bool init() = mac 0x43f470, win 0x1DE8F0;
void addToggle(const char* name, const char* key, const char* info) = mac 0x440430, win 0x1df6b0;
void onKeybindings(cocos2d::CCObject* sender) = win 0x749d0;
void onKeybindings(cocos2d::CCObject* sender) = mac 0x4410e0, win 0x749d0;
void onToggle(cocos2d::CCObject* sender) = mac 0x441370;
}
@ -4468,11 +4497,14 @@ class PauseLayer : CCBlockLayer {
void createToggleButton(gd::string caption, cocos2d::SEL_MenuHandler callback, bool on, cocos2d::CCMenu* menu, cocos2d::CCPoint pos) = mac 0x20c890, win 0x1e5570;
virtual void customSetup() = mac 0x20b300, win 0x1e4620;
void onRestart(cocos2d::CCObject* sender) = win 0x1e6040;
void onRestart(cocos2d::CCObject* sender) = mac 0x20c860, win 0x1e6040;
void onPracticeMode(cocos2d::CCObject* sender) = mac 0x20c6d0, win 0x1e5f30;
void onNormalMode(cocos2d::CCObject* sender) = mac 0x20c720, win 0x1e5f60;
void onResume(cocos2d::CCObject* sender) = mac 0x20c760, win 0x1e5fa0;
virtual void keyDown(cocos2d::enumKeyCodes) = mac 0x20cc80, win 0x1E6580;
void musicSliderChanged(cocos2d::CCObject* sender) = win 0x1e5ce0;
void sfxSliderChanged(cocos2d::CCObject* sender) = win 0x1ddfa0;
void musicSliderChanged(cocos2d::CCObject* sender) = win 0x1e5ce0, mac 0x20cb00;
void sfxSliderChanged(cocos2d::CCObject* sender) = win 0x1ddfa0, mac 0x20cb40;
bool m_unknown;
bool m_unknown2;
@ -4625,7 +4657,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate,
void spawnFirework() = mac 0x74200;
void spawnParticle(char const*, int, cocos2d::tCCPositionType, cocos2d::CCPoint) = mac 0x76330;
void spawnPlayer2() = mac 0x7d170, win 0x2089e0;
void startGame() = mac 0x726b0;
void startGame() = mac 0x726b0, win 0x1fd390;
void startMusic() = mac 0x72910, win 0x20C8F0;
void startRecording() = mac 0x7fec0;
void startRecordingDelayed() = mac 0x7fed0;
@ -4641,7 +4673,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate,
void toggleBGEffectVisibility(bool) = mac 0x7fe80;
void toggleDualMode(GameObject*, bool, PlayerObject*, bool) = mac 0x7bf90, win 0x208880;
void toggleFlipped(bool, bool) = mac 0x7bdc0, win 0x20ab20;
void toggleGhostEffect(int) = mac 0x7fe40;
void toggleGhostEffect(int) = mac 0x7fe40, win 0x1f8930;
void toggleGlitter(bool) = mac 0x70e00, win 0x20a0d0;
void togglePracticeMode(bool) = mac 0x7f9e0, win 0x20d0d0;
void toggleProgressbar() = mac 0x6eeb0, win 0x208160;
@ -5240,6 +5272,9 @@ class SetGroupIDLayer : FLAlertLayer, TextInputDelegate {
void updateZOrder() = win 0x22e3d0;
void onAddGroup(cocos2d::CCObject* sender) = mac 0x1967d0, win 0x22de20;
void onClose(cocos2d::CCObject* sender) = mac 0x1966a0, win 0x22e830;
void onEditorLayer(cocos2d::CCObject* sender) = win 0x22d690, mac 0x196800;
void onEditorLayer2(cocos2d::CCObject* sender) = win 0x22d710, mac 0x196a40;
void onZOrder(cocos2d::CCObject* sender) = win 0x22de80, mac 0x196920;
GameObject* m_targetObject;
cocos2d::CCArray* m_targetObjects;
@ -5350,12 +5385,14 @@ class SetupOpacityPopup : FLAlertLayer {
class SetupPickupTriggerPopup : FLAlertLayer {
static SetupPickupTriggerPopup* create(EffectGameObject*, cocos2d::CCArray*) = mac 0x35e70, win 0x23d4a0;
bool init(EffectGameObject* obj, cocos2d::CCArray* arr) = win 0x23d550, mac 0x36070;
void onItemIDArrow(cocos2d::CCObject*) = mac 0x37100;
void onNextItemID(cocos2d::CCObject*) = mac 0x37260;
void textChanged(CCTextInputNode*) = mac 0x37ca0;
void updateItemID() = mac 0x37ab0, win 0x23e4f0;
PAD = win 0xc;
PAD = win 0xc, mac 0x18;
CCTextInputNode* m_itemIDInput;
CCTextInputNode* m_countInput;
}
@ -5432,9 +5469,9 @@ class SimplePlayer : cocos2d::CCSprite {
static SimplePlayer* create(int iconID) = mac 0x1b6140, win 0x12bd80;
void updatePlayerFrame(int iconID, IconType iconType) = mac 0x1b62f0, win 0x12c650;
void updateColors() = mac 0x1ba1f0, win 0x12c440, ios 0x224f2c;
void setFrames(const char* firstLayer, const char* secondLayer, const char* birdDome, const char* outlineSprite, const char* detailSprite) = win 0x12c9e0;
void setFrames(const char* firstLayer, const char* secondLayer, const char* birdDome, const char* outlineSprite, const char* detailSprite) = mac 0x1bca10, win 0x12c9e0;
virtual void setColor(const cocos2d::ccColor3B& color) = mac 0x1bc9b0, win 0x12c410;
virtual void setOpacity(unsigned char opacity) = win 0x12cb90;
virtual void setOpacity(unsigned char opacity) = mac 0x135370, win 0x12cb90;
cocos2d::CCSprite* m_firstLayer;
cocos2d::CCSprite* m_secondLayer;
@ -5465,7 +5502,7 @@ class Slider : cocos2d::CCLayer {
SliderTouchLogic* m_touchLogic;
cocos2d::CCSprite* m_sliderBar;
cocos2d::CCSprite* m_groove;
float m_unknown;
float m_width;
float m_height;
}
@ -5542,6 +5579,8 @@ class SpeedObject : cocos2d::CCNode {
float m_somethingToCompare;
float m_idk3;
float m_idk4;
static SpeedObject* create(GameObject*, int, float) = win 0x20DE70;
}
class SpritePartDelegate {}
@ -5741,7 +5780,7 @@ class UILayer : cocos2d::CCLayerColor {
virtual void keyDown(cocos2d::enumKeyCodes key) = mac 0x280470, win 0x25f890;
virtual void keyUp(cocos2d::enumKeyCodes key) = mac 0x280600, win 0x25fa10;
UILayer() = win 0x25f230;
~UILayer() = win 0x25fef0;
~UILayer() = win 0x25fef0, mac 0x280c90;
PAD = mac 0x16, win 0x8, android 0x8;
cocos2d::CCMenu* m_checkPointMenu;

View file

@ -307,6 +307,8 @@ function(package_geode_resources_now proname src dest header_dest)
if (NOT FILE_NAME STREQUAL ".geode_cache" AND NOT FILE_SHOULD_HASH EQUAL -1)
file(SHA256 ${file} COMPUTED_HASH)
file(SIZE ${file} FILE_SIZE)
message(STATUS "Hashed ${file} to ${COMPUTED_HASH} (${FILE_SIZE} bytes)")
list(APPEND HEADER_FILE "\t{ \"${FILE_NAME}\", \"${COMPUTED_HASH}\" },\n")
# list(APPEND HEADER_FILE "\t\"${FILE_NAME}\",\n")

View file

@ -185,7 +185,8 @@ std::string generateBindingHeader(Root const& root, ghc::filesystem::path const&
single_output += fmt::format(::format_strings::class_start,
fmt::arg("class_name", cls.name),
fmt::arg("base_classes", supers)
fmt::arg("base_classes", supers)//,
// fmt::arg("hidden", str_if("GEODE_HIDDEN ", (codegen::platform & (Platform::Mac | Platform::iOS)) != Platform::None))
);
// what.

View file

@ -27,10 +27,13 @@ execute_process(
)
# Package info file for internal representation
set(GEODE_RESOURCES_PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources)
configure_file(resources/mod.json.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/mod.json)
file(READ resources/mod.json LOADER_MOD_JSON)
configure_file(${GEODE_ROOT_PATH}/VERSION ${CMAKE_CURRENT_SOURCE_DIR}/resources/version COPYONLY)
configure_file(${GEODE_ROOT_PATH}/CHANGELOG.md ${CMAKE_CURRENT_SOURCE_DIR}/resources/changelog.md COPYONLY)
configure_file(${GEODE_ROOT_PATH}/VERSION ${GEODE_RESOURCES_PATH}/version COPYONLY)
configure_file(${GEODE_RESOURCES_PATH}/about.md.in ${GEODE_RESOURCES_PATH}/about.md NEWLINE_STYLE LF)
configure_file(${GEODE_ROOT_PATH}/CHANGELOG.md ${GEODE_RESOURCES_PATH}/changelog.md NEWLINE_STYLE LF)
configure_file(${GEODE_RESOURCES_PATH}/support.md.in ${GEODE_RESOURCES_PATH}/support.md NEWLINE_STYLE LF)
configure_file(src/internal/about.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/src/internal/about.hpp)
# Source files

View file

@ -700,12 +700,6 @@ public:
* @param cleanup true if all running actions and callbacks on the child node will be cleanup, false otherwise.
*/
virtual void removeChildByTag(int tag, bool cleanup);
/**
* Removes a child from the container by its ID.
* @param id The ID of the node
* @note Geode addition
*/
void removeChildByID(std::string const& id);
/**
* Removes all children from the container with a cleanup.
*
@ -890,6 +884,13 @@ public:
*/
GEODE_DLL CCNode* getChildByIDRecursive(std::string const& id);
/**
* Removes a child from the container by its ID.
* @param id The ID of the node
* @note Geode addition
*/
GEODE_DLL void removeChildByID(std::string const& id);
/**
* Add a child before a specified existing child
* @param child The node to add. The node may not be a child of another

View file

@ -90,6 +90,7 @@ protected:
bool m_bIsSendCleanupToScene;
public:
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCTransitionScene, CCScene)
/**
* @js ctor
*/
@ -147,6 +148,7 @@ public:
* @js ctor
*/
CCTransitionSceneOriented();
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCTransitionSceneOriented, CCTransitionScene)
/**
* @js NA
* @lua NA
@ -171,6 +173,7 @@ public:
* @js ctor
*/
CCTransitionRotoZoom();
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCTransitionRotoZoom, CCTransitionScene)
/**
* @js NA
* @lua NA
@ -623,6 +626,7 @@ public:
* @js ctor
*/
CCTransitionFade();
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCTransitionFade, CCTransitionScene)
/**
* @js NA
* @lua NA

View file

@ -3,12 +3,8 @@
#include <android/log.h>
#ifdef GEODE_EXPORTING
#define CC_DLL __attribute__((visibility("default")))
#else
#define CC_DLL
#endif
#define ACTUAL_CC_DLL CC_DLL
#define ACTUAL_CC_DLL
#define CC_NO_MESSAGE_PSEUDOASSERT(cond) \
if (!(cond)) { \

View file

@ -3,12 +3,8 @@
#include <assert.h>
#ifdef GEODE_EXPORTING
#define CC_DLL __attribute__((visibility("default")))
#else
#define CC_DLL
#endif
#define ACTUAL_CC_DLL CC_DLL
#define CC_DLL //__attribute__((visibility("hidden")))
#define ACTUAL_CC_DLL
#define CC_ASSERT(cond) assert(cond)

View file

@ -3,12 +3,8 @@
#include <assert.h>
#ifdef GEODE_EXPORTING
#define CC_DLL __attribute__((visibility("default")))
#else
#define CC_DLL
#endif
#define ACTUAL_CC_DLL CC_DLL
#define CC_DLL //__attribute__((visibility("hidden")))
#define ACTUAL_CC_DLL
#if CC_DISABLE_ASSERT > 0

View file

@ -31,7 +31,7 @@ FMOD_RESULT F_API FMOD_File_GetDiskBusy (int *busy);
/*
FMOD System factory functions. Use this to create an FMOD System Instance. below you will see FMOD_System_Init/Close to get started.
*/
FMOD_RESULT F_API FMOD_System_Create (FMOD_SYSTEM **system);
FMOD_RESULT /*F_API*/ FMOD_System_Create (FMOD_SYSTEM **system);
FMOD_RESULT F_API FMOD_System_Release (FMOD_SYSTEM *system);
/*

View file

@ -406,10 +406,12 @@ namespace geode {
bool isLoggingEnabled() const;
void setLoggingEnabled(bool enabled);
bool shouldLoad() const;
friend class ModImpl;
};
}
inline char const* operator"" _spr(char const* str, size_t) {
GEODE_HIDDEN inline char const* operator"" _spr(char const* str, size_t) {
return geode::Mod::get()->expandSpriteName(str);
}

View file

@ -96,6 +96,11 @@ namespace geode {
*/
std::optional<std::string> match;
/**
* The CCTextInputNode's allowed character filter
*/
std::optional<std::string> filter;
static Result<StringSetting> parse(JsonMaybeObject& obj);
};

View file

@ -5,7 +5,7 @@
namespace geode::modifier {
template <uint32_t Id>
uintptr_t address();
GEODE_HIDDEN uintptr_t address();
Result<tulip::hook::HandlerMetadata> handlerMetadataForAddress(uintptr_t address);
}

View file

@ -0,0 +1,77 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include <cocos2d.h>
namespace geode {
enum WrappingMode {
NO_WRAP,
WORD_WRAP,
CUTOFF_WRAP
};
/**
* A class which provides a textarea with proper alignment and some extra features like:
*
* - Max lines
* - Changing all aspects after creation
* - Custom text alignment
* - Configurable and automatic word wrapping
* - Line padding
*
* Contact me on Discord (\@smjs) if you have any questions, suggestions or bugs.
*/
class GEODE_DLL SimpleTextArea : public cocos2d::CCNode {
static SimpleTextArea* create(const std::string& text, const std::string& font = "chatFont.fnt", const float scale = 1);
static SimpleTextArea* create(const std::string& text, const std::string& font, const float scale, const float width);
cocos2d::CCMenu* m_container;
std::string m_font;
std::string m_text;
std::vector<cocos2d::CCLabelBMFont*> m_lines;
cocos2d::ccColor4B m_color;
cocos2d::CCTextAlignment m_alignment;
WrappingMode m_wrappingMode;
size_t m_maxLines;
float m_scale;
float m_lineHeight;
float m_linePadding;
void setFont(const std::string& font);
std::string getFont();
void setColor(const cocos2d::ccColor4B& color);
cocos2d::ccColor4B getColor();
void setAlignment(const cocos2d::CCTextAlignment alignment);
cocos2d::CCTextAlignment getAlignment();
void setWrappingMode(const WrappingMode mode);
WrappingMode getWrappingMode();
void setText(const std::string& text);
std::string getText();
void setMaxLines(const size_t maxLines);
size_t getMaxLines();
void setWidth(const float width);
float getWidth();
void setScale(const float scale);
float getScale();
void setLinePadding(const float padding);
float getLinePadding();
std::vector<cocos2d::CCLabelBMFont*> getLines();
float getHeight();
float getLineHeight();
private:
static SimpleTextArea* create(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth);
bool m_shouldUpdate;
bool m_artificialWidth;
SimpleTextArea(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth);
cocos2d::CCLabelBMFont* createLabel(const std::string& text, const float top);
float calculateOffset(cocos2d::CCLabelBMFont* label);
void charIteration(const std::function<cocos2d::CCLabelBMFont*(cocos2d::CCLabelBMFont* line, const char c, const float top)>& overflowHandling);
void updateLinesNoWrap();
void updateLinesWordWrap();
void updateLinesCutoffWrap();
void updateContainer();
virtual void draw() override;
};
}

View file

@ -953,7 +953,7 @@ namespace geode::cocos {
return m_arr ? m_arr->count() : 0;
}
T operator[](size_t index) {
T* operator[](size_t index) {
return static_cast<T*>(m_arr->objectAtIndex(index));
}

View file

@ -8,68 +8,77 @@
using namespace geode::prelude;
struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
CCLabelBMFont* m_loadedModsLabel;
bool m_updatingResources;
CustomLoadingLayer() : m_loadedModsLabel(nullptr), m_updatingResources(false) {}
CCLabelBMFont* m_smallLabel = nullptr;
int m_geodeLoadStep = 0;
void updateLoadedModsLabel() {
auto allMods = Loader::get()->getAllMods();
auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
return item->isEnabled();
});
auto str = fmt::format("Geode: Loaded {}/{} mods", count, allMods.size());
m_fields->m_loadedModsLabel->setCString(str.c_str());
auto totalCount = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
return item->shouldLoad();
});
auto str = fmt::format("Geode: Loaded {}/{} mods", count, totalCount);
this->setSmallText(str);
}
void setSmallText(std::string const& text) {
m_fields->m_smallLabel->setString(text.c_str());
}
// hook
bool init(bool fromReload) {
CCFileUtils::get()->updatePaths();
if (!LoadingLayer::init(fromReload)) return false;
if (fromReload) return true;
auto winSize = CCDirector::sharedDirector()->getWinSize();
m_fields->m_loadedModsLabel = CCLabelBMFont::create("Geode: Loaded 0/0 mods", "goldFont.fnt");
m_fields->m_loadedModsLabel->setPosition(winSize.width / 2, 30.f);
m_fields->m_loadedModsLabel->setScale(.45f);
m_fields->m_loadedModsLabel->setID("geode-loaded-info");
this->addChild(m_fields->m_loadedModsLabel);
this->updateLoadedModsLabel();
// fields have unpredictable destructors
this->addChild(EventListenerNode<ResourceDownloadFilter>::create(
this, &CustomLoadingLayer::updateResourcesProgress
));
// verify loader resources
if (!LoaderImpl::get()->verifyLoaderResources()) {
m_fields->m_updatingResources = true;
this->setUpdateText("Downloading Resources");
}
else {
LoaderImpl::get()->updateSpecialFiles();
}
m_fields->m_smallLabel = CCLabelBMFont::create("", "goldFont.fnt");
m_fields->m_smallLabel->setPosition(winSize.width / 2, 30.f);
m_fields->m_smallLabel->setScale(.45f);
m_fields->m_smallLabel->setID("geode-small-label");
this->addChild(m_fields->m_smallLabel);
return true;
}
void setUpdateText(std::string const& text) {
m_textArea->setString(text.c_str());
void setupLoadingMods() {
if (Loader::get()->getLoadingState() != Loader::LoadingState::Done) {
this->updateLoadedModsLabel();
this->waitLoadAssets();
}
else {
this->continueLoadAssets();
}
}
void setupLoaderResources() {
// verify loader resources
if (!LoaderImpl::get()->verifyLoaderResources()) {
this->setSmallText("Downloading Loader Resources");
this->addChild(EventListenerNode<ResourceDownloadFilter>::create(
this, &CustomLoadingLayer::updateResourcesProgress
));
}
else {
this->setSmallText("Loading Loader Resources");
LoaderImpl::get()->updateSpecialFiles();
this->continueLoadAssets();
}
}
void updateResourcesProgress(ResourceDownloadEvent* event) {
std::visit(makeVisitor {
[&](UpdateProgress const& progress) {
this->setUpdateText(fmt::format(
"Downloading Resources: {}%", progress.first
this->setSmallText(fmt::format(
"Downloading Loader Resources: {}%", progress.first
));
},
[&](UpdateFinished) {
this->setUpdateText("Resources Downloaded");
m_fields->m_updatingResources = false;
this->loadAssets();
this->setSmallText("Downloaded Loader Resources");
this->continueLoadAssets();
},
[&](UpdateFailed const& error) {
LoaderImpl::get()->platformMessageBox(
@ -81,24 +90,70 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
"The game will be loaded as normal, but please be aware "
"that it is very likely to crash. "
);
this->setUpdateText("Resource Download Failed");
m_fields->m_updatingResources = false;
this->loadAssets();
this->setSmallText("Failed Loader Resources");
this->continueLoadAssets();
}
}, event->status);
}
void loadAssets() {
if (Loader::get()->getLoadingState() != Loader::LoadingState::Done) {
this->updateLoadedModsLabel();
void setupModResources() {
log::debug("Loading mod resources");
this->setSmallText("Loading mod resources");
Loader::get()->updateResources(true);
this->continueLoadAssets();
}
int getCurrentStep() {
return m_fields->m_geodeLoadStep + m_loadStep + 1;
}
int getTotalStep() {
return 18;
}
void updateLoadingBar() {
auto length = m_sliderGrooveXPos * this->getCurrentStep() / this->getTotalStep();
m_sliderBar->setTextureRect({0, 0, length, m_sliderGrooveHeight});
}
void waitLoadAssets() {
Loader::get()->queueInMainThread([this]() {
this->loadAssets();
});
return;
}
if (m_fields->m_updatingResources) {
return;
void continueLoadAssets() {
++m_fields->m_geodeLoadStep;
Loader::get()->queueInMainThread([this]() {
this->loadAssets();
});
}
bool skipOnRefresh() {
if (m_fromRefresh) {
this->continueLoadAssets();
}
return !m_fromRefresh;
}
// hook
void loadAssets() {
switch (m_fields->m_geodeLoadStep) {
case 0:
if (this->skipOnRefresh()) this->setupLoadingMods();
break;
case 1:
if (this->skipOnRefresh()) this->setupLoaderResources();
break;
case 2:
this->setupModResources();
break;
case 3:
default:
this->setSmallText("Loading game resources");
LoadingLayer::loadAssets();
break;
}
this->updateLoadingBar();
}
};

View file

@ -1,15 +0,0 @@
#include <Geode/loader/Loader.hpp>
#include <Geode/modify/LoadingLayer.hpp>
#include <Geode/modify/GameManager.hpp>
using namespace geode::prelude;
struct ResourcesUpdate : Modify<ResourcesUpdate, LoadingLayer> {
void loadAssets() {
LoadingLayer::loadAssets();
// this is in case the user refreshes texture quality at runtime
if (m_loadStep == 10) {
Loader::get()->updateResources(true);
}
}
};

View file

@ -7,8 +7,11 @@
using namespace geode::prelude;
$register_ids(GJGarageLayer) {
// the lock does not exist for not logged in users
auto loggedInOffset = GJAccountManager::get()->m_accountID == GJAccountManager::get()->m_playerID ? -1 : 0;
setIDSafe(this, 2, "username-label");
setIDSafe(this, 6, "player-icon");
setIDSafe(this, 6 + loggedInOffset, "player-icon");
auto winSize = CCDirector::get()->getWinSize();
@ -39,7 +42,7 @@ $register_ids(GJGarageLayer) {
setIDs(
this,
10,
10 + loggedInOffset,
"cube-selection-menu",
"ship-selection-menu",
"ball-selection-menu",

View file

@ -408,7 +408,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
return;
}
if (Mod::get()->getSavedValue<bool>("should-load-" + node->getID(), true)) {
if (node->shouldLoad()) {
log::debug("Load");
auto res = node->m_impl->loadBinary();
if (!res) {
@ -432,6 +432,10 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
void Loader::Impl::findProblems() {
for (auto const& [id, mod] : m_mods) {
if (!mod->shouldLoad()) {
log::debug("{} is not enabled", id);
continue;
}
log::debug(id);
log::pushNest();
@ -492,7 +496,7 @@ void Loader::Impl::findProblems() {
Mod* myEpicMod = mod; // clang fix
// if the mod is not loaded but there are no problems related to it
if (!mod->isEnabled() &&
Mod::get()->getSavedValue<bool>("should-load-" + mod->getID(), true) &&
mod->shouldLoad() &&
!std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) {
return std::holds_alternative<ModMetadata>(item.cause) &&
std::get<ModMetadata>(item.cause).getID() == myEpicMod->getID() ||
@ -777,7 +781,7 @@ void Loader::Impl::downloadLoaderResources(bool useLatestRelease) {
.json()
.then([this](json::Value const& json) {
this->tryDownloadLoaderResources(fmt::format(
"https://github.com/geode-sdk/geode/releases/download/{}/resources-" GEODE_PLATFORM_SHORT_IDENTIFIER ".zip",
"https://github.com/geode-sdk/geode/releases/download/{}/resources.zip",
this->getVersion().toString()
), true);
})
@ -805,7 +809,7 @@ void Loader::Impl::downloadLoaderResources(bool useLatestRelease) {
// find release asset
for (auto asset : root.needs("assets").iterate()) {
auto obj = asset.obj();
if (obj.needs("name").template get<std::string>() == "resources-" GEODE_PLATFORM_SHORT_IDENTIFIER ".zip") {
if (obj.needs("name").template get<std::string>() == "resources.zip") {
this->tryDownloadLoaderResources(
obj.needs("browser_download_url").template get<std::string>(),
false

View file

@ -13,7 +13,6 @@
#include <Geode/utils/ranges.hpp>
#include <Geode/utils/MiniFunction.hpp>
#include "ModImpl.hpp"
#include <about.hpp>
#include <crashlog.hpp>
#include <mutex>
#include <optional>

View file

@ -245,3 +245,7 @@ void Mod::setLoggingEnabled(bool enabled) {
bool Mod::hasSavedValue(std::string const& key) {
return this->getSaveContainer().contains(key);
}
bool Mod::shouldLoad() const {
return m_impl->shouldLoad();
}

View file

@ -43,7 +43,9 @@ Result<> Mod::Impl::setup() {
log::warn("Unable to load data for \"{}\": {}", m_metadata.getID(), loadRes.unwrapErr());
}
if (!m_resourcesLoaded) {
LoaderImpl::get()->updateModResources(m_self);
auto searchPathRoot = dirs::getModRuntimeDir() / m_metadata.getID() / "resources";
CCFileUtils::get()->addSearchPath(searchPathRoot.string().c_str());
m_resourcesLoaded = true;
}
@ -590,14 +592,13 @@ ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const {
}
char const* Mod::Impl::expandSpriteName(char const* name) {
static std::unordered_map<std::string, char const*> expanded = {};
if (expanded.count(name)) return expanded[name];
if (m_expandedSprites.count(name)) return m_expandedSprites[name];
auto exp = new char[strlen(name) + 2 + m_metadata.getID().size()];
auto exps = m_metadata.getID() + "/" + name;
memcpy(exp, exps.c_str(), exps.size() + 1);
expanded[name] = exp;
m_expandedSprites[name] = exp;
return exp;
}
@ -633,6 +634,10 @@ void Mod::Impl::setLoggingEnabled(bool enabled) {
m_loggingEnabled = enabled;
}
bool Mod::Impl::shouldLoad() const {
return Mod::get()->getSavedValue<bool>("should-load-" + m_metadata.getID(), true);
}
static Result<ModMetadata> getModImplInfo() {
std::string err;
json::Value json;

View file

@ -61,6 +61,8 @@ namespace geode {
*/
bool m_loggingEnabled = true;
std::unordered_map<std::string, char const*> m_expandedSprites;
ModRequestedAction m_requestedAction = ModRequestedAction::None;
@ -137,6 +139,8 @@ namespace geode {
bool isLoggingEnabled() const;
void setLoggingEnabled(bool enabled);
bool shouldLoad() const;
};
class ModImpl : public Mod::Impl {

View file

@ -62,6 +62,7 @@ Result<StringSetting> StringSetting::parse(JsonMaybeObject& obj) {
StringSetting sett;
parseCommon(sett, obj);
obj.has("match").into(sett.match);
obj.has("filter").into(sett.filter);
return Ok(sett);
}

View file

@ -68,7 +68,7 @@ CCNode* geode::createDefaultLogo(CCSize const& size) {
if (!spr) {
spr = CCLabelBMFont::create("OwO", "goldFont.fnt");
}
limitNodeSize(spr, size, 1.f, .1f);
limitNodeSize(spr, size, 1.f, .01f);
return spr;
}
@ -78,7 +78,7 @@ CCNode* geode::createModLogo(Mod* mod, CCSize const& size) {
CCSprite::create(fmt::format("{}/logo.png", mod->getID()).c_str());
if (!spr) spr = CCSprite::createWithSpriteFrameName("no-logo.png"_spr);
if (!spr) spr = CCLabelBMFont::create("N/A", "goldFont.fnt");
limitNodeSize(spr, size, 1.f, .1f);
limitNodeSize(spr, size, 1.f, .01f);
spr->setPosition(size/2);
spr->setAnchorPoint({.5f, .5f});
@ -116,7 +116,7 @@ CCNode* geode::createIndexItemLogo(IndexItemHandle item, CCSize const& size) {
spr = logoGlow;
}
else {
limitNodeSize(spr, size, 1.f, .1f);
limitNodeSize(spr, size, 1.f, .01f);
}
spr->setPosition(size/2);
spr->setAnchorPoint({.5f, .5f});

View file

@ -5,8 +5,9 @@
#include "../list/ModListCell.hpp"
#include "../list/ModListLayer.hpp"
bool DevProfilePopup::setup(std::string const& developer) {
bool DevProfilePopup::setup(std::string const& developer, ModListLayer* list) {
m_noElasticity = true;
m_layer = list;
this->setTitle("Mods by " + developer);
@ -18,7 +19,7 @@ bool DevProfilePopup::setup(std::string const& developer) {
for (auto& mod : Loader::get()->getAllMods()) {
if (mod->getDeveloper() == developer) {
auto cell = ModCell::create(
mod, nullptr, ModListDisplay::Concise, { 358.f, 40.f }
mod, m_layer, ModListDisplay::Concise, { 358.f, 40.f }
);
cell->disableDeveloperButton();
items->addObject(cell);
@ -31,7 +32,7 @@ bool DevProfilePopup::setup(std::string const& developer) {
continue;
}
auto cell = IndexItemCell::create(
item, nullptr, ModListDisplay::Concise, { 358.f, 40.f }
item, m_layer, ModListDisplay::Concise, { 358.f, 40.f }
);
cell->disableDeveloperButton();
items->addObject(cell);
@ -39,18 +40,18 @@ bool DevProfilePopup::setup(std::string const& developer) {
// mods list
auto listSize = CCSize { 358.f, 160.f };
auto list = ListView::create(items, 40.f, listSize.width, listSize.height);
list->setPosition(winSize / 2 - listSize / 2);
m_mainLayer->addChild(list);
auto cellList = ListView::create(items, 40.f, listSize.width, listSize.height);
cellList->setPosition(winSize / 2 - listSize / 2);
m_mainLayer->addChild(cellList);
addListBorders(m_mainLayer, winSize / 2, listSize);
return true;
}
DevProfilePopup* DevProfilePopup::create(std::string const& developer) {
DevProfilePopup* DevProfilePopup::create(std::string const& developer, ModListLayer* list) {
auto ret = new DevProfilePopup();
if (ret && ret->init(420.f, 260.f, developer)) {
if (ret && ret->init(420.f, 260.f, developer, list)) {
ret->autorelease();
return ret;
}

View file

@ -4,10 +4,14 @@
using namespace geode::prelude;
class DevProfilePopup : public Popup<std::string const&> {
class ModListLayer;
class DevProfilePopup : public Popup<std::string const&, ModListLayer*> {
protected:
bool setup(std::string const& developer) override;
ModListLayer* m_layer;
bool setup(std::string const& developer, ModListLayer* list) override;
public:
static DevProfilePopup* create(std::string const& developer);
static DevProfilePopup* create(std::string const& developer, ModListLayer* list);
};

View file

@ -4,6 +4,7 @@
#include "../list/ModListLayer.hpp"
#include "../settings/ModSettingsPopup.hpp"
#include <Geode/loader/Dirs.hpp>
#include <about.hpp>
#include <Geode/binding/ButtonSprite.hpp>
#include <Geode/binding/CCTextInputNode.hpp>
@ -49,45 +50,51 @@ bool ModInfoPopup::init(ModMetadata const& metadata, ModListLayer* list) {
constexpr float logoSize = 40.f;
constexpr float logoOffset = 10.f;
auto nameLabel = CCLabelBMFont::create(metadata.getName().c_str(), "bigFont.fnt");
nameLabel->setAnchorPoint({ .0f, .5f });
nameLabel->limitLabelWidth(200.f, .7f, .1f);
m_mainLayer->addChild(nameLabel, 2);
auto topNode = CCNode::create();
topNode->setContentSize({350.f, 80.f});
topNode->setLayout(
RowLayout::create()
->setAxisAlignment(AxisAlignment::Center)
->setAutoScale(false)
->setCrossAxisOverflow(true)
);
m_mainLayer->addChild(topNode);
topNode->setAnchorPoint({.5f, .5f});
topNode->setPosition(winSize.width / 2, winSize.height / 2 + 115.f);
auto logoSpr = this->createLogo({logoSize, logoSize});
m_mainLayer->addChild(logoSpr);
topNode->addChild(logoSpr);
auto labelNode = CCNode::create();
labelNode->setLayout(
ColumnLayout::create()
->setAxisAlignment(AxisAlignment::Center)
->setCrossAxisLineAlignment(AxisAlignment::Start)
->setGap(0.f)
->setAutoScale(false)
->setCrossAxisOverflow(true)
);
labelNode->setContentSize({200.f, 80.f});
topNode->addChild(labelNode);
auto nameLabel = CCLabelBMFont::create(metadata.getName().c_str(), "bigFont.fnt");
nameLabel->limitLabelWidth(200.f, .7f, .1f);
labelNode->addChild(nameLabel, 2);
auto developerStr = "by " + metadata.getDeveloper();
auto developerLabel = CCLabelBMFont::create(developerStr.c_str(), "goldFont.fnt");
developerLabel->setScale(.5f);
developerLabel->setAnchorPoint({.0f, .5f});
m_mainLayer->addChild(developerLabel);
auto logoTitleWidth =
std::max(nameLabel->getScaledContentSize().width, developerLabel->getScaledContentSize().width) +
logoSize + logoOffset;
nameLabel->setPosition(
winSize.width / 2 - logoTitleWidth / 2 + logoSize + logoOffset, winSize.height / 2 + 125.f
);
logoSpr->setPosition(
{winSize.width / 2 - logoTitleWidth / 2 + logoSize / 2, winSize.height / 2 + 115.f}
);
developerLabel->setPosition(
winSize.width / 2 - logoTitleWidth / 2 + logoSize + logoOffset, winSize.height / 2 + 105.f
);
labelNode->addChild(developerLabel);
auto versionLabel = CCLabelBMFont::create(metadata.getVersion().toString().c_str(),
"bigFont.fnt"
);
versionLabel->setAnchorPoint({ .0f, .5f });
versionLabel->setScale(.4f);
versionLabel->setPosition(
nameLabel->getPositionX() + nameLabel->getScaledContentSize().width + 5.f,
winSize.height / 2 + 125.f
);
versionLabel->setColor({0, 255, 0});
m_mainLayer->addChild(versionLabel);
topNode->addChild(versionLabel);
labelNode->updateLayout();
topNode->updateLayout();
this->setTouchEnabled(true);
@ -425,7 +432,7 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) {
disableBtnSpr, enableBtnSpr, this, menu_selector(LocalModInfoPopup::onEnableMod)
);
enableBtn->setPosition(-155.f, 75.f);
enableBtn->toggle(!mod->isEnabled());
enableBtn->toggle(!mod->shouldLoad());
m_buttonMenu->addChild(enableBtn);
if (!mod->supportsDisabling()) {
@ -629,9 +636,9 @@ void LocalModInfoPopup::onEnableMod(CCObject* sender) {
}
}
if (m_layer) {
m_layer->updateAllStates();
m_layer->reloadList();
}
as<CCMenuItemToggler*>(sender)->toggle(m_mod->isEnabled());
as<CCMenuItemToggler*>(sender)->toggle(m_mod->shouldLoad());
}
void LocalModInfoPopup::onOpenConfigDir(CCObject*) {
@ -640,7 +647,7 @@ void LocalModInfoPopup::onOpenConfigDir(CCObject*) {
void LocalModInfoPopup::onDisablingNotSupported(CCObject* pSender) {
FLAlertLayer::create("Unsupported", "<cr>Disabling</c> is not supported for this mod.", "OK")->show();
as<CCMenuItemToggler*>(pSender)->toggle(m_mod->isEnabled());
as<CCMenuItemToggler*>(pSender)->toggle(m_mod->shouldLoad());
}
void LocalModInfoPopup::onSettings(CCObject*) {

View file

@ -53,24 +53,21 @@ void InstallListCell::setupInfo(
}
this->addChild(m_titleLabel);
m_developerBtn = nullptr;
m_creatorLabel = nullptr;
if (developer) {
auto creatorStr = "by " + *developer;
auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
creatorLabel->setScale(.34f);
m_creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
m_creatorLabel->setScale(.34f);
if (inactive) {
creatorLabel->setColor({ 163, 163, 163 });
m_creatorLabel->setColor({ 163, 163, 163 });
}
m_developerBtn = CCMenuItemSpriteExtra::create(
creatorLabel, this, menu_selector(InstallListCell::onViewDev)
);
m_developerBtn->setPosition(
m_creatorLabel->setPosition(
m_titleLabel->getPositionX() + m_titleLabel->getScaledContentSize().width + 3.f +
creatorLabel->getScaledContentSize().width / 2,
m_creatorLabel->getScaledContentSize().width / 2,
m_height / 2
);
m_menu->addChild(m_developerBtn);
m_menu->addChild(m_creatorLabel);
}
this->setupVersion(version);
@ -96,7 +93,7 @@ void InstallListCell::setupVersion(std::variant<VersionInfo, ComparableVersionIn
m_versionLabel->setScale(.2f);
m_versionLabel->setPosition(
m_titleLabel->getPositionX() + m_titleLabel->getScaledContentSize().width + 3.f +
(m_developerBtn ? m_developerBtn->getScaledContentSize().width + 3.f : 0.f),
(m_creatorLabel ? m_creatorLabel->getScaledContentSize().width + 3.f : 0.f),
m_titleLabel->getPositionY() - 1.f
);
m_versionLabel->setColor({ 0, 255, 0 });
@ -123,7 +120,7 @@ void InstallListCell::setupInfo(ModMetadata const& metadata, bool inactive) {
}
void InstallListCell::onViewDev(CCObject*) {
DevProfilePopup::create(getDeveloper())->show();
// DevProfilePopup::create(getDeveloper(), m_layer)->show();
}
bool InstallListCell::init(InstallListPopup* list, CCSize const& size) {

View file

@ -21,7 +21,7 @@ protected:
float m_height;
InstallListPopup* m_layer = nullptr;
CCMenu* m_menu = nullptr;
CCMenuItemSpriteExtra* m_developerBtn = nullptr;
CCLabelBMFont* m_creatorLabel = nullptr;
CCLabelBMFont* m_titleLabel = nullptr;
CCLabelBMFont* m_versionLabel = nullptr;
TagNode* m_tagLabel = nullptr;

View file

@ -113,7 +113,7 @@ CCArray* InstallListPopup::createCells(std::unordered_map<std::string, InstallLi
// installed
// TODO: we should be able to select a different version even if its installed
if (/*item.mod && !item.mod->isUninstalled()*/item.mod->getMetadata().getID() == "geode.loader") {
if (item.mod && /*!item.mod->isUninstalled()*/item.mod->getMetadata().getID() == "geode.loader") {
bottom.push_back(ModInstallListCell::create(item.mod, this, this->getCellSize()));
for (auto const& dep : item.mod->getMetadata().getDependencies()) {
queue.push(dep);

View file

@ -186,7 +186,7 @@ void ModListCell::updateCellLayout() {
}
void ModListCell::onViewDev(CCObject*) {
DevProfilePopup::create(this->getDeveloper())->show();
DevProfilePopup::create(this->getDeveloper(), m_layer)->show();
}
bool ModListCell::init(ModListLayer* list, CCSize const& size) {
@ -233,8 +233,10 @@ void ModCell::onEnable(CCObject* sender) {
else {
tryOrAlert(m_mod->disable(), "Error disabling mod");
}
if (m_layer) {
m_layer->reloadList();
}
}
void ModCell::onUnresolvedInfo(CCObject*) {
ProblemsListPopup::create(m_mod)->show();
@ -250,13 +252,15 @@ void ModCell::onRestart(CCObject*) {
void ModCell::updateState() {
bool unresolved = m_mod->hasUnresolvedDependencies();
bool shouldLoad = m_mod->shouldLoad();
auto toggleable = !unresolved || !shouldLoad;
if (m_enableToggle) {
m_enableToggle->toggle(m_mod->isEnabled());
m_enableToggle->setEnabled(!unresolved);
m_enableToggle->m_offButton->setOpacity(unresolved ? 100 : 255);
m_enableToggle->m_offButton->setColor(unresolved ? cc3x(155) : cc3x(255));
m_enableToggle->m_onButton->setOpacity(unresolved ? 100 : 255);
m_enableToggle->m_onButton->setColor(unresolved ? cc3x(155) : cc3x(255));
m_enableToggle->setEnabled(toggleable);
m_enableToggle->m_offButton->setOpacity(!toggleable ? 100 : 255);
m_enableToggle->m_offButton->setColor(!toggleable ? cc3x(155) : cc3x(255));
m_enableToggle->m_onButton->setOpacity(!toggleable ? 100 : 255);
m_enableToggle->m_onButton->setColor(!toggleable ? cc3x(155) : cc3x(255));
}
bool hasProblems = false;
for (auto const& item : Loader::get()->getProblems()) {
@ -309,9 +313,6 @@ bool ModCell::init(
auto viewSpr = ButtonSprite::create("View", "bigFont.fnt", "GJ_button_01.png", .8f);
viewSpr->setScale(.65f);
auto viewBtn = CCMenuItemSpriteExtra::create(viewSpr, this, menu_selector(ModCell::onInfo));
m_menu->addChild(viewBtn);
if (m_mod->isEnabled()) {
auto latestIndexItem = Index::get()->getMajorItem(
mod->getMetadata().getID()
@ -333,6 +334,9 @@ bool ModCell::init(
}
}
}
auto viewBtn = CCMenuItemSpriteExtra::create(viewSpr, this, menu_selector(ModCell::onInfo));
m_menu->addChild(viewBtn);
}
this->updateState();

View file

@ -324,6 +324,11 @@ bool StringSettingNode::setup(StringSettingValue* setting, float width) {
m_input = InputNode::create(width / 2 - 10.f, "Text", "chatFont.fnt");
m_input->setPosition({ -(width / 2 - 70.f) / 2, .0f });
m_input->setScale(.65f);
if (setting->castDefinition().filter.has_value()) {
m_input->getInput()->setAllowedChars(setting->castDefinition().filter.value());
}
m_input->getInput()->setDelegate(this);
m_menu->addChild(m_input);

View file

@ -109,8 +109,8 @@ bool MDTextArea::init(std::string const& str, CCSize const& size) {
if (!CCLayer::init()) return false;
m_text = str;
m_size = size;
this->setContentSize(size);
m_size = size - CCSize { 15.f, 0.f };
this->setContentSize(m_size);
m_renderer = TextRenderer::create();
CC_SAFE_RETAIN(m_renderer);
@ -118,8 +118,8 @@ bool MDTextArea::init(std::string const& str, CCSize const& size) {
m_bgSprite->setScale(.5f);
m_bgSprite->setColor({ 0, 0, 0 });
m_bgSprite->setOpacity(75);
m_bgSprite->setContentSize(size * 2 + CCSize { 25.f, 25.f });
m_bgSprite->setPosition(size / 2);
m_bgSprite->setContentSize(size * 2);
m_bgSprite->setPosition(m_size / 2);
this->addChild(m_bgSprite);
m_scrollLayer = ScrollLayer::create({ 0, 0, m_size.width, m_size.height }, true);
@ -209,6 +209,7 @@ struct MDParser {
static float s_codeStart;
static size_t s_orderedListNum;
static std::vector<TextRenderer::Label> s_codeSpans;
static bool s_breakListLine;
static int parseText(MD_TEXTTYPE type, MD_CHAR const* rawText, MD_SIZE size, void* mdtextarea) {
auto textarea = static_cast<MDTextArea*>(mdtextarea);
@ -364,6 +365,10 @@ struct MDParser {
renderer->pushIndent(g_indent);
s_isOrderedList = type == MD_BLOCKTYPE::MD_BLOCK_OL;
s_orderedListNum = 0;
if (s_breakListLine) {
renderer->breakLine();
s_breakListLine = false;
}
}
break;
@ -377,6 +382,10 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_LI:
{
if (s_breakListLine) {
renderer->breakLine();
s_breakListLine = false;
}
renderer->pushOpacity(renderer->getCurrentOpacity() / 2);
auto lidetail = static_cast<MD_BLOCK_LI_DETAIL*>(detail);
if (s_isOrderedList) {
@ -387,6 +396,7 @@ struct MDParser {
renderer->renderString("");
}
renderer->popOpacity();
s_breakListLine = true;
}
break;
@ -446,7 +456,13 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_UL:
{
renderer->popIndent();
if (s_breakListLine) {
renderer->breakLine();
s_breakListLine = false;
}
if (renderer->getCurrentIndent() == 0) {
renderer->breakLine();
}
}
break;
@ -489,7 +505,6 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_LI:
{
renderer->breakLine();
}
break;
@ -626,6 +641,7 @@ size_t MDParser::s_orderedListNum = 0;
bool MDParser::s_isCodeBlock = false;
float MDParser::s_codeStart = 0;
decltype(MDParser::s_codeSpans) MDParser::s_codeSpans = {};
bool MDParser::s_breakListLine = false;
void MDTextArea::updateLabel() {
m_renderer->begin(m_content, CCPointZero, m_size);
@ -679,7 +695,16 @@ void MDTextArea::updateLabel() {
m_renderer->end();
if (m_content->getContentSize().height > m_size.height) {
// Generate bottom padding
m_scrollLayer->m_contentLayer->setContentSize(m_content->getContentSize() + CCSize { 0.f, 12.5 });
m_content->setPositionY(10.f);
} else {
m_scrollLayer->m_contentLayer->setContentSize(m_content->getContentSize());
m_content->setPositionY(-2.5f);
}
m_scrollLayer->moveToTop();
}

View file

@ -0,0 +1,300 @@
#include <Geode/ui/TextArea.hpp>
using namespace geode::prelude;
SimpleTextArea* SimpleTextArea::create(const std::string& text, const std::string& font, const float scale) {
return SimpleTextArea::create(font, text, scale, CCDirector::sharedDirector()->getWinSize().width / 2, false);
}
SimpleTextArea* SimpleTextArea::create(const std::string& text, const std::string& font, const float scale, const float width) {
return SimpleTextArea::create(font, text, scale, width, true);
}
SimpleTextArea* SimpleTextArea::create(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth) {
SimpleTextArea* instance = new SimpleTextArea(font, text, scale, width, artificialWidth);
if (instance && instance->init()) {
instance->autorelease();
return instance;
} else {
CC_SAFE_DELETE(instance);
return nullptr;
}
}
SimpleTextArea::SimpleTextArea(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth) {
m_font = font;
m_text = text;
m_maxLines = 0;
m_scale = scale;
m_linePadding = 0;
m_color = { 0xFF, 0xFF, 0xFF, 0xFF };
m_alignment = kCCTextAlignmentLeft;
m_wrappingMode = WORD_WRAP;
m_artificialWidth = artificialWidth;
m_container = CCMenu::create();
m_shouldUpdate = true;
this->setAnchorPoint({ 0.5f, 0.5f });
m_container->setPosition({ 0, 0 });
m_container->setAnchorPoint({ 0, 1 });
m_container->setContentSize({ width, 0 });
this->addChild(m_container);
}
void SimpleTextArea::setFont(const std::string& font) {
m_font = font;
m_shouldUpdate = true;
}
std::string SimpleTextArea::getFont() {
return m_font;
}
void SimpleTextArea::setColor(const ccColor4B& color) {
m_color = color;
m_shouldUpdate = true;
}
ccColor4B SimpleTextArea::getColor() {
return m_color;
}
void SimpleTextArea::setAlignment(const CCTextAlignment alignment) {
m_alignment = alignment;
m_shouldUpdate = true;
}
CCTextAlignment SimpleTextArea::getAlignment() {
return m_alignment;
}
void SimpleTextArea::setWrappingMode(const WrappingMode mode) {
m_wrappingMode = mode;
m_shouldUpdate = true;
}
WrappingMode SimpleTextArea::getWrappingMode() {
return m_wrappingMode;
}
void SimpleTextArea::setText(const std::string& text) {
m_text = text;
m_shouldUpdate = true;
}
std::string SimpleTextArea::getText() {
return m_text;
}
void SimpleTextArea::setMaxLines(const size_t maxLines) {
m_maxLines = maxLines;
m_shouldUpdate = true;
}
size_t SimpleTextArea::getMaxLines() {
return m_maxLines;
}
void SimpleTextArea::setWidth(const float width) {
m_artificialWidth = true;
m_shouldUpdate = true;
this->setContentSize({ width, this->getContentSize().height });
m_container->setContentSize(this->getContentSize());
}
float SimpleTextArea::getWidth() {
return m_container->getContentSize().width;
}
void SimpleTextArea::setScale(const float scale) {
m_scale = scale;
m_shouldUpdate = true;
}
float SimpleTextArea::getScale() {
return m_scale;
}
void SimpleTextArea::setLinePadding(const float padding) {
m_linePadding = padding;
m_shouldUpdate = true;
}
float SimpleTextArea::getLinePadding() {
return m_linePadding;
}
std::vector<CCLabelBMFont*> SimpleTextArea::getLines() {
return m_lines;
}
float SimpleTextArea::getHeight() {
return m_container->getContentSize().height;
}
float SimpleTextArea::getLineHeight() {
return m_lineHeight;
}
CCLabelBMFont* SimpleTextArea::createLabel(const std::string& text, const float top) {
CCLabelBMFont* label = CCLabelBMFont::create(text.c_str(), m_font.c_str());
label->setScale(m_scale);
label->setPosition({ 0, top });
label->setColor({ m_color.r, m_color.g, m_color.b });
label->setOpacity(m_color.a);
return label;
}
float SimpleTextArea::calculateOffset(CCLabelBMFont* label) {
return m_linePadding + label->getContentSize().height * m_scale;
}
void SimpleTextArea::charIteration(const std::function<CCLabelBMFont*(CCLabelBMFont* line, const char c, const float top)>& overflowHandling) {
float top = 0;
CCLabelBMFont* line = this->createLabel("", top);
m_lines = { line };
for (const char c : m_text) {
if (m_maxLines && m_lines.size() > m_maxLines) {
CCLabelBMFont* last = m_lines.at(m_maxLines - 1);
const std::string text = last->getString();
m_lines.pop_back();
last->setString(text.substr(0, text.size() - 3).append("...").c_str());
break;
} else if (c == '\n') {
m_lines.push_back(line = this->createLabel("", top -= this->calculateOffset(line)));
} else if (m_artificialWidth && line->getContentSize().width * m_scale >= this->getWidth()) {
m_lines.push_back(line = overflowHandling(line, c, top -= this->calculateOffset(line)));
} else {
line->setString((std::string(line->getString()) + c).c_str());
}
}
}
void SimpleTextArea::updateLinesNoWrap() {
std::stringstream stream(m_text);
std::string part;
float top = 0;
while (std::getline(stream, part)) {
if (m_maxLines && m_lines.size() >= m_maxLines) {
CCLabelBMFont* last = m_lines.at(m_maxLines - 1);
const std::string text = last->getString();
last->setString(text.substr(0, text.size() - 3).append("...").c_str());
break;
} else {
CCLabelBMFont* line = this->createLabel(part, 0);
top -= this->calculateOffset(line);
m_lines.push_back(line);
}
}
}
void SimpleTextArea::updateLinesWordWrap() {
this->charIteration([this](CCLabelBMFont* line, const char c, const float top) {
static std::string delimiters(" `~!@#$%^&*()-_=+[{}];:'\",<.>/?\\|");
if (delimiters.find(c) == std::string_view::npos) {
const std::string text = line->getString();
const size_t position = text.find_last_of(delimiters) + 1;
line->setString(text.substr(0, position).c_str());
return this->createLabel(text.substr(position) + c, top);
} else {
return this->createLabel(std::string(c, c != ' '), top);
}
});
}
void SimpleTextArea::updateLinesCutoffWrap() {
this->charIteration([this](CCLabelBMFont* line, const char c, const float top) {
const std::string text = line->getString();
const char back = text.back();
const bool lastIsSpace = back == ' ';
CCLabelBMFont* newLine = this->createLabel(std::string(!lastIsSpace, back).append(std::string(c != ' ', c)), top);
if (!lastIsSpace) {
if (text[text.size() - 2] == ' ') {
line->setString(text.substr(0, text.size() - 1).c_str());
} else {
line->setString((text.substr(0, text.size() - 1) + '-').c_str());
}
}
return newLine;
});
}
void SimpleTextArea::updateContainer() {
switch (m_wrappingMode) {
case NO_WRAP: {
this->updateLinesNoWrap();
} break;
case WORD_WRAP: {
this->updateLinesWordWrap();
} break;
case CUTOFF_WRAP: {
this->updateLinesCutoffWrap();
} break;
}
const size_t lineCount = m_lines.size();
const float width = this->getWidth();
if (lineCount > 0) {
m_lineHeight = m_lines.back()->getContentSize().height * m_scale;
} else {
m_lineHeight = 0;
}
float height = m_lineHeight * lineCount + m_linePadding * (lineCount - 1);
this->setContentSize({ width, height });
m_container->setContentSize(this->getContentSize());
m_container->removeAllChildren();
for (CCLabelBMFont* line : m_lines) {
const float y = height + line->getPositionY();
switch (m_alignment) {
case kCCTextAlignmentLeft: {
line->setAnchorPoint({ 0, 1 });
line->setPosition({ 0, y });
} break;
case kCCTextAlignmentCenter: {
line->setAnchorPoint({ 0, 1 });
line->setPosition({ width / 2, y });
} break;
case kCCTextAlignmentRight: {
line->setAnchorPoint({ 1, 1 });
line->setPosition({ width, y });
} break;
}
m_container->addChild(line);
}
}
void SimpleTextArea::draw() {
CCNode::draw();
if (m_shouldUpdate) {
this->updateContainer();
m_shouldUpdate = false;
}
}

View file

@ -341,8 +341,8 @@ std::vector<TextRenderer::Label> TextRenderer::renderStringEx(
auto lastIndent =
m_indentationStack.size() > 1 ? m_indentationStack.at(m_indentationStack.size() - 1) : .0f;
if (m_cursor.x == m_origin.x + lastIndent && this->getCurrentIndent() > .0f) {
m_cursor.x += this->getCurrentIndent();
if (m_cursor.x < m_origin.x + this->getCurrentIndent()) {
m_cursor.x = this->getCurrentIndent();
}
auto createLabel = [&]() -> bool {
@ -487,7 +487,7 @@ void TextRenderer::breakLine(float incY) {
}
if (h > y) y = h;
m_cursor.y -= y;
m_cursor.x = m_origin.x + getCurrentIndent();
m_cursor.x = m_origin.x;
}
float TextRenderer::adjustLineAlignment() {

View file

@ -21,12 +21,17 @@ using namespace geode::prelude;
using namespace geode::utils::file;
Result<std::string> utils::file::readString(ghc::filesystem::path const& path) {
if (!ghc::filesystem::exists(path))
return Err("File does not exist");
#if _WIN32
std::ifstream in(path.wstring(), std::ios::in | std::ios::binary);
#else
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
#endif
if (in) {
if (!in)
return Err("Unable to open file");
std::string contents;
in.seekg(0, std::ios::end);
contents.resize((const size_t)in.tellg());
@ -35,34 +40,32 @@ Result<std::string> utils::file::readString(ghc::filesystem::path const& path) {
in.close();
return Ok(contents);
}
return Err("Unable to open file");
}
Result<json::Value> utils::file::readJson(ghc::filesystem::path const& path) {
auto str = utils::file::readString(path);
if (str) {
if (!str)
return Err(str.unwrapErr());
try {
return Ok(json::parse(str.value()));
} catch(std::exception const& e) {
return Err("Unable to parse JSON: " + std::string(e.what()));
}
} else {
return Err("Unable to open file");
catch(std::exception const& e) {
return Err("Unable to parse JSON: " + std::string(e.what()));
}
}
Result<ByteVector> utils::file::readBinary(ghc::filesystem::path const& path) {
if (!ghc::filesystem::exists(path))
return Err("File does not exist");
#if _WIN32
std::ifstream in(path.wstring(), std::ios::in | std::ios::binary);
#else
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
#endif
if (in) {
return Ok(ByteVector(std::istreambuf_iterator<char>(in), {}));
}
if (!in)
return Err("Unable to open file");
return Ok(ByteVector(std::istreambuf_iterator<char>(in), {}));
}
Result<> utils::file::writeString(ghc::filesystem::path const& path, std::string const& data) {
@ -72,16 +75,16 @@ Result<> utils::file::writeString(ghc::filesystem::path const& path, std::string
#else
file.open(path.string());
#endif
if (file.is_open()) {
file << data;
file.close();
return Ok();
}
if (!file.is_open()) {
file.close();
return Err("Unable to open file");
}
file << data;
file.close();
return Ok();
}
Result<> utils::file::writeBinary(ghc::filesystem::path const& path, ByteVector const& data) {
std::ofstream file;
#if _WIN32
@ -89,16 +92,16 @@ Result<> utils::file::writeBinary(ghc::filesystem::path const& path, ByteVector
#else
file.open(path.string(), std::ios::out | std::ios::binary);
#endif
if (file.is_open()) {
file.write(reinterpret_cast<char const*>(data.data()), data.size());
file.close();
return Ok();
}
if (!file.is_open()) {
file.close();
return Err("Unable to open file");
}
file.write(reinterpret_cast<char const*>(data.data()), data.size());
file.close();
return Ok();
}
Result<> utils::file::createDirectory(ghc::filesystem::path const& path) {
try {
#ifdef GEODE_IS_WINDOWS

View file

@ -79,6 +79,7 @@ Result<ByteVector> web::fetchBytes(std::string const& url) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::fetch::writeBytes);
auto res = curl_easy_perform(curl);
if (res != CURLE_OK) {
@ -118,6 +119,7 @@ Result<std::string> web::fetch(std::string const& url) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::fetch::writeString);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
auto res = curl_easy_perform(curl);
if (res != CURLE_OK) {
curl_easy_cleanup(curl);