跳到正文

Python MOD

作者:kscm1236

This mod lets you use Python to connect to the Python MOD API

收藏

介绍

中文介绍正在准备中,下面暂时显示原文。

Python MOD

Write Minecraft mods in Python.

Python MOD is a Fabric mod that embeds a real Python 3 runtime into Minecraft
and exposes a sandboxed API for registering content, hooking game events and
building screens. Drop a .pymod file into a folder, restart, and your Python
is running inside the game — no Java, no Gradle, no recompiling.

  • Minecraft 1.21.1 · Fabric Loader 0.16+ · Fabric API
  • Runtime: GraalPy 24.2.2 (CPython 3.11 compatible)
  • API level: 1
  • Licence: Available License — © 2026 kscm · Project Owner: kscm

Hello, world

hello_world.pymod is a zip with two files:

hello_world.pymod
├── pymod.json
└── src/
    └── main.py

pymod.json

{
  "id": "hello_world",
  "name": "Hello World",
  "version": "1.0.0",
  "api_version": 1,
  "entrypoint": "src/main.py",
  "permissions": []
}

src/main.py

import pythonmod
from pythonmod import registry, events

registry.block("hello_block", hardness=1.0, sounds="wood", name="Hello Block")

@events.player_join
def greet(player):
    player.send_message("Hello from Python!")

Put it in .minecraft/mods/pythonmods/, start the game, press P.


What the API covers

pythonmod.registry — content

| Function | Registers |
| — | — |
| block(id, hardness, resistance, requires_tool, luminance, sounds, group, item, texture, name) | A full-cube block, optionally with a block item |
| item(id, max_stack, group, texture, name) | A plain item |
| food(id, nutrition, saturation, always_edible, max_stack, group, texture, name) | An edible item |

Everything is namespaced under your module id, so block("ruby_ore") in a
package with "id": "gems" becomes gems:ruby_ore. Two unrelated packages can
both define ruby_ore and never collide.

Models and English names are generated into a PythonMOD Generated resource
pack, so new content is usable before you have drawn a single texture.

pythonmod.events — game hooks

| Event | Arguments |
| — | — |
| server_tick | (server) |
| server_started / server_stopping | (server) |
| player_join / player_leave | (player) |
| block_break | (player, pos, block) |
| block_use | (player, pos) |
| item_use | (player) |
| client_tick | (client) |

from pythonmod import events

@events.block_break
def on_break(player, pos, block):
    player.send_actionbar("broke %s at %d,%d,%d" % (block.id(), pos.x(), pos.y(), pos.z()))

An unrecognised event name raises at subscription time. A hook that silently
never fires is the most expensive kind of typo, so it is not allowed to happen.

pythonmod.gui — screens

from pythonmod import gui

(gui.screen("Ore Scanner")
    .size(280, 160)
    .label("Radius", 20, 34)
    .slider("blocks", 20, 48, 240, value=16, min=4, max=64, on_change=set_radius)
    .checkbox("Include deepslate", 20, 80, checked=True, on_change=set_deepslate)
    .button("Scan", 20, 110, 240, 20, on_click=scan)
    .open())

Coordinates are relative to the panel and the panel is centred for you.
Light and dark palettes are built in and follow the player’s setting — a script
never picks colours by hand.

On a dedicated server there is no client, so open() returns False and logs
a warning instead of raising. Guard with gui.available() when a package is
meant to run on both sides.

pythonmod.xmlgui — declarative HUD (XML)

Declare an in-game HUD panel in gui/*.xml — no Python screen code required.
Each module’s gui/ folder is scanned automatically at load time.

gui/hud.xml

<gui>
  <screen id="hud_demo" show_page="hud" x="12" y="12">
    <label id="title" text="Python MOD · XML HUD" x="0" y="0"
           style="color:#1b1f24" style_dark="color:#eceff3"/>
    <divider x="0" y="20" w="180"/>
    <button id="mine" text="Mine +1" x="0" y="30" w="160" h="20"
            style="bg:#1565c0;color:#ffffff" style_dark="bg:#5fa8ff;color:#0b0e12"
            click_script="on_click.py" follow_script="after.py"/>
    <checkbox id="auto" text="Auto mine" x="0" y="58" checked="true"
              style="color:#1b1f24" style_dark="color:#eceff3"
              click_script="on_toggle.py"/>
    <slider id="speed" text="Speed" x="0" y="84" w="180" value="0.5" min="0" max="1"/>
    <text_field id="status" placeholder="Status: ready" x="0" y="110" w="180" h="20"/>
  </screen>
</gui>

| Attribute | On | Meaning |
| — | — | — |
| style / style_dark | widget | CSS-like key:value pairs (color, bg, border). The active light/dark theme picks which one |
| click_script | button, checkbox | Python file run when the widget is clicked |
| follow_script | button | Python file run right after click_script completes |
| show_page | screen | Where to show it: hud (in-game overlay). screen / main_menu are reserved |
| x / y | screen, widget | Coordinates in GUI pixels; the screen is the panel anchor, a widget is relative to it |

The scripts run in an isolated context — same permissions and sandbox as the
module, but a crash disables only that script, never the whole module. They can
import pythonmod like any other code. A clicked button runs click_script
then follow_script; the same path is reachable from Python:

from pythonmod import xmlgui
xmlgui.trigger("hud_demo", "mine")   # runs on_click.py then after.py

See examples/xml_hud_demo/ for a complete, runnable panel (button, checkbox,
slider and text field with light/dark styles and Python scripts).


The manifest

| Field | Required | Notes |
| — | — | — |
| id | yes | 2–64 chars of a-z, 0-9, _. Becomes your registry namespace |
| version | yes | Free-form |
| api_version | yes | Must be 1. See Attribution below |
| name | no | Defaults to id |
| description | no | Shown in the manager screen |
| authors | no | Array of strings |
| entrypoint | no | Defaults to src/main.py |
| environment | no | *, client or server |
| permissions | no | See the table below |

Permissions

| Permission | Risk | Grants |
| — | — | — |
| file_read | low | Reading inside your own data folder |
| file_write | medium | Writing inside your own data folder |
| network | high | Outbound sockets |
| thread | high | Creating threads |
| native | critical | Native/JNI access — effectively no sandbox |
| process | critical | Spawning processes — effectively no sandbox |

The sandbox confines file access to pythonmod/data/<your-id>/ regardless of
what is granted. pythonmod.data_path("state.json") builds a legal path;
anything outside that tree is refused before it reaches the filesystem.

Packages asking for native or process produce a loud warning in the log and
a red entry in the manager screen. That is deliberate: those two permissions
hand a script the same power a Java mod has.


In-game manager

Press P (rebindable) for:

  • what loaded, what failed, and the exact reason
  • what each package registered, and how long it took
  • the permissions it was granted, colour-coded by risk
  • the last few lines it printed
  • a light / dark / auto theme switch, saved to the config

Configuration

.minecraft/config/pythonmod.json

| Key | Default | Meaning |
| — | — | — |
| enabled | true | Master switch |
| autoDownloadRuntime | true | Fetch GraalPy on first launch |
| mavenRepository | Maven Central | Mirror to download from |
| verifyChecksums | true | Verify every downloaded jar |
| theme | "auto" | auto, light or dark |
| callbackTimeoutMs | 5000 | A callback exceeding this disables its package |
| verboseLogging | false | Extra diagnostics |


How it works

preLaunch   RuntimeProvisioner   downloads GraalPy, verifies SHA-1,
                                 injects it into the Knot class loader
   ↓
main        PythonEngine         one shared Engine
            SandboxPolicy        one Context per package, with its own
                                 permission set and virtual filesystem
            PyModLoader          scan → validate → unpack → run
            PyBridge             the single Java object Python can reach
   ↓
runtime     PyEventBridge        Fabric callbacks fan out to Python hooks
            PyGuiBridge          screen descriptions, rendered client-side
            XmlHudRenderer       XML-declared HUD panels, scanned from gui/*.xml
            XmlGuiBridge         fires a widget's click/follow scripts

The runtime is not bundled. GraalPy is roughly 200 MB — larger than most
modpacks. It is downloaded once on first launch, checksum-verified, and cached
in .minecraft/pythonmod/runtime/. If the download fails the game still starts;
Python support is simply reported as unavailable.

One context per package, not one shared context. A polyglot context cannot
hold two different permission sets, so a shared one would grant every package
the union of everyone’s permissions — one package asking for network would
silently hand network access to all the others. Separate contexts also mean a
crashing package can be disabled on its own.

Guest exceptions never escape. Every call into Python goes through
PythonEngine.invoke, which catches the guest exception, prints the Python
traceback, and disables the offending package. A typo in a script is not
allowed to take the server down.


Building

Requires JDK 21. A local Temurin 21 lives in .tooling/jdk-21; point
org.gradle.java.home in gradle.properties at your own if you prefer.

./gradlew build          # builds the mod jar
./gradlew packExamples   # packs examples/ into build/pymods/*.pymod

Attribution

Python MOD is distributed under the Available License (see LICENSE),
© 2026 kscm, Project Owner kscm.

Section 6 requires software using this API to state the original project
name and version. Python MOD does that for you:

  • api_version is mandatory in every manifest — a package without it is refused rather than silently loaded
  • the loader prints <package> v<version> — Powered by Python MOD v<x.y.z> (API <n>) when the package starts
  • the same string is available as pythonmod.ATTRIBUTION
  • gradlew packExamples writes ATTRIBUTION.txt into every archive

Declaring api_version is therefore all an author has to do.

Section 3 — using this project’s source code requires authorisation from
the Project Owner, and any such use must state the original project name, team
and version.

Section 7 — “Python MOD” is used as the sole project name; no translated
name is claimed or authorised.

Not affiliated with Mojang Studios or Microsoft.

常见问题

Python MOD 支持哪些 Minecraft 版本?

Python MOD 支持 Minecraft Java 版 1.21.1–1.21.11,共 11 个版本,可用的加载器:Fabric。下载时注意选择和你游戏版本一致的文件。

Python MOD 怎么安装?

先用 PCL2 或 HMCL 启动器安装对应版本的 Fabric,再把下载的 .jar 文件放进游戏目录的 mods 文件夹,重新启动游戏即可。开启了版本隔离的,mods 文件夹在 versions/版本名 下面。运行环境:客户端和服务端都要装。

评论

登录后评论和评分

kscm1236 的其他作品

查看全部 →