seperation of modify and bindings

This commit is contained in:
altalk23 2022-10-13 11:31:23 +03:00
parent 6ba63208a2
commit 1cfc793f7c
25 changed files with 163 additions and 115 deletions

View file

@ -3,7 +3,7 @@
namespace { namespace format_strings {
char const* declare_address = R"GEN(
GEODE_NOINLINE GEODE_HIDDEN inline static uintptr_t address{index}() {{
GEODE_INLINE GEODE_HIDDEN inline static uintptr_t address{index}() {{
static uintptr_t ret = {address};
return ret;
}}

View file

@ -3,34 +3,41 @@
#include <set>
namespace { namespace format_strings {
char const* class_predeclare = "class {class_name};\n";
// requires: base_classes, class_name
char const* binding_include = R"GEN(#include "binding/{file_name}"
)GEN";
char const* class_includes = R"GEN(#pragma once
#include <Geode/c++stl/gdstdlib.hpp>
#include <cocos2d.h>
#include <codegenned/GeneratedPredeclare.hpp>
)GEN";
char const* class_include_prereq = R"GEN(#include "{file_name}"
)GEN";
char const* class_start = R"GEN(
class {class_name}{base_classes} {{
public:
)GEN";
char const* monostate_constructor = R"GEN(
GEODE_MONOSTATE_CONSTRUCTOR_GD({class_name}, {first_base})
char const* monostate_constructor = R"GEN( GEODE_MONOSTATE_CONSTRUCTOR_GD({class_name}, {first_base})
)GEN";
char const* monostate_constructor_cutoff = R"GEN(
GEODE_MONOSTATE_CONSTRUCTOR_CUTOFF({class_name}, {first_base})
char const* monostate_constructor_cutoff = R"GEN( GEODE_MONOSTATE_CONSTRUCTOR_CUTOFF({class_name}, {first_base})
)GEN";
char const* function_definition = R"GEN(
{docs}{static}{virtual}{return_type} {function_name}({parameters}){const};
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( template <bool T=false>
{static}{return_type} {function_name}({parameters}){const}{{
static_assert(T, "Implement {class_name}::{function_name}");
}}
)GEN";
char const* error_definition_virtual = R"GEN(
[[deprecated("Use of undefined virtual function - will crash at runtime!!!")]]
char const* error_definition_virtual = R"GEN( [[deprecated("Use of undefined virtual function - will crash at runtime!!!")]]
{virtual}{return_type} {function_name}({parameters}){const}{{
#ifdef GEODE_NO_UNDEFINED_VIRTUALS
static_assert(false, "Undefined virtual function - implement in GeometryDash.bro");
@ -43,52 +50,52 @@ public:
{function_name}({parameters});)GEN";
// requires: type, member_name, array
char const* member_definition = R"GEN(
{type} {member_name};)GEN";
char const* member_definition = R"GEN( {type} {member_name};
)GEN";
char const* pad_definition = R"GEN(
GEODE_PAD({hardcode});)GEN";
char const* unimplemented_definition = R"GEN(
GEODE_UNIMPLEMENTED_PAD)GEN";
char const* pad_definition = R"GEN( GEODE_PAD({hardcode});
)GEN";
// requires: hardcode_macro, type, member_name, hardcode
char const* hardcode_definition = R"GEN(
CLASSPARAM({type}, {member_name}, {hardcode});)GEN";
char const* class_end = R"GEN(
};
char const* class_end = R"GEN(};
)GEN";
}}
std::string generateGDHeader(Root& root) {
std::string output("#pragma once\n#include <Geode/c++stl/gdstdlib.hpp>\n#include <cocos2d.h>\n");
for (auto& cls : root.classes) {
if (can_find(cls.name, "cocos2d"))
continue;
output += fmt::format(::format_strings::class_predeclare,
fmt::arg("class_name", cls.name)
);
}
std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singleFolder) {
std::string output;
for (auto& cls : root.classes) {
if (can_find(cls.name, "cocos2d"))
continue;
std::string filename = (codegen::getUnqualifiedClassName(cls.name) + ".hpp");
output += fmt::format(format_strings::binding_include,
fmt::arg("file_name", filename)
);
std::string single_output;
single_output += format_strings::class_includes;
for (auto dep : cls.superclasses) {
if (can_find(dep, "cocos2d::")) continue;
std::string depfilename = (codegen::getUnqualifiedClassName(dep) + ".hpp");
single_output += fmt::format(format_strings::class_include_prereq, fmt::arg("file_name", depfilename));
}
std::string supers = str_if(
fmt::format(" : public {}", fmt::join(cls.superclasses, ", ")),
!cls.superclasses.empty()
);
output += fmt::format(::format_strings::class_start,
single_output += fmt::format(::format_strings::class_start,
fmt::arg("class_name", cls.name),
fmt::arg("base_classes", supers)
);
// what.
if (!cls.superclasses.empty()) {
output += fmt::format(
single_output += fmt::format(
can_find(cls.superclasses[0], "cocos2d")
? format_strings::monostate_constructor_cutoff
: format_strings::monostate_constructor,
@ -97,15 +104,17 @@ std::string generateGDHeader(Root& root) {
);
}
bool unimplementedField = false;
for (auto field : cls.fields) {
FunctionBegin* fb;
char const* used_format = format_strings::function_definition;
if (auto i = field.get_as<InlineField>()) {
output += "\t" + i->inner + "\n";
single_output += "\t" + i->inner + "\n";
continue;
} else if (auto m = field.get_as<MemberField>()) {
output += fmt::format(format_strings::member_definition,
if (unimplementedField) single_output += "\t[[deprecated(\"Member placed incorrectly - will crash at runtime!!!\")]]\n";
single_output += fmt::format(format_strings::member_definition,
fmt::arg("type", m->type.name),
fmt::arg("member_name", m->name + str_if(fmt::format("[{}]", m->count), m->count))
);
@ -114,9 +123,9 @@ std::string generateGDHeader(Root& root) {
auto hardcode = codegen::platformNumber(p->amount);
if (hardcode) {
output += fmt::format(format_strings::pad_definition, fmt::arg("hardcode", hardcode));
single_output += fmt::format(format_strings::pad_definition, fmt::arg("hardcode", hardcode));
} else {
output += "\n GEODE_UNIMPLEMENTED_PAD";
unimplementedField = true;
}
continue;
} else if (auto fn = field.get_as<OutOfLineField>()) {
@ -135,7 +144,7 @@ std::string generateGDHeader(Root& root) {
}
}
output += fmt::format(used_format,
single_output += fmt::format(used_format,
fmt::arg("virtual", str_if("virtual ", fb->is_virtual)),
fmt::arg("static", str_if("static ", fb->is_static)),
fmt::arg("class_name", cls.name),
@ -149,9 +158,9 @@ std::string generateGDHeader(Root& root) {
}
// if (hasClass)
output += ::format_strings::class_end;
single_output += ::format_strings::class_end;
// queued.pop_front();
writeFile(singleFolder / filename, single_output);
}
return output;

View file

@ -3,21 +3,6 @@
using namespace codegen;
void writeFile(ghc::filesystem::path const& writePath, std::string const& output) {
std::ifstream readfile;
readfile >> std::noskipws;
readfile.open(writePath);
std::string data((std::istreambuf_iterator<char>(readfile)), std::istreambuf_iterator<char>());
readfile.close();
if (data != output) {
std::ofstream writefile;
writefile.open(writePath);
writefile << output;
writefile.close();
}
}
int main(int argc, char** argv) try {
if (argc != 4) throw codegen::error("Invalid number of parameters (expected 3 found {})", argc-1);
@ -33,6 +18,8 @@ int main(int argc, char** argv) try {
ghc::filesystem::path writeDir = argv[3];
ghc::filesystem::create_directories(writeDir);
ghc::filesystem::create_directories(writeDir / "modify");
ghc::filesystem::create_directories(writeDir / "binding");
Root root = broma::parse_file("Entry.bro");
@ -45,11 +32,12 @@ int main(int argc, char** argv) try {
}
writeFile(writeDir / "GeneratedAddress.hpp", generateAddressHeader(root));
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root)); // pretty much obsolete with a custom compiler
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify")); // pretty much obsolete with a custom compiler
writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root)); // pretty much obsolete with a custom compiler
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root)); // pretty much obsolete with a custom compiler
writeFile(writeDir / "GeneratedHeader.hpp", generateGDHeader(root));
writeFile(writeDir / "GeneratedSource.cpp", generateGDSource(root));
writeFile(writeDir / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding"));
writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root));
writeFile(writeDir / "GeneratedSource.cpp", generateBindingSource(root));
} catch(std::exception& e) {
std::cout << "Codegen error: " << e.what() << "\n";
return 1;

View file

@ -3,34 +3,51 @@
namespace { namespace format_strings {
// requires: class_name
char const* modify_start = R"GEN(
template<class Derived>
struct Modify<Derived, {class_name}> : ModifyBase<Modify<Derived, {class_name}>> {{
using ModifyBase<Modify<Derived, {class_name}>>::ModifyBase;
using Base = {class_name};
static void apply() {{
using namespace geode::core::meta;
char const* modify_start = R"GEN(#pragma once
#include <Geode/modify/Modify.hpp>
#include <Geode/modify/Field.hpp>
#include <Geode/modify/InternalMacros.hpp>
using namespace geode::modifier;
namespace geode::modifier {{
template<class Derived>
struct Modify<Derived, {class_name}> : ModifyBase<Modify<Derived, {class_name}>> {{
using ModifyBase<Modify<Derived, {class_name}>>::ModifyBase;
using Base = {class_name};
static void apply() {{
using namespace geode::core::meta;
)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({index}, {function_convention}, {class_name}, {function_name}))GEN";
GEODE_APPLY_MODIFY_FOR_FUNCTION({index}, {function_convention}, {class_name}, {function_name}))GEN";
char const* modify_end = R"GEN(
}
};
}
};
}
)GEN";
char const* modify_include = R"GEN(#include "modify/{file_name}"
)GEN";
}}
std::string generateModifyHeader(Root& root) {
std::string generateModifyHeader(Root& root, ghc::filesystem::path const& singleFolder) {
std::string output;
for (auto c : root.classes) {
if (c.name == "cocos2d")
continue;
output += fmt::format(format_strings::modify_start,
std::string filename = (codegen::getUnqualifiedClassName(c.name) + ".hpp");
output += fmt::format(format_strings::modify_include,
fmt::arg("file_name", filename)
);
std::string single_output;
single_output += fmt::format(format_strings::modify_start,
fmt::arg("class_name", c.name)
);
@ -52,7 +69,7 @@ std::string generateModifyHeader(Root& root) {
break;
}
output += fmt::format(format_strings::apply_function,
single_output += fmt::format(format_strings::apply_function,
fmt::arg("index", f.field_id),
fmt::arg("class_name", c.name),
fmt::arg("function_name", function_name),
@ -61,7 +78,9 @@ std::string generateModifyHeader(Root& root) {
}
}
output += format_strings::modify_end;
single_output += format_strings::modify_end;
writeFile(singleFolder / filename, single_output);
}
return output;

View file

@ -0,0 +1,22 @@
#include "Shared.hpp"
#include <iostream>
#include <set>
namespace { namespace format_strings {
char const* class_predeclare = "class {class_name};\n";
}}
std::string generatePredeclareHeader(Root& root) {
std::string output("#pragma once\n");
for (auto& cls : root.classes) {
if (can_find(cls.name, "cocos2d"))
continue;
output += fmt::format(::format_strings::class_predeclare,
fmt::arg("class_name", cls.name)
);
}
return output;
}

View file

@ -5,6 +5,7 @@
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <fstream>
#include <fs/filesystem.hpp> // bruh
using std::istreambuf_iterator;
@ -19,13 +20,29 @@ using std::istreambuf_iterator;
#endif
std::string generateAddressHeader(Root& root);
std::string generateModifyHeader(Root& root);
std::string generateModifyHeader(Root& root, ghc::filesystem::path const& singleFolder);
std::string generateWrapperHeader(Root& root);
std::string generateTypeHeader(Root& root);
std::string generateGDHeader(Root& root);
std::string generateGDSource(Root& root);
std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singleFolder);
std::string generatePredeclareHeader(Root& root);
std::string generateBindingSource(Root& root);
std::string generateTidyHeader(Root& root);
inline void writeFile(ghc::filesystem::path const& writePath, std::string const& output) {
std::ifstream readfile;
readfile >> std::noskipws;
readfile.open(writePath);
std::string data((std::istreambuf_iterator<char>(readfile)), std::istreambuf_iterator<char>());
readfile.close();
if (data != output) {
std::ofstream writefile;
writefile.open(writePath);
writefile << output;
writefile.close();
}
}
inline std::string str_if(std::string&& str, bool cond) {
return cond ? str : "";
}

View file

@ -72,7 +72,7 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
)GEN";
}}
std::string generateGDSource(Root& root) {
std::string generateBindingSource(Root& root) {
std::string output(format_strings::source_start);
for (auto& c : root.classes) {

View file

@ -352,4 +352,4 @@ enum class LeaderboardState {
#define CLASSPARAM(...)
#define STRUCTPARAM(...)
#include <codegenned/GeneratedHeader.hpp>
#include <codegenned/GeneratedBinding.hpp>

View file

@ -2,8 +2,7 @@
#include <Geode/DefaultInclude.hpp>
#include "modify/Traits.hpp"
#include "modify/Modify.hpp"
#include <codegenned/GeneratedModify.hpp>
#include "modify/Field.hpp"
#include "modify/InternalMacros.hpp"

View file

@ -107,7 +107,6 @@ It's new in cocos2d-x since v0.99.5
class GeodeNodeMetadata;
namespace geode {
struct modify;
struct temp_name_find_better;
namespace modifier {
struct addresses;
struct types;
@ -115,10 +114,9 @@ namespace geode {
}
}
#define GEODE_FRIEND_MODIFY GEODE_ADD(\
friend struct geode::modify;\
friend struct geode::modifier::addresses;\
friend struct geode::modifier::types;\
friend struct geode::temp_name_find_better;\
friend struct ::geode::modify;\
friend struct ::geode::modifier::addresses;\
friend struct ::geode::modifier::types;\
friend class ::GeodeNodeMetadata;\
)
#define GEODE_ADD(...) __VA_ARGS__

View file

@ -44,6 +44,4 @@ namespace geode::modifier {
static_assert(core::meta::always_false<Derived>, "Custom Modify not implemented.");
}
};
#include <codegenned/GeneratedModify.hpp>
}

View file

@ -28,7 +28,7 @@ namespace geode::modifier {
using type = FunctionType*;
};
using geode::core::meta::always_false;
using ::geode::core::meta::always_false;
/**
* The ~unevaluated~ function that gets the appropriate
* version of a function type from its return, parameters, and classes.

View file

@ -71,7 +71,7 @@ namespace std {
#define GEODE_PLATFORM_TARGET PlatformID::Windows
#define GEODE_HIDDEN
#define GEODE_DUPABLE __forceinline
#define GEODE_INLINE __forceinline
#define GEODE_VIRTUAL_CONSTEXPR
#define GEODE_NOINLINE __declspec(noinline)
@ -90,7 +90,7 @@ namespace std {
#define GEODE_PLATFORM_TARGET PlatformID::MacOS
#define GEODE_HIDDEN __attribute__((visibility("hidden")))
#define GEODE_DUPABLE __attribute__((always_inline))
#define GEODE_INLINE __attribute__((always_inline))
#define GEODE_VIRTUAL_CONSTEXPR constexpr
#define GEODE_NOINLINE __attribute__((noinline))
@ -109,7 +109,7 @@ namespace std {
#define GEODE_PLATFORM_TARGET PlatformID::iOS
#define GEODE_HIDDEN __attribute__((visibility("hidden")))
#define GEODE_DUPABLE __attribute__((always_inline))
#define GEODE_INLINE __attribute__((always_inline))
#define GEODE_VIRTUAL_CONSTEXPR constexpr
#define GEODE_NOINLINE __attribute__((noinline))
@ -128,7 +128,7 @@ namespace std {
#define GEODE_PLATFORM_TARGET PlatformID::Android
#define GEODE_HIDDEN __attribute__((visibility("hidden")))
#define GEODE_DUPABLE __attribute__((always_inline))
#define GEODE_INLINE __attribute__((always_inline))
#define GEODE_VIRTUAL_CONSTEXPR constexpr
#define GEODE_NOINLINE __attribute__((noinline))

View file

@ -1,7 +1,7 @@
#include <Geode/Bindings.hpp>
#include <Geode/utils/Ref.hpp>
#include <Geode/Modify.hpp>
#include <Geode/utils/WackyGeodeMacros.hpp>
#include <Geode/modify/Field.hpp>
USE_GEODE_NAMESPACE();
using namespace geode::modifier;
@ -59,6 +59,7 @@ public:
};
// proxy forwards
#include <codegenned/modify/CCNode.hpp>
class $modify(ProxyCCNode, CCNode) {
virtual CCObject* getUserObject() {
return GeodeNodeMetadata::set(this)->m_userObject;

View file

@ -1,8 +1,8 @@
#include <Geode/Modify.hpp>
#include <array>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/LoadingLayer.hpp>
class $modify(CustomLoadingLayer, LoadingLayer) {
bool init(bool fromReload) {
if (!LoadingLayer::init(fromReload))

View file

@ -1,4 +1,3 @@
#include <Geode/Geode.hpp>
#include <Geode/utils/WackyGeodeMacros.hpp>
#include <Geode/ui/BasedButtonSprite.hpp>
#include <Geode/ui/Notification.hpp>
@ -8,7 +7,6 @@
#include <InternalMod.hpp>
#include "../ui/internal/info/ModInfoLayer.hpp"
#include <InternalLoader.hpp>
#include <Geode/Modify.hpp>
USE_GEODE_NAMESPACE();
@ -130,6 +128,7 @@ static void updateIndexProgress(
}
}
#include <codegenned/modify/MenuLayer.hpp>
class $modify(CustomMenuLayer, MenuLayer) {
void destructor() {
g_geodeButton = nullptr;

View file

@ -1,5 +1,3 @@
#include <Geode/Modify.hpp>
#ifdef GEODE_IS_WINDOWS
USE_GEODE_NAMESPACE();

View file

@ -1,7 +1,6 @@
#include <Geode/Modify.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/CCTouchDispatcher.hpp>
class $modify(CCTouchDispatcher) {
void addTargetedDelegate(CCTouchDelegate *delegate, int priority, bool swallowsTouches) {
m_bForcePrio = false;

View file

@ -1,13 +1,10 @@
#include <Geode/Modify.hpp>
// this is the fix for the dynamic_cast problems
// TODO: completely replace dynamic_cast on macos
using namespace cocos2d;
using namespace geode::modifier;
#if defined(GEODE_IS_IOS) || defined(GEODE_IS_MACOS)
namespace geode::fixes {
using namespace geode::cast;
#define HandlerFixFor(CCUtility) \
@ -49,10 +46,14 @@ class $modify(CCUtility##HandlerTypeinfoFix, CCUtility##Handler) {
} \
}
#include <codegenned/modify/CCKeypadHandler.hpp>
HandlerFixFor(CCKeypad);
#include <codegenned/modify/CCKeyboardHandler.hpp>
HandlerFixFor(CCKeyboard);
#include <codegenned/modify/CCMouseHandler.hpp>
HandlerFixFor(CCMouse);
#include <codegenned/modify/CCTargetedTouchHandler.hpp>
class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) {
void destructor() {
if (m_pDelegate) {
@ -99,6 +100,7 @@ class $modify(CCTargetedTouchHandlerTypeinfoFix, CCTargetedTouchHandler) {
}
};
#include <codegenned/modify/CCStandardTouchHandler.hpp>
class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) {
void destructor() {
if (m_pDelegate) {
@ -140,6 +142,4 @@ class $modify(CCStandardTouchHandlerTypeinfoFix, CCStandardTouchHandler) {
}
};
} // geode::fixes
#endif

View file

@ -1,8 +1,8 @@
#include <Geode/Modify.hpp>
#include <Geode/ui/SceneManager.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/AchievementNotifier.hpp>
class $modify(AchievementNotifier) {
void willSwitchToScene(CCScene* scene) {
AchievementNotifier::willSwitchToScene(scene);

View file

@ -1,8 +1,8 @@
#include <Geode/Modify.hpp>
#include <Geode/loader/Loader.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/AppDelegate.hpp>
class $modify(AppDelegate) {
void trySaveGame() {
log::log(Severity::Info, Loader::getInternalMod(), "Saving...");

View file

@ -1,8 +1,8 @@
#include <Geode/Modify.hpp>
#include <InternalLoader.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/CCScheduler.hpp>
class $modify(CCScheduler) {
void update(float dt) {
InternalLoader::get()->executeGDThreadQueue();

View file

@ -1,8 +1,8 @@
#include <Geode/Modify.hpp>
#include <Geode/loader/Loader.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/GameManager.hpp>
class $modify(GameManager) {
void reloadAllStep2() {
GameManager::reloadAllStep2();
@ -10,6 +10,7 @@ class $modify(GameManager) {
}
};
#include <codegenned/modify/LoadingLayer.hpp>
class $modify(LoadingLayer) {
void loadAssets() {
LoadingLayer::loadAssets();

View file

@ -1,8 +1,8 @@
#include <Geode/Geode.hpp>
#include <Geode/Modify.hpp>
USE_GEODE_NAMESPACE();
#include <codegenned/modify/MenuLayer.hpp>
class $modify(MenuLayer) {
void onMoreGames(CCObject*) {
if (Mod::get()->getSettingValue<bool>("its-raining-after-all")) {

View file

@ -1,5 +1,4 @@
#include <Geode/Geode.hpp>
#include <Geode/Modify.hpp>
USE_GEODE_NAMESPACE();
@ -30,6 +29,7 @@ GEODE_API bool GEODE_CALL geode_unload() {
}
// Modify
#include <codegenned/modify/GJGarageLayer.hpp>
class $modify(GJGarageLayerTest, GJGarageLayer) {
GJGarageLayerTest() :
myValue(1907) {}