Merge branch 'main' of https://github.com/geode-sdk/geode into main

This commit is contained in:
camila314 2023-02-22 14:17:25 -06:00
commit cdea5c00e8
15 changed files with 205 additions and 196 deletions

View file

@ -12,6 +12,14 @@ body:
- "Windows" - "Windows"
validations: validations:
required: true required: true
- type: input
id: commit
attributes:
label: SDK commit
description: The commit you used to compile your code with. If the bug is not related with your mod, you can leave this field empty.
placeholder: "Example: a674b97"
validations:
required: false
- type: input - type: input
id: version id: version
attributes: attributes:

View file

@ -54,6 +54,12 @@ include(cmake/GeodeFile.cmake)
include(cmake/Platform.cmake) include(cmake/Platform.cmake)
include(cmake/CPM.cmake) include(cmake/CPM.cmake)
# this is needed for cross compilation on linux,
# since fmtlib will fail to compile otherwise
if (GEODE_DISABLE_FMT_CONSTEVAL)
target_compile_definitions(${PROJECT_NAME} INTERFACE -DFMT_CONSTEVAL=)
endif()
CPMAddPackage("gh:geode-sdk/json#2b76460") CPMAddPackage("gh:geode-sdk/json#2b76460")
CPMAddPackage("gh:fmtlib/fmt#9.1.0") CPMAddPackage("gh:fmtlib/fmt#9.1.0")
CPMAddPackage("gh:gulrak/filesystem#3e5b930") CPMAddPackage("gh:gulrak/filesystem#3e5b930")
@ -77,8 +83,11 @@ set(GEODE_CODEGEN_BINARY_OUT ${CMAKE_CURRENT_BINARY_DIR}/codegen)
ExternalProject_Add(CodegenProject ExternalProject_Add(CodegenProject
BUILD_ALWAYS ON BUILD_ALWAYS ON
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/codegen SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/codegen
CMAKE_CACHE_ARGS "-DCMAKE_INSTALL_PREFIX:STRING=${GEODE_CODEGEN_BINARY_OUT}" # manually set configure command as to not inherit generator used by geode,
CMAKE_ARGS ${GEODE_CODEGEN_CMAKE_ARGS} # this should hopefully fix generator cache mismatch between different projects, however
# it causes a warning to be shown every time. if you know a better solution please tell us ok thx
CONFIGURE_COMMAND ${CMAKE_COMMAND} ${GEODE_CODEGEN_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:STRING=${GEODE_CODEGEN_BINARY_OUT} -S <SOURCE_DIR> -B <BINARY_DIR>
INSTALL_COMMAND ${CMAKE_COMMAND} --install <BINARY_DIR> --config $<CONFIGURATION>
) )

View file

@ -186,15 +186,13 @@ class ButtonSprite : cocos2d::CCSprite {
) = win 0x134b0, mac 0x4f1d0; ) = win 0x134b0, mac 0x4f1d0;
[[docs(" [[docs("
/** Create a ButtonSprite with a top sprite and a texture.
* Create a ButtonSprite with a top sprite and a texture. @param topSprite The top sprite to add on top of the sprite
* @param topSprite The top sprite to add on top of the sprite @param width Sprite width; ignored if `absolute` is false
* @param width Sprite width; ignored if `absolute` is false @param absolute Whether to use absolute width or not
* @param absolute Whether to use absolute width or not @param texture The name of the background sprite file (can't be in a spritesheet)
* @param texture The name of the background sprite file (can't be in a spritesheet) @param height The height of the button, leave 0 for automatic
* @param height The height of the button, leave 0 for automatic @param scale Scale of top sprite
* @param scale Scale of top sprite
*/
")]] ")]]
static ButtonSprite* create( static ButtonSprite* create(
cocos2d::CCSprite* topSprite, cocos2d::CCSprite* topSprite,
@ -208,26 +206,27 @@ class ButtonSprite : cocos2d::CCSprite {
} }
[[docs(" [[docs("
/** Create a ButtonSprite with text, a font and a texture.
* Create a ButtonSprite with text, a font and a texture. @param caption The text of the ButtonSprite
* @param caption The text of the ButtonSprite @param width Sprite width; ignored if `absolute` is false
* @param width Sprite width; ignored if `absolute` is false @param absolute Whether to use absolute width or not
* @param absolute Whether to use absolute width or not @param font The name of the BM font file to use
* @param font The name of the BM font file to use @param texture The name of the background sprite file (can't be in a spritesheet)
* @param texture The name of the background sprite file (can't be in a spritesheet) @param height The height of the button, leave 0 for automatic
* @param height The height of the button, leave 0 for automatic @param scale Scale of text
* @param scale Scale of text @returns Pointer to the created ButtonSprite, or nullptr on error
* @returns Pointer to the created ButtonSprite, or nullptr on error
*/
")]] ")]]
static ButtonSprite* create(const char* caption, int width, bool absolute, const char* font, const char* texture, float height, float scale) { static ButtonSprite* create(const char* caption, int width, bool absolute, const char* font, const char* texture, float height, float scale) {
return create(caption, width, 0, scale, absolute, font, texture, height); return create(caption, width, 0, scale, absolute, font, texture, height);
} }
inline static ButtonSprite* create(char const* caption) { static ButtonSprite* create(char const* caption) {
return ButtonSprite::create(caption, 0, 0, "goldFont.fnt", "GJ_button_01.png", .0f, 1.f); return ButtonSprite::create(caption, 0, 0, "goldFont.fnt", "GJ_button_01.png", .0f, 1.f);
} }
inline static ButtonSprite* create(char const* caption, const char* font, const char* texture, float scale = 1.f) { static ButtonSprite* create(char const* caption, const char* font, const char* texture) {
return ButtonSprite::create(caption, 0, 0, font, texture, .0f, 1.f);
}
static ButtonSprite* create(char const* caption, const char* font, const char* texture, float scale) {
return ButtonSprite::create(caption, 0, 0, font, texture, .0f, scale); return ButtonSprite::create(caption, 0, 0, font, texture, .0f, scale);
} }
static ButtonSprite* create(char const*, int, int, float, bool) = mac 0x4fa40; static ButtonSprite* create(char const*, int, int, float, bool) = mac 0x4fa40;
@ -1235,6 +1234,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void editObject2(cocos2d::CCObject* sender) = win 0x8d1b0; void editObject2(cocos2d::CCObject* sender) = win 0x8d1b0;
void editGroup(cocos2d::CCObject* sender) = win 0x8d720; void editGroup(cocos2d::CCObject* sender) = win 0x8d720;
void moveObjectCall(cocos2d::CCObject* sender) = mac 0x29830, win 0x8db30; void moveObjectCall(cocos2d::CCObject* sender) = mac 0x29830, win 0x8db30;
void moveObjectCall(EditCommand) = win 0x8db50;
void transformObjectCall(cocos2d::CCObject* sender) = mac 0x29860, win 0x8def0; void transformObjectCall(cocos2d::CCObject* sender) = mac 0x29860, win 0x8def0;
void onDelete(cocos2d::CCObject* sender) = mac 0x1b3d0, win 0x7b8d0; void onDelete(cocos2d::CCObject* sender) = mac 0x1b3d0, win 0x7b8d0;
void onDeleteSelected(cocos2d::CCObject* sender) = mac 0xb990, win 0x7bf50; void onDeleteSelected(cocos2d::CCObject* sender) = mac 0xb990, win 0x7bf50;
@ -1268,6 +1268,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void onUngroupSticky(cocos2d::CCObject* sender) = mac 0xc1d0, win 0x87ac0; void onUngroupSticky(cocos2d::CCObject* sender) = mac 0xc1d0, win 0x87ac0;
void onGoToLayer(cocos2d::CCObject* sender) = win 0x886b0; void onGoToLayer(cocos2d::CCObject* sender) = win 0x886b0;
void onGoToBaseLayer(cocos2d::CCObject* sender) = win 0x88790; void onGoToBaseLayer(cocos2d::CCObject* sender) = win 0x88790;
void onToggleGuide(cocos2d::CCObject* sender) = mac 0x19da0, win 0x79160;
void editColor(cocos2d::CCObject* sender) = mac 0x19190, win 0x8d3c0; void editColor(cocos2d::CCObject* sender) = mac 0x19190, win 0x8d3c0;
void alignObjects(cocos2d::CCArray* objs, bool alignY) = mac 0x2cea0, win 0x8f320; void alignObjects(cocos2d::CCArray* objs, bool alignY) = mac 0x2cea0, win 0x8f320;
virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884; virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;
@ -2590,7 +2591,7 @@ class GooglePlayDelegate {
class GooglePlayManager : cocos2d::CCNode { class GooglePlayManager : cocos2d::CCNode {
virtual bool init() = win 0x11070; virtual bool init() = win 0x11070;
static GooglePlayManager *sharedState() = win 0x4295a0; static GooglePlayManager* sharedState() = win 0x295a0;
} }
class GameLevelManager : cocos2d::CCNode { class GameLevelManager : cocos2d::CCNode {
@ -3763,7 +3764,7 @@ class LevelPage {
class LevelSearchLayer : cocos2d::CCLayer { class LevelSearchLayer : cocos2d::CCLayer {
static LevelSearchLayer* create() = win 0x17d9c0; static LevelSearchLayer* create() = win 0x17d9c0;
bool init() = mac 0x384770, win 0x17da60; virtual bool init() = mac 0x384770, win 0x17da60;
GJSearchObject* getSearchObject(SearchType, gd::string) = mac 0x388a50, win 0x1805f0; GJSearchObject* getSearchObject(SearchType, gd::string) = mac 0x388a50, win 0x1805f0;
void onMoreOptions(cocos2d::CCObject*) = win 0x17f500; void onMoreOptions(cocos2d::CCObject*) = win 0x17f500;
void onSearch(cocos2d::CCObject*) = win 0x180fc0; void onSearch(cocos2d::CCObject*) = win 0x180fc0;
@ -3931,7 +3932,7 @@ class MapPackCell : TableViewCell {
class MenuGameLayer { class MenuGameLayer {
void resetPlayer() = mac 0x28fdc0, win 0x18f4b0; void resetPlayer() = mac 0x28fdc0, win 0x18f4b0;
void destroyPlayer() = win 0x190100; void destroyPlayer() = win 0x190100;
void update(float) = mac 0x28fa70, win 0x18f190; virtual void update(float) = mac 0x28fa70, win 0x18f190;
virtual bool init() = win 0x18e770; virtual bool init() = win 0x18e770;
void updateColors() = win 0x18edd0; void updateColors() = win 0x18edd0;
} }
@ -3972,12 +3973,12 @@ class MessageListDelegate {}
class MoreSearchLayer : FLAlertLayer { class MoreSearchLayer : FLAlertLayer {
static MoreSearchLayer* create() = win 0x182520; static MoreSearchLayer* create() = win 0x182520;
bool init() = win 0x1825c0; virtual bool init() = win 0x1825c0;
} }
class MoreOptionsLayer { class MoreOptionsLayer {
static MoreOptionsLayer* create() = win 0x1de850; static MoreOptionsLayer* create() = win 0x1de850;
bool init() = mac 0x43f470, win 0x1DE8F0; virtual bool init() = mac 0x43f470, win 0x1DE8F0;
void addToggle(const char* name, const char* key, const char* info) = mac 0x440430, win 0x1df6b0; void addToggle(const char* name, const char* key, const char* info) = mac 0x440430, win 0x1df6b0;
void onKeybindings(cocos2d::CCObject* sender) = win 0x749d0; void onKeybindings(cocos2d::CCObject* sender) = win 0x749d0;
void onToggle(cocos2d::CCObject* sender) = mac 0x441370; void onToggle(cocos2d::CCObject* sender) = mac 0x441370;
@ -4127,7 +4128,7 @@ class PauseLayer : CCBlockLayer {
virtual void customSetup() = mac 0x20b300, win 0x1e4620; virtual void customSetup() = mac 0x20b300, win 0x1e4620;
void onRestart(cocos2d::CCObject* sender) = win 0x1e6040; void onRestart(cocos2d::CCObject* sender) = win 0x1e6040;
void keyDown(cocos2d::enumKeyCodes) = mac 0x20cc80, win 0x1E6580; virtual void keyDown(cocos2d::enumKeyCodes) = mac 0x20cc80, win 0x1E6580;
bool m_unknown; bool m_unknown;
bool m_unknown2; bool m_unknown2;

View file

@ -4,7 +4,7 @@ project(Codegen LANGUAGES C CXX)
include(../cmake/CPM.cmake) include(../cmake/CPM.cmake)
CPMAddPackage("gh:fmtlib/fmt#9.1.0") CPMAddPackage("gh:fmtlib/fmt#9.1.0")
CPMAddPackage("gh:camila314/Broma#1.0.0") CPMAddPackage("gh:geode-sdk/Broma#eb45fab")
file(GLOB SOURCES file(GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp

View file

@ -40,13 +40,18 @@ public:
char const* monostate_constructor_cutoff = R"GEN( GEODE_MONOSTATE_CONSTRUCTOR_CUTOFF({class_name}, {first_base}) char const* monostate_constructor_cutoff = R"GEN( GEODE_MONOSTATE_CONSTRUCTOR_CUTOFF({class_name}, {first_base})
)GEN"; )GEN";
char const* function_definition = R"GEN({docs} {static}{virtual}{return_type} {function_name}({parameters}){const}; char const* function_definition = R"GEN(
/**
{docs}{docs_addresses} */
{static}{virtual}{return_type} {function_name}({parameters}){const};
)GEN"; )GEN";
char const* error_definition = R"GEN( char const* error_definition = R"GEN(
#ifdef GEODE_WARN_INCORRECT_MEMBERS #ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Function is not implemented - will throw at runtime!!!")]] [[deprecated("Function is not implemented - will throw at runtime!!!")]]
#endif #endif
/**
{docs}{docs_addresses} */
{static}{return_type} {function_name}({parameters}){const}{{ {static}{return_type} {function_name}({parameters}){const}{{
throw std::runtime_error("Use of undefined function " + GEODE_PRETTY_FUNCTION); throw std::runtime_error("Use of undefined function " + GEODE_PRETTY_FUNCTION);
}} }}
@ -56,6 +61,8 @@ public:
#ifdef GEODE_WARN_INCORRECT_MEMBERS #ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Use of undefined virtual function - will crash at runtime!!!")]] [[deprecated("Use of undefined virtual function - will crash at runtime!!!")]]
#endif #endif
/**
{docs}{docs_addresses} */
{virtual}{return_type} {function_name}({parameters}){const}{{ {virtual}{return_type} {function_name}({parameters}){const}{{
#ifdef GEODE_NO_UNDEFINED_VIRTUALS #ifdef GEODE_NO_UNDEFINED_VIRTUALS
static_assert(false, "Undefined virtual function - implement in GeometryDash.bro"); static_assert(false, "Undefined virtual function - implement in GeometryDash.bro");
@ -68,10 +75,13 @@ public:
#ifdef GEODE_WARN_INCORRECT_MEMBERS #ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Member placed incorrectly - will crash at runtime!!!")]] [[deprecated("Member placed incorrectly - will crash at runtime!!!")]]
#endif #endif
)GEN"; )GEN";
char const* structor_definition = R"GEN( char const* structor_definition = R"GEN(
{function_name}({parameters});)GEN"; /**
{docs}{docs_addresses} */
{function_name}({parameters});
)GEN";
// requires: type, member_name, array // requires: type, member_name, array
char const* member_definition = R"GEN( {type} {member_name}; char const* member_definition = R"GEN( {type} {member_name};
@ -84,6 +94,52 @@ public:
)GEN"; )GEN";
}} }}
inline std::string nameForPlatform(Platform platform) {
switch (platform) {
case Platform::Mac: return "MacOS";
case Platform::Windows: return "Windows";
case Platform::iOS: return "iOS";
case Platform::Android: return "Android";
default: // unreachable
return "Windows";
}
}
std::string generateAddressDocs(Field const& field, FunctionBindField* fn) {
std::string ret;
for (auto platform : {Platform::Mac, Platform::Windows, Platform::iOS, Platform::Android}) {
auto status = codegen::getStatusWithPlatform(platform, field);
if (status == BindStatus::NeedsBinding) {
ret += fmt::format(" * @note[short] {}: 0x{:x}\n",
nameForPlatform(platform),
codegen::platformNumberWithPlatform(platform, fn->binds)
);
}
else if (status == BindStatus::Binded) {
ret += fmt::format(" * @note[short] {}\n",
nameForPlatform(platform)
);
}
}
return ret;
}
std::string generateDocs(std::string const& docs) {
if (docs.size() < 7) return "";
auto ret = docs.substr(1, docs.size() - 6); // i hate this but idk how to generalize
for (auto next = ret.find(" "); next != std::string::npos; next = ret.find(" ")) {
ret.replace(next, 8, " * ");
}
return ret;
}
std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singleFolder) { std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singleFolder) {
std::string output; std::string output;
@ -137,6 +193,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
FunctionBegin* fb; FunctionBegin* fb;
char const* used_format = format_strings::function_definition; char const* used_format = format_strings::function_definition;
std::string addressDocs;
if (auto i = field.get_as<InlineField>()) { if (auto i = field.get_as<InlineField>()) {
single_output += "\t" + i->inner + "\n"; single_output += "\t" + i->inner + "\n";
continue; continue;
@ -158,6 +216,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
continue; continue;
} else if (auto fn = field.get_as<OutOfLineField>()) { } else if (auto fn = field.get_as<OutOfLineField>()) {
fb = &fn->beginning; fb = &fn->beginning;
addressDocs = " * @note[short] Out of line\n";
} else if (auto fn = field.get_as<FunctionBindField>()) { } else if (auto fn = field.get_as<FunctionBindField>()) {
fb = &fn->beginning; fb = &fn->beginning;
@ -170,8 +230,12 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
if (fb->type != FunctionType::Normal) if (fb->type != FunctionType::Normal)
continue; continue;
} }
addressDocs = generateAddressDocs(field, fn);
} }
std::string docs = generateDocs(fb->docs);
single_output += fmt::format(used_format, single_output += fmt::format(used_format,
fmt::arg("virtual", str_if("virtual ", fb->is_virtual)), fmt::arg("virtual", str_if("virtual ", fb->is_virtual)),
fmt::arg("static", str_if("static ", fb->is_static)), fmt::arg("static", str_if("static ", fb->is_static)),
@ -181,7 +245,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
fmt::arg("index", field.field_id), fmt::arg("index", field.field_id),
fmt::arg("parameters", codegen::getParameters(*fb)), fmt::arg("parameters", codegen::getParameters(*fb)),
fmt::arg("return_type", fb->ret.name), fmt::arg("return_type", fb->ret.name),
fmt::arg("docs", fb->docs) fmt::arg("docs_addresses", addressDocs),
fmt::arg("docs", docs)
); );
} }

View file

@ -34,7 +34,7 @@ int main(int argc, char** argv) try {
writeFile(writeDir / "GeneratedAddress.cpp", generateAddressHeader(root)); writeFile(writeDir / "GeneratedAddress.cpp", generateAddressHeader(root));
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify")); writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify"));
// writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root)); // writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root));
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root)); // writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root));
writeFile(writeDir / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding")); writeFile(writeDir / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding"));
writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root)); writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root));
writeFile(writeDir / "GeneratedSource.cpp", generateBindingSource(root)); writeFile(writeDir / "GeneratedSource.cpp", generateBindingSource(root));

View file

@ -70,22 +70,26 @@ namespace codegen {
inline Platform platform; inline Platform platform;
inline uintptr_t platformNumber(PlatformNumber const& p) { inline uintptr_t platformNumberWithPlatform(Platform p, PlatformNumber const& pn) {
switch (codegen::platform) { switch (p) {
case Platform::Mac: return p.mac; case Platform::Mac: return pn.mac;
case Platform::Windows: return p.win; case Platform::Windows: return pn.win;
case Platform::iOS: return p.ios; case Platform::iOS: return pn.ios;
case Platform::Android: return p.android; case Platform::Android: return pn.android;
default: // unreachable default: // unreachable
return p.win; return pn.win;
} }
} }
inline BindStatus getStatus(Field const& field) { inline uintptr_t platformNumber(PlatformNumber const& p) {
return platformNumberWithPlatform(codegen::platform, p);
}
inline BindStatus getStatusWithPlatform(Platform p, Field const& field) {
FunctionBegin const* fb; FunctionBegin const* fb;
if (auto fn = field.get_as<FunctionBindField>()) { if (auto fn = field.get_as<FunctionBindField>()) {
if (platformNumber(fn->binds)) return BindStatus::NeedsBinding; if (platformNumberWithPlatform(p, fn->binds)) return BindStatus::NeedsBinding;
fb = &fn->beginning; fb = &fn->beginning;
} }
@ -96,7 +100,7 @@ namespace codegen {
// if (field.parent.rfind("GDString", 0) == 0) return BindStatus::NeedsBinding; // if (field.parent.rfind("GDString", 0) == 0) return BindStatus::NeedsBinding;
if (platform == Platform::Android) { if (p == Platform::Android) {
for (auto& [type, name] : fb->args) { for (auto& [type, name] : fb->args) {
if (type.name.find("gd::") != std::string::npos) return BindStatus::NeedsBinding; if (type.name.find("gd::") != std::string::npos) return BindStatus::NeedsBinding;
} }
@ -108,13 +112,17 @@ namespace codegen {
if (fb->type == FunctionType::Normal) { if (fb->type == FunctionType::Normal) {
if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded; if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded;
if (field.parent.rfind("cocos2d::", 0) == 0 && platform == Platform::Windows) if (field.parent.rfind("cocos2d::", 0) == 0 && p == Platform::Windows)
return BindStatus::Binded; return BindStatus::Binded;
} }
return BindStatus::Unbindable; return BindStatus::Unbindable;
} }
inline BindStatus getStatus(Field const& field) {
return getStatusWithPlatform(codegen::platform, field);
}
inline std::string getParameters(FunctionBegin const& f) { // int p0, float p1 inline std::string getParameters(FunctionBegin const& f) { // int p0, float p1
std::vector<std::string> parameters; std::vector<std::string> parameters;

View file

@ -1,96 +0,0 @@
#include "Shared.hpp"
#include "TypeOpt.hpp"
#include <set>
std::string generateTypeHeader(Root& root) {
std::string output;
TypeBank bank;
bank.loadFrom(root);
std::map<std::string, int> used_returns;
std::map<std::string, int> used_funcs;
std::map<std::string, int> used_pures;
int i = 0;
for (auto& f : bank.typeList()) {
char const* return_fmt = "using ret{index} = {return};";
char const* func_fmt;
char const* pure_fmt = "ret{ret_index}({parameter_types});";
char const* meta_fmt;
char const* member_fmt;
switch (f.type) {
case FuncType::Member:
func_fmt = "ret{ret_index}(*)( {const}{class_name}*{parameter_type_comma}{parameter_types});";
meta_fmt = "ret{ret_index}({const}{class_name}*{parameter_type_comma}{parameter_types});";
member_fmt = "ret{ret_index}({class_name}::*)({parameter_types}){const};";
break;
case FuncType::Static:
func_fmt = "ret{ret_index}(*)({parameter_types});";
meta_fmt = "ret{ret_index}({parameter_types});";
member_fmt = "func{index};";
break;
case FuncType::Structor:
func_fmt = "ret{ret_index}(*)({class_name}*{parameter_type_comma}{parameter_types});";
meta_fmt = "ret{ret_index}({const}{class_name}*{parameter_type_comma}{parameter_types});";
member_fmt = "func{index};";
break;
}
if (used_returns.count(f.return_type) == 0) {
output += fmt::format(return_fmt,
fmt::arg("index", i),
fmt::arg("return", f.return_type)
) + "\n";
used_returns[f.return_type] = i;
}
int ret_index = used_returns[f.return_type];
std::string pure_val = fmt::format(pure_fmt,
fmt::arg("ret_index", ret_index),
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", "))
);
if (used_pures.count(pure_val) == 0) {
output += fmt::format("using pure{} = {}\n", i, pure_val);
used_pures[pure_val] = i;
}
std::string func_val = fmt::format(func_fmt,
fmt::arg("ret_index", ret_index),
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
fmt::arg("parameter_type_comma", str_if(", ", !f.parameter_types.empty())),
fmt::arg("class_name", f.class_name),
fmt::arg("const", str_if(" const ", f.is_const))
);
std::string meta_val = fmt::format(meta_fmt,
fmt::arg("ret_index", ret_index),
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
fmt::arg("parameter_type_comma", str_if(", ", !f.parameter_types.empty())),
fmt::arg("class_name", f.class_name),
fmt::arg("const", str_if(" const ", f.is_const))
);
std::string member_val = fmt::format(member_fmt,
fmt::arg("ret_index", ret_index),
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
fmt::arg("class_name", f.class_name),
fmt::arg("const", str_if(" const ", f.is_const)),
fmt::arg("index", i)
);
if (used_funcs.count(func_val) == 0) {
output += fmt::format("using func{index} = {func}\nusing meta{index} = {meta}\nusing member{index} = {member}\n",
fmt::arg("index", i),
fmt::arg("func", func_val),
fmt::arg("meta", meta_val),
fmt::arg("member", member_val)
);
used_funcs[func_val] = i;
}
++i;
}
return output;
}

View file

@ -108,25 +108,19 @@ namespace geode {
class GEODE_DLL Logger { class GEODE_DLL Logger {
private: private:
static inline std::vector<Log> s_logs; static std::vector<Log>& logs();
static inline std::ofstream s_logStream; static std::ofstream& logStream();
Logger() = delete; Logger() = delete;
~Logger() = delete; ~Logger() = delete;
// logs // logs
static void _push(Log&& log);
public: public:
static void setup(); static void setup();
static inline void push(Log&& log) { static void push(Log&& log);
Logger::_push(std::move(log));
}
static inline void pop(Log* log) { static void pop(Log* log);
geode::utils::ranges::remove(Logger::s_logs, *log);
}
static std::vector<Log*> list(); static std::vector<Log*> list();
static void clear(); static void clear();

View file

@ -219,9 +219,9 @@ namespace geode {
using ColorAlphaSettingValue = GeodeSettingValue<ColorAlphaSetting>; using ColorAlphaSettingValue = GeodeSettingValue<ColorAlphaSetting>;
template<class T> template<class T>
struct SettingValueSetter { struct GEODE_DLL SettingValueSetter {
static GEODE_DLL T get(SettingValue* setting); static T get(SettingValue* setting);
static GEODE_DLL void set(SettingValue* setting, T const& value); static void set(SettingValue* setting, T const& value);
}; };
} }

View file

@ -106,7 +106,7 @@ namespace geode::modifier {
class ModifyDerive { class ModifyDerive {
public: public:
ModifyDerive() { ModifyDerive() {
static_assert(alwaysFalse<Derived>, "Custom Modify not implemented."); static_assert(alwaysFalse<Derived>, "Modified class not recognized, please include <Geode/modify/ClassName.hpp> to be able to use it.");
} }
}; };
} }

View file

@ -77,10 +77,10 @@ namespace geode::addresser {
} }
// I gave up // I gave up
template <HasCreate Class> // template <HasCreate Class>
static Class* generateInstance(Class*) { // static Class* generateInstance(Class*) {
return friendCreate<Class>(nullptr); // return friendCreate<Class>(nullptr);
} // }
// I extra gave up // I extra gave up
static cocos2d::extension::CCScrollView* generateInstance(cocos2d::extension::CCScrollView*) { static cocos2d::extension::CCScrollView* generateInstance(cocos2d::extension::CCScrollView*) {
@ -131,15 +131,7 @@ namespace geode::addresser {
// [[this + thunk] + offset] is the f we want // [[this + thunk] + offset] is the f we want
auto address = *(intptr_t*)(*(intptr_t*)(reference_cast<intptr_t>(ins) + thunk) + index); auto address = *(intptr_t*)(*(intptr_t*)(reference_cast<intptr_t>(ins) + thunk) + index);
#ifdef GEODE_IS_WINDOWS address = followThunkFunction(address);
// check if first instruction is a jmp, i.e. if the func is a thunk
if (*reinterpret_cast<uint16_t*>(address) == 0x25ff) {
// read where the jmp points to and jump there
address = *reinterpret_cast<uint32_t*>(address + 2);
// that then contains the actual address of the func
address = *reinterpret_cast<uintptr_t*>(address);
}
#endif
return address; return address;
} }
@ -171,14 +163,16 @@ namespace geode::addresser {
return addressOfNonVirtual(reinterpret_cast<R (T::*)(Ps...)>(func)); return addressOfNonVirtual(reinterpret_cast<R (T::*)(Ps...)>(func));
} }
static intptr_t followThunkFunction(intptr_t address);
template <typename R, typename T, typename... Ps> template <typename R, typename T, typename... Ps>
static intptr_t addressOfNonVirtual(R (T::*func)(Ps...)) { static intptr_t addressOfNonVirtual(R (T::*func)(Ps...)) {
return geode::cast::reference_cast<intptr_t>(func); return followThunkFunction(geode::cast::reference_cast<intptr_t>(func));
} }
template <typename R, typename... Ps> template <typename R, typename... Ps>
static intptr_t addressOfNonVirtual(R (*func)(Ps...)) { static intptr_t addressOfNonVirtual(R (*func)(Ps...)) {
return geode::cast::reference_cast<intptr_t>(func); return followThunkFunction(geode::cast::reference_cast<intptr_t>(func));
} }
template <typename T> template <typename T>

View file

@ -183,30 +183,43 @@ void Log::addFormat(std::string_view formatStr, std::span<ComponentTrait*> compo
// Logger // Logger
void Logger::setup() { std::vector<Log>& Logger::logs() {
s_logStream = std::ofstream(dirs::getGeodeLogDir() / log::generateLogName()); static std::vector<Log> logs;
return logs;
}
std::ofstream& Logger::logStream() {
static std::ofstream logStream;
return logStream;
} }
void Logger::_push(Log&& log) { void Logger::setup() {
logStream() = std::ofstream(dirs::getGeodeLogDir() / log::generateLogName());
}
void Logger::push(Log&& log) {
std::string logStr = log.toString(true); std::string logStr = log.toString(true);
LoaderImpl::get()->logConsoleMessage(logStr); LoaderImpl::get()->logConsoleMessage(logStr);
s_logStream << logStr << std::endl; logStream() << logStr << std::endl;
s_logs.emplace_back(std::forward<Log>(log)); logs().emplace_back(std::forward<Log>(log));
}
void Logger::pop(Log* log) {
geode::utils::ranges::remove(Logger::logs(), *log);
} }
std::vector<Log*> Logger::list() { std::vector<Log*> Logger::list() {
std::vector<Log*> logs; std::vector<Log*> logs_;
logs.reserve(s_logs.size()); logs_.reserve(logs().size());
for (auto& log : s_logs) { for (auto& log : logs()) {
logs.push_back(&log); logs_.push_back(&log);
} }
return logs; return logs_;
} }
void Logger::clear() { void Logger::clear() {
s_logs.clear(); logs().clear();
} }
// Misc // Misc

View file

@ -275,18 +275,6 @@ std::string SettingValue::getKey() const {
typename type_##Setting::ValueType const& value \ typename type_##Setting::ValueType const& value \
) const ) const
// instantiate value setters
namespace geode {
template struct SettingValueSetter<typename BoolSetting::ValueType>;
template struct SettingValueSetter<typename IntSetting::ValueType>;
template struct SettingValueSetter<typename FloatSetting::ValueType>;
template struct SettingValueSetter<typename StringSetting::ValueType>;
template struct SettingValueSetter<typename FileSetting::ValueType>;
template struct SettingValueSetter<typename ColorSetting::ValueType>;
template struct SettingValueSetter<typename ColorAlphaSetting::ValueType>;
}
// instantiate values // instantiate values
namespace geode { namespace geode {
@ -370,6 +358,18 @@ IMPL_NODE_AND_SETTERS(File);
IMPL_NODE_AND_SETTERS(Color); IMPL_NODE_AND_SETTERS(Color);
IMPL_NODE_AND_SETTERS(ColorAlpha); IMPL_NODE_AND_SETTERS(ColorAlpha);
// instantiate value setters
namespace geode {
template struct SettingValueSetter<typename BoolSetting::ValueType>;
template struct SettingValueSetter<typename IntSetting::ValueType>;
template struct SettingValueSetter<typename FloatSetting::ValueType>;
template struct SettingValueSetter<typename StringSetting::ValueType>;
template struct SettingValueSetter<typename FileSetting::ValueType>;
template struct SettingValueSetter<typename ColorSetting::ValueType>;
template struct SettingValueSetter<typename ColorAlphaSetting::ValueType>;
}
// SettingChangedEvent // SettingChangedEvent
SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value) SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value)

View file

@ -65,3 +65,16 @@ namespace {
Addresser::MultipleInheritance* Addresser::instance() { Addresser::MultipleInheritance* Addresser::instance() {
return reinterpret_cast<Addresser::MultipleInheritance*>(&TableTable::table); return reinterpret_cast<Addresser::MultipleInheritance*>(&TableTable::table);
} }
intptr_t Addresser::followThunkFunction(intptr_t address) {
#ifdef GEODE_IS_WINDOWS
// check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk
if (*reinterpret_cast<uint8_t*>(address) == 0xFF && *reinterpret_cast<uint8_t*>(address + 1) == 0x25) {
// read where the jmp reads from
address = *reinterpret_cast<uint32_t*>(address + 2);
// that then contains the actual address of the func
address = *reinterpret_cast<uintptr_t*>(address);
}
#endif
return address;
}