From b7571738f5af167813026c0d47a9562c35e5c607 Mon Sep 17 00:00:00 2001 From: Leonard Jonathan Oh Date: Sat, 22 Oct 2022 19:51:42 +0000 Subject: [PATCH] Enhancement (ESAI): Add `esai-helper apply|delete default-strategy` subcommand to easily apply a default ESAI strategy --- README.md | 27 ++- .../v1.5-bf2hub-bf2stats-2/docker-compose.yml | 4 +- .../v1.5-bf2hub-spoofed/docker-compose.yml | 4 +- docs/examples/v1.5-bf2hub/docker-compose.yml | 4 +- .../v1.5-bf2stats-2/docker-compose.yml | 4 +- .../v1.5-bf2stats-3/docker-compose.yml | 4 +- .../docker-compose.yml | 9 +- .../docker-compose.yml | 14 +- .../docker-compose.yml | 10 +- docs/examples/v1.5/docker-compose.yml | 4 +- generate/templates/README.md.ps1 | 27 ++- variants/v1.5.3153.0-bf2hub/esai-helper | 191 ++++++++++++------ .../v1.5.3153.0-bf2stats-2.3.3/esai-helper | 191 ++++++++++++------ .../v1.5.3153.0-bf2stats-3.1.1/esai-helper | 191 ++++++++++++------ variants/v1.5.3153.0-fh2-4.6.304/esai-helper | 191 ++++++++++++------ variants/v1.5.3153.0/esai-helper | 191 ++++++++++++------ vendor/esai-helper | 191 ++++++++++++------ 17 files changed, 851 insertions(+), 406 deletions(-) diff --git a/README.md b/README.md index 8c151af..6c31f5c 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/readmes/pb_e ESAI greatly enhances bot performance, and is compatible with any BF2 mod. It is included but not enabled by default. -A handy tool called [`esai-helper`](vendor/esai-helper) is included in all images. It can be used to generate maplists for a mod, list gamemodes, list a levels' `strategies.ai`, apply custom `strategies.ai` to levels, and more. See `esai-helper --help` for usage. +A handy tool called [`esai-helper`](vendor/esai-helper) is included in all images. It can be used to list gamemodes, generate maplists for a mod, list a levels' `strategies.ai`, apply default or custom `strategies.ai` to levels, and more. See `esai-helper --help` for usage. To use a default strategy for all levels, see [this example](docs/examples/v1.5-esai-default-strategy/). @@ -83,3 +83,28 @@ To override the default strategy with a level-specific strategy, optimized strat To use optimized strategies for levels, see [this example](docs/examples/v1.5-esai-optimized-strategies/). To use custom strategies for levels, see [example](docs/examples/v1.5-esai-custom-strategies/). + +```sh +# Read ESAI readmes +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/readme.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/directory.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/docs/credits.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat "/server/bf2/mods/bf2/esai/docs/quick start.txt" +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat "/server/bf2/mods/bf2/esai/docs/users guide.txt" +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/docs/version.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/mapfiles/dir.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/plugin/dir.txt + +# esai-helper useful one-liners +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --help # See usage +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get gamemodes # Get gamemodes +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get levels # Get levels +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get maplist # Generate a maplist for maplist.con +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get mods # Get mods +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get strategies # Get strategies +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply default-strategy # Apply a default strategy +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply # Apply a strategy for a level +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 delete # Delete a strategy for a level +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply -f strategies.txt # Apply strategies for levels +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 delete -f strategies.txt # Delete strategies for levels +``` diff --git a/docs/examples/v1.5-bf2hub-bf2stats-2/docker-compose.yml b/docs/examples/v1.5-bf2hub-bf2stats-2/docker-compose.yml index 2bc0f3b..51ea4e5 100644 --- a/docs/examples/v1.5-bf2hub-bf2stats-2/docker-compose.yml +++ b/docs/examples/v1.5-bf2hub-bf2stats-2/docker-compose.yml @@ -8,8 +8,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist - ./config/bf2/python/bf2/BF2StatisticsConfig-custom.py:/server/bf2/python/bf2/BF2StatisticsConfig.py:ro # bf2stats python config diff --git a/docs/examples/v1.5-bf2hub-spoofed/docker-compose.yml b/docs/examples/v1.5-bf2hub-spoofed/docker-compose.yml index 50fb6cf..74a2b7d 100644 --- a/docs/examples/v1.5-bf2hub-spoofed/docker-compose.yml +++ b/docs/examples/v1.5-bf2hub-spoofed/docker-compose.yml @@ -8,8 +8,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist ports: diff --git a/docs/examples/v1.5-bf2hub/docker-compose.yml b/docs/examples/v1.5-bf2hub/docker-compose.yml index 85581a7..1e84db0 100644 --- a/docs/examples/v1.5-bf2hub/docker-compose.yml +++ b/docs/examples/v1.5-bf2hub/docker-compose.yml @@ -7,8 +7,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist ports: diff --git a/docs/examples/v1.5-bf2stats-2/docker-compose.yml b/docs/examples/v1.5-bf2stats-2/docker-compose.yml index 1bb8474..b83a636 100644 --- a/docs/examples/v1.5-bf2stats-2/docker-compose.yml +++ b/docs/examples/v1.5-bf2stats-2/docker-compose.yml @@ -8,8 +8,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist - ./config/bf2/python/bf2/BF2StatisticsConfig-custom.py:/server/bf2/python/bf2/BF2StatisticsConfig.py:ro # bf2stats python config diff --git a/docs/examples/v1.5-bf2stats-3/docker-compose.yml b/docs/examples/v1.5-bf2stats-3/docker-compose.yml index 6fd81c6..15c6d1d 100644 --- a/docs/examples/v1.5-bf2stats-3/docker-compose.yml +++ b/docs/examples/v1.5-bf2stats-3/docker-compose.yml @@ -8,8 +8,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist - ./config/bf2/python/bf2/BF2StatisticsConfig-custom.py:/server/bf2/python/bf2/BF2StatisticsConfig.py:ro # bf2stats python config diff --git a/docs/examples/v1.5-esai-custom-strategies/docker-compose.yml b/docs/examples/v1.5-esai-custom-strategies/docker-compose.yml index 2a18425..5bf0ff5 100644 --- a/docs/examples/v1.5-esai-custom-strategies/docker-compose.yml +++ b/docs/examples/v1.5-esai-custom-strategies/docker-compose.yml @@ -1,12 +1,14 @@ version: '2.2' services: + # This is the official BF2 1.5 dedicated server. It does not work unless DNS spoofing is added. + # A default ESAI strategy for all maps, and custom ESAI strategies for maps are configured in entrypoint bf2: image: startersclan/docker-bf2:v1.5.3153.0 volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/strategies.txt:/strategies.txt # Custom ESAI strategies for levels - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist @@ -23,7 +25,8 @@ services: - -c - | set -eu - esai-helper apply -f /strategies.txt + esai-helper --mod bf2 apply default-strategy mediumfca + esai-helper --mod bf2 apply -f /strategies.txt exec ./start.sh" networks: diff --git a/docs/examples/v1.5-esai-default-strategy/docker-compose.yml b/docs/examples/v1.5-esai-default-strategy/docker-compose.yml index 28165b3..845a97d 100644 --- a/docs/examples/v1.5-esai-default-strategy/docker-compose.yml +++ b/docs/examples/v1.5-esai-default-strategy/docker-compose.yml @@ -1,12 +1,14 @@ version: '2.2' services: + # This is the official BF2 1.5 dedicated server. It does not work unless DNS spoofing is added. + # A default ESAI strategy for all maps is configured in entrypoint bf2: image: startersclan/docker-bf2:v1.5.3153.0 volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist ports: @@ -16,6 +18,14 @@ services: - default tty: true stdin_open: true + entrypoint: + - /bin/bash + command: + - -c + - | + set -eu + esai-helper --mod bf2 apply default-strategy mediumfca + exec ./start.sh" networks: default: diff --git a/docs/examples/v1.5-esai-optimized-strategies/docker-compose.yml b/docs/examples/v1.5-esai-optimized-strategies/docker-compose.yml index 9551adb..a3316b3 100644 --- a/docs/examples/v1.5-esai-optimized-strategies/docker-compose.yml +++ b/docs/examples/v1.5-esai-optimized-strategies/docker-compose.yml @@ -1,12 +1,15 @@ version: '2.2' services: + # This is the official BF2 1.5 dedicated server. It does not work unless DNS spoofing is added. + # A default ESAI strategy is configured in entrypoint + # In addition, optimized ESAI strategies are configured in entrypoint bf2: image: startersclan/docker-bf2:v1.5.3153.0 volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist ports: @@ -22,7 +25,8 @@ services: - -c - | set -eu - esai-helper apply -f /esai-optimized-strategies-bf2.txt + esai-helper --mod bf2 apply default-strategy mediumfca + esai-helper --mod bf2 apply -f /esai-optimized-strategies-bf2.txt exec ./start.sh" networks: diff --git a/docs/examples/v1.5/docker-compose.yml b/docs/examples/v1.5/docker-compose.yml index 39314ea..8478f97 100644 --- a/docs/examples/v1.5/docker-compose.yml +++ b/docs/examples/v1.5/docker-compose.yml @@ -6,8 +6,8 @@ services: volumes: - ./config/bf2/mods/bf2/ai/aidefault-custom.ai:/server/bf2/mods/bf2/ai/aidefault.ai:ro # Customize bots - ./config/bf2/mods/bf2/ai/aibehaviours-fixlookatwrapper.ai:/server/bf2/mods/bf2/ai/aibehaviours.ai:ro # LoopAtWrapper fix - # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps - # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps + # - ./config/bf2/mods/bf2/ai/aidefaultstrategies-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategies.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca + # - ./config/bf2/mods/bf2/ai/aidefaultstrategiesadd-custom-esai.ai:/server/bf2/mods/bf2/ai/aidefaultstrategiesadd.ai:ro # Enable ESAI with a default strategy for all maps. The same can be achieved using: esai-helper apply default-strategy mediumfca - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist ports: diff --git a/generate/templates/README.md.ps1 b/generate/templates/README.md.ps1 index 4d812f5..eec97ff 100644 --- a/generate/templates/README.md.ps1 +++ b/generate/templates/README.md.ps1 @@ -88,7 +88,7 @@ docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/readmes/pb_e ESAI greatly enhances bot performance, and is compatible with any BF2 mod. It is included but not enabled by default. -A handy tool called [`esai-helper`](vendor/esai-helper) is included in all images. It can be used to generate maplists for a mod, list gamemodes, list a levels' `strategies.ai`, apply custom `strategies.ai` to levels, and more. See `esai-helper --help` for usage. +A handy tool called [`esai-helper`](vendor/esai-helper) is included in all images. It can be used to list gamemodes, generate maplists for a mod, list a levels' `strategies.ai`, apply default or custom `strategies.ai` to levels, and more. See `esai-helper --help` for usage. To use a default strategy for all levels, see [this example](docs/examples/v1.5-esai-default-strategy/). @@ -98,5 +98,30 @@ To use optimized strategies for levels, see [this example](docs/examples/v1.5-es To use custom strategies for levels, see [example](docs/examples/v1.5-esai-custom-strategies/). +```sh +# Read ESAI readmes +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/readme.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/directory.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/docs/credits.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat "/server/bf2/mods/bf2/esai/docs/quick start.txt" +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat "/server/bf2/mods/bf2/esai/docs/users guide.txt" +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/docs/version.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/mapfiles/dir.txt +docker run --rm startersclan/docker-bf2:v1.5.3153.0 cat /server/bf2/mods/bf2/esai/plugin/dir.txt + +# esai-helper useful one-liners +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --help # See usage +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get gamemodes # Get gamemodes +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get levels # Get levels +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get maplist # Generate a maplist for maplist.con +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get mods # Get mods +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 get strategies # Get strategies +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply default-strategy # Apply a default strategy +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply # Apply a strategy for a level +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 delete # Delete a strategy for a level +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 apply -f strategies.txt # Apply strategies for levels +docker run --rm startersclan/docker-bf2:v1.5.3153.0 esai-helper --mod bf2 delete -f strategies.txt # Delete strategies for levels +``` + '@ diff --git a/variants/v1.5.3153.0-bf2hub/esai-helper b/variants/v1.5.3153.0-bf2hub/esai-helper index e62223c..85dbf42 100755 --- a/variants/v1.5.3153.0-bf2hub/esai-helper +++ b/variants/v1.5.3153.0-bf2hub/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi diff --git a/variants/v1.5.3153.0-bf2stats-2.3.3/esai-helper b/variants/v1.5.3153.0-bf2stats-2.3.3/esai-helper index e62223c..85dbf42 100755 --- a/variants/v1.5.3153.0-bf2stats-2.3.3/esai-helper +++ b/variants/v1.5.3153.0-bf2stats-2.3.3/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi diff --git a/variants/v1.5.3153.0-bf2stats-3.1.1/esai-helper b/variants/v1.5.3153.0-bf2stats-3.1.1/esai-helper index e62223c..85dbf42 100755 --- a/variants/v1.5.3153.0-bf2stats-3.1.1/esai-helper +++ b/variants/v1.5.3153.0-bf2stats-3.1.1/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi diff --git a/variants/v1.5.3153.0-fh2-4.6.304/esai-helper b/variants/v1.5.3153.0-fh2-4.6.304/esai-helper index e62223c..85dbf42 100755 --- a/variants/v1.5.3153.0-fh2-4.6.304/esai-helper +++ b/variants/v1.5.3153.0-fh2-4.6.304/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi diff --git a/variants/v1.5.3153.0/esai-helper b/variants/v1.5.3153.0/esai-helper index e62223c..85dbf42 100755 --- a/variants/v1.5.3153.0/esai-helper +++ b/variants/v1.5.3153.0/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi diff --git a/vendor/esai-helper b/vendor/esai-helper index e62223c..85dbf42 100755 --- a/vendor/esai-helper +++ b/vendor/esai-helper @@ -2,7 +2,7 @@ set -eu usage() { - echo "$0: Get and apply ESAI Strategies.ai in levels//server.zip" + echo "esai-helper: Get and apply ESAI Strategies.ai in levels//server.zip" echo "Options:" echo " -d|--dir BF2 server installation directory. Defaults to '/server/bf2'" echo " -m|--mod Mod. E.g. 'bf2' or 'xpack'. Defaults to 'bf2'" @@ -17,25 +17,29 @@ usage() { echo " levels Get all available levels" echo " mods Get all available mods" echo " strategies Get all available ESAI strategies" - echo " apply|delete [options] [arg...]" - echo " Apply the specified ESAI strategy to a specified gamemode" + echo " apply|delete [subcommand]" + echo " default-strategy Apply a default ESAI strategy for all levels." + echo " This is the default strategy if a level-strategy is not found for a level" + echo " level-strategy Apply the specified ESAI strategy to a specified gamemode" echo " of a specified level's server.zip" echo " -f|--file Apply ESAI strategies based on a space-delimited file" echo " Format per line: " echo " Use '#' for comments" echo "Examples:" - echo " $0 -m bf2 get gamemodes" - echo " $0 -m xpack get gamemodes" - echo " $0 -m bf2 get maplist" - echo " $0 -m bf2 get level-strategies" - echo " $0 -m bf2 get level-strategiescontent" - echo " $0 -m bf2 get levels" - echo " $0 -m bf2 get mods" - echo " $0 -m bf2 get strategies" - echo " $0 -m bf2 apply highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 apply -f esai-optimized-strategies.txt" - echo " $0 -m bf2 delete highway_tampa gpm_cq 32 mediumfca" - echo " $0 -m bf2 delete -f esai-optimized-strategies.txt" + echo " esai-helper -m bf2 get gamemodes" + echo " esai-helper -m xpack get gamemodes" + echo " esai-helper -m bf2 get maplist" + echo " esai-helper -m bf2 get level-strategies" + echo " esai-helper -m bf2 get level-strategiescontent" + echo " esai-helper -m bf2 get levels" + echo " esai-helper -m bf2 get mods" + echo " esai-helper -m bf2 get strategies" + echo " esai-helper -m bf2 apply default-strategy mediumfca" + echo " esai-helper -m bf2 apply level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 apply -f strategies.txt" + echo " esai-helper -m bf2 delete default-strategy mediumfca" + echo " esai-helper -m bf2 delete level-strategy highway_tampa gpm_cq 32 mediumfca" + echo " esai-helper -m bf2 delete -f strategies.txt" } # Exit if we got no options if [ $# -eq 0 ]; then usage; exit 1; fi @@ -117,11 +121,7 @@ while test $# -gt 0; do esac ;; apply|delete) - if [ "$1" = 'apply' ]; then - APPLY=1 - else - DELETE=1 - fi + SUBCOMMAND="$1" shift if [ "$#" = 0 ]; then echo "Missing options or arguments" @@ -129,14 +129,27 @@ while test $# -gt 0; do exit 1 fi case "$1" in - -f|--file) + default-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_DEFAULT_STRATEGY=1 + else + DELETE_DEFAULT_STRATEGY=1 + fi shift - if [ "$#" -gt 0 ]; then - FILE="$1" - shift + STRATEGY="${1:-}" + if [ -z "$STRATEGY" ]; then + echo "Please specify an ESAI strategy an argument. E.g. mediumfcapb" + exit 1 fi + shift ;; - *) + level-strategy) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_LEVEL_STRATEGY=1 + else + DELETE_LEVEL_STRATEGY=1 + fi + shift LEVEL="${1:-}" if [ -z "$LEVEL" ]; then echo "Please specify a level as the first argument. E.g. dalian_plant" @@ -162,6 +175,23 @@ while test $# -gt 0; do fi shift ;; + -f|--file) + if [ "$SUBCOMMAND" = 'apply' ]; then + APPLY_FILE=1 + else + DELETE_FILE=1 + fi + shift + if [ "$#" -gt 0 ]; then + FILE="$1" + shift + fi + ;; + *) + echo "Invalid option '$1'" 1>&2 + usage + exit 1 + ;; esac ;; *) @@ -181,9 +211,12 @@ GET_LEVEL_STRATEGIESCONTENT=${GET_LEVEL_STRATEGIESCONTENT:-} GET_LEVELS=${GET_LEVELS:-} GET_MODS=${GET_MODS:-} GET_STRATEGIES=${GET_STRATEGIES:-} -APPLY=${APPLY:-} -DELETE=${DELETE:-} -FILE=${FILE:-} +APPLY_DEFAULT_STRATEGY=${APPLY_DEFAULT_STRATEGY:-} +DELETE_DEFAULT_STRATEGY=${DELETE_DEFAULT_STRATEGY:-} +APPLY_LEVEL_STRATEGY=${APPLY_LEVEL_STRATEGY:-} +DELETE_LEVEL_STRATEGY=${DELETE_LEVEL_STRATEGY:-} +APPLY_FILE=${APPLY_FILE:-} +DELETE_FILE=${DELETE_FILE:-} LEVEL=${LEVEL:-} GAMEMODE=${GAMEMODE:-} SIZE=${SIZE:-} @@ -269,6 +302,7 @@ if [ -n "$GET_LEVEL_STRATEGIESCONTENT" ]; then STRATEGIES_AI=$( unzip -l "$i" | grep -iE "GameModes/[^/]+/[0-9]+/[^/]+/Strategies.ai" | awk '{print $4}' | sort -n | uniq || true ) if [ -n "$STRATEGIES_AI" ]; then for s in $STRATEGIES_AI; do + echo "Content of $s in $i:" >&2 unzip -p "$i" "$s" done else @@ -286,9 +320,38 @@ if [ -n "$GET_STRATEGIES" ]; then find . | grep -E "mods/$MOD/esai/mapfiles/[^/]+/[^/]+/strategies.ai" | cut -d '/' -f7 | sort -n fi -if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then +if [ -n "$APPLY_DEFAULT_STRATEGY" ]; then + # A trick not found in ESAI readmes + # The default ESAI strategy is used when there is no ESAI strategy for a particular level. + # According to Void, the original author of ESAI, it's easy to add the default ESAI strategy for all maps: + # 1. All except the last two lines of an ESAI strategy (i.e. mods/bf2/esai/mapfiles/*//strategies.ai) goes into aidefaultstrategies.ai + # 2. The last two lines go into aidefaultstrategiesadd.ai + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + if [ -z "$STRATEGIES_AI" ]; then + echo "No such strategy: $STRATEGY" + echo "To get a list of available strategies, run:" + echo " esai-helper -m "$MOD" get strategies" + exit 1 + fi + CONTENT=$( cat "$STRATEGIES_AI" ) + LINE_COUNT=$( echo "$CONTENT" | wc -l ) + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategies.ai">&2 + echo "$CONTENT" | head -n $(( $LINE_COUNT - 2 )) > "$DIR/mods/$MOD/ai/aidefaultstrategies.ai" + echo "Applying $STRATEGIES_AI to $DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai">&2 + echo "$CONTENT" | tail -n 2 > "$DIR/mods/$MOD/ai/aidefaultstrategiesadd.ai" +fi + +if [ -n "$DELETE_DEFAULT_STRATEGY" ]; then + echo "Deleting a default ESAI strategy is not supported. The server needs a default strategy." + exit 1 +fi + +if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then # Validation - if [ -n "$FILE" ]; then + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$DELETE_LEVEL_STRATEGY" ]; then + CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" + fi + if [ -n "$APPLY_FILE" ] || [ -n "$DELETE_FILE" ]; then if [ ! -f "$FILE" ]; then echo "No such file: $FILE" exit 1 @@ -298,52 +361,52 @@ if [ -n "$APPLY" ] || [ -n "$DELETE" ]; then echo "No ESAI strategies to apply in: $FILE" exit 1 fi - else - CONTENT="$LEVEL $GAMEMODE $SIZE $STRATEGY" fi echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do SERVER_ZIP="$DIR/mods/$MOD/levels/$LEVEL/server.zip" if ! unzip -l "$SERVER_ZIP" | grep "GameModes/$GAMEMODE/$SIZE" > /dev/null; then echo "The gamemode '$GAMEMODE' does not exist in $SERVER_ZIP" echo "To get a list of available gamemodes, run:" - echo " $0 get gamemodes" + echo " esai-helper -m "$MOD" get gamemodes" exit 1 fi - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) if [ -z "$STRATEGIES_AI" ]; then echo "No such strategy: $STRATEGY" echo "To get a list of available strategies, run:" - echo " $0 get strategies" - exit 1 - fi - done -fi -if [ -n "$APPLY" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - STRATEGIES_AI=$( find $DIR | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) - STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" - echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" - mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip - cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" - zip -qru server.zip GameModes - rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" - done -fi -if [ -n "$DELETE" ]; then - echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do - cd "$DIR/mods/$MOD/levels/$LEVEL" - SERVER_ZIP="$PWD/server.zip" - EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) - if [ -n "$EXISTING_STRATEGIES_AI" ]; then - for i in $EXISTING_STRATEGIES_AI; do - echo "Removing existing strategy $i from $SERVER_ZIP at $i" - zip -q -d "$SERVER_ZIP" "$i" - done - else - echo "No existing strategy in: $SERVER_ZIP" + echo " esai-helper -m "$MOD" get strategies" exit 1 fi done + + if [ -n "$APPLY_LEVEL_STRATEGY" ] || [ -n "$APPLY_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + STRATEGIES_AI=$( find "$DIR" | grep -E "mods/$MOD/esai/mapfiles/[^/]+/$STRATEGY/strategies.ai" | head -n1 || true ) + STRATEGIES_AI_DESTINATION_IN_ZIP="GameModes/$GAMEMODE/$SIZE/ai/Strategies.ai" + echo "Applying strategy $STRATEGIES_AI to $SERVER_ZIP at $STRATEGIES_AI_DESTINATION_IN_ZIP" + mkdir -p "$( dirname "$STRATEGIES_AI_DESTINATION_IN_ZIP" )" # Same layout as content of server.zip + cp -f "$STRATEGIES_AI" "$STRATEGIES_AI_DESTINATION_IN_ZIP" + zip -qru server.zip GameModes + rm -rf "$DIR/mods/$MOD/levels/$LEVEL/GameModes" + done + fi + + if [ -n "$DELETE_LEVEL_STRATEGY" ] || [ -n "$DELETE_FILE" ]; then + echo "$CONTENT" | while read -r LEVEL GAMEMODE SIZE STRATEGY; do + cd "$DIR/mods/$MOD/levels/$LEVEL" + SERVER_ZIP="$PWD/server.zip" + EXISTING_STRATEGIES_AI=$( unzip -l "$SERVER_ZIP" | grep -iE "GameModes/$GAMEMODE/$SIZE/(ai|AI)/Strategies.ai" | awk '{print $4}' || true ) + if [ -n "$EXISTING_STRATEGIES_AI" ]; then + for i in $EXISTING_STRATEGIES_AI; do + echo "Removing existing strategy $i from $SERVER_ZIP at $i" + zip -q -d "$SERVER_ZIP" "$i" + done + else + echo "No existing strategy in: $SERVER_ZIP" + exit 1 + fi + done + fi fi