Merge branch 'main' into tulip-hook

This commit is contained in:
altalk23 2022-12-13 13:30:34 +03:00
commit c605c24f26
29 changed files with 229 additions and 142 deletions

View file

@ -113,7 +113,7 @@ elseif(EXISTS ${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/Modify.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"

View file

@ -3,7 +3,6 @@
#include <Geode/loader/Mod.hpp>
GEODE_API void GEODE_CALL geode_implicit_load(geode::Mod* m) {
geode::Mod::setSharedMod(m);
geode::log::Logger::runScheduled(m);
geode::Loader::get()->dispatchScheduledFunctions(m);
// geode::Mod::setSharedMod(m);
// geode::Loader::get()->dispatchScheduledFunctions(m);
}

View file

@ -168,19 +168,16 @@ namespace cocos2d::extension {}
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, \
18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define $execute \
template <class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(); \
namespace { \
struct GEODE_CONCAT(ExecFuncUnique, __LINE__) {}; \
} \
static inline auto GEODE_CONCAT(Exec, __LINE__) = \
(Loader::get()->scheduleOnModLoad( \
getMod(), \
&GEODE_CONCAT(geodeExecFunction, __LINE__) < GEODE_CONCAT(ExecFuncUnique, __LINE__) > \
), \
0); \
template <class> \
#define $execute \
template <class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(); \
namespace { \
struct GEODE_CONCAT(ExecFuncUnique, __LINE__) {}; \
} \
static inline auto GEODE_CONCAT(Exec, __LINE__) = \
(GEODE_CONCAT(geodeExecFunction, __LINE__) < GEODE_CONCAT(ExecFuncUnique, __LINE__) > (), \
0); \
template <class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)()
// #define GEODE_NEST1(macro, begin) \

View file

@ -113,7 +113,7 @@ namespace geode {
class GEODE_DLL [[nodiscard]] Event {
private:
static std::unordered_set<EventListenerProtocol*> s_listeners;
static std::unordered_set<EventListenerProtocol*>& listeners();
friend EventListenerProtocol;
public:

View file

@ -64,11 +64,9 @@ namespace geode {
template<class = void>
std::monostate listenForIPC(std::string const& messageID, nlohmann::json(*callback)(IPCEvent*)) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
new EventListener(
callback, IPCFilter(getMod()->getID(), messageID)
);
});
(void) new EventListener(
callback, IPCFilter(getMod()->getID(), messageID)
);
return std::monostate();
}
}

View file

@ -36,6 +36,8 @@ namespace geode {
friend void GEODE_CALL ::geode_implicit_load(Mod*);
Result<Mod*> loadModFromInfo(ModInfo const& info);
Mod* takeNextMod();
public:
// TODO: do we want to expose all of these functions?
@ -64,7 +66,6 @@ namespace geode {
void updateResources();
void queueInGDThread(ScheduledFunction func);
void scheduleOnModLoad(Mod* mod, ScheduledFunction func);
void waitForModsToBeLoaded();
/**
@ -79,5 +80,16 @@ namespace geode {
bool didLastLaunchCrash() const;
friend class LoaderImpl;
friend Mod* takeNextLoaderMod();
};
/**
* @brief Take the next mod to load
*
* @return Mod* The next mod to load
*/
inline GEODE_HIDDEN Mod* takeNextLoaderMod() {
return Loader::get()->takeNextMod();
}
}

View file

@ -114,40 +114,22 @@ namespace geode {
Logger() = delete;
~Logger() = delete;
// Unscheduled logs
// logs
static void _push(Log&& log);
// Scheduled functions
template <class = void>
static inline std::vector<Log>& scheduled() {
static std::vector<Log> scheduledLogs;
return scheduledLogs;
}
static void run(Mod* m, std::vector<Log>& scheduled);
public:
static void setup();
static inline void push(Log&& log) {
if (log.m_sender == nullptr)
Logger::scheduled().push_back(std::move(log));
else
Logger::_push(std::move(log));
Logger::_push(std::move(log));
}
static inline void pop(Log* log) {
if (log->m_sender == nullptr)
geode::utils::ranges::remove(Logger::scheduled(), *log);
else
geode::utils::ranges::remove(Logger::s_logs, *log);
geode::utils::ranges::remove(Logger::s_logs, *log);
}
static std::vector<Log*> list();
static void clear();
static inline void runScheduled(Mod* m) {
Logger::run(m, Logger::scheduled());
}
};
template <typename... Args>

View file

@ -32,6 +32,8 @@ namespace geode {
~HandleToSaved();
};
inline GEODE_HIDDEN Mod* takeNextLoaderMod();
/**
* @class Mod
* Represents a Mod ingame.
@ -226,6 +228,9 @@ namespace geode {
*/
template <class = void>
static inline GEODE_HIDDEN Mod* get() {
if (!sharedMod<>) {
sharedMod<> = takeNextLoaderMod();
}
return sharedMod<>;
}

View file

@ -47,14 +47,10 @@ void GEODE_CONCAT(geodeExecFunction, __LINE__)(ModStateEvent*); \
namespace { \
struct GEODE_CONCAT(ExecFuncUnique, __LINE__) {}; \
} \
static inline auto GEODE_CONCAT(Exec, __LINE__) = (geode::Loader::get()->scheduleOnModLoad(\
geode::Mod::get(), []() { \
new geode::EventListener( \
static inline auto GEODE_CONCAT(Exec, __LINE__) = (new geode::EventListener( \
&GEODE_CONCAT(geodeExecFunction, __LINE__)<GEODE_CONCAT(ExecFuncUnique, __LINE__)>,\
geode::ModStateFilter(geode::Mod::get(), geode::ModEventType::type)\
); \
} \
), 0); \
), 0); \
template<class> \
void GEODE_CONCAT(geodeExecFunction, __LINE__)(ModStateEvent*)
// clang-format on

View file

@ -56,20 +56,16 @@ namespace geode {
std::monostate listenForSettingChanges(
std::string const& settingID, void (*callback)(T*)
) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
new EventListener(
callback, SettingChangedFilter<T>(getMod()->getID(), settingID)
);
});
(void)new EventListener(
callback, SettingChangedFilter<T>(getMod()->getID(), settingID)
);
return std::monostate();
}
static std::monostate listenForAllSettingChanges(void (*callback)(Setting*)) {
Loader::get()->scheduleOnModLoad(getMod(), [=]() {
new EventListener(
callback, SettingChangedFilter(getMod()->getID())
);
});
(void)new EventListener(
callback, SettingChangedFilter(getMod()->getID())
);
return std::monostate();
}
}

View file

@ -47,16 +47,14 @@ namespace geode::modifier {
// unordered_map<handles> idea
ModifyBase() {
Loader::get()->scheduleOnModLoad(getMod(), [this]() {
this->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: {}", res.error());
}
this->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: {}", res.error());
}
});
}
}
virtual void apply() {}

View file

@ -2,6 +2,7 @@
#include <Geode/binding/CCMenuItemSpriteExtra.hpp>
#include <Geode/binding/FLAlertLayer.hpp>
#include <Geode/utils/MiniFunction.hpp>
namespace geode {
template <typename... InitArgs>
@ -89,11 +90,11 @@ namespace geode {
GEODE_DLL FLAlertLayer* createQuickPopup(
char const* title, std::string const& content, char const* btn1, char const* btn2,
std::function<void(FLAlertLayer*, bool)> selected, bool doShow = true
utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow = true
);
GEODE_DLL FLAlertLayer* createQuickPopup(
char const* title, std::string const& content, char const* btn1, char const* btn2,
float width, std::function<void(FLAlertLayer*, bool)> selected, bool doShow = true
float width, utils::MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow = true
);
}

View file

@ -0,0 +1,86 @@
#pragma once
#include <Geode/DefaultInclude.hpp>
#include <memory>
namespace geode::utils {
template <class FunctionType>
class MiniFunction;
template <class Ret, class... Args>
class MiniFunctionStateBase {
public:
virtual ~MiniFunctionStateBase() = default;
virtual Ret call(Args... args) const = 0;
virtual MiniFunctionStateBase* clone() const = 0;
};
template <class Type, class Ret, class... Args>
class MiniFunctionState final : public MiniFunctionStateBase<Ret, Args...> {
public:
Type m_func;
explicit MiniFunctionState(Type func) : m_func(std::move(func)) {}
Ret call(Args... args) const override {
return const_cast<Type&>(m_func)(args...);
}
MiniFunctionStateBase<Ret, Args...>* clone() const override {
return new MiniFunctionState(*this);
}
};
template <class Ret, class... Args>
class MiniFunction<Ret(Args...)> {
public:
using FunctionType = Ret(Args...);
using StateType = MiniFunctionStateBase<Ret, Args...>;
private:
StateType* m_state;
public:
MiniFunction() : m_state(nullptr) {}
MiniFunction(MiniFunction const& other) :
m_state(other.m_state ? other.m_state->clone() : nullptr) {}
MiniFunction(MiniFunction&& other) : m_state(other.m_state) {
other.m_state = nullptr;
}
~MiniFunction() {
delete m_state;
}
template <class Callable>
requires requires(Callable&& func, Args... args) {
{ func(args...) } -> std::same_as<Ret>;
}
MiniFunction(Callable&& func) :
m_state(new MiniFunctionState<std::decay_t<Callable>, Ret, Args...>(std::forward<Callable>(func))) {}
MiniFunction& operator=(MiniFunction const& other) {
delete m_state;
m_state = other.m_state ? other.m_state->clone() : nullptr;
return *this;
}
MiniFunction& operator=(MiniFunction&& other) {
delete m_state;
m_state = other.m_state;
other.m_state = nullptr;
return *this;
}
Ret operator()(Args... args) const {
return m_state->call(args...);
}
explicit operator bool() const {
return m_state;
}
};
}

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.3.0)
add_library(Bootstrapper SHARED Bootstrapper.cpp)
target_compile_features(Bootstrapper PUBLIC cxx_std_17)
set_target_properties(Bootstrapper PROPERTIES
PREFIX ""
OUTPUT_NAME "GeodeBootstrapper"

View file

@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.3.0)
add_library(ProxyLoader SHARED proxyLoader.c)
target_compile_features(ProxyLoader PUBLIC cxx_std_17)
set_target_properties(ProxyLoader PROPERTIES
PREFIX ""
OUTPUT_NAME "XInput9_1_0"
@ -21,6 +22,7 @@ set_target_properties(ProxyLoader PROPERTIES
)
add_library(Bootstrapper SHARED Bootstrapper.cpp)
target_compile_features(Bootstrapper PUBLIC cxx_std_17)
set_target_properties(Bootstrapper PROPERTIES
PREFIX ""
OUTPUT_NAME "GeodeBootstrapper"

View file

@ -26,7 +26,7 @@ if (GEODE_TARGET_PLATFORM STREQUAL "iOS")
target_link_libraries(lilac_hook "-F ${CMAKE_CURRENT_SOURCE_DIR}/../ios -framework CydiaSubstrate")
endif()
target_compile_features(lilac_hook PUBLIC cxx_std_17)
target_compile_features(lilac_hook PUBLIC cxx_std_20)
target_include_directories(lilac_hook
PRIVATE
${lilac_SOURCE_DIR}/include/geode/core/hook

View file

@ -42,15 +42,12 @@ static ModInfo getInternalModInfo() {
}
}
InternalMod::InternalMod() : Mod(getInternalModInfo()) {
InternalMod::InternalMod() : Mod(ModInfo()) {}
void InternalMod::setModInfo() {
m_info = getInternalModInfo();
m_saveDirPath = dirs::getModsSaveDir() / m_info.id;
ghc::filesystem::create_directories(m_saveDirPath);
auto sett = this->loadData();
if (!sett) {
log::internalLog(Severity::Error, this, "{}", sett.unwrapErr());
}
}
InternalMod::~InternalMod() {}

View file

@ -13,4 +13,6 @@ protected:
public:
static InternalMod* get();
void setModInfo();
};

View file

@ -2,14 +2,12 @@
USE_GEODE_NAMESPACE();
std::unordered_set<EventListenerProtocol*> Event::s_listeners = {};
void EventListenerProtocol::enable() {
Event::s_listeners.insert(this);
Event::listeners().insert(this);
}
void EventListenerProtocol::disable() {
Event::s_listeners.erase(this);
Event::listeners().erase(this);
}
EventListenerProtocol::~EventListenerProtocol() {
@ -21,9 +19,14 @@ Event::~Event() {}
void Event::postFrom(Mod* m) {
if (m) this->sender = m;
for (auto h : Event::s_listeners) {
for (auto h : Event::listeners()) {
if (h->passThrough(this) == ListenerResult::Stop) {
break;
}
}
}
std::unordered_set<EventListenerProtocol*>& Event::listeners() {
static std::unordered_set<EventListenerProtocol*> listeners;
return listeners;
}

View file

@ -21,10 +21,6 @@ void Loader::addSearchPaths() {
return m_impl->addSearchPaths();
}
void Loader::dispatchScheduledFunctions(Mod* mod) {
return m_impl->dispatchScheduledFunctions(mod);
}
Result<Mod*> Loader::loadModFromInfo(ModInfo const& info) {
return m_impl->loadModFromInfo(info);
}
@ -105,10 +101,6 @@ void Loader::queueInGDThread(ScheduledFunction func) {
return m_impl->queueInGDThread(func);
}
void Loader::scheduleOnModLoad(Mod* mod, ScheduledFunction func) {
return m_impl->scheduleOnModLoad(mod, func);
}
void Loader::waitForModsToBeLoaded() {
return m_impl->waitForModsToBeLoaded();
}
@ -124,3 +116,7 @@ void Loader::closePlatformConsole() {
bool Loader::didLastLaunchCrash() const {
return m_impl->didLastLaunchCrash();
}
Mod* Loader::takeNextMod() {
return m_impl->takeNextMod();
}

View file

@ -245,22 +245,6 @@ Mod* Loader::Impl::getLoadedMod(std::string const& id) const {
return nullptr;
}
void Loader::Impl::dispatchScheduledFunctions(Mod* mod) {
std::lock_guard _(m_scheduledFunctionsMutex);
for (auto& func : m_scheduledFunctions) {
func();
}
m_scheduledFunctions.clear();
}
void Loader::Impl::scheduleOnModLoad(Mod* mod, ScheduledFunction func) {
std::lock_guard _(m_scheduledFunctionsMutex);
if (mod) {
return func();
}
m_scheduledFunctions.push_back(func);
}
void Loader::Impl::updateModResources(Mod* mod) {
if (!mod->m_info.spritesheets.size()) {
return;
@ -595,6 +579,47 @@ ListenerResult ResourceDownloadFilter::handle(
ResourceDownloadFilter::ResourceDownloadFilter() {}
void Loader::Impl::provideNextMod(Mod* mod) {
m_nextModLock.lock();
m_nextMod = mod;
}
Mod* Loader::Impl::takeNextMod() {
if (!m_nextMod) {
// this means we're hopefully loading the internal mod
// TODO: make this less hacky
auto res = this->setupInternalMod();
if (!res) {
log::error("{}", res.unwrapErr());
return nullptr;
}
return m_nextMod;
}
auto ret = m_nextMod;
m_nextModCV.notify_all();
return ret;
}
void Loader::Impl::releaseNextMod() {
auto lock = std::unique_lock<std::mutex>(m_nextModAccessMutex);
m_nextModCV.wait(lock);
m_nextModLock.unlock();
}
Result<> Loader::Impl::setupInternalMod() {
this->provideNextMod(InternalMod::get());
(void)Mod::get();
m_nextModLock.unlock();
InternalMod::get()->setModInfo();
auto sett = Mod::get()->loadData();
if (!sett) {
log::error("{}", sett.unwrapErr());
}
return Ok();
}
Result<> Loader::Impl::createHandler(void* address, tulip::hook::HandlerMetadata const& metadata) {
if (m_handlerHandles.count(address)) {
@ -603,6 +628,7 @@ Result<> Loader::Impl::createHandler(void* address, tulip::hook::HandlerMetadata
GEODE_UNWRAP_INTO(auto handle, tulip::hook::createHandler(address, metadata));
m_handlerHandles[address] = handle;
return Ok();
}
bool Loader::Impl::hasHandler(void* address) {
@ -625,4 +651,5 @@ Result<> Loader::Impl::removeHandler(void* address) {
auto handle = m_handlerHandles[address];
GEODE_UNWRAP(tulip::hook::removeHandler(handle));
m_handlerHandles.erase(address);
return Ok();
}

View file

@ -47,8 +47,6 @@ public:
std::vector<InvalidGeodeFile> m_invalidMods;
std::unordered_map<std::string, Mod*> m_mods;
std::vector<ghc::filesystem::path> m_texturePaths;
std::vector<ScheduledFunction> m_scheduledFunctions;
mutable std::mutex m_scheduledFunctionsMutex;
bool m_isSetup = false;
std::condition_variable m_earlyLoadFinishedCV;
@ -60,6 +58,18 @@ public:
std::vector<std::pair<Hook*, Mod*>> m_internalHooks;
bool m_readyToHook = false;
std::mutex m_nextModMutex;
std::unique_lock<std::mutex> m_nextModLock = std::unique_lock<std::mutex>(m_nextModMutex, std::defer_lock);
std::condition_variable m_nextModCV;
std::mutex m_nextModAccessMutex;
Mod* m_nextMod = nullptr;
Result<> setupInternalMod();
void provideNextMod(Mod* mod);
Mod* takeNextMod();
void releaseNextMod();
std::unordered_map<void*, tulip::hook::HandlerHandle> m_handlerHandles;
Result<> createHandler(void* address, tulip::hook::HandlerMetadata const& metadata);
@ -80,7 +90,6 @@ public:
void updateModResources(Mod* mod);
void addSearchPaths();
void dispatchScheduledFunctions(Mod* mod);
friend void GEODE_CALL ::geode_implicit_load(Mod*);
Result<Mod*> loadModFromInfo(ModInfo const& info);
@ -110,7 +119,6 @@ public:
void updateResources();
void scheduleOnModLoad(Mod* mod, ScheduledFunction func);
void waitForModsToBeLoaded();
bool didLastLaunchCrash() const;

View file

@ -106,7 +106,7 @@ std::string Log::toString(bool logTime) const {
res += fmt::format("{:%H:%M:%S}", m_time);
}
res += fmt::format(" [{}]: ", m_sender ? m_sender->getName() : "?");
res += fmt::format(" [{}]: ", m_sender ? m_sender->getName() : "Geode?");
for (auto& i : m_components) {
res += i->_toString();
@ -209,15 +209,6 @@ void Logger::clear() {
s_logs.clear();
}
void Logger::run(Mod* m, std::vector<Log>& scheduled) {
for (auto&& log : scheduled) {
log.m_sender = m;
Logger::_push(std::move(log));
}
scheduled.clear();
}
// Misc
std::string geode::log::generateLogName() {

View file

@ -203,6 +203,8 @@ Result<> Mod::loadBinary() {
return Err("Mod has unresolved dependencies");
}
LoaderImpl::get()->provideNextMod(this);
GEODE_UNWRAP(this->loadPlatformBinary());
m_binaryLoaded = true;

View file

@ -149,16 +149,6 @@ int geodeEntry(void* platformData) {
Loader::get()->openPlatformConsole();
if (!Loader::get()) {
LoaderImpl::get()->platformMessageBox(
"Unable to Load Geode!",
"There was an unknown fatal error setting up "
"internal tools and Geode can not be loaded. "
"(Loader::get returned nullptr)"
);
return 1;
}
if (!geode::core::hook::initialize()) {
LoaderImpl::get()->platformMessageBox(
"Unable to load Geode!",
@ -169,8 +159,6 @@ int geodeEntry(void* platformData) {
return 1;
}
geode_implicit_load(InternalMod::get());
// set up loader, load mods, etc.
if (!LoaderImpl::get()->setup()) {
LoaderImpl::get()->platformMessageBox(

View file

@ -136,7 +136,7 @@ namespace {
"Are you sure you want to <cr>reset</c> <cl>" + setting->getDisplayName() +
"</c> to <cy>default</c>?",
"Cancel", "Reset",
[this](auto, bool btn2) {
[this](FLAlertLayer*, bool btn2) {
if (btn2) this->resetToDefault();
}
);

View file

@ -4,7 +4,7 @@ USE_GEODE_NAMESPACE();
class QuickPopup : public FLAlertLayer, public FLAlertLayerProtocol {
protected:
std::function<void(FLAlertLayer*, bool)> m_selected;
MiniFunction<void(FLAlertLayer*, bool)> m_selected;
void FLAlert_Clicked(FLAlertLayer* layer, bool btn2) override {
if (m_selected) {
@ -15,7 +15,7 @@ protected:
public:
static QuickPopup* create(
char const* title, std::string const& content, char const* btn1, char const* btn2,
float width, std::function<void(FLAlertLayer*, bool)> selected
float width, MiniFunction<void(FLAlertLayer*, bool)> selected
) {
auto inst = new QuickPopup;
inst->m_selected = selected;
@ -30,7 +30,7 @@ public:
FLAlertLayer* geode::createQuickPopup(
char const* title, std::string const& content, char const* btn1, char const* btn2, float width,
std::function<void(FLAlertLayer*, bool)> selected, bool doShow
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow
) {
auto ret = QuickPopup::create(title, content, btn1, btn2, width, selected);
if (doShow) {
@ -41,7 +41,7 @@ FLAlertLayer* geode::createQuickPopup(
FLAlertLayer* geode::createQuickPopup(
char const* title, std::string const& content, char const* btn1, char const* btn2,
std::function<void(FLAlertLayer*, bool)> selected, bool doShow
MiniFunction<void(FLAlertLayer*, bool)> selected, bool doShow
) {
return createQuickPopup(title, content, btn1, btn2, 350.f, selected, doShow);
}

View file

@ -1,5 +1,5 @@
{
"geode": "0.4.1",
"geode": "0.6.1",
"version": "1.0.0",
"id": "geode.testdep",
"name": "Geode Test Dependency",

View file

@ -1,5 +1,5 @@
{
"geode": "0.4.1",
"geode": "0.6.1",
"version": "1.0.0",
"id": "geode.test",
"name": "Geode Test",