Paper Minecraft Server Auto Updater for 1.21.5

  • After careful consideration and due to limited usage, we’ve made the decision to discontinue the PaperMC forums. Moving forward, we recommend using Hangar for plugin uploads, and for all other community discussions and support, please join us on Discord.

CraniX

New member
Apr 25, 2025
2
0
1
Canada
modrinth.com

paper_updater.py​


Code:
import os
import requests
import shutil

# Configuration
paper_version = "1.21.5"
paper_dir = os.path.abspath(".")  # current directory
paper_api = f"https://api.papermc.io/v2/projects/paper/versions/{paper_version}"

def get_latest_build():
    print("[INFO] Fetching latest build info from PaperMC API...")
    response = requests.get(paper_api)
    if response.status_code != 200:
        print("[ERROR] Failed to get version info.")
        return None

    builds = response.json().get("builds", [])
    if not builds:
        print("[ERROR] No builds found.")
        return None

    return max(builds)  # highest build number is the latest

def construct_jar_name(build):
    return f"paper-{paper_version}-{build}.jar"

def download_latest_jar(build):
    jar_name = construct_jar_name(build)
    url = f"{paper_api}/builds/{build}/downloads/{jar_name}"
    print(f"[INFO] Downloading latest Paper jar: {jar_name}")
    response = requests.get(url, stream=True)

    if response.status_code == 200:
        with open(os.path.join(paper_dir, jar_name), 'wb') as f:
            shutil.copyfileobj(response.raw, f)
        print("[INFO] Download complete.")
        return jar_name
    else:
        print("[ERROR] Failed to download the latest jar.")
        return None

def get_existing_jar():
    for filename in os.listdir(paper_dir):
        if filename.startswith("paper-") and filename.endswith(".jar"):
            return filename
    return None

def main():
    print(f"({get_current_time()}) Checking for updates...")
    latest_build = get_latest_build()
    if latest_build is None:
        return

    latest_jar = construct_jar_name(latest_build)
    existing_jar = get_existing_jar()

    if existing_jar == latest_jar:
        print("[INFO] Latest jar is already present. No update needed.")
    else:
        # Remove old jar(s)
        for filename in os.listdir(paper_dir):
            if filename.startswith("paper-") and filename.endswith(".jar"):
                print(f"[INFO] Removing old jar: {filename}")
                os.remove(os.path.join(paper_dir, filename))

        # Download new jar
        downloaded = download_latest_jar(latest_build)
        if not downloaded:
            print("[ERROR] Could not download latest jar.")
            return

    print("[INFO] Update check complete. Control returning to batch file.")

def get_current_time():
    from datetime import datetime
    return datetime.now().strftime("%H:%M:%S.%f")[:-3]

if __name__ == "__main__":
    main()

This downloads the latest Paper version and auto deletes the old one. Below is an example of how I use paper_updater.py with a windows batch file.

Code:
@echo off
setlocal enabledelayedexpansion
title Paper Minecraft Server Updater + Launcher

:: STEP 1: Check for updates
echo (%time%) Checking for updates...
python paper_updater.py

:: STEP 2: Find latest Paper jar
for /f "delims=" %%f in ('dir /b /a:-d /o-d "paper-*.jar"') do (
    set "jarname=%%f"
    goto launch_server
)

echo ERROR: No paper-*.jar file found!
pause
exit /b

:launch_server
:: STEP 3: Run the server in a loop if it crashes
:server_loop
echo (%time%) Starting Minecraft server using !jarname!...
"C:\Program Files\Java\jdk-24\bin\java.exe" -Xms8G -Xmx12G -jar "!jarname!" --nogui

echo (%time%) WARNING: Server stopped or crashed! Restarting in 5 seconds...
timeout /t 5
goto server_loop
 

electronicboy

Administrator
Staff member
Dec 11, 2021
321
18
68
28
Nothing is obfuscated, we just host our builds on CFs network now rather than distributing them ourselves; the v2 API should still work as-is for now, but you should migrate to the v3 API