File size: 6,002 Bytes
02f4a63 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | # ==============================================================================
# Stage 1: Build OpenRA from source (C#/.NET 8.0)
# ==============================================================================
FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS openra-build
RUN apt-get update && apt-get install -y --no-install-recommends \
make \
git \
libsdl2-dev \
libopenal-dev \
libfreetype-dev \
liblua5.1-0-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Clone OpenRA source from GitHub (works on HF Spaces where submodules aren't initialized)
ARG OPENRA_REPO=https://github.com/yxc20089/OpenRA.git
RUN git clone --depth=1 "$OPENRA_REPO" /src/openra
WORKDIR /src/openra
# Fix Windows CRLF line endings in shell scripts (git autocrlf on Windows adds \r)
RUN find . -name '*.sh' -exec sed -i 's/\r$//' {} + && \
find . -name '*.sh' -exec chmod +x {} +
# Build with system libraries (unix-generic avoids bundled native binaries)
# SKIP_PROTOC=true uses pre-generated protobuf C# files (avoids protoc arm64 crash in Docker)
ENV SKIP_PROTOC=true
RUN make TARGETPLATFORM=unix-generic CONFIGURATION=Release
# Verify critical output (includes Null platform for headless RL operation)
RUN test -f bin/OpenRA.dll && \
test -f bin/OpenRA.Game.dll && \
test -f bin/OpenRA.Mods.Common.dll && \
test -f bin/OpenRA.Platforms.Null.dll
# ==============================================================================
# Stage 2: Install Python dependencies
# ==============================================================================
FROM python:3.11-slim-bookworm AS python-build
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml /app/
COPY openra_env/ /app/openra_env/
COPY proto/ /app/proto/
COPY README.md /app/
RUN pip install --upgrade pip && \
pip install --no-cache-dir .
# ==============================================================================
# Stage 3: Runtime image
# ==============================================================================
FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS dotnet-runtime
FROM python:3.11-slim-bookworm
LABEL maintainer="OpenRA-RL"
LABEL description="OpenRA RL Environment - headless game engine with gRPC bridge + OpenEnv API"
# Copy ASP.NET Core runtime from official Microsoft image
COPY --from=dotnet-runtime /usr/share/dotnet /usr/share/dotnet
RUN ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb \
libgl1-mesa-dri \
libgl1-mesa-glx \
libegl-mesa0 \
mesa-vulkan-drivers \
libvulkan1 \
libsdl2-2.0-0 \
libopenal1 \
libfreetype6 \
liblua5.1-0 \
libicu72 \
curl procps \
x11vnc novnc websockify \
&& rm -rf /var/lib/apt/lists/*
# Copy Python packages from builder
COPY --from=python-build /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=python-build /usr/local/bin /usr/local/bin
# Copy built OpenRA (bin, mods, glsl shaders, and global mix database for content resolution)
COPY --from=openra-build /src/openra/bin /opt/openra/bin
COPY --from=openra-build /src/openra/mods /opt/openra/mods
COPY --from=openra-build /src/openra/glsl /opt/openra/glsl
COPY --from=openra-build ["/src/openra/global mix database.dat", "/opt/openra/global mix database.dat"]
# Create native library symlinks that OpenRA expects
# (configure-system-libraries.sh points these to system lib paths)
RUN LIBDIR=$( [ "$(dpkg --print-architecture)" = "arm64" ] && echo "/usr/lib/aarch64-linux-gnu" || echo "/usr/lib/x86_64-linux-gnu" ) && \
ln -sf "$LIBDIR/libSDL2-2.0.so.0" /opt/openra/bin/SDL2.so && \
ln -sf "$LIBDIR/libopenal.so.1" /opt/openra/bin/soft_oal.so && \
ln -sf "$LIBDIR/libfreetype.so.6" /opt/openra/bin/freetype6.so && \
ln -sf "$LIBDIR/liblua5.1.so.0" /opt/openra/bin/lua51.so
# Copy Python application code
COPY openra_env/ /app/openra_env/
COPY proto/ /app/proto/
COPY pyproject.toml /app/
# Create OpenRA support directory and pre-install RA game content (best-effort).
# Only needed for the replay viewer (Game.Platform=Default with full UI).
# The RL environment works without this content (headless mode).
RUN mkdir -p /root/.config/openra/Content/ra/v2/expand /root/.config/openra/Content/ra/v2/cnc && \
( curl -sfL --max-time 30 -o /tmp/ra-quickinstall.zip \
https://openra.baxxster.no/openra/ra-quickinstall.zip && \
apt-get update && apt-get install -y --no-install-recommends unzip && \
unzip -o /tmp/ra-quickinstall.zip -d /tmp/ra-content && \
cp /tmp/ra-content/*.mix /root/.config/openra/Content/ra/v2/ && \
cp /tmp/ra-content/expand/* /root/.config/openra/Content/ra/v2/expand/ && \
cp /tmp/ra-content/cnc/* /root/.config/openra/Content/ra/v2/cnc/ && \
rm -rf /tmp/ra-quickinstall.zip /tmp/ra-content && \
apt-get purge -y unzip && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* \
) || echo "WARNING: RA content download failed (replay viewer will be unavailable)"
# Copy entrypoints (fix Windows CRLF line endings)
COPY docker/entrypoint.sh /entrypoint.sh
COPY docker/replay-viewer.sh /replay-viewer.sh
RUN sed -i 's/\r$//' /entrypoint.sh /replay-viewer.sh && \
chmod +x /entrypoint.sh /replay-viewer.sh
# Environment
ENV OPENRA_PATH=/opt/openra
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
ENV DISPLAY=:99
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV DOTNET_ROLL_FORWARD=LatestMajor
ENV LIBGL_ALWAYS_SOFTWARE=1
ENV MESA_GL_VERSION_OVERRIDE=3.3
# Game configuration (override at runtime with -e)
ENV AI_SLOT=Multi0
ENV BOT_TYPE=normal
ENV RECORD_REPLAYS=true
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "-m", "openra_env.server.app"]
|