Skip to content

Commit 177489e

Browse files
committed
add async migration
1 parent c5c9a53 commit 177489e

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

tutorials/migrate-v5.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Migrating from Geode v4.x to v5.0
22

3+
## C++ Standard
4+
5+
Geode now requires C++23 to build. The mod template has been updated a while ago, but for older mods you might need to open `CMakeLists.txt` and edit this line:
6+
```cmake
7+
set(CMAKE_CXX_STANDARD 20)
8+
```
9+
10+
to say `23` instead of `20`.
11+
312
## Changes to `Popup`
413

514
`geode::Popup` is no longer templated, and instead accepts its own arguments in `Popup::init` (which also replaces `initAnchored`). It now uses the pattern similar to any other node. For example the following code:
@@ -55,6 +64,76 @@ protected:
5564
};
5665
```
5766

67+
## Async changes (web, file picker, etc.)
68+
69+
`geode::Task` has been replaced by an asynchronous system that utilizes C++ coroutines. This makes it much easier to write performant, concurrent code, but it also means there's a lot to change to port to the new system.
70+
71+
Functions like `geode::utils::file::pick` or `web::WebRequest::get` now return a Future that can be awaited or spawned to run in parallel. For example, to launch a global file picker in v4, you would use this code:
72+
73+
```cpp
74+
file::pick(...).listen([](Result<std::filesystem::path>* path) {
75+
if (path && path->isOk()) {
76+
auto path = path->unwrap();
77+
}
78+
});
79+
```
80+
81+
The new version for that would be:
82+
```cpp
83+
#include <Geode/utils/async.hpp>
84+
85+
async::spawn(
86+
file::pick(...),
87+
[](Result<std::filesystem::path> path) { // note that this is not a pointer anymore!
88+
if (path.isOk()) {
89+
auto path = path.unwrap();
90+
}
91+
}
92+
);
93+
```
94+
95+
This will behave similar to original, it will spawn `file::pick()` on the async runtime, and once completed, call the provided callback on the main thread. If you want more control over what happens (such as not calling your function on main thread), you can use the `Runtime` directly:
96+
```cpp
97+
arc::Runtime& rt = async::runtime();
98+
auto handle = rt.spawn([](this auto self) -> arc::Future<> {
99+
auto result = co_await file::pick(...);
100+
if (result.isOk()) {
101+
auto path = result.unwrap();
102+
}
103+
});
104+
```
105+
106+
If you've instead used listeners, a `async::TaskHolder` class was added which has a similar API. For example, the following v4 code that makes requests:
107+
108+
```cpp
109+
EventListener<WebTask> listener;
110+
111+
auto req = WebRequest().get("https://example.org");
112+
listener.bind([](WebTask::Event* e) {
113+
if (WebResponse* value = e->getValue()) {
114+
log::debug("Response: ", value->code());
115+
} else if (WebProgress* progress = e->getProgress()) {
116+
log::debug("Progress: ", progress->downloadProgress());
117+
}
118+
});
119+
listener.setFilter(req);
120+
```
121+
122+
should now be changed to this:
123+
124+
```cpp
125+
async::TaskHolder<WebResponse> listener;
126+
127+
listener.spawn(
128+
WebRequest().get("https://example.org"),
129+
[](WebResponse value) {
130+
log::debug("Response: {}", value.code());
131+
}
132+
);
133+
```
134+
135+
(TODO: we are yet to figure how to do progress)
136+
58137
## Changes to `std::function` arguments
59138

60139
Almost all parts of geode that accepted a `std::function` (such as `queueInMainThread`, `TextInput::setCallback`, etc.) have been changed to use `geode::Function` instead. The primary difference is that a `geode::Function` cannot be copied, only moved. Most proper usages should still compile and work properly, but if you have errors that are related to `std::function`, try adding `std::move`s or making sure to explicitly use `geode::Function` everywhere.

0 commit comments

Comments
 (0)