From c01a92ab1a0c35a13ff5c4664004636d459d491c Mon Sep 17 00:00:00 2001 From: 4ian <1280130+4ian@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:22:33 +0000 Subject: [PATCH] [Auto] [Improve] Fixed async events docs and improved network and storage feature documentation --- automated_updates_data.json | 4 +++ docs/gdevelop5/all-features/network/index.md | 21 ++++++++++++++++ docs/gdevelop5/all-features/storage/index.md | 17 +++++++++++++ docs/gdevelop5/events/async.md | 26 +++++++++++++++++--- 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/automated_updates_data.json b/automated_updates_data.json index 5ed505c4ec..11a333854f 100644 --- a/automated_updates_data.json +++ b/automated_updates_data.json @@ -44,6 +44,10 @@ { "date": "2026-02-18", "summary": "Improved audio docs with fade, pitch/rate, seeking, unload, and spatial sound; improved linked objects docs with bidirectional links, auto-cleanup, and use cases" + }, + { + "date": "2026-02-18", + "summary": "Fixed incomplete async events docs, added async action list and example; improved network docs with error handling and CORS notes; improved storage docs with data type guidance and JSON workaround" } ] } diff --git a/docs/gdevelop5/all-features/network/index.md b/docs/gdevelop5/all-features/network/index.md index 1271f4d58f..bdcc3d9a9d 100644 --- a/docs/gdevelop5/all-features/network/index.md +++ b/docs/gdevelop5/all-features/network/index.md @@ -20,6 +20,27 @@ GDevelop provides the action called "Send a request to a web page". You can spec When the server sends the response, it is saved in a variable so that you can read what was sent. +!!! note + + The "Send a request to a web page" action is **asynchronous**. Actions and sub-events placed after it will only run once the response has been received (or an error has occurred). See [asynchronous events](/gdevelop5/events/async/) for details. + +## Error handling + +The action accepts an optional **error variable**. After the request completes: + +- If the server responds with an HTTP status code **400 or higher** (e.g. 404 Not Found, 500 Server Error), the error variable is set to that status code as a string (e.g. `"404"`). +- If the request could not be sent at all (e.g. no internet connection, or a CORS issue on web builds), the error variable is set to `"REQUEST_NOT_SENT"`. +- If the request succeeds (status code below 400), the error variable remains empty and the response body is stored in the response variable. + +Use a condition to check whether the error variable is empty to detect success or failure: + +- Success: error variable equals `""` (empty string) +- Failure: error variable is not empty + +!!! warning + + On **web/HTML5 builds**, requests to a different domain may be blocked by the browser due to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) restrictions. Your server must include the appropriate `Access-Control-Allow-Origin` headers to allow requests from your game's domain. If the request is blocked, the error variable will be set to `"REQUEST_NOT_SENT"`. + ## How to format the content * For GET requests, parameters have to be sent in the content in the format of a "query string": diff --git a/docs/gdevelop5/all-features/storage/index.md b/docs/gdevelop5/all-features/storage/index.md index b94127e39c..2a13949c27 100644 --- a/docs/gdevelop5/all-features/storage/index.md +++ b/docs/gdevelop5/all-features/storage/index.md @@ -31,6 +31,23 @@ A group name can be used to organize the data that is being saved. This makes it - `"Player/PositionX"` to store the X position of the player. - `"Player/Life"` to store the life of the player. +## What data can be stored + +Storage actions can store **numbers** and **strings** (text). Each value is stored at a path made up of the storage name and the group path. + +To save a complex game state (e.g. an inventory or multiple player stats), you can either: + +- Use multiple storage entries with slash-separated group paths, such as `"Inventory/Sword"`, `"Inventory/Shield"`, etc. +- Convert a structure variable to JSON using `ToJSON(myVariable)`, store the resulting string, and later read it back and convert it with the "Convert JSON to a variable" action. + +!!! note + + Storage does **not** directly support storing array or structure variables in one action. Use the JSON conversion approach above if you need to save a whole variable structure at once. + +## Checking if data exists + +Use the condition **"Element exists in storage"** before reading a value to make sure a save file exists. This avoids reading an undefined value, for example on the very first launch of the game before any data has been saved. + ## Advanced: Clear the storage during a preview Data is stored permanently in the internal storage of the preview window, which is persisted across previews and even after GDevelop is closed (like in an exported game). diff --git a/docs/gdevelop5/events/async.md b/docs/gdevelop5/events/async.md index dc3a6585b1..3f0293f6ea 100644 --- a/docs/gdevelop5/events/async.md +++ b/docs/gdevelop5/events/async.md @@ -11,13 +11,33 @@ Sometimes though, you might want to make an exception. Some actions and conditio Asynchronous events are special actions that will not execute when called. Instead, they'll do a bit of work between each frame, and once it is done, will allow the actions and subevents following it to run. Just after being called, the actions and subevents following it will be skipped, as they'll only run when the asynchronous action has finished its work, and the event sheet will continue executing the rest normally. +## Which actions are asynchronous? + +The following built-in actions are asynchronous: + +- **Wait** (from the Time/timers feature) — pauses execution for a given duration without freezing the game. +- **Send a request to a web page** (from the Network feature) — waits for the server response before continuing. +- **File system** actions (desktop only) — file read, write, delete operations all have async variants. +- **Steamworks** actions — lobby creation, workshop operations, etc. + +Custom functions written with events can also be made asynchronous. See [asynchronous functions](/gdevelop5/events/functions/asynchronous-functions/). + ## Gotchas What you do **not** need to watch out for: - - Object picking - object picking works like normal events, previously picked objects will still be picked afterward. Objects deleted in the meantime will be unpicked. - - Using results of the event in actions or subevents after the asynchronous actions - If an action is just after an asynchronous action, or in a subevent of the event it was used in, it will only get executed once the asynchronous action is done with its work, so you can use + - **Object picking** — object picking works like normal events. Previously picked objects will still be picked after the async action finishes. Objects deleted in the meantime will be unpicked automatically. + - **Actions and sub-events that follow the async action** — any action placed directly after an asynchronous action in the same event, and any sub-events of the event containing the async action, are queued and will only run once the asynchronous action has finished. You can safely use the results of the async action in these actions and sub-events. What you **do** need to watch out for: - - Using the results of the asynchronous action or side effects of actions/subevents following it in a sibling event - uniquely actions following the asynchronous one in the same event, and events that are subevents of the event using the asynchronous action will be queued for execution after the asynchronous action has finished its job. The others will be executed synchronously. \ No newline at end of file + - **Sibling events** — events that are siblings (at the same indentation level) of the event containing the async action are *not* queued. They run synchronously at their normal turn in the event sheet, without waiting for the async action to complete. Do not rely on the results of an async action in a sibling event. + +## Example + +The **Wait** action is the simplest async action. The following events create a 2-second delay before deleting an enemy: + +1. Event: `[no condition]` → action: **Wait 2 seconds** *(async)* +2. Sub-event of the above → action: **Delete Enemy** + +Because "Delete Enemy" is in a sub-event of the event that contains the Wait action, it will only run after the 2 seconds have elapsed. The rest of the event sheet continues to run normally (the game does not freeze) while waiting. \ No newline at end of file