Files
SirStone ef16dd982d robocode_shim: generalize bridge to any legacy bot; validate 28 champions as sparring partners
Generalize the classic-Robocode shim so the hosted bot's main class, jar, extra
classpath and data directory are configurable (SHIM_BOT_CLASS / SHIM_BOT_JAR /
SHIM_EXTRA_CP / SHIM_DATA), with DrussGT kept as the default so every existing
script, fixture and generated bot dir behaves identically.

- LegacyBotBridge: generalized bridge (DrussGTBridge kept as an alias).
- BotHost: (mainClass, jar, extraJars, dataDir); disableShield -> generic
  disableStaticBoolean.
- ClassicPeer: implement ITeamRobotPeer; synthesize StatusEvent each turn;
  make move/turnBody/turnGun/turnRadar the immediate (turn-ending) variants;
  guard re-entrant execute() from event handlers; record delivered events.
- make_botdir.sh / run_bridge_battle.sh / run_smoke.sh generalized, legacy
  invocations unchanged; generated launcher uses a per-process mktemp data dir
  so concurrent bots/battles cannot clobber one classic data directory.

Validated 35 legacy bots against a real Tank Royale battle (2 rounds vs sample
SpinBot): 28 usable (27 effective + DrussGT), 5 weak-but-playing, 2 failing.
Adds robots.json (manifest) and LEGACY_BOTS.md (how-to, status, missing-API
costs). No third-party jar is committed.
2026-09-26 00:25:33 +02:00

151 lines
5.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Generate a Tank Royale bot directory that boots a classic Robocode robot
# through the robocode_shim bridge.
#
# tools/robocode_shim/make_botdir.sh [TARGET|NAME] \
# [--class FQCN] [--jar PATH] [--name DISPLAY] \
# [--version V] [--authors A] [--desc D] [--country CC] [--gametypes G]
#
# The first positional argument may be either
# * a directory path (legacy form, e.g. /tmp/tr_bots/DrussGT), or
# * a bare bot name, in which case the dir is /tmp/tr_bots/<NAME>.
# With no arguments at all it reproduces the original DrussGT directory.
#
# The generated directory contains only text files (<dir>.json + <dir>.sh); the
# third-party jars stay outside the repo and are referenced by absolute path.
#
# Defaults (so the original no-arg DrussGT invocation is byte-for-byte usable):
# --class jk.mega.DrussGT
# --jar $DRUSSGT_JAR (/tmp/drussgt/DrussGT.jar)
# display name = bot-dir basename, version parsed from the jar name (or 3.1.4159)
#
# Data-directory isolation: the generated launcher sets SHIM_DATA to a fresh
# per-process mktemp directory unless the caller already provided SHIM_DATA /
# DRUSSGT_DATA. Two bots (or two concurrent battles) therefore can never share
# or clobber one classic data directory.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TARGET=""
CLASS=""
JAR=""
DISPLAY=""
VERSION=""
AUTHORS=""
DESC=""
COUNTRY="se"
GAMETYPES="classic,1v1"
if [[ $# -gt 0 && "${1}" != --* ]]; then
TARGET="$1"; shift
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--class) CLASS="$2"; shift 2;;
--jar) JAR="$2"; shift 2;;
--name) DISPLAY="$2"; shift 2;;
--version) VERSION="$2"; shift 2;;
--authors) AUTHORS="$2"; shift 2;;
--desc) DESC="$2"; shift 2;;
--country) COUNTRY="$2"; shift 2;;
--gametypes) GAMETYPES="$2"; shift 2;;
-h|--help) sed -n '2,30p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0;;
*) echo "unknown argument: $1" >&2; exit 2;;
esac
done
# --- resolve target dir + name (legacy forms preserved) ---
if [[ -z "$TARGET" ]]; then
TARGET="/tmp/tr_bots/DrussGT"
elif [[ "$TARGET" != */* ]]; then
TARGET="/tmp/tr_bots/$TARGET"
fi
DIR_NAME="$(basename "$TARGET")"
DRUSSGT_JAR="${DRUSSGT_JAR:-/tmp/drussgt/DrussGT.jar}"
CLASS="${CLASS:-jk.mega.DrussGT}"
JAR="${JAR:-$DRUSSGT_JAR}"
NAME="${DISPLAY:-$DIR_NAME}"
# --- defaults that keep the DrussGT case identical to the old script ---
if [[ -z "$VERSION" ]]; then
if [[ "$CLASS" == "jk.mega.DrussGT" ]]; then
VERSION="3.1.4159"
else
stem="$(basename "$JAR")"; stem="${stem%.jar}"
if [[ "$stem" == *_* ]]; then VERSION="${stem##*_}"; else VERSION="1.0"; fi
fi
fi
[[ -n "$AUTHORS" ]] || { if [[ "$CLASS" == "jk.mega.DrussGT" ]]; then AUTHORS="Jacob"; else AUTHORS="unknown"; fi; }
[[ -n "$DESC" ]] || { if [[ "$CLASS" == "jk.mega.DrussGT" ]]; then
DESC="Real classic DrussGT running on Tank Royale via the robocode_shim bridge"
else
DESC="Classic Robocode robot ${CLASS} running on Tank Royale via the robocode_shim bridge"
fi; }
GAMETYPES_JSON="$(printf '%s' "$GAMETYPES" | sed 's/,/\", \"/g')"
ROBOCODE_JAR="${ROBOCODE_JAR:-/tmp/robocode/install/libs/robocode.jar}"
TR_BOT_API_JAR="${TR_BOT_API_JAR:-$HOME/Downloads/sample-bots-java-1.0.2/lib/robocode-tankroyale-bot-api-1.0.2.jar}"
OUT="${OUT:-$HERE/out}"
EXTRA_CP="${SHIM_EXTRA_CP:-}"
EXTRA_LINE=""
[[ -n "$EXTRA_CP" ]] && EXTRA_LINE="export SHIM_EXTRA_CP=\"$EXTRA_CP\""
mkdir -p "$TARGET"
cat > "$TARGET/$DIR_NAME.json" <<JSON
{
"name": "$NAME",
"version": "$VERSION",
"authors": ["$AUTHORS"],
"description": "$DESC",
"homepage": "",
"countryCodes": ["$COUNTRY"],
"gameTypes": ["$GAMETYPES_JSON"],
"platform": "JVM",
"programmingLang": "Java 8"
}
JSON
# The Tank Royale bot API reads bot identity from BOT_* environment variables.
# When the TR booter launches this directory it supplies them (derived from the
# .json above), but running this script BY HAND does not - and the API then
# rejects the handshake with "Required bot property 'name' is missing".
# Exporting them here makes the script work standalone as well.
#
# SHIM_BOT_CLASS / SHIM_BOT_JAR select the hosted classic robot. SHIM_DATA is a
# fresh per-process directory by default: two bots (or two concurrent battles)
# can never share or clobber the same classic data directory.
cat > "$TARGET/$DIR_NAME.sh" <<SH
#!/bin/sh
cd "\$(dirname "\$0")"
# Hosted classic robot selection - keep in sync with $DIR_NAME.json
export SHIM_BOT_CLASS="$CLASS"
export SHIM_BOT_JAR="$JAR"
$EXTRA_LINE
: "\${SHIM_DATA:=\${DRUSSGT_DATA:-\$(mktemp -d "\${TMPDIR:-/tmp}/tr_shim_data.XXXXXX")}}"
export SHIM_DATA
# Bot identity - keep in sync with $DIR_NAME.json
export BOT_NAME="$NAME"
export BOT_VERSION="$VERSION"
export BOT_AUTHORS="$AUTHORS"
export BOT_DESCRIPTION="$DESC"
export BOT_HOMEPAGE=""
export BOT_COUNTRY_CODES="$COUNTRY"
export BOT_GAME_TYPES="$GAMETYPES"
export BOT_PLATFORM="JVM"
export BOT_PROG_LANG="Java 8"
exec java -cp "$OUT:$ROBOCODE_JAR:$TR_BOT_API_JAR" robocode_shim.LegacyBotBridge
SH
chmod +x "$TARGET/$DIR_NAME.sh"
echo "bot dir ready: $TARGET"
echo " $TARGET/$DIR_NAME.json"
echo " $TARGET/$DIR_NAME.sh"
echo " class: $CLASS"
echo " jar: $JAR"
echo " (classpath: $OUT:$ROBOCODE_JAR:$TR_BOT_API_JAR)"