This commit is contained in:
Justin Pridgen 2024-07-06 19:41:27 -04:00
commit d117d50fb0
74 changed files with 309 additions and 206 deletions

View file

@ -1,5 +1,23 @@
# Geode Changelog # Geode Changelog
## v3.2.0
* Fix auto-updater on MacOS (d752bc2)
* Use tasks for `FileSettingNode` (f94e95e)
* Fix single argument overload of `Task` (6fe1ac9)
* Fix the GLFW message box fix (09c188a)
* Shrink `TextInput` input to give some padding (1da73cf)
* Undither account and editor blank sprites, add missing editor blank sprites (427e86e, efc4a00, 9fd9a78)
* Fix populating web headers and add some new getters (a96ec91)
* Build mods to load stack statically (255066a)
* Force internal mod to always appear enabled (e659b97)
* Bring back uninstall Geode button on Windows (22b2580)
* Add `geode::openChangelogPopup` (e432e72)
* Add special visuals for paid tag (0082765)
* Add 64-bit check to the Windows installer (c45d8f6)
* Add `Mod::checkUpdates` (9d02155)
* Error on attempting to hook missing or inlined functions (2dc989f)
* Implement function bound checking on Windows crashlog for symbol resolution (66c2f9a)
## v3.1.1 ## v3.1.1
* Update Windows installer translations (ae589d2, dca28db, d12fb37, 08d8af3, f52cf02, 3fa1d9b) * Update Windows installer translations (ae589d2, dca28db, d12fb37, 08d8af3, f52cf02, 3fa1d9b)
* Add safe mode by holding shift on MacOS (e4905a0) * Add safe mode by holding shift on MacOS (e4905a0)

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Tento průvodce vás provede odi
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nV této cestě se nenachází Geometry Dash!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nV této cestě se nenachází Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nVaše verze Geometry Dash je moc stará pro tuto verzi Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "V této cestě jsou již nainstalovány jiné mody!$\r$\nGeode bude nainstalován místo nich. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "V této cestě jsou již nainstalovány jiné mody!$\r$\nGeode bude nainstalován místo nich. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -18,6 +18,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup will guide you through the
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nThis path does not have Geometry Dash installed!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nThis path does not have Geometry Dash installed!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Saat tarvittavia ohjeita sitä m
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nValitussa kansiossa ei ole Geometry Dash -peliä asennettuna." ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nValitussa kansiossa ei ole Geometry Dash -peliä asennettuna."
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Valitussa kansiossa on jo Mega Hack v6/v7 asennettuna.$\r$\nGeode ei ole yhteensopiva MHv6/v7 kanssa (MHv8 on ensimmäinen yhteensopiva versio Geoden kanssa).$\r$\nPoistathan Mega Hackin ennen Geoden asentamista." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nGeometry Dash -pelisi on vanhentunut, eikä ole yhteensopiva tämän Geode-version kanssa!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Valitussa kansiossa on jo joitain modeja asennettuna.$\r$\nGeode ei ole yhteensopiva .DLL-muotoisten modien tai niiden lataajien kanssa.$\r$\nPoistathan .DLL-muotoiset modit ja niiden lataajat ennen Geoden asentamista. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Valitussa kansiossa on muita modeja asennettuna!$\r$\nGeode tulee poistamaan ne. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Le programme d'installation vous
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash n'est pas installé sur ce chemin !" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash n'est pas installé sur ce chemin !"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Ce chemin a déjà Mega Hack v6/v7 installé !$\r$\nGeode ne fonctionne pas avec MHv6/v7 (MHv8 sera compatible avec Geode).$\r$\nVeuillez le désinstaller avant de continuer." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Ce chemin contient déjà un autre chargeur de mod installé !$\r$\nGeode ne fonctionne avec aucun autre chargeur de mod.$\r$\nVeuillez le désinstaller avant de continuer. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Το setup θα σας καθο
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nΑυτό το path δεν έχει το Geometry Dash εγκατεστημένο!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nΑυτό το path δεν έχει το Geometry Dash εγκατεστημένο!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Αυτό το path έχει ήδη το Mega Hack v6/v7 εγκατεστημένο!$\r$\nΤο Geode δεν λειτουργεί με το MHv6/v7 (MHv8 θα είναι συμβατό με το Geode).$\r$\nΠαρακαλώ, απεγκαταστήστε το πριν προχωρήσετε." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Αυτό το path έχει ήδη ένα mod loader εγκατεστημένο!$\r$\nΤο Geode δεν λειτουργεί με οποιοδήποτε άλλο mod loader.$\r$\nΠαρακαλώ, απεγκαταστήστε το πριν προχωρήσετε. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "このセットアップは$(^Na
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nこのパスにはGeometry Dashがインストールされていません" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nこのパスにはGeometry Dashがインストールされていません"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "このパスには他のモッドがインストールされています!$\r$\nそれらはGeodeによって上書きされます。the dll trademark" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "このパスには他のモッドがインストールされています!$\r$\nそれらはGeodeによって上書きされます。the dll trademark"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "이 프로그램은 $(^NameDA)
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n이 경로에는 Geometry Dash가 설치되어 있지 않습니다." ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n이 경로에는 Geometry Dash가 설치되어 있지 않습니다."
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "이 경로에는 다른 모드가 설치되어 있습니다!$\r$\nGeode에 의해 덮어쓰게 될 것입니다. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "이 경로에는 다른 모드가 설치되어 있습니다!$\r$\nGeode에 의해 덮어쓰게 될 것입니다. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Instalator przeprowadzi Cię prz
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash nie jest zainstalowane w tym folderze!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash nie jest zainstalowane w tym folderze!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "W tym folderze zainstalowane są inne modyfikacje!$\r$\nZostaną one zastąpione przez Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "W tym folderze zainstalowane są inne modyfikacje!$\r$\nZostaną one zastąpione przez Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "O instalador guiará você atrav
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nEsse caminho não tem Geometry Dash instalado!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nEsse caminho não tem Geometry Dash instalado!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nSua versão do Geometry Dash é muito antiga para essa versão do Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Esse caminho já tem outros mods instalados!$\r$\nEles serão substituídos pelo Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Esse caminho já tem outros mods instalados!$\r$\nEles serão substituídos pelo Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Эта программа уда
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nПо этому пути не установлен Geometry Dash!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nПо этому пути не установлен Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nВаша версия Geometry Dash слишком старая для этой версии Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "По этому пути уже установлены другие моды!$\r$\nОни будут перезаписаны Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "По этому пути уже установлены другие моды!$\r$\nОни будут перезаписаны Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup会帮您卸载$(^NameDA)
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在这文件夹请再试一遍" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在这文件夹请再试一遍"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "这文件夹已经安装了Mega Hack v6/v7$\r$\nGeode不能跟MHv6/v7一起用(可是MHv8可以)。$\r$\n请先卸载MHv6/v7。" ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "这文件夹已经安装了不同的游戏修改器加载器!$\r$\nGeode不能和不同的游戏修改器加载器一起用。$\r$\n请先卸载那个游戏修改器加载器。 (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Este asistente te guiará durant
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "¡Mega Hack v6/v7 está instalado en esta ruta!$\r$\nGeode no es compatible con MHv6/v7 (MHv8 será compatible con Geode).$\r$\nPor favor, desinstálalo antes de continuar." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nTu versión de Geometry Dash es muy vieja para esta versión de Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "¡Hay otro cargador de mods instalado en esta ruta!$\r$\nGeode no funciona con ningún otro cargador de mods.$\r$\nPor favor, desinstálalo antes de continuar. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Esta ruta ya tiene otros mods instalados!$\r$\nEstos serán sobreescritos por Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Este asistente le guiará durant
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "¡Mega Hack v6/v7 está instalado en esta ruta!$\r$\nGeode no es compatible con MHv6/v7 (MHv8 será compatible con Geode).$\r$\nPor favor, desinstálelo antes de continuar." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "¡Hay otro mod loader instalado en esta ruta!$\r$\nGeode no funciona con ningún otro mod loader.$\r$\nPor favor, desinstálelo antes de continuar. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Denna guide tar dig igenom avins
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nDen valda mappen innehåller ingen installation av Geometry Dash." ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nDen valda mappen innehåller ingen installation av Geometry Dash."
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Den valda mappen innehåller redan Mega Hack v6/v7.$\r$\nGeode är inte kompatibel med MHv6/v7 (MHv8 är den första versionen som är kompatibel med Geode).$\r$\nSe till att avinstallera Mega Hack innan du startar installationen av Geode." ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nDin version av Geometry Dash är för gammal för denna versionen av Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Den valda mappen innehåller redan några andra mod.$\r$\nGeode är inte kompatibel med .DLL-slag mod eller sin mod loader.$\r$\nSe till att avinstallera .DLL-slag mod och sin mod loader innan du startar installationen av Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Den valda versionen av Geometry Dash har andra mod redan installerad!$\r$\nDom ska skrivs över av Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup會幫您卸載$(^NameDA)
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在這文件夾請再試一遍" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在這文件夾請再試一遍"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "這文件夾已經安裝了Mega Hack v6/v7$\r$\nGeode不能跟MHv6/v7一起用(可是MHv8可以跟Geode一起用)。$\r$\n請先卸載MHv6/v7。" ${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "這文件夾已經安裝了不同的遊戲修改器加載器!$\r$\nGeode不能跟不同的遊戲修改器加載器一起用。$\r$\n請先卸載那個遊戲修改器加載器。 (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Bu sihirbaz size $(^NameDA) prog
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nBu dizin yolunda Geometry Dash yüklü değildir!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nBu dizin yolunda Geometry Dash yüklü değildir!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nGeometry Dash versiyonunuz bu Geode versiyonu için çok eskidir!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Bu dizin yolunda başka modlar yüklüdür!$\r$\nGeode bunların üzerine yazılacaktır. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Bu dizin yolunda başka modlar yüklüdür!$\r$\nGeode bunların üzerine yazılacaktır. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Ця програма допом
; installer ; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nУ цій теці не встановлено Geometry Dash!" ${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nУ цій теці не встановлено Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nВаша версія Geometry Dash занадто стара для цієї версії Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Ця тека вже містить інші моди!$\r$\nВони будуть замінені Geode. (the dll trademark)" ${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Ця тека вже містить інші моди!$\r$\nВони будуть замінені Geode. (the dll trademark)"
; uninstaller ; uninstaller

View file

@ -407,6 +407,11 @@ Function .onVerifyInstDir
IfFileExists $INSTDIR\*.exe 0 noGameNoLife IfFileExists $INSTDIR\*.exe 0 noGameNoLife
IfFileExists $INSTDIR\libcocos2d.dll 0 noGameNoLife IfFileExists $INSTDIR\libcocos2d.dll 0 noGameNoLife
; check if we're on 64-bit gd (checks for some of the DLLs introduced in 2.206)
IfFileExists $INSTDIR\libpng16.dll 0 versionIssueImo
IfFileExists $INSTDIR\pthreadVC3.dll 0 versionIssueImo
IfFileExists $INSTDIR\libcrypto-3-x64.dll 0 versionIssueImo
; check if geode is already installed ; check if geode is already installed
IfFileExists $INSTDIR\Geode.dll valid IfFileExists $INSTDIR\Geode.dll valid
@ -423,6 +428,9 @@ Function .onVerifyInstDir
noGameNoLife: noGameNoLife:
SendMessage $geode.DirectoryPage.ErrorText ${WM_SETTEXT} "" "STR:$(GEODE_TEXT_GD_MISSING)" SendMessage $geode.DirectoryPage.ErrorText ${WM_SETTEXT} "" "STR:$(GEODE_TEXT_GD_MISSING)"
Goto error Goto error
versionIssueImo:
SendMessage $geode.DirectoryPage.ErrorText ${WM_SETTEXT} "" "STR:$(GEODE_TEXT_GD_OLD)"
Goto error
other_hackpro: other_hackpro:
StrCpy $0 "hackpro.dll" StrCpy $0 "hackpro.dll"
Goto other Goto other

View file

@ -183,7 +183,7 @@ public:
private: private:
void getSetOfTouchesEndOrCancel(CCSet& set, int num, int ids[], float xs[], float ys[]); void getSetOfTouchesEndOrCancel(CCSet& set, int num, int ids[], float xs[], float ys[]);
protected: public:
EGLTouchDelegate* m_pDelegate; EGLTouchDelegate* m_pDelegate;
// real screen size // real screen size

View file

@ -244,130 +244,4 @@ namespace geode {
virtual ~Event(); virtual ~Event();
}; };
// template <is_filter F, std::move_constructible T>
// class [[nodiscard]] EventMapper final {
// public:
// using Value = T;
// class Handle final {
// std::optional<EventListener<F>> m_listener;
// class PrivateMarker final {};
// static std::shared_ptr<Handle> create() {
// return std::make_shared<Handle>(PrivateMarker());
// }
// friend class EventMapper;
// public:
// Handle(PrivateMarker) {}
// };
// class Event final : public geode::Event {
// private:
// std::shared_ptr<Handle> m_handle;
// T m_value;
// Event(std::shared_ptr<Handle> handle, T&& value)
// : m_handle(handle), m_value(std::move(value)) {}
// friend class EventMapper;
// public:
// T& getValue() & {
// return m_value;
// }
// T const& getValue() const& {
// return m_value;
// }
// T&& getValue() && {
// return std::move(m_value);
// }
// operator T*() const {
// return m_value;
// }
// T* operator*() const {
// return m_value;
// }
// T* operator->() const {
// return m_value;
// }
// };
// using Mapper = utils::MiniFunction<T(typename F::Event*)>;
// using Callback = void(Event*);
// private:
// EventListenerProtocol* m_listener = nullptr;
// std::shared_ptr<Handle> m_handle;
// EventMapper(std::shared_ptr<Handle> handle) : m_handle(handle) {}
// public:
// EventMapper() : m_handle(nullptr) {}
// static EventMapper immediate(T&& value) {
// auto emapper = EventMapper(Handle::create());
// Loader::get()->queueInMainThread([handle = emapper.m_handle, value = std::move(value)]() mutable {
// EventMapper::Event(handle, std::move(value)).post();
// });
// return emapper;
// }
// static EventMapper create(F&& filter, Mapper&& mapper) {
// auto emapper = EventMapper(Handle::create());
// emapper.m_handle->m_listener.emplace(EventListener(
// // The event listener should not own itself (circular ref = memory leak!!)
// [handle = std::weak_ptr(emapper.m_handle), mapper = std::move(mapper)](F::Event* event) {
// if (auto lock = handle.lock()) {
// EventMapper::Event(lock, mapper(event)).post();
// }
// },
// std::move(filter)
// ));
// return emapper;
// }
// template <class NewMapper>
// auto map(NewMapper&& mapper) {
// using T2 = decltype(mapper(std::declval<T*>()));
// return mapEvent(*this, [mapper = std::move(mapper)](Event* event) -> T2 {
// return mapper(&event->getValue());
// });
// }
// ListenerResult handle(utils::MiniFunction<Callback> fn, Event* e) {
// if (e->m_handle == m_handle) {
// fn(e);
// }
// return ListenerResult::Propagate;
// }
// // todo: i believe alk wanted these to be in their own pool
// EventListenerPool* getPool() const {
// return DefaultEventListenerPool::get();
// }
// void setListener(EventListenerProtocol* listener) {
// m_listener = listener;
// }
// EventListenerProtocol* getListener() const {
// return m_listener;
// }
// };
// template <is_filter F, class Mapper>
// static auto mapEvent(F&& filter, Mapper&& mapper) {
// using T = decltype(mapper(std::declval<typename F::Event*>()));
// return EventMapper<F, T>::create(std::move(filter), std::move(mapper));
// }
// template <is_filter F, class Mapper>
// requires std::copy_constructible<F>
// static auto mapEvent(F const& filter, Mapper&& mapper) {
// using T = decltype(mapper(std::declval<typename F::Event*>()));
// return EventMapper<F, T>::create(F(filter), std::move(mapper));
// }
} }

View file

@ -142,8 +142,22 @@ namespace geode {
* @returns The latest available version on the index if there are * @returns The latest available version on the index if there are
* updates for this mod * updates for this mod
*/ */
[[deprecated("Use Mod::checkUpdates instead; this function always returns nullopt")]]
std::optional<VersionInfo> hasAvailableUpdate() const; std::optional<VersionInfo> hasAvailableUpdate() const;
using CheckUpdatesTask = Task<Result<std::optional<VersionInfo>, std::string>>;
/**
* Check if this Mod has updates available on the mods index. If
* you're using this for automatic update checking, use
* `openInfoPopup` from the `ui/GeodeUI.hpp` header to open the Mod's
* page to let the user install the update
* @returns A task that resolves to an option, either the latest
* available version on the index if there are updates available, or
* `std::nullopt` if there are no updates. On error, the Task returns
* an error
*/
CheckUpdatesTask checkUpdates() const;
Result<> saveData(); Result<> saveData();
Result<> loadData(); Result<> loadData();

View file

@ -103,7 +103,6 @@ namespace geode {
class FieldIntermediate; class FieldIntermediate;
} }
// TODO: make ordered
using ModJson = matjson::Value; using ModJson = matjson::Value;
} }

View file

@ -41,4 +41,11 @@ namespace geode::modifier {
GEODE_AS_STATIC_FUNCTION(constructor) GEODE_AS_STATIC_FUNCTION(constructor)
GEODE_AS_STATIC_FUNCTION(destructor) GEODE_AS_STATIC_FUNCTION(destructor)
#define GEODE_CONCEPT_FUNCTION_CHECK(FunctionName_) \
template <class Class, class... Args> \
concept FunctionExists_##FunctionName_ = requires(Class* self, Args... args) { \
self->FunctionName_(args...); \
};
} }

View file

@ -42,6 +42,38 @@
} \ } \
} while (0); } while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR(ClassName_, FunctionName_, ...) \
do { \
static_assert(!FunctionExists_##FunctionName_<Derived __VA_ARGS__>, \
"Function " #ClassName_ "::" #FunctionName_ " does not have an available address in the" \
" bindings, please add it to the bindings to hook it." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR_DEFINED(ClassName_, FunctionName_, ...) \
do { \
static auto constexpr different = Unique::different< \
Resolve<__VA_ARGS__>::func(&Base::FunctionName_), \
Resolve<__VA_ARGS__>::func(&Derived::FunctionName_) \
>(); \
static_assert(!different, \
"Function " #ClassName_ "::" #FunctionName_ " does not have an available address in the" \
" bindings, please add it to the bindings to hook it." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR_INLINE(ClassName_, FunctionName_, ...) \
do { \
static auto constexpr different = Unique::different< \
Resolve<__VA_ARGS__>::func(&Base::FunctionName_), \
Resolve<__VA_ARGS__>::func(&Derived::FunctionName_) \
>(); \
static_assert(!different, \
"Function " #ClassName_ "::" #FunctionName_ " cannot be hooked due to an inline definition" \
" existing for the function." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_CONSTRUCTOR(AddressInline_, Convention_, ClassName_, ...) \ #define GEODE_APPLY_MODIFY_FOR_CONSTRUCTOR(AddressInline_, Convention_, ClassName_, ...) \
do { \ do { \
if constexpr (HasConstructor<Derived>) { \ if constexpr (HasConstructor<Derived>) { \

View file

@ -85,6 +85,7 @@ namespace geode {
Magenta = 9, Magenta = 9,
DimGreen = 10, DimGreen = 10,
BrightGreen = 11, BrightGreen = 11,
Salmon = 12,
}; };
GEODE_DLL const char* baseEnumToString(EditorBaseColor); GEODE_DLL const char* baseEnumToString(EditorBaseColor);

View file

@ -11,6 +11,10 @@ namespace geode {
* Open the info popup for a mod * Open the info popup for a mod
*/ */
GEODE_DLL void openInfoPopup(Mod* mod); GEODE_DLL void openInfoPopup(Mod* mod);
/**
* Open the info popup for a mod on the changelog page
*/
GEODE_DLL void openChangelogPopup(Mod* mod);
/** /**
* Open the issue report popup for a mod * Open the issue report popup for a mod
*/ */
@ -23,6 +27,7 @@ namespace geode {
/** /**
* Open the store page for a mod (if it exists) * Open the store page for a mod (if it exists)
*/ */
[[deprecated("Will be removed, use openInfoPopup instead")]]
GEODE_DLL void openIndexPopup(Mod* mod); GEODE_DLL void openIndexPopup(Mod* mod);
/** /**
* Open the settings popup for a mod (if it has any settings) * Open the settings popup for a mod (if it has any settings)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -50,6 +50,7 @@ editor_colors = {
"LightBlue": ["#52e8ff", "#4fb1ff", "#2f6ac7"], "LightBlue": ["#52e8ff", "#4fb1ff", "#2f6ac7"],
"Gray": ["#c8c7c9", "#9b9a9b", "#5c5c5d"], "Gray": ["#c8c7c9", "#9b9a9b", "#5c5c5d"],
"DarkGray": ["#9a9a9a", "#717171", "#3a3a3a"], "DarkGray": ["#9a9a9a", "#717171", "#3a3a3a"],
"Salmon": ["#ffbbb9", "#ff9260", "#e15032"],
} }
for size in sizes: for size in sizes:
@ -57,7 +58,7 @@ for size in sizes:
svg_base = file.read() svg_base = file.read()
for name, cols in colors.items(): for name, cols in colors.items():
svg = svg_base svg = svg_base
out = f"../baseCircle_{size}_{name.title()}.png" out = f"../baseCircle_{size}_{name}.png"
print(f"Generating {out}") print(f"Generating {out}")
for color_orig, color_to in zip(color_from, cols): for color_orig, color_to in zip(color_from, cols):
svg = svg.replace(color_orig, color_to) svg = svg.replace(color_orig, color_to)
@ -68,8 +69,8 @@ for size in editor_sizes:
svg_base = file.read() svg_base = file.read()
for name, cols in editor_colors.items(): for name, cols in editor_colors.items():
svg = svg_base svg = svg_base
out = f"../baseEditor_{size}_{name.title()}.png" out = f"../baseEditor_{size}_{name}.png"
print(f"Generating {out}") print(f"Generating {out}")
for color_orig, color_to in zip(editor_color_from, cols): for color_orig, color_to in zip(editor_color_from, cols):
svg = svg.replace(color_orig, color_to) svg = svg.replace(color_orig, color_to)
subprocess.run(["rsvg-convert", "-o", out], input=svg.encode()) subprocess.run(["rsvg-convert", "-o", out], input=svg.encode())

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -384,11 +384,6 @@ void Loader::Impl::buildModGraph() {
} }
void Loader::Impl::loadModGraph(Mod* node, bool early) { void Loader::Impl::loadModGraph(Mod* node, bool early) {
if (early && !node->needsEarlyLoad()) {
m_modsToLoad.push_back(node);
return;
}
if (node->hasUnresolvedDependencies()) { if (node->hasUnresolvedDependencies()) {
log::debug("{} {} has unresolved dependencies", node->getID(), node->getVersion()); log::debug("{} {} has unresolved dependencies", node->getID(), node->getVersion());
return; return;
@ -402,9 +397,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
log::pushNest(); log::pushNest();
if (node->isEnabled()) { if (node->isEnabled()) {
for (auto const& dep : node->m_impl->m_dependants) { log::warn("Mod {} already loaded, this should never happen", node->getID());
m_modsToLoad.push_front(dep);
}
log::popNest(); log::popNest();
return; return;
} }
@ -434,10 +427,6 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
m_refreshingModCount -= 1; m_refreshingModCount -= 1;
return; return;
} }
for (auto const& dep : node->m_impl->m_dependants) {
m_modsToLoad.push_front(dep);
}
} }
m_refreshingModCount -= 1; m_refreshingModCount -= 1;
@ -702,11 +691,18 @@ void Loader::Impl::refreshModGraph() {
this->buildModGraph(); this->buildModGraph();
log::popNest(); log::popNest();
log::debug("Ordering mod stack");
log::pushNest();
this->orderModStack();
log::popNest();
m_loadingState = LoadingState::EarlyMods; m_loadingState = LoadingState::EarlyMods;
log::debug("Loading early mods"); log::debug("Loading early mods");
log::pushNest(); log::pushNest();
for (auto const& dep : ModImpl::get()->m_dependants) { while (!m_modsToLoad.empty() && m_modsToLoad.front()->needsEarlyLoad()) {
this->loadModGraph(dep, true); auto mod = m_modsToLoad.front();
m_modsToLoad.pop_front();
this->loadModGraph(mod, true);
} }
log::popNest(); log::popNest();
@ -716,16 +712,60 @@ void Loader::Impl::refreshModGraph() {
log::popNest(); log::popNest();
if (m_modsToLoad.empty()) m_loadingState = LoadingState::Mods;
m_loadingState = LoadingState::Problems;
else
m_loadingState = LoadingState::Mods;
queueInMainThread([&]() { queueInMainThread([&]() {
this->continueRefreshModGraph(); this->continueRefreshModGraph();
}); });
} }
void Loader::Impl::orderModStack() {
std::unordered_set<Mod*> visited;
visited.insert(Mod::get());
Mod* selectedMod = nullptr;
do {
selectedMod = nullptr;
for (auto const& mod : ModImpl::get()->m_dependants) {
if (visited.count(mod) != 0) continue;
for (auto dep : mod->getMetadata().getDependencies()) {
if (dep.mod && dep.importance == ModMetadata::Dependency::Importance::Required &&
visited.count(dep.mod) == 0) {
// the dependency is not visited yet
// so we cant select this mod
goto skip_mod;
}
}
if (selectedMod) {
if (
!selectedMod->m_impl->needsEarlyLoad() &&
mod->m_impl->needsEarlyLoad()
) {
// this mod is implied to be loaded early
// so we can override a mod that is not
selectedMod = mod;
}
}
else {
selectedMod = mod;
}
skip_mod:
continue;
}
if (selectedMod) {
m_modsToLoad.push_back(selectedMod);
visited.insert(selectedMod);
}
} while (selectedMod != nullptr);
for (auto mod : m_modsToLoad) {
log::debug("{}, early: {}", mod->getID(), mod->needsEarlyLoad());
}
}
void Loader::Impl::continueRefreshModGraph() { void Loader::Impl::continueRefreshModGraph() {
if (m_refreshingModCount != 0) { if (m_refreshingModCount != 0) {
queueInMainThread([&]() { queueInMainThread([&]() {

View file

@ -22,7 +22,6 @@
#include <queue> #include <queue>
#include <tulip/TulipHook.hpp> #include <tulip/TulipHook.hpp>
// TODO: Find a file convention for impl headers
namespace geode { namespace geode {
static constexpr std::string_view LAUNCH_ARG_PREFIX = "--geode:"; static constexpr std::string_view LAUNCH_ARG_PREFIX = "--geode:";
@ -100,6 +99,7 @@ namespace geode {
void queueMods(std::vector<ModMetadata>& modQueue); void queueMods(std::vector<ModMetadata>& modQueue);
void populateModList(std::vector<ModMetadata>& modQueue); void populateModList(std::vector<ModMetadata>& modQueue);
void buildModGraph(); void buildModGraph();
void orderModStack();
void loadModGraph(Mod* node, bool early); void loadModGraph(Mod* node, bool early);
void findProblems(); void findProblems();
void refreshModGraph(); void refreshModGraph();

View file

@ -4,6 +4,7 @@
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <server/Server.hpp>
using namespace geode::prelude; using namespace geode::prelude;
@ -101,17 +102,30 @@ std::vector<Mod*> Mod::getDependants() const {
#endif #endif
std::optional<VersionInfo> Mod::hasAvailableUpdate() const { std::optional<VersionInfo> Mod::hasAvailableUpdate() const {
// TODO
// if (auto item = Index::get()->getItem(this->getID(), std::nullopt)) {
// if (
// item->getMetadata().getVersion() > this->getVersion() &&
// item->getAvailablePlatforms().contains(GEODE_PLATFORM_TARGET)
// ) {
// return item->getMetadata().getVersion();
// }
// }
return std::nullopt; return std::nullopt;
} }
Mod::CheckUpdatesTask Mod::checkUpdates() const {
return server::checkUpdates(this).map(
[](auto* result) -> Mod::CheckUpdatesTask::Value {
if (result->isOk()) {
if (auto value = result->unwrap()) {
if (value->replacement) {
return Err(
"Mod has been replaced by {} - please visit the Geode "
"menu to install the replacement",
value->replacement->id
);
}
return Ok(value->version);
}
return Ok(std::nullopt);
}
auto err = result->unwrapErr();
return Err("{} (code {})", err.details, err.code);
},
[](auto*) { return std::monostate(); }
);
}
Result<> Mod::saveData() { Result<> Mod::saveData() {
return m_impl->saveData(); return m_impl->saveData();

View file

@ -140,7 +140,7 @@ matjson::Value& Mod::Impl::getSavedSettingsData() {
} }
bool Mod::Impl::isEnabled() const { bool Mod::Impl::isEnabled() const {
return m_enabled; return m_enabled || this->isInternal();
} }
bool Mod::Impl::isInternal() const { bool Mod::Impl::isInternal() const {
@ -148,11 +148,11 @@ bool Mod::Impl::isInternal() const {
} }
bool Mod::Impl::needsEarlyLoad() const { bool Mod::Impl::needsEarlyLoad() const {
auto deps = m_dependants; if (this->getMetadata().needsEarlyLoad()) return true;
return getMetadata().needsEarlyLoad() || for (auto& dep : m_dependants) {
!deps.empty() && std::any_of(deps.begin(), deps.end(), [&](auto& item) { if (dep->needsEarlyLoad()) return true;
return item->needsEarlyLoad(); }
}); return false;
} }
std::vector<Hook*> Mod::Impl::getHooks() const { std::vector<Hook*> Mod::Impl::getHooks() const {
@ -800,7 +800,7 @@ void Mod::Impl::setLoggingEnabled(bool enabled) {
} }
bool Mod::Impl::shouldLoad() const { bool Mod::Impl::shouldLoad() const {
return Mod::get()->getSavedValue<bool>("should-load-" + m_metadata.getID(), true); return Mod::get()->getSavedValue<bool>("should-load-" + m_metadata.getID(), true) || this->isInternal();
} }
bool Mod::Impl::isCurrentlyLoading() const { bool Mod::Impl::isCurrentlyLoading() const {

View file

@ -91,8 +91,36 @@ static Mod* modFromAddress(PVOID exceptionAddress) {
return nullptr; return nullptr;
} }
PVOID GeodeFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
typedef union _UNWIND_CODE {
struct {
uint8_t CodeOffset;
uint8_t UnwindOp : 4;
uint8_t OpInfo : 4;
};
uint16_t FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
typedef struct _UNWIND_INFO {
uint8_t Version : 3;
uint8_t Flags : 5;
uint8_t SizeOfProlog;
uint8_t CountOfCodes;
uint8_t FrameRegister : 4;
uint8_t FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
/* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
* union {
* OPTIONAL ULONG ExceptionHandler;
* OPTIONAL ULONG FunctionEntry;
* };
* OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, *PUNWIND_INFO;
static void printAddr(std::ostream& stream, void const* addr, bool fullPath = true) { static void printAddr(std::ostream& stream, void const* addr, bool fullPath = true) {
HMODULE module = nullptr; HMODULE module = nullptr;
auto proc = GetCurrentProcess();
if (GetModuleHandleEx( if (GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
@ -114,12 +142,26 @@ static void printAddr(std::ostream& stream, void const* addr, bool fullPath = tr
symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO); symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
symbolInfo->MaxNameLen = MAX_SYM_NAME; symbolInfo->MaxNameLen = MAX_SYM_NAME;
auto proc = GetCurrentProcess();
if (SymFromAddr( if (SymFromAddr(
proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)), &displacement, proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)), &displacement,
symbolInfo symbolInfo
)) { )) {
if (auto entry = SymFunctionTableAccess64(proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)))) {
auto moduleBase = SymGetModuleBase64(proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)));
auto runtimeFunction = static_cast<PRUNTIME_FUNCTION>(entry);
auto unwindInfo = reinterpret_cast<PUNWIND_INFO>(moduleBase + runtimeFunction->UnwindInfoAddress);
// This is a chain of unwind info structures, so we traverse back to the first one
while (unwindInfo->Flags & UNW_FLAG_CHAININFO) {
runtimeFunction = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);
unwindInfo = reinterpret_cast<PUNWIND_INFO>(moduleBase + runtimeFunction->UnwindInfoAddress);
}
if (moduleBase + runtimeFunction->BeginAddress != symbolInfo->Address) {
// the symbol address is not the same as the function address
return;
}
}
stream << " (" << std::string(symbolInfo->Name, symbolInfo->NameLen) << " + " stream << " (" << std::string(symbolInfo->Name, symbolInfo->NameLen) << " + "
<< displacement; << displacement;
@ -141,11 +183,13 @@ static void printAddr(std::ostream& stream, void const* addr, bool fullPath = tr
} }
else { else {
stream << addr; stream << addr;
if (GeodeFunctionTableAccess64(proc, reinterpret_cast<DWORD64>(addr))) {
stream << " (Hook handler)";
}
} }
} }
PVOID GeodeFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
// https://stackoverflow.com/a/50208684/9124836 // https://stackoverflow.com/a/50208684/9124836
static std::string getStacktrace(PCONTEXT context, Mod*& suspectedFaultyMod) { static std::string getStacktrace(PCONTEXT context, Mod*& suspectedFaultyMod) {
std::stringstream stream; std::stringstream stream;

View file

@ -770,7 +770,7 @@ ServerRequest<std::unordered_set<std::string>> server::getTags(bool useCache) {
); );
} }
ServerRequest<std::optional<ServerModUpdate>> server::checkUpdates(Mod* mod) { ServerRequest<std::optional<ServerModUpdate>> server::checkUpdates(Mod const* mod) {
return checkAllUpdates().map( return checkAllUpdates().map(
[mod](Result<std::vector<ServerModUpdate>, ServerError>* result) -> Result<std::optional<ServerModUpdate>, ServerError> { [mod](Result<std::vector<ServerModUpdate>, ServerError>* result) -> Result<std::optional<ServerModUpdate>, ServerError> {
if (result->isOk()) { if (result->isOk()) {

View file

@ -150,7 +150,7 @@ namespace server {
ServerRequest<ByteVector> getModLogo(std::string const& id, bool useCache = true); ServerRequest<ByteVector> getModLogo(std::string const& id, bool useCache = true);
ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true); ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true);
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod* mod); ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
ServerRequest<std::vector<ServerModUpdate>> checkAllUpdates(bool useCache = true); ServerRequest<std::vector<ServerModUpdate>> checkAllUpdates(bool useCache = true);
void clearServerCaches(bool clearGlobalCaches = false); void clearServerCaches(bool clearGlobalCaches = false);

View file

@ -66,12 +66,17 @@ void geode::openSupportPopup(ModMetadata const& metadata) {
} }
void geode::openInfoPopup(Mod* mod) { void geode::openInfoPopup(Mod* mod) {
// TODO ModPopup::create(mod)->show();
// LocalModInfoPopup::create(mod, nullptr)->show(); }
void geode::openIndexPopup(Mod* mod) {
// deprecated func
openInfoPopup(mod);
} }
void geode::openIndexPopup(Mod* mod) { void geode::openChangelogPopup(Mod* mod) {
ModPopup::create(mod)->show(); auto popup = ModPopup::create(mod);
popup->loadTab(ModPopup::Tab::Changelog);
popup->show();
} }
void geode::openSettingsPopup(Mod* mod) { void geode::openSettingsPopup(Mod* mod) {

View file

@ -20,7 +20,7 @@ $on_mod(Loaded) {
ColorProvider::get()->define("mod-list-tab-deselected-bg"_spr, { 26, 24, 29, 255 }); ColorProvider::get()->define("mod-list-tab-deselected-bg"_spr, { 26, 24, 29, 255 });
ColorProvider::get()->define("mod-list-tab-selected-bg"_spr, { 168, 147, 185, 255 }); ColorProvider::get()->define("mod-list-tab-selected-bg"_spr, { 168, 147, 185, 255 });
ColorProvider::get()->define("mod-list-tab-selected-bg-alt"_spr, { 147, 163, 185, 255 }); ColorProvider::get()->define("mod-list-tab-selected-bg-alt"_spr, { 147, 163, 185, 255 });
ColorProvider::get()->define("mod-list-featured-color"_spr, { 255, 255, 120, 255 }); ColorProvider::get()->define("mod-list-featured-color"_spr, { 240, 211, 42, 255 });
ColorProvider::get()->define("mod-list-enabled"_spr, { 120, 255, 100, 255 }); ColorProvider::get()->define("mod-list-enabled"_spr, { 120, 255, 100, 255 });
ColorProvider::get()->define("mod-list-disabled"_spr, { 255, 120, 100, 255 }); ColorProvider::get()->define("mod-list-disabled"_spr, { 255, 120, 100, 255 });
ColorProvider::get()->define("mod-list-recommended-bg"_spr, ccc3(25, 255, 167)); ColorProvider::get()->define("mod-list-recommended-bg"_spr, ccc3(25, 255, 167));
@ -28,6 +28,7 @@ $on_mod(Loaded) {
ColorProvider::get()->define("mod-list-recommended-by-2"_spr, ccc3(47, 255, 255)); ColorProvider::get()->define("mod-list-recommended-by-2"_spr, ccc3(47, 255, 255));
ColorProvider::get()->define("mod-problems-item-bg"_spr, { 255, 255, 255, 15 }); ColorProvider::get()->define("mod-problems-item-bg"_spr, { 255, 255, 255, 15 });
ColorProvider::get()->define("mod-developer-item-bg"_spr, { 255, 255, 255, 15 }); ColorProvider::get()->define("mod-developer-item-bg"_spr, { 255, 255, 255, 15 });
ColorProvider::get()->define("mod-list-paid-color"_spr, { 0, 255, 63, 255 });
// Only used when GD theme is active // Only used when GD theme is active
ColorProvider::get()->define("mods-layer-gd-bg"_spr, { 0, 102, 255, 255 }); ColorProvider::get()->define("mods-layer-gd-bg"_spr, { 0, 102, 255, 255 });

View file

@ -53,6 +53,7 @@ bool ModItem::init(ModSource&& source) {
m_titleLabel = CCLabelBMFont::create(m_source.getMetadata().getName().c_str(), "bigFont.fnt"); m_titleLabel = CCLabelBMFont::create(m_source.getMetadata().getName().c_str(), "bigFont.fnt");
m_titleLabel->setID("title-label"); m_titleLabel->setID("title-label");
m_titleLabel->setLayoutOptions(AxisLayoutOptions::create()->setScalePriority(1));
m_titleContainer->addChild(m_titleLabel); m_titleContainer->addChild(m_titleLabel);
m_versionLabel = CCLabelBMFont::create("", "bigFont.fnt"); m_versionLabel = CCLabelBMFont::create("", "bigFont.fnt");
@ -182,16 +183,14 @@ bool ModItem::init(ModSource&& source) {
}, },
[this](server::ServerModMetadata const& metadata) { [this](server::ServerModMetadata const& metadata) {
if (metadata.featured) { if (metadata.featured) {
auto starBG = CCScale9Sprite::createWithSpriteFrameName("GJ_colorBtn_001.png"); auto star = CCSprite::createWithSpriteFrameName("tag-featured.png"_spr);
starBG->setContentSize({ 50, 38 }); star->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
starBG->setColor(to3B(ColorProvider::get()->color("mod-list-featured-color"_spr))); m_titleContainer->addChild(star);
starBG->setOpacity(45); }
if (metadata.tags.contains("paid")) {
auto star = CCSprite::createWithSpriteFrameName("GJ_starsIcon_001.png"); auto paidModLabel = CCSprite::createWithSpriteFrameName("tag-paid.png"_spr);
starBG->addChildAtPosition(star, Anchor::Center); paidModLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
starBG->setID("star-bg"); m_titleContainer->addChild(paidModLabel);
m_titleContainer->addChild(starBG);
} }
// Show mod download count here already so people can make informed decisions // Show mod download count here already so people can make informed decisions
@ -338,9 +337,15 @@ void ModItem::updateState() {
[this](server::ServerModMetadata const& metadata) { [this](server::ServerModMetadata const& metadata) {
m_bg->setColor(isGeodeTheme() ? ccWHITE : ccBLACK); m_bg->setColor(isGeodeTheme() ? ccWHITE : ccBLACK);
m_bg->setOpacity(isGeodeTheme() ? 25 : 90); m_bg->setOpacity(isGeodeTheme() ? 25 : 90);
if (metadata.tags.contains("paid")) {
m_bg->setColor("mod-list-paid-color"_cc3b);
m_bg->setOpacity(55);
}
if (isGeodeTheme() && metadata.featured) { if (isGeodeTheme() && metadata.featured) {
m_bg->setColor("mod-list-featured-color"_cc3b); m_bg->setColor("mod-list-featured-color"_cc3b);
m_bg->setOpacity(40); m_bg->setOpacity(65);
} }
}, },
[this](ModSuggestion const& suggestion) { [this](ModSuggestion const& suggestion) {
@ -449,6 +454,22 @@ void ModItem::onCheckUpdates(typename server::ServerRequest<std::optional<server
} }
void ModItem::onView(CCObject*) { void ModItem::onView(CCObject*) {
// This is a local static and not a mod saved value because we might want
// to periodically remind users that paid mods are paid
static bool shownPaidNotif = false;
if (m_source.asServer() && m_source.asServer()->tags.contains("paid") && !shownPaidNotif) {
shownPaidNotif = true;
return FLAlertLayer::create(
nullptr,
"Paid Content",
"This mod contains <cg>Paid Content</c>. This means that some or all "
"features of the mod <cj>require money to use</c>.\n\n"
"<cy>Geode does not handle any payments. The mod handles all transactions in their own way.</c>\n\n"
"<cp>The paid content may not be available in your country.</c>",
"OK", nullptr, 360
)->show();
}
// Always open up the popup for the installed mod page if that is possible // Always open up the popup for the installed mod page if that is possible
ModPopup::create(m_source.convertForPopup())->show(); ModPopup::create(m_source.convertForPopup())->show();
} }

View file

@ -19,6 +19,11 @@ bool ConfirmUninstallPopup::setup(Mod* mod) {
deleteDataLabel->setScale(.35f); deleteDataLabel->setScale(.35f);
m_buttonMenu->addChildAtPosition(deleteDataLabel, Anchor::Center, ccp(-70, -15), ccp(0, .5f)); m_buttonMenu->addChildAtPosition(deleteDataLabel, Anchor::Center, ccp(-70, -15), ccp(0, .5f));
if (mod->isInternal()) {
deleteDataLabel->setString("Delete ALL mods and their save data");
deleteDataLabel->setScale(0.275f);
}
m_deleteDataToggle = CCMenuItemToggler::createWithStandardSprites(this, nullptr, .6f); m_deleteDataToggle = CCMenuItemToggler::createWithStandardSprites(this, nullptr, .6f);
m_buttonMenu->addChildAtPosition(m_deleteDataToggle, Anchor::Center, ccp(-88, -15)); m_buttonMenu->addChildAtPosition(m_deleteDataToggle, Anchor::Center, ccp(-88, -15));

View file

@ -648,9 +648,12 @@ void ModPopup::updateState() {
if (asMod && asMod->isInternal()) { if (asMod && asMod->isInternal()) {
m_enableBtn->setVisible(false); m_enableBtn->setVisible(false);
// you can uninstall loader ingame just fine on windows
#if !defined(GEODE_IS_WINDOWS)
m_uninstallBtn->setVisible(false); m_uninstallBtn->setVisible(false);
m_installStatusLabel->setString("N/A"); m_installStatusLabel->setString("N/A");
m_installStatusLabel->setVisible(true); m_installStatusLabel->setVisible(true);
#endif
} }
auto download = server::ModDownloadManager::get()->getDownload(m_source.getID()); auto download = server::ModDownloadManager::get()->getDownload(m_source.getID());

View file

@ -10,13 +10,14 @@
using namespace geode::prelude; using namespace geode::prelude;
class ModPopup : public GeodePopup<ModSource&&> { class ModPopup : public GeodePopup<ModSource&&> {
protected: public:
enum class Tab { enum class Tab {
Details, Details,
Changelog, Changelog,
Versions, Versions,
}; };
protected:
ModSource m_source; ModSource m_source;
CCNode* m_stats; CCNode* m_stats;
CCNode* m_tags; CCNode* m_tags;
@ -51,7 +52,6 @@ protected:
void onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event); void onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event);
void onCheckUpdates(typename server::ServerRequest<std::optional<server::ServerModUpdate>>::Event* event); void onCheckUpdates(typename server::ServerRequest<std::optional<server::ServerModUpdate>>::Event* event);
void loadTab(Tab tab);
void onTab(CCObject* sender); void onTab(CCObject* sender);
void onEnable(CCObject*); void onEnable(CCObject*);
void onInstall(CCObject*); void onInstall(CCObject*);
@ -63,5 +63,6 @@ protected:
void onSupport(CCObject*); void onSupport(CCObject*);
public: public:
void loadTab(Tab tab);
static ModPopup* create(ModSource&& src); static ModPopup* create(ModSource&& src);
}; };

View file

@ -98,6 +98,7 @@ const char* geode::baseEnumToString(EditorBaseColor value) {
case EditorBaseColor::Magenta: return "Magenta"; case EditorBaseColor::Magenta: return "Magenta";
case EditorBaseColor::DimGreen: return "DimGreen"; case EditorBaseColor::DimGreen: return "DimGreen";
case EditorBaseColor::BrightGreen: return "BrightGreen"; case EditorBaseColor::BrightGreen: return "BrightGreen";
case EditorBaseColor::Salmon: return "Salmon";
} }
return "Unknown"; return "Unknown";
} }