diff --git a/apps/counterstrikesharp/Dockerfile b/apps/counterstrikesharp/Dockerfile index e31b7d4..0375b03 100644 --- a/apps/counterstrikesharp/Dockerfile +++ b/apps/counterstrikesharp/Dockerfile @@ -79,6 +79,12 @@ ENV SERVER_TYPE="Ranked" ENV METAMOD_URL=https://github.com/alliedmodders/metamod-source/releases/download/2.0.0.1402/mmsource-2.0.0-git1402-linux.tar.gz ENV COUNTER_STRIKE_SHARP_URL=https://github.com/roflmuffin/CounterStrikeSharp/releases/download/v1.0.369/counterstrikesharp-with-runtime-linux-1.0.369.zip +ENV CS2FOW_URL=https://github.com/karola3vax/CS2FOW/releases/download/v0.1.1-preview/cs2fow-0.1.1-preview-linux-x86_64.zip +ENV CS2FOW_SHA256=517eff95d5bae15b0aa9fb79c47a6eebe3bb7033228bfe9d7d397fc9446750d6 +# prebake pack v0.1.0-preview is upstream-declared compatible with plugin v0.1.1-preview; bump both pins together after checking upstream release notes +ENV CS2FOW_PREBAKE_URL=https://github.com/karola3vax/CS2FOW/releases/download/v0.1.0-preview/cs2fow-0.1.0-preview-official-maps.zip +ENV CS2FOW_PREBAKE_SHA256=66114d74a13f933f38f81a79d2fa10ad89e2cf254b45afc5c589c8782067215c +ENV CS2FOW_PREBAKE_VERSION=0.1.0-preview ENV METAMOD_CSGO_URL=https://mms.alliedmods.net/mmsdrop/1.12/mmsource-1.12.0-git1219-linux.tar.gz ENV SOURCEMOD_CSGO_URL=https://sm.alliedmods.net/smdrop/1.13/sourcemod-1.13.0-git7297-linux.tar.gz @@ -108,7 +114,6 @@ RUN mkdir -p /opt/metamod /opt/counterstrikesharp && \ unzip -q /tmp/counterstrikesharp.zip -d /opt/counterstrikesharp && \ rm /tmp/counterstrikesharp.zip - RUN mkdir -p /opt/csgo-metamod /opt/csgo-sourcemod /opt/csgo-no-lobby-reservation && \ wget -q $METAMOD_CSGO_URL -O /tmp/metamod-csgo.tar.gz && \ tar -xz -C /opt/csgo-metamod -f /tmp/metamod-csgo.tar.gz && \ @@ -132,4 +137,14 @@ RUN mv /opt/metamod/addons /opt/addons && \ mkdir -p /opt/addons/counterstrikesharp/plugins && \ rm -rf /opt/metamod /opt/counterstrikesharp +RUN mkdir -p /opt/cs2fow /opt/cs2fow-tools && \ + wget -q $CS2FOW_URL -O /tmp/cs2fow.zip && \ + echo "${CS2FOW_SHA256} /tmp/cs2fow.zip" | sha256sum -c - && \ + unzip -q /tmp/cs2fow.zip -d /opt/cs2fow && \ + rm /tmp/cs2fow.zip && \ + cp -R /opt/cs2fow/addons/cs2fow /opt/addons && \ + cp /opt/cs2fow/addons/metamod/cs2fow.vdf /opt/addons/metamod/ && \ + cp -R /opt/cs2fow/tools/. /opt/cs2fow-tools/ && \ + rm -rf /opt/cs2fow + ENTRYPOINT ["/bin/bash", "-c", "/opt/scripts/setup.sh && /opt/scripts/server.sh"] \ No newline at end of file diff --git a/apps/counterstrikesharp/Dockerfile.dev b/apps/counterstrikesharp/Dockerfile.dev index 6fb983c..3f95797 100644 --- a/apps/counterstrikesharp/Dockerfile.dev +++ b/apps/counterstrikesharp/Dockerfile.dev @@ -30,6 +30,12 @@ ENV SERVER_TYPE="Ranked" ENV METAMOD_URL=https://mms.alliedmods.net/mmsdrop/2.0/mmsource-2.0.0-git1374-linux.tar.gz ENV COUNTER_STRIKE_SHARP_URL=https://github.com/roflmuffin/CounterStrikeSharp/releases/download/v1.0.369/counterstrikesharp-with-runtime-linux-1.0.369.zip +ENV CS2FOW_URL=https://github.com/karola3vax/CS2FOW/releases/download/v0.1.1-preview/cs2fow-0.1.1-preview-linux-x86_64.zip +ENV CS2FOW_SHA256=517eff95d5bae15b0aa9fb79c47a6eebe3bb7033228bfe9d7d397fc9446750d6 +# prebake pack v0.1.0-preview is upstream-declared compatible with plugin v0.1.1-preview; bump both pins together after checking upstream release notes +ENV CS2FOW_PREBAKE_URL=https://github.com/karola3vax/CS2FOW/releases/download/v0.1.0-preview/cs2fow-0.1.0-preview-official-maps.zip +ENV CS2FOW_PREBAKE_SHA256=66114d74a13f933f38f81a79d2fa10ad89e2cf254b45afc5c589c8782067215c +ENV CS2FOW_PREBAKE_VERSION=0.1.0-preview RUN apt-get update && \ apt-get install -y --no-install-recommends \ @@ -59,6 +65,16 @@ RUN mv /opt/metamod/addons /opt/addons && \ mkdir -p /opt/dev && \ rm -rf /opt/metamod /opt/counterstrikesharp +RUN mkdir -p /opt/cs2fow /opt/cs2fow-tools && \ + wget -q $CS2FOW_URL -O /tmp/cs2fow.zip && \ + echo "${CS2FOW_SHA256} /tmp/cs2fow.zip" | sha256sum -c - && \ + unzip -q /tmp/cs2fow.zip -d /opt/cs2fow && \ + rm /tmp/cs2fow.zip && \ + cp -R /opt/cs2fow/addons/cs2fow /opt/addons && \ + cp /opt/cs2fow/addons/metamod/cs2fow.vdf /opt/addons/metamod/ && \ + cp -R /opt/cs2fow/tools/. /opt/cs2fow-tools/ && \ + rm -rf /opt/cs2fow + WORKDIR /opt/5stack COPY . . diff --git a/apps/counterstrikesharp/cfg/cs2fow.cfg b/apps/counterstrikesharp/cfg/cs2fow.cfg new file mode 100644 index 0000000..3713f3c --- /dev/null +++ b/apps/counterstrikesharp/cfg/cs2fow.cfg @@ -0,0 +1,7 @@ +cs2fow_enable 1 +cs2fow_update_interval_ms 10 +cs2fow_max_lookahead_ms 210 +cs2fow_min_lookahead_ms 120 +cs2fow_peek_margin_units 21 +cs2fow_visibility_hold_ms 150 +cs2fow_debug 0 \ No newline at end of file diff --git a/apps/counterstrikesharp/scripts/setup.sh b/apps/counterstrikesharp/scripts/setup.sh index 0e44bd8..44337a7 100755 --- a/apps/counterstrikesharp/scripts/setup.sh +++ b/apps/counterstrikesharp/scripts/setup.sh @@ -41,6 +41,23 @@ done echo "---Install Addons---" cp -r "/opt/addons" "${INSTANCE_SERVER_DIR}/game/csgo" +echo "---Setup CS2FOW---" +if grep -qw avx /proc/cpuinfo; then + mkdir -p "${BASE_SERVER_DIR}/.cs2fow/maps" + mkdir -p "${INSTANCE_SERVER_DIR}/game/csgo/addons/cs2fow/data" + rm -rf "${INSTANCE_SERVER_DIR}/game/csgo/addons/cs2fow/data/maps" + ln -s "${BASE_SERVER_DIR}/.cs2fow/maps" "${INSTANCE_SERVER_DIR}/game/csgo/addons/cs2fow/data/maps" + + mkdir -p "${INSTANCE_SERVER_DIR}/game/csgo/tools" + create_symlinks "/opt/cs2fow-tools" "${INSTANCE_SERVER_DIR}/game/csgo/tools" + + cp "/opt/server-cfg/cs2fow.cfg" "${INSTANCE_SERVER_DIR}/game/csgo/cfg/cs2fow.cfg" +else + echo "---CS2FOW disabled: CPU lacks AVX support---" + rm -f "${INSTANCE_SERVER_DIR}/game/csgo/addons/metamod/cs2fow.vdf" + rm -rf "${INSTANCE_SERVER_DIR}/game/csgo/addons/cs2fow" +fi + echo "---Create Symbolic Links---" if [ "$SERVER_TYPE" = "Ranked" ]; then diff --git a/apps/counterstrikesharp/src/FiveStack.Services/MatchManager.cs b/apps/counterstrikesharp/src/FiveStack.Services/MatchManager.cs index 3b5d65b..3d4ae70 100644 --- a/apps/counterstrikesharp/src/FiveStack.Services/MatchManager.cs +++ b/apps/counterstrikesharp/src/FiveStack.Services/MatchManager.cs @@ -537,6 +537,9 @@ public void SetupMatch(MatchData match) } } + ApplyAntiWallhack(); + PublishAntiWallhackStatus(); + Server.NextFrame(() => { if (!wasAlreadySetup) @@ -784,6 +787,9 @@ private void StartLive() _gameServer.SendCommands([$"exec 5stack.{_matchData.options.type.ToLower()}.cfg"]); + ApplyAntiWallhack(); + PublishAntiWallhackStatus(); + Server.NextFrame(() => { _gameDemos.Start(); @@ -807,6 +813,56 @@ private void StartLive() }); } + private void ApplyAntiWallhack() + { + if (_matchData == null) + { + return; + } + + if (ConVar.Find("cs2fow_enable") == null) + { + _logger.LogInformation("CS2FOW is not loaded; skipping anti-wallhack apply"); + return; + } + + _gameServer.SendCommands([$"cs2fow_enable {(_matchData.options.anti_wallhack ? 1 : 0)}"]); + } + + private void PublishAntiWallhackStatus() + { + if (_matchData == null) + { + return; + } + + bool pluginLoaded = ConVar.Find("cs2fow_enable") != null; + + string mapsDir = Path.Join( + Server.GameDirectory, + "csgo", + "addons", + "cs2fow", + "data", + "maps" + ); + string bakePath = Path.Join(mapsDir, $"{Server.MapName}.bvh8"); + + if (pluginLoaded && !Directory.Exists(mapsDir)) + { + _logger.LogWarning( + $"CS2FOW maps directory missing at {mapsDir}; bake layout may have changed" + ); + } + + bool active = _matchData.options.anti_wallhack && pluginLoaded && File.Exists(bakePath); + + _matchEvents.PublishGameEvent( + "antiWallhackStatus", + new Dictionary { { "active", active } } + ); + } + public void EnforceMemberTeam(CCSPlayerController player, CsTeam? currentTeam = null) { CsTeam expectedTeam = GetExpectedTeam(player); diff --git a/shared/dotnet/FiveStack.Entities/MatchOptions.cs b/shared/dotnet/FiveStack.Entities/MatchOptions.cs index 7bb01b1..824d0fc 100644 --- a/shared/dotnet/FiveStack.Entities/MatchOptions.cs +++ b/shared/dotnet/FiveStack.Entities/MatchOptions.cs @@ -12,6 +12,7 @@ public class MatchOptions public bool coaches { get; set; } = true; public int number_of_substitutes { get; set; } = 0; public bool knife_round { get; set; } = true; + public bool anti_wallhack { get; set; } = true; public bool? default_models { get; set; } = false; public string ready_setting { get; set; } = "Players"; public string timeout_setting { get; set; } = "CoachAndPlayers"; diff --git a/shared/scripts/update.sh b/shared/scripts/update.sh index bc7c912..7b9e96b 100755 --- a/shared/scripts/update.sh +++ b/shared/scripts/update.sh @@ -174,8 +174,35 @@ EOF echo "${BUILD_ID}" > "${BUILD_TRACK_FILE}" echo "---Done Updating Server To Version ${BUILD_ID}---" + UPDATE_RC=0 else echo "---Update Server To Latest Version---" "${STEAMCMD_DIR}/steamcmd.sh" +force_install_dir "${BASE_SERVER_DIR}" +login anonymous +app_update "${GAME_ID}" ${VALIDATE:+validate} +quit -fi \ No newline at end of file + UPDATE_RC=$? +fi + +if [ "${GAME_ID}" = "730" ] && [ -n "${CS2FOW_PREBAKE_URL:-}" ] && grep -qw avx /proc/cpuinfo; then + CS2FOW_MAPS_DIR="${BASE_SERVER_DIR}/.cs2fow/maps" + CS2FOW_MARKER="${BASE_SERVER_DIR}/.cs2fow/.prebake-version" + + if [ ! -f "${CS2FOW_MARKER}" ] || [ "$(cat "${CS2FOW_MARKER}" 2>/dev/null)" != "${CS2FOW_PREBAKE_VERSION}" ]; then + echo "---Downloading CS2FOW Official Map Prebakes (${CS2FOW_PREBAKE_VERSION})---" + mkdir -p "${CS2FOW_MAPS_DIR}" + if curl -sSL -o /tmp/cs2fow-prebakes.zip "${CS2FOW_PREBAKE_URL}" \ + && echo "${CS2FOW_PREBAKE_SHA256} /tmp/cs2fow-prebakes.zip" | sha256sum -c - ; then + # -j flattens paths so this works regardless of the zip's internal layout + if unzip -o -j -q /tmp/cs2fow-prebakes.zip "*.bvh8" -d "${CS2FOW_MAPS_DIR}"; then + echo "${CS2FOW_PREBAKE_VERSION}" > "${CS2FOW_MARKER}" + echo "---CS2FOW prebakes installed: $(ls "${CS2FOW_MAPS_DIR}" | wc -l) files---" + else + echo "---CS2FOW prebake unzip failed; auto-bake will cover maps---" + fi + else + echo "---CS2FOW prebake download failed; auto-bake will cover maps---" + fi + rm -f /tmp/cs2fow-prebakes.zip + fi +fi + +exit ${UPDATE_RC:-1} \ No newline at end of file