Merge branch 'main' into 1.2.0-dev

This commit is contained in:
altalk23 2023-08-27 19:16:32 +03:00
commit 7836e60b86
20 changed files with 476 additions and 164 deletions

View file

@ -143,7 +143,7 @@ jobs:
- name: Zip Windows Artifacts
uses: vimtor/action-zip@v1.1
with:
files: geode-win/XInput9_1_0.dll geode-win/Geode.dll geode-win/GeodeUpdater.exe geode-win/Geode.lib
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

View file

@ -1,5 +1,13 @@
# Geode Changelog
## v1.1.1
* Improve installation confirmation popup (9192769)
* Remove unnecessary main thread queues for mod events (38cc38c)
* Fix search and filter buttons being not clickable when over the view/restart button of a mod (ef1f1d1)
* Improve tab textures (108f56a)
* Properly align the borders
* Make the selected and unselected tabs the same height
## v1.1.0
* Fix json library not actually being dynamically exported/imported (5f65d97)
* Update TulipHook, gets rid of keystone dependency and adds stdcall support (efcbf58, 7b90903)

24
EULA
View file

@ -4,9 +4,9 @@
This is the End User License Agreement for the Geode Software. By using this Software, you agree to the terms of this EULA.
===========================================
============================================
1.0. Definitions
===========================================
============================================
The Software is all of the source code within the Geode (geode-sdk) Organization on GitHub that when put in a funky little blender and mashed together form the compiled Geode libraries and runtime binaries along with any additional side dishes such as the documentation website.
@ -18,9 +18,9 @@ A Modder is someone who is using Geode and its functions in order to develope th
Geometry Dash is a game by RobTop Games. If you're using Geode, you probably know what it is. If you're an actual laywer or something alike looking at this text document, why? How did we end up in this situation? Can you let us off the hook if we just give you some cute photos of catgirls?
===========================================
============================================
1.1. Your rights as an End User
===========================================
============================================
You are not allowed to not do anything you want to without your own written permission. You are required to stop before every step of using this Software and ponder to yourself: "Is a car with a trailer driving on railway tracks a train?" Failing to do this will result in absolutely no punishments whatsoever. Not because it isn't wrong, but because we simply do not care.
@ -48,9 +48,9 @@ There are also things you are permitted to use this Software for. These include:
Any act you might use this Software for that isn't explicitly listed in any of the above lists you must consult at least yourself to decide if it's okay to do. Do note that the Developers of this Software, i.e. The Core Geode Team, may, at any time, publicly announce other cases that you may / may not use this Software for, or exceptions to previous cases. In the case that that happens, you are required to - wow did I just use 'that' twice in a row? That's so cool - comply with whatever The Core Geode Team says. Unless it's Pie telling you not to use any libraries. Don't listen to Pie.
===========================================
============================================
1.2. Your rights as a Modder
===========================================
============================================
This section mostly lists types of mods that you are allowed to and not allowed to make. Creating a mod that has features which are explicitly disallowed within this document will result in your mod being publicly shamed and humiliated. Be warned.
@ -76,23 +76,23 @@ You are not allowed to create mods that:
Anything not listed in the above lists may be okay to make, or it may not. Consult The Core Geode Team in case you aren't sure if a given mod is okay to make. It is also advised to communicate and discuss with other modders in the Geometry Dash modding community about any mods you are planning on creating which you are unsure about. It might be that your mod does more harm than good.
===========================================
============================================
1.3 Our rights
===========================================
============================================
We reserve the right to publicly shame and humiliate you for failing to understand our perfectly reasonable and unquestionable choices in the matters of design, code, public speaking, advertising, private speaking, behaviour, protected speaking, and anything else.
Our rights are your lefts. Because we are standing menacingly in front of you. Metaphorically speaking.
===========================================
============================================
1.4 Software
===========================================
============================================
I am tired of writing and I don't know what to write here. It's a mod loader and a modding SDK. You didn't download it not knowing what it is, did you?
===========================================
============================================
1.5 Too Long; Didn't Read
===========================================
============================================
* Geode is a mod loader & modding SDK for the game Geometry Dash.

View file

@ -7,6 +7,14 @@ class cocos2d::CCActionTween {
[[link(win)]]
class cocos2d::CCActionManager {
CCActionManager() {
m_pTargets = nullptr;
m_pCurrentTarget = nullptr;
m_bCurrentTargetSalvaged = false;
}
~CCActionManager() {}
virtual auto update(float) = mac 0x10c9a0;
auto addAction(cocos2d::CCAction*, cocos2d::CCNode*, bool) = mac 0x10bed0;
auto pauseTarget(cocos2d::CCObject*) = mac 0x10bc50;
auto resumeTargets(cocos2d::CCSet*) = mac 0x10be80;
@ -302,7 +310,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo {
static void purgeFileUtils();
virtual void addSearchPath(const char* path);
virtual void removeSearchPath(const char *path);
virtual std::string fullPathForFilename(const char* filename, bool unk);
virtual gd::string fullPathForFilename(const char* filename, bool unk) = mac 0x23f940;
void removeAllPaths() = mac 0x241600;
}
@ -1250,6 +1258,8 @@ class DS_Dictionary {
bool stepIntoSubDictWithKey(char const*) = mac 0xc0cd0;
int getIntegerForKey(char const*) = mac 0xc1610;
void setIntegerForKey(char const*, int) = mac 0xc26b0;
void setDictForKey(char const*, cocos2d::CCDictionary*) = mac 0xC4EA0;
auto getObjectForKey(char const*) = mac 0xC4BB0;
}
[[link(win)]]

View file

@ -887,10 +887,10 @@ class ColorSetupDelegate {
class CommentCell : TableViewCell, LikeItemDelegate, FLAlertLayerProtocol {
void loadFromComment(GJComment*) = mac 0x111c70, win 0x5f3d0;
void onConfirmDelete(cocos2d::CCObject* sender) = mac 0x25ec80, win 0x61140;
void onConfirmDelete(cocos2d::CCObject* sender) = mac 0x11d100, win 0x61140;
void onLike(cocos2d::CCObject* sender) = mac 0x11d000, win 0x60F90;
virtual void FLAlert_Clicked(FLAlertLayer* layer, bool btn) = win 0x61260;
virtual void likedItem(LikeItemType type, int id, bool special) = win 0x61070;
virtual void FLAlert_Clicked(FLAlertLayer* layer, bool btn) = mac 0x11d540, win 0x61260;
virtual void likedItem(LikeItemType type, int id, bool special) = mac 0x11d340, win 0x61070;
cocos2d::CCSprite* m_iconSprite;
cocos2d::CCLabelBMFont* m_likeLabel;
@ -957,7 +957,7 @@ class CreatorLayer : cocos2d::CCLayer, cocos2d::CCSceneTransitionDelegate, Dialo
void onGauntlets(cocos2d::CCObject*) = mac 0x142b20, win 0x4f0a0;
void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0;
void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540;
virtual void sceneWillResume() = win 0x4fb50;
virtual void sceneWillResume() = mac 0x1438F0, win 0x4fb50;
virtual bool init() = mac 0x141c10, win 0x4de40;
static CreatorLayer* create() = win 0x4dda0;
}
@ -1072,13 +1072,13 @@ class CustomizeObjectLayer : FLAlertLayer, TextInputDelegate, HSVWidgetPopupDele
bool m_customColorSelected;
}
class DailyLevelPage : FLAlertLayer {
class DailyLevelPage : FLAlertLayer, FLAlertLayerProtocol, GJDailyLevelDelegate, LevelDownloadDelegate {
static DailyLevelPage* create(bool weekly) = win 0x6a860;
bool init(bool weekly) = mac 0x10abb0, win 0x6a900;
virtual void updateTimers(float) = win 0x6bef0;
bool init(bool weekly) = mac 0x108C90, win 0x6a900;
virtual void updateTimers(float) = mac 0x109780, win 0x6bef0;
virtual void show() = mac 0x10a4b0, win 0x3f360;
PAD = win 0x21;
PAD = mac 0x29, win 0x15;
bool m_weekly;
}
@ -1226,6 +1226,9 @@ class EditLevelLayer : cocos2d::CCLayer, FLAlertLayerProtocol, TextInputDelegate
static EditLevelLayer* create(GJGameLevel* level) = mac 0xe1e50, win 0x6f530, ios 0x82420;
bool init(GJGameLevel* level) = mac 0xe1fd0, win 0x6f5d0;
void onLevelInfo(cocos2d::CCObject*) = mac 0xe4f60, win 0x70660;
void onPlay(cocos2d::CCObject*) = mac 0xe3ae0, win 0x71700;
void onEdit(cocos2d::CCObject*) = mac 0xe3970, win 0x71ac0;
void onShare(cocos2d::CCObject*) = mac 0xe3c60, win 0x71be0;
cocos2d::CCMenu* m_buttonMenu;
GJGameLevel* m_level;
@ -1447,8 +1450,9 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
PAD = mac 0x2, win 0x2, android 0x2;
bool m_freeMoveEnabled;
bool m_unkSwipeRelated;
PAD = mac 0xa, win 0xa, android 0x9;
PAD = mac 0x2, win 0x2, android 0x2;
bool m_updateTimeMarkers;
PAD = mac 0x8, win 0x8, android 0x2;
cocos2d::CCArray* m_unknownArray2;
PAD = mac 0x8, win 0x8, android 0x8;
cocos2d::CCArray* m_selectedObjects;
@ -1687,7 +1691,6 @@ class FLAlertLayer : cocos2d::CCLayerColor {
static FLAlertLayer* create(FLAlertLayerProtocol* protocol, char const* title, gd::string content, char const* btn1, char const* btn2, float width, bool scrollable, float height) = mac 0x25dec0, win 0x227e0;
void onBtn1(cocos2d::CCObject*) = mac 0x25ec20, win 0x23340;
void onBtn2(cocos2d::CCObject*) = mac 0x25ec80, win 0x23380;
void onClose(cocos2d::CCObject*) = win 0x49C60;
cocos2d::CCMenu* m_buttonMenu;
int m_controlConnected;
@ -2032,7 +2035,10 @@ class GJCommentListLayer : cocos2d::CCLayerColor {
BoomListView* m_list;
}
class GJDailyLevelDelegate {}
class GJDailyLevelDelegate {
virtual void dailyStatusFinished(bool) {}
virtual void dailyStatusFailed(bool) {}
}
class GJDropDownLayer : cocos2d::CCLayerColor {
virtual void customSetup() {}
@ -2278,7 +2284,7 @@ class GJGameLevel : cocos2d::CCNode {
void savePercentage(int, bool, int, int, bool) = mac 0x2db700;
void dataLoaded(DS_Dictionary* dict) = mac 0x2dc0e0, win 0xbded0, ios 0x6fca4;
GJDifficulty getAverageDifficulty() = win 0xbd9b0;
gd::string getUnpackedLevelDescription() = win 0xbf890;
gd::string getUnpackedLevelDescription() = mac 0x2DDB50, win 0xbf890;
gd::string lengthKeyToString(int key) = win 0xbd910;
static GJGameLevel* getCurrent() {
@ -2330,7 +2336,7 @@ class GJGameLevel : cocos2d::CCNode {
int m_chk;
bool m_isChkValid;
bool m_isCompletionLegitimate;
geode::SeedValueVRS m_normalPercent;
geode::SeedValueVSR m_normalPercent;
geode::SeedValueRSV m_orbCompletion;
geode::SeedValueRSV m_newNormalPercent2;
int m_practicePercent;
@ -2592,11 +2598,14 @@ class GJScaleControlDelegate {
virtual void scaleChanged(float) {}
}
class GJScoreCell : TableViewCell {
virtual void FLAlert_Clicked(FLAlertLayer*, bool) = win 0x624a0;
void loadFromScore(GJUserScore* score) = win 0x61440;
class GJScoreCell : TableViewCell, FLAlertLayerProtocol {
virtual void FLAlert_Clicked(FLAlertLayer*, bool) = mac 0x11D8E0, win 0x624a0;
void loadFromScore(GJUserScore* score) = mac 0x113AA0, win 0x61440;
void onViewProfile(cocos2d::CCObject* sender) = win 0x62380;
void updateBGColor(int index) = win 0x5c6b0;
void updateBGColor(int index) = mac 0x113A40, win 0x5c6b0;
inline GJScoreCell(char const* identifier, float parentHeight, float height) : TableViewCell(identifier, parentHeight, height) {}
GJUserScore* m_score;
}
class GJSearchObject : cocos2d::CCNode {
@ -2606,8 +2615,8 @@ class GJSearchObject : cocos2d::CCNode {
static GJSearchObject* create(SearchType nID) = win 0xc2b90, mac 0x2df120;
static GJSearchObject* create(SearchType nID, gd::string str) = win 0xc2c80, mac 0x2df310;
static GJSearchObject* createFromKey(const char* key) = win 0xC2760;
const char* getKey() = win 0xC30A0;
static GJSearchObject* createFromKey(const char* key) = mac 0x2C0620, win 0xC2760;
const char* getKey() = mac 0x2C6A40, win 0xC30A0;
const char* getNextPageKey() = win 0xC31F0;
SearchType m_searchType;
@ -2709,8 +2718,19 @@ class GJUserScore : cocos2d::CCNode {
gd::string getPlayerName() const {
return m_userName;
}
static GJUserScore* create() = win 0xc1660;
static GJUserScore* create(cocos2d::CCDictionary*) = win 0xc0750;
static GJUserScore* create() {
auto pRet = new GJUserScore();
if (pRet) {
pRet->autorelease();
return pRet;
}
CC_SAFE_DELETE(pRet);
return nullptr;
}
inline GJUserScore() : CCNode() {}
static GJUserScore* create(cocos2d::CCDictionary*) = mac 0x2BD020, win 0xc0750;
gd::string m_userName;
gd::string m_userUDID;
@ -2755,7 +2775,7 @@ class GJUserScore : cocos2d::CCNode {
}
class GManager : cocos2d::CCNode {
virtual void setup() = win 0x28F60;
virtual void setup() = mac 0x26EE20, win 0x28F60;
virtual void encodeDataTo(DS_Dictionary* data) {}
virtual void dataLoaded(DS_Dictionary* data) {}
virtual void firstLoad() {}
@ -2788,13 +2808,13 @@ class GameLevelManager : cocos2d::CCNode {
cocos2d::CCArray* createAndGetScores(gd::string, GJScoreType) = win 0xa2780;
GJGameLevel* createNewLevel() = mac 0x2b8180, win 0xa0db0;
static GameLevelManager* sharedState() = mac 0x2a8340, win 0x9f860;
void limitSavedLevels() = win 0xA43B0;
cocos2d::CCArray* getCompletedLevels(bool newFilter) = win 0xa2d20;
void getGJUserInfo(int) = win 0xb00b0;
void getLevelLeaderboard(GJGameLevel* level, LevelLeaderboardType leaderboardType) = win 0xAED70;
void getOnlineLevels(GJSearchObject*) = win 0xa7bc0;
void limitSavedLevels() = mac 0x2C0C30, win 0xA43B0;
cocos2d::CCArray* getCompletedLevels(bool newFilter) = mac 0x2BEEE0, win 0xa2d20;
void getGJUserInfo(int) = mac 0x2CEBB0, win 0xb00b0;
void getLevelLeaderboard(GJGameLevel* level, LevelLeaderboardType leaderboardType) = mac 0x2CD6F0, win 0xAED70;
void getOnlineLevels(GJSearchObject*) = mac 0x2C5920, win 0xa7bc0;
void getPageInfo(char const*) = mac 0x2c0050;
cocos2d::CCArray* getSavedLevels(bool favorite, int levelFolder) = win 0xa2960;
cocos2d::CCArray* getSavedLevels(bool favorite, int levelFolder) = mac 0x2BE910, win 0xa2960;
cocos2d::CCArray* getStoredOnlineLevels(char const*) = mac 0x2bfe80, win 0xa3a90;
void getTopArtists(int, int) = mac 0x2ce3d0;
void getTopArtistsKey(int) = mac 0x2ce7a0;
@ -2805,15 +2825,15 @@ class GameLevelManager : cocos2d::CCNode {
callback void ProcessHttpRequest(gd::string, gd::string, gd::string, GJHttpType) = mac 0x2a8670, win 0x9f8e0;
cocos2d::CCDictionary* responseToDict(gd::string response, bool comment) = win 0xbba50;
void storeUserNames(gd::string) = win 0xa1840;
void storeUserName(int userID, int accountID, gd::string str) = win 0xa1a70;
gd::string userNameForUserID(int id) = win 0xa1c20;
void updateUserScore() = win 0xada60;
void storeUserName(int userID, int accountID, gd::string str) = mac 0x2B9020, win 0xa1a70;
gd::string userNameForUserID(int id) = mac 0x2B91D0, win 0xa1c20;
void updateUserScore() = mac 0x2CB6A0, win 0xada60;
void downloadLevel(int id, bool downloadData) = win 0xaa730;
bool hasDownloadedLevel(int id) = win 0xab830;
GJGameLevel* getSavedLevel(int id) = win 0xa2ee0;
void saveLevel(GJGameLevel* level) = win 0xa31c0;
void deleteLevel(GJGameLevel* level) = mac 0x2b88d0, win 0xa1640;
void resetCommentTimersForLevelID(int id, bool commentHistory) = win 0xB3F10;
void resetCommentTimersForLevelID(int id, bool commentHistory) = mac 0x2D43D0, win 0xB3F10;
void resetStoredUserInfo(int id) {
m_storedUserInfo->removeObjectForKey(id);
}
@ -2837,12 +2857,11 @@ class GameLevelManager : cocos2d::CCNode {
return GameLevelManager::sharedState();
}
//cocos2d::CCDictionary* timerDict = mac 0x1e8;
cocos2d::CCDictionary* m_mainLevels;
cocos2d::CCDictionary* m_searchFilters;
cocos2d::CCDictionary* m_onlineLevels;
PAD = win 0x4;
cocos2d::CCDictionary* m_unkDict;
cocos2d::CCDictionary* m_followedCreators;
cocos2d::CCDictionary* m_downloadedLevels;
cocos2d::CCDictionary* m_likedLevels;
@ -2855,13 +2874,12 @@ class GameLevelManager : cocos2d::CCNode {
int m_dailyTimeLeft;
int m_dailyID;
int m_dailyIDUnk;
PAD = win 0x4;
PAD = mac 0x10, win 0x4;
int m_weeklyTimeLeft;
int m_weeklyID;
int m_weeklyIDUnk;
cocos2d::CCDictionary* m_gauntletLevels;
cocos2d::CCDictionary* m_unkDict13;
PAD = win 0x4;
gd::map<gd::string, bool> m_availableFilters;
cocos2d::CCDictionary* m_timerDict;
cocos2d::CCDictionary* m_knownUsers;
cocos2d::CCDictionary* m_accountIDtoUserIDDict;
@ -3523,9 +3541,9 @@ class GameStatsManager : cocos2d::CCNode {
void awardCurrencyForLevel(GJGameLevel*) = mac 0x43600;
void awardDiamondsForLevel(GJGameLevel*) = mac 0x43c60;
void awardSecretKey() = mac 0x4b1e0;
int getAwardedCurrencyForLevel(GJGameLevel*) = win 0xf83e0;
int getBaseCurrencyForLevel(GJGameLevel*) = win 0xf8530;
GJChallengeItem* getChallenge(int id) = win 0xa2fb0;
int getAwardedCurrencyForLevel(GJGameLevel*) = mac 0x432E0, win 0xf83e0;
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;
void hasPendingUserCoin(char const*) = mac 0x42730, win 0xf7c50;
@ -3540,14 +3558,14 @@ class GameStatsManager : cocos2d::CCNode {
void storeUserCoin(char const*) = mac 0x42890;
bool isItemUnlocked(UnlockType type, int id) = win 0xfbb80;
PAD = win 0x28;
PAD = mac 0x50, win 0x28;
cocos2d::CCDictionary* m_dailyChests;
cocos2d::CCDictionary* m_worldAdvertChests;
cocos2d::CCDictionary* m_activeChallenges;
cocos2d::CCDictionary* m_upcomingChallenges;
PAD = win 0xc;
PAD = mac 0x18, win 0xc;
cocos2d::CCDictionary* m_playerStats;
PAD = win 0x10;
PAD = mac 0x50, win 0x10;
cocos2d::CCDictionary* m_completedLevels;
cocos2d::CCDictionary* m_verifiedUserCoins;
cocos2d::CCDictionary* m_pendingUserCoins;
@ -3656,9 +3674,9 @@ class InfoAlertButton : CCMenuItemSpriteExtra {
class InfoLayer : FLAlertLayer, LevelCommentDelegate, CommentUploadDelegate, FLAlertLayerProtocol {
bool init(GJGameLevel* level, GJUserScore* score) = mac 0x456850, win 0x14f5a0;
void setupCommentsBrowser(cocos2d::CCArray* comments) = mac 0x458590, win 0x152270;
void onMore(cocos2d::CCObject* sender) = win 0x151500;
void onMore(cocos2d::CCObject* sender) = mac 0x459400, win 0x151500;
void onLevelInfo(cocos2d::CCObject* sender) = mac 0x459400, win 0x151850;
void loadPage(int page, bool) = win 0x151e70;
void loadPage(int page, bool) = mac 0x458FB0, win 0x151e70;
static InfoLayer* create(GJGameLevel* level, GJUserScore* score) = mac 0x456600, win 0x14f4f0;
GJGameLevel* m_level;
@ -3713,7 +3731,7 @@ class LeaderboardManagerDelegate {
}
class LeaderboardsLayer : cocos2d::CCLayer {
static LeaderboardsLayer* create(LeaderboardState state) = win 0x158710;
static LeaderboardsLayer* create(LeaderboardState state) = mac 0x29F590, win 0x158710;
bool init(LeaderboardState state) = mac 0x29f6d0, win 0x1587b0;
}
@ -3727,9 +3745,12 @@ class LevelBrowserLayer : cocos2d::CCLayer, LevelManagerDelegate, FLAlertLayerPr
}
bool init(GJSearchObject* search) = mac 0x2513f0, win 0x15a040;
void loadPage(GJSearchObject* search) = win 0x15b160;
void loadPage(GJSearchObject* search) = mac 0x253650, win 0x15b160;
void setupLevelBrowser(cocos2d::CCArray* levels) = win 0x15bb40;
void updateLevelsLabel() = win 0x15c350;
virtual void setupPageInfo(gd::string, char const*) = mac 0x255050, win 0x15C1C0;
void updateLevelsLabel() = mac 0x255450, win 0x15c350;
void onRefresh(cocos2d::CCObject* sender) = mac 0x253090;
void onInfo(cocos2d::CCObject* sender) = mac 0x253170, win 0x15cb00;
static LevelBrowserLayer* create(GJSearchObject* search) = mac 0x251210, win 0x159fa0, ios 0x2d0a00;
PAD = win 0x4, mac 0x8;
@ -3759,8 +3780,9 @@ class LevelCell : TableViewCell {
void onViewProfile(cocos2d::CCObject*) = mac 0x11a4a0, win 0x5c790;
void loadCustomLevelCell() = mac 0x1183b0, win 0x5a020;
void updateBGColor(int index) = win 0x5c6b0;
void loadFromLevel(GJGameLevel* level) = win 0x59FD0;
void updateBGColor(int index) = mac 0x110460, win 0x5c6b0;
void loadFromLevel(GJGameLevel* level) = mac 0x110410, win 0x59FD0;
inline LevelCell(char const* identifier, float parentHeight, float height) : TableViewCell(identifier, parentHeight, height) {}
}
class LevelCommentDelegate {
@ -3992,7 +4014,12 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg
void onViewProfile(cocos2d::CCObject* sender) = mac 0x1617d0, win 0x17ac90;
void onLevelInfo(cocos2d::CCObject* sender) = mac 0x163880, win 0x17acf0;
void setupProgressBars() = win 0x177fc0;
void setupLevelInfo() = mac 0x161C80, win 0x178680;
void downloadLevel() = win 0x177d90;
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;
PAD = win 0x4, mac 0x8;
cocos2d::CCMenu* m_playBtnMenu;
@ -4013,28 +4040,28 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg
PAD = win 0x4, mac 0x8;
}
class LevelLeaderboard : FLAlertLayer {
void onChangeType(cocos2d::CCObject* sender) = win 0x17d090;
void onUpdate(cocos2d::CCObject* sender) = win 0x17d1b0;
class LevelLeaderboard : FLAlertLayer, LeaderboardManagerDelegate {
void onChangeType(cocos2d::CCObject* sender) = mac 0x20e310, win 0x17d090;
void onUpdate(cocos2d::CCObject* sender) = mac 0x20e240, win 0x17d1b0;
bool init(GJGameLevel* level, LevelLeaderboardType type) = mac 0x20d710, win 0x17c4f0;
static LevelLeaderboard* create(GJGameLevel* level, LevelLeaderboardType leaderboardType) = win 0x17c440;
static LevelLeaderboard* create(GJGameLevel* level, LevelLeaderboardType leaderboardType) = mac 0x20D550, win 0x17c440;
void onClose(cocos2d::CCObject*) = mac 0x20e210, win 0x49C60;
PAD = win 0x4;
GJGameLevel* m_level;
LevelLeaderboardType m_type;
}
class LevelManagerDelegate {
virtual void loadLevelsFailed(char const*) {}
virtual void loadLevelsFinished(cocos2d::CCArray *,char const*) {}
virtual void setupPageInfo(std::string,char const*) {}
virtual void loadLevelsFailed(char const*) {}
virtual void setupPageInfo(gd::string,char const*) {}
}
class LevelPage {
PAD = win 0x124;
class LevelPage : cocos2d::CCLayer, DialogDelegate {
PAD = mac 0x8, win 0x4;
GJGameLevel* m_level;
void onInfo(cocos2d::CCObject* sender) = win 0x189070;
void onInfo(cocos2d::CCObject* sender) = mac 0x23AAE0, win 0x189070;
}
class LevelSearchLayer : cocos2d::CCLayer {
@ -4284,6 +4311,7 @@ class MessageListDelegate {}
class MoreSearchLayer : FLAlertLayer {
static MoreSearchLayer* create() = mac 0x38ab40, win 0x182520;
virtual bool init() = mac 0x3896b0, win 0x1825c0;
void onClose(cocos2d::CCObject*) = mac 0x38aa40, win 0x1848f0;
}
class MoreOptionsLayer : FLAlertLayer, TextInputDelegate, GooglePlayDelegate {
@ -4736,7 +4764,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate,
bool unk42C;
bool m_isPlayer2Frozen;
gd::string m_previousRecords;
double unknown6a8;
cocos2d::CCArray* m_replayInputs;
double m_time;
int unknown6b8;
int unknown6bc;
@ -4909,12 +4937,12 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
void saveToCheckpoint(PlayerCheckpoint*) = mac 0x22e2f0, win 0x1f9ee0;
void setSecondColor(cocos2d::_ccColor3B const&) = mac 0x219610, win 0x1f7870;
void setupStreak() = mac 0x218720, win 0x1e7e90;
void spawnCircle() = mac 0x225480;
void spawnCircle() = mac 0x2251b0;
void spawnCircle2() = mac 0x2252a0;
void spawnDualCircle() = mac 0x2255c0;
void spawnFromPlayer(PlayerObject*) = mac 0x22dde0, win 0x1f9540;
void spawnPortalCircle(cocos2d::_ccColor3B, float) = mac 0x225350, win 0x1ef680;
void spawnScaleCircle() = mac 0x2251b0, win 0x1ef810;
void spawnScaleCircle() = mac 0x225480, win 0x1ef810;
void specialGroundHit() = mac 0x22dbf0;
void speedDown() = mac 0x22e970;
void speedUp() = mac 0x22e950;
@ -5109,18 +5137,18 @@ class PointNode : cocos2d::CCObject {
class ProfilePage : FLAlertLayer, FLAlertLayerProtocol, LevelCommentDelegate, CommentUploadDelegate, UserInfoDelegate, UploadActionDelegate, UploadPopupDelegate, LeaderboardManagerDelegate {
static ProfilePage* create(int accountID, bool idk) = mac 0x45eed0, win 0x20ee50;
virtual void getUserInfoFailed(int) = win 0x2133e0;
virtual void getUserInfoChanged(GJUserScore*) = win 0x213430;
virtual void getUserInfoFailed(int) = mac 0x463FB0, win 0x2133e0;
virtual void userInfoChanged(GJUserScore*) = mac 0x464070, win 0x213430;
bool init(int accountID, bool idk) = mac 0x45f170, win 0x20ef00;
void onMyLevels(cocos2d::CCObject*) = win 0x211bb0;
void onUpdate(cocos2d::CCObject*) = win 0x20fa20;
void onMyLevels(cocos2d::CCObject*) = mac 0x462d70, win 0x211bb0;
void onUpdate(cocos2d::CCObject*) = mac 0x460150, win 0x20fa20;
void onClose(cocos2d::CCObject*) = mac 0x45fd20, win 0x49C60;
virtual void keyBackClicked() = win 0x49C80;
void loadPageFromUserInfo(GJUserScore* score) = win 0x210040;
virtual void keyBackClicked() = mac 0x464A60, win 0x49C80;
void loadPageFromUserInfo(GJUserScore* score) = mac 0x460480, win 0x210040;
GJUserScore* m_score;
int m_accountID;
PAD = win 0x38, android 0x24;
PAD = mac 0x44, win 0x38, android 0x24;
cocos2d::CCArray* m_buttons;
}
@ -5641,7 +5669,7 @@ class TeleportPortalObject : GameObject {
}
class TextAlertPopup : cocos2d::CCNode {
static TextAlertPopup* create(gd::string text, float time, float scale) = win 0x1450b0;
static TextAlertPopup* create(gd::string text, float time, float scale) = mac 0x157080, win 0x1450b0;
}
class TextArea : cocos2d::CCSprite {
@ -5749,7 +5777,7 @@ class UploadPopupDelegate {
class UserInfoDelegate {
virtual void getUserInfoFinished(GJUserScore *) {}
virtual void getUserInfoFailed(int) {}
virtual void getUserInfoChanged(GJUserScore *) {}
virtual void userInfoChanged(GJUserScore *) {}
}
class UserListDelegate {

View file

@ -26,6 +26,8 @@
; pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "..\..\LICENSE.txt"
!define MUI_COMPONENTSPAGE_NODESC
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_SHOW DirectoryPageShow
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
@ -189,6 +191,132 @@
Exch $R0
!macroend
; https://nsis.sourceforge.io/StrStr
Function un.StrStr
Exch $R0
Exch
Exch $R1
Push $R2
Push $R3
Push $R4
Push $R5
StrLen $R2 $R0
StrLen $R3 $R1
StrCpy $R4 0
loop:
StrCpy $R5 $R1 $R2 $R4
StrCmp $R5 $R0 done
IntCmp $R4 $R3 done 0 done
IntOp $R4 $R4 + 1
Goto loop
done:
StrCpy $R0 $R1 `` $R4
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
; https://nsis.sourceforge.io/Get_command_line_parameters
Function un.GetParameters
Push $R0
Push $R1
Push $R2
Push $R3
StrCpy $R2 1
StrLen $R3 $CMDLINE
StrCpy $R0 $CMDLINE $R2
StrCmp $R0 '"' 0 +3
StrCpy $R1 '"'
Goto loop
StrCpy $R1 " "
loop:
IntOp $R2 $R2 + 1
StrCpy $R0 $CMDLINE 1 $R2
StrCmp $R0 $R1 get
StrCmp $R2 $R3 get
Goto loop
get:
IntOp $R2 $R2 + 1
StrCpy $R0 $CMDLINE 1 $R2
StrCmp $R0 " " get
StrCpy $R0 $CMDLINE "" $R2
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
; https://nsis.sourceforge.io/Get_command_line_parameter_by_name
Function un.GetParameterValue
Exch $R0
Exch
Exch $R1
Push $R2
Push $R3
Push $R4
Push $R5
Strlen $R2 $R1+2
Call un.GetParameters
Pop $R3
StrCpy $R5 '"'
Push $R3
Push '"/$R1='
Call un.StrStr
Pop $R4
StrCpy $R4 $R4 "" 1
StrCmp $R4 "" "" next
StrCpy $R5 ' '
Push $R3
Push '/$R1='
Call un.StrStr
Pop $R4
next:
StrCmp $R4 "" check_for_switch
StrCpy $R0 $R4 "" $R2
Push $R0
Push $R5
Call un.StrStr
Pop $R4
StrCmp $R4 "" done
StrLen $R4 $R4
StrCpy $R0 $R0 -$R4
goto done
check_for_switch:
Push $R3
Push '/$R1'
Call un.StrStr
Pop $R4
StrCmp $R4 "" done
StrCpy $R0 ""
done:
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
; actual code
!define BINDIR ..\..\bin\nightly
@ -248,16 +376,6 @@ Function FindGamePath
Pop $0
FunctionEnd
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
Call FindGamePath
IfErrors 0 +3
StrCpy $GamePath ""
Return
StrCpy $INSTDIR "$GamePath\"
FunctionEnd
Function DirectoryPageShow
System::Call 'USER32::CreateWindowEx(i${__NSD_Label_EXSTYLE}, t"${__NSD_Label_CLASS}", t"", i${__NSD_Label_STYLE}, i0, i70, i400, i40, p$mui.DirectoryPage, p0, p0, p0)p.s'
Pop $geode.DirectoryPage.ErrorText
@ -309,6 +427,25 @@ Function .onVerifyInstDir
Return
FunctionEnd
SectionGroup "Geode"
Section "Loader" LOADER_SECTION
SetOutPath $INSTDIR
File ${BINDIR}\Geode.dll
File ${BINDIR}\Geode.pdb
File ${BINDIR}\GeodeUpdater.exe
File ${BINDIR}\XInput9_1_0.dll
WriteUninstaller "GeodeUninstaller.exe"
SectionEnd
Section "Resources"
CreateDirectory $INSTDIR\geode\resources\geode.loader
SetOutPath $INSTDIR\geode\resources\geode.loader
File /r ${BINDIR}\resources\*
SectionEnd
SectionGroupEnd
; download vc redist in compile-time
!execute "pwsh -nol -noni -nop dl-vcr.ps1"
Section "Visual Studio Runtime"
@ -318,21 +455,18 @@ Section "Visual Studio Runtime"
Delete "$INSTDIR\VC_redist.x86.exe"
SectionEnd
Section "Geode"
SetOutPath $INSTDIR
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
File ${BINDIR}\Geode.dll
File ${BINDIR}\Geode.pdb
File ${BINDIR}\GeodeUpdater.exe
File ${BINDIR}\XInput9_1_0.dll
IntOp $0 ${SF_SELECTED} | ${SF_RO}
SectionSetFlags ${LOADER_SECTION} $0
WriteUninstaller "geode\Uninstall.exe"
CreateDirectory $INSTDIR\geode\resources\geode.loader
SetOutPath $INSTDIR\geode\resources\geode.loader
File /r ${BINDIR}\resources\*
SectionEnd
Call FindGamePath
IfErrors 0 +3
StrCpy $GamePath ""
Return
StrCpy $INSTDIR "$GamePath\"
FunctionEnd
; uninstaller
@ -357,10 +491,47 @@ Function un.onInit
Abort
FunctionEnd
Section "Uninstall"
DeleteRegKey /ifempty HKCU "Software\Geode"
Delete $INSTDIR\Geode.dll
Delete $INSTDIR\Geode.pdb
Delete $INSTDIR\GeodeUpdater.exe
Delete $INSTDIR\XInput9_1_0.dll
# default value of DATA is an empty string
# if DATA is empty, keep user data
# otherwise, delete the entire geode and DATA\geode\mods dirs
# the reason we're deleting DATA\geode\mods instead of just passing
# that dir directly to DATA is so that in case someone (either accidentally or maliciously)
# passes the wrong directory, the uninstaller doesn't just blindly clear it
# it will also check for the presence of CCGameManager.dat and CCLocalLevels.dat in DATA
Push "DATA"
Push ""
Call un.GetParameterValue
Pop $0
StrCmp $0 "" keep_data remove_data
keep_data:
# keep configs, mods, logs and crash logs
RMdir /r $INSTDIR\geode\index
RMdir /r $INSTDIR\geode\resources
RMdir /r $INSTDIR\geode\temp
RMdir /r $INSTDIR\geode\unzipped
RMdir /r $INSTDIR\geode\update
Return
remove_data:
RMdir /r $INSTDIR\geode
DeleteRegKey /ifempty HKCU "Software\Geode"
IfFileExists $0\CCGameManager.dat 0 invalid
IfFileExists $0\CCLocalLevels.dat 0 invalid
RMdir /r $0\geode\mods ; delete DATA\geode\mods
RMdir $0\geode ; then delete DATA\geode non-recursively, assuming mods is the only directory in DATA\geode
Return
invalid:
# this message doesnt rly need translatable as
# its only supposed to be used internally by geode itself
MessageBox MB_ICONSTOP|MB_OK "The path passed to DATA is not a valid Geometry Dash data folder!"
Abort
SectionEnd

View file

@ -250,7 +250,7 @@ if (APPLE)
add_subdirectory(launcher/mac)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR GEODE_TARGET_PLATFORM STREQUAL "iOS")
if(GEODE_TARGET_PLATFORM STREQUAL "iOS")
add_custom_command(TARGET geode-loader
POST_BUILD COMMAND
${CMAKE_INSTALL_NAME_TOOL} -id \"/Library/MobileSubstrate/DynamicLibraries/Geode.dylib\"

View file

@ -68,6 +68,8 @@ public:
*/
~CCActionManager(void);
GEODE_CUSTOM_CONSTRUCTOR_COCOS(CCActionManager, CCObject);
// actions
/** Adds an action with a target.

View file

@ -91,6 +91,14 @@ namespace geode::addresser {
*reinterpret_cast<intptr_t*>(reinterpret_cast<intptr_t>(ins) + thunk) + index
);
#ifdef GEODE_IS_WINDOWS
// if the first instruction is a long jmp then this might still be a thunk
if (*reinterpret_cast<uint8_t*>(address) == 0xE9) {
auto relative = *reinterpret_cast<uint32_t*>(address + 1);
address = address + relative + 5;
}
#endif
address = followThunkFunction(address);
return address;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -93,4 +93,18 @@ struct FileUtilsUpdatePaths : Modify<FileUtilsUpdatePaths, CCFileUtils> {
}
return ret;
}
gd::string fullPathForFilename(const char* filename, bool unk) override {
using namespace std::string_literals;
using namespace std::string_view_literals;
// this filename in particular is never cached because its not actually present anywhere.
// this is only an issue because cocos itself requests the full path for this in CCSprite,
// and with a lot of search paths (specially ones added by geode), this can cause a significant amount of lag.
if (filename == "cc_2x2_white_image"sv) {
return "cc_2x2_white_image"s;
}
return CCFileUtils::fullPathForFilename(filename, unk);
}
};

View file

@ -330,7 +330,7 @@ static void handlerThread() {
auto text = crashlog::writeCrashlog(faultyMod, getInfo(signalAddress, faultyMod), getStacktrace(), getRegisters());
log::error("Geode crashed!\n{}" + text);
log::error("Geode crashed!\n{}", text);
s_signal = 0;
s_cv.notify_all();

View file

@ -14,7 +14,6 @@
#include "../../loader/LoaderImpl.hpp"
#include <thread>
#include <variant>
#include <objc/runtime.h>
using namespace geode::prelude;
@ -112,26 +111,38 @@ void updateGeode() {
extern "C" void fake() {}
static IMP s_applicationDidFinishLaunching;
void applicationDidFinishLaunching(id self, SEL sel, NSNotification* notification) {
void applicationDidFinishLaunchingHook(void* self, SEL sel, NSNotification* notification) {
updateGeode();
std::array<uint8_t, 6> patchBytes = {
0x55,
0x48, 0x89, 0xe5,
0x41, 0x57
};
auto res = tulip::hook::writeMemory((void*)(base::get() + 0x69a0), patchBytes.data(), 6);
if (!res)
return;
int exitCode = geodeEntry(nullptr);
if (exitCode != 0)
return;
using Type = decltype(&applicationDidFinishLaunching);
return reinterpret_cast<Type>(s_applicationDidFinishLaunching)(self, sel, notification);
return reinterpret_cast<void(*)(void*, SEL, NSNotification*)>(geode::base::get() + 0x69a0)(self, sel, notification);
}
bool loadGeode() {
Class class_ = objc_getClass("AppController");
SEL selector = @selector(applicationDidFinishLaunching:);
IMP function = (IMP)applicationDidFinishLaunching;
using Type = decltype(&applicationDidFinishLaunching);
auto detourAddr = reinterpret_cast<uintptr_t>(&applicationDidFinishLaunchingHook) - geode::base::get() - 0x69a5;
auto detourAddrPtr = reinterpret_cast<uint8_t*>(&detourAddr);
s_applicationDidFinishLaunching = class_replaceMethod(class_, selector, function, @encode(Type));
std::array<uint8_t, 5> patchBytes = {
0xe9, detourAddrPtr[0], detourAddrPtr[1], detourAddrPtr[2], detourAddrPtr[3]
};
auto res = tulip::hook::writeMemory((void*)(base::get() + 0x69a0), patchBytes.data(), 5);
if (!res)
return false;
return true;
}

View file

@ -750,13 +750,55 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
}
void IndexItemInfoPopup::onInstall(CCObject*) {
createQuickPopup(
"Confirm Install",
"Installing this mod requires a few other mods to be installed. "
auto deps = m_item->getMetadata().getDependencies();
enum class DepState {
None,
HasOnlyRequired,
HasOptional
} depState = DepState::None;
for (auto const& item : deps) {
// resolved means it's already installed, so
// no need to ask the user whether they want to install it
if (Loader::get()->isModLoaded(item.id))
continue;
if (item.importance != ModMetadata::Dependency::Importance::Required) {
depState = DepState::HasOptional;
break;
}
depState = DepState::HasOnlyRequired;
}
std::string content;
char const* btn1;
char const* btn2;
switch (depState) {
case DepState::None:
content = fmt::format(
"Are you sure you want to install <cg>{}</c>?",
m_item->getMetadata().getName()
);
btn1 = "Info";
btn2 = "Install";
break;
case DepState::HasOnlyRequired:
content =
"Installing this mod requires other mods to be installed. "
"Would you like to <cy>proceed</c> with the installation or "
"<cb>view</c> which mods are going to be installed?";
btn1 = "View";
btn2 = "Proceed";
break;
case DepState::HasOptional:
content =
"This mod recommends installing other mods alongside it. "
"Would you like to continue with <cy>recommended settings</c> or "
"<cb>customize</c> which mods to install?",
"Customize", "Recommended", 320.f,
[&](FLAlertLayer*, bool btn2) {
"<cb>customize</c> which mods to install?";
btn1 = "Customize";
btn2 = "Recommended";
break;
}
createQuickPopup("Confirm Install", content, btn1, btn2, 320.f, [&](FLAlertLayer*, bool btn2) {
if (btn2) {
auto canInstall = Index::get()->canInstall(m_item);
if (!canInstall) {
@ -776,8 +818,7 @@ void IndexItemInfoPopup::onInstall(CCObject*) {
Index::get()->install(list);
})->show();
}
}, true, true
);
}, true, true);
}
void IndexItemInfoPopup::preInstall() {

View file

@ -428,6 +428,9 @@ void ModListLayer::createSearchControl() {
inputBG->setScale(.5f);
m_searchBG->addChild(inputBG);
if (m_searchInput)
return;
m_searchInput =
CCTextInputNode::create(310.f - buttonSpace, 20.f, "Search Mods...", "bigFont.fnt");
m_searchInput->setLabelPlaceholderColor({ 150, 150, 150 });
@ -457,10 +460,7 @@ void ModListLayer::reloadList(std::optional<ModListQuery> const& query) {
std::nullopt;
// remove old list
if (m_list) {
if (m_searchBG) m_searchBG->retain();
m_list->removeFromParent();
}
if (m_list) m_list->removeFromParent();
auto items = this->createModCells(g_tab, m_query);
@ -522,13 +522,7 @@ void ModListLayer::reloadList(std::optional<ModListQuery> const& query) {
m_tabsGradientSprite->setPosition(m_list->getPosition() + CCPoint{179.f, 235.f});
// add search input to list
if (!m_searchInput) {
this->createSearchControl();
}
else {
m_list->addChild(m_searchBG);
m_searchBG->release();
}
// enable filter button
m_filterBtn->setEnabled(g_tab != ModListType::Installed);

View file

@ -11,6 +11,10 @@ GEODE_MEMBER_CHECK(PlayerObject, m_playerColor1, 0x7c2);
// EditorUI
GEODE_MEMBER_CHECK(EditorUI, m_buttonBar, 0x1a0);
GEODE_MEMBER_CHECK(EditorUI, m_scaleControl, 0x208);
GEODE_MEMBER_CHECK(EditorUI, m_swipeEnabled, 0x23c);
GEODE_MEMBER_CHECK(EditorUI, m_updateTimeMarkers, 0x244);
GEODE_MEMBER_CHECK(EditorUI, m_selectedObjects, 0x260);
GEODE_MEMBER_CHECK(EditorUI, m_selectedObject, 0x440);
// LevelEditorLayer
@ -21,7 +25,7 @@ GEODE_MEMBER_CHECK(LevelEditorLayer, m_level, 0x618);
GEODE_MEMBER_CHECK(PlayLayer, unknown518, 0x518);
GEODE_MEMBER_CHECK(PlayLayer, unknown5f4, 0x5f4);
GEODE_MEMBER_CHECK(PlayLayer, unknown680, 0x680);
GEODE_MEMBER_CHECK(PlayLayer, unknown6a8, 0x6a8);
GEODE_MEMBER_CHECK(PlayLayer, m_replayInputs, 0x6a8);
GEODE_MEMBER_CHECK(PlayLayer, m_level, 0x728);
GEODE_MEMBER_CHECK(PlayLayer, m_shouldTryToKick, 0x7a8);
@ -76,4 +80,19 @@ GEODE_MEMBER_CHECK(LevelBrowserLayer, m_itemCount, 0x208);
// LocalLevelManager
GEODE_MEMBER_CHECK(LocalLevelManager, m_localLevels, 0x140);
// GameStatsManager
GEODE_MEMBER_CHECK(GameStatsManager, m_dailyChests, 0x170);
GEODE_MEMBER_CHECK(GameStatsManager, m_completedLevels, 0x200);
GEODE_MEMBER_CHECK(GameStatsManager, m_weeklyChest, 0x278);
// DailyLevelPage
GEODE_MEMBER_CHECK(DailyLevelPage, m_weekly, 0x291);
// GameLevelManager
GEODE_MEMBER_CHECK(GameLevelManager, m_weeklyID, 0x1a8);
GEODE_MEMBER_CHECK(GameLevelManager, m_gauntletLevels, 0x1b0);
GEODE_MEMBER_CHECK(GameLevelManager, m_timerDict, 0x1e8);
GEODE_MEMBER_CHECK(GameLevelManager, m_accountIDtoUserIDDict, 0x1f8);
GEODE_MEMBER_CHECK(GameLevelManager, m_userIDtoAccountIDDict, 0x200);
#endif

View file

@ -56,4 +56,10 @@ static_assert(sizeof(GJBaseGameLayer) == 0x2cc);
GEODE_MEMBER_CHECK(AudioEffectsLayer, m_unk19C, 0x19c);
GEODE_MEMBER_CHECK(GameStatsManager, m_dailyChests, 0x114);
GEODE_MEMBER_CHECK(GameStatsManager, m_completedLevels, 0x144);
GEODE_MEMBER_CHECK(DailyLevelPage, m_weekly, 0x1ed);
#endif