esper 3.1__tar.gz → 3.2__tar.gz
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.
- esper-3.2/.github/workflows/type-checking.yml +25 -0
- {esper-3.1 → esper-3.2}/.github/workflows/unit-tests.yml +1 -18
- {esper-3.1 → esper-3.2}/.mypy.ini +2 -2
- {esper-3.1 → esper-3.2}/PKG-INFO +35 -30
- {esper-3.1 → esper-3.2}/README.md +34 -29
- {esper-3.1 → esper-3.2}/RELEASE_NOTES +10 -0
- {esper-3.1 → esper-3.2}/esper/__init__.py +39 -36
- {esper-3.1 → esper-3.2}/tests/test_world.py +34 -2
- {esper-3.1 → esper-3.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {esper-3.1 → esper-3.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {esper-3.1 → esper-3.2}/.github/ISSUE_TEMPLATE/question-or-comment.md +0 -0
- {esper-3.1 → esper-3.2}/.gitignore +0 -0
- {esper-3.1 → esper-3.2}/.readthedocs.yaml +0 -0
- {esper-3.1 → esper-3.2}/.ruff.toml +0 -0
- {esper-3.1 → esper-3.2}/LICENSE +0 -0
- {esper-3.1 → esper-3.2}/MANIFEST.in +0 -0
- {esper-3.1 → esper-3.2}/docs/Makefile +0 -0
- {esper-3.1 → esper-3.2}/docs/conf.py +0 -0
- {esper-3.1 → esper-3.2}/docs/index.rst +0 -0
- {esper-3.1 → esper-3.2}/docs/make.bat +0 -0
- {esper-3.1 → esper-3.2}/esper/py.typed +0 -0
- {esper-3.1 → esper-3.2}/examples/benchmark.py +0 -0
- {esper-3.1 → esper-3.2}/examples/benchmark_cache.py +0 -0
- {esper-3.1 → esper-3.2}/examples/bluesquare.png +0 -0
- {esper-3.1 → esper-3.2}/examples/headless_example.py +0 -0
- {esper-3.1 → esper-3.2}/examples/pygame_example.py +0 -0
- {esper-3.1 → esper-3.2}/examples/pyglet_example.py +0 -0
- {esper-3.1 → esper-3.2}/examples/pyglet_example_batch.py +0 -0
- {esper-3.1 → esper-3.2}/examples/pysdl2_example.py +0 -0
- {esper-3.1 → esper-3.2}/examples/pythonista_ios_example.py +0 -0
- {esper-3.1 → esper-3.2}/examples/redsquare.png +0 -0
- {esper-3.1 → esper-3.2}/make.py +0 -0
- {esper-3.1 → esper-3.2}/pyproject.toml +0 -0
- {esper-3.1 → esper-3.2}/tests/__init__.py +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: type checking
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
typechecking:
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
|
|
14
|
+
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12-dev' ]
|
|
15
|
+
steps:
|
|
16
|
+
- name: Python ${{ matrix.python-version }} ${{ matrix.os }}
|
|
17
|
+
uses: actions/checkout@v3
|
|
18
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
+
uses: actions/setup-python@v4
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- name: Install mypy
|
|
23
|
+
run: pip install mypy
|
|
24
|
+
- name: Run mypy
|
|
25
|
+
run: mypy -v esper
|
|
@@ -11,7 +11,7 @@ jobs:
|
|
|
11
11
|
strategy:
|
|
12
12
|
matrix:
|
|
13
13
|
os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
|
|
14
|
-
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.
|
|
14
|
+
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.10' ]
|
|
15
15
|
steps:
|
|
16
16
|
- name: Python ${{ matrix.python-version }} ${{ matrix.os }}
|
|
17
17
|
uses: actions/checkout@v3
|
|
@@ -23,20 +23,3 @@ jobs:
|
|
|
23
23
|
run: pip install pytest
|
|
24
24
|
- name: Run tests
|
|
25
25
|
run: pytest -v tests
|
|
26
|
-
typechecking:
|
|
27
|
-
runs-on: ${{ matrix.os }}
|
|
28
|
-
strategy:
|
|
29
|
-
matrix:
|
|
30
|
-
os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
|
|
31
|
-
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12-dev' ]
|
|
32
|
-
steps:
|
|
33
|
-
- name: Python ${{ matrix.python-version }} ${{ matrix.os }}
|
|
34
|
-
uses: actions/checkout@v3
|
|
35
|
-
- name: Set up Python ${{ matrix.python-version }}
|
|
36
|
-
uses: actions/setup-python@v4
|
|
37
|
-
with:
|
|
38
|
-
python-version: ${{ matrix.python-version }}
|
|
39
|
-
- name: Install mypy
|
|
40
|
-
run: pip install mypy
|
|
41
|
-
- name: Run mypy
|
|
42
|
-
run: mypy -v esper
|
|
@@ -10,11 +10,11 @@ warn_unused_ignores = True
|
|
|
10
10
|
warn_return_any = True
|
|
11
11
|
no_implicit_reexport = True
|
|
12
12
|
strict_equality = True
|
|
13
|
-
|
|
13
|
+
extra_checks = True
|
|
14
14
|
|
|
15
15
|
[mypy-esper]
|
|
16
16
|
disallow_untyped_defs = True
|
|
17
17
|
disallow_untyped_calls = True
|
|
18
18
|
|
|
19
19
|
[mypy-tests]
|
|
20
|
-
check_untyped_defs = True
|
|
20
|
+
check_untyped_defs = True
|
{esper-3.1 → esper-3.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: esper
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2
|
|
4
4
|
Summary: esper is a lightweight Entity System (ECS) for Python, with a focus on performance
|
|
5
5
|
Author-email: Benjamin Moran <benmoran@protonmail.com>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -16,11 +16,14 @@ Esper is a lightweight Entity System module for Python, with a focus on performa
|
|
|
16
16
|
===================================================================================
|
|
17
17
|
|
|
18
18
|
Esper is an MIT licensed Entity System, or, Entity Component System (ECS).
|
|
19
|
-
The design is based on the Entity System concepts
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
The design is based on the Entity System concepts originally popularized by
|
|
20
|
+
Adam Martin and others. The primary focus for esper is to maximize perfomance,
|
|
21
|
+
while handling most common use cases.
|
|
22
|
+
|
|
23
|
+
For more information on the ECS pattern, you might find the following
|
|
24
|
+
resources interesting:
|
|
25
|
+
https://github.com/SanderMertens/ecs-faq/blob/master/README.md
|
|
26
|
+
https://github.com/jslee02/awesome-entity-component-system/blob/master/README.md
|
|
24
27
|
https://en.wikipedia.org/wiki/Entity_component_system
|
|
25
28
|
|
|
26
29
|
API documentation is hosted at ReadTheDocs: https://esper.readthedocs.io
|
|
@@ -48,22 +51,22 @@ documentation.
|
|
|
48
51
|
|
|
49
52
|
Compatibility
|
|
50
53
|
=============
|
|
51
|
-
Esper attempts to target all currently supported Python releases (
|
|
52
|
-
100% pure Python, so *any* compliant interpreter should work.
|
|
53
|
-
done for both CPython and PyPy3.
|
|
54
|
+
Esper attempts to target all currently supported Python releases (any Python version that is
|
|
55
|
+
not EOL). Esper is written in 100% pure Python, so *any* compliant interpreter should work.
|
|
56
|
+
Automated testing is currently done for both CPython and PyPy3.
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
Installation
|
|
57
60
|
============
|
|
58
|
-
Esper is a pure Python package with no dependencies, so installation is
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
Esper is a pure Python package with no dependencies, so installation is flexible.
|
|
62
|
+
You can simply copy the *esper* folder right into your project, and *import esper*.
|
|
63
|
+
You can also install into your site-packages from PyPi via `pip`::
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
pip install --user --upgrade esper
|
|
63
66
|
|
|
64
|
-
Or from
|
|
67
|
+
Or from the source directory::
|
|
65
68
|
|
|
66
|
-
pip install --user
|
|
69
|
+
pip install . --user
|
|
67
70
|
|
|
68
71
|
|
|
69
72
|
Design
|
|
@@ -71,8 +74,8 @@ Design
|
|
|
71
74
|
|
|
72
75
|
* World Context
|
|
73
76
|
|
|
74
|
-
Esper uses the concept of "World" contexts. When you import esper
|
|
75
|
-
You create Entities, assign Components, register Processesors, etc., by calling functions
|
|
77
|
+
Esper uses the concept of "World" contexts. When you first `import esper`, a default context is
|
|
78
|
+
active. You create Entities, assign Components, register Processesors, etc., by calling functions
|
|
76
79
|
on the `esper` module. Entities, Components and Processors can be created, assigned, or deleted
|
|
77
80
|
while your game is running. A simple call to `esper.process()` is all that's needed for each
|
|
78
81
|
iteration of your game loop. Advanced users can switch contexts, which can be useful for
|
|
@@ -91,14 +94,15 @@ Creating an Entity is done with the `esper.create_entity()` function.
|
|
|
91
94
|
|
|
92
95
|
Components are defined as simple Python classes. In keeping with a pure Entity System
|
|
93
96
|
design philosophy, they should not contain any logic. They might have initialization
|
|
94
|
-
code, but no processing logic whatsoever. A simple
|
|
97
|
+
code or perhaps Python properties, but no processing logic whatsoever. A simple
|
|
98
|
+
Component can be defined as::
|
|
95
99
|
|
|
96
100
|
class Position:
|
|
97
101
|
def __init__(self, x=0.0, y=0.0):
|
|
98
102
|
self.x = x
|
|
99
103
|
self.y = y
|
|
100
104
|
|
|
101
|
-
|
|
105
|
+
To save on typing, the standard library dataclass decorator is quite useful.
|
|
102
106
|
https://docs.python.org/3/library/dataclasses.html#module-dataclasses
|
|
103
107
|
This decorator simplifies defining your Component classes. The attribute names don't need to
|
|
104
108
|
be repeated, and you can still instantiate the Component with positional or keyword arguments::
|
|
@@ -190,19 +194,20 @@ General Usage
|
|
|
190
194
|
World Contexts
|
|
191
195
|
--------------
|
|
192
196
|
Esper has the capability of supporting multiple "World" contexts. On import, a "default" World is
|
|
193
|
-
active. All creation of Entities, assignment of Processors, and all operations
|
|
194
|
-
confines of
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
active. All creation of Entities, assignment of Processors, and all other operations occur within
|
|
198
|
+
the confines of the active World. In other words, the World contexts are completely isolated from
|
|
199
|
+
each other. For basic games and designs, you may not need to bother with this functionality. A
|
|
200
|
+
single default World context can often be enough. For advanced use cases, such as when different
|
|
201
|
+
scenes in your game have different Entities and Processor requirements, this functionality can be
|
|
202
|
+
quite useful. World context operations are done with the following functions::
|
|
203
|
+
*
|
|
199
204
|
* esper.list_worlds()
|
|
200
205
|
* esper.switch_world(name)
|
|
201
206
|
* esper.delete_world(name)
|
|
202
207
|
|
|
203
|
-
When switching Worlds, be
|
|
204
|
-
You can delete old Worlds
|
|
205
|
-
World.
|
|
208
|
+
When switching Worlds, be mindful of the `name`. If a World doesn't exist, it will be created when
|
|
209
|
+
you first switch to it. You can delete old Worlds if they are no longer needed, but you can not
|
|
210
|
+
delete the currently active World.
|
|
206
211
|
|
|
207
212
|
Adding and Removing Processors
|
|
208
213
|
------------------------------
|
|
@@ -396,8 +401,8 @@ Contributions to Esper are always welcome, but there are some specific project g
|
|
|
396
401
|
|
|
397
402
|
- Pure Python code only: no binary extensions, Cython, etc.
|
|
398
403
|
- Try to target all non-EOL Python versions. Exceptions can be made if there is a compelling reason.
|
|
399
|
-
- Avoid bloat as much as possible. New features will be considered if they are commonly useful. Generally speaking, we don't want to add functionality that is better
|
|
400
|
-
- Performance is preferrable to readability.
|
|
404
|
+
- Avoid bloat as much as possible. New features will be considered if they are commonly useful. Generally speaking, we don't want to add functionality that is better served by another module or library.
|
|
405
|
+
- Performance is preferrable to readability. The public API should remain clean, but ugly internal code is acceptable if it provides a performance benefit. Every cycle counts!
|
|
401
406
|
|
|
402
407
|
If you have any questions before contributing, feel free to [open an issue].
|
|
403
408
|
|
|
@@ -6,11 +6,14 @@ Esper is a lightweight Entity System module for Python, with a focus on performa
|
|
|
6
6
|
===================================================================================
|
|
7
7
|
|
|
8
8
|
Esper is an MIT licensed Entity System, or, Entity Component System (ECS).
|
|
9
|
-
The design is based on the Entity System concepts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
The design is based on the Entity System concepts originally popularized by
|
|
10
|
+
Adam Martin and others. The primary focus for esper is to maximize perfomance,
|
|
11
|
+
while handling most common use cases.
|
|
12
|
+
|
|
13
|
+
For more information on the ECS pattern, you might find the following
|
|
14
|
+
resources interesting:
|
|
15
|
+
https://github.com/SanderMertens/ecs-faq/blob/master/README.md
|
|
16
|
+
https://github.com/jslee02/awesome-entity-component-system/blob/master/README.md
|
|
14
17
|
https://en.wikipedia.org/wiki/Entity_component_system
|
|
15
18
|
|
|
16
19
|
API documentation is hosted at ReadTheDocs: https://esper.readthedocs.io
|
|
@@ -38,22 +41,22 @@ documentation.
|
|
|
38
41
|
|
|
39
42
|
Compatibility
|
|
40
43
|
=============
|
|
41
|
-
Esper attempts to target all currently supported Python releases (
|
|
42
|
-
100% pure Python, so *any* compliant interpreter should work.
|
|
43
|
-
done for both CPython and PyPy3.
|
|
44
|
+
Esper attempts to target all currently supported Python releases (any Python version that is
|
|
45
|
+
not EOL). Esper is written in 100% pure Python, so *any* compliant interpreter should work.
|
|
46
|
+
Automated testing is currently done for both CPython and PyPy3.
|
|
44
47
|
|
|
45
48
|
|
|
46
49
|
Installation
|
|
47
50
|
============
|
|
48
|
-
Esper is a pure Python package with no dependencies, so installation is
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
Esper is a pure Python package with no dependencies, so installation is flexible.
|
|
52
|
+
You can simply copy the *esper* folder right into your project, and *import esper*.
|
|
53
|
+
You can also install into your site-packages from PyPi via `pip`::
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
pip install --user --upgrade esper
|
|
53
56
|
|
|
54
|
-
Or from
|
|
57
|
+
Or from the source directory::
|
|
55
58
|
|
|
56
|
-
pip install --user
|
|
59
|
+
pip install . --user
|
|
57
60
|
|
|
58
61
|
|
|
59
62
|
Design
|
|
@@ -61,8 +64,8 @@ Design
|
|
|
61
64
|
|
|
62
65
|
* World Context
|
|
63
66
|
|
|
64
|
-
Esper uses the concept of "World" contexts. When you import esper
|
|
65
|
-
You create Entities, assign Components, register Processesors, etc., by calling functions
|
|
67
|
+
Esper uses the concept of "World" contexts. When you first `import esper`, a default context is
|
|
68
|
+
active. You create Entities, assign Components, register Processesors, etc., by calling functions
|
|
66
69
|
on the `esper` module. Entities, Components and Processors can be created, assigned, or deleted
|
|
67
70
|
while your game is running. A simple call to `esper.process()` is all that's needed for each
|
|
68
71
|
iteration of your game loop. Advanced users can switch contexts, which can be useful for
|
|
@@ -81,14 +84,15 @@ Creating an Entity is done with the `esper.create_entity()` function.
|
|
|
81
84
|
|
|
82
85
|
Components are defined as simple Python classes. In keeping with a pure Entity System
|
|
83
86
|
design philosophy, they should not contain any logic. They might have initialization
|
|
84
|
-
code, but no processing logic whatsoever. A simple
|
|
87
|
+
code or perhaps Python properties, but no processing logic whatsoever. A simple
|
|
88
|
+
Component can be defined as::
|
|
85
89
|
|
|
86
90
|
class Position:
|
|
87
91
|
def __init__(self, x=0.0, y=0.0):
|
|
88
92
|
self.x = x
|
|
89
93
|
self.y = y
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
To save on typing, the standard library dataclass decorator is quite useful.
|
|
92
96
|
https://docs.python.org/3/library/dataclasses.html#module-dataclasses
|
|
93
97
|
This decorator simplifies defining your Component classes. The attribute names don't need to
|
|
94
98
|
be repeated, and you can still instantiate the Component with positional or keyword arguments::
|
|
@@ -180,19 +184,20 @@ General Usage
|
|
|
180
184
|
World Contexts
|
|
181
185
|
--------------
|
|
182
186
|
Esper has the capability of supporting multiple "World" contexts. On import, a "default" World is
|
|
183
|
-
active. All creation of Entities, assignment of Processors, and all operations
|
|
184
|
-
confines of
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
active. All creation of Entities, assignment of Processors, and all other operations occur within
|
|
188
|
+
the confines of the active World. In other words, the World contexts are completely isolated from
|
|
189
|
+
each other. For basic games and designs, you may not need to bother with this functionality. A
|
|
190
|
+
single default World context can often be enough. For advanced use cases, such as when different
|
|
191
|
+
scenes in your game have different Entities and Processor requirements, this functionality can be
|
|
192
|
+
quite useful. World context operations are done with the following functions::
|
|
193
|
+
*
|
|
189
194
|
* esper.list_worlds()
|
|
190
195
|
* esper.switch_world(name)
|
|
191
196
|
* esper.delete_world(name)
|
|
192
197
|
|
|
193
|
-
When switching Worlds, be
|
|
194
|
-
You can delete old Worlds
|
|
195
|
-
World.
|
|
198
|
+
When switching Worlds, be mindful of the `name`. If a World doesn't exist, it will be created when
|
|
199
|
+
you first switch to it. You can delete old Worlds if they are no longer needed, but you can not
|
|
200
|
+
delete the currently active World.
|
|
196
201
|
|
|
197
202
|
Adding and Removing Processors
|
|
198
203
|
------------------------------
|
|
@@ -386,8 +391,8 @@ Contributions to Esper are always welcome, but there are some specific project g
|
|
|
386
391
|
|
|
387
392
|
- Pure Python code only: no binary extensions, Cython, etc.
|
|
388
393
|
- Try to target all non-EOL Python versions. Exceptions can be made if there is a compelling reason.
|
|
389
|
-
- Avoid bloat as much as possible. New features will be considered if they are commonly useful. Generally speaking, we don't want to add functionality that is better
|
|
390
|
-
- Performance is preferrable to readability.
|
|
394
|
+
- Avoid bloat as much as possible. New features will be considered if they are commonly useful. Generally speaking, we don't want to add functionality that is better served by another module or library.
|
|
395
|
+
- Performance is preferrable to readability. The public API should remain clean, but ugly internal code is acceptable if it provides a performance benefit. Every cycle counts!
|
|
391
396
|
|
|
392
397
|
If you have any questions before contributing, feel free to [open an issue].
|
|
393
398
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
esper 3.2
|
|
2
|
+
=========
|
|
3
|
+
Maintenance release
|
|
4
|
+
|
|
5
|
+
Changes
|
|
6
|
+
-------
|
|
7
|
+
- Add `esper.current_world` property to easily check the current World context.
|
|
8
|
+
- Made some minor docstring corrections, and added some programmer notes.
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
esper 3.1
|
|
2
12
|
=========
|
|
3
13
|
Maintenance release
|
|
@@ -23,9 +23,7 @@ from weakref import WeakMethod as _WeakMethod
|
|
|
23
23
|
|
|
24
24
|
from itertools import count as _count
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
version = '3.1'
|
|
28
|
-
__version__ = version
|
|
26
|
+
__version__ = version = '3.2'
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
###################
|
|
@@ -50,6 +48,7 @@ def dispatch_event(name: str, *args: _Any) -> None:
|
|
|
50
48
|
|
|
51
49
|
def _make_callback(name: str) -> _Callable[[_Any], None]:
|
|
52
50
|
"""Create an internal callback to remove dead handlers."""
|
|
51
|
+
|
|
53
52
|
def callback(weak_method: _Any) -> None:
|
|
54
53
|
event_registry[name].remove(weak_method)
|
|
55
54
|
if not event_registry[name]:
|
|
@@ -106,23 +105,19 @@ class Processor:
|
|
|
106
105
|
|
|
107
106
|
Processor instances must contain a `process` method, but you are otherwise
|
|
108
107
|
free to define the class any way you wish. Processors should be instantiated,
|
|
109
|
-
and then added to
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
my_world = World()
|
|
108
|
+
and then added to the current World context by calling :py:func:`esper.add_processor`.
|
|
109
|
+
For example::
|
|
113
110
|
|
|
114
111
|
my_processor_instance = MyProcessor()
|
|
115
|
-
|
|
112
|
+
esper.add_processor(my_processor_instance)
|
|
116
113
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
so you will generally want to iterate over entities with one (or more) calls to
|
|
122
|
-
the appropriate world methods::
|
|
114
|
+
All the Processors that have been added to the World context will have their
|
|
115
|
+
:py:meth:`esper.Processor.process` methods called by a single call to
|
|
116
|
+
:py:func:`esper.process`. Inside the `process` method is generally where you
|
|
117
|
+
should iterate over Entities with one (or more) calls to the appropriate methods::
|
|
123
118
|
|
|
124
119
|
def process(self):
|
|
125
|
-
for ent, (rend, vel) in
|
|
120
|
+
for ent, (rend, vel) in esper.get_components(Renderable, Velocity):
|
|
126
121
|
your_code_here()
|
|
127
122
|
"""
|
|
128
123
|
|
|
@@ -132,7 +127,6 @@ class Processor:
|
|
|
132
127
|
raise NotImplementedError
|
|
133
128
|
|
|
134
129
|
|
|
135
|
-
|
|
136
130
|
###################
|
|
137
131
|
# ECS functions
|
|
138
132
|
###################
|
|
@@ -506,34 +500,33 @@ def process(*args: _Any, **kwargs: _Any) -> None:
|
|
|
506
500
|
def timed_process(*args: _Any, **kwargs: _Any) -> None:
|
|
507
501
|
"""Track Processor execution time for benchmarking.
|
|
508
502
|
|
|
509
|
-
This function is identical to :py:func:`esper.process`,
|
|
510
|
-
|
|
511
|
-
|
|
503
|
+
This function is identical to :py:func:`esper.process`, but
|
|
504
|
+
it additionally records the elapsed time of each processor
|
|
505
|
+
call (in milliseconds) in the`esper.process_times` dictionary.
|
|
512
506
|
"""
|
|
513
507
|
clear_dead_entities()
|
|
514
508
|
for processor in _processors:
|
|
515
509
|
start_time = _time.process_time()
|
|
516
510
|
processor.process(*args, **kwargs)
|
|
517
|
-
|
|
518
|
-
process_times[processor.__class__.__name__] = process_time
|
|
511
|
+
process_times[processor.__class__.__name__] = int((_time.process_time() - start_time) * 1000)
|
|
519
512
|
|
|
520
513
|
|
|
521
514
|
def list_worlds() -> _List[str]:
|
|
522
515
|
"""A list all World context names."""
|
|
523
|
-
return list(_context_map
|
|
516
|
+
return list(_context_map)
|
|
524
517
|
|
|
525
518
|
|
|
526
519
|
def delete_world(name: str) -> None:
|
|
527
520
|
"""Delete a World context.
|
|
528
521
|
|
|
529
|
-
This will completely delete the World, including
|
|
522
|
+
This will completely delete the World, including all entities
|
|
530
523
|
that are contained within it.
|
|
531
524
|
|
|
532
|
-
Raises
|
|
525
|
+
Raises `PermissionError` if you attempt to delete the currently
|
|
533
526
|
active World context.
|
|
534
527
|
"""
|
|
535
528
|
if _current_context == name:
|
|
536
|
-
raise
|
|
529
|
+
raise PermissionError("The active World context cannot be deleted.")
|
|
537
530
|
|
|
538
531
|
del _context_map[name]
|
|
539
532
|
|
|
@@ -542,19 +535,19 @@ def switch_world(name: str) -> None:
|
|
|
542
535
|
"""Switch to a new World context by name.
|
|
543
536
|
|
|
544
537
|
Esper can have one or more "Worlds". Each World is a dedicated
|
|
545
|
-
context, and does not share Entities, Components, etc.
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
be sufficient.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
538
|
+
context, and does not share Entities, Components, events, etc.
|
|
539
|
+
Some game designs can benefit from using a dedicated World
|
|
540
|
+
for each scene. For other designs, a single World may
|
|
541
|
+
be sufficient.
|
|
542
|
+
|
|
543
|
+
This function will allow you to create and switch between as
|
|
544
|
+
many World contexts as required. If the requested name does not
|
|
545
|
+
exist, a new context is created automatically with that name.
|
|
546
|
+
|
|
547
|
+
.. note:: At startup, a "default" World context is active.
|
|
555
548
|
"""
|
|
556
549
|
if name not in _context_map:
|
|
557
|
-
# Create a new
|
|
550
|
+
# Create a new context if the name does not already exist:
|
|
558
551
|
_context_map[name] = (_count(start=1), {}, {}, set(), {}, {}, [], {}, {})
|
|
559
552
|
|
|
560
553
|
global _current_context
|
|
@@ -568,6 +561,16 @@ def switch_world(name: str) -> None:
|
|
|
568
561
|
global process_times
|
|
569
562
|
global event_registry
|
|
570
563
|
|
|
564
|
+
# switch the references to the objects in the named context_map:
|
|
571
565
|
(_entity_count, _components, _entities, _dead_entities, _get_component_cache,
|
|
572
566
|
_get_components_cache, _processors, process_times, event_registry) = _context_map[name]
|
|
573
567
|
_current_context = name
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
@property # type: ignore
|
|
571
|
+
def current_world() -> str:
|
|
572
|
+
"""The currently active World context.
|
|
573
|
+
|
|
574
|
+
To switch World contexts, see :py:func:`esper.switch_world`.
|
|
575
|
+
"""
|
|
576
|
+
return _current_context
|
|
@@ -275,14 +275,24 @@ def test_clear_dead_entities():
|
|
|
275
275
|
|
|
276
276
|
|
|
277
277
|
def test_switch_world():
|
|
278
|
+
# The `create_entities` helper will add <number>/2 of
|
|
279
|
+
# 'ComponentA' to the World context. Make a new
|
|
280
|
+
# "left" context, and confirm this is True:
|
|
278
281
|
esper.switch_world("left")
|
|
279
282
|
assert len(esper.get_component(ComponentA)) == 0
|
|
280
283
|
create_entities(200)
|
|
281
284
|
assert len(esper.get_component(ComponentA)) == 100
|
|
285
|
+
|
|
286
|
+
# Switching to a new "right" World context, no
|
|
287
|
+
# 'ComponentA' Components should yet exist.
|
|
282
288
|
esper.switch_world("right")
|
|
283
289
|
assert len(esper.get_component(ComponentA)) == 0
|
|
284
290
|
create_entities(300)
|
|
285
291
|
assert len(esper.get_component(ComponentA)) == 150
|
|
292
|
+
|
|
293
|
+
# Switching back to the original "left" context,
|
|
294
|
+
# the original 100 Components should still exist.
|
|
295
|
+
# From there, 200 more should be added:
|
|
286
296
|
esper.switch_world("left")
|
|
287
297
|
assert len(esper.get_component(ComponentA)) == 100
|
|
288
298
|
create_entities(400)
|
|
@@ -293,6 +303,16 @@ def test_switch_world():
|
|
|
293
303
|
# Some helper functions and Component templates:
|
|
294
304
|
##################################################
|
|
295
305
|
def create_entities(number):
|
|
306
|
+
"""This function will create X number of entities.
|
|
307
|
+
|
|
308
|
+
The entities are created with a mix of Components,
|
|
309
|
+
so the World context will see an addition of
|
|
310
|
+
ComponentA * number * 1
|
|
311
|
+
ComponentB * number * 1
|
|
312
|
+
ComponentC * number * 2
|
|
313
|
+
ComponentD * number * 1
|
|
314
|
+
ComponentE * number * 1
|
|
315
|
+
"""
|
|
296
316
|
for _ in range(number // 2):
|
|
297
317
|
esper.create_entity(ComponentA(), ComponentB(), ComponentC())
|
|
298
318
|
esper.create_entity(ComponentC(), ComponentD(), ComponentE())
|
|
@@ -459,17 +479,29 @@ def test_event_handler_switch_world():
|
|
|
459
479
|
def handler():
|
|
460
480
|
nonlocal called
|
|
461
481
|
called += 1
|
|
482
|
+
|
|
483
|
+
# Switch to a new "left" World context, and register
|
|
484
|
+
# an event handler. Confirm that it is being called
|
|
485
|
+
# by checking that the 'called' variable is incremented.
|
|
462
486
|
esper.switch_world("left")
|
|
463
487
|
esper.set_handler("foo", handler)
|
|
464
488
|
assert called == 0
|
|
465
489
|
esper.dispatch_event("foo")
|
|
466
490
|
assert called == 1
|
|
491
|
+
|
|
492
|
+
# Here we switch to a new "right" World context.
|
|
493
|
+
# The handler is registered to the "left" context only,
|
|
494
|
+
# so dispatching the event should have no effect. The
|
|
495
|
+
# handler is not attached, and so the 'called' value
|
|
496
|
+
# should not be incremented further.
|
|
467
497
|
esper.switch_world("right")
|
|
468
|
-
assert called == 1
|
|
469
498
|
esper.dispatch_event("foo")
|
|
470
499
|
assert called == 1
|
|
500
|
+
|
|
501
|
+
# Switching back to the "left" context and dispatching
|
|
502
|
+
# the event, the handler should still be registered and
|
|
503
|
+
# the 'called' variable should be incremented by 1.
|
|
471
504
|
esper.switch_world("left")
|
|
472
|
-
assert called == 1
|
|
473
505
|
esper.dispatch_event("foo")
|
|
474
506
|
assert called == 2
|
|
475
507
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{esper-3.1 → esper-3.2}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{esper-3.1 → esper-3.2}/make.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|