Skip to content
Draft
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e27d913
save and load from factorio
hrshtt Jul 27, 2025
e831c7f
python port
hrshtt Jul 27, 2025
9fc3bbb
added environment
hrshtt Jul 27, 2025
b951905
consolidated image creation and scenario2map approaches
hrshtt Jul 27, 2025
6f1adec
linting fixes
hrshtt Jul 27, 2025
dcf30c0
defaulting to saves
hrshtt Jul 27, 2025
4258838
cleaner
hrshtt Jul 27, 2025
52754fb
minor changes
hrshtt Jul 28, 2025
3e3ffdd
moved to aiodocker
hrshtt Jul 28, 2025
92b955d
more async
hrshtt Jul 28, 2025
11dd335
even more async
hrshtt Jul 28, 2025
778b899
clean up
hrshtt Jul 28, 2025
44d9529
fixed rcon issue
hrshtt Jul 28, 2025
05506fd
new location for factorio-server structure
hrshtt Jul 28, 2025
285c626
added hot reloading control.lua
hrshtt Jul 28, 2025
c8ce309
FactorioInstance refactor
hrshtt Jul 29, 2025
46d3902
moved script loading
hrshtt Jul 29, 2025
46c2de1
moved script loading even more
hrshtt Jul 29, 2025
a9b6586
tests passing
hrshtt Jul 29, 2025
7921aea
minor fixes all actions tests passed
hrshtt Jul 29, 2025
124bbe2
formatted, no change
hrshtt Jul 29, 2025
d088d11
api changes + verbose set_speed method
hrshtt Jul 29, 2025
99e5a21
minor changes
hrshtt Jul 29, 2025
ed24b00
dir/module name change
hrshtt Jul 29, 2025
f48bc22
api change
hrshtt Jul 29, 2025
b284424
minor changes
hrshtt Jul 29, 2025
743921a
moved factorio_server out
hrshtt Jul 30, 2025
cbfec2a
Merge remote-tracking branch 'upstream/main' into factorio_native_save
hrshtt Jul 30, 2025
caff3c8
moved run_envs to fle/env
hrshtt Jul 30, 2025
778a400
cleanup
hrshtt Jul 30, 2025
fcfef79
moved mods and tools to fle/env/factorio
hrshtt Jul 30, 2025
79ae1cd
minor update + remove script for now
hrshtt Jul 30, 2025
c938a7c
restructure
hrshtt Jul 31, 2025
46a0c9e
remove cluster directory
hrshtt Jul 31, 2025
8bc383e
client goes to game
hrshtt Jul 31, 2025
05a012e
import path changes
hrshtt Jul 31, 2025
437116d
added config + path changes
hrshtt Jul 31, 2025
f0799f4
wow
hrshtt Aug 7, 2025
d9f9f7b
a lotta things
hrshtt Aug 12, 2025
a9788d6
generic-ify
hrshtt Aug 12, 2025
4404fea
even more changes
hrshtt Aug 12, 2025
8796a70
renaming factorio_server & namespace
hrshtt Aug 12, 2025
35aa145
snapshot driven eval
hrshtt Aug 13, 2025
88768bc
minor changes
hrshtt Aug 13, 2025
706e843
minor changes
hrshtt Aug 13, 2025
fb050de
shifting code around
hrshtt Aug 13, 2025
929fb63
minor changes
hrshtt Aug 13, 2025
226e6b7
explicit semantics
hrshtt Aug 13, 2025
a102069
make it run
hrshtt Aug 13, 2025
7607d7c
rm
hrshtt Aug 13, 2025
c5e3eb5
fixes to be able to run
hrshtt Aug 13, 2025
2d5000f
redo fixtures
hrshtt Aug 14, 2025
bd58368
update tests
hrshtt Aug 14, 2025
0060f6f
almost there
hrshtt Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 112 additions & 20 deletions fle/cluster/local/run-envs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ setup_platform() {
ARCH=$(uname -m)
OS=$(uname -s)
if [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then
export DOCKER_PLATFORM="linux/arm64"
export DOCKER_PLATFORM="linux/amd64"
Comment thread
hrshtt marked this conversation as resolved.
Outdated
else
export DOCKER_PLATFORM="linux/amd64"
fi
export SAVES_PATH="../../../.fle/saves"
# Detect OS for mods path
if [[ "$OS" == *"MINGW"* ]] || [[ "$OS" == *"MSYS"* ]] || [[ "$OS" == *"CYGWIN"* ]]; then
# Windows detected
Expand Down Expand Up @@ -38,15 +39,42 @@ setup_compose_cmd() {
fi
}

# Function to check for saves and find the latest one
check_saves_and_get_latest() {
# Check if saves directory exists
if [ ! -d "$SAVES_PATH" ]; then
echo "Error: Saves directory not found at $SAVES_PATH"
exit 1
fi

# Add the specified number of factorio services
for i in $(seq 0 $(($NUM_INSTANCES - 1))); do
if ! ls "$SAVES_PATH/${i}"/*.zip 1> /dev/null 2>&1; then
echo "Error: No .zip save files found in $SAVES_PATH/${i} for instance $i"
exit 1
fi
done

# Find the latest save file based on modification time
LATEST_SAVE=$(ls -t "$SAVES_PATH"/*.zip | head -1)
LATEST_SAVE_NAME=$(basename "$LATEST_SAVE")

echo "Found latest save: $LATEST_SAVE_NAME"
echo "Using save path: $SAVES_PATH"
}

# Generate the dynamic docker-compose.yml file
generate_compose_file() {
NUM_INSTANCES=${1:-1}
SCENARIO=${2:-"default_lab_scenario"}
USE_LATEST_SAVE=${3:-false}

# Validate scenario
if [ "$SCENARIO" != "open_world" ] && [ "$SCENARIO" != "default_lab_scenario" ]; then
echo "Error: Scenario must be either 'open_world' or 'default_lab_scenario'."
exit 1
# Validate scenario if not using latest save
if [ "$USE_LATEST_SAVE" = "false" ]; then
if [ "$SCENARIO" != "open_world" ] && [ "$SCENARIO" != "default_lab_scenario" ]; then
echo "Error: Scenario must be either 'open_world' or 'default_lab_scenario'."
exit 1
fi
fi

# Validate input
Expand All @@ -60,6 +88,18 @@ generate_compose_file() {
exit 1
fi

# Determine the command based on whether to use latest save or scenario
if [ "$USE_LATEST_SAVE" = "true" ]; then
# Add the specified number of factorio services
for i in $(seq 0 $(($NUM_INSTANCES - 1))); do
mkdir -p ${SAVES_PATH}/${i}
done

START_COMMAND="--start-server-load-latest"
else
START_COMMAND="--start-server-load-scenario ${SCENARIO}"
fi

# Create the docker-compose file
cat > docker-compose.yml << EOF
version: '3'
Expand All @@ -76,7 +116,7 @@ EOF
factorio_${i}:
image: factorio
platform: \${DOCKER_PLATFORM:-linux/amd64}
command: /opt/factorio/bin/x64/factorio --start-server-load-scenario ${SCENARIO}
command: /opt/factorio/bin/x64/factorio ${START_COMMAND}
--port 34197 --server-settings /opt/factorio/config/server-settings.json --map-gen-settings
/opt/factorio/config/map-gen-settings.json --map-settings /opt/factorio/config/map-settings.json
--server-banlist /opt/factorio/config/server-banlist.json --rcon-port 27015
Expand Down Expand Up @@ -115,30 +155,51 @@ EOF
- source: ../../data/_screenshots
target: /opt/factorio/script-output
type: bind
- source: ${SAVES_PATH}/${i}
target: /opt/factorio/saves
type: bind

EOF
done

echo "Generated docker-compose.yml with $NUM_INSTANCES Factorio instance(s) using scenario $SCENARIO"
if [ "$USE_LATEST_SAVE" = "true" ]; then
echo "Generated docker-compose.yml with $NUM_INSTANCES Factorio instance(s) using latest save"
else
echo "Generated docker-compose.yml with $NUM_INSTANCES Factorio instance(s) using scenario $SCENARIO"
fi
}

# Function to start Factorio cluster
start_cluster() {
NUM_INSTANCES=$1
SCENARIO=$2
USE_LATEST_SAVE=$3

setup_platform
setup_compose_cmd

# Check for saves if using latest save mode
if [ "$USE_LATEST_SAVE" = "true" ]; then
check_saves_and_get_latest
fi

# Generate the docker-compose file
generate_compose_file "$NUM_INSTANCES" "$SCENARIO"
generate_compose_file "$NUM_INSTANCES" "$SCENARIO" "$USE_LATEST_SAVE"

# Run the docker-compose file
echo "Starting $NUM_INSTANCES Factorio instance(s) with scenario $SCENARIO..."
if [ "$USE_LATEST_SAVE" = "true" ]; then
echo "Starting $NUM_INSTANCES Factorio instance(s) with latest save..."
else
echo "Starting $NUM_INSTANCES Factorio instance(s) with scenario $SCENARIO..."
fi
export NUM_INSTANCES # Make it available to docker-compose
$COMPOSE_CMD -f docker-compose.yml up -d

echo "Factorio cluster started with $NUM_INSTANCES instance(s) using platform $DOCKER_PLATFORM and scenario $SCENARIO"
if [ "$USE_LATEST_SAVE" = "true" ]; then
echo "Factorio cluster started with $NUM_INSTANCES instance(s) using platform $DOCKER_PLATFORM and latest save"
else
echo "Factorio cluster started with $NUM_INSTANCES instance(s) using platform $DOCKER_PLATFORM and scenario $SCENARIO"
fi
}

# Function to stop Factorio cluster
Expand Down Expand Up @@ -169,23 +230,35 @@ restart_cluster() {
# Extract the number of instances
CURRENT_INSTANCES=$(grep -c "factorio_" docker-compose.yml)

# Extract the scenario from the first instance
CURRENT_SCENARIO=$(grep -A1 "command:" docker-compose.yml | grep "start-server-load-scenario" | head -1 | sed -E 's/.*start-server-load-scenario ([^ ]+).*/\1/')

if [ -z "$CURRENT_SCENARIO" ]; then
CURRENT_SCENARIO="default_lab_scenario"
echo "Warning: Could not determine current scenario, using default: $CURRENT_SCENARIO"
# Check if using latest save or scenario
if grep -q "start-server-load-latest" docker-compose.yml; then
CURRENT_MODE="latest_save"
echo "Found cluster using latest save mode"
else
CURRENT_MODE="scenario"
# Extract the scenario from the first instance
CURRENT_SCENARIO=$(grep -A1 "command:" docker-compose.yml | grep "start-server-load-scenario" | head -1 | sed -E 's/.*start-server-load-scenario ([^ ]+).*/\1/')

if [ -z "$CURRENT_SCENARIO" ]; then
CURRENT_SCENARIO="default_lab_scenario"
echo "Warning: Could not determine current scenario, using default: $CURRENT_SCENARIO"
fi
echo "Found cluster with scenario: $CURRENT_SCENARIO"
fi

echo "Found cluster with $CURRENT_INSTANCES instances using scenario: $CURRENT_SCENARIO"
echo "Found cluster with $CURRENT_INSTANCES instances"

# Stop the current cluster
echo "Stopping current cluster..."
$COMPOSE_CMD -f docker-compose.yml down

# Start with the same configuration
echo "Restarting cluster..."
start_cluster "$CURRENT_INSTANCES" "$CURRENT_SCENARIO"
if [ "$CURRENT_MODE" = "latest_save" ]; then
start_cluster "$CURRENT_INSTANCES" "" "true"
else
start_cluster "$CURRENT_INSTANCES" "$CURRENT_SCENARIO" "false"
fi

echo "Factorio cluster restarted successfully."
}
Expand All @@ -203,20 +276,29 @@ show_help() {
echo "Options:"
echo " -n NUMBER Number of Factorio instances to run (1-33, default: 1)"
echo " -s SCENARIO Scenario to run (open_world or default_lab_scenario, default: default_lab_scenario)"
echo " -l Use latest save instead of scenario (loads most recent .zip save from ../../../.fle/saves/0..n)"
echo ""
echo "Examples:"
echo " $0 Start 1 instance with default_lab_scenario"
echo " $0 -n 5 Start 5 instances with default_lab_scenario"
echo " $0 -n 3 -s open_world Start 3 instances with open_world"
echo " $0 -l Start 1 instance with latest save"
echo " $0 -n 5 -l Start 5 instances with latest save"
echo " $0 start -n 10 -s open_world Start 10 instances with open_world"
echo " $0 stop Stop all running instances"
echo " $0 restart Restart the current cluster"
echo ""
echo "Note: When using -l (latest save), the system will:"
echo " 1. Check for .zip save files in ../../../.fle/saves/0..n"
echo " 2. Finds the most recently modified save file"
echo " 3. Start the server with --start-server-load-latest"
}

# Main script execution
COMMAND="start"
NUM_INSTANCES=1
SCENARIO="default_lab_scenario"
USE_LATEST_SAVE=false

# Check if first arg is a command
if [[ "$1" == "start" || "$1" == "stop" || "$1" == "restart" || "$1" == "help" ]]; then
Expand All @@ -225,7 +307,7 @@ if [[ "$1" == "start" || "$1" == "stop" || "$1" == "restart" || "$1" == "help" ]
fi

# Parse options with getopts
while getopts ":n:s:h" opt; do
while getopts ":n:s:lh" opt; do
case ${opt} in
n )
if ! [[ "$OPTARG" =~ ^[0-9]+$ ]]; then
Expand All @@ -241,6 +323,9 @@ while getopts ":n:s:h" opt; do
fi
SCENARIO=$OPTARG
;;
l )
USE_LATEST_SAVE=true
;;
h )
show_help
exit 0
Expand All @@ -259,10 +344,17 @@ while getopts ":n:s:h" opt; do
done
shift $((OPTIND -1))

# Validate that scenario and latest save are not used together
if [ "$USE_LATEST_SAVE" = "true" ] && [ "$SCENARIO" != "default_lab_scenario" ]; then
echo "Error: Cannot use both -l (latest save) and -s (scenario) options together."
echo "When using -l, the scenario option is ignored as the server loads the latest save."
exit 1
fi

# Execute the appropriate command
case "$COMMAND" in
start)
start_cluster "$NUM_INSTANCES" "$SCENARIO"
start_cluster "$NUM_INSTANCES" "$SCENARIO" "$USE_LATEST_SAVE"
;;
stop)
stop_cluster
Expand Down