Merge branch 'geode-sdk:main' into main

This commit is contained in:
OmgRod 2025-02-25 18:43:08 +00:00 committed by GitHub
commit 1e8500c5db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 218 additions and 33 deletions

4
.git-blame-ignore-revs Normal file
View file

@ -0,0 +1,4 @@
# add clang format (#62)
11e81e3d64313d319955d9a214ad0ded78985bed
2bb416ba77f2f01897cc10a1afac40c957feadfc

View file

@ -236,7 +236,7 @@ if (ANDROID)
endif()
set(MAT_JSON_AS_INTERFACE ON)
CPMAddPackage("gh:geode-sdk/result@1.3.2")
CPMAddPackage("gh:geode-sdk/result@1.3.3")
CPMAddPackage("gh:geode-sdk/json@3.2.1")
CPMAddPackage("gh:fmtlib/fmt#11.0.2")

View file

@ -4,7 +4,7 @@
[project]
name = "Geode"
version = "v3.0.0"
version = "" # dont bother
repository = "https://github.com/geode-sdk/geode"
tree = "https://github.com/geode-sdk/geode/tree/main"
icon = "loader/resources/logos/geode-circle.png"
@ -18,6 +18,14 @@ assets = [
"docs/assets/handbook/vol2/*.png",
]
[[external-libs]]
pattern = "matjson"
repository = "https://github.com/geode-sdk/json"
[[external-libs]]
pattern = "Result.hpp"
repository = "https://github.com/geode-sdk/result"
[[sources]]
name = "Geode"
dir = "loader/include"
@ -42,6 +50,23 @@ include = [
# Bindings are generated at compile time
exists-online = false
[ignore]
patterns-name = [
# anything that starts with a double underscore
# shouldnt be included
"^__",
"^tinyxml2$",
"^format_as$",
# operator overloads
"^operator\\W"
]
patterns-full = [
"^geode::modifier",
"^geode::prelude",
"^geode::stl",
"^geode::geode_internal"
]
# CMake options
[cmake]

View file

@ -693,7 +693,7 @@ namespace pugi
xml_node& operator*() const;
xml_node* operator->() const;
const xml_node_iterator& operator++();
xml_node_iterator& operator++();
xml_node_iterator operator++(int);
const xml_node_iterator& operator--();
@ -735,7 +735,7 @@ namespace pugi
xml_attribute& operator*() const;
xml_attribute* operator->() const;
const xml_attribute_iterator& operator++();
xml_attribute_iterator& operator++();
xml_attribute_iterator operator++(int);
const xml_attribute_iterator& operator--();
@ -769,7 +769,7 @@ namespace pugi
xml_node& operator*() const;
xml_node* operator->() const;
const xml_named_node_iterator& operator++();
xml_named_node_iterator& operator++();
xml_named_node_iterator operator++(int);
private:

View file

@ -17,6 +17,9 @@ namespace geode {
struct TaskAwaiter;
}
template <typename T>
concept is_task_type = std::move_constructible<T> || std::same_as<T, void>;
/**
* Tasks represent an asynchronous operation that will be finished at some
* unknown point in the future. Tasks can report their progress, and will
@ -40,17 +43,17 @@ namespace geode {
* Once a Task has finished or has been cancelled, it can no longer be
* revived
* @tparam T The type the Task will eventually finish to. This type must be
* move-constructible; though as there is no way to move the value out
* move-constructible or void; though as there is no way to move the value out
* of the Task (because of potentially multiple listeners), one
* should ensure they can reasonably copy the value out in some form if they
* wish to gain ownership of it after the Task is finished
* @tparam P The type of the progress values the Task (may) post
*/
template <typename T, std::move_constructible P = std::monostate>
requires std::move_constructible<T> || std::same_as<T, void>
template <is_task_type T, std::move_constructible P = std::monostate>
class [[nodiscard]] Task final {
using Type = std::conditional_t<std::same_as<T, void>, TaskVoid, T>;
public:
using Type = std::conditional_t<std::same_as<T, void>, TaskVoid, T>;
/**
* A struct used for cancelling Tasks; Tasks may return an instance of
* this struct to cancel themselves, or to mark they have handled
@ -78,8 +81,7 @@ namespace geode {
return m_value.index() == 1;
}
template <typename T2, std::move_constructible P2>
requires std::move_constructible<T2> || std::same_as<T2, void>
template <is_task_type T2, std::move_constructible P2>
friend class Task;
public:
@ -170,8 +172,7 @@ namespace geode {
return m_status == status;
}
template <typename T2, std::move_constructible P2>
requires std::move_constructible<T2> || std::same_as<T2, void>
template <is_task_type T2, std::move_constructible P2>
friend class Task;
template <class, class>
@ -227,8 +228,7 @@ namespace geode {
return Event(handle, std::variant<Type*, P*, Cancel>(std::in_place_index<2>, Cancel()));
}
template <typename T2, std::move_constructible P2>
requires std::move_constructible<T2> || std::same_as<T2, void>
template <is_task_type T2, std::move_constructible P2>
friend class Task;
public:
@ -333,8 +333,7 @@ namespace geode {
}
}
template <typename T2, std::move_constructible P2>
requires std::move_constructible<T2> || std::same_as<T2, void>
template <is_task_type T2, std::move_constructible P2>
friend class Task;
template <class, class>
@ -1094,7 +1093,7 @@ namespace geode {
);
}
T await_resume() {
Task<T, P>::Type await_resume() {
return std::move(*task.getFinishedValue());
}
};

View file

@ -0,0 +1,100 @@
#pragma once
#include <coroutine>
#include <Geode/DefaultInclude.hpp>
#include "Task.hpp"
namespace geode {
template <is_task_type T = void, typename P = std::monostate>
class CoTask final {
using Type = Task<T, P>::Type;
Task<T, P> m_task;
public:
using promise_type = std::coroutine_traits<Task<T, P>>::promise_type;
auto operator<=>(const CoTask&) const = default;
operator Task<T, P>() { return std::move(m_task); }
CoTask() = default;
CoTask(CoTask&&) = default;
CoTask(Task<T, P>&& task) : m_task(std::move(task)) {}
Type* getFinishedValue() { return m_task.getFinishedValue(); }
void cancel() { return m_task.cancel(); }
void shallowCancel() { m_task.shallowCancel(); }
bool isPending() const { return m_task.isPending(); }
bool isFinished() const { return m_task.isFinished(); }
bool isCancelled() const { return m_task.isCancelled(); }
bool isNull() const { return m_task.isNull(); }
Task<T, P> task() { return std::move(m_task); }
static inline struct {
template <typename F>
decltype(auto) operator<<(F fn) { return fn(); }
} invoke;
};
namespace geode_internal {
template <typename T, typename E>
struct promise_type {
using Inner = std::optional<Result<T, E>>;
struct: public std::shared_ptr<Inner> {
using std::shared_ptr<Inner>::shared_ptr;
operator Result<T>() {
return (*this->get()).value();
}
} result{new Inner()};
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
auto get_return_object() { return result; }
void unhandled_exception() {}
void return_value(Result<T, E>&& value) { *result = std::move(value); }
};
template <typename T, typename E>
struct Awaiter {
Result<T, E> result;
bool await_ready() { return result.isOk(); }
T&& await_resume() { return std::move(result.unwrap()); }
Awaiter(Result<T, E>&& res) : result(std::move(res)) {}
template <typename U>
void await_suspend(std::coroutine_handle<U> handle) {
handle.promise().return_value(Err(result.unwrapErr()));
handle.destroy();
}
};
template <typename E>
struct Awaiter<void, E> {
Result<void, E> result;
bool await_ready() { return result.isOk(); }
void await_resume() { return; }
Awaiter(Result<void, E> res) : result(res) {}
template <typename U>
void await_suspend(std::coroutine_handle<U> handle) {
handle.promise().return_value(Err(result.unwrapErr()));
handle.destroy();
}
};
}
#define $async(...) geode::CoTask<>::invoke << [__VA_ARGS__]() -> geode::CoTask<>
#define $try geode::CoTask<>::invoke << [&]() -> geode::Result
};
template <typename T = void, typename E = std::string>
auto operator co_await(geode::Result<T, E>&& res) {
return geode::geode_internal::Awaiter { std::move(res) };
}
template <typename T, typename E, typename ...Args>
struct std::coroutine_traits<geode::Result<T, E>, Args...> {
using promise_type = geode::geode_internal::promise_type<T, E>;
};

View file

@ -209,7 +209,7 @@ namespace geode::utils::ranges {
template <ValidContainer C, ValidCUnaryPredicate<C> Predicate>
C filter(C const& container, Predicate filterFun) {
auto res = C();
std::copy_if(container.begin(), container.end(), res.end(), filterFun);
std::copy_if(container.begin(), container.end(), std::back_inserter(res), filterFun);
return res;
}
@ -238,7 +238,7 @@ namespace geode::utils::ranges {
typename C::value_type min(C const& container) {
auto it = std::min_element(container.begin(), container.end());
if (it == container.end()) {
return C::value_type();
return typename C::value_type();
}
return *it;
}
@ -264,7 +264,7 @@ namespace geode::utils::ranges {
typename C::value_type max(C const& container) {
auto it = std::max_element(container.begin(), container.end());
if (it == container.end()) {
return C::value_type();
return typename C::value_type();
}
return *it;
}

View file

@ -1,8 +1,4 @@
#include <Geode/Geode.hpp>
// TODO: this affects every platform :P, but i cant be bothered rn
#ifdef GEODE_IS_WINDOWS
#include <loader/LoaderImpl.hpp>
using namespace geode::prelude;
@ -15,6 +11,7 @@ $execute {
// for some reason cocos only properly returns false on winRT, everywhere
// else it just closes the whole game
#if defined(GEODE_IS_WINDOWS)
auto addr = reinterpret_cast<uintptr_t>(
GetProcAddress(
GetModuleHandle("libcocos2d.dll"), "?compileShader@CCGLProgram@cocos2d@@AEAA_NPEAIIPEBD@Z"
@ -25,9 +22,36 @@ $execute {
0x31, 0xc0, // xor eax, eax
0xeb, 0x07 // jmp +7 (to a nearby ret)
});
#elif defined(GEODE_IS_ANDROID64)
auto addr = reinterpret_cast<uintptr_t>(
dlsym(RTLD_DEFAULT, "_ZN7cocos2d11CCGLProgram13compileShaderEPjjPKc")
) + 0x74;
(void) Mod::get()->patch(reinterpret_cast<void*>(addr), {
0x1f, 0x20, 0x03, 0xd5 // nop (skip if statement)
});
#elif defined(GEODE_IS_ANDROID32)
auto addr = reinterpret_cast<uintptr_t>(
dlsym(RTLD_DEFAULT, "_ZN7cocos2d11CCGLProgram13compileShaderEPjjPKc")
) + 0x43;
(void) Mod::get()->patch(reinterpret_cast<void*>(addr), {
0x14, 0xe0 // b +2c (skip if statement)
});
#elif defined(GEODE_IS_ARM_MAC)
auto addr = base::get() + 0x393aa0;
(void) Mod::get()->patch(reinterpret_cast<void*>(addr), {
0x1f, 0x20, 0x03, 0xd5 // nop (skip if statement)
});
#elif defined(GEODE_IS_INTEL_MAC)
auto addr = base::get() + 0x417f65;
(void) Mod::get()->patch(reinterpret_cast<void*>(addr), {
0x48, 0x90, // nop (skip if statement)
});
#endif
#else
#pragma message("Unsupported GD version!")
#endif
};
#endif

View file

@ -92,6 +92,10 @@ std::string cocos2d::format_as(cocos2d::ccColor4B const& col) {
return fmt::format("rgba({}, {}, {}, {})", col.r, col.g, col.b, col.a);
}
std::string cocos2d::format_as(cocos2d::ccColor4F const& col) {
return fmt::format("rgba({}, {}, {}, {})", col.r, col.g, col.b, col.a);
}
// Log
inline static thread_local int32_t s_nestLevel = 0;

View file

@ -651,12 +651,6 @@ bool ModPopup::setup(ModSource&& src) {
return ListenerResult::Propagate;
});
#ifdef GEODE_IS_WINDOWS
if (src.asMod() && src.asMod()->isInternal()) {
class S:public CCLayer{CCSize m_size=CCSize(1,1);Ref<CCTexture2D> m_tex=nullptr;Ref<CCGLProgram> m_shader=nullptr;public: bool init()override {if(!CCLayer::init())return false;m_shader=new CCGLProgram();if(!m_shader->initWithVertexShaderByteArray("attribute vec4 a_position;attribute vec2 a_texCoord;varying vec2 v_texCoord;void main(){gl_Position=CC_MVPMatrix*a_position;v_texCoord=a_texCoord;}","varying vec2 v_texCoord;uniform sampler2D CC_Texture0;void main(){vec2 uv=v_texCoord;float t=CC_Time.y;float off=sin(uv.y*4.0-t*2.0)*sin(uv.y*13.-t*4.);float r=texture(CC_Texture0,uv-vec2(off*0.01,0)).r;float g=texture(CC_Texture0,uv-vec2(off*0.03,0)).g;float b=texture(CC_Texture0,uv-vec2(off*0.05,0)).b;vec4 col=vec4(r,g,b,1);col*=vec4(.5,1,.5,1);col=vec4(pow(col.rgb,vec3(.8)),1);gl_FragColor=col;}")){delete m_shader;return false;}uint32_t x=0;m_tex=new CCTexture2D;m_tex->autorelease();m_tex->initWithData(&x,kCCTexture2DPixelFormat_RGBA8888,1,1,CCSize(1,1));m_shader->addAttribute(kCCAttributeNamePosition,kCCVertexAttrib_Position);m_shader->addAttribute(kCCAttributeNameTexCoord,kCCVertexAttrib_TexCoords);m_shader->autorelease();m_shader->link();m_shader->updateUniforms();m_tex->setShaderProgram(m_shader);return true;}void draw()override {CCLayer::draw();glBindTexture(GL_TEXTURE_2D,m_tex->getName());auto size=CCEGLView::get()->getFrameSize();auto winSize=CCDirector::get()->getWinSize();if(size != m_size){m_size=size;glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,size.width,size.height,0,GL_RGBA,GL_UNSIGNED_BYTE,nullptr);}glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,size.width,size.height);m_shader->use();m_tex->drawInRect(CCRect(0.f,winSize.height,winSize.width,-winSize.height));if(auto z=CCScene::get()->getHighestChildZ(); z > this->getZOrder()){this->setZOrder(CCScene::get()->getHighestChildZ()+ 1);}}void add(CCObject*){if(auto* s=S::create())CCScene::get()->addChild(s);}CREATE_FUNC(S);};if(Loader::get()->getVersion()!=VersionInfo(4,2,0))return true;auto* node=m_stats->getChildByIDRecursive("version")->getChildByIDRecursive("value-label");node->setVisible(false);auto pos=node->convertToWorldSpace(node->getContentSize()/ 2.f);auto size=pos - node->convertToWorldSpace(-node->getContentSize()/ 2.f);auto* label=CCLabelBMFont::create("v4.2.0","bigFont.fnt");label->limitLabelWidth(size.x,1.f,0.001f);auto menu=CCMenu::create();auto btn=CCMenuItemSpriteExtra::create(label,this,menu_selector(S::add));btn->setPosition(pos);menu->setPosition(ccp(0,0));menu->addChild(btn);this->addChild(menu);
}
#endif
return true;
}

View file

@ -1,7 +1,9 @@
#include <Geode/Loader.hpp>
#include <Geode/loader/ModEvent.hpp>
#include <Geode/utils/cocos.hpp>
#include <chrono>
#include "../dependency/main.hpp"
#include "Geode/utils/general.hpp"
using namespace geode::prelude;
@ -25,6 +27,39 @@ $execute {
});
}
// Coroutines
#include <Geode/utils/async.hpp>
auto advanceFrame() {
auto [task, finish, progress, cancelled] = Task<void>::spawn();
queueInMainThread(std::bind(finish, true));
return task;
}
$execute {
$async() {
auto start = std::chrono::steady_clock::now();
log::info("Waiting for 10 frames...");
for (int i = 0; i < 10; ++i)
co_await advanceFrame();
log::info("Finished waiting! Took {} seconds", std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::now() - start
).count());
};
auto output = $try<VersionInfo> {
log::info("Parsing number 123: {}", co_await utils::numFromString<int>("123"));
log::info("Parsing number 12.3: {}", co_await utils::numFromString<int>("12.3"));
co_return VersionInfo::parse("1.2.3-alpha.4");
};
if (!output) {
log::info("$try successfully caught error");
}
}
#include <Geode/modify/MenuLayer.hpp>
struct $modify(MenuLayer) {
bool init() {