mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
Merge branch 'geode-sdk:main' into main
This commit is contained in:
commit
8f4e117325
24 changed files with 801 additions and 241 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -1,5 +1,28 @@
|
|||
# Geode Changelog
|
||||
|
||||
## v0.6.0
|
||||
|
||||
- Mod resource loading has been reworked again, with the intent of adding support for texture pack loaders
|
||||
- Added `Loader::addTexturePath` and `Loader::removeTexturePath` to work with additional resource paths
|
||||
- Mods that work with Cocos2d search paths directly should convert to using the above functions
|
||||
- New header `Geode/ui/LayerBG.hpp` with `createLayerBG` function for creating the blue gradient background GD layers have
|
||||
- All Cocos2d include paths have been changed to be relative
|
||||
- `cocos2dx` folder has been removed, cocos2d is now directly inside `Geode/cocos`
|
||||
- Loader resources updating will no longer check for plist file differences due to problems with CLI on Mac
|
||||
- More codegen optimizations, Geode mods should now compile faster
|
||||
- Added `NewResult` class, which will eventually replace the old `Result`
|
||||
- Add `deprecate` and `nodiscard` attributes to the old `Result` class
|
||||
- Many more bindings on Mac and Windows
|
||||
|
||||
## v0.5.0
|
||||
|
||||
- Added `CCFileUtils::get`
|
||||
- Fix crashes related to setting IDs in `MenuLayer`
|
||||
- Remove `Loader::updateModResourcePaths` and `Loader::updateResourcePaths`. The minimum mod target version is still v0.4.0 however, as you should never have been using these functions.
|
||||
- Rework how mod resources are added
|
||||
- Deprecate `geode::utils::vector` and `geode::utils::container` namespaces and replace them with `geode::utils::ranges`
|
||||
- Finally added a license to Geode! The framework is now licensed under BSL v1.0.
|
||||
|
||||
## v0.4.8
|
||||
|
||||
- CLI issues fixed in v1.0.6 so loader again verifies if loader resources are missing / corrupt on startup
|
||||
|
|
|
@ -39,14 +39,23 @@ target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp)
|
|||
|
||||
add_subdirectory(codegen)
|
||||
|
||||
add_custom_target(CodegenRun ALL
|
||||
message(STATUS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
add_custom_command(
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bindings/GeometryDash.bro
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bindings/Cocos2d.bro
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bindings/Entry.bro
|
||||
COMMAND Codegen ${GEODE_TARGET_PLATFORM} bindings ${GEODE_CODEGEN_PATH}
|
||||
COMMAND echo codegen > ${GEODE_CODEGEN_PATH}/.stamp
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Run Codegen"
|
||||
BYPRODUCTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp
|
||||
OUTPUT ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/.stamp
|
||||
)
|
||||
|
||||
add_custom_target(CodegenRun
|
||||
DEPENDS ${GEODE_CODEGEN_PATH}/.stamp
|
||||
)
|
||||
|
||||
add_dependencies(${PROJECT_NAME} CodegenRun)
|
||||
add_dependencies(CodegenRun Codegen)
|
||||
|
||||
# Hacky way to supress the not generated error
|
||||
if (NOT EXISTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.5.0
|
||||
0.6.0
|
|
@ -17,6 +17,7 @@ class AchievementManager : cocos2d::CCNode {
|
|||
PAD = win 0x4;
|
||||
}
|
||||
|
||||
|
||||
class AchievementNotifier : cocos2d::CCNode {
|
||||
void notifyAchievement(const char* title, const char* desc, const char* icon, bool quest) {
|
||||
m_queue->addObject(AchievementBar::create(title, desc, icon, quest));
|
||||
|
@ -1205,6 +1206,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
|
|||
void onGoToBaseLayer(cocos2d::CCObject* sender) = win 0x88790;
|
||||
void editColor(cocos2d::CCObject* sender) = mac 0x19190, win 0x8d3c0;
|
||||
void alignObjects(cocos2d::CCArray* objs, bool alignY) = win 0x8f320;
|
||||
virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;
|
||||
|
||||
EditButtonBar* m_buttonBar;
|
||||
PAD = mac 0x8, win 0x4;
|
||||
|
@ -3917,7 +3919,7 @@ class MenuGameLayer {
|
|||
void update(float) = mac 0x28fa70, win 0x18f190;
|
||||
}
|
||||
|
||||
class MenuLayer : cocos2d::CCLayer, FLAlertLayerProtocol {
|
||||
class MenuLayer : cocos2d::CCLayer, FLAlertLayerProtocol, GooglePlayDelegate {
|
||||
inline MenuLayer() {}
|
||||
virtual ~MenuLayer() = mac 0x1d1230, win 0x190620;
|
||||
virtual bool init() = mac 0x1d14b0, win 0x1907b0;
|
||||
|
@ -3942,6 +3944,11 @@ class MenuLayer : cocos2d::CCLayer, FLAlertLayerProtocol {
|
|||
void onYouTube(cocos2d::CCObject*) = win 0x1919A0;
|
||||
static cocos2d::CCScene* scene(bool) = mac 0x1d12d0, win 0x190720, ios 0x19e57c;
|
||||
MenuLayer* node() = win 0x190550;
|
||||
|
||||
cocos2d::CCSprite* m_googlePlaySprite;
|
||||
cocos2d::CCSprite* m_viewProfileInfoText;
|
||||
cocos2d::CCLabelBMFont* m_playerNameLabel;
|
||||
CCMenuItemSpriteExtra* m_profileBtn;
|
||||
}
|
||||
|
||||
class MessageListDelegate {}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
|
||||
namespace { namespace format_strings {
|
||||
|
||||
|
@ -14,6 +15,9 @@ GEODE_INLINE GEODE_HIDDEN static uintptr_t address{index}() {{
|
|||
std::string generateAddressHeader(Root& root) {
|
||||
std::string output;
|
||||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
|
||||
for (auto& field : c.fields) {
|
||||
|
@ -26,18 +30,16 @@ std::string generateAddressHeader(Root& root) {
|
|||
}
|
||||
|
||||
if (codegen::getStatus(field) == BindStatus::Binded) {
|
||||
const auto ids = bank.getIDs(fn->beginning, c.name);
|
||||
|
||||
address_str = fmt::format("addresser::get{}Virtual((types::member{})(&{}::{}))",
|
||||
str_if("Non", !fn->beginning.is_virtual),
|
||||
field.field_id,
|
||||
ids.member,
|
||||
field.parent,
|
||||
fn->beginning.name
|
||||
);
|
||||
|
||||
} else if (codegen::getStatus(field) == BindStatus::NeedsBinding) {
|
||||
|
||||
address_str = fmt::format("base::get() + 0x{:x}", codegen::platformNumber(fn->binds));
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ int main(int argc, char** argv) try {
|
|||
}
|
||||
|
||||
writeFile(writeDir / "GeneratedAddress.hpp", generateAddressHeader(root));
|
||||
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify")); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root)); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root)); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify"));
|
||||
writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root));
|
||||
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root));
|
||||
writeFile(writeDir / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding"));
|
||||
writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root));
|
||||
writeFile(writeDir / "GeneratedSource.cpp", generateBindingSource(root));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
|
@ -36,7 +37,7 @@ namespace geode::modifier {{
|
|||
|
||||
// requires: index, class_name, arg_types, function_name, raw_arg_types, non_virtual
|
||||
char const* apply_function = R"GEN(
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({index}, {function_convention}, {class_name}, {function_name}))GEN";
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({addr_index}, {pure_index}, {function_convention}, {class_name}, {function_name}))GEN";
|
||||
|
||||
char const* modify_end = R"GEN(
|
||||
}
|
||||
|
@ -52,6 +53,9 @@ namespace geode::modifier {{
|
|||
std::string generateModifyHeader(Root& root, ghc::filesystem::path const& singleFolder) {
|
||||
std::string output;
|
||||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
for (auto c : root.classes) {
|
||||
if (c.name == "cocos2d")
|
||||
continue;
|
||||
|
@ -104,7 +108,8 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
|
|||
}
|
||||
|
||||
single_output += fmt::format(format_strings::apply_function,
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("addr_index", f.field_id),
|
||||
fmt::arg("pure_index", bank.getPure(*begin, c.name)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("function_name", function_name),
|
||||
fmt::arg("function_convention", codegen::getConvention(f))
|
||||
|
|
|
@ -175,113 +175,4 @@ namespace codegen {
|
|||
if (index == std::string::npos) return s;
|
||||
return s.substr(index + 2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// defined : we have a symbol that is usable
|
||||
inline bool isFunctionDefined(Function const& f) {
|
||||
// basically this is true for
|
||||
// fmod for all platforms
|
||||
// cocos for windows
|
||||
// all funcs without stl parameter for android
|
||||
// destructors for no platforms
|
||||
if (f.function_type == kDestructor) return false;
|
||||
if (f.function_type == kConstructor) return false;
|
||||
if (f.parent_class->name.rfind("fmod::", 0) == 0) return true;
|
||||
if (f.parent_class->name.rfind("cocos2d::", 0) == 0 && codegen::platform == kWindows) return true;
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return false;
|
||||
if (codegen::platform == kAndroid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// definable : we can define it and hook it
|
||||
inline bool isFunctionDefinable(Function const& f) {
|
||||
// basically this is true for
|
||||
// all funcs that we have the offset for
|
||||
// all funcs with stl parameter for android
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return true;
|
||||
if (getBind(f) != "") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string getUnqualifiedClassName(Function const& f) {
|
||||
auto index = f.parent_class->name.rfind("::");
|
||||
if (index == std::string::npos) return f.parent_class->name;
|
||||
return f.parent_class->name.substr(index + 2);
|
||||
}
|
||||
|
||||
inline std::string getFunctionName(Function const& f) {
|
||||
return f.name;
|
||||
}
|
||||
|
||||
inline std::string getConst(Function const& f) {
|
||||
return f.is_const ? "const" : "";
|
||||
}
|
||||
|
||||
inline std::string getConstWhitespace(Function const& f) {
|
||||
return f.is_const ? " " : "";
|
||||
}
|
||||
|
||||
inline std::string getParameterTypes(Function const& f) { //int, float
|
||||
return fmt::format("{}", fmt::join(f.args, ", "));
|
||||
}
|
||||
|
||||
inline std::string getArguments(Function const& f) { // p0, p1
|
||||
return fmt::format("{}", fmt::join(f.argnames, ", "));
|
||||
}
|
||||
|
||||
inline std::string getParameterComma(Function const& f) { // int p0, float p1
|
||||
return f.args.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
inline std::string getParameterTypeComma(Function const& f) { //int, float
|
||||
return f.args.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
inline std::string getArgumentComma(Function const& f) { // p0, p1
|
||||
return f.argnames.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
// defined : we have a symbol that is usable
|
||||
inline bool isFunctionDefined(Function const& f) {
|
||||
// basically this is true for
|
||||
// fmod for all platforms
|
||||
// cocos for windows
|
||||
// all funcs without stl parameter for android
|
||||
// destructors for no platforms
|
||||
if (f.function_type == kDestructor) return false;
|
||||
if (f.function_type == kConstructor) return false;
|
||||
if (f.parent_class->name.rfind("fmod::", 0) == 0) return true;
|
||||
if (f.parent_class->name.rfind("cocos2d::", 0) == 0 && codegen::platform == kWindows) return true;
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return false;
|
||||
if (codegen::platform == kAndroid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// definable : we can define it and hook it
|
||||
inline bool isFunctionDefinable(Function const& f) {
|
||||
// basically this is true for
|
||||
// all funcs that we have the offset for
|
||||
// all funcs with stl parameter for android
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return true;
|
||||
if (getBind(f) != "") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string getConvention(Function const& f) {
|
||||
if (codegen::platform != kWindows) return "DefaultConv";
|
||||
switch (f.function_type) {
|
||||
case kConstructor: [[fallthrough]];
|
||||
case kDestructor: [[fallthrough]];
|
||||
case kRegularFunction:
|
||||
if (isFunctionDefined(f)) return "x86::Thiscall";
|
||||
return "x86::Membercall";
|
||||
case kVirtualFunction:
|
||||
return "x86::Thiscall";
|
||||
case kStaticFunction:
|
||||
if (isFunctionDefined(f)) return "x86::Cdecl";
|
||||
return "x86::Optcall";
|
||||
}
|
||||
return "x86::Membercall";
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
|
||||
namespace { namespace format_strings {
|
||||
char const* source_start = R"CAC(
|
||||
|
@ -16,23 +17,23 @@ using namespace geode::modifier; // types
|
|||
)CAC";
|
||||
|
||||
char const* declare_member = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_virtual = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto self = addresser::thunkAdjust((types::member{index})(&{class_name}::{function_name}), this);
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto self = addresser::thunkAdjust((types::member{member_index})(&{class_name}::{function_name}), this);
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func(self{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_static = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func({arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
@ -42,7 +43,7 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
// basically we destruct it once by calling the gd function,
|
||||
// then lock it, so that other gd destructors dont get called
|
||||
if (CCDestructor::lock(this)) return;
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
// we need to construct it back so that it uhhh ummm doesnt crash
|
||||
// while going to the child destructors
|
||||
|
@ -58,7 +59,7 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
// no crashes :pray:
|
||||
CCDestructor::lock(this) = true;
|
||||
{class_name}::~{unqualified_class_name}();
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
@ -75,6 +76,9 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
std::string generateBindingSource(Root& root) {
|
||||
std::string output(format_strings::source_start);
|
||||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
|
||||
for (auto& f : c.fields) {
|
||||
|
@ -100,7 +104,6 @@ std::string generateBindingSource(Root& root) {
|
|||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("definition", fn->inner)
|
||||
);
|
||||
break;
|
||||
|
@ -110,7 +113,6 @@ std::string generateBindingSource(Root& root) {
|
|||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("definition", fn->inner),
|
||||
fmt::arg("return", fn->beginning.ret.name)
|
||||
);
|
||||
|
@ -140,13 +142,18 @@ std::string generateBindingSource(Root& root) {
|
|||
if (fn->beginning.is_virtual && fn->beginning.type != FunctionType::Dtor)
|
||||
used_declare_format = format_strings::declare_virtual;
|
||||
|
||||
auto ids = bank.getIDs(fn->beginning, c.name);
|
||||
|
||||
output += fmt::format(used_declare_format,
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("unqualified_class_name", codegen::getUnqualifiedClassName(c.name)),
|
||||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("convention", codegen::getConvention(f)),
|
||||
fmt::arg("function_name", fn->beginning.name),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("meta_index", ids.meta),
|
||||
fmt::arg("member_index", ids.member),
|
||||
fmt::arg("ret_index", ids.ret),
|
||||
fmt::arg("addr_index", f.field_id),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("parameter_types", codegen::getParameterTypes(fn->beginning)),
|
||||
fmt::arg("arguments", codegen::getParameterNames(fn->beginning)),
|
||||
|
|
|
@ -1,84 +1,95 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
#include <set>
|
||||
|
||||
namespace { namespace format_strings {
|
||||
|
||||
char const* declare_member_type = R"GEN(
|
||||
using ret{index} = {return};
|
||||
using func{index} = ret{index}(*)({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using member{index} = ret{index}({class_name}::*)({parameter_types}){const};
|
||||
)GEN";
|
||||
|
||||
char const* declare_static_type = R"GEN(
|
||||
using ret{index} = {return};
|
||||
using func{index} = ret{index}(*)({parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({parameter_types});
|
||||
using member{index} = func{index};
|
||||
)GEN";
|
||||
|
||||
char const* declare_structor_type = R"GEN(
|
||||
using ret{index} = void;
|
||||
using func{index} = ret{index}(*)({class_name}*{parameter_type_comma}{parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using member{index} = func{index};
|
||||
)GEN";
|
||||
|
||||
}}
|
||||
|
||||
static std::string getReturn(FunctionBegin const& fn, std::string const& parent) {
|
||||
if (fn.type != FunctionType::Normal)
|
||||
return "void";
|
||||
|
||||
if (fn.ret.name == "auto") {
|
||||
std::vector<std::string> declvals;
|
||||
|
||||
for (auto& [t, n] : fn.args) {
|
||||
declvals.push_back(fmt::format("std::declval<{}>()", t.name));
|
||||
}
|
||||
|
||||
return fmt::format(
|
||||
fn.is_static ? "decltype({}::{}({}))" : "decltype(std::declval<{}>().{}({}))",
|
||||
parent,
|
||||
fn.name,
|
||||
fmt::join(declvals, ", ")
|
||||
);
|
||||
}
|
||||
|
||||
return fn.ret.name;
|
||||
}
|
||||
|
||||
std::string generateTypeHeader(Root& root) {
|
||||
std::string output;
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
for (auto& f : c.fields) {
|
||||
if (codegen::getStatus(f) == BindStatus::Unbindable)
|
||||
continue;
|
||||
auto fn = f.get_fn();
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
char const* used_format = format_strings::declare_member_type;
|
||||
std::map<std::string, int> used_returns;
|
||||
std::map<std::string, int> used_funcs;
|
||||
std::map<std::string, int> used_pures;
|
||||
|
||||
if (fn->type != FunctionType::Normal) {
|
||||
used_format = format_strings::declare_structor_type;
|
||||
}
|
||||
int i = 0;
|
||||
for (auto& f : bank.typeList()) {
|
||||
|
||||
if (fn->is_static) {
|
||||
used_format = format_strings::declare_static_type;
|
||||
}
|
||||
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;
|
||||
|
||||
output += fmt::format(used_format,
|
||||
fmt::arg("parameter_types", codegen::getParameterTypes(*fn)),
|
||||
fmt::arg("parameter_type_comma", str_if(", ", !fn->args.empty())),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("const", str_if(" const ", fn->is_const)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("return", getReturn(*fn, c.name))
|
||||
);
|
||||
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;
|
||||
|
|
180
codegen/src/TypeOpt.hpp
Normal file
180
codegen/src/TypeOpt.hpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
#include "Shared.hpp"
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
enum class FuncType : int {
|
||||
Structor,
|
||||
Static,
|
||||
Member
|
||||
};
|
||||
struct Func {
|
||||
std::string return_type;
|
||||
bool is_const;
|
||||
std::string class_name;
|
||||
std::vector<std::string> parameter_types;
|
||||
FuncType type;
|
||||
|
||||
std::string toStr() const {
|
||||
return fmt::format("{}{}{}{}{}",
|
||||
return_type,
|
||||
class_name,
|
||||
fmt::join(parameter_types, ","),
|
||||
is_const ? " const " : "",
|
||||
static_cast<int>(type)
|
||||
);
|
||||
}
|
||||
|
||||
bool operator<(Func const& f) const {
|
||||
return toStr() < f.toStr();
|
||||
}
|
||||
|
||||
bool operator==(Func const& f) const {
|
||||
return (
|
||||
return_type == f.return_type &&
|
||||
is_const == f.is_const &&
|
||||
class_name == f.class_name &&
|
||||
parameter_types == f.parameter_types &&
|
||||
type == f.type
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct Ids {
|
||||
int ret = -1;
|
||||
int func = -1;
|
||||
int pure = -1;
|
||||
int meta = -1;
|
||||
int member = -1;
|
||||
};
|
||||
|
||||
class TypeBank {
|
||||
std::vector<Func> m_stuff;
|
||||
public:
|
||||
static std::string getReturn(FunctionBegin const& fn, std::string const& parent) {
|
||||
if (fn.type != FunctionType::Normal)
|
||||
return "void";
|
||||
|
||||
if (fn.ret.name == "auto") {
|
||||
std::vector<std::string> declvals;
|
||||
|
||||
for (auto& [t, n] : fn.args) {
|
||||
declvals.push_back(fmt::format("std::declval<{}>()", t.name));
|
||||
}
|
||||
|
||||
return fmt::format(
|
||||
fn.is_static ? "decltype({}::{}({}))" : "decltype(std::declval<{}>().{}({}))",
|
||||
parent,
|
||||
fn.name,
|
||||
fmt::join(declvals, ", ")
|
||||
);
|
||||
}
|
||||
|
||||
return fn.ret.name;
|
||||
}
|
||||
|
||||
static Func makeFunc(FunctionBegin const& fn, std::string const& parent) {
|
||||
Func f;
|
||||
f.return_type = TypeBank::getReturn(fn, parent);
|
||||
f.is_const = fn.is_const;
|
||||
f.class_name = parent;
|
||||
|
||||
for (auto& arg : fn.args) {
|
||||
f.parameter_types.push_back(arg.first.name);
|
||||
}
|
||||
|
||||
if (fn.is_static)
|
||||
f.type = FuncType::Static;
|
||||
else if (fn.type != FunctionType::Normal)
|
||||
f.type = FuncType::Structor;
|
||||
else
|
||||
f.type = FuncType::Member;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void loadFrom(Root& root) {
|
||||
for (auto& c : root.classes) {
|
||||
for (auto& f : c.fields) {
|
||||
if (codegen::getStatus(f) == BindStatus::Unbindable)
|
||||
continue;
|
||||
|
||||
m_stuff.push_back(TypeBank::makeFunc(*f.get_fn(), c.name));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(m_stuff.begin(), m_stuff.end());
|
||||
m_stuff.erase(std::unique(m_stuff.begin(), m_stuff.end()), m_stuff.end());
|
||||
}
|
||||
|
||||
std::vector<Func> const& typeList() { return m_stuff; }
|
||||
|
||||
Ids getIDs(FunctionBegin const& fn, std::string const& parent) {
|
||||
Ids out;
|
||||
Func in_f = TypeBank::makeFunc(fn, parent);
|
||||
|
||||
int i = 0;
|
||||
for (auto f : m_stuff) {
|
||||
if (out.ret == -1 && f.return_type == in_f.return_type) {
|
||||
out.ret = i;
|
||||
}
|
||||
|
||||
if (out.func == -1) {
|
||||
if (in_f.type == FuncType::Member) {
|
||||
if (f == in_f) out.func = i;
|
||||
} else if (in_f.type == FuncType::Structor) {
|
||||
if (
|
||||
f.return_type == in_f.return_type &&
|
||||
f.class_name == in_f.class_name &&
|
||||
f.is_const == in_f.is_const &&
|
||||
f.parameter_types == in_f.parameter_types
|
||||
) out.func = i;
|
||||
} else {
|
||||
if (
|
||||
f.return_type == in_f.return_type &&
|
||||
f.parameter_types == in_f.parameter_types &&
|
||||
f.type == in_f.type
|
||||
) out.func = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.meta == -1 || out.member == -1) {
|
||||
Func assume_member = f;
|
||||
assume_member.type = FuncType::Member;
|
||||
|
||||
if (in_f == assume_member) {
|
||||
out.meta = i;
|
||||
} else if (out.func != -1) {
|
||||
out.meta = out.func;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.pure == -1 && f.return_type == in_f.return_type && f.parameter_types == in_f.parameter_types) {
|
||||
out.pure = i;
|
||||
}
|
||||
|
||||
if (out.ret != -1 && out.func != -1 && out.pure != -1)
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
out.member = out.func;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int getPure(FunctionBegin const& fn, std::string const& parent) {
|
||||
Func in_f = TypeBank::makeFunc(fn, parent);
|
||||
|
||||
int i = 0;
|
||||
for (auto f : m_stuff) {
|
||||
if (f.return_type == in_f.return_type && f.parameter_types == in_f.parameter_types) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -173,14 +173,14 @@ typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
|
|||
typedef void (CCObject::*SEL_EventHandler)(CCEvent*);
|
||||
typedef int (CCObject::*SEL_Compare)(CCObject*);
|
||||
|
||||
#define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR)
|
||||
#define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR)
|
||||
#define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR)
|
||||
#define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR)
|
||||
#define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR)
|
||||
#define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR)
|
||||
#define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR)
|
||||
#define compare_selector(_SELECTOR) (SEL_Compare)(&_SELECTOR)
|
||||
#define schedule_selector(_SELECTOR) (cocos2d::SEL_SCHEDULE)(&_SELECTOR)
|
||||
#define callfunc_selector(_SELECTOR) (cocos2d::SEL_CallFunc)(&_SELECTOR)
|
||||
#define callfuncN_selector(_SELECTOR) (cocos2d::SEL_CallFuncN)(&_SELECTOR)
|
||||
#define callfuncND_selector(_SELECTOR) (cocos2d::SEL_CallFuncND)(&_SELECTOR)
|
||||
#define callfuncO_selector(_SELECTOR) (cocos2d::SEL_CallFuncO)(&_SELECTOR)
|
||||
#define menu_selector(_SELECTOR) (cocos2d::SEL_MenuHandler)(&_SELECTOR)
|
||||
#define event_selector(_SELECTOR) (cocos2d::SEL_EventHandler)(&_SELECTOR)
|
||||
#define compare_selector(_SELECTOR) (cocos2d::SEL_Compare)(&_SELECTOR)
|
||||
|
||||
// end of base_nodes group
|
||||
/// @}
|
||||
|
|
|
@ -175,13 +175,13 @@ namespace geode {
|
|||
void setValue(ValueType const& value) {
|
||||
m_value = value;
|
||||
if constexpr (std::is_base_of_v<IMinMax<ValueType>, Class>) {
|
||||
static_cast<Class*>(this)->constrainMinMax(m_value);
|
||||
(void)static_cast<Class*>(this)->constrainMinMax(m_value);
|
||||
}
|
||||
if constexpr (std::is_base_of_v<IOneOf<Class, ValueType>, Class>) {
|
||||
static_cast<Class*>(this)->constrainOneOf(m_value);
|
||||
(void)static_cast<Class*>(this)->constrainOneOf(m_value);
|
||||
}
|
||||
if constexpr (std::is_base_of_v<IMatch<Class, ValueType>, Class>) {
|
||||
static_cast<Class*>(this)->constrainMatch(m_value);
|
||||
(void)static_cast<Class*>(this)->constrainMatch(m_value);
|
||||
}
|
||||
this->valueChanged();
|
||||
}
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
#include <Geode/loader/Mod.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(index, convention, className, functionName) \
|
||||
using base##index = wrap::functionName<Base, types::pure##index>; \
|
||||
using derived##index = wrap::functionName<Derived, types::pure##index>; \
|
||||
if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (void*)derived##index::uuid) { \
|
||||
Mod::get()->addHook<derived##index::value, convention>( \
|
||||
#className "::" #functionName, \
|
||||
(void*)addresses::address##index() \
|
||||
); \
|
||||
} \
|
||||
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(addr_index, pure_index, convention, className, functionName) \
|
||||
if constexpr ( \
|
||||
wrap::functionName<Derived, types::pure##pure_index>::uuid != nullptr && \
|
||||
(void*)wrap::functionName<Base, types::pure##pure_index>::uuid != (void*)wrap::functionName<Derived, types::pure##pure_index>::uuid \
|
||||
) { \
|
||||
(void)Mod::get()->addHook<wrap::functionName<Derived, types::pure##pure_index>::value, convention>( \
|
||||
#className "::" #functionName, \
|
||||
(void*)addresses::address##addr_index() \
|
||||
); \
|
||||
} \
|
||||
|
||||
|
||||
namespace geode::modifier {
|
||||
|
|
315
loader/include/Geode/utils/NewResult.hpp
Normal file
315
loader/include/Geode/utils/NewResult.hpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#pragma once
|
||||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace geode {
|
||||
namespace {
|
||||
struct AnyType {
|
||||
explicit AnyType() = delete;
|
||||
};
|
||||
|
||||
template<class V, class RV>
|
||||
concept ConvertibleToResult =
|
||||
std::is_convertible_v<
|
||||
std::remove_reference_t<V>,
|
||||
std::remove_reference_t<RV>
|
||||
> || std::is_same_v<
|
||||
std::remove_reference_t<V>,
|
||||
std::remove_reference_t<RV>
|
||||
>;
|
||||
|
||||
using DefaultValue = std::monostate;
|
||||
using DefaultError = std::string;
|
||||
}
|
||||
|
||||
template<class T = DefaultValue, class E = DefaultError>
|
||||
class [[nodiscard]] NewResult {
|
||||
public:
|
||||
using value_type = std::remove_reference_t<T>;
|
||||
using error_type = std::remove_reference_t<E>;
|
||||
|
||||
// for some reason doing requires causes errors with pch...
|
||||
static_assert(
|
||||
std::is_copy_constructible_v<value_type> ||
|
||||
std::is_move_constructible_v<value_type>,
|
||||
"T must be copiable or movable!"
|
||||
);
|
||||
static_assert(
|
||||
std::is_copy_constructible_v<error_type> ||
|
||||
std::is_move_constructible_v<error_type>,
|
||||
"E must be copiable or movable!"
|
||||
);
|
||||
|
||||
protected:
|
||||
std::variant<value_type, error_type> m_value;
|
||||
|
||||
public:
|
||||
bool isOk() const {
|
||||
return std::holds_alternative<value_type>(m_value);
|
||||
}
|
||||
|
||||
bool isErr() const {
|
||||
return std::holds_alternative<error_type>(m_value);
|
||||
}
|
||||
|
||||
explicit NewResult(value_type const& value)
|
||||
requires std::is_copy_constructible_v<value_type>
|
||||
: m_value(value) {}
|
||||
explicit NewResult(value_type&& value)
|
||||
requires std::is_move_constructible_v<value_type>
|
||||
: m_value(std::forward<value_type>(value)) {}
|
||||
|
||||
explicit NewResult(error_type const& value)
|
||||
requires std::is_copy_constructible_v<error_type>
|
||||
: m_value(value) {}
|
||||
explicit NewResult(error_type&& value)
|
||||
requires std::is_move_constructible_v<error_type>
|
||||
: m_value(std::forward<error_type>(value)) {}
|
||||
|
||||
NewResult(NewResult<T, E> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
= default;
|
||||
|
||||
NewResult(NewResult<T, E>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
) = default;
|
||||
|
||||
template<class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E>
|
||||
NewResult(NewResult<T2, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
|
||||
|
||||
template<class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E>
|
||||
NewResult(NewResult<T2, E2>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
) : m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
|
||||
|
||||
template<class T2>
|
||||
requires ConvertibleToResult<T2, T>
|
||||
NewResult(NewResult<T2, AnyType> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: NewResult(value_type(other.unwrap())) {}
|
||||
|
||||
template<class E2>
|
||||
requires ConvertibleToResult<E2, E>
|
||||
NewResult(NewResult<AnyType, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: m_value(std::forward<E2>(other.unwrapErr())) {}
|
||||
|
||||
template<class T2>
|
||||
requires ConvertibleToResult<T2, T>
|
||||
NewResult(NewResult<T2, AnyType>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
) : m_value(other.unwrap()) {}
|
||||
|
||||
template<class E2>
|
||||
requires ConvertibleToResult<E2, E>
|
||||
NewResult(NewResult<AnyType, E2>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
) : NewResult(std::forward<error_type>(other.unwrapErr())) {}
|
||||
|
||||
value_type unwrap() const
|
||||
requires std::is_copy_constructible_v<value_type>
|
||||
{
|
||||
return std::get<value_type>(m_value);
|
||||
}
|
||||
|
||||
value_type&& unwrap()
|
||||
requires (!std::is_copy_constructible_v<value_type>)
|
||||
{
|
||||
return std::move(std::get<value_type>(m_value));
|
||||
}
|
||||
|
||||
error_type unwrapErr() const
|
||||
requires std::is_copy_constructible_v<error_type>
|
||||
{
|
||||
return std::get<error_type>(m_value);
|
||||
}
|
||||
|
||||
error_type&& unwrapErr()
|
||||
requires (!std::is_copy_constructible_v<error_type>)
|
||||
{
|
||||
return std::move(std::get<error_type>(m_value));
|
||||
}
|
||||
|
||||
explicit operator bool() const requires (
|
||||
!std::is_same_v<T, bool> &&
|
||||
!std::is_same_v<E, bool>
|
||||
) {
|
||||
return this->isOk();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class [[nodiscard]] NewResult<T, T> {
|
||||
public:
|
||||
using value_type = std::remove_reference_t<T>;
|
||||
using error_type = std::remove_reference_t<T>;
|
||||
|
||||
// for some reason doing requires causes errors with pch...
|
||||
static_assert(
|
||||
std::is_copy_constructible_v<value_type> ||
|
||||
std::is_move_constructible_v<value_type>,
|
||||
"T must be copiable or movable!"
|
||||
);
|
||||
|
||||
protected:
|
||||
bool m_success;
|
||||
value_type m_value;
|
||||
|
||||
public:
|
||||
bool isOk() const {
|
||||
return m_success;
|
||||
}
|
||||
|
||||
bool isErr() const {
|
||||
return !m_success;
|
||||
}
|
||||
|
||||
explicit NewResult(value_type const& value, bool success)
|
||||
requires std::is_copy_constructible_v<value_type>
|
||||
: m_value(value), m_success(success) {}
|
||||
|
||||
explicit NewResult(value_type&& value, bool success)
|
||||
requires std::is_move_constructible_v<value_type>
|
||||
: m_value(std::forward<value_type>(value)), m_success(success) {}
|
||||
|
||||
NewResult(NewResult<T, T> const& other)
|
||||
requires std::is_copy_constructible_v<value_type> = default;
|
||||
|
||||
NewResult(NewResult<T, T>&& other)
|
||||
requires (!std::is_copy_constructible_v<value_type>) = default;
|
||||
|
||||
template<class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T>
|
||||
NewResult(NewResult<T2, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type>
|
||||
: m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
|
||||
m_success(other.isOk()) {}
|
||||
|
||||
template<class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T>
|
||||
NewResult(NewResult<T2, E2>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type>
|
||||
) : m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
|
||||
m_success(other.isOk()) {}
|
||||
|
||||
template<class T2>
|
||||
requires ConvertibleToResult<T2, T>
|
||||
NewResult(NewResult<T2, AnyType> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type>
|
||||
: NewResult(value_type(other.unwrap()), true) {}
|
||||
|
||||
template<class T2>
|
||||
requires ConvertibleToResult<T2, T>
|
||||
NewResult(NewResult<T2, AnyType>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type>
|
||||
) : NewResult(std::forward<value_type>(other.unwrap()), true) {}
|
||||
|
||||
template<class E2>
|
||||
requires ConvertibleToResult<E2, T>
|
||||
NewResult(NewResult<AnyType, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type>
|
||||
: NewResult(error_type(other.unwrapErr()), false) {}
|
||||
|
||||
template<class E2>
|
||||
requires ConvertibleToResult<E2, T>
|
||||
NewResult(NewResult<AnyType, E2>&& other)
|
||||
requires (
|
||||
!std::is_copy_constructible_v<value_type>
|
||||
) : NewResult(std::forward<error_type>(other.unwrapErr()), false) {}
|
||||
|
||||
value_type unwrap() const
|
||||
requires std::is_copy_constructible_v<value_type>
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
value_type&& unwrap()
|
||||
requires (!std::is_copy_constructible_v<value_type>)
|
||||
{
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
error_type unwrapErr() const
|
||||
requires std::is_copy_constructible_v<error_type>
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
error_type&& unwrapErr()
|
||||
requires (!std::is_copy_constructible_v<error_type>)
|
||||
{
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
explicit operator bool() const requires (
|
||||
!std::is_same_v<T, bool>
|
||||
) {
|
||||
return this->isOk();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T = DefaultValue, class E = AnyType>
|
||||
requires std::is_copy_constructible_v<T>
|
||||
NewResult<T, E> NewOk(T value = T()) {
|
||||
return NewResult<T, E>(value);
|
||||
}
|
||||
|
||||
template<class T = DefaultValue, class E = AnyType>
|
||||
requires (!std::is_copy_constructible_v<T>)
|
||||
NewResult<T, E> NewOk(T&& value) {
|
||||
return NewResult<T, E>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
template<class E = DefaultError, class T = AnyType>
|
||||
requires std::is_copy_constructible_v<E>
|
||||
NewResult<T, E> NewErr(E error = E()) {
|
||||
return NewResult<T, E>(error);
|
||||
}
|
||||
|
||||
template<class E = DefaultError, class T = AnyType>
|
||||
requires (!std::is_copy_constructible_v<E>)
|
||||
NewResult<T, E> NewErr(E&& error) {
|
||||
return NewResult<T, E>(std::forward<E>(error));
|
||||
}
|
||||
|
||||
#define GEODE_UNWRAP_INTO(into, ...) \
|
||||
auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__);\
|
||||
if (GEODE_CONCAT(res_, __LINE__).isErr()) {\
|
||||
return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr()));\
|
||||
}\
|
||||
into = std::move(GEODE_CONCAT(res_, __LINE__).unwrap())
|
||||
|
||||
#define GEODE_UNWRAP(...) \
|
||||
{ auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__);\
|
||||
if (GEODE_CONCAT(res_, __LINE__).isErr()) {\
|
||||
return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr()));\
|
||||
} }
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <string_view>
|
||||
#include "types.hpp"
|
||||
#include "NewResult.hpp"
|
||||
|
||||
namespace geode {
|
||||
/**
|
||||
|
@ -26,7 +27,7 @@ namespace geode {
|
|||
* @authors Matcool, HJfod
|
||||
*/
|
||||
template <class T = no_result, class E = std::string>
|
||||
class Result {
|
||||
class [[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]] Result {
|
||||
protected:
|
||||
bool success;
|
||||
union {
|
||||
|
@ -109,7 +110,7 @@ namespace geode {
|
|||
* Convert to bool
|
||||
* @example if (result) { <handle success> } else { <handle failure> }
|
||||
*/
|
||||
operator bool() const { return this->success; }
|
||||
explicit operator bool() const { return this->success; }
|
||||
|
||||
/**
|
||||
* Create a success result
|
||||
|
@ -130,6 +131,7 @@ namespace geode {
|
|||
* @returns Successful Result
|
||||
*/
|
||||
template <class T = no_result>
|
||||
[[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]]
|
||||
Result<T> Ok(T value = T()) {
|
||||
return Result<T>::ok(value);
|
||||
}
|
||||
|
@ -141,7 +143,7 @@ namespace geode {
|
|||
* @returns Errorful Result
|
||||
*/
|
||||
template <class E = std::string>
|
||||
struct Err {
|
||||
struct [[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]] Err {
|
||||
const E _value;
|
||||
Err(const TypeIdentityType<E> value) : _value(value) {}
|
||||
template <class T>
|
||||
|
|
98
loader/src/hooks/LevelSearchLayer.cpp
Normal file
98
loader/src/hooks/LevelSearchLayer.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Index.hpp>
|
||||
#include "../ui/internal/list/ModListLayer.hpp"
|
||||
#include <InternalMod.hpp>
|
||||
#include "../ui/internal/info/ModInfoLayer.hpp"
|
||||
#include <InternalLoader.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
#pragma warning(disable: 4217)
|
||||
template<class T = CCNode>
|
||||
requires std::is_base_of_v<CCNode, T>
|
||||
T* setIDSafe(CCNode* node, int index, const char* id) {
|
||||
if constexpr (std::is_same_v<CCNode, T>) {
|
||||
if (auto child = getChild(node, index)) {
|
||||
child->setID(id);
|
||||
return child;
|
||||
}
|
||||
} else {
|
||||
if (auto child = getChildOfType<T>(node, index)) {
|
||||
child->setID(id);
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#include <Geode/modify/LevelSearchLayer.hpp>
|
||||
class $modify(LevelSearchLayer) {
|
||||
bool init() {
|
||||
if (!LevelSearchLayer::init())
|
||||
return false;
|
||||
|
||||
// set the funny ids
|
||||
this->setID("creator-layer");
|
||||
setIDSafe(this, 0, "creator-layer-bg");
|
||||
getChildOfType<CCTextInputNode>(this, 0)->setID("search-bar");
|
||||
getChildOfType<CCScale9Sprite>(this, 0)->setID("level-search-bg");
|
||||
getChildOfType<CCScale9Sprite>(this, 1)->setID("level-search-bar-bg");
|
||||
getChildOfType<CCScale9Sprite>(this, 2)->setID("quick-search-bg");
|
||||
getChildOfType<CCScale9Sprite>(this, 3)->setID("difficulty-filters-bg");
|
||||
getChildOfType<CCScale9Sprite>(this, 4)->setID("length-filters-bg");
|
||||
getChildOfType<CCLabelBMFont>(this, 0)->setID("quick-search-title");
|
||||
getChildOfType<CCLabelBMFont>(this, 1)->setID("filters-title");
|
||||
getChildOfType<CCSprite>(this, 1)->setID("left-corner");
|
||||
getChildOfType<CCSprite>(this, 2)->setID("right-corner");
|
||||
|
||||
if (auto filtermenu = getChildOfType<CCMenu>(this, 0)) {
|
||||
filtermenu->setID("other-filter-menu");
|
||||
setIDSafe(filtermenu, 0, "clear-filters-button");
|
||||
setIDSafe(filtermenu, 1, "advanced-filters-button");
|
||||
}
|
||||
if (auto searchmenu = getChildOfType<CCMenu>(this, 1)) {
|
||||
searchmenu->setID("search-button-menu");
|
||||
setIDSafe(searchmenu, 0, "search-level-button");
|
||||
setIDSafe(searchmenu, 1, "search-user-button");
|
||||
|
||||
}
|
||||
if (auto quickmenu = getChildOfType<CCMenu>(this, 2)) {
|
||||
quickmenu->setID("quick-search-menu");
|
||||
setIDSafe(quickmenu, 0, "most-downloaded-button");
|
||||
setIDSafe(quickmenu, 1, "most-liked-button");
|
||||
setIDSafe(quickmenu, 2, "trending-button");
|
||||
setIDSafe(quickmenu, 3, "recent-button");
|
||||
setIDSafe(quickmenu, 4, "magic-button");
|
||||
setIDSafe(quickmenu, 5, "awarded-button");
|
||||
setIDSafe(quickmenu, 6, "followed-button");
|
||||
setIDSafe(quickmenu, 7, "friends-button");
|
||||
}
|
||||
if (auto filtersmenu = getChildOfType<CCMenu>(this, 3)) {
|
||||
filtersmenu->setID("difficulty-filter-menu");
|
||||
setIDSafe(filtersmenu, 0, "na-filter-button");
|
||||
setIDSafe(filtersmenu, 1, "easy-filter-button");
|
||||
setIDSafe(filtersmenu, 2, "normal-filter-button");
|
||||
setIDSafe(filtersmenu, 3, "hard-filter-button");
|
||||
setIDSafe(filtersmenu, 4, "harder-filter-button");
|
||||
setIDSafe(filtersmenu, 5, "insane-filter-button");
|
||||
setIDSafe(filtersmenu, 6, "demon-filter-button");
|
||||
setIDSafe(filtersmenu, 7, "auto-filter-button");
|
||||
setIDSafe(filtersmenu, 8, "demon-type-filter-button");
|
||||
}
|
||||
if (auto filtersmenu = getChildOfType<CCMenu>(this, 4)) {
|
||||
filtersmenu->setID("length-filter-menu");
|
||||
setIDSafe(filtersmenu, 0, "clock-icon");
|
||||
setIDSafe(filtersmenu, 1, "tiny-filter-button");
|
||||
setIDSafe(filtersmenu, 2, "short-filter-button");
|
||||
setIDSafe(filtersmenu, 3, "medium-filter-button");
|
||||
setIDSafe(filtersmenu, 4, "long-filter-button");
|
||||
setIDSafe(filtersmenu, 5, "xl-filter-button");
|
||||
setIDSafe(filtersmenu, 6, "star-filter-button");
|
||||
}
|
||||
if (auto backmenu = getChildOfType<CCMenu>(this, 5)) {
|
||||
backmenu->setID("exit-menu");
|
||||
setIDSafe(backmenu, 0, "exit-button");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -37,7 +37,7 @@ static CCEGLView* CCEGLView_CCEGLView(CCEGLView* self) {
|
|||
}
|
||||
|
||||
$execute {
|
||||
Mod::get()->addHook<&CCEGLView_CCEGLView, Thiscall>("CCEGLView::CCEGLView", CCEGLVIEW_CON_ADDR);
|
||||
(void)Mod::get()->addHook<&CCEGLView_CCEGLView, Thiscall>("CCEGLView::CCEGLView", CCEGLVIEW_CON_ADDR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -150,7 +150,7 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) {
|
|||
// different sha
|
||||
if (force || currentCommitSHA != upcomingCommitSHA) {
|
||||
// save new sha in file
|
||||
utils::file::writeString(indexDir / "current", upcomingCommitSHA);
|
||||
(void)utils::file::writeString(indexDir / "current", upcomingCommitSHA);
|
||||
|
||||
web::AsyncWebRequest()
|
||||
.join("index-download")
|
||||
|
@ -643,7 +643,7 @@ InstallItems::CallbackID InstallItems::start(
|
|||
auto item = Index::get()->getKnownItem(inst);
|
||||
|
||||
auto indexDir = Loader::get()->getGeodeDirectory() / "index";
|
||||
file::createDirectoryAll(indexDir / "temp");
|
||||
(void)file::createDirectoryAll(indexDir / "temp");
|
||||
auto tempFile = indexDir / "temp" / item.m_download.m_filename;
|
||||
|
||||
m_downloaded.push_back(tempFile);
|
||||
|
|
|
@ -257,11 +257,11 @@ static void printMods(std::ostream& stream) {
|
|||
|
||||
static LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info) {
|
||||
// make sure crashlog directory exists
|
||||
utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
(void)utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
|
||||
// add a file to let Geode know on next launch that it crashed previously
|
||||
// this could also be done by saving a loader setting or smth but eh.
|
||||
utils::file::writeBinary(
|
||||
(void)utils::file::writeBinary(
|
||||
crashlog::getCrashLogDirectory() + "/last-crashed", {}
|
||||
);
|
||||
|
||||
|
|
|
@ -362,7 +362,10 @@ bool Loader::setup() {
|
|||
log::debug("Setting up Loader...");
|
||||
|
||||
this->createDirectories();
|
||||
this->loadSettings();
|
||||
auto sett = this->loadSettings();
|
||||
if (!sett) {
|
||||
log::warn("Unable to load loader settings: {}", sett.error());
|
||||
}
|
||||
this->refreshMods();
|
||||
|
||||
m_isSetup = true;
|
||||
|
|
|
@ -48,7 +48,7 @@ Mod::Mod(ModInfo const& info) {
|
|||
}
|
||||
|
||||
Mod::~Mod() {
|
||||
this->unload();
|
||||
(void)this->unload();
|
||||
}
|
||||
|
||||
Result<> Mod::loadSettings() {
|
||||
|
@ -217,14 +217,14 @@ Result<> Mod::load() {
|
|||
if (m_implicitLoadFunc) {
|
||||
auto r = m_implicitLoadFunc(this);
|
||||
if (!r) {
|
||||
this->unloadPlatformBinary();
|
||||
(void)this->unloadPlatformBinary();
|
||||
RETURN_LOAD_ERR("Implicit mod entry point returned an error");
|
||||
}
|
||||
}
|
||||
if (m_loadFunc) {
|
||||
auto r = m_loadFunc(this);
|
||||
if (!r) {
|
||||
this->unloadPlatformBinary();
|
||||
(void)this->unloadPlatformBinary();
|
||||
RETURN_LOAD_ERR("Mod entry point returned an error");
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ bool Mod::updateDependencyStates() {
|
|||
}
|
||||
if (dep.isUnresolved()) {
|
||||
m_resolved = false;
|
||||
this->unload();
|
||||
(void)this->unload();
|
||||
hasUnresolved = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,7 +195,10 @@ Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
|
|||
auto info = res.value();
|
||||
info.m_path = path;
|
||||
if (path.has_parent_path()) {
|
||||
info.addSpecialFiles(path.parent_path());
|
||||
auto err = info.addSpecialFiles(path.parent_path());
|
||||
if (!err) {
|
||||
return Err(err.error());
|
||||
}
|
||||
}
|
||||
return Ok(info);
|
||||
} catch(std::exception& e) {
|
||||
|
@ -245,7 +248,10 @@ Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path)
|
|||
auto info = res.value();
|
||||
info.m_path = path;
|
||||
|
||||
info.addSpecialFiles(unzip);
|
||||
auto err = info.addSpecialFiles(unzip);
|
||||
if (!err) {
|
||||
return Err(err.error());
|
||||
}
|
||||
|
||||
return Ok(info);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ static bool tryOrAlert(Result<T> const& res, const char* title) {
|
|||
if (!res) {
|
||||
FLAlertLayer::create(title, res.error(), "OK")->show();
|
||||
}
|
||||
return res;
|
||||
return res.is_value();
|
||||
}
|
||||
|
||||
ModCell::ModCell(const char* name, CCSize size) :
|
||||
|
|
Loading…
Reference in a new issue