diff --git a/1.1/Dockerfile b/1.1/Dockerfile new file mode 100644 index 0000000..0689d04 --- /dev/null +++ b/1.1/Dockerfile @@ -0,0 +1,45 @@ +FROM frolvlad/alpine-glibc:alpine-3.12 + +LABEL maintainer="https://github.com/factoriotools/factorio-docker" + +ARG USER=factorio +ARG GROUP=factorio +ARG PUID=845 +ARG PGID=845 + +ENV PORT=34197 \ + RCON_PORT=27015 \ + VERSION=1.1.0 \ + SHA1=2356ca6f836312b6e77c86ac44699223f1dc3026 \ + SAVES=/factorio/saves \ + CONFIG=/factorio/config \ + MODS=/factorio/mods \ + SCENARIOS=/factorio/scenarios \ + SCRIPTOUTPUT=/factorio/script-output \ + PUID="$PUID" \ + PGID="$PGID" + +SHELL ["/bin/ash", "-eo", "pipefail", "-c"] +RUN set -ox pipefail \ + && archive="/tmp/factorio_headless_x64_$VERSION.tar.xz" \ + && mkdir -p /opt /factorio \ + && apk add --update --no-cache --no-progress bash binutils curl file gettext jq libintl pwgen shadow su-exec \ + && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/linux64" -o "$archive" \ + && echo "$SHA1 $archive" | sha1sum -c \ + || (sha1sum "$archive" && file "$archive" && exit 1) \ + && tar xf "$archive" --directory /opt \ + && chmod ugo=rwx /opt/factorio \ + && rm "$archive" \ + && ln -s "$SCENARIOS" /opt/factorio/scenarios \ + && ln -s "$SAVES" /opt/factorio/saves \ + && mkdir -p /opt/factorio/config/ \ + && addgroup -g "$PGID" -S "$GROUP" \ + && adduser -u "$PUID" -G "$GROUP" -s /bin/sh -SDH "$USER" \ + && chown -R "$USER":"$GROUP" /opt/factorio /factorio + +COPY files/*.sh / +COPY files/config.ini /opt/factorio/config/config.ini + +VOLUME /factorio +EXPOSE $PORT/udp $RCON_PORT/tcp +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/1.1/docker-compose.yml b/1.1/docker-compose.yml new file mode 100644 index 0000000..3ff6b50 --- /dev/null +++ b/1.1/docker-compose.yml @@ -0,0 +1,16 @@ +version: '2' +services: + factorio: + build: . + ports: + - "34197:34197/udp" + - "27015:27015/tcp" + volumes: + - /opt/factorio:/factorio +# environment: +# - PUID=1000 +# - PGID=1000 +# - UPDATE_MODS_ON_START=true +# - USERNAME=FactorioUsername +# - TOKEN=FactorioToken +# - PORT=34198 diff --git a/1.1/files/config.ini b/1.1/files/config.ini new file mode 100644 index 0000000..856063e --- /dev/null +++ b/1.1/files/config.ini @@ -0,0 +1,755 @@ +; version=8 +; This is INI file : https://en.wikipedia.org/wiki/INI_file#Format +; Semicolons (;) at the beginning of the line indicate a comment. Comment lines are ignored. +[path] +read-data=__PATH__executable__/../../data +write-data=__PATH__executable__/../.. + +[general] +locale= + +[other] +; Options: true, false +; verbose-logging=false + +; Options: true, false +; log-saving-statistics=false + +; autosave-interval=5 + +; autosave-slots=3 + +; In ticks +; minimum-latency-in-multiplayer=0 + +; In seconds +; multiplayer-initial-connection-timeout=10 + +; port=34197 + +; max-map-preview-chunk-side=64 + +; max-map-preview-threads=7 + +; In bytes +; max-multiplayer-script-reload-size=1048576 + +; Options: true, false +; enable-steam-networking=true + +; proxy= + +; proxy-username= + +; proxy-password= + +; Options: true, false +; check-updates=true + +; Options: true, false +; enable-experimental-updates=false + +; Options: true, false +; enable-new-mods=true + +; Options: true, false +; use-mod-settings-per-save=true + +; Options: true, false +; disable-minimal-mode=false + +; Options: true, false +; disable-blueprint-storage=false + +; Disables tracking which mod created/changed what prototype. Mainly for faster startup during development. +; +; Options: true, false +; disable-prototype-history=false + +; Print a warning for all prototype values that were not accessed. +; +; Options: true, false +; check-unused-prototype-data=false + +; Cache data stage prototype data for faster startup. Experimental. +; +; Options: true, false +; cache-prototype-data=false + +; Options: true, false +; enable-razer-chroma-support=true + +; Options: true, false +; enable-logitech-led-support=true + +; Options: true, false +; enable-crash-log-uploading=true + +; Options: true, false +; enable-heap-validation=true + +; Options: true, false +; enable-threaded-message-pump=true + +; Options: true, false +; enable-taskbar-animation=true + +; Does nothing on Windows +; +; Options: true, false +; non-blocking-saving=false + +; Related to MacOS +; +; Options: true, false +; discard-mouse-events-when-accessibility-zoomed=false + +; Options: true, false +; enable-blueprint-storage-cloud-sync=false + +; Options: true, false +; force-enable-factorio-version-check=false + +; Options: true, false +; bring-window-to-top-on-click=true + +; Options: fast, maximum +; multiplayer-compression-level=fast + +; Options: none, fast, maximum +; autosave-compression-level=fast + +; Socket to host RCON on when lauching MP server from the menu. +; local-rcon-socket=0.0.0.0:0 + +; Password for RCON when launching MP server from the menu. +; local-rcon-password= + + +[interface] +; Options: true, false +; automatic-ui-scale=true + +; custom-ui-scale=1.000000 + +; tooltip-delay=0.040000 + +; entity-tooltip-delay=0.000000 + +; tooltip-offset=20 + +; output-console-delay=1200 + +; train-stop-label-angle=0.085526 + +; active-quick-bars=2 + +; shortcut-bar-rows=2 + +; Options: true, false +; autosort-inventory=true + +; Options: true, false +; research-finished-stops-game=false + +; Options: true, false +; use-item-groups=true + +; Options: true, false +; use-item-subgroups=true + +; Options: true, false +; use-version-filter-in-browse-games-gui=true + +; Options: true, false +; use-version-filter-in-install-mods-gui=true + +; Options: true, false +; play-sound-for-chat-messages=true + +; Options: true, false +; fuzzy-search-enabled=false + +; Options: true, false +; pick-ghost-cursor=false + +; Options: true, false +; show-minimap=true + +; Options: true, false +; show-tips-and-tricks=true + +; Options: true, false +; show-tutorial-notifications=true + +; Options: true, false +; show-turret-radius-when-blueprinting=false + +; Options: true, false +; show-item-labels-in-cursor=true + +; Options: true, false +; show-rail-block-visualization=true + +; Options: true, false +; show-missing-logistic-network-icon=true + +; Options: true, false +; show-interaction-indications=true + +; Options: true, false +; show-grid-when-paused=true + +; Options: true, false +; show-inserter-arrows-when-selected=true + +; Options: true, false +; show-inserter-arrows-when-detailed-info-is-on=false + +; Options: true, false +; show-pump-arrows-when-detailed-info-is-on=true + +; Options: true, false +; show-mining-drill-arrows-when-detailed-info-is-on=true + +; Options: true, false +; show-combinator-settings-when-detailed-info-is-on=false + +; Options: true, false +; entity-tooltip-on-the-side=true + +; Options: true, false +; show-mod-owners-in-tooltips=true + +; Options: true, false +; show-descriptions-in-tooltips=true + +; Options: true, false +; show-total-raw-in-recipe-tooltips=true + +; debug-font-size=18 + +; train-visualization-length=5 + + +[sound] +; master-volume=0.800000 + +; music-volume=0.500000 + +; game-effects-volume=0.700000 + +; gui-effects-volume=0.600000 + +; walking-sound-volume=0.250000 + +; environment-sounds-volume=0.550000 + +; alerts-volume=0.500000 + +; wind-volume=0.350000 + +; audible-distance=40.000000 + +; environment-audible-distance=30.000000 + +; maximum-environment-sounds=50 + +; active-gui-volume-modifier=0.800000 + +; active-gui-environment-volume-modifier=0.400000 + +; The maximum volume allowed for any sound. +; maximum-volume=2.000000 + +; ambient-music-pause-mean-seconds=45.000000 + +; ambient-music-pause-variance-seconds=30.000000 + +; Options: main-tracks-only, interleave-main-tracks-with-interludes, randomize-all +; ambient-music-mode=interleave-main-tracks-with-interludes + +; zoom-audible-distance-coefficient=0.500000 + +; zoom-volume-coefficient=0.750000 + + +[map-view] +; Options: true, false +; show-logistic-network=false + +; Options: true, false +; show-electric-network=false + +; Options: true, false +; show-turret-range=false + +; Options: true, false +; show-pollution=true + +; Options: true, false +; show-networkless-logistic-members=false + +; Options: true, false +; show-train-station-names=true + +; Options: true, false +; show-player-names=true + +; Options: true, false +; show-non-standard-map-info=false + + +[debug] +; force=enemy + +; Options: true, false +; capture-perf-statistics=false + +; Options: always, debug, never +; show-fps=debug + +; Options: always, debug, never +; show-detailed-info=debug + +; Options: always, debug, never +; show-time-usage=debug + +; Options: always, debug, never +; show-gpu-time-usage=debug + +; Options: always, debug, never +; show-sprite-counts=never + +; Options: always, debug, never +; show-lua-object-statistics=never + +; Options: always, debug, never +; show-heat-buffer-info=never + +; Options: always, debug, never +; show-multiplayer-waiting-icon=debug + +; Options: always, debug, never +; show-multiplayer-statistics=debug + +; Options: always, debug, never +; show-multiplayer-selection-rectangles=never + +; Options: always, debug, never +; show-debug-info-in-tooltips=debug + +; Options: always, debug, never +; hide-mod-guis=never + +; Options: always, debug, never +; show-tile-grid=never + +; Options: always, debug, never +; show-collision-rectangles=never + +; Options: always, debug, never +; show-selection-rectangles=never + +; Options: always, debug, never +; show-render-rectangles=never + +; Options: always, debug, never +; show-entity-positions=never + +; Options: always, debug, never +; show-entity-velocities=never + +; Options: always, debug, never +; show-selected-entity-advanced-tiles=never + +; Options: always, debug, never +; show-selected-input-transport-belts=never + +; Options: always, debug, never +; show-paths=never + +; Options: always, debug, never +; show-path-requests=never + +; Options: always, debug, never +; show-next-waypoint-bb=never + +; Options: always, debug, never +; show-target=never + +; Options: always, debug, never +; show-unit-group-info=never + +; Options: always, debug, never +; show-unit-behavior-info=never + +; Options: always, debug, never +; show-pathfinder-fringe=never + +; Options: always, debug, never +; show-path-cache=never + +; Options: always, debug, never +; show-path-cache-paths=never + +; Options: always, debug, never +; show-rail-paths=never + +; Options: always, debug, never +; show-rolling-stock-count=never + +; Options: always, debug, never +; show-rail-connections=never + +; Options: always, debug, never +; show-rail-joints=never + +; Options: always, debug, never +; show-rail-signal-states=never + +; Options: always, debug, never +; show-rail-segment-collision-boxes=never + +; Options: always, debug, never +; show-train-stop-point=never + +; Options: always, debug, never +; show-train-braking-distance=never + +; Options: always, debug, never +; show-train-signals=never + +; Options: always, debug, never +; show-train-repathing=never + +; Options: always, debug, never +; show-network-connected-entities=never + +; Options: always, debug, never +; show-circuit-network-numbers=never + +; Options: always, debug, never +; show-energy-sources-networks=never + +; Options: always, debug, never +; show-active-state=never + +; Options: always, debug, never +; show-wakeup-lists=never + +; Options: always, debug, never +; show-transport-lines=never + +; Options: always, debug, never +; show-transport-line-gaps=never + +; Options: always, debug, never +; show-pollution-values=never + +; Options: always, debug, never +; show-active-entities-on-chunk-counts=never + +; Options: always, debug, never +; show-active-chunks=never + +; Options: always, debug, never +; show-polluted-chunks=never + +; Options: always, debug, never +; hide-chart-tags=never + +; Options: always, debug, never +; show-enemy-expansion-candidate-chunks=never + +; Options: always, debug, never +; show-enemy-expansion-candidate-chunk-values=never + +; Options: always, debug, never +; show-bad-attack-chunks=never + +; Options: always, debug, never +; show-tile-variations=never + +; Options: always, debug, never +; show-raw-tile-transitions=never + +; Options: always, debug, never +; show-fluid-box-fluid-info=never + +; Options: always, debug, never +; show-environment-sound-info=never + +; Options: always, debug, never +; show-environment-sound-area=never + +; Options: always, debug, never +; show-selected-entity-audible-range=never + +; Options: always, debug, never +; show-recently-played-sound-info=never + +; Options: always, debug, never +; show-logistic-robot-targets=never + +; Options: always, debug, never +; show-logistic-robots-on-map=never + +; Options: always, debug, never +; show-recipe-icons-on-map=never + +; Options: always, debug, never +; show-player-robots=never + +; Options: always, debug, never +; show-fire-info=never + +; Options: always, debug, never +; show-sticker-info=never + +; Options: always, debug, never +; show-decorative-names=never + +; Options: always, debug, never +; show-decorative-collision-rectangles=never + +; Options: always, debug, never +; allow-increased-zoom=never + +; Options: always, debug, never +; show-chunk-components=never + + +[multiplayer-lobby] +; name= + +; description= + +; Options: true, false +; visibility-public=true + +; Options: true, false +; visibility-steam=true + +; Options: true, false +; visibility-lan=true + +; max-players=0 + +; Options: true, false +; ignore-player-limit-when-returning=false + +; max-upload-in-kilobytes-per-second=0 + +; max-upload-slots=5 + +; password= + +; tag-list= + +; afk-auto-kick=0 + +; Options: true, false, admins-only +; allowed-commands=admins-only + +; Options: true, false +; only-admins-can-pause=true + +; Options: true, false +; autosave-only-on-server=true + +; Options: true, false +; non-blocking-saving=true + +; Options: true, false +; verify-user-identity=true + +; Options: true, false +; enable-whitelist=false + + +[graphics] +; lights-render-quality=0.250000 + +; Default preferred display index should force finding primary monitor +; preferred-display-index=255 + +; screenshots-threads-count=8 + +; cache-sprite-atlas-count=1 + +; Options: true, false +; cache-sprite-atlas=false + +; Options: true, false +; compress-sprite-atlas-cache=false + +; Options: true, false +; texture-streaming=true + +; streamed-atlas-physical-vram-size=0 + +; sprite-vertex-buffer-size=1048576 + +; max-texture-size=0 + +; max-threads=8 + +; 'low' and 'very-low' options are deprecated and will be migrated to 'normal' +; +; Options: high, normal, low, very-low +; graphics-quality=normal + +; brightness=0 + +; contrast=0 + +; saturation=100 + +; Options: true, false +; full-screen=true + +; Options: true, false +; minimize-on-focus-loss=false + +; Options: true, false +; show-smoke=true + +; Options: true, false +; show-clouds=true + +; Options: true, false +; show-decoratives=true + +; Options: true, false +; show-particles=true + +; Options: true, false +; show-item-shadows=true + +; Options: true, false +; show-inserter-shadows=true + +; Options: true, false +; show-animated-water=true + +; Options: true, false +; show-tree-distortion=true + +; Options: true, false +; force-opengl=false + +; Options: true, false +; v-sync=true + +; Options: true, false +; high-quality-animations=true + +; Options: true, false +; high-quality-shadows=false + +; Options: true, false +; high-quality-terrain=true + +; Minimum number of turrets required to turn on the turret range overdraw optimization +; turret-overdraw-minimum-count=4 + +; Scale at which the turret range overdraw optimization will start being applied +; turret-overdraw-scale-threshold=0.200000 + +; Options: true, false +; skip-vram-detection=false + +; Options: true, false +; halt-rendering-when-minimized=true + +; Options: true, false +; runtime-sprite-reload=false + +; Options: true, false +; full-color-depth=true + +; Options: true, false +; render-in-native-resolution=true + +; Options: true, false +; use-flip-presentation-model=false + +; Options: true, false +; debug-api=false + +; Options: true, false +; discard-buffers-on-begin-frame=true + +; Options: all, high, medium, low +; video-memory-usage=high + +; Options: none, high-quality, low-quality +; texture-compression-level=high-quality + +; Options: true, false +; compress-virtual-atlas=true + +; Options: copy, copy-sequential, flip, flip-discard +; dxgi-presentation-model=copy + +; Options: none, flush, wait-for-vblank, flush-and-wait-for-vblank +; dxgi-action-before-present=none + +; relevant only for flip presentation models +; +; Options: true, false +; dxgi-allow-tearing=false + +; Options: false, true, auto +; dxgi-flip-do-not-wait=false + +; Options: true, false +; dxgi-present-restart=false + +; dxgi-swap-chain-buffer-count=0 + +; dxgi-max-frame-latency=0 + +; dxgi-adapter-index=-1 + +; max-sprite-loading-threads=32 + +; Options: true, false +; gpu-accelerated-compression=true + +; Options: true, false +; gpu-accelerated-mipmap-compression=true + +; Options: true, false +; wait-until-mipmap-generation-finished=true + +; Options: true, false +; check-for-unused-pixels=false + +; ogl-depth-buffer-bit-depth=0 + +; Options: false, true, auto +; ogl-accelerated-renderer=auto + +; Options: true, false +; ogl-double-buffered=true + +; Set to true if mipmapped sprites render very blurry on your GPU. Limited support. +; +; Options: true, false +; legacy-gpu-no-mipmaps=false + +; Options: true, false +; force-linear-magnification=false + +; Options: true, false +; custom-mipmap-workaround=false + +; Options: true, false +; buffer-rename-workaround=false + +; Comma separated list of OpenGL extensions that should not be used (for example: ARB_copy_image,KHR_debug) +; disabled-opengl-extensions= + + diff --git a/1.1/files/docker-entrypoint.sh b/1.1/files/docker-entrypoint.sh new file mode 100755 index 0000000..ccd7273 --- /dev/null +++ b/1.1/files/docker-entrypoint.sh @@ -0,0 +1,98 @@ +#!/bin/bash +set -eoux pipefail + +FACTORIO_VOL=/factorio +LOAD_LATEST_SAVE="${LOAD_LATEST_SAVE:-true}" +GENERATE_NEW_SAVE="${GENERATE_NEW_SAVE:-false}" +SAVE_NAME="${SAVE_NAME:-""}" + +mkdir -p "$FACTORIO_VOL" +mkdir -p "$SAVES" +mkdir -p "$CONFIG" +mkdir -p "$MODS" +mkdir -p "$SCENARIOS" +mkdir -p "$SCRIPTOUTPUT" + +if [[ ! -f $CONFIG/rconpw ]]; then + # Generate a new RCON password if none exists + pwgen 15 1 >"$CONFIG/rconpw" +fi + +if [[ ! -f $CONFIG/server-settings.json ]]; then + # Copy default settings if server-settings.json doesn't exist + cp /opt/factorio/data/server-settings.example.json "$CONFIG/server-settings.json" +fi + +if [[ ! -f $CONFIG/map-gen-settings.json ]]; then + cp /opt/factorio/data/map-gen-settings.example.json "$CONFIG/map-gen-settings.json" +fi + +if [[ ! -f $CONFIG/map-settings.json ]]; then + cp /opt/factorio/data/map-settings.example.json "$CONFIG/map-settings.json" +fi + +NRTMPSAVES=$( find -L "$SAVES" -iname \*.tmp.zip -mindepth 1 | wc -l ) +if [[ $NRTMPSAVES -gt 0 ]]; then + # Delete incomplete saves (such as after a forced exit) + rm -f "$SAVES"/*.tmp.zip +fi + +if [[ ${UPDATE_MODS_ON_START:-} == "true" ]]; then + ./docker-update-mods.sh +fi + +if [[ $(id -u) = 0 ]]; then + # Update the User and Group ID based on the PUID/PGID variables + usermod -o -u "$PUID" factorio + groupmod -o -g "$PGID" factorio + # Take ownership of factorio data if running as root + chown -R factorio:factorio "$FACTORIO_VOL" + # Drop to the factorio user + SU_EXEC="su-exec factorio" +else + SU_EXEC="" +fi + +sed -i '/write-data=/c\write-data=\/factorio/' /opt/factorio/config/config.ini + +NRSAVES=$(find -L "$SAVES" -iname \*.zip -mindepth 1 | wc -l) +if [[ $GENERATE_NEW_SAVE != true && $NRSAVES == 0 ]]; then + GENERATE_NEW_SAVE=true + SAVE_NAME=_autosave1 +fi + +if [[ $GENERATE_NEW_SAVE == true ]]; then + if [[ -z "$SAVE_NAME" ]]; then + echo "If \$GENERATE_NEW_SAVE is true, you must specify \$SAVE_NAME" + exit 1 + fi + if [[ -f "$SAVES/$SAVE_NAME.zip" ]]; then + echo "Map $SAVES/$SAVE_NAME.zip already exists, skipping map generation" + else + $SU_EXEC /opt/factorio/bin/x64/factorio \ + --create "$SAVES/$SAVE_NAME.zip" \ + --map-gen-settings "$CONFIG/map-gen-settings.json" \ + --map-settings "$CONFIG/map-settings.json" + fi +fi + +FLAGS=(\ + --port "$PORT" \ + --server-settings "$CONFIG/server-settings.json" \ + --server-banlist "$CONFIG/server-banlist.json" \ + --rcon-port "$RCON_PORT" \ + --server-whitelist "$CONFIG/server-whitelist.json" \ + --use-server-whitelist \ + --server-adminlist "$CONFIG/server-adminlist.json" \ + --rcon-password "$(cat "$CONFIG/rconpw")" \ + --server-id /factorio/config/server-id.json \ +) + +if [[ $LOAD_LATEST_SAVE == true ]]; then + FLAGS+=( --start-server-load-latest ) +else + FLAGS+=( --start-server "$SAVE_NAME" ) +fi + +# shellcheck disable=SC2086 +exec $SU_EXEC /opt/factorio/bin/x64/factorio "${FLAGS[@]}" "$@" diff --git a/1.1/files/docker-update-mods.sh b/1.1/files/docker-update-mods.sh new file mode 100755 index 0000000..bd3a223 --- /dev/null +++ b/1.1/files/docker-update-mods.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -eou pipefail + +if [[ -f /run/secrets/username ]]; then + USERNAME=$(cat /run/secrets/username) +fi + +if [[ -f /run/secrets/token ]]; then + TOKEN=$(cat /run/secrets/token) +fi + +if [[ -z ${USERNAME:-} ]]; then + USERNAME="$(jq -j ".username" "$CONFIG/server-settings.json")" +fi + +if [[ -z ${TOKEN:-} ]]; then + TOKEN="$(jq -j ".token" "$CONFIG/server-settings.json")" +fi + +if [[ -z ${USERNAME:-} ]]; then + echo "You need to provide your Factorio username to update mods." +fi + +if [[ -z ${TOKEN:-} ]]; then + echo "You need to provide your Factorio token to update mods." +fi + +./update-mods.sh "$VERSION" "$MODS" "$USERNAME" "$TOKEN" diff --git a/1.1/files/scenario.sh b/1.1/files/scenario.sh new file mode 100755 index 0000000..bafac0b --- /dev/null +++ b/1.1/files/scenario.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -eoux pipefail + +if [[ -z ${1:-} ]]; then + echo "No argument supplied" +fi + +SERVER_SCENARIO="$1" +mkdir -p "$SAVES" +mkdir -p "$CONFIG" +mkdir -p "$MODS" +mkdir -p "$SCENARIOS" + +#chown -R factorio /factorio + +if [[ ! -f $CONFIG/rconpw ]]; then + pwgen 15 1 >"$CONFIG/rconpw" +fi + +if [[ ! -f $CONFIG/server-settings.json ]]; then + cp /opt/factorio/data/server-settings.example.json "$CONFIG/server-settings.json" +fi + +if [[ ! -f $CONFIG/map-gen-settings.json ]]; then + cp /opt/factorio/data/map-gen-settings.example.json "$CONFIG/map-gen-settings.json" +fi + +if [[ ! -f $CONFIG/map-settings.json ]]; then + cp /opt/factorio/data/map-settings.example.json "$CONFIG/map-settings.json" +fi + +exec /opt/factorio/bin/x64/factorio \ + --port "$PORT" \ + --start-server-load-scenario "$SERVER_SCENARIO" \ + --map-gen-settings "$CONFIG/map-gen-settings.json" \ + --map-settings "$CONFIG/map-settings.json" \ + --server-settings "$CONFIG/server-settings.json" \ + --server-banlist "$CONFIG/server-banlist.json" \ + --server-whitelist "$CONFIG/server-whitelist.json" \ + --use-server-whitelist \ + --server-adminlist "$CONFIG/server-adminlist.json" \ + --rcon-port "$RCON_PORT" \ + --rcon-password "$(cat "$CONFIG/rconpw")" \ + --server-id /factorio/config/server-id.json diff --git a/1.1/files/scenario2map.sh b/1.1/files/scenario2map.sh new file mode 100755 index 0000000..94c4dd2 --- /dev/null +++ b/1.1/files/scenario2map.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -eoux pipefail + +if [[ -z ${1:-} ]]; then + echo "No argument supplied" +fi + +SERVER_SCENARIO="$1" +mkdir -p "$SAVES" +mkdir -p "$CONFIG" +mkdir -p "$MODS" +mkdir -p "$SCENARIOS" + +if [[ ! -f $CONFIG/server-settings.json ]]; then + cp /opt/factorio/data/server-settings.example.json "$CONFIG/server-settings.json" +fi + +if [[ ! -f $CONFIG/map-gen-settings.json ]]; then + cp /opt/factorio/data/map-gen-settings.example.json "$CONFIG/map-gen-settings.json" +fi + +if [[ ! -f $CONFIG/map-settings.json ]]; then + cp /opt/factorio/data/map-settings.example.json "$CONFIG/map-settings.json" +fi + +exec /opt/factorio/bin/x64/factorio \ + --scenario2map "$SERVER_SCENARIO" diff --git a/1.1/files/update-mods.sh b/1.1/files/update-mods.sh new file mode 100755 index 0000000..20bfffe --- /dev/null +++ b/1.1/files/update-mods.sh @@ -0,0 +1,96 @@ +#!/bin/bash +set -eou pipefail + +FACTORIO_VERSION=$1 +MOD_DIR=$2 +USERNAME=$3 +TOKEN=$4 + +MOD_BASE_URL="https://mods.factorio.com" + +print_step() +{ + echo "$1" +} + +print_success() +{ + echo "$1" +} + +print_failure() +{ + echo "$1" +} + +update_mod() +{ + MOD_NAME="$1" + MOD_NAME_ENCODED="${1// /%20}" + + print_step "Checking for update of mod $MOD_NAME..." + + MOD_INFO_URL="$MOD_BASE_URL/api/mods/$MOD_NAME_ENCODED" + MOD_INFO_JSON=$(curl --silent "$MOD_INFO_URL") + + if ! echo "$MOD_INFO_JSON" | jq -e .name >/dev/null; then + print_success " Custom mod not on $MOD_BASE_URL, skipped." + return 0 + fi + + MOD_INFO=$(echo "$MOD_INFO_JSON" | jq -j --arg version "$FACTORIO_VERSION" ".releases|reverse|map(select(.info_json.factorio_version as \$mod_version | \$version | startswith(\$mod_version)))[0]|.file_name, \";\", .download_url, \";\", .sha1") + + MOD_FILENAME=$(echo "$MOD_INFO" | cut -f1 -d";") + MOD_URL=$(echo "$MOD_INFO" | cut -f2 -d";") + MOD_SHA1=$(echo "$MOD_INFO" | cut -f3 -d";") + + if [[ $MOD_FILENAME == null ]]; then + print_failure " Not compatible with version" + return 0 + fi + + if [[ -f $MOD_DIR/$MOD_FILENAME ]]; then + print_success " Already up-to-date." + return 0 + fi + + print_step "Downloading..." + FULL_URL="$MOD_BASE_URL$MOD_URL?username=$USERNAME&token=$TOKEN" + HTTP_STATUS=$(curl --silent -L -w "%{http_code}" -o "$MOD_DIR/$MOD_FILENAME" "$FULL_URL") + + if [[ $HTTP_STATUS != 200 ]]; then + print_failure " Download failed: Code $HTTP_STATUS." + rm -f "$MOD_DIR/$MOD_FILENAME" + return 1 + fi + + if [[ ! -f $MOD_DIR/$MOD_FILENAME ]]; then + print_failure " Downloaded file missing!" + return 1 + fi + + if ! [[ $(sha1sum "$MOD_DIR/$MOD_FILENAME") =~ $MOD_SHA1 ]]; then + print_failure " SHA1 mismatch!" + rm -f "$MOD_DIR/$MOD_FILENAME" + return 1 + fi + + print_success " Download complete." + + for file in "$MOD_DIR/${MOD_NAME}_"*".zip"; do # wildcard does usually not work in quotes: https://unix.stackexchange.com/a/67761 + if [[ $file != $MOD_DIR/$MOD_FILENAME ]]; then + print_success " Deleting old version: $file" + rm -f "$file" + fi + done + + return 0 +} + +if [[ -f $MOD_DIR/mod-list.json ]]; then + jq -r ".mods|map(select(.enabled))|.[].name" "$MOD_DIR/mod-list.json" | while read -r mod; do + if [[ $mod != base ]]; then + update_mod "$mod" + fi + done +fi