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

This commit is contained in:
camila314 2023-09-11 13:12:21 -05:00
commit 734ddd0ed9
103 changed files with 469 additions and 323 deletions

View file

@ -1,5 +1,8 @@
# Geode Changelog # Geode Changelog
## v1.3.1
* Fix TulipHook not relocating RIP relative operands on MacOS (6cad19d)
## v1.3.0 ## v1.3.0
* Completely remove runtime enabling & disabling of mods (d817749) * Completely remove runtime enabling & disabling of mods (d817749)
* Patches auto enabling can be disabled (69821f3) * Patches auto enabling can be disabled (69821f3)

View file

@ -96,7 +96,7 @@ if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS)
set(TULIP_LINK_SOURCE ON) set(TULIP_LINK_SOURCE ON)
endif() endif()
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE) set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
CPMAddPackage("gh:geode-sdk/TulipHook#2e4cb5a") CPMAddPackage("gh:geode-sdk/TulipHook#3423a29")
set(CMAKE_WARN_DEPRECATED ON CACHE BOOL "" FORCE) set(CMAKE_WARN_DEPRECATED ON CACHE BOOL "" FORCE)
# Silence warnings from dependencies # Silence warnings from dependencies

View file

@ -1 +1 @@
1.3.0 1.4.0

View file

@ -174,7 +174,7 @@ class cocos2d::CCDirector {
auto convertToGL(cocos2d::CCPoint const&) = mac 0x24a210; auto convertToGL(cocos2d::CCPoint const&) = mac 0x24a210;
auto convertToUI(cocos2d::CCPoint const&) = mac 0x24a340; auto convertToUI(cocos2d::CCPoint const&) = mac 0x24a340;
auto drawScene() = mac 0x249690; auto drawScene() = mac 0x249690;
auto willSwitchToScene(cocos2d::CCScene* scene); auto willSwitchToScene(cocos2d::CCScene* scene) = mac 0x24a520;
auto setOpenGLView(cocos2d::CCEGLView *pobOpenGLView) = mac 0x249be0; auto setOpenGLView(cocos2d::CCEGLView *pobOpenGLView) = mac 0x249be0;
auto updateScreenScale(cocos2d::CCSize) = mac 0x249f10; auto updateScreenScale(cocos2d::CCSize) = mac 0x249f10;
auto setContentScaleFactor(float); auto setContentScaleFactor(float);
@ -291,7 +291,7 @@ class cocos2d::CCEGLViewProtocol {
auto getScaleX() const = mac 0x29e300; auto getScaleX() const = mac 0x29e300;
auto getScaleY() const = mac 0x29e310; auto getScaleY() const = mac 0x29e310;
virtual auto setDesignResolutionSize(float, float, ResolutionPolicy); virtual auto setDesignResolutionSize(float, float, ResolutionPolicy);
auto setFrameSize(float, float) = mac 0x29d960; virtual void setFrameSize(float, float) = mac 0x29d960;
} }
[[link(win)]] [[link(win)]]
@ -318,6 +318,7 @@ class cocos2d::CCFileUtils : cocos2d::TypeInfo {
class cocos2d::CCGLProgram { class cocos2d::CCGLProgram {
auto setUniformsForBuiltins() = mac 0x232c70; auto setUniformsForBuiltins() = mac 0x232c70;
auto use() = mac 0x231d70; auto use() = mac 0x231d70;
bool compileShader(unsigned int* shader, unsigned int type, const char* source);
} }
[[link(win)]] [[link(win)]]
@ -891,6 +892,7 @@ class cocos2d::CCSet {
class cocos2d::CCShaderCache { class cocos2d::CCShaderCache {
static auto sharedShaderCache() = mac 0xe6d10; static auto sharedShaderCache() = mac 0xe6d10;
auto programForKey(const char*) = mac 0xe7d40; auto programForKey(const char*) = mac 0xe7d40;
void reloadDefaultShaders();
} }
[[link(win)]] [[link(win)]]

View file

@ -3045,7 +3045,9 @@ class GameManager : GManager {
void loadGround(int) = mac 0x1cc8e0, win 0xc9a50; void loadGround(int) = mac 0x1cc8e0, win 0xc9a50;
void reloadAll(bool, bool, bool) = mac 0x1d08a0, win 0xce950; void reloadAll(bool, bool, bool) = mac 0x1d08a0, win 0xce950;
void reloadAllStep2() = mac 0x1d0940, win 0xce9e0, ios 0x23b1f4; void reloadAllStep2() = mac 0x1d0940, win 0xce9e0, ios 0x23b1f4;
void reloadAllStep5() = mac 0x1d0b00; void reloadAllStep3() = win 0xceb10;
void reloadAllStep4() = win 0xceb80;
void reloadAllStep5() = mac 0x1d0b00, win 0xcebf0;
void reportPercentageForLevel(int, int, bool) = mac 0x1c5b00; void reportPercentageForLevel(int, int, bool) = mac 0x1c5b00;
void setGameVariable(const char*, bool) = mac 0x1cca80, win 0xc9b50; void setGameVariable(const char*, bool) = mac 0x1cca80, win 0xc9b50;
void setIntGameVariable(const char*, int) = mac 0x1cd0e0, win 0xca230; void setIntGameVariable(const char*, int) = mac 0x1cd0e0, win 0xca230;

View file

@ -46,6 +46,7 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS")
target_link_libraries(${PROJECT_NAME} INTERFACE target_link_libraries(${PROJECT_NAME} INTERFACE
"-framework Cocoa" "-framework Cocoa"
"-framework OpenGL"
${CURL_LIBRARIES} ${CURL_LIBRARIES}
${GEODE_LOADER_PATH}/include/link/libfmod.dylib ${GEODE_LOADER_PATH}/include/link/libfmod.dylib
) )

View file

@ -490,8 +490,10 @@ Function un.onInit
FunctionEnd FunctionEnd
Section "Uninstall" Section "Uninstall"
DeleteRegKey /ifempty HKCU "Software\Geode" DeleteRegKey /ifempty HKCU "Software\Geode"
Delete $INSTDIR\GeodeUninstaller.exe
Delete $INSTDIR\Geode.dll Delete $INSTDIR\Geode.dll
Delete $INSTDIR\Geode.pdb Delete $INSTDIR\Geode.pdb
Delete $INSTDIR\Geode.lib
Delete $INSTDIR\GeodeUpdater.exe Delete $INSTDIR\GeodeUpdater.exe
Delete $INSTDIR\XInput9_1_0.dll Delete $INSTDIR\XInput9_1_0.dll

View file

@ -54,6 +54,30 @@ public:
size_t getGrow() const; size_t getGrow() const;
}; };
/**
* A spacer node that updates the content size of its child to match its own
* @note This is useful for making a spacer node that takes up the remaining
* space in a layout
*/
class GEODE_DLL SpacerNodeChild : public SpacerNode {
protected:
CCNode* m_child = nullptr;
bool init(CCNode* child, size_t grow);
public:
/**
* Create a new spacer node. When the layout is applied,
* if there is space left over the remaining space is distributed among
* all spacer nodes in proportion to the sum of all the spacers' grow
* factors (akin to CSS flew grow)
* @param grow The grow factor for this node. Default is 1
*/
static SpacerNodeChild* create(CCNode* child, size_t grow = 1);
void setContentSize(CCSize const& size) override;
};
#pragma warning(pop) #pragma warning(pop)
NS_CC_END NS_CC_END

View file

@ -271,7 +271,7 @@ public:
*/ */
inline const GLuint getProgram() { return m_uProgram; } inline const GLuint getProgram() { return m_uProgram; }
protected: private:
bool updateUniformLocation(GLint location, GLvoid* data, unsigned int bytes); bool updateUniformLocation(GLint location, GLvoid* data, unsigned int bytes);
const char* description(); const char* description();
bool compileShader(GLuint * shader, GLenum type, const GLchar* source); bool compileShader(GLuint * shader, GLenum type, const GLchar* source);

View file

@ -38,6 +38,7 @@ namespace geode {
Enable, Enable,
Disable, Disable,
Uninstall, Uninstall,
UninstallWithSaveData
}; };
GEODE_HIDDEN Mod* takeNextLoaderMod(); GEODE_HIDDEN Mod* takeNextLoaderMod();
@ -85,14 +86,14 @@ namespace geode {
ghc::filesystem::path getPackagePath() const; ghc::filesystem::path getPackagePath() const;
VersionInfo getVersion() const; VersionInfo getVersion() const;
bool isEnabled() const; bool isEnabled() const;
bool isLoaded() const; [[deprecated("use isEnabled instead")]] bool isLoaded() const;
bool supportsDisabling() const; bool supportsDisabling() const;
bool canDisable() const; [[deprecated("always true")]] bool canDisable() const;
bool canEnable() const; [[deprecated("always true")]] bool canEnable() const;
bool needsEarlyLoad() const; bool needsEarlyLoad() const;
[[deprecated]] bool supportsUnloading() const; [[deprecated("always false")]] bool supportsUnloading() const;
[[deprecated("use wasSuccessfullyLoaded instead")]] bool wasSuccesfullyLoaded() const; [[deprecated("use isEnabled instead")]] bool wasSuccesfullyLoaded() const;
bool wasSuccessfullyLoaded() const; [[deprecated("use isEnabled instead")]] bool wasSuccessfullyLoaded() const;
[[deprecated("use getMetadata instead")]] ModInfo getModInfo() const; [[deprecated("use getMetadata instead")]] ModInfo getModInfo() const;
ModMetadata getMetadata() const; ModMetadata getMetadata() const;
ghc::filesystem::path getTempDir() const; ghc::filesystem::path getTempDir() const;
@ -336,12 +337,20 @@ namespace geode {
*/ */
Result<> disable(); Result<> disable();
// TODO: in 2.0.0 make this use an optional arg instead
/** /**
* Disable this mod (if supported), then delete the mod's .geode package. * Delete the mod's .geode package.
* @returns Successful result on success, * @returns Successful result on success,
* errorful result with info on error * errorful result with info on error
*/ */
Result<> uninstall(); Result<> uninstall();
/**
* Delete the mod's .geode package.
* @param deleteSaveData Whether should also delete the mod's save data
* @returns Successful result on success,
* errorful result with info on error
*/
Result<> uninstall(bool deleteSaveData);
bool isUninstalled() const; bool isUninstalled() const;
ModRequestedAction getRequestedAction() const; ModRequestedAction getRequestedAction() const;

View file

@ -129,5 +129,7 @@ namespace geode::utils::clipboard {
} }
namespace geode::utils::game { namespace geode::utils::game {
GEODE_DLL void exit();
GEODE_DLL void restart(); GEODE_DLL void restart();
GEODE_DLL void launchLoaderUninstaller(bool deleteSaveData);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -177,7 +177,7 @@ struct AxisLayout::Row : public CCObject {
this->autorelease(); this->autorelease();
} }
void accountSpacers(Axis axis, float availableLength) { void accountSpacers(Axis axis, float availableLength, float crossLength) {
std::vector<SpacerNode*> spacers; std::vector<SpacerNode*> spacers;
for (auto& node : CCArrayExt<CCNode>(nodes)) { for (auto& node : CCArrayExt<CCNode>(nodes)) {
if (auto spacer = typeinfo_cast<SpacerNode*>(node)) { if (auto spacer = typeinfo_cast<SpacerNode*>(node)) {
@ -193,10 +193,10 @@ struct AxisLayout::Row : public CCObject {
for (auto& spacer : spacers) { for (auto& spacer : spacers) {
auto size = unusedSpace * spacer->getGrow() / static_cast<float>(sum); auto size = unusedSpace * spacer->getGrow() / static_cast<float>(sum);
if (axis == Axis::Row) { if (axis == Axis::Row) {
spacer->setContentSize({ size, this->crossLength }); spacer->setContentSize({ size, crossLength });
} }
else { else {
spacer->setContentSize({ this->crossLength, size }); spacer->setContentSize({ crossLength, size });
} }
} }
this->axisLength = availableLength; this->axisLength = availableLength;
@ -376,16 +376,16 @@ AxisLayout::Row* AxisLayout::fitInRow(
} }
// todo: make this calculation more smart to avoid so much unnecessary recursion // todo: make this calculation more smart to avoid so much unnecessary recursion
auto scaleDownFactor = scale - .0125f; auto scaleDownFactor = scale - .002f;
auto squishFactor = available.axisLength / (axisUnsquishedLength + .01f) * squish; auto squishFactor = available.axisLength / (axisUnsquishedLength + .01f) * squish;
// calculate row scale, squish, and prio // calculate row scale, squish, and prio
int tries = 1000; int tries = 1000;
while (axisLength > available.axisLength) { while (axisLength > available.axisLength) {
if (this->canTryScalingDown( if (this->canTryScalingDown(
res, prio, scale, scale - .0125f, minMaxPrios res, prio, scale, scale - .002f, minMaxPrios
)) { )) {
scale -= .0125f; scale -= .002f;
} }
else { else {
squish = available.axisLength / (axisUnsquishedLength + .01f) * squish; squish = available.axisLength / (axisUnsquishedLength + .01f) * squish;
@ -643,7 +643,7 @@ void AxisLayout::tryFitLayout(
float rowEvenSpace = available.crossLength / rows->count(); float rowEvenSpace = available.crossLength / rows->count();
for (auto row : CCArrayExt<Row*>(rows)) { for (auto row : CCArrayExt<Row*>(rows)) {
row->accountSpacers(m_axis, available.axisLength); row->accountSpacers(m_axis, available.axisLength, available.crossLength);
if (m_crossAlignment == AxisAlignment::Even) { if (m_crossAlignment == AxisAlignment::Even) {
rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2; rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2;
@ -1053,3 +1053,34 @@ void SpacerNode::setGrow(size_t grow) {
size_t SpacerNode::getGrow() const { size_t SpacerNode::getGrow() const {
return m_grow; return m_grow;
} }
bool SpacerNodeChild::init(CCNode* child, size_t grow) {
if (!SpacerNode::init(grow))
return false;
if (child) {
this->addChild(child);
m_child = child;
}
return true;
}
SpacerNodeChild* SpacerNodeChild::create(CCNode* child, size_t grow) {
auto ret = new SpacerNodeChild;
if (ret && ret->init(child, grow)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void SpacerNodeChild::setContentSize(CCSize const& size) {
CCNode::setContentSize(size);
if (m_child) {
m_child->setPosition(CCPointZero);
m_child->setContentSize(size);
m_child->setAnchorPoint(CCPointZero);
}
}

View file

@ -69,16 +69,19 @@ public:
#include <Geode/modify/CCNode.hpp> #include <Geode/modify/CCNode.hpp>
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> { struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
virtual CCObject* getUserObject() { virtual CCObject* getUserObject() {
if (static_cast<CCObject*>(this) == static_cast<CCObject*>(CCDirector::get())) { if (typeinfo_cast<CCNode*>(this)) {
return GeodeNodeMetadata::set(this)->m_userObject;
}
// apparently this function is the same as // apparently this function is the same as
// CCDirector::getNextScene so yeah // CCDirector::getNextScene so yeah
return m_pUserObject; return m_pUserObject;
} }
return GeodeNodeMetadata::set(this)->m_userObject;
}
virtual void setUserObject(CCObject* obj) { virtual void setUserObject(CCObject* obj) {
if (typeinfo_cast<CCNode*>(this)) {
GeodeNodeMetadata::set(this)->m_userObject = obj; GeodeNodeMetadata::set(this)->m_userObject = obj;
} }
m_pUserObject = obj;
}
}; };
static inline std::unordered_map<std::string, size_t> s_nextIndex; static inline std::unordered_map<std::string, size_t> s_nextIndex;

View file

@ -16,7 +16,7 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
void updateLoadedModsLabel() { void updateLoadedModsLabel() {
auto allMods = Loader::get()->getAllMods(); auto allMods = Loader::get()->getAllMods();
auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) { auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) {
return item->isLoaded(); return item->isEnabled();
}); });
auto str = fmt::format("Geode: Loaded {}/{} mods", count, allMods.size()); auto str = fmt::format("Geode: Loaded {}/{} mods", count, allMods.size());
m_fields->m_loadedModsLabel->setCString(str.c_str()); m_fields->m_loadedModsLabel->setCString(str.c_str());

View file

@ -208,14 +208,14 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
#ifdef GEODE_IS_DESKTOP #ifdef GEODE_IS_DESKTOP
(void) utils::file::createDirectoryAll(dirs::getGeodeDir() / "update" / "resources"); (void) utils::file::createDirectoryAll(dirs::getGeodeDir() / "update" / "resources" / "geode.loader");
createQuickPopup( createQuickPopup(
"Missing Textures", "Missing Textures",
"You appear to be missing textures, and the automatic texture fixer " "You appear to be missing textures, and the automatic texture fixer "
"hasn't fixed the issue.\n" "hasn't fixed the issue.\n"
"Download <cy>resources.zip</c> from the latest release on GitHub, " "Download <cy>resources.zip</c> from the latest release on GitHub, "
"and <cy>unzip its contents</c> into <cb>geode/update/resources</c>.\n" "and <cy>unzip its contents</c> into <cb>geode/update/resources/geode.loader</c>.\n"
"Afterwards, <cg>restart the game</c>.\n" "Afterwards, <cg>restart the game</c>.\n"
"You may also continue without installing resources, but be aware that " "You may also continue without installing resources, but be aware that "
"you won't be able to open <cr>the Geode menu</c>.", "you won't be able to open <cr>the Geode menu</c>.",

View file

@ -24,14 +24,13 @@ static void printGeodeInfo(std::stringstream& stream) {
static void printMods(std::stringstream& stream) { static void printMods(std::stringstream& stream) {
auto mods = Loader::get()->getAllMods(); auto mods = Loader::get()->getAllMods();
if (!mods.size()) { if (mods.empty()) {
stream << "<None>\n"; stream << "<None>\n";
} }
using namespace std::string_view_literals; using namespace std::string_view_literals;
for (auto& mod : mods) { for (auto& mod : mods) {
stream << fmt::format("{:>8} | {:>8} | [{}] {}\n", stream << fmt::format("{} | [{}] {}\n",
mod->isLoaded() ? "Loaded"sv : "Unloaded"sv, mod->isEnabled() ? "x"sv : " "sv,
mod->isEnabled() ? "Enabled"sv : "Disabled"sv,
mod->getVersion().toString(), mod->getID() mod->getVersion().toString(), mod->getID()
); );
} }

View file

@ -8,6 +8,8 @@
#include <hash/hash.hpp> #include <hash/hash.hpp>
#include <Geode/utils/JsonValidation.hpp> #include <Geode/utils/JsonValidation.hpp>
#include <thread>
#ifdef GEODE_IS_WINDOWS #ifdef GEODE_IS_WINDOWS
#include <filesystem> #include <filesystem>
#endif #endif
@ -318,19 +320,25 @@ void Index::Impl::downloadIndex() {
return; return;
} }
std::thread([=, this]() {
// unzip new index // unzip new index
auto unzip = file::Unzip::intoDir(targetFile, targetDir, true) auto unzip = file::Unzip::intoDir(targetFile, targetDir, true)
.expect("Unable to unzip new index"); .expect("Unable to unzip new index");
if (!unzip) { if (!unzip) {
Loader::get()->queueInMainThread([unzip] {
IndexUpdateEvent(UpdateFailed(unzip.unwrapErr())).post(); IndexUpdateEvent(UpdateFailed(unzip.unwrapErr())).post();
});
return; return;
} }
// remove the directory github adds to the root of the zip // remove the directory github adds to the root of the zip
(void)flattenGithubRepo(targetDir); (void)flattenGithubRepo(targetDir);
Loader::get()->queueInMainThread([this] {
// update index // update index
this->updateFromLocalTree(); this->updateFromLocalTree();
});
}).detach();
}) })
.expect([](std::string const& err) { .expect([](std::string const& err) {
IndexUpdateEvent(UpdateFailed(fmt::format("Error downloading: {}", err))).post(); IndexUpdateEvent(UpdateFailed(fmt::format("Error downloading: {}", err))).post();
@ -448,7 +456,8 @@ void Index::update(bool force) {
// update sources // update sources
if (force) { if (force) {
m_impl->downloadIndex(); m_impl->downloadIndex();
} else { }
else {
m_impl->checkForUpdates(); m_impl->checkForUpdates();
} }
} }

View file

@ -201,13 +201,13 @@ Mod* Loader::Impl::getInstalledMod(std::string const& id) const {
} }
bool Loader::Impl::isModLoaded(std::string const& id) const { bool Loader::Impl::isModLoaded(std::string const& id) const {
return m_mods.count(id) && m_mods.at(id)->isLoaded(); return m_mods.count(id) && m_mods.at(id)->isEnabled();
} }
Mod* Loader::Impl::getLoadedMod(std::string const& id) const { Mod* Loader::Impl::getLoadedMod(std::string const& id) const {
if (m_mods.count(id)) { if (m_mods.count(id)) {
auto mod = m_mods.at(id); auto mod = m_mods.at(id);
if (mod->isLoaded()) { if (mod->isEnabled()) {
return mod; return mod;
} }
} }
@ -225,8 +225,6 @@ void Loader::Impl::updateModResources(Mod* mod) {
if (mod->getMetadata().getSpritesheets().empty()) if (mod->getMetadata().getSpritesheets().empty())
return; return;
auto searchPath = mod->getResourcesDir();
log::debug("Adding resources for {}", mod->getID()); log::debug("Adding resources for {}", mod->getID());
// add spritesheets // add spritesheets
@ -402,7 +400,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
log::debug("{} {}", node->getID(), node->getVersion()); log::debug("{} {}", node->getID(), node->getVersion());
log::pushNest(); log::pushNest();
if (node->isLoaded()) { if (node->isEnabled()) {
for (auto const& dep : node->m_impl->m_dependants) { for (auto const& dep : node->m_impl->m_dependants) {
this->loadModGraph(dep, early); this->loadModGraph(dep, early);
} }
@ -438,7 +436,7 @@ void Loader::Impl::findProblems() {
log::pushNest(); log::pushNest();
for (auto const& dep : mod->getMetadata().getDependencies()) { for (auto const& dep : mod->getMetadata().getDependencies()) {
if (dep.mod && dep.mod->isLoaded() && dep.version.compare(dep.mod->getVersion())) if (dep.mod && dep.mod->isEnabled() && dep.version.compare(dep.mod->getVersion()))
continue; continue;
switch(dep.importance) { switch(dep.importance) {
case ModMetadata::Dependency::Importance::Suggested: case ModMetadata::Dependency::Importance::Suggested:
@ -493,19 +491,21 @@ void Loader::Impl::findProblems() {
Mod* myEpicMod = mod; // clang fix Mod* myEpicMod = mod; // clang fix
// if the mod is not loaded but there are no problems related to it // if the mod is not loaded but there are no problems related to it
// if (!mod->isLoaded() && !std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) { if (!mod->isEnabled() &&
// return std::holds_alternative<ModMetadata>(item.cause) && Mod::get()->getSavedValue<bool>("should-load-" + mod->getID(), true) &&
// std::get<ModMetadata>(item.cause).getID() == myEpicMod->getID() || !std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) {
// std::holds_alternative<Mod*>(item.cause) && return std::holds_alternative<ModMetadata>(item.cause) &&
// std::get<Mod*>(item.cause) == myEpicMod; std::get<ModMetadata>(item.cause).getID() == myEpicMod->getID() ||
// })) { std::holds_alternative<Mod*>(item.cause) &&
// m_problems.push_back({ std::get<Mod*>(item.cause) == myEpicMod;
// LoadProblem::Type::Unknown, })) {
// mod, m_problems.push_back({
// "" LoadProblem::Type::Unknown,
// }); mod,
// log::error("{} failed to load for an unknown reason", id); ""
// } });
log::error("{} failed to load for an unknown reason", id);
}
log::popNest(); log::popNest();
} }

View file

@ -47,7 +47,7 @@ bool Mod::isEnabled() const {
} }
bool Mod::isLoaded() const { bool Mod::isLoaded() const {
return m_impl->isLoaded(); return this->isEnabled();
} }
bool Mod::supportsDisabling() const { bool Mod::supportsDisabling() const {
@ -55,11 +55,11 @@ bool Mod::supportsDisabling() const {
} }
bool Mod::canDisable() const { bool Mod::canDisable() const {
return m_impl->canDisable(); return true;
} }
bool Mod::canEnable() const { bool Mod::canEnable() const {
return m_impl->canEnable(); return true;
} }
bool Mod::needsEarlyLoad() const { bool Mod::needsEarlyLoad() const {
@ -71,10 +71,10 @@ bool Mod::supportsUnloading() const {
} }
bool Mod::wasSuccesfullyLoaded() const { bool Mod::wasSuccesfullyLoaded() const {
return this->wasSuccessfullyLoaded(); return this->isEnabled();
} }
bool Mod::wasSuccessfullyLoaded() const { bool Mod::wasSuccessfullyLoaded() const {
return m_impl->wasSuccessfullyLoaded(); return this->isEnabled();
} }
ModInfo Mod::getModInfo() const { ModInfo Mod::getModInfo() const {
@ -191,7 +191,10 @@ Result<> Mod::disable() {
} }
Result<> Mod::uninstall() { Result<> Mod::uninstall() {
return m_impl->uninstall(); return m_impl->uninstall(false);
}
Result<> Mod::uninstall(bool deleteSaveData) {
return m_impl->uninstall(deleteSaveData);
} }
bool Mod::isUninstalled() const { bool Mod::isUninstalled() const {

View file

@ -42,8 +42,9 @@ Result<> Mod::Impl::setup() {
if (!loadRes) { if (!loadRes) {
log::warn("Unable to load data for \"{}\": {}", m_metadata.getID(), loadRes.unwrapErr()); log::warn("Unable to load data for \"{}\": {}", m_metadata.getID(), loadRes.unwrapErr());
} }
if (LoaderImpl::get()->m_isSetup) { if (!m_resourcesLoaded) {
Loader::get()->updateResources(false); LoaderImpl::get()->updateModResources(m_self);
m_resourcesLoaded = true;
} }
return Ok(); return Ok();
@ -112,22 +113,10 @@ bool Mod::Impl::isEnabled() const {
return m_enabled; return m_enabled;
} }
bool Mod::Impl::isLoaded() const {
return m_binaryLoaded;
}
bool Mod::Impl::supportsDisabling() const { bool Mod::Impl::supportsDisabling() const {
return m_metadata.getID() != "geode.loader"; return m_metadata.getID() != "geode.loader";
} }
bool Mod::Impl::canDisable() const {
return true;
}
bool Mod::Impl::canEnable() const {
return true;
}
bool Mod::Impl::needsEarlyLoad() const { bool Mod::Impl::needsEarlyLoad() const {
auto deps = m_dependants; auto deps = m_dependants;
return getMetadata().needsEarlyLoad() || return getMetadata().needsEarlyLoad() ||
@ -136,10 +125,6 @@ bool Mod::Impl::needsEarlyLoad() const {
}); });
} }
bool Mod::Impl::wasSuccessfullyLoaded() const {
return !this->isEnabled() || this->isLoaded();
}
std::vector<Hook*> Mod::Impl::getHooks() const { std::vector<Hook*> Mod::Impl::getHooks() const {
return m_hooks; return m_hooks;
} }
@ -321,7 +306,7 @@ bool Mod::Impl::hasSetting(std::string const& key) const {
Result<> Mod::Impl::loadBinary() { Result<> Mod::Impl::loadBinary() {
log::debug("Loading binary for mod {}", m_metadata.getID()); log::debug("Loading binary for mod {}", m_metadata.getID());
if (m_binaryLoaded) if (m_enabled)
return Ok(); return Ok();
LoaderImpl::get()->provideNextMod(m_self); LoaderImpl::get()->provideNextMod(m_self);
@ -333,7 +318,6 @@ Result<> Mod::Impl::loadBinary() {
log::error("Failed to load binary for mod {}: {}", m_metadata.getID(), res.unwrapErr()); log::error("Failed to load binary for mod {}: {}", m_metadata.getID(), res.unwrapErr());
return res; return res;
} }
m_binaryLoaded = true;
LoaderImpl::get()->releaseNextMod(); LoaderImpl::get()->releaseNextMod();
@ -393,12 +377,20 @@ Result<> Mod::Impl::disable() {
return Ok(); return Ok();
} }
Result<> Mod::Impl::uninstall() { Result<> Mod::Impl::uninstall(bool deleteSaveData) {
if (m_requestedAction != ModRequestedAction::None) { if (m_requestedAction != ModRequestedAction::None) {
return Err("Mod already has a requested action"); return Err("Mod already has a requested action");
} }
m_requestedAction = ModRequestedAction::Uninstall; if (this->getID() == "geode.loader") {
utils::game::launchLoaderUninstaller(deleteSaveData);
utils::game::exit();
return Ok();
}
m_requestedAction = deleteSaveData ?
ModRequestedAction::UninstallWithSaveData :
ModRequestedAction::Uninstall;
std::error_code ec; std::error_code ec;
ghc::filesystem::remove(m_metadata.getPath(), ec); ghc::filesystem::remove(m_metadata.getPath(), ec);
@ -408,11 +400,21 @@ Result<> Mod::Impl::uninstall() {
); );
} }
if (deleteSaveData) {
ghc::filesystem::remove_all(this->getSaveDir(), ec);
if (ec) {
return Err(
"Unable to delete mod's save directory: " + ec.message()
);
}
}
return Ok(); return Ok();
} }
bool Mod::Impl::isUninstalled() const { bool Mod::Impl::isUninstalled() const {
return m_requestedAction == ModRequestedAction::Uninstall; return m_requestedAction == ModRequestedAction::Uninstall ||
m_requestedAction == ModRequestedAction::UninstallWithSaveData;
} }
ModRequestedAction Mod::Impl::getRequestedAction() const { ModRequestedAction Mod::Impl::getRequestedAction() const {
@ -612,8 +614,9 @@ ModJson Mod::Impl::getRuntimeInfo() const {
for (auto patch : m_patches) { for (auto patch : m_patches) {
obj["patches"].as_array().push_back(ModJson(patch->getRuntimeInfo())); obj["patches"].as_array().push_back(ModJson(patch->getRuntimeInfo()));
} }
// TODO: so which one is it
// obj["enabled"] = m_enabled; // obj["enabled"] = m_enabled;
obj["loaded"] = m_binaryLoaded; obj["loaded"] = m_enabled;
obj["temp-dir"] = this->getTempDir(); obj["temp-dir"] = this->getTempDir();
obj["save-dir"] = this->getSaveDir(); obj["save-dir"] = this->getSaveDir();
obj["config-dir"] = this->getConfigDir(false); obj["config-dir"] = this->getConfigDir(false);
@ -660,7 +663,6 @@ Mod* Loader::Impl::createInternalMod() {
else { else {
mod = new Mod(infoRes.unwrap()); mod = new Mod(infoRes.unwrap());
} }
mod->m_impl->m_binaryLoaded = true;
mod->m_impl->m_enabled = true; mod->m_impl->m_enabled = true;
m_mods.insert({ mod->getID(), mod }); m_mods.insert({ mod->getID(), mod });
return mod; return mod;

View file

@ -26,10 +26,6 @@ namespace geode {
* Whether the mod is enabled or not * Whether the mod is enabled or not
*/ */
bool m_enabled = false; bool m_enabled = false;
/**
* Whether the mod binary is loaded or not
*/
bool m_binaryLoaded = false;
/** /**
* Mod temp directory name * Mod temp directory name
*/ */
@ -66,7 +62,6 @@ namespace geode {
bool m_loggingEnabled = true; bool m_loggingEnabled = true;
ModRequestedAction m_requestedAction = ModRequestedAction::None; ModRequestedAction m_requestedAction = ModRequestedAction::None;
Impl(Mod* self, ModMetadata const& metadata); Impl(Mod* self, ModMetadata const& metadata);
@ -88,12 +83,8 @@ namespace geode {
ghc::filesystem::path getPackagePath() const; ghc::filesystem::path getPackagePath() const;
VersionInfo getVersion() const; VersionInfo getVersion() const;
bool isEnabled() const; bool isEnabled() const;
bool isLoaded() const;
bool supportsDisabling() const; bool supportsDisabling() const;
bool canDisable() const;
bool canEnable() const;
bool needsEarlyLoad() const; bool needsEarlyLoad() const;
bool wasSuccessfullyLoaded() const;
ModMetadata getMetadata() const; ModMetadata getMetadata() const;
ghc::filesystem::path getTempDir() const; ghc::filesystem::path getTempDir() const;
ghc::filesystem::path getBinaryPath() const; ghc::filesystem::path getBinaryPath() const;
@ -127,7 +118,7 @@ namespace geode {
Result<> unpatch(Patch* patch); Result<> unpatch(Patch* patch);
Result<> enable(); Result<> enable();
Result<> disable(); Result<> disable();
Result<> uninstall(); Result<> uninstall(bool deleteSaveData);
bool isUninstalled() const; bool isUninstalled() const;
// 1.3.0 additions // 1.3.0 additions

View file

@ -15,7 +15,7 @@ ModInfo::Impl& ModInfoImpl::getImpl(ModInfo& info) {
bool Dependency::isResolved() const { bool Dependency::isResolved() const {
return !this->required || return !this->required ||
(this->mod && this->mod->isLoaded() && this->mod->isEnabled() && (this->mod && this->mod->isEnabled() &&
this->version.compare(this->mod->getVersion())); this->version.compare(this->mod->getVersion()));
} }

View file

@ -18,7 +18,7 @@ ModMetadata::Impl& ModMetadataImpl::getImpl(ModMetadata& info) {
bool ModMetadata::Dependency::isResolved() const { bool ModMetadata::Dependency::isResolved() const {
return this->importance != Importance::Required || return this->importance != Importance::Required ||
this->mod && this->mod->isLoaded() && this->version.compare(this->mod->getVersion()); this->mod && this->mod->isEnabled() && this->version.compare(this->mod->getVersion());
} }
bool ModMetadata::Incompatibility::isResolved() const { bool ModMetadata::Incompatibility::isResolved() const {

View file

@ -48,16 +48,17 @@ void Loader::Impl::openPlatformConsole() {
auto script = outFile + ".command"; auto script = outFile + ".command";
auto scriptContent = fmt::format(R"( auto scriptContent = fmt::format(R"(
#!/bin/sh #!/bin/sh
echo -n -e "\033]0;Geode Console\007" echo -n -e "\033]0;Geode Console {}\007"
tail -f {} & tail -f {} &
trap "" SIGINT trap "" SIGINT
while [ $(lsof -t {} 2>/dev/null | wc -l) -gt 1 ]; do :; done lsof -p {} +r 1 &>/dev/null
pkill -P $$
osascript -e 'tell application "Terminal" osascript -e 'tell application "Terminal"
close (every window whose name contains "Geode Console") close (every window whose name contains "Geode Console {}")
if (count windows) is 0 then quit if (count windows) is 0 then quit
end tell' & end tell' &
exit exit
)", outFile, outFile); )", getpid(), outFile, getpid(), getpid());
if (file::writeString(script, scriptContent)) { if (file::writeString(script, scriptContent)) {
chmod(script.c_str(), 0777); chmod(script.c_str(), 0777);

View file

@ -151,7 +151,7 @@ static Mod* modFromAddress(void const* addr) {
} }
for (auto& mod : Loader::get()->getAllMods()) { for (auto& mod : Loader::get()->getAllMods()) {
if (!mod->isLoaded() || !ghc::filesystem::exists(mod->getBinaryPath())) { if (!mod->isEnabled() || !ghc::filesystem::exists(mod->getBinaryPath())) {
continue; continue;
} }
if (ghc::filesystem::equivalent(imagePath, mod->getBinaryPath())) { if (ghc::filesystem::equivalent(imagePath, mod->getBinaryPath())) {

View file

@ -200,6 +200,30 @@ ghc::filesystem::path dirs::getSaveDir() {
return path; return path;
} }
void geode::utils::game::exit() {
if (CCApplication::sharedApplication() &&
(GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) {
log::error("Cannot restart in PlayLayer or LevelEditorLayer!");
return;
}
class Exit : public CCObject {
public:
void shutdown() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
[[[NSClassFromString(@"AppControllerManager") sharedInstance] controller] shutdownGame];
#pragma clang diagnostic pop
}
};
CCDirector::get()->getActionManager()->addAction(CCSequence::create(
CCDelayTime::create(0.5f),
CCCallFunc::create(nullptr, callfunc_selector(Exit::shutdown)),
nullptr
), CCDirector::get()->getRunningScene(), false);
}
void geode::utils::game::restart() { void geode::utils::game::restart() {
if (CCApplication::sharedApplication() && if (CCApplication::sharedApplication() &&
(GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) { (GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) {
@ -216,22 +240,12 @@ void geode::utils::game::restart() {
[task launch]; [task launch];
}; };
class Exit : public CCObject {
public:
void shutdown() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
[[[NSClassFromString(@"AppControllerManager") sharedInstance] controller] shutdownGame];
#pragma clang diagnostic pop
}
};
std::atexit(restart); std::atexit(restart);
CCDirector::get()->getActionManager()->addAction(CCSequence::create( exit();
CCDelayTime::create(0.5f), }
CCCallFunc::create(nullptr, callfunc_selector(Exit::shutdown)),
nullptr void geode::utils::game::launchLoaderUninstaller(bool deleteSaveData) {
), CCDirector::get()->getRunningScene(), false); log::error("Launching Geode uninstaller is not supported on macOS");
} }
Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) { Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) {

View file

@ -126,7 +126,7 @@ void Loader::Impl::setupIPC() {
if (ConnectNamedPipe(pipe, nullptr)) { if (ConnectNamedPipe(pipe, nullptr)) {
// log::debug("Got connection, creating thread"); // log::debug("Got connection, creating thread");
std::thread pipeThread(&ipcPipeThread, pipe); std::thread pipeThread(&ipcPipeThread, pipe);
SetThreadDescription(pipeThread.native_handle(), L"Geode IPC Pipe"); // SetThreadDescription(pipeThread.native_handle(), L"Geode IPC Pipe");
pipeThread.detach(); pipeThread.detach();
} }
else { else {
@ -135,7 +135,7 @@ void Loader::Impl::setupIPC() {
} }
} }
}); });
SetThreadDescription(ipcThread.native_handle(), L"Geode Main IPC"); // SetThreadDescription(ipcThread.native_handle(), L"Geode Main IPC");
ipcThread.detach(); ipcThread.detach();
log::debug("IPC set up"); log::debug("IPC set up");

View file

@ -158,6 +158,22 @@ ghc::filesystem::path dirs::getSaveDir() {
return path; return path;
} }
void geode::utils::game::exit() {
if (CCApplication::sharedApplication() &&
(GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) {
log::error("Cannot exit in PlayLayer or LevelEditorLayer!");
return;
}
if (CCApplication::sharedApplication())
// please forgive me..
// manually set the closed flag
// TODO: actually call glfwSetWindowShouldClose
*reinterpret_cast<bool*>(reinterpret_cast<uintptr_t>(CCEGLView::sharedOpenGLView()->getWindow()) + 0xa) = true;
else
std::exit(0);
}
void geode::utils::game::restart() { void geode::utils::game::restart() {
if (CCApplication::sharedApplication() && if (CCApplication::sharedApplication() &&
(GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) { (GameManager::get()->m_playLayer || GameManager::get()->m_levelEditorLayer)) {
@ -175,13 +191,25 @@ void geode::utils::game::restart() {
const auto updaterPath = (workingDir / "GeodeUpdater.exe").string(); const auto updaterPath = (workingDir / "GeodeUpdater.exe").string();
ShellExecuteA(nullptr, "open", updaterPath.c_str(), gdName.c_str(), workingDir.string().c_str(), false); ShellExecuteA(nullptr, "open", updaterPath.c_str(), gdName.c_str(), workingDir.string().c_str(), false);
if (CCApplication::sharedApplication()) exit();
// please forgive me.. }
// manually set the closed flag
// TODO: actually call glfwSetWindowShouldClose void geode::utils::game::launchLoaderUninstaller(bool deleteSaveData) {
*reinterpret_cast<bool*>(reinterpret_cast<uintptr_t>(CCEGLView::sharedOpenGLView()->getWindow()) + 0xa) = true; const auto workingDir = dirs::getGameDir();
else
exit(0); if (!exists((workingDir / "GeodeUninstaller.exe"))) {
log::error("Uninstaller not found! Not launching.");
return;
}
std::string params;
if (deleteSaveData) {
params = "\"/DATA=" + dirs::getSaveDir().string() + "\"";
}
// launch uninstaller
const auto uninstallerPath = (workingDir / "GeodeUninstaller.exe").string();
ShellExecuteA(nullptr, "open", uninstallerPath.c_str(), params.c_str(), workingDir.string().c_str(), false);
} }
Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) { Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) {

View file

@ -79,7 +79,13 @@ CCNode* geode::createModLogo(Mod* mod, CCSize const& size) {
if (!spr) spr = CCSprite::createWithSpriteFrameName("no-logo.png"_spr); if (!spr) spr = CCSprite::createWithSpriteFrameName("no-logo.png"_spr);
if (!spr) spr = CCLabelBMFont::create("N/A", "goldFont.fnt"); if (!spr) spr = CCLabelBMFont::create("N/A", "goldFont.fnt");
limitNodeSize(spr, size, 1.f, .1f); limitNodeSize(spr, size, 1.f, .1f);
return spr; spr->setPosition(size/2);
spr->setAnchorPoint({.5f, .5f});
auto node = CCNode::create();
node->addChild(spr);
node->setContentSize(size);
return node;
} }
CCNode* geode::createIndexItemLogo(IndexItemHandle item, CCSize const& size) { CCNode* geode::createIndexItemLogo(IndexItemHandle item, CCSize const& size) {
@ -112,5 +118,11 @@ CCNode* geode::createIndexItemLogo(IndexItemHandle item, CCSize const& size) {
else { else {
limitNodeSize(spr, size, 1.f, .1f); limitNodeSize(spr, size, 1.f, .1f);
} }
return spr; spr->setPosition(size/2);
spr->setAnchorPoint({.5f, .5f});
auto node = CCNode::create();
node->addChild(spr);
node->setContentSize(size);
return node;
} }

View file

@ -24,7 +24,7 @@
static constexpr int const TAG_CONFIRM_UNINSTALL = 5; static constexpr int const TAG_CONFIRM_UNINSTALL = 5;
static constexpr int const TAG_CONFIRM_UPDATE = 6; static constexpr int const TAG_CONFIRM_UPDATE = 6;
static constexpr int const TAG_DELETE_SAVEDATA = 7; static constexpr int const TAG_CONFIRM_UNINSTALL_WITH_SAVEDATA = 7;
static const CCSize LAYER_SIZE = {440.f, 290.f}; static const CCSize LAYER_SIZE = {440.f, 290.f};
bool ModInfoPopup::init(ModMetadata const& metadata, ModListLayer* list) { bool ModInfoPopup::init(ModMetadata const& metadata, ModListLayer* list) {
@ -434,7 +434,12 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) {
disableBtnSpr->setColor({150, 150, 150}); disableBtnSpr->setColor({150, 150, 150});
} }
if (mod != Mod::get()) { bool shouldShowUninstall = mod != Mod::get();
#if defined(GEODE_IS_WINDOWS)
shouldShowUninstall = shouldShowUninstall ||
exists((dirs::getGameDir() / "GeodeUninstaller.exe"));
#endif
if (shouldShowUninstall) {
auto uninstallBtnSpr = auto uninstallBtnSpr =
ButtonSprite::create("Uninstall", "bigFont.fnt", "GJ_button_05.png", .6f); ButtonSprite::create("Uninstall", "bigFont.fnt", "GJ_button_05.png", .6f);
uninstallBtnSpr->setScale(.6f); uninstallBtnSpr->setScale(.6f);
@ -552,10 +557,9 @@ void LocalModInfoPopup::onUpdateProgress(ModInstallEvent* event) {
this->setInstallStatus(std::nullopt); this->setInstallStatus(std::nullopt);
FLAlertLayer::create( FLAlertLayer::create(
"Update complete", "Update Complete",
"Mod successfully updated! :) " "Mod updated successfully!\n"
"(You have to <cy>restart the game</c> " "<cy>Restart</c> the game to apply changes.",
"for the mod to take effect)",
"OK" "OK"
)->show(); )->show();
@ -571,7 +575,7 @@ void LocalModInfoPopup::onUpdateProgress(ModInstallEvent* event) {
this->setInstallStatus(std::nullopt); this->setInstallStatus(std::nullopt);
FLAlertLayer::create( FLAlertLayer::create(
"Update failed :(", info, "OK" "Update Failed", info, "OK"
)->show(); )->show();
m_installBtn->setEnabled(true); m_installBtn->setEnabled(true);
@ -592,7 +596,10 @@ void LocalModInfoPopup::onUninstall(CCObject*) {
auto layer = FLAlertLayer::create( auto layer = FLAlertLayer::create(
this, this,
"Confirm Uninstall", "Confirm Uninstall",
fmt::format("Are you sure you want to uninstall <cr>{}</c>?", m_mod->getName()), fmt::format("Are you sure you want to uninstall <cr>{}</c>?{}", m_mod->getName(),
m_mod == Mod::get() ?
"\nThis will close the game and launch the <co>Geode Uninstaller</c>. "
"You will have to restart the game <cy>manually</c> after that." : ""),
"Cancel", "Cancel",
"OK" "OK"
); );
@ -601,13 +608,11 @@ void LocalModInfoPopup::onUninstall(CCObject*) {
} }
void LocalModInfoPopup::onEnableMod(CCObject* sender) { void LocalModInfoPopup::onEnableMod(CCObject* sender) {
if (!Mod::get()->setSavedValue("shown-disable-vs-unload-info", true)) { if (!Mod::get()->setSavedValue("shown-mod-toggle-info", true)) {
FLAlertLayer::create( FLAlertLayer::create(
"Notice", "Notice",
"<cb>Disabling</c> a <cy>mod</c> removes its hooks & patches and " "<cb>Toggling</c> a mod requires you to <cg>restart</c> the game.\n"
"calls its user-defined disable function if one exists. You may " "When a mod is <cr>disabled</c>, it will not get loaded at all.",
"still see some effects of the mod left however, and you may "
"need to <cg>restart</c> the game to have it fully unloaded.",
"OK" "OK"
)->show(); )->show();
} }
@ -651,18 +656,23 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) {
switch (layer->getTag()) { switch (layer->getTag()) {
case TAG_CONFIRM_UNINSTALL: { case TAG_CONFIRM_UNINSTALL: {
if (btn2) { if (btn2) {
this->doUninstall(); auto layer2 = FLAlertLayer::create(
this,
"Confirm Uninstall",
"Would you also like to <cr>delete</c> the mod's <co>save data</c>?",
"Keep",
"Delete",
350.f
);
layer2->setTag(TAG_CONFIRM_UNINSTALL_WITH_SAVEDATA);
layer2->show();
} }
} break; } break;
case TAG_DELETE_SAVEDATA: { case TAG_CONFIRM_UNINSTALL_WITH_SAVEDATA: {
if (btn2) { auto res = m_mod->uninstall(btn2);
if (ghc::filesystem::remove_all(m_mod->getSaveDir())) { if (!res) {
FLAlertLayer::create("Deleted", "The mod's save data was deleted.", "OK")->show(); return FLAlertLayer::create("Uninstall Failed", res.unwrapErr(), "OK")->show();
}
else {
FLAlertLayer::create("Error", "Unable to delete mod's save directory!", "OK")->show();
}
} }
if (m_layer) { if (m_layer) {
m_layer->reloadList(); m_layer->reloadList();
@ -672,27 +682,6 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) {
} }
} }
void LocalModInfoPopup::doUninstall() {
auto res = m_mod->uninstall();
if (!res) {
return FLAlertLayer::create("Uninstall failed :(", res.unwrapErr(), "OK")->show();
}
auto layer = FLAlertLayer::create(
this,
"Uninstall complete",
"Mod was successfully uninstalled! :) "
"(You have to <cy>restart the game</c> "
"for the mod to take effect). "
"<co>Would you also like to delete the mod's "
"save data?</c>",
"Keep",
"Delete",
350.f
);
layer->setTag(TAG_DELETE_SAVEDATA);
layer->show();
}
LocalModInfoPopup* LocalModInfoPopup::create(Mod* mod, ModListLayer* list) { LocalModInfoPopup* LocalModInfoPopup::create(Mod* mod, ModListLayer* list) {
auto ret = new LocalModInfoPopup; auto ret = new LocalModInfoPopup;
if (ret && ret->init(mod, list)) { if (ret && ret->init(mod, list)) {
@ -750,10 +739,9 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
this->setInstallStatus(std::nullopt); this->setInstallStatus(std::nullopt);
FLAlertLayer::create( FLAlertLayer::create(
"Install complete", "Install Complete",
"Mod successfully installed! :) " "Mod installed successfully!\n"
"(You have to <cy>restart the game</c> " "<cy>Restart</c> the game to apply changes.",
"for the mod to take effect)",
"OK" "OK"
)->show(); )->show();
@ -769,7 +757,7 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
this->setInstallStatus(std::nullopt); this->setInstallStatus(std::nullopt);
FLAlertLayer::create( FLAlertLayer::create(
"Installation failed :(", info, "OK" "Installation Failed", info, "OK"
)->show(); )->show();
m_installBtn->setEnabled(true); m_installBtn->setEnabled(true);

View file

@ -74,7 +74,6 @@ protected:
void onEnableMod(CCObject*); void onEnableMod(CCObject*);
void onUninstall(CCObject*); void onUninstall(CCObject*);
void onOpenConfigDir(CCObject*); void onOpenConfigDir(CCObject*);
void doUninstall();
void onUpdateProgress(ModInstallEvent* event); void onUpdateProgress(ModInstallEvent* event);
void onUpdate(CCObject*); void onUpdate(CCObject*);

Some files were not shown because too many files have changed in this diff Show more