▶️ ЗАБЕРИ СВОИ 8 ПОДАРКОВ 🎁 ПРИ СОЗДАНИИ СВОЕГО МАЙНКРАФТ СЕРВЕРА
PyRunner

PyRunner

Run your Python Discord bot directly alongside your Minecraft server! Features auto-setup, live web dashboard, and in-game controls

Оцените первым
43
2
Все версииPyRunner 1.2.0

PyRunner 1.2.0

Release27.04.2026

Список изменений

🆕 What's new in 1.2.0

Dashboard — Settings & Bot Management

The web dashboard has been completely overhauled. It is no longer just a log viewer — it now gives you full control over the plugin without ever touching config.yml or SSHing into the server.

New Settings tab — every config value is editable live from the browser:

  • Process behaviour: auto-restart toggle, restart delay, max restarts, crash window, startup delay
  • Python runtime: version pin and custom executable path
  • Discord webhook: URL, enable/disable, and individual toggles for each event type (start, stop, crash, log lines)
  • Dashboard: log history line count and password (changing the password immediately invalidates all active sessions)

New Bots tab — full bot instance management with TunnelMC-style modal dialogs:

  • Add a new bot (name, entry file, env vars) — starts automatically
  • Edit an existing bot — stops it, applies the new config, and restarts
  • Delete a bot — stops it and removes it from config.yml
  • All changes persist to disk immediately

Download logs — a new button on the sidebar downloads the current bot.log as a file attachment.

SSE push-based streaming — log lines are now pushed directly to the browser the moment they are written, rather than polled. This eliminates latency and CPU overhead.

Log counter fix — the line counter now reflects what is actually visible in the DOM (capped at 3000) rather than a stale incrementing integer.

switchBot() race fixed — historical logs are fully loaded before the SSE stream connects, preventing out-of-order or duplicate lines when switching bots.

Bug Fixes

  • failedAttempts map unbounded growth — swept hourly alongside the session map.

  • JSON injection in status/bots API — bot names and entry file paths serialised with Gson instead of string concatenation.

  • setsid path now covers Alpine Linux / Pterodactyl — checks /usr/bin/setsid, /bin/setsid, and /usr/local/bin/setsid. Previously process group killing silently did nothing on Alpine-based containers.

  • FileReader platform charset/proc/<pid>/status read with explicit UTF-8.

  • FileUtils.deleteDir() returns boolean — failures logged per-file instead of silently swallowed.

  • GET endpoints reject non-GET requests — 405 returned for wrong-method calls.

  • Log timestamps include the dateMM-dd HH:mm:ss format so logs spanning midnight are unambiguous.

  • Python downloader fetches 20 releases — up from 5, so rare platform/version combos are found correctly.

  • Content-Security-Policy header added to all dashboard responses.

  • Gradle performance flagsparallel, caching, and G1GC JVM args added to gradle.properties.

  • Fixed state race conditionBotState is now managed via AtomicReference instead of a plain volatile field, eliminating a class of bugs where background threads could write the state without memory visibility guarantees.

  • Fixed forceReinstall() not actually reinstalling — The command now passes --force-reinstall to pip, guaranteeing packages are freshly installed. Previously it only deleted the flag file and ran a normal pip install, which would skip already-installed packages.

  • Fixed restart() busy-wait — The polling loop has been replaced with a CountDownLatch, so restarts are more reliable and use zero CPU while waiting for the process to fully stop.

  • Fixed GitHub API rate limiting causing confusing errorsfindReleaseAsset() now checks the HTTP status code before attempting to parse JSON. A 403 or 429 from GitHub now produces a clear "rate limit reached" message instead of a cryptic JsonParseException.

  • Fixed config values not validated — All numeric config getters (restart-delay-seconds, max-restarts, crash-window-seconds, startup-delay-seconds) now clamp to valid ranges, preventing Thread.sleep(-N) exceptions from negative values.

  • Fixed log-history cap not enforcedgetDashboardLogHistory() is now capped at 500 (matching LogManager's ring buffer size), so requesting more lines than the buffer holds no longer silently returns a truncated result without warning.

  • Fixed static instance not volatile — The singleton is now declared volatile for safe cross-thread visibility, and is nulled out in onDisable() to prevent classloader leaks on plugin reload.

  • Fixed Discord embed JSON escaping — Webhook embeds now use Gson's toJson() for string serialisation instead of a manual replace() chain, correctly escaping all Unicode control characters (\u0000\u001F) that could cause Discord to reject payloads.

  • Fixed malformed bot entries crashing plugin load — Each entry in the bots: YAML list is now parsed inside a try-catch; a bad entry logs a warning and is skipped rather than throwing a ClassCastException that aborts the whole enable sequence.

  • Added default password warning — A prominent console warning is now printed at startup if the dashboard is enabled and the password is still set to "changeme".

  • Improved getBotDir() fallback — When entry-file has no directory component (e.g. main.py instead of bot/main.py), the plugin now derives the directory from the actual file path and logs a descriptive warning, rather than silently assuming "bot".

  • Fixed dashboard SSE exhausting the HTTP thread pool — The server now uses Java 21 virtual threads (newVirtualThreadPerTaskExecutor) instead of a fixed 8-thread pool. Previously, 8+ simultaneous SSE log-stream connections could fill the pool and cause all other API requests to hang indefinitely.

  • Fixed DashboardServer.jsonString() unsafe escaping — Dashboard log API responses now use GSON.toJson() instead of a manual replace() chain, correctly handling Unicode control characters (\u0000\u001F) that could previously produce malformed JSON.

  • Fixed memory cache non-atomic reads — Three separate volatile fields replaced with a single volatile MemCache record swapped atomically, preventing threads from observing a new timestamp with stale memory values.

  • Fixed SSE handler busy-pollingwhile (!heartbeatFuture.isDone()) Thread.sleep(1000) replaced with heartbeatFuture.get(), eliminating unnecessary 1-second wakeups while waiting for client disconnection.

  • Fixed session map growing without bound — A scheduled hourly sweep now removes expired sessions. Previously, repeated logins accumulated stale entries indefinitely.

  • Fixed dashboard password using string equality — Login now uses MessageDigest.isEqual() for constant-time comparison, preventing timing attacks.

  • Fixed duplicate deleteDir() logic — A new shared util/FileUtils.deleteDir() (NIO-based) replaces the identical recursive-delete duplicated across PyBotCommand and DashboardServer.

  • Fixed plugin.yml api-version outdated — Updated from '1.13' to '1.21' to match the actual target platform and suppress Paper deprecation warnings on load.

  • Fixed Gson used as implicit transitive dependency — Gson is now declared explicitly as compileOnly in build.gradle.kts.

  • Fixed legacy § color codes in commands — All in-game messages in PyBotCommand now use the Paper Adventure API (MiniMessage), eliminating deprecation warnings and ensuring correct rendering in modern clients.

Config changes

No new config keys. Existing configs remain fully compatible.

Файлы

PyRunner.jar(73.30 KiB)
Основной
Скачать

Метаданные

Канал релиза

Release

Номер версии

1.2.0

Загрузчики

Bukkit
Paper
Purpur
Spigot

Версии игры

1.21–1.21.11

Загрузок

7

Дата публикации

27.04.2026

Загрузил

ID версии

Главная