pumpkin-api-py 0.1.0.dev0__tar.gz → 0.1.0.dev2__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.
- {pumpkin_api_py-0.1.0.dev0 → pumpkin_api_py-0.1.0.dev2}/PKG-INFO +9 -16
- {pumpkin_api_py-0.1.0.dev0 → pumpkin_api_py-0.1.0.dev2}/README.md +8 -15
- pumpkin_api_py-0.1.0.dev2/hatch_build.py +28 -0
- pumpkin_api_py-0.1.0.dev2/pyproject.toml +35 -0
- pumpkin_api_py-0.1.0.dev2/src/pumpkin_api/__init__.py +41 -0
- pumpkin_api_py-0.1.0.dev2/src/pumpkin_api/build.py +69 -0
- pumpkin_api_py-0.1.0.dev2/src/pumpkin_api/impl.py +216 -0
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/entity.wit → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1/block-entity.wit +2 -2
- pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1/boss-bar.wit +82 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/command.wit +3 -2
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/common.wit +22 -0
- pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1/entity.wit +3 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/event.wit +8 -1
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/gui.wit +12 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/metadata.wit +2 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/player.wit +16 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/plugin.wit +7 -4
- pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1/server.wit +86 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/world.wit +42 -1
- pumpkin_api_py-0.1.0.dev0/example/main.py +0 -36
- pumpkin_api_py-0.1.0.dev0/pyproject.toml +0 -22
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/__init__.py +0 -139
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/app.py +0 -8
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/build.py +0 -35
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/componentize_py_async_support/__init__.py +0 -529
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/componentize_py_async_support/futures.py +0 -93
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/componentize_py_async_support/streams.py +0 -189
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/componentize_py_runtime.pyi +0 -34
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/componentize_py_types.py +0 -19
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/poll_loop.py +0 -440
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/__init__.py +0 -70
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/exports/__init__.py +0 -19
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/exports/metadata.py +0 -22
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/__init__.py +0 -0
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/command.py +0 -539
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/common.py +0 -213
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/context.py +0 -70
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/entity.py +0 -84
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/event.py +0 -434
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/gui.py +0 -61
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/i18n.py +0 -35
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/logging.py +0 -30
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/permission.py +0 -71
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/player.py +0 -350
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/scheduler.py +0 -44
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/scoreboard.py +0 -95
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/server.py +0 -75
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/text.py +0 -89
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit/wit_world/imports/world.py +0 -215
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/componentize_py_async_support/__init__.py +0 -529
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/componentize_py_async_support/futures.py +0 -93
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/componentize_py_async_support/streams.py +0 -189
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/componentize_py_runtime.pyi +0 -34
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/componentize_py_types.py +0 -19
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/poll_loop.py +0 -440
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/server.wit +0 -41
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/__init__.py +0 -70
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/exports/__init__.py +0 -19
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/exports/metadata.py +0 -22
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/__init__.py +0 -0
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/command.py +0 -539
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/common.py +0 -213
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/context.py +0 -70
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/entity.py +0 -84
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/event.py +0 -434
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/gui.py +0 -61
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/i18n.py +0 -35
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/logging.py +0 -30
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/permission.py +0 -71
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/player.py +0 -350
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/scheduler.py +0 -44
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/scoreboard.py +0 -95
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/server.py +0 -75
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/text.py +0 -89
- pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files/wit_world/imports/world.py +0 -215
- {pumpkin_api_py-0.1.0.dev0 → pumpkin_api_py-0.1.0.dev2}/.gitignore +0 -0
- {pumpkin_api_py-0.1.0.dev0 → pumpkin_api_py-0.1.0.dev2}/LICENSE +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/context.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/i18n.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/log.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/permission.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/scheduler.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/scoreboard.wit +0 -0
- {pumpkin_api_py-0.1.0.dev0/src/pumpkin_api/wit_files → pumpkin_api_py-0.1.0.dev2/wit/repo/pumpkin-plugin-wit/v0.1}/text.wit +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pumpkin-api-py
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
4
|
Summary: Pumpkin plugin API for Python
|
|
5
5
|
Author: alex
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -24,29 +24,22 @@ pip install pumpkin-api-py
|
|
|
24
24
|
2. Create your plugin (`main.py`):
|
|
25
25
|
|
|
26
26
|
```python
|
|
27
|
-
from pumpkin_api import
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
27
|
+
from pumpkin_api import Plugin, context, logging, metadata, register_plugin
|
|
28
|
+
|
|
29
|
+
PluginMetadata = metadata.PluginMetadata
|
|
31
30
|
|
|
32
31
|
class MyPlugin(Plugin):
|
|
33
32
|
def metadata(self) -> PluginMetadata:
|
|
34
33
|
return PluginMetadata(
|
|
35
|
-
name="my-plugin",
|
|
34
|
+
name="my-python-plugin",
|
|
36
35
|
version="0.1.0",
|
|
37
36
|
authors=["you"],
|
|
38
|
-
description="An example plugin."
|
|
37
|
+
description="An example python plugin.",
|
|
38
|
+
dependencies=[],
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
def on_load(self, ctx: context.Context) -> None:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# Register an event handler
|
|
45
|
-
self.register_event(ctx, event.EventType.PLAYER_JOIN_EVENT, self.on_player_join)
|
|
46
|
-
|
|
47
|
-
def on_player_join(self, srv: server.Server, evt: event.PlayerJoinEventData) -> event.PlayerJoinEventData:
|
|
48
|
-
print(f"Player {evt.player.get_name()} joined!")
|
|
49
|
-
return evt
|
|
42
|
+
logging.log(logging.Level.INFO, "Python plugin loaded!")
|
|
50
43
|
|
|
51
44
|
register_plugin(MyPlugin)
|
|
52
45
|
```
|
|
@@ -54,5 +47,5 @@ register_plugin(MyPlugin)
|
|
|
54
47
|
3. Build your plugin into a WebAssembly component:
|
|
55
48
|
|
|
56
49
|
```bash
|
|
57
|
-
pumpkin-
|
|
50
|
+
pumpkin-plugin-build main -o my_plugin.wasm
|
|
58
51
|
```
|
|
@@ -13,29 +13,22 @@ pip install pumpkin-api-py
|
|
|
13
13
|
2. Create your plugin (`main.py`):
|
|
14
14
|
|
|
15
15
|
```python
|
|
16
|
-
from pumpkin_api import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
16
|
+
from pumpkin_api import Plugin, context, logging, metadata, register_plugin
|
|
17
|
+
|
|
18
|
+
PluginMetadata = metadata.PluginMetadata
|
|
20
19
|
|
|
21
20
|
class MyPlugin(Plugin):
|
|
22
21
|
def metadata(self) -> PluginMetadata:
|
|
23
22
|
return PluginMetadata(
|
|
24
|
-
name="my-plugin",
|
|
23
|
+
name="my-python-plugin",
|
|
25
24
|
version="0.1.0",
|
|
26
25
|
authors=["you"],
|
|
27
|
-
description="An example plugin."
|
|
26
|
+
description="An example python plugin.",
|
|
27
|
+
dependencies=[],
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
def on_load(self, ctx: context.Context) -> None:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Register an event handler
|
|
34
|
-
self.register_event(ctx, event.EventType.PLAYER_JOIN_EVENT, self.on_player_join)
|
|
35
|
-
|
|
36
|
-
def on_player_join(self, srv: server.Server, evt: event.PlayerJoinEventData) -> event.PlayerJoinEventData:
|
|
37
|
-
print(f"Player {evt.player.get_name()} joined!")
|
|
38
|
-
return evt
|
|
31
|
+
logging.log(logging.Level.INFO, "Python plugin loaded!")
|
|
39
32
|
|
|
40
33
|
register_plugin(MyPlugin)
|
|
41
34
|
```
|
|
@@ -43,5 +36,5 @@ register_plugin(MyPlugin)
|
|
|
43
36
|
3. Build your plugin into a WebAssembly component:
|
|
44
37
|
|
|
45
38
|
```bash
|
|
46
|
-
pumpkin-
|
|
39
|
+
pumpkin-plugin-build main -o my_plugin.wasm
|
|
47
40
|
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
from shutil import rmtree
|
|
3
|
+
|
|
4
|
+
import componentize_py
|
|
5
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CustomBuildHook(BuildHookInterface):
|
|
9
|
+
def initialize(self, version: str, build_data: dict[str, any]) -> None:
|
|
10
|
+
bindings_out_path = path.join(self.directory, "bindings")
|
|
11
|
+
if path.exists(bindings_out_path):
|
|
12
|
+
rmtree(bindings_out_path)
|
|
13
|
+
|
|
14
|
+
componentize_py.generate_bindings(
|
|
15
|
+
wit_path=[
|
|
16
|
+
path.join(self.root, "wit", "repo", "pumpkin-plugin-wit", "v0.1")
|
|
17
|
+
],
|
|
18
|
+
worlds=[],
|
|
19
|
+
features=[],
|
|
20
|
+
all_features=False,
|
|
21
|
+
world_module="wit_world",
|
|
22
|
+
output_dir=bindings_out_path,
|
|
23
|
+
import_interface_names=[],
|
|
24
|
+
export_interface_names=[],
|
|
25
|
+
full_names=False,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
build_data["force_include"][bindings_out_path] = ""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pumpkin-api-py"
|
|
3
|
+
version = "0.1.0.dev2"
|
|
4
|
+
description = "Pumpkin plugin API for Python"
|
|
5
|
+
authors = [{name = "alex"}]
|
|
6
|
+
license = "GPL-3.0-only"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"componentize-py>=0.22.1",
|
|
9
|
+
]
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
|
|
13
|
+
[project.scripts]
|
|
14
|
+
pumpkin-plugin-build = "pumpkin_api.build:main"
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["hatchling","componentize-py>=0.22.1"]
|
|
18
|
+
build-backend = "hatchling.build"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.sdist]
|
|
21
|
+
include = [
|
|
22
|
+
"src/pumpkin_api",
|
|
23
|
+
"hatch_build.py",
|
|
24
|
+
"wit/repo/pumpkin-plugin-wit/v0.1"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build.targets.wheel]
|
|
28
|
+
include = ["src/pumpkin_api", "wit/repo/pumpkin-plugin-wit/v0.1/"]
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel.sources]
|
|
31
|
+
"src" = ""
|
|
32
|
+
"bindings" = ""
|
|
33
|
+
"wit/repo/pumpkin-plugin-wit/v0.1/" = "pumpkin_api/wit"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.wheel.hooks.custom]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from wit_world.exports import metadata
|
|
2
|
+
from wit_world.imports import (
|
|
3
|
+
block_entity,
|
|
4
|
+
command,
|
|
5
|
+
common,
|
|
6
|
+
context,
|
|
7
|
+
event,
|
|
8
|
+
gui,
|
|
9
|
+
i18n,
|
|
10
|
+
logging,
|
|
11
|
+
permission,
|
|
12
|
+
player,
|
|
13
|
+
scheduler,
|
|
14
|
+
scoreboard,
|
|
15
|
+
server,
|
|
16
|
+
text,
|
|
17
|
+
world,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .impl import Plugin, register_plugin
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Plugin",
|
|
24
|
+
"register_plugin",
|
|
25
|
+
"block_entity",
|
|
26
|
+
"command",
|
|
27
|
+
"common",
|
|
28
|
+
"context",
|
|
29
|
+
"event",
|
|
30
|
+
"gui",
|
|
31
|
+
"i18n",
|
|
32
|
+
"logging",
|
|
33
|
+
"metadata",
|
|
34
|
+
"permission",
|
|
35
|
+
"player",
|
|
36
|
+
"scheduler",
|
|
37
|
+
"server",
|
|
38
|
+
"scoreboard",
|
|
39
|
+
"text",
|
|
40
|
+
"world",
|
|
41
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
import componentize_py
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _build_entrypoint_wrapper(app_module: str, wrapper_dir: str) -> str:
|
|
9
|
+
wrapper_name = "_pumpkin_componentize_entry"
|
|
10
|
+
wrapper_path = os.path.join(wrapper_dir, f"{wrapper_name}.py")
|
|
11
|
+
|
|
12
|
+
with open(wrapper_path, "w", encoding="utf-8") as wrapper_file:
|
|
13
|
+
wrapper_file.write(
|
|
14
|
+
"from pathlib import Path\n"
|
|
15
|
+
"from pumpkin_api.impl import MetadataImpl, WitWorldImpl\n\n"
|
|
16
|
+
"WitWorld = WitWorldImpl\n"
|
|
17
|
+
"Metadata = MetadataImpl\n\n"
|
|
18
|
+
f"import {app_module}\n"
|
|
19
|
+
)
|
|
20
|
+
return wrapper_name
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main():
|
|
24
|
+
parser = argparse.ArgumentParser(description="Build a Pumpkin Python plugin")
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"app_module", help="The python module containing the plugin (e.g. 'main')"
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"-o", "--output", default="plugin.wasm", help="Output wasm file name"
|
|
30
|
+
)
|
|
31
|
+
args = parser.parse_args()
|
|
32
|
+
|
|
33
|
+
import pumpkin_api
|
|
34
|
+
|
|
35
|
+
pkg_dir = os.path.dirname(pumpkin_api.__file__)
|
|
36
|
+
# In source checkout, they are in wit_files/repo/...
|
|
37
|
+
# In installed package, they are directly in wit_files/
|
|
38
|
+
wit_dir = os.path.join(
|
|
39
|
+
pkg_dir, "..", "..", "wit", "repo", "pumpkin-plugin-wit", "v0.1.0"
|
|
40
|
+
)
|
|
41
|
+
if not os.path.exists(wit_dir):
|
|
42
|
+
wit_dir = os.path.join(pkg_dir, "wit")
|
|
43
|
+
|
|
44
|
+
# Pass the parent directory of pumpkin_api to componentize-py so it can resolve `pumpkin_api` module
|
|
45
|
+
# in case it's not installed in a standard site-packages (e.g. editable install or no venv)
|
|
46
|
+
pkg_parent_dir = os.path.dirname(pkg_dir)
|
|
47
|
+
|
|
48
|
+
with tempfile.TemporaryDirectory(prefix="pumpkin-api-build-") as wrapper_dir:
|
|
49
|
+
wrapper_module = _build_entrypoint_wrapper(args.app_module, wrapper_dir)
|
|
50
|
+
|
|
51
|
+
componentize_py.componentize(
|
|
52
|
+
wit_path=[wit_dir],
|
|
53
|
+
worlds=[],
|
|
54
|
+
features=[],
|
|
55
|
+
all_features=False,
|
|
56
|
+
world_module="wit_world",
|
|
57
|
+
python_path=[".", pkg_parent_dir, wrapper_dir],
|
|
58
|
+
module_worlds=[],
|
|
59
|
+
app_name=wrapper_module,
|
|
60
|
+
output_path=args.output,
|
|
61
|
+
stub_wasi=False,
|
|
62
|
+
import_interface_names=[],
|
|
63
|
+
export_interface_names=[],
|
|
64
|
+
full_names=False,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# pumpkin-api-py: Pumpkin plugin API for Python
|
|
2
|
+
# Copyright (C) 2024 alex
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import traceback
|
|
18
|
+
from typing import Any, Callable, Dict, Optional, Type
|
|
19
|
+
|
|
20
|
+
import wit_world
|
|
21
|
+
import wit_world.exports
|
|
22
|
+
from componentize_py_types import Err
|
|
23
|
+
from wit_world.exports import metadata
|
|
24
|
+
from wit_world.imports import command, context, event, scheduler, server, text
|
|
25
|
+
|
|
26
|
+
_PLUGIN_INSTANCE: Optional["Plugin"] = None
|
|
27
|
+
_EVENT_HANDLERS: Dict[int, Callable[[server.Server, Any], Any]] = {}
|
|
28
|
+
_COMMAND_HANDLERS: Dict[
|
|
29
|
+
int, Callable[[command.CommandSender, server.Server, command.ConsumedArgs], int]
|
|
30
|
+
] = {}
|
|
31
|
+
_TASK_HANDLERS: Dict[int, Callable[[server.Server], None]] = {}
|
|
32
|
+
_NEXT_HANDLER_ID: int = 0
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _exception_message(exc: Exception) -> str:
|
|
36
|
+
if hasattr(exc, "value"):
|
|
37
|
+
value = getattr(exc, "value")
|
|
38
|
+
if value is not None:
|
|
39
|
+
return str(value)
|
|
40
|
+
message = str(exc)
|
|
41
|
+
if message:
|
|
42
|
+
return message
|
|
43
|
+
return "".join(traceback.format_exception_only(type(exc), exc)).strip()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _format_exception(exc: Exception) -> str:
|
|
47
|
+
details = "".join(
|
|
48
|
+
traceback.format_exception(type(exc), exc, exc.__traceback__)
|
|
49
|
+
).strip()
|
|
50
|
+
if details:
|
|
51
|
+
return details
|
|
52
|
+
return _exception_message(exc)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _get_next_handler_id() -> int:
|
|
56
|
+
global _NEXT_HANDLER_ID
|
|
57
|
+
handler_id = _NEXT_HANDLER_ID
|
|
58
|
+
_NEXT_HANDLER_ID += 1
|
|
59
|
+
return handler_id
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Plugin:
|
|
63
|
+
def __init__(self):
|
|
64
|
+
self._pending_events = []
|
|
65
|
+
|
|
66
|
+
def metadata(self) -> metadata.PluginMetadata:
|
|
67
|
+
raise NotImplementedError
|
|
68
|
+
|
|
69
|
+
def on_load(self, ctx: context.Context) -> None:
|
|
70
|
+
for event_type, handler, priority, blocking in self._pending_events:
|
|
71
|
+
self.register_event(ctx, event_type, handler, priority, blocking)
|
|
72
|
+
|
|
73
|
+
def on_unload(self, ctx: context.Context) -> None:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def register_event(
|
|
77
|
+
self,
|
|
78
|
+
ctx: context.Context,
|
|
79
|
+
event_type: event.EventType,
|
|
80
|
+
handler: Callable[[server.Server, Any], Any],
|
|
81
|
+
priority=event.EventPriority.NORMAL,
|
|
82
|
+
blocking=True,
|
|
83
|
+
):
|
|
84
|
+
handler_id = _get_next_handler_id()
|
|
85
|
+
_EVENT_HANDLERS[handler_id] = handler
|
|
86
|
+
ctx.register_event(handler_id, event_type, priority, blocking)
|
|
87
|
+
|
|
88
|
+
def register_command(
|
|
89
|
+
self,
|
|
90
|
+
ctx: context.Context,
|
|
91
|
+
cmd: command.Command,
|
|
92
|
+
handler: Callable[
|
|
93
|
+
[command.CommandSender, server.Server, command.ConsumedArgs], int
|
|
94
|
+
],
|
|
95
|
+
permission: str = "",
|
|
96
|
+
):
|
|
97
|
+
handler_id = _get_next_handler_id()
|
|
98
|
+
_COMMAND_HANDLERS[handler_id] = handler
|
|
99
|
+
cmd.execute_with_handler_id(handler_id)
|
|
100
|
+
ctx.register_command(cmd, permission)
|
|
101
|
+
|
|
102
|
+
def schedule_delayed_task(
|
|
103
|
+
self, delay_ticks: int, handler: Callable[[server.Server], None]
|
|
104
|
+
) -> int:
|
|
105
|
+
handler_id = _get_next_handler_id()
|
|
106
|
+
_TASK_HANDLERS[handler_id] = handler
|
|
107
|
+
return scheduler.schedule_delayed_task(handler_id, delay_ticks)
|
|
108
|
+
|
|
109
|
+
def schedule_repeating_task(
|
|
110
|
+
self,
|
|
111
|
+
delay_ticks: int,
|
|
112
|
+
period_ticks: int,
|
|
113
|
+
handler: Callable[[server.Server], None],
|
|
114
|
+
) -> int:
|
|
115
|
+
handler_id = _get_next_handler_id()
|
|
116
|
+
_TASK_HANDLERS[handler_id] = handler
|
|
117
|
+
return scheduler.schedule_repeating_task(handler_id, delay_ticks, period_ticks)
|
|
118
|
+
|
|
119
|
+
def event_handler(
|
|
120
|
+
self,
|
|
121
|
+
event_type: event.EventType,
|
|
122
|
+
priority=event.EventPriority.NORMAL,
|
|
123
|
+
blocking=True,
|
|
124
|
+
):
|
|
125
|
+
def decorator(func):
|
|
126
|
+
self._pending_events.append((event_type, func, priority, blocking))
|
|
127
|
+
return func
|
|
128
|
+
|
|
129
|
+
return decorator
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def register_plugin(plugin_class: Type[Plugin]):
|
|
133
|
+
global _PLUGIN_INSTANCE
|
|
134
|
+
_PLUGIN_INSTANCE = plugin_class()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class WitWorldImpl(wit_world.WitWorld):
|
|
138
|
+
def init_plugin(self) -> None:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
def on_load(self, context: context.Context) -> None:
|
|
142
|
+
if _PLUGIN_INSTANCE:
|
|
143
|
+
try:
|
|
144
|
+
# In WIT, on-load returns result<_, string>
|
|
145
|
+
# componentize-py handles this by expecting None or raising Err
|
|
146
|
+
_PLUGIN_INSTANCE.on_load(context)
|
|
147
|
+
except Err as e:
|
|
148
|
+
raise Err(_exception_message(e))
|
|
149
|
+
except Exception as e:
|
|
150
|
+
raise Err(_format_exception(e))
|
|
151
|
+
|
|
152
|
+
def on_unload(self, context: context.Context) -> None:
|
|
153
|
+
if _PLUGIN_INSTANCE:
|
|
154
|
+
try:
|
|
155
|
+
_PLUGIN_INSTANCE.on_unload(context)
|
|
156
|
+
except Err as e:
|
|
157
|
+
raise Err(_exception_message(e))
|
|
158
|
+
except Exception as e:
|
|
159
|
+
raise Err(_format_exception(e))
|
|
160
|
+
|
|
161
|
+
def handle_event(
|
|
162
|
+
self, event_id: int, server: server.Server, event: event.Event
|
|
163
|
+
) -> event.Event:
|
|
164
|
+
if event_id in _EVENT_HANDLERS:
|
|
165
|
+
# Pass the inner event data to the handler
|
|
166
|
+
result = _EVENT_HANDLERS[event_id](server, event.value)
|
|
167
|
+
# If the handler returns something, assume it's the updated event data
|
|
168
|
+
if result is not None:
|
|
169
|
+
event.value = result
|
|
170
|
+
return event
|
|
171
|
+
|
|
172
|
+
def handle_command(
|
|
173
|
+
self,
|
|
174
|
+
command_id: int,
|
|
175
|
+
sender: command.CommandSender,
|
|
176
|
+
server: server.Server,
|
|
177
|
+
args: command.ConsumedArgs,
|
|
178
|
+
) -> int:
|
|
179
|
+
if command_id in _COMMAND_HANDLERS:
|
|
180
|
+
try:
|
|
181
|
+
return _COMMAND_HANDLERS[command_id](sender, server, args)
|
|
182
|
+
except Exception as e:
|
|
183
|
+
if hasattr(e, "value") and isinstance(
|
|
184
|
+
e.value,
|
|
185
|
+
(
|
|
186
|
+
command.CommandError_InvalidConsumption,
|
|
187
|
+
command.CommandError_InvalidRequirement,
|
|
188
|
+
command.CommandError_PermissionDenied,
|
|
189
|
+
command.CommandError_CommandFailed,
|
|
190
|
+
),
|
|
191
|
+
):
|
|
192
|
+
raise e
|
|
193
|
+
raise Err(
|
|
194
|
+
command.CommandError_CommandFailed(
|
|
195
|
+
text.TextComponent.text(_format_exception(e))
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
raise Err(
|
|
200
|
+
command.CommandError_CommandFailed(
|
|
201
|
+
text.TextComponent.text(
|
|
202
|
+
f"no handler registered for command id {command_id}"
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def handle_task(self, handler_id: int, server: server.Server) -> None:
|
|
208
|
+
if handler_id in _TASK_HANDLERS:
|
|
209
|
+
_TASK_HANDLERS[handler_id](server)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class MetadataImpl:
|
|
213
|
+
def get_metadata(self) -> metadata.PluginMetadata:
|
|
214
|
+
if _PLUGIN_INSTANCE:
|
|
215
|
+
return _PLUGIN_INSTANCE.metadata()
|
|
216
|
+
return metadata.PluginMetadata("unknown", "0.0.0", [], "No metadata", [])
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface entity {
|
|
1
|
+
interface block-entity {
|
|
2
2
|
use common.{block-position};
|
|
3
3
|
|
|
4
4
|
resource block-entity {
|
|
@@ -30,7 +30,7 @@ interface entity {
|
|
|
30
30
|
powered: func() -> bool;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
variant entity {
|
|
33
|
+
variant block-entity-type {
|
|
34
34
|
command-block-entity(command-block-entity),
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
interface boss-bar {
|
|
2
|
+
use text.{text-component};
|
|
3
|
+
use player.{player};
|
|
4
|
+
|
|
5
|
+
/// Represents the color of a boss bar.
|
|
6
|
+
enum boss-bar-color {
|
|
7
|
+
pink,
|
|
8
|
+
blue,
|
|
9
|
+
red,
|
|
10
|
+
green,
|
|
11
|
+
yellow,
|
|
12
|
+
purple,
|
|
13
|
+
white,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// Represents the notches/divisions of a boss bar.
|
|
17
|
+
enum boss-bar-division {
|
|
18
|
+
no-division,
|
|
19
|
+
notches-6,
|
|
20
|
+
notches-10,
|
|
21
|
+
notches-12,
|
|
22
|
+
notches-20,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Metadata flags that can be toggled on a boss bar.
|
|
26
|
+
record boss-bar-metadata {
|
|
27
|
+
/// Darkens the sky for players who see the boss bar.
|
|
28
|
+
darken-sky: bool,
|
|
29
|
+
/// If true, the bar is considered a "dragon bar" (used for Ender Dragon).
|
|
30
|
+
dragon-bar: bool,
|
|
31
|
+
/// If true, fog is created around the players who see the boss bar.
|
|
32
|
+
create-fog: bool,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Represents a boss bar that can be shown to players.
|
|
36
|
+
resource boss-bar {
|
|
37
|
+
/// Creates a new boss bar.
|
|
38
|
+
constructor(title: text-component, color: boss-bar-color, division: boss-bar-division);
|
|
39
|
+
|
|
40
|
+
/// Returns the title of this boss bar.
|
|
41
|
+
get-title: func() -> text-component;
|
|
42
|
+
|
|
43
|
+
/// Sets the title of this boss bar.
|
|
44
|
+
set-title: func(title: text-component);
|
|
45
|
+
|
|
46
|
+
/// Returns the health (0.0 to 1.0) of this boss bar.
|
|
47
|
+
get-health: func() -> f32;
|
|
48
|
+
|
|
49
|
+
/// Sets the health (0.0 to 1.0) of this boss bar.
|
|
50
|
+
set-health: func(health: f32);
|
|
51
|
+
|
|
52
|
+
/// Returns the color of this boss bar.
|
|
53
|
+
get-color: func() -> boss-bar-color;
|
|
54
|
+
|
|
55
|
+
/// Sets the color of this boss bar.
|
|
56
|
+
set-color: func(color: boss-bar-color);
|
|
57
|
+
|
|
58
|
+
/// Returns the division of this boss bar.
|
|
59
|
+
get-division: func() -> boss-bar-division;
|
|
60
|
+
|
|
61
|
+
/// Sets the division of this boss bar.
|
|
62
|
+
set-division: func(division: boss-bar-division);
|
|
63
|
+
|
|
64
|
+
/// Returns the currently active metadata on this boss bar.
|
|
65
|
+
get-metadata: func() -> boss-bar-metadata;
|
|
66
|
+
|
|
67
|
+
/// Updates the metadata on this boss bar.
|
|
68
|
+
set-metadata: func(metadata: boss-bar-metadata);
|
|
69
|
+
|
|
70
|
+
/// Adds a player to this boss bar, making it visible to them.
|
|
71
|
+
add-player: func(player: player);
|
|
72
|
+
|
|
73
|
+
/// Removes a player from this boss bar, hiding it from them.
|
|
74
|
+
remove-player: func(player: player);
|
|
75
|
+
|
|
76
|
+
/// Returns a list of all players currently seeing this boss bar.
|
|
77
|
+
get-players: func() -> list<player>;
|
|
78
|
+
|
|
79
|
+
/// Removes this boss bar from all players and cleans it up.
|
|
80
|
+
remove-all: func();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
interface command {
|
|
2
|
-
use player.{player};
|
|
3
2
|
use %world.{%world};
|
|
4
|
-
use entity.{
|
|
3
|
+
use entity.{entity};
|
|
4
|
+
use player.{player};
|
|
5
|
+
use block-entity.{command-block-entity};
|
|
5
6
|
use common.{position, block-position, locale};
|
|
6
7
|
use server.{server, difficulty};
|
|
7
8
|
use text.{text-component};
|
|
@@ -67,6 +67,28 @@ interface common {
|
|
|
67
67
|
count: u8,
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/// Represents the various poses an entity can be in.
|
|
71
|
+
enum entity-pose {
|
|
72
|
+
standing,
|
|
73
|
+
fall-flying,
|
|
74
|
+
sleeping,
|
|
75
|
+
swimming,
|
|
76
|
+
spin-attack,
|
|
77
|
+
crouching,
|
|
78
|
+
long-jumping,
|
|
79
|
+
dying,
|
|
80
|
+
croaking,
|
|
81
|
+
using-tongue,
|
|
82
|
+
sitting,
|
|
83
|
+
roaring,
|
|
84
|
+
sniffing,
|
|
85
|
+
emerging,
|
|
86
|
+
digging,
|
|
87
|
+
sliding,
|
|
88
|
+
shooting,
|
|
89
|
+
inhaling,
|
|
90
|
+
}
|
|
91
|
+
|
|
70
92
|
/// All Minecraft-supported locales.
|
|
71
93
|
enum locale {
|
|
72
94
|
af-za,
|
|
@@ -150,7 +150,6 @@ interface event {
|
|
|
150
150
|
player: player,
|
|
151
151
|
action: interact-action,
|
|
152
152
|
clicked-pos: option<block-position>,
|
|
153
|
-
item: item-stack,
|
|
154
153
|
block: string,
|
|
155
154
|
cancelled: bool
|
|
156
155
|
}
|
|
@@ -161,6 +160,12 @@ interface event {
|
|
|
161
160
|
cancelled: bool
|
|
162
161
|
}
|
|
163
162
|
|
|
163
|
+
record player-toggle-flight-event-data {
|
|
164
|
+
player: player,
|
|
165
|
+
is-flying: bool,
|
|
166
|
+
cancelled: bool
|
|
167
|
+
}
|
|
168
|
+
|
|
164
169
|
record player-toggle-sprint-event-data {
|
|
165
170
|
player: player,
|
|
166
171
|
is-sprinting: bool,
|
|
@@ -265,6 +270,7 @@ interface event {
|
|
|
265
270
|
player-interact-unknown-entity-event,
|
|
266
271
|
player-interact-event,
|
|
267
272
|
player-toggle-sneak-event,
|
|
273
|
+
player-toggle-flight-event,
|
|
268
274
|
player-toggle-sprint-event,
|
|
269
275
|
block-redstone-event,
|
|
270
276
|
block-break-event,
|
|
@@ -297,6 +303,7 @@ interface event {
|
|
|
297
303
|
player-interact-unknown-entity-event(player-interact-unknown-entity-event-data),
|
|
298
304
|
player-interact-event(player-interact-event-data),
|
|
299
305
|
player-toggle-sneak-event(player-toggle-sneak-event-data),
|
|
306
|
+
player-toggle-flight-event(player-toggle-flight-event-data),
|
|
300
307
|
player-toggle-sprint-event(player-toggle-sprint-event-data),
|
|
301
308
|
block-redstone-event(block-redstone-event-data),
|
|
302
309
|
block-break-event(block-break-event-data),
|
|
@@ -34,5 +34,17 @@ interface gui {
|
|
|
34
34
|
constructor(%type: gui-type, title: text-component);
|
|
35
35
|
set-item: func(slot: u32, item: item-stack);
|
|
36
36
|
get-item: func(slot: u32) -> option<item-stack>;
|
|
37
|
+
|
|
38
|
+
/// Returns the type of this GUI.
|
|
39
|
+
get-type: func() -> gui-type;
|
|
40
|
+
|
|
41
|
+
/// Returns the title of this GUI.
|
|
42
|
+
get-title: func() -> text-component;
|
|
43
|
+
|
|
44
|
+
/// Returns the number of slots in this GUI.
|
|
45
|
+
get-size: func() -> u32;
|
|
46
|
+
|
|
47
|
+
/// Clears all items from the GUI.
|
|
48
|
+
clear-items: func();
|
|
37
49
|
}
|
|
38
50
|
}
|