├── .gitignore
├── icon.png
├── .gitattributes
├── addons
└── godot-nesink
│ ├── plugin.gd
│ ├── plugin.cfg
│ ├── NesinkronaDeferIdleAsync.gd
│ ├── NesinkronaFromAsync.gd
│ ├── NesinkronaCanceledAsync.gd
│ ├── NesinkronaDeferPhysicsFrameAsync.gd
│ ├── NesinkronaDeferProcessFrameAsync.gd
│ ├── NesinkronaCompletedAsync.gd
│ ├── NesinkronaDelayAsync.gd
│ ├── NesinkronaThenAsync.gd
│ ├── NesinkronaFromCallbackAsync.gd
│ ├── NesinkronaUnwrapAsync.gd
│ ├── NesinkronaRaceAsync.gd
│ ├── NesinkronaAnyAsync.gd
│ ├── NesinkronaThenCallbackAsync.gd
│ ├── NesinkronaAllAsync.gd
│ ├── NesinkronaAllSettledAsync.gd
│ ├── Cancel.gd
│ ├── NesinkronaFromSignalAsync.gd
│ ├── NesinkronaFromSignalNameAsync.gd
│ ├── NesinkronaAsyncBase.gd
│ ├── NesinkronaConditionalSignalNameAsync.gd
│ ├── NesinkronaConditionalSignalAsync.gd
│ └── Async.gd
├── project.godot
├── icon.png.import
├── LICENSE.md
├── README_zh.md
├── README_ja.md
├── README.md
├── Test_Task.tscn
└── Test_Task.gd
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/folt-a/godot-nesink/HEAD/icon.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Normalize EOL for all files that Git considers text files.
2 | * text=auto eol=lf
3 |
--------------------------------------------------------------------------------
/addons/godot-nesink/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 | #-------------------------------------------------------------------------------
5 |
6 | func _get_plugin_name() -> String:
7 | return "Nesinkrona"
8 |
--------------------------------------------------------------------------------
/addons/godot-nesink/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Nesinkrona"
4 | description="Pseudo (task based) asynchronous patterns for Godot 4."
5 | author="Ydi (@ydipeepo), @folt-a"
6 | version="1.0.2"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaDeferIdleAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaDeferIdleAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init() -> void:
6 | _on_completed.call_deferred()
7 |
8 | func _on_completed() -> void:
9 | if is_pending:
10 | complete_release(null)
11 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaFromAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init(coroutine: Callable) -> void:
6 | _init_core(coroutine)
7 |
8 | func _init_core(coroutine: Callable) -> void:
9 | reference()
10 | complete_release(await coroutine.call())
11 | unreference()
12 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaCanceledAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaCanceledAsync extends Async
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # メソッド
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | func wait(cancel: Cancel = null) -> Variant:
8 | return null
9 |
10 | func get_state() -> int:
11 | return STATE_CANCELED
12 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaDeferPhysicsFrameAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaDeferPhysicsFrameAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init() -> void:
6 | get_tree().physics_frame.connect(_on_completed)
7 |
8 | func _on_completed() -> void:
9 | get_tree().physics_frame.disconnect(_on_completed)
10 | if is_pending:
11 | complete_release(null)
12 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaDeferProcessFrameAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaDeferProcessFrameAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init() -> void:
6 | get_tree().process_frame.connect(_on_completed)
7 |
8 | func _on_completed() -> void:
9 | get_tree().process_frame.disconnect(_on_completed)
10 | if is_pending:
11 | complete_release(null)
12 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaCompletedAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaCompletedAsync extends Async
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # メソッド
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | func wait(cancel: Cancel = null) -> Variant:
8 | return _result
9 |
10 | func get_state() -> int:
11 | return STATE_COMPLETED
12 |
13 | #---------------------------------------------------------------------------------------------------
14 |
15 | var _result: Variant
16 |
17 | func _init(result: Variant) -> void:
18 | _result = result
19 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="godot-nesink"
14 | config/description="Pseudo (task based) asynchronous patterns for Godot 4."
15 | run/main_scene="res://Test_Task.tscn"
16 | config/features=PackedStringArray("4.3")
17 |
18 | [editor_plugins]
19 |
20 | enabled=PackedStringArray("res://addons/godot-nesink/plugin.cfg")
21 |
22 | [rendering]
23 |
24 | vulkan/rendering/back_end=1
25 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaDelayAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaDelayAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # 定数
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | const MIN_TIMEOUT := 0.0
8 |
9 | #---------------------------------------------------------------------------------------------------
10 |
11 | var _timeout: float
12 |
13 | func _init(timeout: float) -> void:
14 | assert(MIN_TIMEOUT <= timeout)
15 |
16 | _timeout = timeout
17 | get_tree().create_timer(timeout).timeout.connect(_on_timeout)
18 |
19 | func _on_timeout() -> void:
20 | complete_release(_timeout)
21 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaThenAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaThenAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init(drain: Async, drain_cancel: Cancel, coroutine: Callable) -> void:
6 | assert(drain != null)
7 |
8 | _init_core(drain, drain_cancel, coroutine)
9 |
10 | func _init_core(drain: Async, drain_cancel: Cancel, coroutine: Callable) -> void:
11 | reference()
12 | var drain_result: Variant = await drain.wait(drain_cancel)
13 | match drain.get_state():
14 | STATE_CANCELED:
15 | cancel_release()
16 | STATE_COMPLETED:
17 | complete_release(await coroutine.call(drain_result))
18 | _:
19 | assert(false, "BUG")
20 | unreference()
21 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaFromCallbackAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromCallbackAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | var _pending := true
6 |
7 | func _init(coroutine: Callable, unbind_cancel: bool) -> void:
8 | if unbind_cancel:
9 | coroutine = coroutine.unbind(1)
10 | _init_core(coroutine)
11 |
12 | func _init_core(coroutine: Callable) -> void:
13 | reference()
14 | await coroutine.call(_complete_core, _cancel_core)
15 |
16 | func _complete_core(result: Variant = null) -> void:
17 | if _pending:
18 | _pending = false
19 | complete_release(result)
20 | unreference()
21 |
22 | func _cancel_core() -> void:
23 | if _pending:
24 | _pending = false
25 | cancel_release()
26 | unreference()
27 |
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bybb02k5ddtuj"
6 | path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.png"
14 | dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaUnwrapAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaUnwrapAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | func _init(drain: Async, drain_cancel: Cancel, depth: int) -> void:
6 | assert(0 < depth)
7 | assert(drain_cancel == null or not drain_cancel.is_requested)
8 |
9 | _init_core(drain, drain_cancel, depth)
10 |
11 | func _init_core(drain: Variant, drain_cancel: Cancel, depth: int) -> void:
12 | reference()
13 | var drain_result: Variant = await drain.wait(drain_cancel)
14 | while drain_result is Async and depth != 0:
15 | drain = drain_result
16 | drain_result = await drain.wait(drain_cancel)
17 | depth -= 1
18 | match drain.get_state():
19 | STATE_CANCELED:
20 | cancel_release()
21 | STATE_COMPLETED:
22 | complete_release(drain_result)
23 | _:
24 | assert(false, "BUG")
25 | unreference()
26 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaRaceAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaRaceAsync extends NesinkronaAsyncBase
2 |
3 | #-------------------------------------------------------------------------------
4 |
5 | var _pending_drains: int
6 |
7 | func _init(drains: Array, drain_cancel: Cancel) -> void:
8 | assert(not drains.is_empty())
9 |
10 | var drain_count := drains.size()
11 |
12 | _pending_drains = drain_count
13 | for drain_index: int in drain_count:
14 | _init_core(
15 | normalize_drain(drains[drain_index]),
16 | drain_cancel)
17 |
18 | func _init_core(drain: Variant, drain_cancel: Cancel) -> void:
19 | if drain is Async:
20 | reference()
21 | var drain_result: Variant = await drain.wait(drain_cancel)
22 | _pending_drains -= 1
23 | match drain.get_state():
24 | STATE_CANCELED:
25 | if _pending_drains == 0:
26 | complete_release(NesinkronaCanceledAsync.new())
27 | STATE_COMPLETED:
28 | complete_release(NesinkronaCompletedAsync.new(drain_result))
29 | _:
30 | assert(false, "BUG")
31 | unreference()
32 | else:
33 | complete_release(NesinkronaCompletedAsync.new(drain))
34 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaAnyAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaAnyAsync extends NesinkronaAsyncBase
2 |
3 | #-------------------------------------------------------------------------------
4 |
5 | var _pending_drains: int
6 |
7 | func _init(drains: Array, drain_cancel: Cancel) -> void:
8 | assert(not drains.is_empty())
9 | assert(drain_cancel == null or not drain_cancel.is_requested)
10 |
11 | var drain_count := drains.size()
12 |
13 | _pending_drains = drain_count
14 | for drain_index: int in drain_count:
15 | _init_core(
16 | normalize_drain(drains[drain_index]),
17 | drain_cancel)
18 |
19 | func _init_core(
20 | drain: Variant,
21 | drain_cancel: Cancel) -> void:
22 |
23 | if drain is Async:
24 | reference()
25 | var drain_result: Variant = await drain.wait(drain_cancel)
26 | _pending_drains -= 1
27 | match drain.get_state():
28 | STATE_CANCELED:
29 | if _pending_drains == 0:
30 | cancel_release()
31 | STATE_COMPLETED:
32 | complete_release(drain_result)
33 | _:
34 | assert(false, "BUG")
35 | unreference()
36 | else:
37 | _pending_drains -= 1
38 | complete_release(drain)
39 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2022 Ydi (@ydipeepo) and Nesinkrona contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaThenCallbackAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaThenCallbackAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 |
5 | var _pending := true
6 |
7 | func _init(
8 | drain: Async,
9 | drain_cancel: Cancel,
10 | coroutine: Callable,
11 | unbind_cancel: bool) -> void:
12 |
13 | assert(drain != null)
14 |
15 | if unbind_cancel:
16 | coroutine = coroutine.unbind(1)
17 | _init_core(drain, drain_cancel, coroutine)
18 |
19 | func _init_core(drain: Async, drain_cancel: Cancel, coroutine: Callable) -> void:
20 | var drain_result: Variant = await drain.wait(drain_cancel)
21 | match drain.get_state():
22 | STATE_CANCELED:
23 | cancel_release()
24 | _pending = true
25 | STATE_COMPLETED:
26 | reference()
27 | await coroutine.call(drain_result, _complete_core, _cancel_core)
28 | _:
29 | assert(false, "BUG")
30 |
31 | func _complete_core(result: Variant = null) -> void:
32 | if _pending:
33 | _pending = false
34 | complete_release(result)
35 | unreference()
36 |
37 | func _cancel_core() -> void:
38 | if _pending:
39 | _pending = false
40 | cancel_release()
41 | unreference()
42 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaAllAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaAllAsync extends NesinkronaAsyncBase
2 |
3 | #-------------------------------------------------------------------------------
4 |
5 | var _pending_drains: int
6 |
7 | func _init(drains: Array, drain_cancel: Cancel) -> void:
8 | assert(not drains.is_empty())
9 |
10 | var drain_count := drains.size()
11 | var result := []
12 | result.resize(drain_count)
13 |
14 | _pending_drains = drain_count
15 | for drain_index: int in drain_count:
16 | _init_core(
17 | normalize_drain(drains[drain_index]),
18 | drain_cancel,
19 | drain_index,
20 | result)
21 |
22 | func _init_core(
23 | drain: Variant,
24 | drain_cancel: Cancel,
25 | drain_index: int,
26 | result: Array) -> void:
27 |
28 | if drain is Async:
29 | reference()
30 | result[drain_index] = await drain.wait(drain_cancel)
31 | _pending_drains -= 1
32 | match drain.get_state():
33 | STATE_CANCELED:
34 | cancel_release()
35 | STATE_COMPLETED:
36 | if _pending_drains == 0:
37 | complete_release(result)
38 | _:
39 | assert(false, "BUG")
40 | unreference()
41 | else:
42 | result[drain_index] = drain
43 | _pending_drains -= 1
44 | if _pending_drains == 0:
45 | complete_release(result)
46 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaAllSettledAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaAllSettledAsync extends NesinkronaAsyncBase
2 |
3 | #-------------------------------------------------------------------------------
4 |
5 | var _pending_drains: int
6 |
7 | func _init(drains: Array, drain_cancel: Cancel) -> void:
8 | assert(not drains.is_empty())
9 |
10 | var drain_count := drains.size()
11 | var result := []
12 | result.resize(drain_count)
13 |
14 | _pending_drains = drain_count
15 | for drain_index: int in drain_count:
16 | _init_core(
17 | normalize_drain(drains[drain_index]),
18 | drain_cancel,
19 | drain_index,
20 | result)
21 |
22 | func _init_core(
23 | drain: Variant,
24 | drain_cancel: Cancel,
25 | drain_index: int,
26 | result: Array) -> void:
27 |
28 | if drain is Async:
29 | reference()
30 | var drain_result: Variant = await drain.wait(drain_cancel)
31 | match drain.get_state():
32 | STATE_CANCELED:
33 | result[drain_index] = NesinkronaCanceledAsync.new()
34 | STATE_COMPLETED:
35 | result[drain_index] = NesinkronaCompletedAsync.new(drain_result)
36 | _:
37 | assert(false, "BUG")
38 | _pending_drains -= 1
39 | if _pending_drains == 0:
40 | complete_release(result)
41 | unreference()
42 | else:
43 | result[drain_index] = NesinkronaCompletedAsync.new(drain)
44 | _pending_drains -= 1
45 | if _pending_drains == 0:
46 | complete_release(result)
47 |
--------------------------------------------------------------------------------
/addons/godot-nesink/Cancel.gd:
--------------------------------------------------------------------------------
1 | ## [Async] や [AsyncSequence] にキャンセルが要求されたことを伝えるためのクラスです。
2 | class_name Cancel extends RefCounted
3 |
4 | #-------------------------------------------------------------------------------
5 | # シグナル
6 | #-------------------------------------------------------------------------------
7 |
8 | ## [b](アドオン内もしくは実装内でのみ使用)[/b] キャンセルされたとき発火するシグナル。[br]
9 | ## [br]
10 | ## このシグナルはアドオン外からの利用を想定していません。[br]
11 | ## デッドロックしてしまったり、[RefCounted] の寿命を跨いでしまったり、[br]
12 | ## 安全ではないため [Async] の実装内でのみ使用するようにしてください。[br]
13 | ## [br]
14 | ## Usage:
15 | ## [codeblock]
16 | ## var cancel: Cancel = ...
17 | ## if not cancel.is_requested: # 必ずチェックすること
18 | ## await cancel.requested
19 | ## [/codeblock]
20 | signal requested
21 |
22 | #-------------------------------------------------------------------------------
23 | # プロパティ
24 | #-------------------------------------------------------------------------------
25 |
26 | ## キャンセルが要求されているかを返します。
27 | var is_requested: bool:
28 | get: return _is_requested
29 |
30 | #-------------------------------------------------------------------------------
31 | # メソッド
32 | #-------------------------------------------------------------------------------
33 |
34 | ## タイムアウトするとキャンセルが要求されるキャンセルを作成します。
35 | static func timeout(timeout_: float) -> Cancel:
36 | var cancel := new()
37 | NesinkronaAsyncBase \
38 | .get_tree() \
39 | .create_timer(timeout_) \
40 | .timeout \
41 | .connect(cancel.request)
42 | return cancel
43 |
44 | ## キャンセルされた状態のキャンセルを作成します。
45 | static func canceled() -> Cancel:
46 | if _canceled == null:
47 | _canceled = new()
48 | _canceled.request()
49 | return _canceled
50 |
51 | ## キャンセルを要求します。
52 | func request() -> void:
53 | if not _is_requested:
54 | _is_requested = true
55 | requested.emit()
56 |
57 | #-------------------------------------------------------------------------------
58 |
59 | static var _canceled: Cancel
60 |
61 | var _is_requested := false
62 |
--------------------------------------------------------------------------------
/README_zh.md:
--------------------------------------------------------------------------------
1 | [English](https://github.com/folt-a/godot-nesink/blob/main/README.md) | [日本語](https://github.com/folt-a/godot-nesink/blob/main/README_ja.md) | 简体中文
2 |
3 |
4 |
5 | [](https://github.com/folt-a/godot-motion/blob/main/LICENSE.md)
6 |
7 |
8 |
9 | # Nesinkrona (for Godot 4)
10 |
11 | 一个增强 GDScript 2.0 await 的插件。
12 |
13 |
14 |
15 | * 它提高了与信号和程序交织在一起的代码的可读性和自然度。(类似于 JS 的 Promise 或 C# 的 Task)
16 | * 由于代码简单,所以速度快。
17 | * 可以从外部取消 await。
18 | * 包含 yield 重现迭代的类型。(实验的)
19 |
20 |
21 |
22 | ---
23 |
24 | ```GDScript
25 | # 多个 Async 或信号 (Signal) 或 Coroutine 会组合成一个新的 Async
26 | var all_async := Async.all([
27 | Async.from(_coro), # from Async
28 | obj.signal, # from Signal
29 | func(): return 0 # from Coroutine
30 | ])
31 | var result = await all_async.wait()
32 |
33 | # 或者可以立即 await 它
34 | var result = await Async.wait_all([
35 | Async.from(_coro),
36 | obj.signal,
37 | func(): return 0
38 | ])
39 |
40 | # 包括等待的大部分一般模式
41 | Async.all()
42 | Async.all_settled()
43 | Async.any()
44 | Async.race()
45 | Async.wait_all()
46 | Async.wait_all_settled()
47 | Async.wait_any()
48 | Async.wait_race()
49 |
50 | # 支持 Async 的延续和取消
51 | var another_async = async.then(func(prev_result):
52 | return prev_result * prev_result)
53 | var cancel := Cancel.new()
54 | await another_async.wait(cancel)
55 | ```
56 |
57 |
58 |
59 | ---
60 |
61 |
62 |
63 | ## 如何使用
64 |
65 |
66 |
67 | #### 检查演示项目
68 |
69 | 1. Git Clone 然后在 Godot 引擎中打开。
70 | 2. (选择 `demo/Demo.tscn` 作为主场景然后) F5
71 |
72 |
73 |
74 | #### 安装这插件
75 |
76 | 1. Git clone 然后将 `addons/godot-nesink` 复制到您的项目中。
77 | 2. 启用 `Nesinkrona` 插件。
78 | 3. 写写代码。
79 |
80 |
81 |
82 | 还有细节: [📖 维基 (Google Translated)](https://github-com.translate.goog/folt-a/godot-nesink/wiki/Async?_x_tr_sl=auto&_x_tr_tl=zh-cn)
83 |
84 |
85 |
86 | ---
87 |
88 |
89 |
90 | ## 贡献
91 |
92 | 我们非常欢迎提供 bug 的修复、文档翻译,和任何其他改进! 谢谢!
93 |
94 | ## Original repository
95 |
96 | This repository was transfer from [ydipeepo](https://github.com/ydipeepo)
--------------------------------------------------------------------------------
/README_ja.md:
--------------------------------------------------------------------------------
1 | [English](https://github.com/folt-a/godot-nesink/blob/main/README.md) | 日本語 | [简体中文](https://github.com/folt-a/godot-nesink/blob/main/README_zh.md)
2 |
3 |
4 |
5 | [](https://github.com/folt-a/godot-motion/blob/main/LICENSE.md)
6 |
7 |
8 |
9 | # Nesinkrona (for Godot 4)
10 |
11 | Godot 4 の await 足回りを強化するアドオン。[Async Helper](https://github.com/ydipeepo/godot-async-helper) (Godot 3) の Godot 4 移植版です。
12 |
13 |
14 |
15 | * シグナルやコルーチンが入り組むコードの見通しを良くし、自然に書けるようにします (JS の Promise や C# の Task に近いです)
16 | * 実装が単純なので高速です
17 | * await 外からキャンセルすることができます (外部から中断させることができる)
18 | * yield によるイテレーションを再現するパターンを含みます (実験的)
19 |
20 | ---
21 |
22 |
23 |
24 | ```GDScript
25 | # 複数の Async もしくは Signal, コルーチンを新たな Async としてまとめることができます
26 | var all_async := Async.all([
27 | Async.from(_coro), # Async から
28 | obj.signal, # Signal から
29 | func(): return 0 # Coroutine から
30 | ])
31 | var result = await all_async.wait()
32 |
33 | # もしくは、即時待機することもできます
34 | var result = await Async.wait_all([
35 | Async.from(_coro), # from Async
36 | obj.signal, # from Signal
37 | func():
38 | # from Coroutine
39 | pass
40 | ])
41 |
42 | # await のための一般的なメソッドをすべて含みます
43 | Async.all()
44 | Async.all_settled()
45 | Async.any()
46 | Async.race()
47 | Async.wait_all()
48 | Async.wait_all_settled()
49 | Async.wait_any()
50 | Async.wait_race()
51 |
52 | # 継続やキャンセルもサポートします
53 | var another_async = async.then(func(prev_result):
54 | return prev_result * prev_result)
55 | var cancel := Cancel.new()
56 | await another_async.wait(cancel)
57 | ```
58 |
59 |
60 |
61 | ---
62 |
63 |
64 |
65 | ## 準備
66 |
67 |
68 |
69 | #### デモを確認したい
70 |
71 | 1. このリポジトリをクローンして Godot Engine で開きます
72 | 2. (`demos/Demo.tscn` をメインシーンに設定して、) F5
73 |
74 | #### アドオンを導入したい
75 |
76 | 1. `addons/godot-nesink` ディレクトリを丸ごとプロジェクトに複製します
77 | 2. `Nesinkrona` アドオンを有効にします
78 | 3. 書く。
79 |
80 |
81 |
82 | Async クラス詳細はこちら: [📖 Wiki](https://github.com/folt-a/godot-nesink/wiki/Async)
83 |
84 |
85 |
86 | ---
87 |
88 |
89 |
90 | ## バグの報告や要望など
91 |
92 | バグの修正や報告、ドキュメント翻訳、およびその他の改善など歓迎いたします。
93 |
94 | ## 元リポジトリ
95 |
96 | このリポジトリは、[ydipeepo](https://github.com/ydipeepo) さんから転送されたものです。
97 |
98 | ありがとうございます……!
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaFromSignalAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromSignalAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # 定数
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | const MAX_SIGNAL_ARGC := 5
8 |
9 | #---------------------------------------------------------------------------------------------------
10 |
11 | var _object: Object
12 |
13 | func _init(signal_: Signal, signal_argc: int) -> void:
14 | assert(signal_argc <= MAX_SIGNAL_ARGC)
15 |
16 | _object = signal_.get_object()
17 |
18 | if is_instance_valid(_object):
19 | match signal_argc:
20 | 0: signal_.connect(_on_completed_0, CONNECT_REFERENCE_COUNTED)
21 | 1: signal_.connect(_on_completed_1, CONNECT_REFERENCE_COUNTED)
22 | 2: signal_.connect(_on_completed_2, CONNECT_REFERENCE_COUNTED)
23 | 3: signal_.connect(_on_completed_3, CONNECT_REFERENCE_COUNTED)
24 | 4: signal_.connect(_on_completed_4, CONNECT_REFERENCE_COUNTED)
25 | 5: signal_.connect(_on_completed_5, CONNECT_REFERENCE_COUNTED)
26 | else:
27 | assert(not signal_.is_null())
28 | match signal_argc:
29 | 0: signal_.connect(_on_completed_0)
30 | 1: signal_.connect(_on_completed_1)
31 | 2: signal_.connect(_on_completed_2)
32 | 3: signal_.connect(_on_completed_3)
33 | 4: signal_.connect(_on_completed_4)
34 | 5: signal_.connect(_on_completed_5)
35 |
36 | func _on_completed_0() -> void:
37 | if is_pending:
38 | complete_release([])
39 | _object = null
40 |
41 | func _on_completed_1(arg1: Variant) -> void:
42 | if is_pending:
43 | complete_release([arg1])
44 | _object = null
45 |
46 | func _on_completed_2(arg1: Variant, arg2: Variant) -> void:
47 | if is_pending:
48 | complete_release([arg1, arg2])
49 | _object = null
50 |
51 | func _on_completed_3(arg1: Variant, arg2: Variant, arg3: Variant) -> void:
52 | if is_pending:
53 | complete_release([arg1, arg2, arg3])
54 | _object = null
55 |
56 | func _on_completed_4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant) -> void:
57 | if is_pending:
58 | complete_release([arg1, arg2, arg3, arg4])
59 | _object = null
60 |
61 | func _on_completed_5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant) -> void:
62 | if is_pending:
63 | complete_release([arg1, arg2, arg3, arg4, arg5])
64 | _object = null
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | English | [日本語](https://github.com/folt-a/godot-nesink/blob/main/README_ja.md) | [简体中文](https://github.com/folt-a/godot-nesink/blob/main/README_zh.md)
2 |
3 |
4 |
5 | [](https://github.com/folt-a/godot-nesink/blob/main/LICENSE.md)
6 |
7 |
8 |
9 | # Nesinkrona (for Godot 4)
10 |
11 | An addon to enhance the awaitability of GDScript 2.0.
12 |
13 |
14 |
15 | * It improves the readability and naturalness of code that is intermingled with signals and coroutines. (similar to Promise in JS or Task in C#).
16 | * Fast due to simple implementation.
17 | * Can be canceled from outside of await.
18 | * Contains patterns that reproduce iterations with yield. (experimental)
19 |
20 |
21 |
22 | ---
23 |
24 | ```GDScript
25 | # Multiple Async or Signal or Coroutine can be combined into a new Async
26 | var all_async := Async.all([
27 | Async.from(_coro), # from Async
28 | obj.signal, # from Signal
29 | func(): return 0 # from Coroutine
30 | ])
31 | var result = await all_async.wait()
32 |
33 | # or you can await it immediately.
34 | var result = await Async.wait_all([
35 | Async.from(_coro),
36 | obj.signal,
37 | func(): return 0
38 | ])
39 |
40 | # Includes general patterns for await
41 | Async.all()
42 | Async.all_settled()
43 | Async.any()
44 | Async.race()
45 | Async.wait_all()
46 | Async.wait_all_settled()
47 | Async.wait_any()
48 | Async.wait_race()
49 |
50 | # and support continuations and cancellations.
51 | var another_async = async.then(func(prev_result):
52 | return prev_result * prev_result)
53 | var cancel := Cancel.new()
54 | await another_async.wait(cancel)
55 | ```
56 |
57 |
58 |
59 | ## How do I use it?
60 |
61 |
62 |
63 | #### Checking demos
64 |
65 | 1. Git clone then open in Godot Engine.
66 | 2. (Select `demo/Demo.tscn` as Main Scene then) F5!
67 |
68 |
69 |
70 | #### Add-on installation
71 |
72 | 1. Git clone then copy `addons/godot-nesink` to your project.
73 | 2. Activate `Nesinkrona` addon.
74 | 3. Code!
75 |
76 |
77 |
78 | And details: [📖 Wiki (Google Translated)](https://github-com.translate.goog/folt-a/godot-nesink/wiki/Async?_x_tr_sl=auto&_x_tr_tl=en)
79 |
80 |
81 |
82 | ---
83 |
84 |
85 |
86 | ## Contributing
87 |
88 | We are grateful to the community for contributing bug fixes, documentation, translations, and any other improvements!
89 |
90 |
91 |
92 | ## Original repository
93 |
94 | This repository was transfer from [ydipeepo](https://github.com/ydipeepo)
95 |
96 | ありがとうございます……!
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaFromSignalNameAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromSignalNameAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # 定数
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | const MAX_SIGNAL_ARGC := 5
8 |
9 | #---------------------------------------------------------------------------------------------------
10 |
11 | var _object: Object
12 | var _signal_name: StringName
13 |
14 | func _init(object: Object, signal_name: StringName, signal_argc: int) -> void:
15 | assert(object != null)
16 | assert(signal_argc <= MAX_SIGNAL_ARGC)
17 |
18 | _object = object
19 | _signal_name = signal_name
20 |
21 | if is_instance_valid(_object):
22 | match signal_argc:
23 | 0: _object.connect(_signal_name, _on_completed_0)
24 | 1: _object.connect(_signal_name, _on_completed_1)
25 | 2: _object.connect(_signal_name, _on_completed_2)
26 | 3: _object.connect(_signal_name, _on_completed_3)
27 | 4: _object.connect(_signal_name, _on_completed_4)
28 | 5: _object.connect(_signal_name, _on_completed_5)
29 | else:
30 | cancel_release()
31 |
32 | func _on_completed_0() -> void:
33 | if is_instance_valid(_object):
34 | _object.disconnect(_signal_name, _on_completed_0)
35 | _object = null
36 | if is_pending:
37 | complete_release([])
38 |
39 | func _on_completed_1(arg1: Variant) -> void:
40 | if is_instance_valid(_object):
41 | _object.disconnect(_signal_name, _on_completed_1)
42 | _object = null
43 | if is_pending:
44 | complete_release([arg1])
45 |
46 | func _on_completed_2(arg1: Variant, arg2: Variant) -> void:
47 | if is_instance_valid(_object):
48 | _object.disconnect(_signal_name, _on_completed_2)
49 | _object = null
50 | if is_pending:
51 | complete_release([arg1, arg2])
52 |
53 | func _on_completed_3(arg1: Variant, arg2: Variant, arg3: Variant) -> void:
54 | if is_instance_valid(_object):
55 | _object.disconnect(_signal_name, _on_completed_3)
56 | _object = null
57 | if is_pending:
58 | complete_release([arg1, arg2, arg3])
59 |
60 | func _on_completed_4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant) -> void:
61 | if is_instance_valid(_object):
62 | _object.disconnect(_signal_name, _on_completed_4)
63 | _object = null
64 | if is_pending:
65 | complete_release([arg1, arg2, arg3, arg4])
66 |
67 | func _on_completed_5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant) -> void:
68 | if is_instance_valid(_object):
69 | _object.disconnect(_signal_name, _on_completed_5)
70 | _object = null
71 | if is_pending:
72 | complete_release([arg1, arg2, arg3, arg4, arg5])
73 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaAsyncBase.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaAsyncBase extends Async
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # メソッド
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | static func get_tree() -> SceneTree:
8 | if _tree == null:
9 | _tree = Engine.get_main_loop()
10 | return _tree
11 |
12 | func get_state() -> int:
13 | return _state
14 |
15 | func wait(cancel: Cancel = null):
16 | if _state == STATE_PENDING:
17 | _state = STATE_PENDING_WITH_WAITERS
18 | if _state == STATE_PENDING_WITH_WAITERS:
19 | if cancel:
20 | await _wait_with_cancel(cancel)
21 | else:
22 | await _wait()
23 | return _result
24 |
25 | func complete_release(result: Variant) -> void:
26 | match _state:
27 | STATE_PENDING:
28 | _result = result
29 | _state = STATE_COMPLETED
30 | STATE_PENDING_WITH_WAITERS:
31 | _result = result
32 | _state = STATE_COMPLETED
33 | _release.emit()
34 |
35 | func cancel_release() -> void:
36 | match _state:
37 | STATE_PENDING:
38 | _state = STATE_CANCELED
39 | STATE_PENDING_WITH_WAITERS:
40 | _state = STATE_CANCELED
41 | _release.emit()
42 |
43 | # https://github.com/folt-a/godot-nesink/issues/4
44 | static func normalize_drain(drain):
45 | if drain is Array:
46 | match len(drain):
47 | # 3:
48 | # if drain[0] is Object and (drain[1] is String or drain[1] is StringName) and drain[2] is int:
49 | # return NesinkronaFromSignalNameAsync.new(drain[0], drain[1], drain[2])
50 | 2:
51 | # if drain[0] is Object and (drain[1] is String or drain[1] is StringName):
52 | # return NesinkronaFromSignalNameAsync.new(drain[0], drain[1], 0)
53 | if drain[0] is Signal and drain[1] is int:
54 | return NesinkronaFromSignalAsync.new(drain[0], drain[1])
55 | 1:
56 | # if drain[0] is Object:
57 | # return NesinkronaFromSignalNameAsync.new(drain[0], "completed", 0)
58 | if drain[0] is Signal:
59 | return NesinkronaFromSignalAsync.new(drain[0], 0)
60 |
61 | # if drain is Object:
62 | # return NesinkronaFromSignalNameAsync.new(drain[0], "completed", 0)
63 |
64 | if drain is Signal:
65 | return NesinkronaFromSignalAsync.new(drain, 0)
66 |
67 | if drain is Callable:
68 | return NesinkronaFromAsync.new(drain)
69 |
70 | return drain
71 |
72 | #---------------------------------------------------------------------------------------------------
73 |
74 | signal _release
75 |
76 | static var _tree: SceneTree
77 |
78 | var _state := STATE_PENDING
79 | var _result
80 |
81 | func _wait() -> void:
82 | assert(_state == STATE_PENDING_WITH_WAITERS)
83 | await _release
84 |
85 | func _wait_with_cancel(cancel: Cancel) -> void:
86 | assert(_state == STATE_PENDING_WITH_WAITERS)
87 |
88 | if cancel.is_requested:
89 | cancel_release()
90 | return
91 |
92 | cancel.reference()
93 | cancel.requested.connect(_on_cancel_requested)
94 | await _release
95 | cancel.requested.disconnect(_on_cancel_requested)
96 | cancel.unreference()
97 |
98 | func _on_cancel_requested() -> void:
99 | assert(_state <= STATE_PENDING_WITH_WAITERS)
100 | cancel_release()
101 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaConditionalSignalNameAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromConditionalSignalNameAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # 定数
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | const MAX_SIGNAL_ARGC := 5
8 |
9 | #---------------------------------------------------------------------------------------------------
10 |
11 | var _object: Object
12 | var _signal_name: StringName
13 | var _signal_args: Array
14 |
15 | static func _match(a: Variant, b: Variant) -> bool:
16 | return a is Object and a == SKIP or a == b
17 |
18 | func _init(object: Object, signal_name: StringName, signal_args: Array) -> void:
19 | assert(object != null)
20 | assert(signal_args.size() <= MAX_SIGNAL_ARGC)
21 |
22 | _object = object
23 | _signal_name = signal_name
24 | _signal_args = signal_args
25 |
26 | if is_instance_valid(_object):
27 | match len(_signal_args):
28 | 0: _object.connect(_signal_name, _on_completed_0)
29 | 1: _object.connect(_signal_name, _on_completed_1)
30 | 2: _object.connect(_signal_name, _on_completed_2)
31 | 3: _object.connect(_signal_name, _on_completed_3)
32 | 4: _object.connect(_signal_name, _on_completed_4)
33 | 5: _object.connect(_signal_name, _on_completed_5)
34 | else:
35 | cancel_release()
36 |
37 | func _on_completed_0() -> void:
38 | if is_instance_valid(_object):
39 | _object.disconnect(_signal_name, _on_completed_0)
40 | _object = null
41 | if is_pending:
42 | complete_release([])
43 |
44 | func _on_completed_1(arg1: Variant) -> void:
45 | if (_match(_signal_args[0], arg1)):
46 | if is_instance_valid(_object):
47 | _object.disconnect(_signal_name, _on_completed_1)
48 | _object = null
49 | if is_pending:
50 | complete_release([arg1])
51 |
52 | func _on_completed_2(arg1: Variant, arg2: Variant) -> void:
53 | if (_match(_signal_args[0], arg1) and
54 | _match(_signal_args[1], arg2)):
55 | if is_instance_valid(_object):
56 | _object.disconnect(_signal_name, _on_completed_2)
57 | _object = null
58 | if is_pending:
59 | complete_release([arg1, arg2])
60 |
61 | func _on_completed_3(arg1: Variant, arg2: Variant, arg3: Variant) -> void:
62 | if (_match(_signal_args[0], arg1) and
63 | _match(_signal_args[1], arg2) and
64 | _match(_signal_args[2], arg3)):
65 | if is_instance_valid(_object):
66 | _object.disconnect(_signal_name, _on_completed_3)
67 | _object = null
68 | if is_pending:
69 | complete_release([arg1, arg2, arg3])
70 |
71 | func _on_completed_4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant) -> void:
72 | if (_match(_signal_args[0], arg1) and
73 | _match(_signal_args[1], arg2) and
74 | _match(_signal_args[2], arg3) and
75 | _match(_signal_args[3], arg4)):
76 | if is_instance_valid(_object):
77 | _object.disconnect(_signal_name, _on_completed_4)
78 | _object = null
79 | if is_pending:
80 | complete_release([arg1, arg2, arg3, arg4])
81 |
82 | func _on_completed_5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant) -> void:
83 | if (_match(_signal_args[0], arg1) and
84 | _match(_signal_args[1], arg2) and
85 | _match(_signal_args[2], arg3) and
86 | _match(_signal_args[3], arg4) and
87 | _match(_signal_args[4], arg5)):
88 | if is_instance_valid(_object):
89 | _object.disconnect(_signal_name, _on_completed_5)
90 | _object = null
91 | if is_pending:
92 | complete_release([arg1, arg2, arg3, arg4, arg5])
93 |
--------------------------------------------------------------------------------
/addons/godot-nesink/NesinkronaConditionalSignalAsync.gd:
--------------------------------------------------------------------------------
1 | class_name NesinkronaFromConditionalSignalAsync extends NesinkronaAsyncBase
2 |
3 | #---------------------------------------------------------------------------------------------------
4 | # 定数
5 | #---------------------------------------------------------------------------------------------------
6 |
7 | const MAX_SIGNAL_ARGC := 5
8 |
9 | #---------------------------------------------------------------------------------------------------
10 |
11 | var _object: Object
12 | var _signal: Signal
13 | var _signal_args: Array
14 |
15 | static func _match(a: Variant, b: Variant) -> bool:
16 | return a is Object and a == SKIP or a == b
17 |
18 | func _init(signal_: Signal, signal_args: Array) -> void:
19 | assert(signal_args.size() <= MAX_SIGNAL_ARGC)
20 |
21 | _object = signal_.get_object()
22 | _signal = signal_
23 | _signal_args = signal_args
24 |
25 | assert(is_instance_valid(_object) or not signal_.is_null())
26 |
27 | match len(_signal_args):
28 | 0: signal_.connect(_on_completed_0)
29 | 1: signal_.connect(_on_completed_1)
30 | 2: signal_.connect(_on_completed_2)
31 | 3: signal_.connect(_on_completed_3)
32 | 4: signal_.connect(_on_completed_4)
33 | 5: signal_.connect(_on_completed_5)
34 |
35 | func _on_completed_0() -> void:
36 | if is_pending:
37 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_0):
38 | _signal.disconnect(_on_completed_0)
39 | complete_release([])
40 | _object = null
41 |
42 | func _on_completed_1(arg1: Variant) -> void:
43 | if is_pending:
44 | if (not _match(_signal_args[0], arg1)):
45 | return
46 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_1):
47 | _signal.disconnect(_on_completed_1)
48 | complete_release([arg1])
49 | _object = null
50 |
51 | func _on_completed_2(arg1: Variant, arg2: Variant) -> void:
52 | if is_pending:
53 | if (not _match(_signal_args[0], arg1) or
54 | not _match(_signal_args[1], arg2)):
55 | return
56 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_2):
57 | _signal.disconnect(_on_completed_2)
58 | complete_release([arg1, arg2])
59 | _object = null
60 |
61 | func _on_completed_3(arg1: Variant, arg2: Variant, arg3: Variant) -> void:
62 | if is_pending:
63 | if (not _match(_signal_args[0], arg1) or
64 | not _match(_signal_args[1], arg2) or
65 | not _match(_signal_args[2], arg3)):
66 | return
67 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_3):
68 | _signal.disconnect(_on_completed_3)
69 | complete_release([arg1, arg2, arg3])
70 | _object = null
71 |
72 | func _on_completed_4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant) -> void:
73 | if is_pending:
74 | if (not _match(_signal_args[0], arg1) or
75 | not _match(_signal_args[1], arg2) or
76 | not _match(_signal_args[2], arg3) or
77 | not _match(_signal_args[3], arg4)):
78 | return
79 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_4):
80 | _signal.disconnect(_on_completed_4)
81 | complete_release([arg1, arg2, arg3, arg4])
82 | _object = null
83 |
84 | func _on_completed_5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant) -> void:
85 | if is_pending:
86 | if (not _match(_signal_args[0], arg1) or
87 | not _match(_signal_args[1], arg2) or
88 | not _match(_signal_args[2], arg3) or
89 | not _match(_signal_args[3], arg4) or
90 | not _match(_signal_args[4], arg5)):
91 | return
92 | if is_instance_valid(_object) and _signal.is_connected(_on_completed_5):
93 | _signal.disconnect(_on_completed_5)
94 | complete_release([arg1, arg2, arg3, arg4, arg5])
95 | _object = null
96 |
--------------------------------------------------------------------------------
/Test_Task.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://63dkar7hk0f8"]
2 |
3 | [ext_resource type="Script" path="res://Test_Task.gd" id="1_6j14v"]
4 |
5 | [node name="Test_Async" type="Control"]
6 | layout_mode = 3
7 | anchors_preset = 15
8 | anchor_right = 1.0
9 | anchor_bottom = 1.0
10 | grow_horizontal = 2
11 | grow_vertical = 2
12 | script = ExtResource("1_6j14v")
13 |
14 | [node name="Title" type="Label" parent="."]
15 | layout_mode = 0
16 | offset_left = 64.0
17 | offset_top = 48.0
18 | offset_right = 576.0
19 | offset_bottom = 96.0
20 | theme_override_font_sizes/font_size = 24
21 | text = "Nesinkrona"
22 | vertical_alignment = 1
23 | metadata/_edit_lock_ = true
24 |
25 | [node name="Description" type="Label" parent="."]
26 | layout_mode = 0
27 | offset_left = 64.0
28 | offset_top = 96.0
29 | offset_right = 576.0
30 | offset_bottom = 128.0
31 | theme_override_colors/font_color = Color(0.733333, 0.733333, 0.733333, 1)
32 | theme_override_font_sizes/font_size = 12
33 | text = "Pseudo (task based) asynchronous patterns for Godot 4."
34 | vertical_alignment = 1
35 | metadata/_edit_lock_ = true
36 |
37 | [node name="Features" type="HBoxContainer" parent="."]
38 | auto_translate_mode = 2
39 | layout_mode = 0
40 | offset_left = 64.0
41 | offset_top = 192.0
42 | offset_right = 1216.0
43 | offset_bottom = 576.0
44 | localize_numeral_system = false
45 | theme_override_constants/separation = 0
46 | metadata/_edit_group_ = true
47 |
48 | [node name="Version_1_0_1" type="VBoxContainer" parent="Features"]
49 | custom_minimum_size = Vector2(256, 0)
50 | layout_mode = 2
51 | theme_override_constants/separation = 0
52 | metadata/_edit_group_ = true
53 |
54 | [node name="Header" type="Label" parent="Features/Version_1_0_1"]
55 | custom_minimum_size = Vector2(0, 32)
56 | layout_mode = 2
57 | theme_override_colors/font_color = Color(1, 1, 1, 1)
58 | text = "1.0.1 features:"
59 | vertical_alignment = 1
60 |
61 | [node name="Completed" type="CheckBox" parent="Features/Version_1_0_1"]
62 | unique_name_in_owner = true
63 | custom_minimum_size = Vector2(0, 24)
64 | layout_mode = 2
65 | focus_mode = 0
66 | mouse_filter = 2
67 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
68 | theme_override_font_sizes/font_size = 10
69 | disabled = true
70 | button_mask = 0
71 | text = "Async.completed()"
72 |
73 | [node name="Canceled" type="CheckBox" parent="Features/Version_1_0_1"]
74 | unique_name_in_owner = true
75 | custom_minimum_size = Vector2(0, 24)
76 | layout_mode = 2
77 | focus_mode = 0
78 | mouse_filter = 2
79 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
80 | theme_override_font_sizes/font_size = 10
81 | disabled = true
82 | button_mask = 0
83 | text = "Async.canceled()"
84 |
85 | [node name="From" type="CheckBox" parent="Features/Version_1_0_1"]
86 | unique_name_in_owner = true
87 | custom_minimum_size = Vector2(0, 24)
88 | layout_mode = 2
89 | focus_mode = 0
90 | mouse_filter = 2
91 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
92 | theme_override_font_sizes/font_size = 10
93 | disabled = true
94 | button_mask = 0
95 | text = "Async.from()"
96 |
97 | [node name="FromSignal" type="CheckBox" parent="Features/Version_1_0_1"]
98 | unique_name_in_owner = true
99 | custom_minimum_size = Vector2(0, 24)
100 | layout_mode = 2
101 | focus_mode = 0
102 | mouse_filter = 2
103 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
104 | theme_override_font_sizes/font_size = 10
105 | disabled = true
106 | button_mask = 0
107 | text = "Async.from_signal()"
108 |
109 | [node name="FromSignalName" type="CheckBox" parent="Features/Version_1_0_1"]
110 | unique_name_in_owner = true
111 | custom_minimum_size = Vector2(0, 24)
112 | layout_mode = 2
113 | focus_mode = 0
114 | mouse_filter = 2
115 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
116 | theme_override_font_sizes/font_size = 10
117 | disabled = true
118 | button_mask = 0
119 | text = "Async.from_signal_name()"
120 |
121 | [node name="Delay" type="CheckBox" parent="Features/Version_1_0_1"]
122 | unique_name_in_owner = true
123 | custom_minimum_size = Vector2(0, 24)
124 | layout_mode = 2
125 | focus_mode = 0
126 | mouse_filter = 2
127 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
128 | theme_override_font_sizes/font_size = 10
129 | disabled = true
130 | button_mask = 0
131 | text = "Async.delay()"
132 |
133 | [node name="DelayMsec" type="CheckBox" parent="Features/Version_1_0_1"]
134 | unique_name_in_owner = true
135 | custom_minimum_size = Vector2(0, 24)
136 | layout_mode = 2
137 | focus_mode = 0
138 | mouse_filter = 2
139 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
140 | theme_override_font_sizes/font_size = 10
141 | disabled = true
142 | button_mask = 0
143 | text = "Async.delay_msec()"
144 |
145 | [node name="DelayUsec" type="CheckBox" parent="Features/Version_1_0_1"]
146 | unique_name_in_owner = true
147 | custom_minimum_size = Vector2(0, 24)
148 | layout_mode = 2
149 | focus_mode = 0
150 | mouse_filter = 2
151 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
152 | theme_override_font_sizes/font_size = 10
153 | disabled = true
154 | button_mask = 0
155 | text = "Async.delay_usec()"
156 |
157 | [node name="All" type="CheckBox" parent="Features/Version_1_0_1"]
158 | unique_name_in_owner = true
159 | custom_minimum_size = Vector2(0, 24)
160 | layout_mode = 2
161 | focus_mode = 0
162 | mouse_filter = 2
163 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
164 | theme_override_font_sizes/font_size = 10
165 | disabled = true
166 | button_mask = 0
167 | text = "Async.all()"
168 |
169 | [node name="AllSettled" type="CheckBox" parent="Features/Version_1_0_1"]
170 | unique_name_in_owner = true
171 | custom_minimum_size = Vector2(0, 24)
172 | layout_mode = 2
173 | focus_mode = 0
174 | mouse_filter = 2
175 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
176 | theme_override_font_sizes/font_size = 10
177 | disabled = true
178 | button_mask = 0
179 | text = "Async.all_settled()"
180 |
181 | [node name="Any" type="CheckBox" parent="Features/Version_1_0_1"]
182 | unique_name_in_owner = true
183 | custom_minimum_size = Vector2(0, 24)
184 | layout_mode = 2
185 | focus_mode = 0
186 | mouse_filter = 2
187 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
188 | theme_override_font_sizes/font_size = 10
189 | disabled = true
190 | button_mask = 0
191 | text = "Async.any()"
192 |
193 | [node name="Race" type="CheckBox" parent="Features/Version_1_0_1"]
194 | unique_name_in_owner = true
195 | custom_minimum_size = Vector2(0, 24)
196 | layout_mode = 2
197 | focus_mode = 0
198 | mouse_filter = 2
199 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
200 | theme_override_font_sizes/font_size = 10
201 | disabled = true
202 | button_mask = 0
203 | text = "Async.race()"
204 |
205 | [node name="Then" type="CheckBox" parent="Features/Version_1_0_1"]
206 | unique_name_in_owner = true
207 | custom_minimum_size = Vector2(0, 24)
208 | layout_mode = 2
209 | focus_mode = 0
210 | mouse_filter = 2
211 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
212 | theme_override_font_sizes/font_size = 10
213 | disabled = true
214 | button_mask = 0
215 | text = "Async.then()"
216 |
217 | [node name="Unwrap" type="CheckBox" parent="Features/Version_1_0_1"]
218 | unique_name_in_owner = true
219 | custom_minimum_size = Vector2(0, 24)
220 | layout_mode = 2
221 | focus_mode = 0
222 | mouse_filter = 2
223 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
224 | theme_override_font_sizes/font_size = 10
225 | disabled = true
226 | button_mask = 0
227 | text = "Async.unwrap()"
228 |
229 | [node name="Version_1_0_2" type="VBoxContainer" parent="Features"]
230 | custom_minimum_size = Vector2(256, 0)
231 | layout_mode = 2
232 | theme_override_constants/separation = 0
233 | metadata/_edit_group_ = true
234 |
235 | [node name="Header" type="Label" parent="Features/Version_1_0_2"]
236 | custom_minimum_size = Vector2(0, 32)
237 | layout_mode = 2
238 | theme_override_colors/font_color = Color(1, 1, 1, 1)
239 | text = "1.0.2 features:"
240 | vertical_alignment = 1
241 |
242 | [node name="Defer" type="CheckBox" parent="Features/Version_1_0_2"]
243 | unique_name_in_owner = true
244 | custom_minimum_size = Vector2(0, 24)
245 | layout_mode = 2
246 | focus_mode = 0
247 | mouse_filter = 2
248 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
249 | theme_override_font_sizes/font_size = 10
250 | disabled = true
251 | button_mask = 0
252 | text = "Async.defer()"
253 |
254 | [node name="FromConditionalSignal" type="CheckBox" parent="Features/Version_1_0_2"]
255 | unique_name_in_owner = true
256 | custom_minimum_size = Vector2(0, 24)
257 | layout_mode = 2
258 | focus_mode = 0
259 | mouse_filter = 2
260 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
261 | theme_override_font_sizes/font_size = 10
262 | disabled = true
263 | button_mask = 0
264 | text = "Async.from_conditional()"
265 |
266 | [node name="FromConditionalSignalName" type="CheckBox" parent="Features/Version_1_0_2"]
267 | unique_name_in_owner = true
268 | custom_minimum_size = Vector2(0, 24)
269 | layout_mode = 2
270 | focus_mode = 0
271 | mouse_filter = 2
272 | theme_override_colors/font_disabled_color = Color(0.8, 0.8, 0.8, 1)
273 | theme_override_font_sizes/font_size = 10
274 | disabled = true
275 | button_mask = 0
276 | text = "Async.from_conditional_signal_name()"
277 |
--------------------------------------------------------------------------------
/addons/godot-nesink/Async.gd:
--------------------------------------------------------------------------------
1 | ## 非同期的な処理の完了とその結果、もしくはキャンセルされたという状態を表すインターフェイスです。
2 | ##
3 | ## 非同期的な処理を抽象化し、将来決まる結果をこの共通のインターフェイスからアクセスできるようにします。
4 | ## 完了もしくはキャンセルされたという状態と、完了した場合はその結果を保持し [method wait] メソッドから取得することができます。
5 | ## またいくつかの重要なファクトリメソッドを公開します。
6 | class_name Async
7 |
8 | #-------------------------------------------------------------------------------
9 | # 定数
10 | #-------------------------------------------------------------------------------
11 |
12 | enum {
13 | ## [b](アドオン内もしくは実装内でのみ使用)[/b]
14 | ## まだ完了もしくはキャンセルされておらず待機中であることを表します。
15 | STATE_PENDING,
16 | ## [b](アドオン内もしくは実装内でのみ使用)[/b]
17 | ## まだ完了もしくはキャンセルされておらず待機中であり、
18 | ## 1 度以上 [method wait] メソッドにより待機している箇所があることを表します。
19 | STATE_PENDING_WITH_WAITERS,
20 | ## [b](アドオン内もしくは実装内でのみ使用)[/b]
21 | ## 完了したことを表します。
22 | STATE_COMPLETED,
23 | ## [b](アドオン内もしくは実装内でのみ使用)[/b]
24 | ## キャンセルされたことを表します。
25 | STATE_CANCELED,
26 | }
27 |
28 | enum {
29 | ## アイドル時に処理されるよう遅延されることを表します。
30 | DEFER_IDLE,
31 | ## _process フレームに処理されるよう遅延されることを表します。
32 | DEFER_PROCESS_FRAME,
33 | ## _physics_process フレームに処理されるよう遅延されることを表します。
34 | DEFER_PHYSICS_FRAME,
35 | }
36 |
37 | ## 条件一致を省略するためのプレースホルダ。
38 | static var SKIP := Object.new()
39 |
40 | #-------------------------------------------------------------------------------
41 | # プロパティ
42 | #-------------------------------------------------------------------------------
43 |
44 | ## この待機可能な単位が完了している場合 true を返します。[br]
45 | ## [br]
46 | ## [b]補足[/b][br]
47 | ## [method wait] を待機した後は、[member is_canceled] もしくは
48 | ## このプロパティのうちどちらかが必ず true になります。
49 | var is_completed: bool:
50 | get:
51 | return get_state() == STATE_COMPLETED
52 |
53 | ## この待機可能な単位がキャンセルされている場合 true を返します。[br]
54 | ## [br]
55 | ## [b]補足[/b][br]
56 | ## [method wait] を待機した後は、[member is_completed] もしくは
57 | ## このプロパティのうちどちらかが必ず true になります。
58 | var is_canceled: bool:
59 | get:
60 | return get_state() == STATE_CANCELED
61 |
62 | ## この待機可能な単位がまだ完了もしくはキャンセルされていない場合 true を返します。
63 | var is_pending: bool:
64 | get:
65 | var state := get_state()
66 | return \
67 | state == STATE_PENDING or \
68 | state == STATE_PENDING_WITH_WAITERS
69 |
70 | #-------------------------------------------------------------------------------
71 | # メソッド
72 | #-------------------------------------------------------------------------------
73 |
74 | ## 完了した状態の [Async] を作成します。[br]
75 | ## [br]
76 | ## [b]使い方[/b]
77 | ## [codeblock]
78 | ## var async := Async.completed("result")
79 | ## assert(async.is_completed)
80 | ## assert(await async.wait() == "result")
81 | ## [/codeblock]
82 | static func completed(result: Variant = null) -> Async:
83 | return NesinkronaCompletedAsync.new(result)
84 |
85 | ## キャンセルされた状態の [Async] を作成します。[br]
86 | ## [br]
87 | ## [b]使い方[/b]
88 | ## [codeblock]
89 | ## var async := Async.canceled()
90 | ## assert(async.is_canceled)
91 | ## assert(await async.wait() == null)
92 | ## [/codeblock]
93 | static func canceled() -> Async:
94 | return NesinkronaCanceledAsync.new()
95 |
96 | ## コルーチン (もしくは関数) の戻り値を結果として完了する [Async] を作成します。[br]
97 | ## [br]
98 | ## [b]補足[/b][br]
99 | ## 第 1 引数 [code]coroutine[/code] は引数を受け取りません。[br]
100 | ## [br]
101 | ## [b]使い方[/b]
102 | ## [codeblock]
103 | ## var async1 := Async.from(func():
104 | ## await get_tree().create_timer(1.0).timeout)
105 | ## var async2 := Async.from(func():
106 | ## await get_tree().create_timer(1.0).timeout
107 | ## return 123)
108 | ## print(await async1.wait()) #
109 | ## print(await async2.wait()) # 123
110 | ## [/codeblock]
111 | static func from(coroutine: Callable) -> Async:
112 | return NesinkronaFromAsync.new(coroutine)
113 |
114 | ## コルーチン (もしくは関数) を呼び出し結果を待機する新たな [Async] を作成します。[br]
115 | ## [br]
116 | ## [b]補足[/b][br]
117 | ## 第 1 引数 [code]coroutine[/code] は引数を 2 つ受け取る
118 | ## [Callable] でなくてはなりません。この引数には完了コールバック、
119 | ## キャンセルコールバックが渡されます。[br]
120 | ## [br]
121 | ## [b]使い方[/b]
122 | ## [codeblock]
123 | ## var async1 := Async.from(func(complete: Callback, cancel: Callback):
124 | ## get_tree().create_timer(1.0).timeout.connect(complete))
125 | ## var async2 := Async.from(func():
126 | ## get_tree().create_timer(1.0).timeout.connect(complete.bind(123)))
127 | ## print(await async1.wait()) #
128 | ## print(await async2.wait()) # 123
129 | ## [/codeblock]
130 | static func from_callback(coroutine: Callable, unbind_cancel := false) -> Async:
131 | return NesinkronaFromCallbackAsync.new(coroutine, unbind_cancel)
132 |
133 | ## シグナルを受信するとその引数を結果として完了する [Async] を作成します。[br]
134 | ## [br]
135 | ## シグナル引数は [Array] に格納され結果となります。[br]
136 | ## [br]
137 | ## [b]補足[/b][br]
138 | ## もしシグナルが引数を持つ場合、その個数を [code]signal_argc[/code] に指定する必要があります。[br]
139 | ## 間違った個数を指定すると正しく受信できません。[br]
140 | ## [br]
141 | ## [b]使い方[/b]
142 | ## [codeblock]
143 | ## signal my_event_0
144 | ## signal my_event_1(a)
145 | ## signal my_event_2(a, b)
146 | ##
147 | ## var async0 := Async.from_signal(my_event_0)
148 | ## var async1 := Async.from_signal(my_event_1, 1) # シグナルの引数の個数を指定する必要があります
149 | ## var async2 := Async.from_signal(my_event_2, 2) # 同上
150 | ## print(await async0.wait()) # []
151 | ## print(await async1.wait()) # [1]
152 | ## print(await async2.wait()) # [1, 2]
153 | ##
154 | ## my_event_0.emit() # どこかにこのようなエミッションがあるとします
155 | ## my_event_1.emit(1) # 同上
156 | ## my_event_2.emit(1, 2) # 同上
157 | ## [/codeblock]
158 | static func from_signal(signal_: Signal, signal_argc := 0) -> Async:
159 | assert(not signal_.is_null())
160 | assert(
161 | signal_argc >= 0 and
162 | signal_argc <= NesinkronaFromSignalAsync.MAX_SIGNAL_ARGC)
163 | return NesinkronaFromSignalAsync.new(signal_, signal_argc)
164 |
165 | ## 文字列によりシグナル名を指定し、そのシグナルを受信すると引数を結果として完了する [Async] を作成します。[br]
166 | ## [br]
167 | ## [b]補足[/b][br]
168 | ## シグナルの指定方法が異なるだけで、他は [method from_signal] メソッドと同じ注意を払う必要があります。
169 | static func from_signal_name(
170 | object: Object,
171 | signal_name: StringName,
172 | signal_argc := 0) -> Async:
173 |
174 | assert(
175 | object != null and
176 | not object.is_queued_for_deletion())
177 | assert(
178 | signal_argc >= 0 and
179 | signal_argc <= NesinkronaFromSignalNameAsync.MAX_SIGNAL_ARGC)
180 | return NesinkronaFromSignalNameAsync.new(object, signal_name, signal_argc)
181 |
182 | ## シグナル引数が一致した場合にのみ完了する条件付き [Async] を作成します。[br]
183 | ## [br]
184 | ## [method Async.wait] はシグナル引数を配列に格納したものを返します。
185 | static func from_conditional_signal(
186 | signal_: Signal,
187 | signal_args := []) -> Async:
188 |
189 | assert(not signal_.is_null())
190 | assert(
191 | signal_args.size() <= NesinkronaFromConditionalSignalAsync.MAX_SIGNAL_ARGC)
192 | return NesinkronaFromConditionalSignalAsync.new(signal_, signal_args)
193 |
194 | ## シグナル引数が一致した場合にのみ完了する条件付き [Async] を作成します。[br]
195 | ## [br]
196 | ## [method Async.wait] はシグナル引数を配列に格納したものを返します。
197 | static func from_conditional_signal_name(
198 | object: Object,
199 | signal_name: StringName,
200 | signal_args := []) -> Async:
201 |
202 | assert(object and not object.is_queued_for_deletion())
203 | assert(
204 | signal_args.size() <= NesinkronaFromConditionalSignalNameAsync.MAX_SIGNAL_ARGC)
205 | return NesinkronaFromConditionalSignalNameAsync.new(object, signal_name, signal_args)
206 |
207 | ## [param callsite] で指定したタイミングで完了する [Async] を作成します。
208 | static func defer(callsite := DEFER_IDLE) -> Async:
209 | match callsite:
210 | DEFER_IDLE:
211 | return NesinkronaDeferIdleAsync.new()
212 | DEFER_PROCESS_FRAME:
213 | return NesinkronaDeferProcessFrameAsync.new()
214 | DEFER_PHYSICS_FRAME:
215 | return NesinkronaDeferPhysicsFrameAsync.new()
216 | _:
217 | assert(false)
218 | return null
219 |
220 | ## タイムアウトすると完了する [Async] を作成します。[br]
221 | ## [br]
222 | ## 結果は第 1 引数 [code]timeout[/code] と同じ値となります。[br]
223 | ## [br]
224 | ## [b]補足[/b][br]
225 | ## 第 1 引数 [code]timeout[/code] は 0.0 以上である必要があります。
226 | ## また過去は指定できません。[br]
227 | ## [br]
228 | ## [b]使い方[/b]
229 | ## [codeblock]
230 | ## var async := Async.delay(1.0)
231 | ## print(await async.wait()) # 1.0
232 | ## [/codeblock]
233 | static func delay(timeout: float) -> Async:
234 | assert(NesinkronaDelayAsync.MIN_TIMEOUT <= timeout)
235 | return \
236 | completed(0.0) \
237 | if timeout == 0.0 else \
238 | NesinkronaDelayAsync.new(timeout)
239 |
240 | ## タイムアウト (ミリ秒) すると完了する [Async] を返します。[br]
241 | ## [br]
242 | ## [b]補足[/b][br]
243 | ## タイムアウトの単位が異なるだけで、他は [method delay] メソッドと同じ注意を払う必要があります。
244 | static func delay_msec(timeout: float) -> Async:
245 | return delay(timeout / 1_000.0)
246 |
247 | ## タイムアウト (マイクロ秒) すると完了する [Async] を返します。[br]
248 | ## [br]
249 | ## [b]補足[/b][br]
250 | ## タイムアウトの単位が異なるだけで、他は [method delay] メソッドと同じ注意を払う必要があります。
251 | static func delay_usec(timeout: float) -> Async:
252 | return delay(timeout / 1_000_000.0)
253 |
254 | ## すべての入力が完了すると、それぞれの結果を配列に格納したものを結果として完了する新たな [Async] を作成します。[br]
255 | ## [br]
256 | ## 第 1 引数 [code]drains[/code] 配列には [Async] や [AsyncSequence] 以外の値も含めることができます。[br]
257 | ## [br]
258 | ## [b]補足[/b][br]
259 | ## 第 1 引数 [code]drains[/code] 配列に [Async] や [AsyncSequence] が含まれている場合、
260 | ## どれか 1 つでもキャンセルされるとこのメソッドで作成した [Async] はキャンセルされた状態となります。
261 | ## これは結果を作成できないためです。もし完了やキャンセルを問わず待機が終わったことだけを待つ場合、
262 | ## このメソッドではなく代わりに [method all_settled] メソッドを使います。[br]
263 | ## [br]
264 | ## [b]使い方[/b]
265 | ## [codeblock]
266 | ## var async := Async.all([
267 | ## Async.completed(1234),
268 | ## Async.delay(1.5),
269 | ## Async.delay(2.0),
270 | ## true,
271 | ## "aaa",
272 | ## )
273 | ## print(await async.wait()) # [1234, 1.5, 2.0, true, "aaa"]
274 | ## [/codeblock]
275 | static func all(drains: Array, cancel: Cancel = null) -> Async:
276 | return \
277 | canceled() \
278 | if cancel and cancel.is_requested else \
279 | completed([]) \
280 | if drains.is_empty() else \
281 | NesinkronaAllAsync.new(drains, cancel)
282 |
283 | ## すべての入力が完了もしくはキャンセルされると、それぞれの結果を [Async] のまま配列に格納したものを結果として完了する [Async] を作成します。[br]
284 | ## [br]
285 | ## 第 1 引数 [code]drains[/code] 配列には [Async] や [AsyncSequence] 以外の値も含めることができます。[br]
286 | ## [br]
287 | ## [b]補足[/b][br]
288 | ## 第 1 引数 [code]drains[/code] 配列に [Async] や [AsyncSequence] ではない値が含まれていると、
289 | ## それは完了した状態の [Async] に変換され処理されます。[br]
290 | ## [br]
291 | ## [b]使い方[/b]
292 | ## [codeblock]
293 | ## var async := Async.all_settled([
294 | ## Async.delay(1.0),
295 | ## Async.delay(2.0),
296 | ## 10,
297 | ## 20,
298 | ## ])
299 | ## var async_result: Array[Async] = await async.wait()
300 | ## print(await async_result[0].wait()) # 1.0
301 | ## print(await async_result[1].wait()) # 2.0
302 | ## print(await async_result[2].wait()) # 10
303 | ## print(await async_result[3].wait()) # 20
304 | ## [/codeblock]
305 | static func all_settled(drains: Array, cancel: Cancel = null) -> Async:
306 | return \
307 | completed([]) \
308 | if drains.is_empty() else \
309 | NesinkronaAllSettledAsync.new(drains, cancel)
310 |
311 | ## すべての入力のうちどれか 1 つが完了すると、それを結果として完了する新たな [Async] を作成します。[br]
312 | ## [br]
313 | ## 第 1 引数 [code]drains[/code] 配列には [Async] や [AsyncSequence] 以外の値も含めることができます。
314 | ## [br]
315 | # [b]補足[/b][br]
316 | ## もし完了やキャンセルを問わずど待機が終わったことだけを待つ場合、
317 | ## このメソッドではなく代わりに [method race] メソッドを使います。[br]
318 | ## [br]
319 | ## [b]使い方[/b]
320 | ## [codeblock]
321 | ## var async := Async.any([
322 | ## Async.canceled(),
323 | ## Async.delay(2.0),
324 | ## Async.delay(3.0),
325 | ## ])
326 | ## print(await async.wait()) # 2.0
327 | ## [/codeblock]
328 | static func any(drains: Array, cancel: Cancel = null) -> Async:
329 | return \
330 | canceled() \
331 | if cancel != null and cancel.is_requested or drains.is_empty() else \
332 | NesinkronaAnyAsync.new(drains, cancel)
333 |
334 | ## すべての入力のうちどれか 1 つが完了もしくはキャンセルされると、それを結果として完了する新たな [Async] を作成します。[br]
335 | ## [br]
336 | ## 第 1 引数 [code]drains[/code] 配列には [Async] や [AsyncSequence] 以外の値も含めることができます。[br]
337 | ## [br]
338 | ## [b]補足[/b][br]
339 | ## 第 1 引数 [code]drains[/code] は、1 以上の長さでなくてはなりません。[br]
340 | ## [br]
341 | ## [b]使い方[/b]
342 | ## [codeblock]
343 | ## var async := Async.race([
344 | ## Async.canceled(),
345 | ## Async.delay(2.0),
346 | ## Async.delay(3.0),
347 | ## ])
348 | ## async = await async.wait()
349 | ## print(async.is_canceled) # true
350 | ## [/codeblock]
351 | static func race(drains: Array, cancel: Cancel = null) -> Async:
352 | assert(not drains.is_empty())
353 | return NesinkronaRaceAsync.new(drains, cancel)
354 |
355 | ## [param callsite] で指定したタイミングを待機します。[br]
356 | ## [br]
357 | ## [b]補足[/b][br]
358 | ## 以下と同じです:
359 | ## [codeblock]
360 | ## defer(callsite).wait(cancel)
361 | ## [/codeblock]
362 | static func wait_defer(callsite := DEFER_IDLE, cancel: Cancel = null) -> Variant:
363 | return await defer(callsite).wait(cancel)
364 |
365 | ## [method delay] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
366 | ## [br]
367 | ## [b]補足[/b][br]
368 | ## 以下と同じです:
369 | ## [codeblock]
370 | ## delay(timeout).wait(cancel)
371 | ## [/codeblock]
372 | static func wait_delay(timeout: float, cancel: Cancel = null) -> Variant:
373 | return await delay(timeout).wait(cancel)
374 |
375 | ## [method delay_msec] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
376 | ## [br]
377 | ## [b]補足[/b][br]
378 | ## 以下と同じです:
379 | ## [codeblock]
380 | ## delay_msec(timeout).wait(cancel)
381 | ## [/codeblock]
382 | static func wait_delay_msec(timeout: float, cancel: Cancel = null) -> Variant:
383 | return await delay_msec(timeout).wait(cancel)
384 |
385 | ## [method delay_usec] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
386 | ## [br]
387 | ## [b]補足[/b][br]
388 | ## 以下と同じです:
389 | ## [codeblock]
390 | ## delay_usec(timeout).wait(cancel)
391 | ## [/codeblock]
392 | static func wait_delay_usec(timeout: float, cancel: Cancel = null) -> Variant:
393 | return await delay_usec(timeout).wait(cancel)
394 |
395 | ## [method all] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
396 | ## [br]
397 | ## [b]補足[/b][br]
398 | ## 以下と同じです:
399 | ## [codeblock]
400 | ## all(drains, cancel).wait(cancel)
401 | ## [/codeblock]
402 | static func wait_all(drains: Array, cancel: Cancel = null) -> Variant:
403 | return await all(drains, cancel).wait(cancel)
404 |
405 | ## [method all_settled] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
406 | ## [br]
407 | ## [b]補足[/b][br]
408 | ## 以下と同じです:
409 | ## [codeblock]
410 | ## all_settled(drains, cancel).wait(cancel)
411 | ## [/codeblock]
412 | static func wait_all_settled(drains: Array, cancel: Cancel = null) -> Variant:
413 | return await all_settled(drains, cancel).wait(cancel)
414 |
415 | ## [method any] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
416 | ## [br]
417 | ## [b]補足[/b][br]
418 | ## 以下と同じです:
419 | ## [codeblock]
420 | ## any(drains, cancel).wait(cancel)
421 | ## [/codeblock]
422 | static func wait_any(drains: Array, cancel: Cancel = null) -> Variant:
423 | return await any(drains, cancel).wait(cancel)
424 |
425 | ## [method race] で作成した [Async] に対して [method wait] を呼び出す短縮表記です。[br]
426 | ## [br]
427 | ## [b]補足[/b][br]
428 | ## 以下と同じです:
429 | ## [codeblock]
430 | ## race(drains, cancel).wait(cancel)
431 | ## [/codeblock]
432 | static func wait_race(drains: Array, cancel: Cancel = null) -> Variant:
433 | return await race(drains, cancel).wait(cancel)
434 |
435 | ## この [Async] の結果が [Async] である場合、
436 | ## 指定した回数アンラップを試みた新たな [Async] を作成します。[br]
437 | ## [br]
438 | ## [b]使い方[/b]
439 | ## [codeblock]
440 | ## var async := Async.completed(Async.completed(10)) # Async に Async がネストされている
441 | ## print(await async.unwrap().wait()) # 10
442 | ## [/codeblock]
443 | func unwrap(depth := 1, cancel: Cancel = null) -> Async:
444 | assert(0 <= depth)
445 | return \
446 | canceled() \
447 | if cancel != null and cancel.is_requested or is_canceled else \
448 | self \
449 | if depth == 0 else \
450 | NesinkronaUnwrapAsync.new(self, cancel, depth)
451 |
452 | ## この [Async] が完了した場合、
453 | ## 指定したコルーチン (もしくは関数) の戻り値を結果として完了する新たな [Async] を作成します。[br]
454 | ## [br]
455 | ## 前の結果を写像する場合 ([method Array.map] 的な使い方) や、
456 | ## 結果から別のコルーチンへ処理を渡す場合に使うことができます。[br]
457 | ## [br]
458 | ## [b]補足[/b][br]
459 | ## 第 1 引数 [code]coroutine[/code] は引数を 1 つ受け取る
460 | ## [Callable] でなくてはなりません。この引数には直前の結果が渡されます。[br]
461 | ## [br]
462 | ## [b]使い方[/b]
463 | ## [codeblock]
464 | ## var async := Async.completed(10).then(func(result): return result * result)
465 | ## print(await async.wait()) # 100
466 | ## [/codeblock]
467 | func then(coroutine: Callable, cancel: Cancel = null) -> Async:
468 | return NesinkronaThenAsync.new(self, cancel, coroutine)
469 |
470 | ## この [Async] が完了した場合、
471 | ## 指定したコルーチン (もしくは関数) を呼び出し結果を待機する新たな [Async] を作成します。[br]
472 | ## [br]
473 | ## [b]補足[/b][br]
474 | ## 第 1 引数 [code]coroutine[/code] は引数を 3 つ受け取る
475 | ## [Callable] でなくてはなりません。この引数には直前の結果、
476 | ## 完了コールバック、キャンセルコールバックが渡されます。[br]
477 | ## [br]
478 | ## [b]使い方[/b]
479 | ## [codeblock]
480 | ## var async := Async.completed(10).then_callback(func(result, complete: Callable, cancel: Callable):
481 | ## complete.call(result * result))
482 | ## print(await async.wait()) # 100
483 | ## [/codeblock]
484 | func then_callback(coroutine: Callable, cancel: Cancel = null, unbind_cancel := false) -> Async:
485 | return NesinkronaThenCallbackAsync.new(self, cancel, coroutine, unbind_cancel)
486 |
487 | ## [b](アドオン内もしくは実装内でのみ使用)[/b]
488 | ## この関数ではなく [member is_completed] もしくは [member is_canceled] を
489 | ## 使うようにしてください。将来名前が変わる可能性があります。
490 | func get_state() -> int:
491 | #
492 | # 継承先で実装する必要があります。
493 | #
494 |
495 | assert(false)
496 | return STATE_PENDING
497 |
498 | ## この待機可能な単位が完了もしくはキャンセルされるまで待機しその結果を返します。[br]
499 | ## [br]
500 | ## キャンセルされた場合の結果は必ず null となりますが、これは
501 | ## キャンセルされたかどうかの判断にはなりません。キャンセルされる可能性がある場合、
502 | ## [member is_completed] もしくは [member is_canceled] を確認する必要があります。[br]
503 | ## [br]
504 | ## [b]補足[/b][br]
505 | ## 状態が [STATE_PENDING] もしくは [STATE_PENDING_WITH_WAITERS] のとき
506 | ## 第 1 引数 [code]cancel[/code] に [Cancel] を指定しキャンセルを要求すると、
507 | ## 状態は [STATE_CANCELED] へ移行します。[br]
508 | ## [br]
509 | ## [b]使い方[/b]
510 | ## [codeblock]
511 | ## var async: Async = ...
512 | ## var result = async.wait()
513 | ## [/codeblock]
514 | func wait(cancel: Cancel = null) -> Variant:
515 | #
516 | # 継承先で実装する必要があります。
517 | #
518 |
519 | assert(false)
520 | return await null
521 |
522 | #-------------------------------------------------------------------------------
523 |
524 | func _to_string() -> String:
525 | var str: String
526 | match get_state():
527 | STATE_PENDING:
528 | str = "(pending)"
529 | STATE_PENDING_WITH_WAITERS:
530 | str = "(pending_with_waiters)"
531 | STATE_CANCELED:
532 | str = "(canceled)"
533 | STATE_COMPLETED:
534 | str = "(completed)"
535 | _:
536 | assert(false)
537 | return str + "" % get_instance_id()
538 |
--------------------------------------------------------------------------------
/Test_Task.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | signal _signal0
4 | signal _signal1(arg1: Variant)
5 | signal _signal2(arg1: Variant, arg2: Variant)
6 | signal _signal3(arg1: Variant, arg2: Variant, arg3: Variant)
7 | signal _signal4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant)
8 | signal _signal5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant)
9 |
10 | @onready var _tree := get_tree()
11 |
12 | func _emit0() -> void:
13 | _signal0.emit()
14 |
15 | func _emit1(arg1: Variant) -> void:
16 | _signal1.emit(arg1)
17 |
18 | func _emit2(arg1: Variant, arg2: Variant) -> void:
19 | _signal2.emit(arg1, arg2)
20 |
21 | func _emit3(arg1: Variant, arg2: Variant, arg3: Variant) -> void:
22 | _signal3.emit(arg1, arg2, arg3)
23 |
24 | func _emit4(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant) -> void:
25 | _signal4.emit(arg1, arg2, arg3, arg4)
26 |
27 | func _emit5(arg1: Variant, arg2: Variant, arg3: Variant, arg4: Variant, arg5: Variant) -> void:
28 | _signal5.emit(arg1, arg2, arg3, arg4, arg5)
29 |
30 | func _delay_emit0(timeout: float) -> void:
31 | _tree.create_timer(timeout).timeout.connect(_emit0)
32 |
33 | func _delay_emit1(timeout: float, arg1) -> void:
34 | _tree.create_timer(timeout).timeout.connect(_emit1.bind(arg1))
35 |
36 | func _delay_emit2(timeout: float, arg1, arg2) -> void:
37 | _tree.create_timer(timeout).timeout.connect(_emit2.bind(arg1, arg2))
38 |
39 | func _delay_emit3(timeout: float, arg1, arg2, arg3) -> void:
40 | _tree.create_timer(timeout).timeout.connect(_emit3.bind(arg1, arg2, arg3))
41 |
42 | func _delay_emit4(timeout: float, arg1, arg2, arg3, arg4) -> void:
43 | _tree.create_timer(timeout).timeout.connect(_emit4.bind(arg1, arg2, arg3, arg4))
44 |
45 | func _delay_emit5(timeout: float, arg1, arg2, arg3, arg4, arg5) -> void:
46 | _tree.create_timer(timeout).timeout.connect(_emit5.bind(arg1, arg2, arg3, arg4, arg5))
47 |
48 | func _delay(timeout := 0.2) -> void:
49 | await _tree.create_timer(timeout).timeout
50 |
51 | func _delay_cancel(timeout := 0.1) -> Cancel:
52 | var cancel := Cancel.new()
53 | _tree.create_timer(timeout).timeout.connect(cancel.request)
54 | return cancel
55 |
56 | func _equal(array1: Array, array2: Array) -> bool:
57 | if array1.size() != array2.size():
58 | return false
59 | for i in array1.size():
60 | if array1[i] != array2[i]:
61 | return false
62 | return true
63 |
64 | func _test_completed() -> void:
65 | var async := Async.completed()
66 | assert(async.is_completed)
67 | assert(not async.is_canceled)
68 | assert(await async.wait() == null)
69 | async = Async.completed(123)
70 | assert(async.is_completed)
71 | assert(not async.is_canceled)
72 | assert(await async.wait() == 123)
73 |
74 | %Completed.button_pressed = true
75 |
76 | func _test_canceled() -> void:
77 | var async := Async.canceled()
78 | assert(not async.is_completed)
79 | assert(async.is_canceled)
80 | assert(await async.wait() == null)
81 |
82 | %Canceled.button_pressed = true
83 |
84 | func _test_from() -> void:
85 | var async := Async.from(func (): pass)
86 | assert(async.is_completed)
87 | assert(await async.wait() == null)
88 |
89 | async = Async.from(func (): return 123)
90 | assert(async.is_completed)
91 | assert(await async.wait() == 123)
92 |
93 | async = Async.from(func(): await _delay())
94 | assert(not async.is_completed)
95 | assert(await async.wait() == null)
96 | assert(async.is_completed)
97 |
98 | async = Async.from(func (): await _delay(); return 123)
99 | assert(not async.is_completed)
100 | assert(await async.wait() == 123)
101 | assert(async.is_completed)
102 |
103 | async = Async.from(func(): await _delay())
104 | assert(not async.is_completed)
105 | assert(await async.wait(_delay_cancel()) == null)
106 | assert(async.is_canceled)
107 |
108 | async = Async.from(func (): await _delay(); return 123)
109 | assert(not async.is_completed)
110 | assert(await async.wait(_delay_cancel()) == null)
111 | assert(async.is_canceled)
112 |
113 | %From.button_pressed = true
114 |
115 | func _test_from_signal() -> void:
116 | var async := Async.from_signal(_signal0)
117 | assert(not async.is_completed)
118 | _emit0()
119 | assert(_equal(await async.wait(), []))
120 | assert(async.is_completed)
121 |
122 | async = Async.from_signal(_signal1, 1)
123 | assert(not async.is_completed)
124 | _emit1(123)
125 | assert(_equal(await async.wait(), [123]))
126 | assert(async.is_completed)
127 |
128 | async = Async.from_signal(_signal2, 2)
129 | assert(not async.is_completed)
130 | _emit2(123, "abc")
131 | assert(_equal(await async.wait(), [123, "abc"]))
132 | assert(async.is_completed)
133 |
134 | async = Async.from_signal(_signal3, 3)
135 | assert(not async.is_completed)
136 | _emit3(123, "abc", true)
137 | assert(_equal(await async.wait(), [123, "abc", true]))
138 | assert(async.is_completed)
139 |
140 | async = Async.from_signal(_signal4, 4)
141 | assert(not async.is_completed)
142 | _emit4(123, "abc", true, null)
143 | assert(_equal(await async.wait(), [123, "abc", true, null]))
144 | assert(async.is_completed)
145 |
146 | async = Async.from_signal(_signal5, 5)
147 | assert(not async.is_completed)
148 | _emit5(123, "abc", true, null, 0.5)
149 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
150 | assert(async.is_completed)
151 |
152 | async = Async.from_signal(_signal0)
153 | assert(not async.is_completed)
154 | _delay_emit0(0.2)
155 | assert(await async.wait(_delay_cancel()) == null)
156 | assert(async.is_canceled)
157 |
158 | async = Async.from_signal(_signal1, 1)
159 | assert(not async.is_completed)
160 | _delay_emit1(0.2, 123)
161 | assert(await async.wait(_delay_cancel()) == null)
162 | assert(async.is_canceled)
163 |
164 | async = Async.from_signal(_signal2, 2)
165 | assert(not async.is_completed)
166 | _delay_emit2(0.2, 123, "abc")
167 | assert(await async.wait(_delay_cancel()) == null)
168 | assert(async.is_canceled)
169 |
170 | async = Async.from_signal(_signal3, 3)
171 | assert(not async.is_completed)
172 | _delay_emit3(0.2, 123, "abc", true)
173 | assert(await async.wait(_delay_cancel()) == null)
174 | assert(async.is_canceled)
175 |
176 | async = Async.from_signal(_signal4, 4)
177 | assert(not async.is_completed)
178 | _delay_emit4(0.2, 123, "abc", true, null)
179 | assert(await async.wait(_delay_cancel()) == null)
180 | assert(async.is_canceled)
181 |
182 | async = Async.from_signal(_signal5, 5)
183 | assert(not async.is_completed)
184 | _delay_emit5(0.2, 123, "abc", true, null, 0.5)
185 | assert(await async.wait(_delay_cancel()) == null)
186 | assert(async.is_canceled)
187 |
188 | %FromSignal.button_pressed = true
189 |
190 | func _test_from_signal_name() -> void:
191 | var async := Async.from_signal_name(self, "_signal0")
192 | assert(not async.is_completed)
193 | _emit0()
194 | assert(_equal(await async.wait(), []))
195 | assert(async.is_completed)
196 |
197 | async = Async.from_signal_name(self, "_signal1", 1)
198 | assert(not async.is_completed)
199 | _emit1(123)
200 | assert(_equal(await async.wait(), [123]))
201 | assert(async.is_completed)
202 |
203 | async = Async.from_signal_name(self, "_signal2", 2)
204 | assert(not async.is_completed)
205 | _emit2(123, "abc")
206 | assert(_equal(await async.wait(), [123, "abc"]))
207 | assert(async.is_completed)
208 |
209 | async = Async.from_signal_name(self, "_signal3", 3)
210 | assert(not async.is_completed)
211 | _emit3(123, "abc", true)
212 | assert(_equal(await async.wait(), [123, "abc", true]))
213 | assert(async.is_completed)
214 |
215 | async = Async.from_signal_name(self, "_signal4", 4)
216 | assert(not async.is_completed)
217 | _emit4(123, "abc", true, null)
218 | assert(_equal(await async.wait(), [123, "abc", true, null]))
219 | assert(async.is_completed)
220 |
221 | async = Async.from_signal_name(self, "_signal5", 5)
222 | assert(not async.is_completed)
223 | _emit5(123, "abc", true, null, 0.5)
224 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
225 | assert(async.is_completed)
226 |
227 | async = Async.from_signal_name(self, "_signal0")
228 | assert(not async.is_completed)
229 | _delay_emit0(0.2)
230 | assert(await async.wait(_delay_cancel()) == null)
231 | assert(async.is_canceled)
232 |
233 | async = Async.from_signal_name(self, "_signal1", 1)
234 | assert(not async.is_completed)
235 | _delay_emit1(0.2, 123)
236 | assert(await async.wait(_delay_cancel()) == null)
237 | assert(async.is_canceled)
238 |
239 | async = Async.from_signal_name(self, "_signal2", 2)
240 | assert(not async.is_completed)
241 | _delay_emit2(0.2, 123, "abc")
242 | assert(await async.wait(_delay_cancel()) == null)
243 | assert(async.is_canceled)
244 |
245 | async = Async.from_signal_name(self, "_signal3", 3)
246 | assert(not async.is_completed)
247 | _delay_emit3(0.2, 123, "abc", true)
248 | assert(await async.wait(_delay_cancel()) == null)
249 | assert(async.is_canceled)
250 |
251 | async = Async.from_signal_name(self, "_signal4", 4)
252 | assert(not async.is_completed)
253 | _delay_emit4(0.2, 123, "abc", true, null)
254 | assert(await async.wait(_delay_cancel()) == null)
255 | assert(async.is_canceled)
256 |
257 | async = Async.from_signal_name(self, "_signal5", 5)
258 | assert(not async.is_completed)
259 | _delay_emit5(0.2, 123, "abc", true, null, 0.5)
260 | assert(await async.wait(_delay_cancel()) == null)
261 | assert(async.is_canceled)
262 |
263 | %FromSignalName.button_pressed = true
264 |
265 | func _test_delay() -> void:
266 | var async := Async.delay(0.1)
267 | assert(not async.is_completed)
268 | assert(await async.wait() == 0.1)
269 |
270 | async = Async.delay(0.2)
271 | assert(not async.is_completed)
272 | assert(await async.wait(_delay_cancel()) == null)
273 | assert(async.is_canceled)
274 |
275 | %Delay.button_pressed = true
276 |
277 | func _test_delay_msec() -> void:
278 | var async := Async.delay_msec(100.0)
279 | assert(not async.is_completed)
280 | assert(await async.wait() == 0.1)
281 |
282 | async = Async.delay_msec(200.0)
283 | assert(not async.is_completed)
284 | assert(await async.wait(_delay_cancel()) == null)
285 | assert(async.is_canceled)
286 |
287 | %DelayMsec.button_pressed = true
288 |
289 | func _test_delay_usec() -> void:
290 | var async := Async.delay_usec(100000.0)
291 | assert(not async.is_completed)
292 | assert(await async.wait() == 0.1)
293 |
294 | async = Async.delay_usec(200000.0)
295 | assert(not async.is_completed)
296 | assert(await async.wait(_delay_cancel()) == null)
297 | assert(async.is_canceled)
298 |
299 | %DelayUsec.button_pressed = true
300 |
301 | func _test_all() -> void:
302 | var async := Async.all([])
303 | assert(async.is_completed)
304 | assert(_equal(await async.wait(), []))
305 |
306 | async = Async.all([123, "abc", true])
307 | assert(async.is_completed)
308 | assert(_equal(await async.wait(), [123, "abc", true]))
309 |
310 | async = Async.all([Async.completed(123), Async.completed("abc"), Async.completed(true)])
311 | assert(async.is_completed)
312 | assert(_equal(await async.wait(), [123, "abc", true]))
313 |
314 | async = Async.all([Async.completed(123), "abc", Async.completed(true)])
315 | assert(async.is_completed)
316 | assert(_equal(await async.wait(), [123, "abc", true]))
317 |
318 | async = Async.all([Async.canceled(), Async.canceled(), Async.canceled()])
319 | assert(async.is_canceled)
320 | assert(await async.wait() == null)
321 |
322 | async = Async.all([Async.completed(123), "abc", Async.canceled()])
323 | assert(async.is_canceled)
324 | assert(await async.wait() == null)
325 |
326 | async = Async.all([Async.delay(0.2), Async.delay(0.2), Async.delay(0.2)])
327 | assert(not async.is_completed)
328 | assert(_equal(await async.wait(), [0.2, 0.2, 0.2]))
329 |
330 | async = Async.all([Async.delay(0.2), Async.delay(0.2), Async.delay(0.2)], Cancel.canceled())
331 | assert(async.is_canceled)
332 | assert(await async.wait() == null)
333 |
334 | async = Async.all([Async.delay(0.2), "abc", Async.completed(true)])
335 | assert(not async.is_completed)
336 | assert(_equal(await async.wait(), [0.2, "abc", true]))
337 |
338 | async = Async.all([Async.delay(0.2), "abc", Async.completed(true)], _delay_cancel())
339 | assert(not async.is_completed)
340 | assert(await async.wait() == null)
341 | assert(async.is_canceled)
342 |
343 | async = Async.all([Async.delay(0.2), "abc", Async.completed(true)])
344 | assert(not async.is_completed)
345 | assert(await async.wait(_delay_cancel()) == null)
346 | assert(async.is_canceled)
347 |
348 | %All.button_pressed = true
349 |
350 | func _test_all_settled() -> void:
351 | var async := Async.all_settled([])
352 | assert(async.is_completed)
353 | var list = await async.wait()
354 | assert(list.size() == 0)
355 |
356 | async = Async.all_settled([123, "abc", true])
357 | assert(async.is_completed)
358 | list = await async.wait()
359 | assert(list.size() == 3)
360 | assert(await list[0].wait() == 123)
361 | assert(await list[1].wait() == "abc")
362 | assert(await list[2].wait())
363 |
364 | async = Async.all_settled([Async.completed(123), Async.completed("abc"), Async.completed(true)])
365 | assert(async.is_completed)
366 | list = await async.wait()
367 | assert(list.size() == 3)
368 | assert(await list[0].wait() == 123)
369 | assert(await list[1].wait() == "abc")
370 | assert(await list[2].wait())
371 |
372 | async = Async.all_settled([Async.completed(123), "abc", Async.completed(true)])
373 | assert(async.is_completed)
374 | list = await async.wait()
375 | assert(list.size() == 3)
376 | assert(await list[0].wait() == 123)
377 | assert(await list[1].wait() == "abc")
378 | assert(await list[2].wait())
379 |
380 | async = Async.all_settled([Async.canceled(), Async.canceled(), Async.canceled()])
381 | assert(async.is_completed)
382 | list = await async.wait()
383 | assert(list.size() == 3)
384 | assert(list[0].is_canceled)
385 | assert(list[1].is_canceled)
386 | assert(list[2].is_canceled)
387 |
388 | async = Async.all_settled([Async.completed(123), "abc", Async.canceled()])
389 | assert(async.is_completed)
390 | list = await async.wait()
391 | assert(list.size() == 3)
392 | assert(await list[0].wait() == 123)
393 | assert(await list[1].wait() == "abc")
394 | assert(list[2].is_canceled)
395 |
396 | async = Async.all_settled([Async.delay(0.1), Async.delay(0.1), Async.delay(0.1)])
397 | assert(not async.is_completed)
398 | list = await async.wait()
399 | assert(list.size() == 3)
400 | assert(await list[0].wait() == 0.1)
401 | assert(await list[1].wait() == 0.1)
402 | assert(await list[2].wait() == 0.1)
403 |
404 | async = Async.all_settled([Async.delay(0.1), "abc", Async.completed(true)])
405 | assert(not async.is_completed)
406 | list = await async.wait()
407 | assert(list.size() == 3)
408 | assert(await list[0].wait() == 0.1)
409 | assert(await list[1].wait() == "abc")
410 | assert(await list[2].wait())
411 |
412 | async = Async.all_settled([Async.delay(0.2), "abc", Async.completed(true)], _delay_cancel())
413 | assert(not async.is_completed)
414 | list = await async.wait()
415 | assert(list[0].is_canceled)
416 | assert(await list[1].wait() == "abc")
417 | assert(await list[2].wait())
418 |
419 | async = Async.all_settled([Async.delay(0.2), "abc", Async.completed(true)])
420 | assert(not async.is_completed)
421 | assert(await async.wait(_delay_cancel()) == null)
422 | assert(async.is_canceled)
423 |
424 | %AllSettled.button_pressed = true
425 |
426 | func _test_any() -> void:
427 | var async := Async.any([])
428 | assert(async.is_canceled)
429 | assert(await async.wait() == null)
430 |
431 | async = Async.any([123, "abc", true])
432 | assert(async.is_completed)
433 | assert(await async.wait() == 123)
434 |
435 | async = Async.any([Async.completed(123), Async.completed("abc"), Async.completed(true)])
436 | assert(async.is_completed)
437 | assert(await async.wait() == 123)
438 |
439 | async = Async.any([Async.completed(123), "abc", Async.completed(true)])
440 | assert(async.is_completed)
441 | assert(await async.wait() == 123)
442 |
443 | async = Async.any([Async.canceled(), Async.canceled(), Async.canceled()])
444 | assert(async.is_canceled)
445 | assert(await async.wait() == null)
446 |
447 | async = Async.any([Async.completed(123), "abc", Async.canceled()])
448 | assert(async.is_completed)
449 | assert(await async.wait() == 123)
450 |
451 | async = Async.any([Async.delay(0.1), Async.delay(0.1), Async.delay(0.1)])
452 | assert(not async.is_completed)
453 | assert(await async.wait() == 0.1)
454 | assert(async.is_completed)
455 |
456 | async = Async.any([Async.delay(0.1), "abc", Async.completed(true)])
457 | assert(async.is_completed)
458 | assert(await async.wait() == "abc")
459 |
460 | async = Async.any([Async.delay(0.1), "abc", Async.canceled()], _delay_cancel())
461 | assert(async.is_completed)
462 | assert(await async.wait() == "abc")
463 |
464 | async = Async.any([Async.delay(0.2), Async.delay(0.2), Async.delay(0.2)], _delay_cancel())
465 | assert(not async.is_completed)
466 | assert(await async.wait() == null)
467 | assert(async.is_canceled)
468 |
469 | async = Async.any([Async.delay(0.2), Async.delay(0.2), Async.delay(0.2)])
470 | assert(not async.is_completed)
471 | assert(await async.wait(_delay_cancel()) == null)
472 | assert(async.is_canceled)
473 |
474 | async = Async.any([123, "abc", true])
475 | assert(async.is_completed)
476 | assert(await async.wait(Cancel.canceled()) == 123)
477 | assert(async.is_completed)
478 |
479 | %Any.button_pressed = true
480 |
481 | func _test_race() -> void:
482 | # var async := Async.race([])
483 | # assert(async.is_completed)
484 | # assert(await async.wait() == null)
485 |
486 | var async := Async.race([123, "abc", true])
487 | assert(async.is_completed)
488 | async = await async.wait()
489 | assert(async is Async)
490 | assert(await async.wait() == 123)
491 |
492 | async = Async.race([Async.completed(123), Async.completed("abc"), Async.completed(true)])
493 | assert(async.is_completed)
494 | async = await async.wait()
495 | assert(await async.wait() == 123)
496 |
497 | async = Async.race([Async.completed(123), "abc", Async.completed(true)])
498 | assert(async.is_completed)
499 | async = await async.wait()
500 | assert(await async.wait() == 123)
501 |
502 | async = Async.race([Async.canceled(), Async.canceled(), Async.canceled()])
503 | assert(async.is_completed)
504 | async = await async.wait()
505 | assert(async.is_canceled)
506 |
507 | async = Async.race([Async.completed(123), "abc", Async.canceled()])
508 | assert(async.is_completed)
509 | async = await async.wait()
510 | assert(await async.wait() == 123)
511 |
512 | async = Async.race([Async.canceled(), "abc", Async.completed(true)])
513 | assert(async.is_completed)
514 | async = await async.wait()
515 | assert(await async.wait() == "abc")
516 |
517 | async = Async.race([Async.delay(0.1), Async.delay(0.1), Async.delay(0.1)])
518 | assert(not async.is_completed)
519 | async = await async.wait()
520 | assert(await async.wait() == 0.1)
521 |
522 | async = Async.race([Async.delay(0.1), Async.delay(0.1), Async.delay(0.1)], Cancel.canceled())
523 | assert(async.is_completed)
524 | async = await async.wait()
525 | assert(async.is_canceled)
526 |
527 | async = Async.race([Async.delay(0.1), "abc", Async.completed(true)])
528 | assert(async.is_completed)
529 | async = await async.wait()
530 | assert(await async.wait() == "abc")
531 |
532 | async = Async.race([Async.delay(0.2), "abc", Async.completed(true)], _delay_cancel())
533 | assert(async.is_completed)
534 | async = await async.wait()
535 | assert(await async.wait() == "abc")
536 |
537 | async = Async.race([Async.delay(0.2), "abc", Async.completed(true)])
538 | assert(async.is_completed)
539 | async = await async.wait(_delay_cancel())
540 | assert(await async.wait() == "abc")
541 |
542 | async = Async.race([Async.delay(0.2), "abc", Async.completed(true)], _delay_cancel())
543 | assert(async.is_completed)
544 | async = await async.wait(_delay_cancel())
545 | assert(await async.wait() == "abc")
546 |
547 | %Race.button_pressed = true
548 |
549 | func _test_then() -> void:
550 | var async := Async.completed(123).then(func (r): return r * r)
551 | assert(async.is_completed)
552 | assert(await async.wait() == 15129)
553 |
554 | async = Async.canceled().then(func (r): return r * r)
555 | assert(async.is_canceled)
556 | assert(await async.wait() == null)
557 |
558 | async = Async.delay(0.1).then(func (_r): return 15129)
559 | assert(not async.is_completed)
560 | assert(await async.wait() == 15129)
561 |
562 | async = Async.completed(123).then(func (r):
563 | await Async.wait_delay(0.1)
564 | return r * r)
565 | assert(not async.is_completed)
566 | assert(await async.wait() == 15129)
567 |
568 | async = Async.delay(0.2).then(func (r): return r * r, _delay_cancel())
569 | assert(not async.is_completed)
570 | assert(not async.is_canceled)
571 | assert(await async.wait() == null)
572 | assert(async.is_canceled)
573 |
574 | async = Async.delay(0.2).then(func (r): return r * r)
575 | assert(not async.is_completed)
576 | assert(not async.is_canceled)
577 | assert(await async.wait(_delay_cancel()) == null)
578 | assert(async.is_canceled)
579 |
580 | async = Async.delay(0.2).then(func (r): return r * r, _delay_cancel())
581 | assert(not async.is_completed)
582 | assert(not async.is_canceled)
583 | assert(await async.wait(_delay_cancel()) == null)
584 | assert(async.is_canceled)
585 |
586 | async = Async.delay(0.2).then(func (r): return r * r, Cancel.canceled())
587 | assert(not async.is_completed)
588 | assert(async.is_canceled)
589 | assert(await async.wait(Cancel.canceled()) == null)
590 |
591 | %Then.button_pressed = true
592 |
593 | func _test_unwrap() -> void:
594 | var async := Async.completed(123).unwrap()
595 | assert(async.is_completed)
596 | assert(await async.wait() == 123)
597 |
598 | async = Async.completed(Async.completed(123)).unwrap()
599 | assert(async.is_completed)
600 | assert(await async.wait() == 123)
601 |
602 | async = Async.completed(Async.completed(Async.completed(123))).unwrap(2)
603 | assert(async.is_completed)
604 | assert(await async.wait() == 123)
605 |
606 | async = Async.canceled().unwrap()
607 | assert(async.is_canceled)
608 | assert(await async.wait() == null)
609 |
610 | async = Async.completed(Async.delay(0.1)).unwrap()
611 | assert(not async.is_completed)
612 | assert(await async.wait() == 0.1)
613 |
614 | async = Async.completed(Async.delay(0.2)).unwrap(1, _delay_cancel(0.1))
615 | assert(not async.is_completed)
616 | assert(not async.is_canceled)
617 | assert(await async.wait() == null)
618 | assert(async.is_canceled)
619 |
620 | async = Async.completed(Async.completed(Async.delay(0.2))).unwrap(1, _delay_cancel(0.1))
621 | assert(async.is_completed)
622 | async = await async.wait()
623 | assert(not async.is_completed)
624 | assert(await async.wait() == 0.2)
625 |
626 | %Unwrap.button_pressed = true
627 |
628 | func _test_from_conditional_signal() -> void:
629 | var async := Async.from_conditional_signal(_signal0, [])
630 | assert(not async.is_completed)
631 | _emit0()
632 | assert(_equal(await async.wait(), []))
633 |
634 | async = Async.from_conditional_signal(_signal1, [123])
635 | assert(not async.is_completed)
636 | _emit1(456)
637 | assert(not async.is_completed)
638 | _emit1(123)
639 | assert(_equal(await async.wait(), [123]))
640 |
641 | async = Async.from_conditional_signal(_signal1, [Async.SKIP])
642 | assert(not async.is_completed)
643 | _emit1(123)
644 | assert(_equal(await async.wait(), [123]))
645 |
646 | async = Async.from_conditional_signal(_signal2, [123, "abc"])
647 | assert(not async.is_completed)
648 | _emit2(123, "def")
649 | assert(not async.is_completed)
650 | _emit2(123, "abc")
651 | assert(_equal(await async.wait(), [123, "abc"]))
652 |
653 | async = Async.from_conditional_signal(_signal2, [123, Async.SKIP])
654 | assert(not async.is_completed)
655 | _emit2(123, "abc")
656 | assert(_equal(await async.wait(), [123, "abc"]))
657 |
658 | async = Async.from_conditional_signal(_signal3, [123, "abc", true])
659 | assert(not async.is_completed)
660 | _emit3(123, "abc", false)
661 | assert(not async.is_completed)
662 | _emit3(123, "abc", true)
663 | assert(_equal(await async.wait(), [123, "abc", true]))
664 |
665 | async = Async.from_conditional_signal(_signal3, [123, "abc", Async.SKIP])
666 | assert(not async.is_completed)
667 | _emit3(123, "abc", true)
668 | assert(_equal(await async.wait(), [123, "abc", true]))
669 |
670 | async = Async.from_conditional_signal(_signal4, [123, "abc", true, null])
671 | assert(not async.is_completed)
672 | _emit4(123, "abc", true, Object.new())
673 | assert(not async.is_completed)
674 | _emit4(123, "abc", true, null)
675 | assert(_equal(await async.wait(), [123, "abc", true, null]))
676 |
677 | async = Async.from_conditional_signal(_signal4, [123, "abc", true, Async.SKIP])
678 | assert(not async.is_completed)
679 | _emit4(123, "abc", true, null)
680 | assert(_equal(await async.wait(), [123, "abc", true, null]))
681 |
682 | async = Async.from_conditional_signal(_signal5, [123, "abc", true, null, 0.5])
683 | assert(not async.is_completed)
684 | _emit5(123, "abc", true, null, 1.0)
685 | assert(not async.is_completed)
686 | _emit5(123, "abc", true, null, 0.5)
687 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
688 |
689 | async = Async.from_conditional_signal(_signal5, [123, "abc", true, null, Async.SKIP])
690 | assert(not async.is_completed)
691 | _emit5(123, "abc", true, null, 0.5)
692 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
693 |
694 | %FromConditionalSignal.button_pressed = true
695 |
696 | func _test_from_conditional_signal_name() -> void:
697 | var async := Async.from_conditional_signal_name(self, "_signal0", [])
698 | assert(not async.is_completed)
699 | _emit0()
700 | assert(_equal(await async.wait(), []))
701 |
702 | async = Async.from_conditional_signal_name(self, "_signal1", [123])
703 | assert(not async.is_completed)
704 | _emit1(456)
705 | assert(not async.is_completed)
706 | _emit1(123)
707 | assert(_equal(await async.wait(), [123]))
708 |
709 | async = Async.from_conditional_signal_name(self, "_signal1", [Async.SKIP])
710 | assert(not async.is_completed)
711 | _emit1(123)
712 | assert(_equal(await async.wait(), [123]))
713 |
714 | async = Async.from_conditional_signal_name(self, "_signal2", [123, "abc"])
715 | assert(not async.is_completed)
716 | _emit2(123, "def")
717 | assert(not async.is_completed)
718 | _emit2(123, "abc")
719 | assert(_equal(await async.wait(), [123, "abc"]))
720 |
721 | async = Async.from_conditional_signal_name(self, "_signal2", [123, Async.SKIP])
722 | assert(not async.is_completed)
723 | _emit2(123, "abc")
724 | assert(_equal(await async.wait(), [123, "abc"]))
725 |
726 | async = Async.from_conditional_signal_name(self, "_signal3", [123, "abc", true])
727 | assert(not async.is_completed)
728 | _emit3(123, "abc", false)
729 | assert(not async.is_completed)
730 | _emit3(123, "abc", true)
731 | assert(_equal(await async.wait(), [123, "abc", true]))
732 |
733 | async = Async.from_conditional_signal_name(self, "_signal3", [123, "abc", Async.SKIP])
734 | assert(not async.is_completed)
735 | _emit3(123, "abc", true)
736 | assert(_equal(await async.wait(), [123, "abc", true]))
737 |
738 | async = Async.from_conditional_signal_name(self, "_signal4", [123, "abc", true, null])
739 | assert(not async.is_completed)
740 | _emit4(123, "abc", true, Object.new())
741 | assert(not async.is_completed)
742 | _emit4(123, "abc", true, null)
743 | assert(_equal(await async.wait(), [123, "abc", true, null]))
744 |
745 | async = Async.from_conditional_signal_name(self, "_signal4", [123, "abc", true, Async.SKIP])
746 | assert(not async.is_completed)
747 | _emit4(123, "abc", true, null)
748 | assert(_equal(await async.wait(), [123, "abc", true, null]))
749 |
750 | async = Async.from_conditional_signal_name(self, "_signal5", [123, "abc", true, null, 0.5])
751 | assert(not async.is_completed)
752 | _emit5(123, "abc", true, null, 1.0)
753 | assert(not async.is_completed)
754 | _emit5(123, "abc", true, null, 0.5)
755 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
756 |
757 | async = Async.from_conditional_signal_name(self, "_signal5", [123, "abc", true, null, Async.SKIP])
758 | assert(not async.is_completed)
759 | _emit5(123, "abc", true, null, 0.5)
760 | assert(_equal(await async.wait(), [123, "abc", true, null, 0.5]))
761 |
762 | %FromConditionalSignalName.button_pressed = true
763 |
764 | func _test_defer() -> void:
765 | var async := Async.defer(Async.DEFER_IDLE)
766 | assert(not async.is_completed)
767 | assert(await async.wait() == null)
768 |
769 | async = Async.defer(Async.DEFER_PROCESS_FRAME)
770 | assert(not async.is_completed)
771 | assert(await async.wait() == null)
772 |
773 | async = Async.defer(Async.DEFER_PHYSICS_FRAME)
774 | assert(not async.is_completed)
775 | assert(await async.wait() == null)
776 |
777 | %Defer.button_pressed = true
778 |
779 | func _ready() -> void:
780 | # 1.0.1
781 | await _test_completed()
782 | await _test_canceled()
783 | await _test_from()
784 | await _test_from_signal()
785 | await _test_from_signal_name()
786 | await _test_delay()
787 | await _test_delay_msec()
788 | await _test_delay_usec()
789 | await _test_all()
790 | await _test_all_settled()
791 | await _test_any()
792 | await _test_race()
793 | await _test_then()
794 | await _test_unwrap()
795 |
796 | # 1.0.2
797 | await _test_defer()
798 | await _test_from_conditional_signal()
799 | await _test_from_conditional_signal_name()
800 |
--------------------------------------------------------------------------------