mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
commit
e170fbdf99
69 changed files with 1440 additions and 689 deletions
|
@ -21,6 +21,10 @@ project(geode-sdk VERSION ${GEODE_VERSION} LANGUAGES CXX C)
|
|||
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(GEODE_ALWAYS_BUILD_CODEGEN ON)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED GEODE_DEBUG AND (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo))
|
||||
set(GEODE_DEBUG ON)
|
||||
endif()
|
||||
|
@ -68,7 +72,7 @@ add_custom_command(
|
|||
COMMAND echo codegen > ${GEODE_CODEGEN_PATH}/.stamp
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Run Codegen"
|
||||
OUTPUT ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/.stamp
|
||||
OUTPUT ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp ${GEODE_CODEGEN_PATH}/.stamp
|
||||
)
|
||||
|
||||
add_custom_target(CodegenRun
|
||||
|
@ -84,7 +88,26 @@ if (NOT EXISTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
|||
file(TOUCH ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} INTERFACE ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
if (NOT EXISTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
|
||||
make_directory(${GEODE_CODEGEN_PATH})
|
||||
make_directory(${GEODE_CODEGEN_PATH}/Geode)
|
||||
file(TOUCH ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
|
||||
endif()
|
||||
|
||||
add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
|
||||
target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
|
||||
target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem fmt TulipHookInclude)
|
||||
target_include_directories(GeodeCodegenSources PRIVATE
|
||||
${GEODE_CODEGEN_PATH}
|
||||
${GEODE_LOADER_PATH}/include
|
||||
${GEODE_LOADER_PATH}/include/Geode/cocos/include
|
||||
${GEODE_LOADER_PATH}/include/Geode/cocos/extensions
|
||||
${GEODE_LOADER_PATH}/include/Geode/fmod
|
||||
)
|
||||
target_compile_features(GeodeCodegenSources PUBLIC cxx_std_20)
|
||||
target_precompile_headers(GeodeCodegenSources INTERFACE
|
||||
"${GEODE_LOADER_PATH}/include/Geode/Bindings.hpp"
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
${GEODE_CODEGEN_PATH}
|
||||
|
@ -99,7 +122,10 @@ target_link_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lo
|
|||
CPMAddPackage("gh:fmtlib/fmt#9.1.0")
|
||||
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt)
|
||||
# Tulip hook (hooking)
|
||||
CPMAddPackage("gh:geode-sdk/TulipHook#9980bcf")
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources)
|
||||
|
||||
|
||||
if (NOT EXISTS ${GEODE_BIN_PATH})
|
||||
|
@ -124,11 +150,8 @@ elseif(EXISTS ${GEODE_PLATFORM_BIN_PATH})
|
|||
target_link_libraries(${PROJECT_NAME} INTERFACE "${GEODE_PLATFORM_BIN_PATH}")
|
||||
target_precompile_headers(${PROJECT_NAME} INTERFACE
|
||||
"${GEODE_LOADER_PATH}/include/Geode/DefaultInclude.hpp"
|
||||
"${GEODE_LOADER_PATH}/include/Geode/Loader.hpp"
|
||||
"${GEODE_LOADER_PATH}/include/Geode/Geode.hpp"
|
||||
# please stop adding modify here its not here because it makes windows compilation take longer than geode 1.0 release date
|
||||
"${GEODE_LOADER_PATH}/include/Geode/UI.hpp"
|
||||
"${GEODE_LOADER_PATH}/include/Geode/cocos/include/cocos2d.h"
|
||||
"${GEODE_LOADER_PATH}/include/Geode/cocos/extensions/cocos-ext.h"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
|
|
|
@ -3801,6 +3801,7 @@ class LevelSettingsObject : cocos2d::CCNode {
|
|||
int m_groundIndex;
|
||||
int m_fontIndex;
|
||||
bool m_startsWithStartPos;
|
||||
bool m_isFlipped;
|
||||
GJGameLevel* m_level;
|
||||
gd::string m_guidelineString;
|
||||
int m_unknown;
|
||||
|
|
|
@ -32,7 +32,7 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS")
|
|||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE curl "-framework Cocoa")
|
||||
target_compile_options(${PROJECT_NAME} INTERFACE -fms-extensions -Wno-deprecated -Wno-ignored-attributes -Os #[[-flto]] -fvisibility=internal)
|
||||
target_compile_options(${PROJECT_NAME} INTERFACE -fms-extensions #[[-Wno-deprecated]] -Wno-ignored-attributes -Os #[[-flto]] #[[-fvisibility=internal]])
|
||||
|
||||
set(GEODE_PLATFORM_BINARY "Geode.dylib")
|
||||
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
|
||||
namespace { namespace format_strings {
|
||||
|
||||
char const* address_begin = R"GEN(
|
||||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/modify/Addresses.hpp>
|
||||
#include <Geode/modify/Traits.hpp>
|
||||
)GEN";
|
||||
|
||||
char const* declare_address = R"GEN(
|
||||
GEODE_INLINE GEODE_HIDDEN static uintptr_t address{index}() {{
|
||||
template <>
|
||||
uintptr_t geode::modifier::address<{index}>() {{
|
||||
static uintptr_t ret = {address};
|
||||
return ret;
|
||||
}}
|
||||
|
@ -17,6 +24,7 @@ std::string generateAddressHeader(Root& root) {
|
|||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
output += format_strings::address_begin;
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
|
||||
|
@ -32,9 +40,9 @@ 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{})(&{}::{}))",
|
||||
address_str = fmt::format("addresser::get{}Virtual(Resolve<{}>::func(&{}::{}))",
|
||||
str_if("Non", !fn->beginning.is_virtual),
|
||||
ids.member,
|
||||
codegen::getParameterTypes(fn->beginning),
|
||||
field.parent,
|
||||
fn->beginning.name
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace { namespace format_strings {
|
|||
)GEN";
|
||||
|
||||
char const* class_includes = R"GEN(#pragma once
|
||||
#include <stdexcept>
|
||||
#include <Geode/platform/platform.hpp>
|
||||
#include <Geode/c++stl/gdstdlib.hpp>
|
||||
#include <cocos2d.h>
|
||||
|
@ -20,6 +21,7 @@ namespace { namespace format_strings {
|
|||
|
||||
char const* class_no_includes = R"GEN(#pragma once
|
||||
#include <Geode/platform/platform.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
)GEN";
|
||||
|
||||
|
@ -41,14 +43,17 @@ public:
|
|||
char const* function_definition = R"GEN({docs} {static}{virtual}{return_type} {function_name}({parameters}){const};
|
||||
)GEN";
|
||||
|
||||
char const* error_definition = R"GEN( template <bool T=false>
|
||||
char const* error_definition = R"GEN(
|
||||
#ifdef GEODE_WARN_INCORRECT_MEMBERS
|
||||
[[deprecated("Function is not implemented - will throw at runtime!!!")]]
|
||||
#endif
|
||||
{static}{return_type} {function_name}({parameters}){const}{{
|
||||
static_assert(T, "Implement {class_name}::{function_name}");
|
||||
throw std::runtime_error("Use of undefined function " + GEODE_PRETTY_FUNCTION);
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* error_definition_virtual = R"GEN(
|
||||
#ifndef GEODE_DONT_WARN_INCORRECT_MEMBERS
|
||||
#ifdef GEODE_WARN_INCORRECT_MEMBERS
|
||||
[[deprecated("Use of undefined virtual function - will crash at runtime!!!")]]
|
||||
#endif
|
||||
{virtual}{return_type} {function_name}({parameters}){const}{{
|
||||
|
@ -60,7 +65,7 @@ public:
|
|||
)GEN";
|
||||
|
||||
char const* warn_offset_member = R"GEN(
|
||||
#ifndef GEODE_DONT_WARN_INCORRECT_MEMBERS
|
||||
#ifdef GEODE_WARN_INCORRECT_MEMBERS
|
||||
[[deprecated("Member placed incorrectly - will crash at runtime!!!")]]
|
||||
#endif
|
||||
)GEN";
|
||||
|
|
|
@ -31,9 +31,9 @@ int main(int argc, char** argv) try {
|
|||
}
|
||||
}
|
||||
|
||||
writeFile(writeDir / "GeneratedAddress.hpp", generateAddressHeader(root));
|
||||
writeFile(writeDir / "GeneratedAddress.cpp", generateAddressHeader(root));
|
||||
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 / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding"));
|
||||
writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root));
|
||||
|
|
|
@ -6,41 +6,44 @@
|
|||
|
||||
namespace {
|
||||
namespace format_strings {
|
||||
char const* wrap_start = R"GEN(
|
||||
namespace wrap {
|
||||
)GEN";
|
||||
|
||||
char const* wrap_declare_identifier = R"GEN(
|
||||
#ifndef GEODE_WRAP_{function_name}
|
||||
#define GEODE_WRAP_{function_name}
|
||||
GEODE_WRAPPER_FOR_IDENTIFIER({function_name})
|
||||
#endif
|
||||
)GEN";
|
||||
|
||||
char const* wrap_end = R"GEN(
|
||||
}
|
||||
)GEN";
|
||||
// requires: class_name
|
||||
// requires: class_name, class_include
|
||||
char const* modify_start = R"GEN(#pragma once
|
||||
#include <Geode/modify/Modify.hpp>
|
||||
#include <Geode/modify/Field.hpp>
|
||||
#include <Geode/modify/InternalMacros.hpp>
|
||||
#include <Geode/modify/Addresses.hpp>
|
||||
{class_include}
|
||||
using namespace geode::modifier;
|
||||
|
||||
namespace geode::modifier {{
|
||||
{wrap}
|
||||
template<class Derived>
|
||||
struct ModifyDerive<Derived, {class_name}> : ModifyBase<ModifyDerive<Derived, {class_name}>> {{
|
||||
using ModifyBase<ModifyDerive<Derived, {class_name}>>::ModifyBase;
|
||||
{statics}
|
||||
|
||||
template<class Der>
|
||||
struct ModifyDerive<Der, {class_name}> : ModifyBase<ModifyDerive<Der, {class_name}>> {{
|
||||
using BaseModify = ModifyBase<ModifyDerive<Der, {class_name}>>;
|
||||
using ModifyBase<ModifyDerive<Der, {class_name}>>::ModifyBase;
|
||||
using Base = {class_name};
|
||||
static void apply() {{
|
||||
using Derived = Der;
|
||||
void apply() override {{
|
||||
using namespace geode::core::meta;
|
||||
|
||||
)GEN";
|
||||
|
||||
char const* statics_declare_identifier = R"GEN(
|
||||
#ifndef GEODE_STATICS_{function_name}
|
||||
#define GEODE_STATICS_{function_name}
|
||||
GEODE_AS_STATIC_FUNCTION({function_name})
|
||||
#endif
|
||||
)GEN";
|
||||
|
||||
// requires: index, class_name, arg_types, function_name, raw_arg_types, non_virtual
|
||||
char const* apply_function = R"GEN(
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({addr_index}, {pure_index}, {function_convention}, {class_name}, {function_name}))GEN";
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({addr_index}, {function_convention}, {class_name}, {function_name}, {parameter_types}))GEN";
|
||||
|
||||
char const* apply_constructor = R"GEN(
|
||||
GEODE_APPLY_MODIFY_FOR_CONSTRUCTOR({addr_index}, {function_convention}, {class_name}, {parameter_types}))GEN";
|
||||
|
||||
char const* apply_destructor = R"GEN(
|
||||
GEODE_APPLY_MODIFY_FOR_DESTRUCTOR({addr_index}, {function_convention}, {class_name}))GEN";
|
||||
|
||||
char const* modify_end = R"GEN(
|
||||
}
|
||||
|
@ -66,45 +69,71 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
|
|||
output += fmt::format(format_strings::modify_include, fmt::arg("file_name", filename));
|
||||
|
||||
std::string single_output;
|
||||
std::string wrap;
|
||||
|
||||
// wrap
|
||||
wrap += format_strings::wrap_start;
|
||||
std::string class_include;
|
||||
|
||||
if (c.name.find("cocos2d::extension") != std::string::npos) {
|
||||
class_include = "#include <cocos-ext.h>";
|
||||
}
|
||||
else if (c.name.find("cocos2d") != std::string::npos) {
|
||||
class_include = "#include <cocos2d.h>";
|
||||
}
|
||||
else {
|
||||
class_include = fmt::format(
|
||||
"#include <Geode/binding/{class_name}.hpp>",
|
||||
fmt::arg("class_name", codegen::getUnqualifiedClassName(c.name))
|
||||
);
|
||||
}
|
||||
|
||||
std::string statics;
|
||||
std::set<std::string> used;
|
||||
for (auto& f : c.fields) {
|
||||
if (auto fn = f.get_fn()) {
|
||||
if (fn->type == FunctionType::Normal && !used.count(fn->name)) {
|
||||
used.insert(fn->name);
|
||||
wrap += fmt::format(
|
||||
format_strings::wrap_declare_identifier, fmt::arg("function_name", fn->name)
|
||||
statics += fmt::format(
|
||||
format_strings::statics_declare_identifier,
|
||||
fmt::arg("function_name", fn->name)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
wrap += format_strings::wrap_end;
|
||||
|
||||
single_output += fmt::format(
|
||||
format_strings::modify_start, fmt::arg("class_name", c.name), fmt::arg("wrap", wrap)
|
||||
format_strings::modify_start,
|
||||
fmt::arg("statics", statics),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("class_include", class_include)
|
||||
);
|
||||
|
||||
// modify
|
||||
for (auto& f : c.fields) {
|
||||
if (codegen::getStatus(f) != BindStatus::Unbindable) {
|
||||
auto begin = f.get_fn();
|
||||
auto func = TypeBank::makeFunc(*begin, c.name);
|
||||
|
||||
std::string function_name;
|
||||
std::string format_string;
|
||||
|
||||
switch (begin->type) {
|
||||
case FunctionType::Normal: function_name = begin->name; break;
|
||||
case FunctionType::Ctor: function_name = "constructor"; break;
|
||||
case FunctionType::Dtor: function_name = "destructor"; break;
|
||||
case FunctionType::Normal:
|
||||
format_string = format_strings::apply_function;
|
||||
break;
|
||||
case FunctionType::Ctor:
|
||||
format_string = format_strings::apply_constructor;
|
||||
break;
|
||||
case FunctionType::Dtor:
|
||||
format_string = format_strings::apply_destructor;
|
||||
break;
|
||||
}
|
||||
|
||||
single_output += fmt::format(
|
||||
format_strings::apply_function, fmt::arg("addr_index", f.field_id),
|
||||
format_string,
|
||||
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))
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("function_name", begin->name),
|
||||
fmt::arg("function_convention", codegen::getModifyConvention(f)),
|
||||
fmt::arg("parameter_types", fmt::join(func.parameter_types, ", "))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,27 @@ namespace codegen {
|
|||
else throw codegen::error("Tried to get convention of non-function");
|
||||
}
|
||||
|
||||
inline std::string getModifyConvention(Field& f) {
|
||||
if (codegen::platform != Platform::Windows) return "tulip::hook::DefaultConvention";
|
||||
|
||||
if (auto fn = f.get_fn()) {
|
||||
auto status = getStatus(f);
|
||||
|
||||
if (fn->is_static) {
|
||||
if (status == BindStatus::Binded) return "tulip::hook::CdeclConvention";
|
||||
else return "tulip::hook::OptcallConvention";
|
||||
}
|
||||
else if (fn->is_virtual) {
|
||||
return "tulip::hook::ThiscallConvention";
|
||||
}
|
||||
else {
|
||||
if (status == BindStatus::Binded) return "tulip::hook::ThiscallConvention";
|
||||
else return "tulip::hook::MembercallConvention";
|
||||
}
|
||||
}
|
||||
else throw codegen::error("Tried to get convention of non-function");
|
||||
}
|
||||
|
||||
inline std::string getUnqualifiedClassName(std::string const& s) {
|
||||
auto index = s.rfind("::");
|
||||
if (index == std::string::npos) return s;
|
||||
|
|
|
@ -3,39 +3,72 @@
|
|||
|
||||
namespace { namespace format_strings {
|
||||
char const* source_start = R"CAC(
|
||||
#include <stdexcept>
|
||||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/utils/addresser.hpp>
|
||||
#include <Geode/utils/casts.hpp>
|
||||
#include <Geode/meta/meta.hpp>
|
||||
#include <Geode/modify/Addresses.hpp>
|
||||
#include <Geode/modify/Types.hpp>
|
||||
#include <Geode/modify/Traits.hpp>
|
||||
#include <tulip/TulipHook.hpp>
|
||||
|
||||
using namespace geode;
|
||||
using namespace geode::cast;
|
||||
using namespace geode::modifier;
|
||||
using cocos2d::CCDestructor;
|
||||
using namespace geode::core::meta; // Default convention
|
||||
using namespace geode::core::meta::x86; // Windows x86 conventions, Function
|
||||
using namespace geode::modifier; // types
|
||||
|
||||
std::unordered_map<void*, bool>& CCDestructor::destructorLock() {{
|
||||
static auto ret = new std::unordered_map<void*, bool>;
|
||||
return *ret;
|
||||
}}
|
||||
bool& CCDestructor::globalLock() {{
|
||||
static thread_local bool ret = false;
|
||||
return ret;
|
||||
}}
|
||||
bool& CCDestructor::lock(void* self) {
|
||||
return destructorLock()[self];
|
||||
}
|
||||
CCDestructor::~CCDestructor() {{
|
||||
destructorLock().erase(this);
|
||||
}}
|
||||
|
||||
auto wrapFunction(uintptr_t address, tulip::hook::WrapperMetadata const& metadata) {
|
||||
auto wrapped = tulip::hook::createWrapper(reinterpret_cast<void*>(address), metadata);
|
||||
if (wrapped.isErr()) {{
|
||||
throw std::runtime_error(wrapped.unwrapErr());
|
||||
}}
|
||||
return wrapped.unwrap();
|
||||
}
|
||||
)CAC";
|
||||
|
||||
char const* declare_member = R"GEN(
|
||||
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});
|
||||
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
|
||||
using FunctionType = decltype({function_name}({arguments}))(*)({class_name}{const}*{parameter_comma}{parameter_types});
|
||||
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
|
||||
.m_convention = std::make_shared<{convention}>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
|
||||
}});
|
||||
return reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_virtual = R"GEN(
|
||||
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});
|
||||
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
|
||||
auto self = addresser::thunkAdjust(Resolve<{parameter_types}>::func(&{class_name}::{function_name}), this);
|
||||
using FunctionType = decltype({function_name}({arguments}))(*)({class_name}{const}*{parameter_comma}{parameter_types});
|
||||
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
|
||||
.m_convention = std::make_shared<{convention}>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
|
||||
}});
|
||||
return reinterpret_cast<FunctionType>(func)(self{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_static = R"GEN(
|
||||
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});
|
||||
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
|
||||
using FunctionType = decltype({function_name}({arguments}))(*)({parameter_types});
|
||||
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
|
||||
.m_convention = std::make_shared<{convention}>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
|
||||
}});
|
||||
return reinterpret_cast<FunctionType>(func)({arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
|
@ -44,8 +77,12 @@ types::ret{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{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
using FunctionType = void(*)({class_name}*{parameter_comma}{parameter_types});
|
||||
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
|
||||
.m_convention = std::make_shared<{convention}>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
|
||||
}});
|
||||
reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
|
||||
// we need to construct it back so that it uhhh ummm doesnt crash
|
||||
// while going to the child destructors
|
||||
auto thing = new (this) {class_name}(std::monostate(), sizeof({class_name}));
|
||||
|
@ -60,8 +97,12 @@ types::ret{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{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
using FunctionType = void(*)({class_name}*{parameter_comma}{parameter_types});
|
||||
static auto func = wrapFunction(address<{addr_index}>(), tulip::hook::WrapperMetadata{{
|
||||
.m_convention = std::make_shared<{convention}>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(FunctionType(nullptr)),
|
||||
}});
|
||||
reinterpret_cast<FunctionType>(func)(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
|
@ -149,7 +190,7 @@ std::string generateBindingSource(Root& root) {
|
|||
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("convention", codegen::getModifyConvention(f)),
|
||||
fmt::arg("function_name", fn->beginning.name),
|
||||
fmt::arg("meta_index", ids.meta),
|
||||
fmt::arg("member_index", ids.member),
|
||||
|
|
15
entry.cpp
15
entry.cpp
|
@ -1,5 +1,18 @@
|
|||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
namespace geode {
|
||||
/**
|
||||
* To bypass the need for cyclic dependencies,
|
||||
* this function does the exact same as Mod::get()
|
||||
* However, it can be externed, unlike Mod::get()
|
||||
* @returns Same thing Mod::get() returns
|
||||
*/
|
||||
Mod* getMod() {
|
||||
return Mod::get();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// to make sure the instance is set into the sharedMod<> in load time
|
||||
|
|
|
@ -121,6 +121,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||
if (APPLE)
|
||||
# For profiling
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC "-ftime-trace")
|
||||
# target_link_options(${PROJECT_NAME} PRIVATE "-Wl,-e,_dynamicInit")
|
||||
#set_property(TARGET ${PROJECT_NAME} PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
|
||||
endif()
|
||||
|
||||
|
@ -134,9 +135,8 @@ CPMAddPackage("gh:google/re2#954656f")
|
|||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${md4c_SOURCE_DIR}/src)
|
||||
|
||||
# Lilac (hooking)
|
||||
add_subdirectory(lilac)
|
||||
target_link_libraries(${PROJECT_NAME} md4c z lilac_hook geode-sdk re2)
|
||||
target_link_libraries(${PROJECT_NAME} md4c z TulipHook geode-sdk re2)
|
||||
|
||||
|
||||
# Use precompiled headers for faster builds
|
||||
if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
|
||||
|
@ -146,7 +146,6 @@ if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp"
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Bindings.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Modify.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h"
|
||||
)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "loader/Mod.hpp"
|
||||
#include "loader/ModEvent.hpp"
|
||||
#include "loader/Setting.hpp"
|
||||
#include "loader/SettingEvent.hpp"
|
||||
#include "loader/Dirs.hpp"
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
|
|
18
loader/include/Geode/cocos/cocoa/CCObject.h
vendored
18
loader/include/Geode/cocos/cocoa/CCObject.h
vendored
|
@ -79,21 +79,11 @@ public:
|
|||
*/
|
||||
class CCDestructor : public CCCopying {
|
||||
private:
|
||||
static inline auto& destructorLock() {
|
||||
static auto ret = new std::unordered_map<void*, bool>;
|
||||
return *ret;
|
||||
}
|
||||
static std::unordered_map<void*, bool>& destructorLock();
|
||||
public:
|
||||
static inline bool& globalLock() {
|
||||
static thread_local bool ret = false;
|
||||
return ret;
|
||||
}
|
||||
static inline bool& lock(void* self) {
|
||||
return destructorLock()[self];
|
||||
}
|
||||
inline ~CCDestructor() {
|
||||
destructorLock().erase(this);
|
||||
}
|
||||
static bool& globalLock();
|
||||
static bool& lock(void* self);
|
||||
~CCDestructor();
|
||||
};
|
||||
|
||||
#pragma warning(push)
|
||||
|
|
|
@ -44,7 +44,8 @@ NS_CC_EXT_BEGIN
|
|||
* @{
|
||||
*/
|
||||
|
||||
class GEODE_DLL ColorPickerDelegate {
|
||||
class CC_DLL ColorPickerDelegate {
|
||||
public:
|
||||
virtual void colorValueChanged(ccColor3B) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ NS_CC_BEGIN
|
|||
class CC_DLL CCLabelTTF : public CCSprite, public CCLabelProtocol
|
||||
{
|
||||
GEODE_FRIEND_MODIFY
|
||||
GEODE_FRIEND_MODIFY
|
||||
public:
|
||||
/**
|
||||
* @js ctor
|
||||
|
|
|
@ -113,20 +113,32 @@ It's new in cocos2d-x since v0.99.5
|
|||
* macro.
|
||||
*/
|
||||
class GeodeNodeMetadata;
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace geode {
|
||||
struct modify;
|
||||
|
||||
namespace modifier {
|
||||
struct addresses;
|
||||
struct types;
|
||||
class FieldContainer;
|
||||
|
||||
template <class Derived, class Base>
|
||||
class ModifyDerive;
|
||||
|
||||
template <uint32_t>
|
||||
uintptr_t address();
|
||||
}
|
||||
}
|
||||
#define GEODE_FRIEND_MODIFY GEODE_ADD(\
|
||||
|
||||
#define GEODE_FRIEND_MODIFY \
|
||||
friend struct ::geode::modify; \
|
||||
friend struct ::geode::modifier::addresses;\
|
||||
template <class Derived, class Base> \
|
||||
friend class ::geode::modifier::ModifyDerive; \
|
||||
friend struct ::geode::modifier::types; \
|
||||
friend class ::GeodeNodeMetadata; \
|
||||
)
|
||||
template <uint32_t> \
|
||||
friend uintptr_t geode::modifier::address();
|
||||
#define GEODE_ADD(...) __VA_ARGS__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
79
loader/include/Geode/external/json/json_fwd.hpp
vendored
Normal file
79
loader/include/Geode/external/json/json_fwd.hpp
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// #include <nlohmann/json_fwd.hpp>
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
namespace nlohmann
|
||||
{
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>>
|
||||
class basic_json;
|
||||
|
||||
/*!
|
||||
@brief JSON Pointer
|
||||
|
||||
A JSON pointer defines a string syntax for identifying a specific value
|
||||
within a JSON document. It can be used with functions `at` and
|
||||
`operator[]`. Furthermore, JSON pointers are the base for JSON patches.
|
||||
|
||||
@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default JSON class
|
||||
|
||||
This type is the default specialization of the @ref basic_json class which
|
||||
uses the standard template types.
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/*!
|
||||
@brief ordered JSON class
|
||||
|
||||
This type preserves the insertion order of object keys.
|
||||
|
||||
@since version 3.9.0
|
||||
*/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
} // namespace nlohmann
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "../utils/casts.hpp"
|
||||
#include "Mod.hpp"
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <type_traits>
|
||||
|
@ -11,6 +10,8 @@ namespace geode {
|
|||
class Mod;
|
||||
class Event;
|
||||
|
||||
Mod* getMod();
|
||||
|
||||
enum class ListenerResult {
|
||||
Propagate,
|
||||
Stop
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
#include "../DefaultInclude.hpp"
|
||||
#include "../hook-core/Hook.hpp"
|
||||
#include "../utils/general.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include <inttypes.h>
|
||||
#include <string_view>
|
||||
#include <tulip/TulipHook.hpp>
|
||||
|
||||
namespace geode {
|
||||
class Mod;
|
||||
|
@ -13,84 +14,132 @@ namespace geode {
|
|||
|
||||
class GEODE_DLL Hook {
|
||||
private:
|
||||
Mod* m_owner;
|
||||
std::string m_displayName;
|
||||
void* m_address;
|
||||
void* m_detour;
|
||||
core::HookHandle m_handle;
|
||||
bool m_enabled;
|
||||
Result<core::HookHandle> (*m_addFunction)(void*);
|
||||
|
||||
// Only allow friend classes to create
|
||||
// hooks. Whatever method created the
|
||||
// hook should take care of populating
|
||||
// m_owner and m_handle.
|
||||
Hook() : m_enabled(false) {}
|
||||
|
||||
template <auto Detour, template <class, class...> class Conv, class Ret, class... Args>
|
||||
static Hook* create(Ret (*address)(Args...), std::string const& displayName, Mod* owner) {
|
||||
auto ret = new Hook;
|
||||
ret->m_address = (void*)address;
|
||||
ret->m_detour = (void*)Detour;
|
||||
ret->m_owner = owner;
|
||||
ret->m_displayName = displayName;
|
||||
ret->m_addFunction =
|
||||
(Result<core::HookHandle>(*)(void*)) & core::hook::add<Detour, Conv, Ret, Args...>;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// no copying
|
||||
Hook(Hook const&) = delete;
|
||||
Hook operator=(Hook const&) = delete;
|
||||
|
||||
// Used by Mod
|
||||
Result<> enable();
|
||||
Result<> disable();
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
Hook(std::shared_ptr<Impl>&& impl);
|
||||
~Hook();
|
||||
|
||||
friend class Mod;
|
||||
friend class Loader;
|
||||
|
||||
static std::vector<std::pair<Hook*, Mod*>> internalHooks;
|
||||
static bool readyToHook;
|
||||
Result<> enable();
|
||||
Result<> disable();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a hook at an address. The hook is enabled immediately. By
|
||||
* default, the hook is placed at the end of the detour list; however,
|
||||
* this can be controlled using metadata settings.
|
||||
* @param owner The mod that owns this hook; must be provided
|
||||
* @param address The address to hook
|
||||
* @param detour The detour to run when the hook is hit. The detour's
|
||||
* calling convention should be cdecl
|
||||
* @param displayName A human-readable name describing the hook,
|
||||
* usually the fully qualified name of the function being hooked
|
||||
* @param handlerMetadata Metadata for the hook handler
|
||||
* @param hookMetadata Metadata for the hook itself
|
||||
* @returns The created hook, or an error. Make sure to add the created
|
||||
* hook to the mod that owns it using mod->addHook!
|
||||
*/
|
||||
static Hook* create(
|
||||
Mod* owner,
|
||||
void* address,
|
||||
void* detour,
|
||||
std::string const& displayName,
|
||||
tulip::hook::HandlerMetadata const& handlerMetadata,
|
||||
tulip::hook::HookMetadata const& hookMetadata
|
||||
);
|
||||
|
||||
template <class Convention, class DetourType>
|
||||
static Hook* create(
|
||||
Mod* owner,
|
||||
void* address,
|
||||
DetourType detour,
|
||||
std::string const& displayName,
|
||||
tulip::hook::HookMetadata const& hookMetadata = tulip::hook::HookMetadata()
|
||||
) {
|
||||
auto handlerMetadata = tulip::hook::HandlerMetadata{
|
||||
.m_convention = std::make_shared<Convention>(),
|
||||
.m_abstract = tulip::hook::AbstractFunction::from(detour)
|
||||
};
|
||||
return Hook::create(
|
||||
owner,
|
||||
address,
|
||||
reinterpret_cast<void*>(detour),
|
||||
displayName,
|
||||
handlerMetadata,
|
||||
hookMetadata
|
||||
);
|
||||
}
|
||||
|
||||
Hook(Hook const&) = delete;
|
||||
Hook operator=(Hook const&) = delete;
|
||||
|
||||
/**
|
||||
* Get the address of the function hooked.
|
||||
* @returns Address
|
||||
*/
|
||||
uintptr_t getAddress() const {
|
||||
return reinterpret_cast<uintptr_t>(m_address);
|
||||
}
|
||||
uintptr_t getAddress() const;
|
||||
|
||||
/**
|
||||
* Get the display name of the function hooked.
|
||||
* @returns Display name
|
||||
*/
|
||||
std::string_view getDisplayName() const {
|
||||
return m_displayName;
|
||||
}
|
||||
std::string_view getDisplayName() const;
|
||||
|
||||
/**
|
||||
* Get whether the hook is enabled or not.
|
||||
* @returns True if enabled, false if not.
|
||||
*/
|
||||
bool isEnabled() const {
|
||||
return m_enabled;
|
||||
}
|
||||
bool isEnabled() const;
|
||||
|
||||
/**
|
||||
* Get the owner of this hook.
|
||||
* @returns Pointer to the owner's Mod handle.
|
||||
*/
|
||||
Mod* getOwner() const {
|
||||
return m_owner;
|
||||
}
|
||||
Mod* getOwner() const;
|
||||
|
||||
/**
|
||||
* Get info about the hook as JSON
|
||||
* @note For IPC
|
||||
*/
|
||||
nlohmann::json getRuntimeInfo() const;
|
||||
|
||||
/**
|
||||
* Get the metadata of the hook.
|
||||
* @returns Hook metadata
|
||||
*/
|
||||
tulip::hook::HookMetadata getHookMetadata() const;
|
||||
|
||||
/**
|
||||
* Set the metadata of the hook.
|
||||
* @param metadata Hook metadata
|
||||
*/
|
||||
void setHookMetadata(tulip::hook::HookMetadata const& metadata);
|
||||
|
||||
/**
|
||||
* Get the priority of the hook.
|
||||
* @returns Priority
|
||||
*/
|
||||
int32_t getPriority() const;
|
||||
|
||||
/**
|
||||
* Set the priority of the hook.
|
||||
* @param priority Priority
|
||||
*/
|
||||
void setPriority(int32_t priority);
|
||||
|
||||
/**
|
||||
* Get whether the hook should be auto enabled or not.
|
||||
* @returns Auto enable
|
||||
*/
|
||||
bool getAutoEnable() const;
|
||||
|
||||
/**
|
||||
* Set whether the hook should be auto enabled or not.
|
||||
* @param autoEnable Auto enable
|
||||
*/
|
||||
void setAutoEnable(bool autoEnable);
|
||||
};
|
||||
|
||||
class GEODE_DLL Patch {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Event.hpp"
|
||||
#include "Loader.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
|
||||
namespace geode {
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
|
@ -31,7 +32,7 @@ namespace geode {
|
|||
public:
|
||||
std::string targetModID;
|
||||
std::string messageID;
|
||||
nlohmann::json messageData;
|
||||
std::unique_ptr<nlohmann::json> messageData;
|
||||
nlohmann::json& replyData;
|
||||
|
||||
friend class IPCFilter;
|
||||
|
@ -62,11 +63,5 @@ namespace geode {
|
|||
);
|
||||
};
|
||||
|
||||
template<class = void>
|
||||
std::monostate listenForIPC(std::string const& messageID, nlohmann::json(*callback)(IPCEvent*)) {
|
||||
(void) new EventListener(
|
||||
callback, IPCFilter(getMod()->getID(), messageID)
|
||||
);
|
||||
return std::monostate();
|
||||
}
|
||||
std::monostate listenForIPC(std::string const& messageID, nlohmann::json(*callback)(IPCEvent*));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace geode {
|
|||
#pragma warning(disable : 4251)
|
||||
|
||||
class Mod;
|
||||
inline Mod* getMod();
|
||||
Mod* getMod();
|
||||
|
||||
namespace log {
|
||||
using log_clock = std::chrono::system_clock;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include "../cocos/support/zip_support/ZipUtils.h"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
#include "../utils/VersionInfo.hpp"
|
||||
#include "../utils/general.hpp"
|
||||
|
@ -16,6 +16,7 @@
|
|||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <tulip/TulipHook.hpp>
|
||||
|
||||
namespace geode {
|
||||
template <class T>
|
||||
|
@ -110,51 +111,16 @@ namespace geode {
|
|||
nlohmann::json& getSaveContainer();
|
||||
|
||||
template <class T>
|
||||
T getSettingValue(std::string const& key) const {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
return SettingValueSetter<T>::get(sett);
|
||||
}
|
||||
return T();
|
||||
}
|
||||
T getSettingValue(std::string const& key) const;
|
||||
|
||||
template <class T>
|
||||
T setSettingValue(std::string const& key, T const& value) {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
auto old = this->getSettingValue<T>(sett);
|
||||
SettingValueSetter<T>::set(sett, value);
|
||||
return old;
|
||||
}
|
||||
return T();
|
||||
}
|
||||
T setSettingValue(std::string const& key, T const& value);
|
||||
|
||||
template <class T>
|
||||
T getSavedValue(std::string const& key) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
if (saved.count(key)) {
|
||||
try {
|
||||
// json -> T may fail
|
||||
return saved.at(key);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
return T();
|
||||
}
|
||||
T getSavedValue(std::string const& key);
|
||||
|
||||
template <class T>
|
||||
T getSavedValue(std::string const& key, T const& defaultValue) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
if (saved.count(key)) {
|
||||
try {
|
||||
// json -> T may fail
|
||||
return saved.at(key);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
saved[key] = defaultValue;
|
||||
return defaultValue;
|
||||
}
|
||||
T getSavedValue(std::string const& key, T const& defaultValue);
|
||||
|
||||
/**
|
||||
* Set the value of an automatically saved variable. When the game is
|
||||
|
@ -164,17 +130,11 @@ namespace geode {
|
|||
* @returns The old value
|
||||
*/
|
||||
template<class T>
|
||||
T setSavedValue(std::string const& key, T const& value) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
auto old = this->getSavedValue<T>(key);
|
||||
saved[key] = value;
|
||||
return old;
|
||||
}
|
||||
T setSavedValue(std::string const& key, T const& value);
|
||||
|
||||
/**
|
||||
* Get the mod container stored in the Interface
|
||||
* @returns nullptr if Interface is not initialized,
|
||||
* the mod pointer if it is initialized
|
||||
* Get the Mod of the current mod being developed
|
||||
* @returns The current mod
|
||||
*/
|
||||
template <class = void>
|
||||
static inline GEODE_HIDDEN Mod* get() {
|
||||
|
@ -197,31 +157,20 @@ namespace geode {
|
|||
* @param address The absolute address of
|
||||
* the function to hook, i.e. gd_base + 0xXXXX
|
||||
* @param detour Pointer to your detour function
|
||||
* @param displayName Name of the hook that will be
|
||||
* displayed in the hook list
|
||||
* @param hookMetadata Metadata of the hook
|
||||
* @returns Successful result containing the
|
||||
* Hook handle, errorful result with info on
|
||||
* Hook pointer, errorful result with info on
|
||||
* error
|
||||
*/
|
||||
template <auto Detour, template <class, class...> class Convention>
|
||||
Result<Hook*> addHook(void* address) {
|
||||
return this->addHook<Detour, Convention>("", address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hook at an address. Call the original
|
||||
* function by calling the original function –
|
||||
* no trampoline needed. Also takes a displayName
|
||||
* parameter to use for when visualizing the hook.
|
||||
* @param address The absolute address of
|
||||
* the function to hook, i.e. gd_base + 0xXXXX
|
||||
* @param detour Pointer to your detour function
|
||||
* @returns Successful result containing the
|
||||
* Hook handle, errorful result with info on
|
||||
* error
|
||||
*/
|
||||
template <auto Detour, template <class, class...> class Convention>
|
||||
Result<Hook*> addHook(std::string const& displayName, void* address) {
|
||||
auto hook =
|
||||
Hook::create<Detour, Convention>((decltype(Detour))address, displayName, this);
|
||||
template <class Convention, class DetourType>
|
||||
Result<Hook*> addHook(
|
||||
void* address, DetourType detour,
|
||||
std::string const& displayName = "",
|
||||
tulip::hook::HookMetadata const& hookMetadata = tulip::hook::HookMetadata()
|
||||
) {
|
||||
auto hook = Hook::create<Convention>(this, address, detour, displayName, hookMetadata);
|
||||
return this->addHook(hook);
|
||||
}
|
||||
|
||||
|
@ -346,16 +295,6 @@ namespace geode {
|
|||
|
||||
friend class ModImpl;
|
||||
};
|
||||
|
||||
/**
|
||||
* To bypass the need for cyclic dependencies,
|
||||
* this function does the exact same as Mod::get()
|
||||
* However, it can be externed, unlike Mod::get()
|
||||
* @returns Same thing Mod::get() returns
|
||||
*/
|
||||
inline GEODE_HIDDEN Mod* getMod() {
|
||||
return Mod::get();
|
||||
}
|
||||
}
|
||||
|
||||
inline char const* operator"" _spr(char const* str, size_t) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
namespace geode {
|
||||
class Mod;
|
||||
inline Mod* getMod();
|
||||
Mod* getMod();
|
||||
|
||||
enum class ModEventType {
|
||||
Loaded,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include "../utils/VersionInfo.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
#include "Setting.hpp"
|
||||
|
@ -157,7 +157,7 @@ namespace geode {
|
|||
static bool validateID(std::string const& id);
|
||||
|
||||
private:
|
||||
ModJson m_rawJSON;
|
||||
std::shared_ptr<ModJson> m_rawJSON;
|
||||
|
||||
/**
|
||||
* Version is passed for backwards
|
||||
|
|
59
loader/include/Geode/loader/ModJsonTest.hpp
Normal file
59
loader/include/Geode/loader/ModJsonTest.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "Mod.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
|
||||
namespace geode {
|
||||
template <class T>
|
||||
T Mod::getSettingValue(std::string const& key) const {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
return SettingValueSetter<T>::get(sett);
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Mod::setSettingValue(std::string const& key, T const& value) {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
auto old = this->getSettingValue<T>(sett);
|
||||
SettingValueSetter<T>::set(sett, value);
|
||||
return old;
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Mod::getSavedValue(std::string const& key) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
if (saved.count(key)) {
|
||||
try {
|
||||
// json -> T may fail
|
||||
return saved.at(key);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Mod::getSavedValue(std::string const& key, T const& defaultValue) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
if (saved.count(key)) {
|
||||
try {
|
||||
// json -> T may fail
|
||||
return saved.at(key);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
saved[key] = defaultValue;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T Mod::setSavedValue(std::string const& key, T const& value) {
|
||||
auto& saved = this->getSaveContainer();
|
||||
auto old = this->getSavedValue<T>(key);
|
||||
saved[key] = value;
|
||||
return old;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
#include "Types.hpp"
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include "../utils/JsonValidation.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
#include "../utils/file.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
|
||||
|
@ -16,6 +15,11 @@ namespace geode {
|
|||
class SettingNode;
|
||||
class SettingValue;
|
||||
|
||||
template <class Json>
|
||||
struct JsonMaybeObject;
|
||||
template <class Json>
|
||||
struct JsonMaybeValue;
|
||||
|
||||
struct GEODE_DLL BoolSetting final {
|
||||
using ValueType = bool;
|
||||
|
||||
|
@ -114,7 +118,7 @@ namespace geode {
|
|||
};
|
||||
|
||||
struct GEODE_DLL CustomSetting final {
|
||||
ModJson json;
|
||||
std::shared_ptr<ModJson> json;
|
||||
};
|
||||
|
||||
using SettingKind = std::variant<
|
||||
|
@ -190,18 +194,8 @@ namespace geode {
|
|||
m_definition(definition),
|
||||
m_value(definition.defaultValue) {}
|
||||
|
||||
bool load(nlohmann::json const& json) override {
|
||||
try {
|
||||
m_value = json.get<ValueType>();
|
||||
return true;
|
||||
} catch(...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool save(nlohmann::json& json) const {
|
||||
json = m_value;
|
||||
return true;
|
||||
}
|
||||
bool load(nlohmann::json const& json) override;
|
||||
bool save(nlohmann::json& json) const;
|
||||
|
||||
GEODE_DLL SettingNode* createNode(float width) override;
|
||||
T castDefinition() const {
|
||||
|
|
21
loader/include/Geode/loader/SettingJsonTest.hpp
Normal file
21
loader/include/Geode/loader/SettingJsonTest.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "Setting.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
|
||||
namespace geode {
|
||||
template<class T>
|
||||
bool GeodeSettingValue<T>::load(nlohmann::json const& json) {
|
||||
try {
|
||||
m_value = json.get<ValueType>();
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool GeodeSettingValue<T>::save(nlohmann::json& json) const {
|
||||
json = m_value;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include "../platform/cplatform.h"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#pragma once
|
||||
#include "Types.hpp"
|
||||
|
||||
#include <Geode/utils/addresser.hpp>
|
||||
|
||||
namespace geode::modifier {
|
||||
struct addresses {
|
||||
#include <Geode/GeneratedAddress.hpp>
|
||||
};
|
||||
template <uint32_t Id>
|
||||
uintptr_t address();
|
||||
}
|
||||
|
|
40
loader/include/Geode/modify/AsStaticFunction.hpp
Normal file
40
loader/include/Geode/modify/AsStaticFunction.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include "../utils/addresser.hpp"
|
||||
#include "Traits.hpp"
|
||||
#include "../loader/Log.hpp"
|
||||
|
||||
namespace geode::modifier {
|
||||
/**
|
||||
* A helper struct that generates a static function that calls the given function.
|
||||
*/
|
||||
#define GEODE_AS_STATIC_FUNCTION(FunctionName_) \
|
||||
template <class Class2, auto Function> \
|
||||
struct AsStaticFunction_##FunctionName_ { \
|
||||
template <class FunctionType2> \
|
||||
struct Impl {}; \
|
||||
template <class Return, class... Params> \
|
||||
struct Impl<Return (*)(Params...)> { \
|
||||
static Return GEODE_CDECL_CALL function(Params... params) { \
|
||||
return Class2::FunctionName_(params...); \
|
||||
} \
|
||||
}; \
|
||||
template <class Return, class Class, class... Params> \
|
||||
struct Impl<Return (Class::*)(Params...)> { \
|
||||
static Return GEODE_CDECL_CALL function(Class* self, Params... params) { \
|
||||
auto self2 = addresser::rthunkAdjust(Function, self); \
|
||||
return self2->Class2::FunctionName_(params...); \
|
||||
} \
|
||||
}; \
|
||||
template <class Return, class Class, class... Params> \
|
||||
struct Impl<Return (Class::*)(Params...) const> { \
|
||||
static Return GEODE_CDECL_CALL function(Class const* self, Params... params) { \
|
||||
auto self2 = addresser::rthunkAdjust(Function, self); \
|
||||
return self2->Class2::FunctionName_(params...); \
|
||||
} \
|
||||
}; \
|
||||
static constexpr auto value = &Impl<decltype(Function)>::function; \
|
||||
};
|
||||
|
||||
GEODE_AS_STATIC_FUNCTION(constructor)
|
||||
GEODE_AS_STATIC_FUNCTION(destructor)
|
||||
}
|
|
@ -1,37 +1,89 @@
|
|||
#pragma once
|
||||
#include "../meta/meta.hpp"
|
||||
#include "Addresses.hpp"
|
||||
#include "AsStaticFunction.hpp"
|
||||
#include "Field.hpp"
|
||||
#include "Types.hpp"
|
||||
#include "Wrapper.hpp"
|
||||
#include "IDManager.hpp"
|
||||
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <iostream>
|
||||
#include "IDManager.hpp"
|
||||
#include <tulip/TulipHook.hpp>
|
||||
|
||||
#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() \
|
||||
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(AddressIndex_, Convention_, ClassName_, FunctionName_, ...) \
|
||||
do { \
|
||||
constexpr auto b = Resolve<__VA_ARGS__>::func(&Base::FunctionName_); \
|
||||
constexpr auto d = Resolve<__VA_ARGS__>::func(&Derived::FunctionName_); \
|
||||
if constexpr (Unique::different<b, d>()) { \
|
||||
auto hook = Hook::create<Convention_>( \
|
||||
Mod::get(), \
|
||||
reinterpret_cast<void*>(address<AddressIndex_>()), \
|
||||
AsStaticFunction_##FunctionName_<Derived, d>::value, \
|
||||
#ClassName_ "::" #FunctionName_ \
|
||||
); \
|
||||
}
|
||||
this->m_hooks[#ClassName_ "::" #FunctionName_] = hook; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define GEODE_APPLY_MODIFY_FOR_CONSTRUCTOR(AddressIndex_, Convention_, ClassName_, ...) \
|
||||
do { \
|
||||
if constexpr (HasConstructor<Derived>) { \
|
||||
constexpr auto d = Resolve<__VA_ARGS__>::func(&Derived::constructor); \
|
||||
auto hook = Hook::create<Convention_>( \
|
||||
Mod::get(), \
|
||||
reinterpret_cast<void*>(address<AddressIndex_>()), \
|
||||
AsStaticFunction_##constructor<Derived, d>::value, \
|
||||
#ClassName_ "::" #ClassName_ \
|
||||
); \
|
||||
this->m_hooks[#ClassName_ "::" #ClassName_] = hook; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define GEODE_APPLY_MODIFY_FOR_DESTRUCTOR(AddressIndex_, Convention_, ClassName_) \
|
||||
do { \
|
||||
if constexpr (HasDestructor<Derived>) { \
|
||||
constexpr auto d = Resolve<>::func(&Derived::destructor); \
|
||||
auto hook = Hook::create<Convention_>( \
|
||||
Mod::get(), \
|
||||
reinterpret_cast<void*>(address<AddressIndex_>()), \
|
||||
AsStaticFunction_##destructor<Derived, d>::value, \
|
||||
#ClassName_ "::" #ClassName_ \
|
||||
); \
|
||||
this->m_hooks[#ClassName_ "::" #ClassName_] = hook; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
namespace geode::modifier {
|
||||
|
||||
template <class Derived, class Base>
|
||||
class ModifyDerive;
|
||||
|
||||
template <class Derived>
|
||||
template <class ModifyDerived>
|
||||
class ModifyBase {
|
||||
public:
|
||||
std::map<std::string, Hook*> m_hooks;
|
||||
|
||||
Result<Hook*> getHook(std::string const& name) {
|
||||
if (m_hooks.find(name) == m_hooks.end()) {
|
||||
return Err("Hook not in this modify");
|
||||
}
|
||||
return Ok(m_hooks[name]);
|
||||
}
|
||||
|
||||
// unordered_map<handles> idea
|
||||
ModifyBase() {
|
||||
Derived::apply();
|
||||
// i really dont want to recompile codegen
|
||||
auto test = static_cast<ModifyDerived*>(this);
|
||||
test->ModifyDerived::apply();
|
||||
ModifyDerived::Derived::onModify(*this);
|
||||
for (auto& [uuid, hook] : m_hooks) {
|
||||
auto res = Mod::get()->addHook(hook);
|
||||
if (!res) {
|
||||
log::error("Failed to add hook {}: {}", hook->getDisplayName(), res.error());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void apply() {}
|
||||
template <class, class>
|
||||
friend class ModifyDerive;
|
||||
// explicit Modify(Property property) idea
|
||||
|
@ -61,12 +113,18 @@ namespace geode {
|
|||
// we already have utilities for these, which are ccdestructor
|
||||
// and the monostate constructor
|
||||
Modify() : Base(std::monostate(), sizeof(Base)) {}
|
||||
|
||||
~Modify() {
|
||||
cocos2d::CCDestructor::lock(this) = true;
|
||||
}
|
||||
|
||||
Modify(Modify const&) = delete;
|
||||
Modify(Modify&&) = delete;
|
||||
Modify& operator=(Modify const&) = delete;
|
||||
Modify& operator=(Modify&&) = delete;
|
||||
|
||||
modifier::FieldIntermediate<Derived, Base> m_fields;
|
||||
|
||||
static void onModify(auto& self) {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <Geode/meta/common.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace geode::modifier {
|
||||
|
@ -28,8 +27,6 @@ namespace geode::modifier {
|
|||
using type = FunctionType*;
|
||||
};
|
||||
|
||||
using ::geode::core::meta::always_false;
|
||||
|
||||
/**
|
||||
* The ~unevaluated~ function that gets the appropriate
|
||||
* version of a function type from its return, parameters, and classes.
|
||||
|
@ -58,11 +55,151 @@ namespace geode::modifier {
|
|||
* function pointers.
|
||||
*/
|
||||
template <auto a>
|
||||
struct function_uuid {
|
||||
struct FunctionUUID {
|
||||
private:
|
||||
constexpr static void function() {}
|
||||
|
||||
public:
|
||||
constexpr static inline void (*value)() = &function_uuid::function;
|
||||
constexpr static inline void (*value)() = &FunctionUUID::function;
|
||||
};
|
||||
|
||||
/**
|
||||
* A type trait that removes the class from a member function pointer.
|
||||
*/
|
||||
template <class Func>
|
||||
struct RemoveClass {
|
||||
using type = Func;
|
||||
};
|
||||
|
||||
template <class Return, class Class, class... Params>
|
||||
struct RemoveClass<Return(Class::*)(Params...)> {
|
||||
using type = Return(Params...);
|
||||
};
|
||||
|
||||
template <class Return, class Class, class... Params>
|
||||
struct RemoveClass<Return(Class::*)(Params...) const> {
|
||||
using type = Return(Params...);
|
||||
};
|
||||
|
||||
template <class Func>
|
||||
using RemoveClassType = typename RemoveClass<Func>::type;
|
||||
|
||||
/**
|
||||
* A helper struct that allows for checking if two function pointers
|
||||
* are the same or different.
|
||||
*/
|
||||
struct Unique {
|
||||
using ValueType = void(*)(...);
|
||||
static constexpr auto nvalue = static_cast<void(*)(...)>(nullptr);
|
||||
|
||||
template <auto Value>
|
||||
struct Impl {
|
||||
static void unique(...) {};
|
||||
|
||||
static constexpr auto value = &unique;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Impl<nvalue> {
|
||||
static constexpr auto value = nvalue;
|
||||
};
|
||||
|
||||
template <auto Value>
|
||||
static constexpr auto value = Impl<Value>::value;
|
||||
|
||||
|
||||
/**
|
||||
* Checks if two function pointers are the same. If their types are
|
||||
* different, returns false.
|
||||
*/
|
||||
template <auto p1, auto p2>
|
||||
static constexpr auto same() {
|
||||
if (!std::is_same_v<RemoveClassType<decltype(p1)>, RemoveClassType<decltype(p2)>>) return false;
|
||||
auto v1 = value<p1>;
|
||||
auto v2 = value<p2>;
|
||||
if (v1 == nvalue) return false;
|
||||
if (v2 == nvalue) return false;
|
||||
return v1 == v2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if two function pointers are different. If their types are
|
||||
* different, returns false.
|
||||
*/
|
||||
template <auto p1, auto p2>
|
||||
static constexpr auto different() {
|
||||
if (!std::is_same_v<RemoveClassType<decltype(p1)>, RemoveClassType<decltype(p2)>>) return false;
|
||||
auto v1 = value<p1>;
|
||||
auto v2 = value<p2>;
|
||||
if (v1 == nvalue) return false;
|
||||
if (v2 == nvalue) return false;
|
||||
return v1 != v2;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helps resolving an overloaded function pointer to a specific function using
|
||||
* its parameter types as the hint.
|
||||
*/
|
||||
template <class... Params>
|
||||
struct Resolve {
|
||||
template <class Return>
|
||||
static constexpr auto func(Return(*ptr)(std::type_identity_t<Params>...)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(std::type_identity_t<Params>...)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(std::type_identity_t<Params>...) const) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static constexpr auto func(...) {
|
||||
return Unique::nvalue;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A specialization for giving the variadic types as a single type with the
|
||||
* function type. The return type is ignored.
|
||||
*/
|
||||
template <class... Params>
|
||||
struct Resolve<void(Params...)> : Resolve<Params...> {
|
||||
using Resolve<Params...>::func;
|
||||
};
|
||||
|
||||
/**
|
||||
* A type trait that checks if a class has a function called "constructor".
|
||||
*/
|
||||
template <class Class>
|
||||
concept HasConstructor = requires {
|
||||
&Class::constructor;
|
||||
};
|
||||
|
||||
/**
|
||||
* A type trait that checks if a class has a function called "destructor".
|
||||
*/
|
||||
template <class Class>
|
||||
concept HasDestructor = requires {
|
||||
&Class::destructor;
|
||||
};
|
||||
|
||||
template <class FunctionType>
|
||||
struct AsStaticType {
|
||||
using type = FunctionType;
|
||||
};
|
||||
|
||||
template <class Return, class Class, class... Params>
|
||||
struct AsStaticType<Return(Class::*)(Params...)> {
|
||||
using type = Return(*)(Class*, Params...);
|
||||
};
|
||||
|
||||
template <class Return, class Class, class... Params>
|
||||
struct AsStaticType<Return(Class::*)(Params...) const> {
|
||||
using type = Return(*)(Class const*, Params...);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <Geode/Bindings.hpp>
|
||||
|
||||
namespace geode::modifier {
|
||||
struct types {
|
||||
#include <Geode/GeneratedType.hpp>
|
||||
};
|
||||
// struct types {
|
||||
// #include <Geode/GeneratedType.hpp>
|
||||
// };
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
#pragma once
|
||||
#include "../utils/addresser.hpp"
|
||||
#include "Traits.hpp"
|
||||
|
||||
#define GEODE_WRAPPER_FOR_IDENTIFIER(identifier) \
|
||||
/* Default - function Return Class::identifier(Parameters...) does not exist */ \
|
||||
template <class Class, class FunctionType, class = void> \
|
||||
struct identifier { \
|
||||
public: \
|
||||
constexpr static inline auto value = nullptr; \
|
||||
constexpr static inline auto uuid = nullptr; \
|
||||
}; \
|
||||
/* Specialization - function Return Class::identifier(Parameters...) is a member function */ \
|
||||
template <class Class, class Return, class... Parameters> \
|
||||
struct identifier< \
|
||||
Class, Return(Parameters...), \
|
||||
std::enable_if_t<std::is_member_function_pointer_v< \
|
||||
decltype(substitute<Return(Parameters...)>(&Class::identifier))>>> { \
|
||||
private: \
|
||||
static Return wrapperImpl(Class* self, Parameters... ps) { \
|
||||
self = addresser::rthunkAdjust( \
|
||||
substitute<Return(Parameters...)>(&Class::identifier), self \
|
||||
); \
|
||||
return self->Class::identifier(ps...); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
constexpr static inline auto value = &wrapperImpl; \
|
||||
constexpr static inline auto uuid = \
|
||||
function_uuid<substitute<Return(Parameters...)>(&Class::identifier)>::value; \
|
||||
}; \
|
||||
/* Specialization - function Return Class::identifier(Parameters...) is a static function */ \
|
||||
template <class Class, class Return, class... Parameters> \
|
||||
struct identifier< \
|
||||
Class, Return(Parameters...), \
|
||||
std::enable_if_t< \
|
||||
std::is_pointer_v<decltype(substitute<Return(Parameters...)>(&Class::identifier))>>> { \
|
||||
private: \
|
||||
static Return wrapperImpl(Parameters... ps) { \
|
||||
return Class::identifier(ps...); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
constexpr static inline auto value = &wrapperImpl; \
|
||||
constexpr static inline auto uuid = \
|
||||
function_uuid<substitute<Return(Parameters...)>(&Class::identifier)>::value; \
|
||||
};
|
||||
|
||||
namespace geode::modifier {
|
||||
namespace wrap {
|
||||
GEODE_WRAPPER_FOR_IDENTIFIER(constructor)
|
||||
GEODE_WRAPPER_FOR_IDENTIFIER(destructor)
|
||||
};
|
||||
|
||||
// template <template<class, class, class=void> class Identifier, class Base, class Derived,
|
||||
// class ...Types> struct PotentiallyWrongIdentifier {
|
||||
|
||||
// template <typename D>
|
||||
// static std::true_type existsImpl(...);
|
||||
|
||||
// template <typename D, typename = std::enable_if_t<
|
||||
// (... && (
|
||||
// Identifier<D, Types>::uuid == nullptr ||
|
||||
// Identifier<Base, Types>::uuid == Identifier<D, Types>::uuid
|
||||
// ))
|
||||
// >>
|
||||
// static std::false_type existsImpl(char);
|
||||
|
||||
// template <typename D, typename = std::enable_if_t<
|
||||
// (... || (
|
||||
// Identifier<D, Types>::uuid != nullptr &&
|
||||
// Identifier<Base, Types>::uuid == Identifier<D, Types>::uuid
|
||||
// ))
|
||||
// >>
|
||||
// static std::false_type existsImpl(int);
|
||||
|
||||
// static constexpr bool value = decltype(existsImpl<Derived>(0))::value;
|
||||
|
||||
// };
|
||||
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
#define GEODE_IS_DESKTOP
|
||||
#define GEODE_PLATFORM_NAME "Windows"
|
||||
#define GEODE_CALL __stdcall
|
||||
#define GEODE_CDECL_CALL __cdecl
|
||||
#define GEODE_PLATFORM_EXTENSION ".dll"
|
||||
#define GEODE_PLATFORM_SHORT_IDENTIFIER "win"
|
||||
#define CC_TARGET_OS_WIN32
|
||||
|
@ -44,6 +45,7 @@
|
|||
#define CC_TARGET_OS_MAC
|
||||
#endif
|
||||
#define GEODE_CALL
|
||||
#define GEODE_CDECL_CALL
|
||||
#else
|
||||
#define GEODE_MACOS(...)
|
||||
#define GEODE_IOS(...)
|
||||
|
@ -56,6 +58,7 @@
|
|||
#define GEODE_IS_MOBILE
|
||||
#define GEODE_PLATFORM_NAME "Android"
|
||||
#define GEODE_CALL
|
||||
#define GEODE_CDECL_CALL
|
||||
#define GEODE_PLATFORM_EXTENSION ".so"
|
||||
#define GEODE_PLATFORM_SHORT_IDENTIFIER "android"
|
||||
#define CC_TARGET_OS_ANDROID
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include <string_view>
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include <tuple>
|
||||
#include "../utils/Result.hpp"
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <cstdlib>
|
||||
#include <stddef.h>
|
||||
#include <type_traits>
|
||||
#include "../utils/casts.hpp"
|
||||
|
||||
namespace geode::addresser {
|
||||
|
||||
|
@ -198,11 +199,19 @@ namespace geode::addresser {
|
|||
|
||||
template <typename T, typename F>
|
||||
inline F thunkAdjust(T func, F self) {
|
||||
// do NOT delete the line below.
|
||||
// doing so breaks thunk adjusting on windows.
|
||||
// why? bruh idk
|
||||
auto _ = *geode::cast::template union_cast<ptrdiff_t*>(&func);
|
||||
return (F)((intptr_t)self + Addresser::thunkOf(func));
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
inline F rthunkAdjust(T func, F self) {
|
||||
// do NOT delete the line below.
|
||||
// doing so breaks thunk adjusting on windows.
|
||||
// why? bruh idk
|
||||
auto _ = *geode::cast::template union_cast<ptrdiff_t*>(&func);
|
||||
return (F)((intptr_t)self - Addresser::thunkOf(func));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include "casts.hpp"
|
||||
#include "general.hpp"
|
||||
#include "../DefaultInclude.hpp"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "Result.hpp"
|
||||
#include "general.hpp"
|
||||
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <ghc/filesystem.hpp>
|
||||
#include <string>
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace geode {
|
|||
using ByteVector = std::vector<uint8_t>;
|
||||
|
||||
template <typename T>
|
||||
ByteVector to_byte_array(T const& a) {
|
||||
ByteVector toByteArray(T const& a) {
|
||||
ByteVector out;
|
||||
out.resize(sizeof(T));
|
||||
std::memcpy(out.data(), &a, sizeof(T));
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace std {
|
|||
}
|
||||
#endif
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace geode::utils::ranges {
|
||||
template <class C>
|
||||
concept ValidConstContainer = requires(C const& c) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include "../external/json/json.hpp"
|
||||
#include "../external/json/json_fwd.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "general.hpp"
|
||||
|
||||
|
@ -46,17 +46,7 @@ namespace geode::utils::web {
|
|||
* @param url URL to fetch
|
||||
* @returns Returned data as JSON, or error on error
|
||||
*/
|
||||
template <class Json = nlohmann::json>
|
||||
Result<Json> fetchJSON(std::string const& url) {
|
||||
std::string res;
|
||||
GEODE_UNWRAP_INTO(res, fetch(url));
|
||||
try {
|
||||
return Ok(Json::parse(res));
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
return Err(e.what());
|
||||
}
|
||||
}
|
||||
Result<nlohmann::json> fetchJSON(std::string const& url);
|
||||
|
||||
class SentAsyncWebRequest;
|
||||
template <class T>
|
||||
|
|
|
@ -14,11 +14,17 @@ void displayError(std::string alertMessage) {
|
|||
}
|
||||
|
||||
void loadGeode() {
|
||||
auto dylib = dlopen("Geode.dylib", RTLD_LAZY);
|
||||
if (dylib) return;
|
||||
|
||||
displayError(std::string("Couldn't open Geode: ") + dlerror());
|
||||
|
||||
auto dylib = dlopen("Geode.dylib", RTLD_NOW);
|
||||
if (!dylib) {
|
||||
displayError(std::string("Couldn't load Geode: ") + dlerror());
|
||||
return;
|
||||
}
|
||||
auto trigger = dlsym(dylib, "dynamicTrigger");
|
||||
if (!trigger) {
|
||||
displayError(std::string("Couldn't start Geode: ") + dlerror());
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<void(*)()>(trigger)();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
|
|||
CCSprite* m_geodeButton;
|
||||
|
||||
bool init() {
|
||||
log::debug("this: {}", this);
|
||||
|
||||
if (!MenuLayer::init()) return false;
|
||||
|
||||
// make sure to add the string IDs for nodes (Geode has no manual
|
||||
|
|
|
@ -7,14 +7,11 @@
|
|||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
using geode::core::meta::x86::Thiscall;
|
||||
|
||||
// for some reason RobTop uses MessageBoxW in his GLFW error handler.
|
||||
// no one knows how this is possible (he passes char* to wchar_t*).
|
||||
// so anyway, here's a fix for it
|
||||
|
||||
static auto CCEGLVIEW_CON_ADDR = reinterpret_cast<void*>(base::getCocos() + 0xc2860);
|
||||
|
||||
static void __cdecl fixedErrorHandler(int code, char const* description) {
|
||||
log::error("GLFW Error {}: {}", code, description);
|
||||
MessageBoxA(
|
||||
|
@ -28,20 +25,10 @@ static void __cdecl fixedErrorHandler(int code, char const* description) {
|
|||
);
|
||||
}
|
||||
|
||||
static CCEGLView* CCEGLView_CCEGLView(CCEGLView* self) {
|
||||
// you will never have to make a manual hook with Geode again, they said
|
||||
// it will be fun, they said
|
||||
reinterpret_cast<CCEGLView*(__thiscall*)(CCEGLView*)>(CCEGLVIEW_CON_ADDR)(self);
|
||||
static auto p = Mod::get()->patch(
|
||||
reinterpret_cast<void*>(geode::base::getCocos() + 0x19feec),
|
||||
to_byte_array(&fixedErrorHandler)
|
||||
);
|
||||
return self;
|
||||
}
|
||||
|
||||
$execute {
|
||||
(void)Mod::get()->addHook<&CCEGLView_CCEGLView, Thiscall>(
|
||||
"CCEGLView::CCEGLView", CCEGLVIEW_CON_ADDR
|
||||
(void)Mod::get()->patch(
|
||||
reinterpret_cast<void*>(geode::base::getCocos() + 0x19feec),
|
||||
toByteArray(&fixedErrorHandler)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "AddIDs.hpp"
|
||||
|
||||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/Modify.hpp>
|
||||
#include <Geode/modify/CreatorLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "AddIDs.hpp"
|
||||
|
||||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/Modify.hpp>
|
||||
#include <Geode/modify/LevelBrowserLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "AddIDs.hpp"
|
||||
|
||||
#include <Geode/Bindings.hpp>
|
||||
#include <Geode/Modify.hpp>
|
||||
#include <Geode/modify/LevelSettingsLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
@ -205,3 +205,25 @@ struct LevelSettingsLayerIDs : Modify<LevelSettingsLayerIDs, LevelSettingsLayer>
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class... Params>
|
||||
struct Resolve2 {
|
||||
template <class Return>
|
||||
static constexpr auto func(Return(*ptr)(float)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(float)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(float) const) {
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
#include <Geode/modify/PlayerObject.hpp>
|
||||
constexpr auto b = Resolve2<float>::func(&PlayerObject::runBallRotation);
|
|
@ -8,43 +8,74 @@
|
|||
#include "ModImpl.hpp"
|
||||
|
||||
#include <Geode/hook-core/Hook.hpp>
|
||||
#include "HookImpl.hpp"
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
Result<> Hook::enable() {
|
||||
if (!m_enabled) {
|
||||
auto res = std::invoke(m_addFunction, m_address);
|
||||
if (res) {
|
||||
log::debug("Enabling hook at function {}", m_displayName);
|
||||
m_enabled = true;
|
||||
m_handle = res.unwrap();
|
||||
return Ok();
|
||||
}
|
||||
else {
|
||||
return Err(
|
||||
"Unable to create hook at " + std::to_string(reinterpret_cast<uintptr_t>(m_address))
|
||||
Hook::Hook(std::shared_ptr<Impl>&& impl) : m_impl(std::move(impl)) {}
|
||||
Hook::~Hook() {}
|
||||
|
||||
Hook* Hook::create(
|
||||
Mod* owner,
|
||||
void* address,
|
||||
void* detour,
|
||||
std::string const& displayName,
|
||||
tulip::hook::HandlerMetadata const& handlerMetadata,
|
||||
tulip::hook::HookMetadata const& hookMetadata
|
||||
) {
|
||||
auto impl = std::make_shared<Hook::Impl>(
|
||||
address, detour, displayName, handlerMetadata, hookMetadata, owner
|
||||
);
|
||||
}
|
||||
return Err("Hook already has a handle");
|
||||
}
|
||||
return Ok();
|
||||
return new Hook(std::move(impl));
|
||||
}
|
||||
|
||||
Result<> Hook::disable() {
|
||||
if (m_enabled) {
|
||||
if (!geode::core::hook::remove(m_handle)) return Err("Unable to remove hook");
|
||||
|
||||
log::debug("Disabling hook at function {}", m_displayName);
|
||||
m_enabled = false;
|
||||
uintptr_t Hook::getAddress() const {
|
||||
return m_impl->getAddress();
|
||||
}
|
||||
return Ok();
|
||||
|
||||
std::string_view Hook::getDisplayName() const {
|
||||
return m_impl->getDisplayName();
|
||||
}
|
||||
|
||||
bool Hook::isEnabled() const {
|
||||
return m_impl->isEnabled();
|
||||
}
|
||||
|
||||
Mod* Hook::getOwner() const {
|
||||
return m_impl->getOwner();
|
||||
}
|
||||
|
||||
nlohmann::json Hook::getRuntimeInfo() const {
|
||||
auto json = nlohmann::json::object();
|
||||
json["address"] = reinterpret_cast<uintptr_t>(m_address);
|
||||
json["detour"] = reinterpret_cast<uintptr_t>(m_detour);
|
||||
json["name"] = m_displayName;
|
||||
json["enabled"] = m_enabled;
|
||||
return json;
|
||||
return m_impl->getRuntimeInfo();
|
||||
}
|
||||
|
||||
tulip::hook::HookMetadata Hook::getHookMetadata() const {
|
||||
return m_impl->getHookMetadata();
|
||||
}
|
||||
|
||||
void Hook::setHookMetadata(tulip::hook::HookMetadata const& metadata) {
|
||||
return m_impl->setHookMetadata(metadata);
|
||||
}
|
||||
|
||||
int32_t Hook::getPriority() const {
|
||||
return m_impl->getPriority();
|
||||
}
|
||||
|
||||
void Hook::setPriority(int32_t priority) {
|
||||
return m_impl->setPriority(priority);
|
||||
}
|
||||
|
||||
bool Hook::getAutoEnable() const {
|
||||
return m_impl->getAutoEnable();
|
||||
}
|
||||
|
||||
void Hook::setAutoEnable(bool autoEnable) {
|
||||
return m_impl->setAutoEnable(autoEnable);
|
||||
}
|
||||
|
||||
Result<> Hook::enable() {
|
||||
return m_impl->enable();
|
||||
}
|
||||
Result<> Hook::disable() {
|
||||
return m_impl->disable();
|
||||
}
|
104
loader/src/loader/HookImpl.cpp
Normal file
104
loader/src/loader/HookImpl.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "HookImpl.hpp"
|
||||
#include "LoaderImpl.hpp"
|
||||
|
||||
Hook::Impl::Impl(void* address, void* detour, std::string const& displayName, tulip::hook::HandlerMetadata const& handlerMetadata, tulip::hook::HookMetadata const& hookMetadata, Mod* owner) :
|
||||
m_address(address),
|
||||
m_detour(detour),
|
||||
m_displayName(displayName),
|
||||
m_handlerMetadata(handlerMetadata),
|
||||
m_hookMetadata(hookMetadata),
|
||||
m_owner(owner),
|
||||
m_enabled(false),
|
||||
m_autoEnable(true) {}
|
||||
Hook::Impl::~Impl() {
|
||||
if (m_enabled) {
|
||||
auto res = this->disable();
|
||||
if (!res) {
|
||||
log::error("Failed to disable hook: {}", res.unwrapErr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t Hook::Impl::getAddress() const {
|
||||
return reinterpret_cast<uintptr_t>(m_address);
|
||||
}
|
||||
std::string_view Hook::Impl::getDisplayName() const {
|
||||
return m_displayName;
|
||||
}
|
||||
bool Hook::Impl::isEnabled() const {
|
||||
return m_enabled;
|
||||
}
|
||||
Mod* Hook::Impl::getOwner() const {
|
||||
return m_owner;
|
||||
}
|
||||
nlohmann::json Hook::Impl::getRuntimeInfo() const {
|
||||
auto json = nlohmann::json::object();
|
||||
json["address"] = reinterpret_cast<uintptr_t>(m_address);
|
||||
json["detour"] = reinterpret_cast<uintptr_t>(m_detour);
|
||||
json["name"] = m_displayName;
|
||||
json["enabled"] = m_enabled;
|
||||
return json;
|
||||
}
|
||||
tulip::hook::HookMetadata Hook::Impl::getHookMetadata() const {
|
||||
return m_hookMetadata;
|
||||
}
|
||||
|
||||
Result<> Hook::Impl::enable() {
|
||||
if (!m_enabled) {
|
||||
if (!LoaderImpl::get()->hasHandler(m_address)) {
|
||||
GEODE_UNWRAP(LoaderImpl::get()->createHandler(m_address, m_handlerMetadata));
|
||||
}
|
||||
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
|
||||
|
||||
m_handle = tulip::hook::createHook(handler, m_detour, m_hookMetadata);
|
||||
log::debug("Enabling hook at function {} with address {}", m_displayName, m_address);
|
||||
m_enabled = true;
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Hook::Impl::disable() {
|
||||
if (m_enabled) {
|
||||
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
|
||||
|
||||
tulip::hook::removeHook(handler, m_handle);
|
||||
|
||||
log::debug("Disabling hook at function {}", m_displayName);
|
||||
m_enabled = false;
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Hook::Impl::updateMetadata() {
|
||||
if (m_enabled) {
|
||||
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
|
||||
|
||||
tulip::hook::updateHookMetadata(handler, m_handle, m_hookMetadata);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
void Hook::Impl::setHookMetadata(tulip::hook::HookMetadata const& metadata) {
|
||||
m_hookMetadata = metadata;
|
||||
auto res = this->updateMetadata();
|
||||
if (!res) {
|
||||
log::error("Failed to update hook metadata: {}", res.unwrapErr());
|
||||
}
|
||||
}
|
||||
int32_t Hook::Impl::getPriority() const {
|
||||
return m_hookMetadata.m_priority;
|
||||
}
|
||||
void Hook::Impl::setPriority(int32_t priority) {
|
||||
m_hookMetadata.m_priority = priority;
|
||||
auto res = this->updateMetadata();
|
||||
if (!res) {
|
||||
log::error("Failed to update hook priority: {}", res.unwrapErr());
|
||||
}
|
||||
}
|
||||
|
||||
bool Hook::Impl::getAutoEnable() const {
|
||||
return m_autoEnable;
|
||||
}
|
||||
|
||||
void Hook::Impl::setAutoEnable(bool autoEnable) {
|
||||
m_autoEnable = autoEnable;
|
||||
}
|
54
loader/src/loader/HookImpl.hpp
Normal file
54
loader/src/loader/HookImpl.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <Geode/loader/Hook.hpp>
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/utils/casts.hpp>
|
||||
#include <Geode/utils/ranges.hpp>
|
||||
#include <vector>
|
||||
// #include <hook/hook.hpp>
|
||||
#include "ModImpl.hpp"
|
||||
|
||||
#include <Geode/hook-core/Hook.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
class Hook::Impl {
|
||||
public:
|
||||
Impl(
|
||||
void* address,
|
||||
void* detour,
|
||||
std::string const& displayName,
|
||||
tulip::hook::HandlerMetadata const& handlerMetadata,
|
||||
tulip::hook::HookMetadata const& hookMetadata,
|
||||
Mod* owner
|
||||
);
|
||||
~Impl();
|
||||
|
||||
|
||||
void* m_address;
|
||||
void* m_detour;
|
||||
std::string m_displayName;
|
||||
tulip::hook::HandlerMetadata m_handlerMetadata;
|
||||
tulip::hook::HookMetadata m_hookMetadata;
|
||||
Mod* m_owner;
|
||||
tulip::hook::HookHandle m_handle;
|
||||
bool m_enabled = false;
|
||||
bool m_autoEnable = true;
|
||||
|
||||
|
||||
// Used by Mod
|
||||
Result<> enable();
|
||||
Result<> disable();
|
||||
Result<> updateMetadata();
|
||||
|
||||
uintptr_t getAddress() const;
|
||||
std::string_view getDisplayName() const;
|
||||
bool isEnabled() const;
|
||||
Mod* getOwner() const;
|
||||
nlohmann::json getRuntimeInfo() const;
|
||||
tulip::hook::HookMetadata getHookMetadata() const;
|
||||
void setHookMetadata(tulip::hook::HookMetadata const& metadata);
|
||||
int32_t getPriority() const;
|
||||
void setPriority(int32_t priority);
|
||||
bool getAutoEnable() const;
|
||||
void setAutoEnable(bool autoEnable);
|
||||
};
|
|
@ -1,7 +1,15 @@
|
|||
#include <Geode/loader/IPC.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
std::monostate geode::listenForIPC(std::string const& messageID, nlohmann::json(*callback)(IPCEvent*)) {
|
||||
(void) new EventListener(
|
||||
callback, IPCFilter(getMod()->getID(), messageID)
|
||||
);
|
||||
return std::monostate();
|
||||
}
|
||||
|
||||
IPCEvent::IPCEvent(
|
||||
void* rawPipeHandle,
|
||||
std::string const& targetModID,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <Geode/utils/string.hpp>
|
||||
#include <Geode/utils/map.hpp>
|
||||
#include <hash/hash.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/loader/ModJsonTest.hpp>
|
||||
#include <Geode/utils/file.hpp>
|
||||
#include <Geode/utils/map.hpp>
|
||||
#include <Geode/utils/ranges.hpp>
|
||||
|
@ -590,13 +591,14 @@ ResourceDownloadFilter::ResourceDownloadFilter() {}
|
|||
|
||||
void Loader::Impl::provideNextMod(Mod* mod) {
|
||||
m_nextModLock.lock();
|
||||
if (mod) {
|
||||
m_nextMod = mod;
|
||||
}
|
||||
}
|
||||
|
||||
Mod* Loader::Impl::takeNextMod() {
|
||||
if (!m_nextMod) {
|
||||
this->setupInternalMod();
|
||||
m_nextMod = Mod::sharedMod<>;
|
||||
m_nextMod = this->createInternalMod();
|
||||
}
|
||||
auto ret = m_nextMod;
|
||||
return ret;
|
||||
|
@ -607,3 +609,37 @@ void Loader::Impl::releaseNextMod() {
|
|||
|
||||
m_nextModLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
Result<> Loader::Impl::createHandler(void* address, tulip::hook::HandlerMetadata const& metadata) {
|
||||
if (m_handlerHandles.count(address)) {
|
||||
return Err("Handler already exists at address");
|
||||
}
|
||||
|
||||
GEODE_UNWRAP_INTO(auto handle, tulip::hook::createHandler(address, metadata));
|
||||
m_handlerHandles[address] = handle;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
bool Loader::Impl::hasHandler(void* address) {
|
||||
return m_handlerHandles.count(address) > 0;
|
||||
}
|
||||
|
||||
Result<tulip::hook::HandlerHandle> Loader::Impl::getHandler(void* address) {
|
||||
if (!m_handlerHandles.count(address)) {
|
||||
return Err("Handler does not exist at address");
|
||||
}
|
||||
|
||||
return Ok(m_handlerHandles[address]);
|
||||
}
|
||||
|
||||
Result<> Loader::Impl::removeHandler(void* address) {
|
||||
if (!m_handlerHandles.count(address)) {
|
||||
return Err("Handler does not exist at address");
|
||||
}
|
||||
|
||||
auto handle = m_handlerHandles[address];
|
||||
GEODE_UNWRAP(tulip::hook::removeHandler(handle));
|
||||
m_handlerHandles.erase(address);
|
||||
return Ok();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <tulip/TulipHook.hpp>
|
||||
|
||||
// TODO: Find a file convention for impl headers
|
||||
namespace geode {
|
||||
|
@ -64,6 +65,13 @@ namespace geode {
|
|||
Mod* takeNextMod();
|
||||
void releaseNextMod();
|
||||
|
||||
std::unordered_map<void*, tulip::hook::HandlerHandle> m_handlerHandles;
|
||||
|
||||
Result<> createHandler(void* address, tulip::hook::HandlerMetadata const& metadata);
|
||||
bool hasHandler(void* address);
|
||||
Result<tulip::hook::HandlerHandle> getHandler(void* address);
|
||||
Result<> removeHandler(void* address);
|
||||
|
||||
void downloadLoaderResources();
|
||||
|
||||
bool loadHooks();
|
||||
|
@ -126,7 +134,8 @@ namespace geode {
|
|||
bool isReadyToHook() const;
|
||||
void addInternalHook(Hook* hook, Mod* mod);
|
||||
|
||||
void setupInternalMod();
|
||||
Mod* createInternalMod();
|
||||
Result<> setupInternalMod();
|
||||
};
|
||||
|
||||
class LoaderImpl {
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/loader/ModEvent.hpp>
|
||||
#include <Geode/utils/file.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -19,8 +21,6 @@ Mod::Impl* ModImpl::getImpl(Mod* mod) {
|
|||
}
|
||||
|
||||
Mod::Impl::Impl(Mod* self, ModInfo const& info) : m_self(self), m_info(info) {
|
||||
m_saveDirPath = dirs::getModsSaveDir() / info.id;
|
||||
ghc::filesystem::create_directories(m_saveDirPath);
|
||||
}
|
||||
|
||||
Mod::Impl::~Impl() {
|
||||
|
@ -28,6 +28,9 @@ Mod::Impl::~Impl() {
|
|||
}
|
||||
|
||||
Result<> Mod::Impl::setup() {
|
||||
m_saveDirPath = dirs::getModsSaveDir() / m_info.id;
|
||||
ghc::filesystem::create_directories(m_saveDirPath);
|
||||
|
||||
this->setupSettings();
|
||||
auto loadRes = this->loadData();
|
||||
if (!loadRes) {
|
||||
|
@ -481,6 +484,9 @@ bool Mod::Impl::depends(std::string const& id) const {
|
|||
Result<> Mod::Impl::enableHook(Hook* hook) {
|
||||
auto res = hook->enable();
|
||||
if (res) m_hooks.push_back(hook);
|
||||
else {
|
||||
log::error("Can't enable hook {} for mod {}: {}", m_info.id, res.unwrapErr());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -491,10 +497,12 @@ Result<> Mod::Impl::disableHook(Hook* hook) {
|
|||
|
||||
Result<Hook*> Mod::Impl::addHook(Hook* hook) {
|
||||
if (LoaderImpl::get()->isReadyToHook()) {
|
||||
if (hook->getAutoEnable()) {
|
||||
auto res = this->enableHook(hook);
|
||||
if (!res) {
|
||||
delete hook;
|
||||
return Err("Can't create hook");
|
||||
return Err("Can't create hook: "+ res.unwrapErr());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -662,13 +670,14 @@ static ModInfo getModImplInfo() {
|
|||
}
|
||||
}
|
||||
|
||||
void Loader::Impl::setupInternalMod() {
|
||||
Mod* Loader::Impl::createInternalMod() {
|
||||
auto& mod = Mod::sharedMod<>;
|
||||
if (mod) return;
|
||||
if (!mod) {
|
||||
mod = new Mod(getModImplInfo());
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
auto setupRes = mod->m_impl->setup();
|
||||
if (!setupRes) {
|
||||
log::error("Failed to setup internal mod! ({})", setupRes.unwrapErr());
|
||||
}
|
||||
Result<> Loader::Impl::setupInternalMod() {
|
||||
return Mod::get()->m_impl->setup();
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
namespace geode {
|
||||
class Mod::Impl {
|
||||
public:
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/utils/file.hpp>
|
||||
#include <Geode/utils/string.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
|
||||
#include <about.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
@ -36,10 +39,9 @@ bool ModInfo::validateID(std::string const& id) {
|
|||
Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
||||
ModInfo info;
|
||||
|
||||
auto json = rawJson;
|
||||
info.m_rawJSON = rawJson;
|
||||
info.m_rawJSON = std::make_unique<ModJson>(rawJson);
|
||||
|
||||
JsonChecker checker(json);
|
||||
JsonChecker checker(*info.m_rawJSON);
|
||||
auto root = checker.root("[mod.json]").obj();
|
||||
|
||||
root.addKnownKey("geode");
|
||||
|
@ -242,14 +244,14 @@ std::vector<std::pair<std::string, std::optional<std::string>*>> ModInfo::getSpe
|
|||
}
|
||||
|
||||
ModJson ModInfo::toJSON() const {
|
||||
auto json = m_rawJSON;
|
||||
auto json = *m_rawJSON;
|
||||
json["path"] = this->path;
|
||||
json["binary"] = this->binaryName;
|
||||
return json;
|
||||
}
|
||||
|
||||
ModJson ModInfo::getRawJSON() const {
|
||||
return m_rawJSON;
|
||||
return *m_rawJSON;
|
||||
}
|
||||
|
||||
bool ModInfo::operator==(ModInfo const& other) const {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include <Geode/loader/Hook.hpp>
|
||||
#include <lilac/include/geode/core/hook/hook.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
bool Patch::apply() {
|
||||
return lilac::hook::write_memory(m_address, m_patch.data(), m_patch.size());
|
||||
return bool(tulip::hook::writeMemory(m_address, m_patch.data(), m_patch.size()));
|
||||
}
|
||||
|
||||
bool Patch::restore() {
|
||||
return lilac::hook::write_memory(m_address, m_original.data(), m_original.size());
|
||||
return bool(tulip::hook::writeMemory(m_address, m_original.data(), m_original.size()));
|
||||
}
|
||||
|
||||
nlohmann::json Patch::getRuntimeInfo() const {
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
#include <Geode/loader/Setting.hpp>
|
||||
#include <Geode/loader/SettingEvent.hpp>
|
||||
#include <Geode/loader/SettingNode.hpp>
|
||||
#include <Geode/loader/SettingJsonTest.hpp>
|
||||
#include <Geode/utils/general.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
#include <re2/re2.h>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
@ -131,7 +133,7 @@ Result<Setting> Setting::parse(
|
|||
|
||||
case hash("custom"): {
|
||||
sett.m_kind = CustomSetting {
|
||||
.json = obj.json()
|
||||
.json = std::make_shared<ModJson>(obj.json())
|
||||
};
|
||||
// skip checking unknown keys
|
||||
return Ok(sett);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <Geode/loader/Setting.hpp>
|
||||
#include <Geode/loader/SettingEvent.hpp>
|
||||
#include <loader/ModImpl.hpp>
|
||||
#include <Geode/loader/ModJsonTest.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
#include <array>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
@ -26,7 +28,7 @@ std::length_error::~length_error() _NOEXCEPT {} // do not ask...
|
|||
// from dynamic to static thats why she needs to define it
|
||||
// this is what old versions does to a silly girl
|
||||
|
||||
__attribute__((constructor)) void _entry() {
|
||||
void dynamicEntry() {
|
||||
auto dylib = dlopen("GeodeBootstrapper.dylib", RTLD_NOLOAD);
|
||||
dlclose(dylib);
|
||||
|
||||
|
@ -54,6 +56,13 @@ __attribute__((constructor)) void _entry() {
|
|||
geodeEntry(nullptr);
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) void dynamicTrigger() {
|
||||
std::thread(&dynamicEntry).detach();
|
||||
}
|
||||
|
||||
// remove when we can figure out how to not remove it
|
||||
auto dynamicTriggerRef = &dynamicTrigger;
|
||||
|
||||
#elif defined(GEODE_IS_WINDOWS)
|
||||
#include <Windows.h>
|
||||
|
||||
|
@ -120,7 +129,7 @@ $execute {
|
|||
listenForIPC("list-mods", [](IPCEvent* event) -> nlohmann::json {
|
||||
std::vector<nlohmann::json> res;
|
||||
|
||||
auto args = event->messageData;
|
||||
auto args = *event->messageData;
|
||||
JsonChecker checker(args);
|
||||
auto root = checker.root("").obj();
|
||||
|
||||
|
@ -155,12 +164,26 @@ int geodeEntry(void* platformData) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// set up internal mod, settings and data
|
||||
auto internalSetupRes = LoaderImpl::get()->setupInternalMod();
|
||||
if (!internalSetupRes) {
|
||||
LoaderImpl::get()->platformMessageBox(
|
||||
"Unable to Load Geode!",
|
||||
"There was an unknown fatal error setting up "
|
||||
"the internal mod and Geode can not be loaded." + internalSetupRes.unwrapErr()
|
||||
);
|
||||
LoaderImpl::get()->reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set up loader, load mods, etc.
|
||||
if (!LoaderImpl::get()->setup()) {
|
||||
auto setupRes = LoaderImpl::get()->setup();
|
||||
if (!setupRes) {
|
||||
LoaderImpl::get()->platformMessageBox(
|
||||
"Unable to Load Geode!",
|
||||
"There was an unknown fatal error setting up "
|
||||
"the loader and Geode can not be loaded. "
|
||||
"(" + setupRes.unwrapErr() + ")"
|
||||
);
|
||||
LoaderImpl::get()->reset();
|
||||
return 1;
|
||||
|
|
|
@ -662,7 +662,7 @@ CCObject* CCArray::randomObject()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
float r = CCRANDOM_0_1();
|
||||
float r = ((float)rand()/(float)RAND_MAX);
|
||||
|
||||
if (r == 1) // to prevent from accessing data-arr[data->num], out of range.
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <Geode/utils/VersionInfo.hpp>
|
||||
#include <Geode/utils/general.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <Geode/modify/LoadingLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <Geode/utils/file.hpp>
|
||||
#include <Geode/utils/map.hpp>
|
||||
#include <Geode/utils/string.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
#include <fstream>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/utils/casts.hpp>
|
||||
#include <Geode/utils/web.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
#include <thread>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
@ -97,6 +98,17 @@ Result<ByteVector> web::fetchBytes(std::string const& url) {
|
|||
return Err("Error getting info: " + std::string(curl_easy_strerror(res)));
|
||||
}
|
||||
|
||||
Result<nlohmann::json> web::fetchJSON(std::string const& url) {
|
||||
std::string res;
|
||||
GEODE_UNWRAP_INTO(res, fetch(url));
|
||||
try {
|
||||
return Ok(nlohmann::json::parse(res));
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
return Err(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
Result<std::string> web::fetch(std::string const& url) {
|
||||
auto curl = curl_easy_init();
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ USE_GEODE_NAMESPACE();
|
|||
|
||||
#include <Geode/modify/MenuLayer.hpp>
|
||||
#include <Geode/loader/SettingNode.hpp>
|
||||
#include <Geode/loader/ModJsonTest.hpp>
|
||||
|
||||
|
||||
enum class Icon {
|
||||
Steve,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <Geode/Loader.hpp>
|
||||
#include <Geode/loader/ModJsonTest.hpp>
|
||||
#include <Geode/loader/ModEvent.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
|
Loading…
Reference in a new issue