mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
feat: enhance decompilation and server management scripts
- Introduced `decompile.sh` to automate the decompilation process, including downloading `MinecraftDecompiler.jar` and server.jar for specified Minecraft versions. - Added `mc-rcon.sh` for sending RCON commands to a Minecraft server, improving server management capabilities. - Created `mcc-env.sh` to provide helper functions for managing Minecraft servers, including starting, stopping, and sending commands. - Implemented `start-server.sh` to launch a Minecraft server in a tmux session with a named pipe for stdin, facilitating easier command input. - Updated `README.md` to reflect new tools and usage instructions for decompiling and server management. These changes streamline the workflow for adapting to new Minecraft versions and enhance the overall development experience.
This commit is contained in:
parent
9e3bfaa868
commit
cca4134e8b
6 changed files with 301 additions and 11 deletions
|
|
@ -10,13 +10,12 @@ Systematic workflow for updating Minecraft Console Client to support a new Minec
|
|||
## Prerequisites
|
||||
|
||||
- Decompiled server source for both the old and new MC versions in `$MCC_REPO/MinecraftOfficial/<version>-decompiled/`
|
||||
- If missing, decompile first:
|
||||
- If missing, decompile and download server.jar:
|
||||
```bash
|
||||
cd $MCC_REPO/MinecraftOfficial
|
||||
java -jar MinecraftDecompiler.jar --version <ver> --side SERVER \
|
||||
--decompile --output <ver>-remapped.jar --decompiled-output <ver>-decompiled
|
||||
$MCC_REPO/tools/decompile.sh --version <ver>
|
||||
```
|
||||
- A test server of the target version in `$MCC_SERVERS/` (see `mcc-dev-workflow` skill)
|
||||
This auto-downloads `MinecraftDecompiler.jar` if needed, produces the decompiled source, and downloads `server.jar` into `$MCC_SERVERS/<ver>/`.
|
||||
- A test server of the target version in `$MCC_SERVERS/<version>/` (see `mcc-dev-workflow` skill)
|
||||
|
||||
## Step 0: Generate Server Reports (CRITICAL since 1.21.9)
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ Systematic workflow for updating Minecraft Console Client to support a new Minec
|
|||
|
||||
```bash
|
||||
cd /tmp && java -DbundlerMainClass=net.minecraft.data.Main \
|
||||
-jar $MCC_SERVERS/<version>-Vanilla/server.jar \
|
||||
-jar $MCC_SERVERS/<version>/server.jar \
|
||||
--reports --output /tmp/mc_reports
|
||||
```
|
||||
|
||||
|
|
@ -186,7 +185,37 @@ Compare key packet codec classes between versions. Known changes:
|
|||
|
||||
When in doubt, compare the relevant packet class (e.g. `ClientboundAddEntityPacket.java`) between versions.
|
||||
|
||||
## Step 8: Compile and Verify
|
||||
## Step 8: Update Block Collision Shapes (Physics Engine)
|
||||
|
||||
MCC's physics engine uses block collision shape data from PrismarineJS `minecraft-data` to perform accurate AABB collision detection (stored in `MinecraftClient/Physics/BlockShapeData.json`, embedded as a resource).
|
||||
|
||||
When a new MC version introduces new blocks or changes block shapes, update this data:
|
||||
|
||||
```bash
|
||||
# Download and compact collision shapes for the target version
|
||||
python3 $MCC_REPO/tools/gen_block_shapes.py <version>
|
||||
# e.g. python3 tools/gen_block_shapes.py 1.21.11
|
||||
```
|
||||
|
||||
If network is slow or unreliable, download the file manually and convert:
|
||||
```bash
|
||||
# Manual download
|
||||
curl -L -o /tmp/bcs.json \
|
||||
"https://raw.githubusercontent.com/PrismarineJS/minecraft-data/master/data/pc/<version>/blockCollisionShapes.json"
|
||||
|
||||
# Then compact from local file
|
||||
python3 $MCC_REPO/tools/gen_block_shapes.py --from-file /tmp/bcs.json
|
||||
```
|
||||
|
||||
Output: `MinecraftClient/Physics/BlockShapeData.json` (embedded via `MinecraftClient.csproj`)
|
||||
|
||||
The JSON maps block names (snake_case) → collision shape IDs → AABB coordinates. At runtime, `BlockShapes.cs` maps MCC's block state IDs to these AABBs using the block palette.
|
||||
|
||||
**When to update**: Whenever new blocks are added that have non-trivial collision shapes (e.g., new slab variants, stairs, fences). If only items or entities changed, this step can be skipped.
|
||||
|
||||
**Data source**: PrismarineJS `minecraft-data` repo, path: `data/pc/<version>/blockCollisionShapes.json`. Version availability can be checked via `data/dataPaths.json`.
|
||||
|
||||
## Step 9: Compile and Verify
|
||||
|
||||
```bash
|
||||
dotnet build $MCC_REPO/MinecraftClient.sln -c Release
|
||||
|
|
@ -244,3 +273,4 @@ All scripts are in `$MCC_REPO/tools/`. See `tools/README.md` for detailed usage.
|
|||
| `gen_block_palette.py` | Generate BlockPalette C# | blocks.json |
|
||||
| `gen_entity_palette.py` | Generate EntityPalette C# | registries.json |
|
||||
| `gen_entity_metadata_palette.py` | Generate EntityMetadataPalette C# | Decompiled source |
|
||||
| `gen_block_shapes.py` | Download & compact block collision shapes | PrismarineJS minecraft-data |
|
||||
|
|
|
|||
|
|
@ -18,17 +18,21 @@ Two types of data can be used as input:
|
|||
### Decompiling a new MC version
|
||||
|
||||
```bash
|
||||
cd MinecraftOfficial
|
||||
java -jar MinecraftDecompiler.jar --version 1.21.9 --side SERVER \
|
||||
--decompile --output 1.21.9-remapped.jar --decompiled-output 1.21.9-decompiled
|
||||
# Server side (default) — also downloads server.jar into MinecraftOfficial/downloads/<ver>/
|
||||
tools/decompile.sh --version 1.21.9
|
||||
|
||||
# Client side
|
||||
tools/decompile.sh --version 1.21.9 --side CLIENT
|
||||
```
|
||||
|
||||
The script auto-downloads `MinecraftDecompiler.jar` from GitHub releases if it doesn't exist.
|
||||
|
||||
### Generating server data reports
|
||||
|
||||
```bash
|
||||
cd /tmp
|
||||
java -DbundlerMainClass=net.minecraft.data.Main \
|
||||
-jar /path/to/server.jar \
|
||||
-jar $MCC_SERVERS/<version>/server.jar \
|
||||
--reports --output /tmp/mc_reports
|
||||
```
|
||||
|
||||
|
|
|
|||
138
tools/decompile.sh
Normal file
138
tools/decompile.sh
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
#!/bin/bash
|
||||
# Download (if needed) and run MinecraftDecompiler to produce decompiled source
|
||||
# and server.jar for a given Minecraft version.
|
||||
#
|
||||
# Usage:
|
||||
# ./tools/decompile.sh --version <ver> [--side SERVER|CLIENT]
|
||||
#
|
||||
# Examples:
|
||||
# ./tools/decompile.sh --version 1.21.11
|
||||
# ./tools/decompile.sh --version 1.21.11 --side CLIENT
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
MC_OFFICIAL="$REPO_ROOT/MinecraftOfficial"
|
||||
DECOMPILER_JAR="$MC_OFFICIAL/MinecraftDecompiler.jar"
|
||||
DECOMPILER_REPO="MaxPixelStudios/MinecraftDecompiler"
|
||||
|
||||
VERSION=""
|
||||
SIDE="SERVER"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2 ;;
|
||||
--side) SIDE="$(echo "$2" | tr '[:lower:]' '[:upper:]')"; shift 2 ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 --version <ver> [--side SERVER|CLIENT]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --version <ver> Minecraft version (e.g. 1.21.11)"
|
||||
echo " --side <env> SERVER (default) or CLIENT"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "Error: --version is required"
|
||||
echo "Usage: $0 --version <ver> [--side SERVER|CLIENT]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SIDE" != "SERVER" && "$SIDE" != "CLIENT" ]]; then
|
||||
echo "Error: --side must be SERVER or CLIENT (got: $SIDE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Ensure MinecraftDecompiler.jar exists ---
|
||||
if [[ ! -f "$DECOMPILER_JAR" ]]; then
|
||||
echo "MinecraftDecompiler.jar not found, downloading latest release..."
|
||||
DOWNLOAD_URL=$(curl -sL "https://api.github.com/repos/$DECOMPILER_REPO/releases/latest" \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
for a in data['assets']:
|
||||
if a['name'] == 'MinecraftDecompiler.jar':
|
||||
print(a['browser_download_url'])
|
||||
break
|
||||
")
|
||||
if [[ -z "$DOWNLOAD_URL" ]]; then
|
||||
echo "Error: could not find MinecraftDecompiler.jar in latest release"
|
||||
exit 1
|
||||
fi
|
||||
echo "Downloading from $DOWNLOAD_URL ..."
|
||||
curl -L -o "$DECOMPILER_JAR" "$DOWNLOAD_URL"
|
||||
echo "Downloaded MinecraftDecompiler.jar"
|
||||
fi
|
||||
|
||||
# --- Build output paths ---
|
||||
SIDE_LOWER="$(echo "$SIDE" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [[ "$SIDE" == "SERVER" ]]; then
|
||||
REMAPPED_JAR="$MC_OFFICIAL/remapped_jar/${VERSION}-remapped.jar"
|
||||
DECOMPILED_DIR="$MC_OFFICIAL/${VERSION}-decompiled"
|
||||
else
|
||||
REMAPPED_JAR="$MC_OFFICIAL/remapped_jar/${VERSION}-${SIDE_LOWER}-remapped.jar"
|
||||
DECOMPILED_DIR="$MC_OFFICIAL/${VERSION}-${SIDE_LOWER}-decompiled"
|
||||
fi
|
||||
|
||||
if [[ -d "$DECOMPILED_DIR" ]]; then
|
||||
echo "Decompiled source already exists: $DECOMPILED_DIR"
|
||||
echo "Delete it first if you want to re-decompile."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$MC_OFFICIAL/remapped_jar"
|
||||
|
||||
echo "=== Decompiling Minecraft $VERSION ($SIDE) ==="
|
||||
echo " Remapped JAR: $REMAPPED_JAR"
|
||||
echo " Decompiled: $DECOMPILED_DIR"
|
||||
echo ""
|
||||
|
||||
cd "$MC_OFFICIAL"
|
||||
java -jar "$DECOMPILER_JAR" \
|
||||
--version "$VERSION" \
|
||||
--side "$SIDE" \
|
||||
--decompile \
|
||||
--output "$REMAPPED_JAR" \
|
||||
--decompiled-output "$DECOMPILED_DIR"
|
||||
|
||||
echo ""
|
||||
echo "=== Done ==="
|
||||
echo "Decompiled source: $DECOMPILED_DIR"
|
||||
|
||||
# --- For SERVER side, also ensure downloads/<ver>/server.jar exists ---
|
||||
if [[ "$SIDE" == "SERVER" ]]; then
|
||||
DOWNLOADS_DIR="$MC_OFFICIAL/downloads/$VERSION"
|
||||
if [[ ! -f "$DOWNLOADS_DIR/server.jar" ]]; then
|
||||
mkdir -p "$DOWNLOADS_DIR"
|
||||
# MinecraftDecompiler downloads the original jar into its cache;
|
||||
# extract it from the bundled remapped jar or re-download via manifest.
|
||||
echo ""
|
||||
echo "Downloading server.jar for $VERSION into $DOWNLOADS_DIR ..."
|
||||
MANIFEST_URL="https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"
|
||||
VERSION_URL=$(curl -sL "$MANIFEST_URL" | python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
for v in data['versions']:
|
||||
if v['id'] == '$VERSION':
|
||||
print(v['url'])
|
||||
break
|
||||
")
|
||||
if [[ -n "$VERSION_URL" ]]; then
|
||||
SERVER_JAR_URL=$(curl -sL "$VERSION_URL" | python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
print(data['downloads']['server']['url'])
|
||||
")
|
||||
curl -L -o "$DOWNLOADS_DIR/server.jar" "$SERVER_JAR_URL"
|
||||
echo "Downloaded server.jar"
|
||||
else
|
||||
echo "Warning: could not find version $VERSION in Mojang manifest; server.jar not downloaded."
|
||||
fi
|
||||
else
|
||||
echo "server.jar already exists: $DOWNLOADS_DIR/server.jar"
|
||||
fi
|
||||
fi
|
||||
46
tools/mc-rcon.sh
Normal file
46
tools/mc-rcon.sh
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
# Send an RCON command to a Minecraft server
|
||||
# Usage: mc-rcon.sh <command> [port] [password]
|
||||
set -euo pipefail
|
||||
|
||||
CMD="${1:?Usage: mc-rcon.sh <command> [port] [password]}"
|
||||
PORT="${2:-25575}"
|
||||
PW="${3:-test123}"
|
||||
|
||||
python3 -c "
|
||||
import socket, struct, sys
|
||||
|
||||
s = socket.socket()
|
||||
s.settimeout(5)
|
||||
try:
|
||||
s.connect(('localhost', $PORT))
|
||||
except Exception as e:
|
||||
print(f'Connection failed: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def send(req_id, pkt_type, body):
|
||||
body = body.encode()
|
||||
s.send(struct.pack('<iii', 10 + len(body), req_id, pkt_type) + body + b'\x00\x00')
|
||||
|
||||
def recv():
|
||||
length = struct.unpack('<i', s.recv(4))[0]
|
||||
data = b''
|
||||
while len(data) < length:
|
||||
data += s.recv(length - len(data))
|
||||
return data
|
||||
|
||||
send(1, 3, '$PW')
|
||||
r = recv()
|
||||
rid = struct.unpack('<i', r[:4])[0]
|
||||
if rid == -1:
|
||||
print('Auth failed', file=sys.stderr)
|
||||
s.close()
|
||||
sys.exit(1)
|
||||
|
||||
send(2, 2, \"\"\"$CMD\"\"\")
|
||||
r = recv()
|
||||
body = r[8:-2].decode(errors='replace')
|
||||
if body:
|
||||
print(body)
|
||||
s.close()
|
||||
"
|
||||
33
tools/mcc-env.sh
Normal file
33
tools/mcc-env.sh
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
# MCC (Minecraft Console Client) Development Utilities
|
||||
# Source this file to get helper functions: source $MCC_REPO/tools/mcc-env.sh
|
||||
# Or add to ~/.bashrc: source "$HOME/Minecraft/Minecraft-Console-Client-milutinke/tools/mcc-env.sh"
|
||||
|
||||
TOOLS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
export MCC_REPO="$(cd "$TOOLS_DIR/.." && pwd)"
|
||||
export MCC_SERVERS="$MCC_REPO/MinecraftOfficial/downloads"
|
||||
|
||||
# Helper: convert version to tmux session name (dots -> underscores)
|
||||
_mc-session() { echo "mc-${1//\./_}"; }
|
||||
|
||||
# --- Minecraft Server Management ---
|
||||
mc-start() { "$MCC_REPO/tools/start-server.sh" "${1:-1.20.6}"; }
|
||||
mc-stop() { local v="${1:-1.20.6}"; echo "stop" > "$MCC_SERVERS/$v/stdin.pipe"; }
|
||||
mc-cmd() { local v="${2:-1.20.6}"; echo "$1" > "$MCC_SERVERS/$v/stdin.pipe"; }
|
||||
mc-log() { local s; s=$(_mc-session "${1:-1.20.6}"); tmux capture-pane -t "$s" -p -S "-${2:-50}"; }
|
||||
mc-kill() { local v="${1:-1.20.6}" s; s=$(_mc-session "$v"); tmux kill-session -t "$s" 2>/dev/null; rm -f "$MCC_SERVERS/$v/stdin.pipe"; echo "Killed $s"; }
|
||||
mc-list() { tmux list-sessions 2>/dev/null | grep "^mc-" || echo "No running MC servers"; }
|
||||
|
||||
# --- RCON ---
|
||||
mc-rcon() { "$MCC_REPO/tools/mc-rcon.sh" "$@"; }
|
||||
|
||||
# --- MCC Build/Run ---
|
||||
mcc-build() { dotnet build "$MCC_REPO/MinecraftClient.sln" -c Release; }
|
||||
mcc-run() { cd "$MCC_REPO" && MCC_FILE_INPUT=1 dotnet run --project MinecraftClient -c Release -- CursorBot - "localhost:${1:-25565}" 2>&1; }
|
||||
mcc-cmd() { echo "$1" >> "$MCC_REPO/mcc_input.txt"; }
|
||||
mcc-kill() { pkill -f "MinecraftClient" 2>/dev/null && echo "MCC killed" || echo "No MCC process found"; }
|
||||
mcc-reload() {
|
||||
mcc-kill
|
||||
sleep 1
|
||||
mcc-build && mcc-run
|
||||
}
|
||||
39
tools/start-server.sh
Normal file
39
tools/start-server.sh
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
# Start a Minecraft server in a tmux session with named pipe for stdin
|
||||
# Servers live in MinecraftOfficial/downloads/<version>/ alongside the downloaded server.jar
|
||||
VERSION="${1}"
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DOWNLOADS="$REPO_ROOT/MinecraftOfficial/downloads"
|
||||
DIR="$DOWNLOADS/$VERSION"
|
||||
PIPE="$DIR/stdin.pipe"
|
||||
SESSION="mc-${VERSION//\./_}"
|
||||
|
||||
if [ -z "$VERSION" ] || [ ! -d "$DIR" ]; then
|
||||
echo "Error: Server directory not found${VERSION:+: $DIR}"
|
||||
echo "Available versions:"
|
||||
ls "$DOWNLOADS" | grep -E '^[0-9]' | sort -V
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$DIR/server.jar" ]; then
|
||||
echo "Error: No server.jar in $DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
echo "Server $VERSION already running in tmux session '$SESSION'"
|
||||
echo "View output: tmux capture-pane -t '$SESSION' -p -S -50"
|
||||
echo "Send command: echo 'say hello' > $PIPE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f "$DIR/world/session.lock"
|
||||
|
||||
[ -p "$PIPE" ] || mkfifo "$PIPE"
|
||||
|
||||
tmux new-session -d -s "$SESSION" -c "$DIR" \
|
||||
"tail -f $PIPE | java -Xmx2G -Xms2G -jar server.jar nogui 2>&1"
|
||||
|
||||
echo "Server $VERSION started in tmux session '$SESSION'"
|
||||
echo "Send commands: echo 'say hello' > $PIPE"
|
||||
echo "View output: tmux capture-pane -t '$SESSION' -p -S -50"
|
||||
Loading…
Add table
Add a link
Reference in a new issue