replace modify checking implementation

i got distracted
This commit is contained in:
altalk23 2023-01-14 22:24:12 +03:00
parent e47a5b4e27
commit a1be695aab
15 changed files with 334 additions and 156 deletions

View file

@ -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")

View file

@ -41,14 +41,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 +63,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";

View file

@ -33,7 +33,7 @@ int main(int argc, char** argv) try {
writeFile(writeDir / "GeneratedAddress.hpp", 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));

View file

@ -6,29 +6,16 @@
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>
{class_include}
using namespace geode::modifier;
namespace geode::modifier {{
{wrap}
{statics}
template<class Der>
struct ModifyDerive<Der, {class_name}> : ModifyBase<ModifyDerive<Der, {class_name}>> {{
using BaseModify = ModifyBase<ModifyDerive<Der, {class_name}>>;
@ -38,11 +25,24 @@ namespace geode::modifier {{
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(
}
@ -68,45 +68,70 @@ 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::getModifyConvention(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, ", "))
);
}
}

View file

@ -18,14 +18,14 @@ using namespace geode::modifier; // types
)CAC";
char const* declare_member = R"GEN(
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
return func(this{parameter_comma}{arguments});
}}
)GEN";
char const* declare_virtual = R"GEN(
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
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});
@ -33,7 +33,7 @@ types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
)GEN";
char const* declare_static = R"GEN(
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
auto {class_name}::{function_name}({parameters}){const} -> decltype({function_name}({arguments})) {{
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
return func({arguments});
}}

View file

@ -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"
)

View file

@ -57,7 +57,6 @@ NS_CC_BEGIN
class CC_DLL CCLabelTTF : public CCSprite, public CCLabelProtocol
{
GEODE_FRIEND_MODIFY
GEODE_FRIEND_MODIFY
public:
/**

View file

@ -113,20 +113,25 @@ It's new in cocos2d-x since v0.99.5
* macro.
*/
class GeodeNodeMetadata;
namespace geode {
struct modify;
namespace modifier {
struct addresses;
struct types;
namespace geode {
struct modify;
namespace modifier {
struct types;
class FieldContainer;
}
template <class Derived, class Base>
class ModifyDerive;
}
}
#define GEODE_FRIEND_MODIFY GEODE_ADD(\
friend struct ::geode::modify;\
friend struct ::geode::modifier::addresses;\
friend struct ::geode::modifier::types;\
friend class ::GeodeNodeMetadata;\
)
#define GEODE_FRIEND_MODIFY \
friend struct ::geode::modify; \
template <class Derived, class Base> \
friend class ::geode::modifier::ModifyDerive; \
friend struct ::geode::modifier::types; \
friend class ::GeodeNodeMetadata;
#define GEODE_ADD(...) __VA_ARGS__
#ifdef __cplusplus

View file

@ -0,0 +1,37 @@
#pragma once
#include "../utils/addresser.hpp"
#include "Traits.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 function(Params... params) { return Class2::FunctionName_(params...); } \
}; \
template <class Return, class Class, class... Params> \
struct Impl<Return (Class::*)(Params...)> { \
static Return 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 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)
}

View file

@ -1,29 +1,57 @@
#pragma once
#include "../meta/meta.hpp"
#include "Addresses.hpp"
#include "AsStaticFunction.hpp"
#include "Field.hpp"
#include "IDManager.hpp"
#include "Types.hpp"
#include "Wrapper.hpp"
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Mod.hpp>
#include <iostream>
#include <tulip/TulipHook.hpp>
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(addr_index, pure_index, convention, className, functionName) \
do { \
using DerivedWrap = wrap::functionName<Derived, types::pure##pure_index>; \
using BaseWrap = wrap::functionName<Base, types::pure##pure_index>; \
if constexpr (DerivedWrap::uuid != nullptr && (void*)BaseWrap::uuid != (void*)DerivedWrap::uuid) { \
auto hook = Hook::create<convention>( \
Mod::get(), \
reinterpret_cast<void*>(addresses::address##addr_index()), \
DerivedWrap::value, \
#className "::" #functionName \
); \
this->m_hooks[#className "::" #functionName] = hook; \
} \
#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*>(addresses::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*>(addresses::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*>(addresses::address##AddressIndex_()), \
AsStaticFunction_##destructor<Derived, d>::value, \
#ClassName_ "::" #ClassName_ \
); \
this->m_hooks[#ClassName_ "::" #ClassName_] = hook; \
} \
} while (0);
namespace geode::modifier {
@ -87,11 +115,15 @@ 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;

View file

@ -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.
@ -65,4 +62,144 @@ namespace geode::modifier {
public:
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...);
};
}

View file

@ -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 = \
FunctionUUID<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 = \
FunctionUUID<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;
// };
}

View file

@ -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();

View file

@ -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();

View file

@ -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);