mini-arcade-core 1.1.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mini_arcade_core/__init__.py +14 -42
- mini_arcade_core/backend/__init__.py +1 -2
- mini_arcade_core/backend/backend.py +182 -184
- mini_arcade_core/backend/types.py +5 -1
- mini_arcade_core/engine/commands.py +8 -8
- mini_arcade_core/engine/game.py +54 -354
- mini_arcade_core/engine/game_config.py +40 -0
- mini_arcade_core/engine/gameplay_settings.py +24 -0
- mini_arcade_core/engine/loop/config.py +20 -0
- mini_arcade_core/engine/loop/hooks.py +77 -0
- mini_arcade_core/engine/loop/runner.py +272 -0
- mini_arcade_core/engine/loop/state.py +32 -0
- mini_arcade_core/engine/managers.py +24 -0
- mini_arcade_core/engine/render/context.py +0 -2
- mini_arcade_core/engine/render/effects/base.py +2 -2
- mini_arcade_core/engine/render/effects/crt.py +4 -4
- mini_arcade_core/engine/render/effects/registry.py +1 -1
- mini_arcade_core/engine/render/effects/vignette.py +8 -8
- mini_arcade_core/engine/render/passes/begin_frame.py +1 -1
- mini_arcade_core/engine/render/passes/end_frame.py +1 -1
- mini_arcade_core/engine/render/passes/postfx.py +1 -1
- mini_arcade_core/engine/render/passes/ui.py +1 -1
- mini_arcade_core/engine/render/passes/world.py +6 -6
- mini_arcade_core/engine/render/pipeline.py +7 -6
- mini_arcade_core/engine/render/viewport.py +10 -4
- mini_arcade_core/engine/scenes/models.py +54 -0
- mini_arcade_core/engine/scenes/scene_manager.py +213 -0
- mini_arcade_core/runtime/audio/audio_adapter.py +4 -3
- mini_arcade_core/runtime/audio/audio_port.py +0 -4
- mini_arcade_core/runtime/capture/capture_adapter.py +13 -6
- mini_arcade_core/runtime/capture/capture_port.py +0 -4
- mini_arcade_core/runtime/context.py +8 -6
- mini_arcade_core/runtime/scene/scene_query_adapter.py +31 -0
- mini_arcade_core/runtime/scene/scene_query_port.py +38 -0
- mini_arcade_core/runtime/services.py +3 -2
- mini_arcade_core/runtime/window/window_adapter.py +43 -41
- mini_arcade_core/runtime/window/window_port.py +3 -17
- mini_arcade_core/scenes/debug_overlay.py +5 -4
- mini_arcade_core/scenes/registry.py +11 -1
- mini_arcade_core/scenes/sim_scene.py +14 -14
- mini_arcade_core/ui/menu.py +54 -16
- mini_arcade_core/utils/__init__.py +2 -1
- mini_arcade_core/utils/logging.py +47 -18
- mini_arcade_core/utils/profiler.py +283 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.0.dist-info}/METADATA +1 -1
- mini_arcade_core-1.2.0.dist-info/RECORD +92 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.0.dist-info}/WHEEL +1 -1
- mini_arcade_core/managers/inputs.py +0 -284
- mini_arcade_core/runtime/scene/scene_adapter.py +0 -125
- mini_arcade_core/runtime/scene/scene_port.py +0 -170
- mini_arcade_core/sim/protocols.py +0 -41
- mini_arcade_core/sim/runner.py +0 -222
- mini_arcade_core-1.1.1.dist-info/RECORD +0 -85
- /mini_arcade_core/{managers → engine}/cheats.py +0 -0
- /mini_arcade_core/{managers → engine/loop}/__init__.py +0 -0
- /mini_arcade_core/{sim → engine/scenes}/__init__.py +0 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
mini_arcade_core/__init__.py,sha256=AdhR8GzhJnPYBkwIdNag1cnB8e4JqCHNZxsZfrw5vCQ,2564
|
|
2
|
+
mini_arcade_core/backend/__init__.py,sha256=J1wZBHX-aqmBP3zh_ey9PK2b_gnWp72zxMfKcs3iwSw,274
|
|
3
|
+
mini_arcade_core/backend/backend.py,sha256=tJYjHqjWZst8P3uikStndEHIVWLvF0ypmibVtCErbag,8699
|
|
4
|
+
mini_arcade_core/backend/events.py,sha256=5Ohve3CQ6n2CztiOhbCoz6yFDY4z0j4v4R9FBKRDRjc,2929
|
|
5
|
+
mini_arcade_core/backend/keys.py,sha256=LTg20SwLBI3kpPIiTNpq2yBft_QUGj-iNFSNm9M-Fus,3010
|
|
6
|
+
mini_arcade_core/backend/sdl_map.py,sha256=_yBRtvaFUcQKy1kcoIf-SPhbbKEW7dzvzBcI6TLmKjc,2060
|
|
7
|
+
mini_arcade_core/backend/types.py,sha256=EW0bW4MvsEZKot0Z1h_5LuFSzoYGiJBphTquBz4oXf4,244
|
|
8
|
+
mini_arcade_core/bus.py,sha256=2Etpoa-UWhk33xJjqDlY5YslPDJEjxNoIEVtF3C73vs,1558
|
|
9
|
+
mini_arcade_core/engine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
mini_arcade_core/engine/cheats.py,sha256=jMx2a8YnaNCkCG5MPmIzz4uHuS7-_aYf0J45cv2-3v0,5569
|
|
11
|
+
mini_arcade_core/engine/commands.py,sha256=Cw1tAwVRO5U2--hFX1Jq00LH_84oe1Oqw-Ngc0RnkGI,5383
|
|
12
|
+
mini_arcade_core/engine/game.py,sha256=DDdvlv0cN4sjBKtoIuP19W3YQCF1LwZbC_jYCz-1E4U,5767
|
|
13
|
+
mini_arcade_core/engine/game_config.py,sha256=4AP8n0Uk1HKEdPLOrV1xsySzBljAh8VhZASNrxPIMMc,1034
|
|
14
|
+
mini_arcade_core/engine/gameplay_settings.py,sha256=W8WBwfAvGZftkL4aMnOTx6SsGxwG-9Ou1Ey0AeWPCxs,549
|
|
15
|
+
mini_arcade_core/engine/loop/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
mini_arcade_core/engine/loop/config.py,sha256=Sj1LrdnD_aACmHUuRQuKB7bDbDZy60WVe8sJHRmzmIU,461
|
|
17
|
+
mini_arcade_core/engine/loop/hooks.py,sha256=nmZi-35iMsZoPedTdZzsIKJP6O_iFUeKjB8xc4-XTHU,2417
|
|
18
|
+
mini_arcade_core/engine/loop/runner.py,sha256=uB4onDMO6lWFt40YNJsovkVHXiyaVdEuEFj8kYqWn6k,8858
|
|
19
|
+
mini_arcade_core/engine/loop/state.py,sha256=fzXQ9GP05PVNXEBTgIwA4qjMujxdUae3CXM6uRQz92Y,858
|
|
20
|
+
mini_arcade_core/engine/managers.py,sha256=eQJYe-xYtRha-FWxzJ3DcpwlcHwiT5sGt4oCD9ZPxEE,664
|
|
21
|
+
mini_arcade_core/engine/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
mini_arcade_core/engine/render/context.py,sha256=igoBmsasv3AJtrIIe2IGkjHXEm5ouEobvdN7Gmm0vxY,1327
|
|
23
|
+
mini_arcade_core/engine/render/effects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
mini_arcade_core/engine/render/effects/base.py,sha256=uix-kfzvN5j3dx655h_Yxe-a3rN1WTtN4tj5zeqFi3c,2357
|
|
25
|
+
mini_arcade_core/engine/render/effects/crt.py,sha256=75ejQVNhftN_GwZV9CYkHv2D672V84zDygmO9h_fo1A,2154
|
|
26
|
+
mini_arcade_core/engine/render/effects/registry.py,sha256=ZBbyyhF4K2gxb4f6hV35uh6RuSj7kOhQgcxwKocqJpY,1212
|
|
27
|
+
mini_arcade_core/engine/render/effects/vignette.py,sha256=K87CjIWpjlWN_tJVrnY3tW2njOvLvnuRezCwk05OgVw,2610
|
|
28
|
+
mini_arcade_core/engine/render/frame_packet.py,sha256=nYHvR7CHlIZa6ZazmPO2dU2P91vEkBjBzUVQGrOkaYc,624
|
|
29
|
+
mini_arcade_core/engine/render/packet.py,sha256=OiAPwGoVHo04OcUWMAoA_N1AFPUMyf8yxNgJthGj4-c,1440
|
|
30
|
+
mini_arcade_core/engine/render/passes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
mini_arcade_core/engine/render/passes/base.py,sha256=LWgWhfafbCvRKIFbt3koW-ibjYxMfKOIXyLNazCakcM,864
|
|
32
|
+
mini_arcade_core/engine/render/passes/begin_frame.py,sha256=RowMYnkSSQVlMCDVRHXEiy4Hb5Ru-VPBqxsmMzzkXuU,706
|
|
33
|
+
mini_arcade_core/engine/render/passes/end_frame.py,sha256=BBNyVhD8s7B9c_s373g9DDH_eVNGGVnMl5n0GhKIgiw,767
|
|
34
|
+
mini_arcade_core/engine/render/passes/lighting.py,sha256=ugmHHNNZWArL_Xs6-1SQIxLptUTQwe4M2sSPEk8X-7s,677
|
|
35
|
+
mini_arcade_core/engine/render/passes/postfx.py,sha256=YLLcJb1qwNwxg40f_6Nh1xXeGN1tsCnGd8_FdKsfRAM,1424
|
|
36
|
+
mini_arcade_core/engine/render/passes/ui.py,sha256=cct8v0Jjqv6w77IlKz2medPkQjPvG8cCifRv943qyFM,1129
|
|
37
|
+
mini_arcade_core/engine/render/passes/world.py,sha256=OhvDB8aPTkFGlHiROlL9A13pdjWAYGbo8NadkWCUK-c,1522
|
|
38
|
+
mini_arcade_core/engine/render/pipeline.py,sha256=A-Pxw0t0RbW_pswVtBEGNIgC-1dSNqwaK8p7JoXiw8k,3288
|
|
39
|
+
mini_arcade_core/engine/render/render_service.py,sha256=1ueir8MZ6Six5gAHt5StoICPAbyppX4DqzWb8HEuS9g,531
|
|
40
|
+
mini_arcade_core/engine/render/viewport.py,sha256=Fi7O04KRC6d3s01sP0cfchdwegt6s_vOdwomck9yryc,5972
|
|
41
|
+
mini_arcade_core/engine/scenes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
mini_arcade_core/engine/scenes/models.py,sha256=UKKGUWyFf_XFC09hICTFQ6_szDXytoI5KauCmr9ugoM,1217
|
|
43
|
+
mini_arcade_core/engine/scenes/scene_manager.py,sha256=xGzMH7tBsHExN9aYLZsx462aY9r5j-cDNqQvwnK3cI8,6455
|
|
44
|
+
mini_arcade_core/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
mini_arcade_core/runtime/audio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
mini_arcade_core/runtime/audio/audio_adapter.py,sha256=lnP35txPzSKX1_il0nXcK7RMF5Qp9Qhi9YMh_7LTdPM,588
|
|
47
|
+
mini_arcade_core/runtime/audio/audio_port.py,sha256=jBd9WabN41uK3MHjg_1n4AOw83NivJlGE2m430WZTnk,831
|
|
48
|
+
mini_arcade_core/runtime/capture/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
|
+
mini_arcade_core/runtime/capture/capture_adapter.py,sha256=XBtiKw3AS2dzB4QogPm9kjhiQAenS25guX87tg-zK58,4882
|
|
50
|
+
mini_arcade_core/runtime/capture/capture_port.py,sha256=niHi0pAo10mC9p73FxFkYBIGLOLRN0PiOvxE4Zgo5fM,1162
|
|
51
|
+
mini_arcade_core/runtime/context.py,sha256=ONKQryO3KEOOqHaByxCUola07kdjrnvr4WfXwgwTobk,1777
|
|
52
|
+
mini_arcade_core/runtime/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
|
+
mini_arcade_core/runtime/file/file_adapter.py,sha256=09q7G9Qijml9d4AAjo6HLC1yuoVTjE_7xaT8apT4mk0,523
|
|
54
|
+
mini_arcade_core/runtime/file/file_port.py,sha256=p1MouCSHXZw--rWNMw3aYBLU-of8mXaT_suopczPtM8,608
|
|
55
|
+
mini_arcade_core/runtime/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
+
mini_arcade_core/runtime/input/input_adapter.py,sha256=vExQiwFIWTI3zYD8lmnD9TvoQPZvJfI6IINPJUqAdQ0,1467
|
|
57
|
+
mini_arcade_core/runtime/input/input_port.py,sha256=d4ptftwf92_LJdyaUMFxIsLHXBINzQyJACHn4laNyxQ,746
|
|
58
|
+
mini_arcade_core/runtime/input_frame.py,sha256=34-RAfOD-YScVLyRQrarpm7byFTHjsWM77lIH0JsmT8,2384
|
|
59
|
+
mini_arcade_core/runtime/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
mini_arcade_core/runtime/render/render_port.py,sha256=Sqp-JBh-iRzzGtgnO_nU1KiJEqyrTYPRDQbg04HdR0A,507
|
|
61
|
+
mini_arcade_core/runtime/scene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
|
+
mini_arcade_core/runtime/scene/scene_query_adapter.py,sha256=FNkqXgwxfugX_xqqFlZl0ELXsrW_gco5Au0tJhMGLgQ,909
|
|
63
|
+
mini_arcade_core/runtime/scene/scene_query_port.py,sha256=qTikQVxOkJCdoMoH_lbe_ctJj7SWeJnnqDo6Ee0N_pQ,1019
|
|
64
|
+
mini_arcade_core/runtime/services.py,sha256=iYcXt2CTapgDzSb54DsPasYZ4jTN7tA_B0lV1Sl5b1g,1243
|
|
65
|
+
mini_arcade_core/runtime/window/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
+
mini_arcade_core/runtime/window/window_adapter.py,sha256=VLZGYBVl7sGMmnk5mVowDleTyciAfE-Tc2woNFvRrgE,2890
|
|
67
|
+
mini_arcade_core/runtime/window/window_port.py,sha256=HBy2OjsZzlxbBDQiTqlKEbIaejpN1zDp5whgvKxZxaY,2322
|
|
68
|
+
mini_arcade_core/scenes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
|
+
mini_arcade_core/scenes/autoreg.py,sha256=wsuY7YUSZFmDyToKHFriAG78OU48-7J4BfL_X6T5GBg,1037
|
|
70
|
+
mini_arcade_core/scenes/debug_overlay.py,sha256=t7zWeTxosCUWj3gBDkYF2448EBM5zwLCOEmWVHXghMk,2495
|
|
71
|
+
mini_arcade_core/scenes/registry.py,sha256=DHliUGGiSLWugtRU9R6JeH5gK3GUDICmS-3iie6GtH8,3631
|
|
72
|
+
mini_arcade_core/scenes/sim_scene.py,sha256=32GVR9XHMak-afyyH9M6_UkCPAjRz8XiUKj2lcpAGAE,1061
|
|
73
|
+
mini_arcade_core/scenes/systems/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
+
mini_arcade_core/scenes/systems/base_system.py,sha256=GfMrXsO8ynW3xOxWeav7Ug5XUbRnbF0vo8VzmG7gpec,1075
|
|
75
|
+
mini_arcade_core/scenes/systems/system_pipeline.py,sha256=Cy9y1DclbMLZZ-yx7OKYe34ORoGLNa6dReQfOdiO8SY,1642
|
|
76
|
+
mini_arcade_core/spaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
|
+
mini_arcade_core/spaces/d2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
+
mini_arcade_core/spaces/d2/boundaries2d.py,sha256=xeTnd0pW5DKfqaKsfSBXnufeb45aXNIspgHRyLXWejo,2804
|
|
79
|
+
mini_arcade_core/spaces/d2/collision2d.py,sha256=5IvgLnyVb8i0uzzZuum1noWsNhoxcvHOLaHkmrTMTxQ,1710
|
|
80
|
+
mini_arcade_core/spaces/d2/geometry2d.py,sha256=FuYzef-XdOyb1aeGLJbxINxr0WJHnqFFBgtbPi1WonY,1716
|
|
81
|
+
mini_arcade_core/spaces/d2/kinematics2d.py,sha256=AJ3DhPXNgm6wZYwCljMIE4_2BYx3E2rPcwhXTgQALkU,2030
|
|
82
|
+
mini_arcade_core/spaces/d2/physics2d.py,sha256=OQT7r-zMtmoKD2aWCSNmRAdI0OGIpxGX-pLR8LcAMbQ,1854
|
|
83
|
+
mini_arcade_core/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
|
+
mini_arcade_core/ui/menu.py,sha256=t2YpwiKqy4KZHfU9U7c6CUE3SNamBSyipWnd9Y4BVxA,25738
|
|
85
|
+
mini_arcade_core/utils/__init__.py,sha256=id1C0au8r1oIzGha42xXwnI9ojcU1hxPgto6QSh9H8c,236
|
|
86
|
+
mini_arcade_core/utils/deprecated_decorator.py,sha256=yrrW2ZqPskK-4MUTyIrMb465Wc54X2poV53ZQutZWqc,1140
|
|
87
|
+
mini_arcade_core/utils/logging.py,sha256=ygKpey6nikp30PrNDP_yRs8pxPPRbsQ0ivR6LUuEn3Q,6413
|
|
88
|
+
mini_arcade_core/utils/profiler.py,sha256=vLzrxDfAplgKGxpuzk4eFJx4t5DU5M3DQAn6sfS5D_4,8733
|
|
89
|
+
mini_arcade_core-1.2.0.dist-info/METADATA,sha256=PeD3ImQ4FG5bjuYKFdLThR59fOvr-lgOS3OaF1XVRis,8188
|
|
90
|
+
mini_arcade_core-1.2.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
91
|
+
mini_arcade_core-1.2.0.dist-info/licenses/LICENSE,sha256=3lHAuV0584cVS5vAqi2uC6GcsVgxUijvwvtZckyvaZ4,1096
|
|
92
|
+
mini_arcade_core-1.2.0.dist-info/RECORD,,
|
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Input manager for handling input bindings and commands.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
# TODO: Implement this manager into the new input system
|
|
6
|
-
# Justification: These module will be used later.
|
|
7
|
-
# pylint: disable=no-name-in-module,import-error,used-before-assignment
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import logging
|
|
12
|
-
from dataclasses import dataclass
|
|
13
|
-
from typing import TYPE_CHECKING, Callable, Dict, Optional
|
|
14
|
-
|
|
15
|
-
from mini_arcade_core.backend import Event, EventType
|
|
16
|
-
from mini_arcade_core.keymaps import Key
|
|
17
|
-
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
from mini_arcade_core.engine.commands import BaseCommand, BaseSceneCommand
|
|
20
|
-
from mini_arcade_core.scenes.scene import Scene
|
|
21
|
-
|
|
22
|
-
logger = logging.getLogger(__name__)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Predicate = Callable[["Event"], bool]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass(frozen=True)
|
|
29
|
-
class InputBinding:
|
|
30
|
-
"""
|
|
31
|
-
Defines an input binding.
|
|
32
|
-
|
|
33
|
-
:ivar action (str): The action name.
|
|
34
|
-
:ivar command (BaseCommand): The command to execute.
|
|
35
|
-
:ivar predicate (Predicate): Predicate to match events.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
action: str
|
|
39
|
-
command: BaseCommand
|
|
40
|
-
predicate: Predicate # decides whether this binding matches an event
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class InputManager:
|
|
44
|
-
"""
|
|
45
|
-
Manager for handling input bindings and commands.
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
def __init__(self):
|
|
49
|
-
# event_type -> key -> action -> command
|
|
50
|
-
self._bindings: Dict[EventType, Dict[Key, Dict[str, BaseCommand]]] = {}
|
|
51
|
-
|
|
52
|
-
# Justification: The method needs multiple optional parameters for flexibility.
|
|
53
|
-
# pylint: disable=too-many-arguments
|
|
54
|
-
def bind(
|
|
55
|
-
self,
|
|
56
|
-
event_type: EventType,
|
|
57
|
-
action: str,
|
|
58
|
-
command: BaseCommand,
|
|
59
|
-
*,
|
|
60
|
-
key: Optional[Key] = None,
|
|
61
|
-
button: Optional[int] = None,
|
|
62
|
-
predicate: Optional[Predicate] = None,
|
|
63
|
-
):
|
|
64
|
-
"""
|
|
65
|
-
Generic binding.
|
|
66
|
-
|
|
67
|
-
You can filter by:
|
|
68
|
-
- key: for KEYDOWN/KEYUP
|
|
69
|
-
- button: for MOUSEBUTTONDOWN/MOUSEBUTTONUP (if your Event exposes it)
|
|
70
|
-
- predicate: custom matcher (for anything)
|
|
71
|
-
|
|
72
|
-
:param event_type: The type of event to bind to.
|
|
73
|
-
:type event_type: EventType
|
|
74
|
-
|
|
75
|
-
:param action: The action name for the binding.
|
|
76
|
-
:type action: str
|
|
77
|
-
|
|
78
|
-
:param command: The command to execute when the binding is triggered.
|
|
79
|
-
:type command: BaseCommand
|
|
80
|
-
|
|
81
|
-
:param key: Optional key to filter KEYDOWN/KEYUP events.
|
|
82
|
-
:type key: Key | None
|
|
83
|
-
|
|
84
|
-
:param button: Optional button to filter MOUSEBUTTONDOWN/MOUSEBUTTONUP events.
|
|
85
|
-
:type button: int | None
|
|
86
|
-
|
|
87
|
-
:param predicate: Optional custom predicate to match events.
|
|
88
|
-
:type predicate: Predicate | None
|
|
89
|
-
"""
|
|
90
|
-
logger.debug(
|
|
91
|
-
f"Binding {action} to {event_type} with key={key}, button={button}"
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
def default_predicate(ev: Event) -> bool:
|
|
95
|
-
if key is not None and getattr(ev, "key", None) != key:
|
|
96
|
-
return False
|
|
97
|
-
if button is not None and getattr(ev, "button", None) != button:
|
|
98
|
-
return False
|
|
99
|
-
return True
|
|
100
|
-
|
|
101
|
-
pred = predicate or default_predicate
|
|
102
|
-
self._bindings.setdefault(event_type, []).append(
|
|
103
|
-
InputBinding(action=action, command=command, predicate=pred)
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# pylint: enable=too-many-arguments
|
|
107
|
-
|
|
108
|
-
def unbind(self, event_type: EventType, action: str):
|
|
109
|
-
"""
|
|
110
|
-
Remove bindings by action for an event type.
|
|
111
|
-
|
|
112
|
-
:param event_type: The type of event to unbind from.
|
|
113
|
-
:type event_type: EventType
|
|
114
|
-
|
|
115
|
-
:param action: The action name of the binding to remove.
|
|
116
|
-
:type action: str
|
|
117
|
-
"""
|
|
118
|
-
lst = self._bindings.get(event_type, [])
|
|
119
|
-
self._bindings[event_type] = [b for b in lst if b.action != action]
|
|
120
|
-
|
|
121
|
-
def clear(self):
|
|
122
|
-
"""Clear all input bindings."""
|
|
123
|
-
self._bindings.clear()
|
|
124
|
-
|
|
125
|
-
def handle_event(self, event: Event, scene: Scene):
|
|
126
|
-
"""
|
|
127
|
-
Handle an incoming event, executing any matching commands.
|
|
128
|
-
|
|
129
|
-
:param event: The event to handle.
|
|
130
|
-
:type event: Event
|
|
131
|
-
|
|
132
|
-
:param scene: The current scene context.
|
|
133
|
-
:type scene: Scene
|
|
134
|
-
"""
|
|
135
|
-
et = event.type
|
|
136
|
-
|
|
137
|
-
for binding in self._bindings.get(et, []):
|
|
138
|
-
if binding.predicate(event):
|
|
139
|
-
to_inject = (
|
|
140
|
-
scene.model
|
|
141
|
-
if isinstance(binding.command, BaseSceneCommand)
|
|
142
|
-
else scene.game
|
|
143
|
-
)
|
|
144
|
-
binding.command.execute(to_inject)
|
|
145
|
-
|
|
146
|
-
def on_quit(self, command: BaseCommand, action: str = "quit"):
|
|
147
|
-
"""
|
|
148
|
-
Bind a command to the QUIT event.
|
|
149
|
-
|
|
150
|
-
:param command: The command to execute on quit.
|
|
151
|
-
:type command: BaseCommand
|
|
152
|
-
|
|
153
|
-
:param action: The action name for the binding.
|
|
154
|
-
:type action: str
|
|
155
|
-
"""
|
|
156
|
-
self.bind(EventType.QUIT, action=action, command=command)
|
|
157
|
-
|
|
158
|
-
def on_key_down(self, key: Key, command: BaseCommand, action: str):
|
|
159
|
-
"""
|
|
160
|
-
Bind a command to a key down event.
|
|
161
|
-
|
|
162
|
-
:param key: The key to bind to.
|
|
163
|
-
:type key: Key
|
|
164
|
-
|
|
165
|
-
:param command: The command to execute on key down.
|
|
166
|
-
:type command: BaseCommand
|
|
167
|
-
|
|
168
|
-
:param action: The action name for the binding.
|
|
169
|
-
:type action: str
|
|
170
|
-
"""
|
|
171
|
-
self.bind(EventType.KEYDOWN, key=key, action=action, command=command)
|
|
172
|
-
|
|
173
|
-
def on_key_up(self, key: Key, command: BaseCommand, action: str):
|
|
174
|
-
"""
|
|
175
|
-
Bind a command to a key up event.
|
|
176
|
-
|
|
177
|
-
:param key: The key to bind to.
|
|
178
|
-
:type key: Key
|
|
179
|
-
|
|
180
|
-
:param command: The command to execute on key up.
|
|
181
|
-
:type command: BaseCommand
|
|
182
|
-
|
|
183
|
-
:param action: The action name for the binding.
|
|
184
|
-
:type action: str
|
|
185
|
-
"""
|
|
186
|
-
self.bind(EventType.KEYUP, key=key, action=action, command=command)
|
|
187
|
-
|
|
188
|
-
def on_mouse_button_down(
|
|
189
|
-
self, button: int, command: BaseCommand, action: str
|
|
190
|
-
):
|
|
191
|
-
"""
|
|
192
|
-
Bind a command to a mouse button down event.
|
|
193
|
-
|
|
194
|
-
:param button: The mouse button to bind to.
|
|
195
|
-
:type button: int
|
|
196
|
-
|
|
197
|
-
:param command: The command to execute on mouse button down.
|
|
198
|
-
:type command: BaseCommand
|
|
199
|
-
|
|
200
|
-
:param action: The action name for the binding.
|
|
201
|
-
:type action: str
|
|
202
|
-
"""
|
|
203
|
-
self.bind(
|
|
204
|
-
EventType.MOUSEBUTTONDOWN,
|
|
205
|
-
button=button,
|
|
206
|
-
action=action,
|
|
207
|
-
command=command,
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
def on_mouse_button_up(
|
|
211
|
-
self, button: int, command: BaseCommand, action: str
|
|
212
|
-
):
|
|
213
|
-
"""
|
|
214
|
-
Bind a command to a mouse button up event.
|
|
215
|
-
|
|
216
|
-
:param button: The mouse button to bind to.
|
|
217
|
-
:type button: int
|
|
218
|
-
|
|
219
|
-
:param command: The command to execute on mouse button up.
|
|
220
|
-
:type command: BaseCommand
|
|
221
|
-
|
|
222
|
-
:param action: The action name for the binding.
|
|
223
|
-
:type action: str
|
|
224
|
-
"""
|
|
225
|
-
self.bind(
|
|
226
|
-
EventType.MOUSEBUTTONUP,
|
|
227
|
-
button=button,
|
|
228
|
-
action=action,
|
|
229
|
-
command=command,
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
def on_mouse_motion(
|
|
233
|
-
self, command: BaseCommand, action: str = "mouse_motion"
|
|
234
|
-
):
|
|
235
|
-
"""
|
|
236
|
-
Bind a command to mouse motion events.
|
|
237
|
-
|
|
238
|
-
:param command: The command to execute on mouse motion.
|
|
239
|
-
:type command: BaseCommand
|
|
240
|
-
|
|
241
|
-
:param action: The action name for the binding.
|
|
242
|
-
:type action: str
|
|
243
|
-
"""
|
|
244
|
-
self.bind(EventType.MOUSEMOTION, action=action, command=command)
|
|
245
|
-
|
|
246
|
-
def on_mouse_wheel(
|
|
247
|
-
self, command: BaseCommand, action: str = "mouse_wheel"
|
|
248
|
-
):
|
|
249
|
-
"""
|
|
250
|
-
Bind a command to mouse wheel events.
|
|
251
|
-
|
|
252
|
-
:param command: The command to execute on mouse wheel.
|
|
253
|
-
:type command: BaseCommand
|
|
254
|
-
|
|
255
|
-
:param action: The action name for the binding.
|
|
256
|
-
:type action: str
|
|
257
|
-
"""
|
|
258
|
-
self.bind(EventType.MOUSEWHEEL, action=action, command=command)
|
|
259
|
-
|
|
260
|
-
def on_window_resized(
|
|
261
|
-
self, command: BaseCommand, action: str = "window_resized"
|
|
262
|
-
):
|
|
263
|
-
"""
|
|
264
|
-
Bind a command to window resized events.
|
|
265
|
-
|
|
266
|
-
:param command: The command to execute on window resize.
|
|
267
|
-
:type command: BaseCommand
|
|
268
|
-
|
|
269
|
-
:param action: The action name for the binding.
|
|
270
|
-
:type action: str
|
|
271
|
-
"""
|
|
272
|
-
self.bind(EventType.WINDOWRESIZED, action=action, command=command)
|
|
273
|
-
|
|
274
|
-
def on_text_input(self, command: BaseCommand, action: str = "text_input"):
|
|
275
|
-
"""
|
|
276
|
-
Bind a command to text input events.
|
|
277
|
-
|
|
278
|
-
:param command: The command to execute on text input.
|
|
279
|
-
:type command: BaseCommand
|
|
280
|
-
|
|
281
|
-
:param action: The action name for the binding.
|
|
282
|
-
:type action: str
|
|
283
|
-
"""
|
|
284
|
-
self.bind(EventType.TEXTINPUT, action=action, command=command)
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module providing runtime adapters for window and scene management.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from mini_arcade_core.runtime.context import RuntimeContext
|
|
8
|
-
from mini_arcade_core.runtime.scene.scene_port import (
|
|
9
|
-
SceneEntry,
|
|
10
|
-
ScenePolicy,
|
|
11
|
-
ScenePort,
|
|
12
|
-
StackItem,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SceneAdapter(ScenePort):
|
|
17
|
-
"""
|
|
18
|
-
Manages multiple scenes (not implemented).
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
def __init__(self, registry, game):
|
|
22
|
-
self._registry = registry
|
|
23
|
-
self._stack = []
|
|
24
|
-
self._game = game
|
|
25
|
-
|
|
26
|
-
@property
|
|
27
|
-
def current_scene(self):
|
|
28
|
-
return self._stack[-1].entry.scene if self._stack else None
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def visible_stack(self):
|
|
32
|
-
return [e.scene for e in self.visible_entries()]
|
|
33
|
-
|
|
34
|
-
def change(self, scene_id):
|
|
35
|
-
self.clean()
|
|
36
|
-
self.push(scene_id, as_overlay=False)
|
|
37
|
-
|
|
38
|
-
def push(
|
|
39
|
-
self,
|
|
40
|
-
scene_id,
|
|
41
|
-
*,
|
|
42
|
-
as_overlay=False,
|
|
43
|
-
policy=None,
|
|
44
|
-
):
|
|
45
|
-
# default policy based on overlay vs base
|
|
46
|
-
if policy is None:
|
|
47
|
-
# base scenes: do not block anything by default
|
|
48
|
-
policy = ScenePolicy()
|
|
49
|
-
runtime_context = RuntimeContext.from_game(self._game)
|
|
50
|
-
scene = self._registry.create(
|
|
51
|
-
scene_id, runtime_context
|
|
52
|
-
) # or whatever your factory call is
|
|
53
|
-
scene.on_enter()
|
|
54
|
-
|
|
55
|
-
entry = SceneEntry(
|
|
56
|
-
scene_id=scene_id,
|
|
57
|
-
scene=scene,
|
|
58
|
-
is_overlay=as_overlay,
|
|
59
|
-
policy=policy,
|
|
60
|
-
)
|
|
61
|
-
self._stack.append(StackItem(entry=entry))
|
|
62
|
-
|
|
63
|
-
def pop(self):
|
|
64
|
-
if not self._stack:
|
|
65
|
-
return
|
|
66
|
-
item = self._stack.pop()
|
|
67
|
-
item.entry.scene.on_exit()
|
|
68
|
-
|
|
69
|
-
def clean(self):
|
|
70
|
-
while self._stack:
|
|
71
|
-
self.pop()
|
|
72
|
-
|
|
73
|
-
def quit(self):
|
|
74
|
-
self._game.quit()
|
|
75
|
-
|
|
76
|
-
def visible_entries(self):
|
|
77
|
-
entries = [i.entry for i in self._stack]
|
|
78
|
-
# find highest opaque from top down; render starting there
|
|
79
|
-
for idx in range(len(entries) - 1, -1, -1):
|
|
80
|
-
if entries[idx].policy.is_opaque:
|
|
81
|
-
return entries[idx:]
|
|
82
|
-
return entries
|
|
83
|
-
|
|
84
|
-
def update_entries(self):
|
|
85
|
-
vis = self.visible_entries()
|
|
86
|
-
if not vis:
|
|
87
|
-
return []
|
|
88
|
-
out = []
|
|
89
|
-
for entry in reversed(vis): # top->down
|
|
90
|
-
out.append(entry)
|
|
91
|
-
if entry.policy.blocks_update:
|
|
92
|
-
break
|
|
93
|
-
return list(reversed(out)) # bottom->top order
|
|
94
|
-
|
|
95
|
-
def input_entry(self):
|
|
96
|
-
vis = self.visible_entries()
|
|
97
|
-
if not vis:
|
|
98
|
-
return None
|
|
99
|
-
|
|
100
|
-
# If some scene blocks input, only scenes at/above it can receive.
|
|
101
|
-
start_idx = 0
|
|
102
|
-
for idx in range(len(vis) - 1, -1, -1):
|
|
103
|
-
if vis[idx].policy.blocks_input:
|
|
104
|
-
start_idx = idx
|
|
105
|
-
break
|
|
106
|
-
|
|
107
|
-
candidates = vis[start_idx:]
|
|
108
|
-
|
|
109
|
-
# Pick the top-most candidate that actually receives input.
|
|
110
|
-
for entry in reversed(candidates):
|
|
111
|
-
if entry.policy.receives_input:
|
|
112
|
-
return entry
|
|
113
|
-
|
|
114
|
-
return None
|
|
115
|
-
|
|
116
|
-
def has_scene(self, scene_id: str) -> bool:
|
|
117
|
-
return any(item.entry.scene_id == scene_id for item in self._stack)
|
|
118
|
-
|
|
119
|
-
def remove_scene(self, scene_id: str):
|
|
120
|
-
# remove first match from top (overlay is usually near top)
|
|
121
|
-
for i in range(len(self._stack) - 1, -1, -1):
|
|
122
|
-
if self._stack[i].entry.scene_id == scene_id:
|
|
123
|
-
item = self._stack.pop(i)
|
|
124
|
-
item.entry.scene.on_exit()
|
|
125
|
-
return
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Service interfaces for runtime components.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from typing import TYPE_CHECKING, List
|
|
9
|
-
|
|
10
|
-
from mini_arcade_core.scenes.registry import SceneRegistry
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from mini_arcade_core.engine.game import Game
|
|
14
|
-
from mini_arcade_core.scenes.scene import Scene
|
|
15
|
-
from mini_arcade_core.sim.protocols import SimScene
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@dataclass(frozen=True)
|
|
19
|
-
class ScenePolicy:
|
|
20
|
-
"""
|
|
21
|
-
Controls how a scene behaves in the scene stack.
|
|
22
|
-
|
|
23
|
-
blocks_update: if True, scenes below do not tick/update (pause modal)
|
|
24
|
-
blocks_input: if True, scenes below do not receive input
|
|
25
|
-
is_opaque: if True, scenes below are not rendered
|
|
26
|
-
receives_input: if True, scene can receive input
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
blocks_update: bool = False
|
|
30
|
-
blocks_input: bool = False
|
|
31
|
-
is_opaque: bool = False
|
|
32
|
-
receives_input: bool = True
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@dataclass(frozen=True)
|
|
36
|
-
class SceneEntry:
|
|
37
|
-
"""
|
|
38
|
-
An entry in the scene stack.
|
|
39
|
-
|
|
40
|
-
:ivar scene_id (str): Identifier of the scene.
|
|
41
|
-
:ivar scene (Scene): The scene instance.
|
|
42
|
-
:ivar is_overlay (bool): Whether the scene is an overlay.
|
|
43
|
-
:ivar policy (ScenePolicy): The scene's policy.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
scene_id: str
|
|
47
|
-
scene: SimScene
|
|
48
|
-
is_overlay: bool
|
|
49
|
-
policy: ScenePolicy
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@dataclass
|
|
53
|
-
class StackItem:
|
|
54
|
-
"""
|
|
55
|
-
An item in the scene stack.
|
|
56
|
-
|
|
57
|
-
:ivar entry (SceneEntry): The scene entry.
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
entry: SceneEntry
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class ScenePort:
|
|
64
|
-
"""Interface for scene management operations."""
|
|
65
|
-
|
|
66
|
-
_registry: SceneRegistry
|
|
67
|
-
_stack: List[StackItem]
|
|
68
|
-
_game: Game
|
|
69
|
-
|
|
70
|
-
@property
|
|
71
|
-
def current_scene(self) -> "SimScene | None":
|
|
72
|
-
"""
|
|
73
|
-
Get the currently active scene.
|
|
74
|
-
|
|
75
|
-
:return: The active Scene instance, or None if no scene is active.
|
|
76
|
-
:rtype: SimScene | None
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
@property
|
|
80
|
-
def visible_stack(self) -> List["SimScene"]:
|
|
81
|
-
"""
|
|
82
|
-
Return the list of scenes that should be drawn (base + overlays).
|
|
83
|
-
We draw from the top-most non-overlay scene upward.
|
|
84
|
-
|
|
85
|
-
:return: List of visible Scene instances.
|
|
86
|
-
:rtype: List[SimScene]
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
def change(self, scene_id: str):
|
|
90
|
-
"""
|
|
91
|
-
Change the current scene to the specified scene.
|
|
92
|
-
|
|
93
|
-
:param scene_id: Identifier of the scene to switch to.
|
|
94
|
-
:type scene_id: str
|
|
95
|
-
"""
|
|
96
|
-
|
|
97
|
-
def push(self, scene_id: str, *, as_overlay: bool = False):
|
|
98
|
-
"""
|
|
99
|
-
Push a new scene onto the scene stack.
|
|
100
|
-
|
|
101
|
-
:param scene_id: Identifier of the scene to push.
|
|
102
|
-
:type scene_id: str
|
|
103
|
-
|
|
104
|
-
:param as_overlay: Whether to push the scene as an overlay.
|
|
105
|
-
:type as_overlay: bool
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
def pop(self) -> "Scene | None":
|
|
109
|
-
"""
|
|
110
|
-
Pop the current scene from the scene stack.
|
|
111
|
-
|
|
112
|
-
:return: The popped Scene instance, or None if the stack was empty.
|
|
113
|
-
:rtype: Scene | None
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
def clean(self):
|
|
117
|
-
"""
|
|
118
|
-
Clean up all scenes from the scene stack.
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
def quit(self):
|
|
122
|
-
"""
|
|
123
|
-
Quit the game
|
|
124
|
-
"""
|
|
125
|
-
|
|
126
|
-
def visible_entries(self) -> list[SceneEntry]:
|
|
127
|
-
"""
|
|
128
|
-
Render from bottom->top unless an opaque entry exists; if so,
|
|
129
|
-
render only from that entry up.
|
|
130
|
-
|
|
131
|
-
:return: List of SceneEntry instances to render.
|
|
132
|
-
:rtype: list[SceneEntry]
|
|
133
|
-
"""
|
|
134
|
-
|
|
135
|
-
def update_entries(self) -> list[SceneEntry]:
|
|
136
|
-
"""
|
|
137
|
-
Tick/update scenes considering blocks_update.
|
|
138
|
-
Typical: pause overlay blocks update below it.
|
|
139
|
-
|
|
140
|
-
:return: List of SceneEntry instances to update.
|
|
141
|
-
:rtype: list[SceneEntry]
|
|
142
|
-
"""
|
|
143
|
-
|
|
144
|
-
def input_entry(self) -> SceneEntry | None:
|
|
145
|
-
"""
|
|
146
|
-
Who gets input this frame. If top blocks_input, only it receives input.
|
|
147
|
-
If not, top still gets input (v1 simple). Later you can allow fall-through.
|
|
148
|
-
|
|
149
|
-
:return: The SceneEntry that receives input, or None if no scenes are active.
|
|
150
|
-
:rtype: SceneEntry | None
|
|
151
|
-
"""
|
|
152
|
-
|
|
153
|
-
def has_scene(self, scene_id: str) -> bool:
|
|
154
|
-
"""
|
|
155
|
-
Check if a scene with the given ID exists in the stack.
|
|
156
|
-
|
|
157
|
-
:param scene_id: Identifier of the scene to check.
|
|
158
|
-
:type scene_id: str
|
|
159
|
-
|
|
160
|
-
:return: True if the scene exists in the stack, False otherwise.
|
|
161
|
-
:rtype: bool
|
|
162
|
-
"""
|
|
163
|
-
|
|
164
|
-
def remove_scene(self, scene_id: str):
|
|
165
|
-
"""
|
|
166
|
-
Remove a scene with the given ID from the stack.
|
|
167
|
-
|
|
168
|
-
:param scene_id: Identifier of the scene to remove.
|
|
169
|
-
:type scene_id: str
|
|
170
|
-
"""
|