completely remove interface + implement scheduling stuff

This commit is contained in:
altalk23 2022-10-08 16:53:09 +03:00
parent 496fcc9965
commit 6d5e02a6b4
28 changed files with 106 additions and 199 deletions

View file

@ -3,6 +3,8 @@
#include <Geode/Geode.hpp>
GEODE_API bool GEODE_CALL geode_implicit_load(geode::Mod* m) {
geode::Interface::get()->init(m);
geode::Mod::setSharedMod(m);
geode::log::releaseSchedules(m);
geode::Loader::get()->releaseScheduledFunctions(m);
return true;
}

View file

@ -11,7 +11,6 @@
#include <cocos-ext.h>
#include <cocos2d.h>
#include <fmod.hpp>
//#include <Interface.hpp>
#include <stdint.h>
#include <type_traits>
#include <unordered_map>

View file

@ -5,6 +5,5 @@
#include "loader/Log.hpp"
#include "loader/Mod.hpp"
#include "loader/Loader.hpp"
#include "loader/Interface.hpp"
#include "loader/Setting.hpp"
#include "loader/SettingEvent.hpp"

View file

@ -1,6 +1,5 @@
#include "Mod.hpp"
#include "Loader.hpp"
#include "Interface.hpp"
#ifdef API_DECL
#undef API_DECL

View file

@ -3,7 +3,6 @@
#include <Geode/DefaultInclude.hpp>
#include <type_traits>
#include "Mod.hpp"
#include "Interface.hpp"
#include <unordered_set>
namespace geode {

View file

@ -1,120 +0,0 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include "Types.hpp"
#include <vector>
#include <variant>
#include "../utils/casts.hpp"
#include "../utils/Result.hpp"
#include "Mod.hpp"
namespace geode {
class Hook;
/**
* For developing your own mods, it is
* often convenient to be able to do things
* like create hooks using statically
* initialized global classes.
*
* At that point however, your mod has not
* yet received the Mod* to create hooks
* through.
*
* For situations like that, you can instead
* inherit from Interface to create your own
* mod interface and create hooks through that;
* calling `init` with the Mod* you receive
* from geode will automatically create all
* scheduled hooks, logs, etc.
*
* Interface also provides a handy &
* standardized way to store access to your
* Mod*; you can just define a `get` function
* and a getter for the Mod* stored in the
* Interface.
*
* @class Interface
*/
class Interface {
protected:
static GEODE_DLL Interface* create();
struct ScheduledHook {
std::string m_displayName;
void* m_address;
Result<Hook*>(Mod::*m_addFunction)(std::string const&, void*);
};
using ScheduledFunction = std::function<void()>;
Mod* m_mod = nullptr;
std::vector<ScheduledHook> m_scheduledHooks;
std::vector<ScheduledFunction> m_scheduledFunctions;
public:
static inline GEODE_HIDDEN Interface* get() {
static Interface* ret = create();
return ret;
}
[[deprecated("Use Mod::get instead")]]
static inline GEODE_HIDDEN Mod* mod() {
return Interface::get()->m_mod;
}
GEODE_DLL void init(Mod*);
/**
* Create a hook at an address. This function can
* be used at static initialization time, as it
* doesn't require the Mod* to be set -- it will
* create the hooks later when the Mod* is set.
*
* @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 (or nullptr if Mod* is not loaded
* yet), errorful result with info on error
*/
template<auto Detour, template <class, class...> class Convention>
Result<Hook*> addHook(void* address) {
return Interface::addHook<Detour, Convention>("", address);
}
/**
* The same as addHook(void*, void*), but also provides
* a display name to show it in the list of the loader.
* Mostly for internal use but if you don't like your
* hooks showing up like base + 0x123456 it can be useful
*/
template<auto Detour, template <class, class...> class Convention>
Result<Hook*> addHook(std::string const& displayName, void* address) {
if (this->m_mod) {
return this->m_mod->addHook<Detour, Convention>(displayName, address);
}
this->m_scheduledHooks.push_back({ displayName, address, &Mod::addHook<Detour, Convention> });
return Ok<Hook*>(nullptr);
}
GEODE_DLL void scheduleOnLoad(ScheduledFunction function);
friend Mod* Mod::get<void>();
};
template<>
inline Mod* Mod::get<void>() {
return Interface::get()->m_mod;
}
inline Mod* getMod() {
return Mod::get();
}
}
inline const char* operator"" _spr(const char* str, size_t) {
return geode::Mod::get()->expandSpriteName(str);
}

View file

@ -32,6 +32,14 @@ namespace geode {
template<class, class, class>
class FieldIntermediate;
}
}
/**
* The predeclaration of the implicit entry
*/
GEODE_API bool GEODE_CALL geode_implicit_load(geode::Mod*);
namespace geode {
class GEODE_DLL Loader {
public:
@ -48,6 +56,9 @@ namespace geode {
std::unordered_map<std::string, ModSettings> m_mods;
};
using ScheduledFunction = std::function<void GEODE_CALL(void)>;
std::vector<ScheduledFunction> m_scheduledFunctions;
std::unordered_map<std::string, Mod*> m_mods;
std::vector<log::Log> m_logs;
std::ofstream m_logStream;
@ -67,16 +78,19 @@ namespace geode {
void updateAllDependencies();
void releaseScheduledFunctions(Mod* mod);
friend class Mod;
friend class CustomLoader;
friend struct ModInfo;
private:
size_t getFieldIndexForClass(size_t hash);
template <class, class, class>
friend class modifier::FieldIntermediate;
friend bool GEODE_CALL ::geode_implicit_load(Mod*);
public:
~Loader();
@ -233,7 +247,15 @@ namespace geode {
* `CCScheduler::update` is called
* @param func Function to run
*/
void queueInGDThread(std::function<void GEODE_CALL(void)> func);
void queueInGDThread(ScheduledFunction func);
/**
* Run a function when the Mod is loaded. Useful if for
* some reason you need to run some function in
* static initialization.
* @param func Function to run
*/
void scheduleOnModLoad(Mod* m, ScheduledFunction func);
/**
* Open the platform-specific external console (if one exists)

View file

@ -96,15 +96,15 @@ namespace geode {
l.pushToLoader();
}
void releaseSchedules(Mod* m);
void GEODE_DLL releaseSchedules(Mod* m);
template <typename ...Args>
void schedule(Severity sev, Args... args) {
auto m = getMod();
if (m) return log(sev, m, args...);
Log::scheduled().push_back([=](Mod* m){
log(sev, m, args...);
Log::scheduled().push_back([=](Mod* m2){
log(sev, m2, args...);
});
}

View file

@ -17,7 +17,6 @@
class InternalLoader;
class InternalMod;
namespace geode {
struct PlatformInfo;
@ -30,6 +29,14 @@ namespace geode {
class Unknown;
using unknownmemfn_t = void(Unknown::*)();
using unknownfn_t = void(*)();
}
/**
* The predeclaration of the implicit entry
*/
GEODE_API bool GEODE_CALL geode_implicit_load(geode::Mod*);
namespace geode {
struct Dependency {
std::string m_id;
@ -197,9 +204,7 @@ namespace geode {
/**
* @class Mod
* Represents a Mod ingame. Inherit
* from this class to create your own
* mod interfaces.
* Represents a Mod ingame.
* @abstract
*/
class GEODE_DLL Mod {
@ -316,6 +321,16 @@ namespace geode {
friend struct ModInfo;
friend class DataStore;
template<class = void>
static inline GEODE_HIDDEN Mod* sharedMod = nullptr;
template<class = void>
static inline GEODE_HIDDEN void setSharedMod(Mod* mod) {
sharedMod<> = mod;
}
friend bool GEODE_CALL ::geode_implicit_load(Mod*);
public:
std::string getID() const;
std::string getName() const;
@ -362,7 +377,9 @@ namespace geode {
* the mod pointer if it is initialized
*/
template<class = void>
static inline Mod* get();
static inline GEODE_HIDDEN Mod* get() {
return sharedMod<>;
}
/**
* Get all hooks owned by this Mod
@ -548,5 +565,11 @@ namespace geode {
* However, it can be externed, unlike Mod::get()
* @returns Same thing Mod::get() returns
*/
inline Mod* getMod();
inline GEODE_HIDDEN Mod* getMod() {
return Mod::get();
}
}
inline const char* operator"" _spr(const char* str, size_t) {
return geode::Mod::get()->expandSpriteName(str);
}

View file

@ -89,8 +89,8 @@ void _##Line_##Function(); \
namespace { \
struct _##Line_##Unique {}; \
} \
static inline auto _line = (Interface::get()->scheduleOnLoad( \
&_##Line_##Function<_##Line_##Unique> \
static inline auto _line = (Loader::get()->scheduleOnModLoad( \
nullptr, &_##Line_##Function<_##Line_##Unique> \
), 0); \
template<class> \
void _##Line_##Function()

View file

@ -3,17 +3,14 @@
#include "Types.hpp"
#include "Addresses.hpp"
#include "../meta/meta.hpp"
#include "../loader/Interface.hpp"
#include <Geode/loader/Mod.hpp>
#include <iostream>
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(index, convention, className, functionName) \
using base##index = wrap::functionName<Base, types::pure##index>; \
using derived##index = wrap::functionName<Derived, types::pure##index>; \
if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (void*)derived##index::uuid) { \
log::debug( \
"Adding hook at function " #className "::" #functionName \
); \
Interface::get()->addHook<derived##index::value, convention>( \
Mod::get()->addHook<derived##index::value, convention>( \
#className "::" #functionName, \
(void*)addresses::address##index() \
); \
@ -30,7 +27,9 @@ namespace geode::modifier {
public:
// unordered_map<handles> idea
ModifyBase() {
Loader::get()->scheduleOnModLoad(getMod(), [](){
Derived::apply();
});
}
template <class, class>
friend class Modify;

View file

@ -8,7 +8,6 @@
#include <stddef.h>
#include <Geode/DefaultInclude.hpp>
#include <type_traits>
#include "../loader/Interface.hpp"
#include "../loader/Mod.hpp"
#include "../loader/Log.hpp"
#include "general.hpp"

View file

@ -210,6 +210,7 @@ class $modify(CustomMenuLayer, MenuLayer) {
}
auto y = getChild(bottomMenu, 0)->getPositionY();
std::cout << "test: " << "geode-logo-outline-gold.png"_spr << std::endl;
g_geodeButton = SafeCreate<CCSprite>()
.with(CircleButtonSprite::createWithSpriteFrameName(

View file

@ -38,7 +38,7 @@ bool InternalLoader::setup() {
return true;
}
void InternalLoader::queueInGDThread(std::function<void GEODE_CALL()> func) {
void InternalLoader::queueInGDThread(ScheduledFunction func) {
std::lock_guard<std::mutex> lock(m_gdThreadMutex);
this->m_gdThreadQueue.push_back(func);
}
@ -113,17 +113,25 @@ void InternalLoader::closePlatformConsole() {
}
#elif defined(GEODE_IS_MACOS)
#include <iostream>
#include <CoreFoundation/CoreFoundation.h>
void InternalLoader::platformMessageBox(const char* title, std::string const& info) {
std::cout << title << ": " << info << std::endl;
CFStringRef cfTitle = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
CFStringRef cfMessage = CFStringCreateWithCString(NULL, info.c_str(), kCFStringEncodingUTF8);
CFUserNotificationDisplayNotice(0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, cfTitle, cfMessage, NULL);
}
void InternalLoader::openPlatformConsole() {
m_platformConsoleOpen = true;
for (auto const& log : Loader::get()->getLogs()) {
std::cout << log->toString(true) << "\n";
}
}
void InternalLoader::closePlatformConsole() {
m_platformConsoleOpen = false;
}
#elif defined(GEODE_IS_IOS)

View file

@ -46,7 +46,7 @@ public:
*/
bool shownInfoAlert(std::string const& key);
void queueInGDThread(std::function<void GEODE_CALL(void)> func);
void queueInGDThread(ScheduledFunction func);
void executeGDThreadQueue();
void logConsoleMessage(std::string const& msg);

View file

@ -3,7 +3,6 @@
class InternalMod;
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
USE_GEODE_NAMESPACE();

View file

@ -1,7 +1,6 @@
#include <Geode/loader/Hook.hpp>
#include <vector>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/utils/casts.hpp>
#include <Geode/utils/vector.hpp>
@ -31,6 +30,7 @@ Result<> Mod::enableHook(Hook* hook) {
if (!hook->isEnabled()) {
auto res = std::invoke(hook->m_addFunction, hook->m_address);
if (res) {
log::debug("Enabling hook at function ", hook->m_displayName);
this->m_hooks.push_back(hook);
hook->m_enabled = true;
hook->m_handle = res.value();
@ -48,6 +48,7 @@ Result<> Mod::enableHook(Hook* hook) {
Result<> Mod::disableHook(Hook* hook) {
if (hook->isEnabled()) {
if (geode::core::hook::remove(hook->m_handle)) {
log::debug("Disabling hook at function {}", hook->m_displayName);
hook->m_enabled = false;
return Ok<>();
}

View file

@ -1,30 +0,0 @@
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Hook.hpp>
#include <Geode/loader/Log.hpp>
#include <Geode/loader/Loader.hpp>
USE_GEODE_NAMESPACE();
void Interface::init(Mod* mod) {
if (!m_mod) {
m_mod = mod;
for (auto const& hook : m_scheduledHooks) {
std::invoke(hook.m_addFunction, m_mod, hook.m_displayName, hook.m_address);
}
m_scheduledHooks.clear();
for (auto const& fn : m_scheduledFunctions) {
std::invoke(fn);
}
m_scheduledFunctions.clear();
}
}
void Interface::scheduleOnLoad(ScheduledFunction function) {
m_scheduledFunctions.push_back(function);
}
Interface* Interface::create() {
return new Interface;
}

View file

@ -1,6 +1,5 @@
#include <Geode/loader/Hook.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Log.hpp>
#include <Geode/loader/Loader.hpp>
#include <InternalLoader.hpp>
@ -404,7 +403,7 @@ std::vector<log::Log*> Loader::getLogs(
return logs;
}
void Loader::queueInGDThread(std::function<void GEODE_CALL()> func) {
void Loader::queueInGDThread(ScheduledFunction func) {
InternalLoader::get()->queueInGDThread(func);
}
@ -462,3 +461,15 @@ void Loader::openPlatformConsole() {
void Loader::closePlatfromConsole() {
InternalLoader::get()->closePlatformConsole();
}
void Loader::scheduleOnModLoad(Mod* m, ScheduledFunction func) {
if (m) return func();
m_scheduledFunctions.push_back(func);
}
void Loader::releaseScheduledFunctions(Mod* mod) {
for (auto& func : m_scheduledFunctions) {
func();
}
m_scheduledFunctions.clear();
}

View file

@ -1,7 +1,6 @@
#include <Geode/Geode.hpp>
#include <Geode/loader/Log.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/utils/general.hpp>
#include <Geode/utils/casts.hpp>
@ -97,10 +96,10 @@ std::string Log::toString(bool logTime) const {
std::string res;
if (logTime) {
res += fmt::format("{:%H:%M:%S}", this->m_time);
res += fmt::format("{:%H:%M:%S}", m_time);
}
res += fmt::format("[{}]: ", m_sender ? m_sender->getName() : "?");
res += fmt::format(" [{}]: ", m_sender ? m_sender->getName() : "?");
for (auto& i : m_components) {
res += i->_toString();
@ -114,5 +113,5 @@ void Log::pushToLoader() {
}
std::string geode::log::generateLogName() {
return fmt::format("Geode_{:%H:%M:%S}.log", log_clock::now());
return fmt::format("Geode_{:%H.%M.%S}.log", log_clock::now());
}

View file

@ -3,7 +3,6 @@
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Log.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Setting.hpp>
#include <Geode/utils/conststring.hpp>
#include <Geode/utils/file.hpp>
@ -211,7 +210,6 @@ Result<> Mod::load() {
if (this->hasUnresolvedDependencies()) {
RETURN_LOAD_ERR("Mod has unresolved dependencies");
}
log::releaseSchedules(this);
auto err = this->loadPlatformBinary();
if (!err) RETURN_LOAD_ERR(err.error());
if (m_implicitLoadFunc) {

View file

@ -1,7 +1,6 @@
#include <about.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/utils/string.hpp>
#include <Geode/utils/file.hpp>

View file

@ -1,7 +1,6 @@
#include <Geode/loader/Hook.hpp>
#include <vector>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/utils/casts.hpp>
#include <Geode/utils/vector.hpp>

View file

@ -1,6 +1,5 @@
#include <Geode/loader/cgeode.h>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Log.hpp>
USE_GEODE_NAMESPACE();

View file

@ -1,7 +1,6 @@
#include <Geode/DefaultInclude.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#undef snprintf
USE_GEODE_NAMESPACE();

View file

@ -3,7 +3,6 @@
#ifdef GEODE_IS_MACOS
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <dlfcn.h>
USE_GEODE_NAMESPACE();

View file

@ -1,5 +1,4 @@
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Interface.hpp>
#include <Geode/loader/Loader.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <InternalLoader.hpp>
@ -124,7 +123,7 @@ int geodeEntry(void* platformData) {
);
}
Interface::get()->init(InternalMod::get());
geode_implicit_load(InternalMod::get());
if (!InternalLoader::get()->setup()) {
// if we've made it here, Geode will

View file

@ -3,6 +3,11 @@
USE_GEODE_NAMESPACE();
auto test = [](){
log::info("Static logged");
return 0;
};
// Exported functions
GEODE_API bool GEODE_CALL geode_enable() {
log::info("Enabled");