Merge branch 'main' of https://github.com/geode-sdk/geode
18
CHANGELOG.md
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,6 @@ namespace geode {
|
||||||
class FieldIntermediate;
|
class FieldIntermediate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make ordered
|
|
||||||
using ModJson = matjson::Value;
|
using ModJson = matjson::Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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...); \
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>) { \
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 11 KiB |
BIN
loader/resources/blanks/baseCircle_Big_DarkAqua.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
loader/resources/blanks/baseEditor_Normal_Blue.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
loader/resources/blanks/baseEditor_Normal_BrightGreen.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
loader/resources/blanks/baseEditor_Normal_DimGreen.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
loader/resources/blanks/baseEditor_Normal_Magenta.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
loader/resources/blanks/baseEditor_Normal_Salmon.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -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,7 +69,7 @@ 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)
|
||||||
|
|
BIN
loader/resources/tag-featured.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
loader/resources/tag-paid.png
Normal file
After Width: | Height: | Size: 33 KiB |
|
@ -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([&]() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|