Skip to content

Commit 8cc987e

Browse files
authored
Merge branch 'main' into fix_airfield_takeoff_frames
2 parents 7bc0326 + c08e01d commit 8cc987e

File tree

3,874 files changed

+80830
-84673
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

3,874 files changed

+80830
-84673
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
root=true
2+
3+
[*]
4+
insert_final_newline = true
5+
trim_trailing_whitespace = true
6+
7+
[{*.h,*.cpp,*.inl}]
8+
indent_style = unset
9+
indent_size = 2
10+
11+
[{CMakeLists.txt,*.cmake,*.py}]
12+
indent_style = spaces
13+
indent_size = 4

.github/workflows/build-toolchain.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ on:
2828

2929
jobs:
3030
build:
31-
name: Preset ${{ inputs.preset }}${{ inputs.tools && '+t' || '' }}${{ inputs.extras && '+e' || '' }}
32-
runs-on: windows-latest
33-
timeout-minutes: 40
31+
name: ${{ inputs.preset }}${{ inputs.tools && '+t' || '' }}${{ inputs.extras && '+e' || '' }}
32+
runs-on: windows-2022
33+
timeout-minutes: 20
3434
steps:
3535
- name: Checkout Code
3636
uses: actions/checkout@v4
@@ -66,7 +66,7 @@ jobs:
6666
$fileHash = (Get-FileHash -Path VS6_VisualStudio6.7z -Algorithm SHA256).Hash
6767
Write-Host "Downloaded file SHA256: $fileHash"
6868
Write-Host "Expected file SHA256: $env:EXPECTED_HASH"
69-
if ($hash -ne $env:EXPECTED_HASH) {
69+
if ($fileHash -ne $env:EXPECTED_HASH) {
7070
Write-Error "Hash verification failed! File may be corrupted or tampered with."
7171
exit 1
7272
}

.github/workflows/check-replays.yml

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
name: check-replays
2+
3+
permissions:
4+
contents: read
5+
pull-requests: write
6+
7+
on:
8+
workflow_call:
9+
inputs:
10+
game:
11+
required: true
12+
type: string
13+
description: "Game to check (only GeneralsMD for now)"
14+
userdata:
15+
required: true
16+
type: string
17+
description: "Path to folder with replays and maps"
18+
preset:
19+
required: true
20+
type: string
21+
description: "CMake preset"
22+
23+
jobs:
24+
build:
25+
name: ${{ inputs.preset }}
26+
runs-on: windows-latest
27+
timeout-minutes: 15
28+
env:
29+
GAME_PATH: C:\GameData
30+
GENERALS_PATH: C:\GameData\Generals
31+
GENERALSMD_PATH: C:\GameData\GeneralsMD
32+
steps:
33+
- name: Checkout Code
34+
uses: actions/checkout@v4
35+
with:
36+
submodules: true
37+
38+
- name: Download Game Artifact
39+
uses: actions/download-artifact@v4
40+
with:
41+
name: ${{ inputs.game }}-${{ inputs.preset }}
42+
path: build
43+
44+
- name: Cache Game Data
45+
id: cache-gamedata
46+
uses: actions/cache@v4
47+
with:
48+
path: ${{ env.GAME_PATH }}
49+
key: gamedata-permanent-cache-v4
50+
51+
- name: Download Game Data from Cloudflare R2
52+
if: ${{ steps.cache-gamedata.outputs.cache-hit != 'true' }}
53+
env:
54+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
55+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
56+
AWS_ENDPOINT_URL: ${{ secrets.R2_ENDPOINT_URL }}
57+
EXPECTED_HASH_GENERALS: "37A351AA430199D1F05DEB9E404857DCE7B461A6AC272C5D4A0B5652CDB06372"
58+
EXPECTED_HASH_GENERALSMD: "6837FE1E3009A4C239406C39B1598216C0943EE8ED46BB10626767029AC05E21"
59+
shell: pwsh
60+
run: |
61+
# Download trimmed gamedata of both Generals 1.08 and Generals Zero Hour 1.04.
62+
# This data cannot be used for playing because it's
63+
# missing textures, audio and gui files. But it's enough for replay checking.
64+
# It's also encrypted because it's not allowed to distribute these files.
65+
66+
if (-not $env:AWS_ACCESS_KEY_ID -or -not $env:AWS_SECRET_ACCESS_KEY -or -not $env:AWS_ENDPOINT_URL) {
67+
$ok1 = [bool]$env:AWS_ACCESS_KEY_ID
68+
$ok2 = [bool]$env:AWS_SECRET_ACCESS_KEY
69+
$ok3 = [bool]$env:AWS_ENDPOINT_URL
70+
Write-Host "One or more required secrets are not set or are empty. R2_ACCESS_KEY_ID: $ok1, R2_SECRET_ACCESS_KEY: $ok2, R2_ENDPOINT_URL: $ok3"
71+
exit 1
72+
}
73+
74+
# Download Generals Game Files
75+
# The archive contains these files:
76+
# BINKW32.DLL
77+
# English.big
78+
# INI.big
79+
# Maps.big
80+
# mss32.dll
81+
# W3D.big
82+
# Data\Scripts\MultiplayerScripts.scb
83+
# Data\Scripts\SkirmishScripts.scb
84+
85+
Write-Host "Downloading Game Data for Generals" -ForegroundColor Cyan
86+
aws s3 cp s3://github-ci/generals108_gamedata_trimmed.7z generals108_gamedata_trimmed.7z --endpoint-url $env:AWS_ENDPOINT_URL
87+
88+
Write-Host "Verifying File Integrity" -ForegroundColor Cyan
89+
$fileHash = (Get-FileHash -Path generals108_gamedata_trimmed.7z -Algorithm SHA256).Hash
90+
Write-Host "Downloaded file SHA256: $fileHash"
91+
Write-Host "Expected file SHA256: $env:EXPECTED_HASH_GENERALS"
92+
if ($fileHash -ne $env:EXPECTED_HASH_GENERALS) {
93+
Write-Error "Hash verification failed! File may be corrupted or tampered with."
94+
exit 1
95+
}
96+
97+
Write-Host "Extracting Archive" -ForegroundColor Cyan
98+
$extractPath = $env:GENERALS_PATH
99+
& 7z x generals108_gamedata_trimmed.7z -o"$extractPath"
100+
Remove-Item generals108_gamedata_trimmed.7z -Verbose
101+
102+
# Download GeneralsMD (ZH) Game Files
103+
# The archive contains these files:
104+
# BINKW32.DLL
105+
# INIZH.big
106+
# MapsZH.big
107+
# mss32.dll
108+
# W3DZH.big
109+
# Data\Scripts\MultiplayerScripts.scb
110+
# Data\Scripts\Scripts.ini
111+
# Data\Scripts\SkirmishScripts.scb
112+
113+
Write-Host "Downloading Game Data for GeneralsMD" -ForegroundColor Cyan
114+
aws s3 cp s3://github-ci/zerohour104_gamedata_trimmed.7z zerohour104_gamedata_trimmed.7z --endpoint-url $env:AWS_ENDPOINT_URL
115+
116+
Write-Host "Verifying File Integrity" -ForegroundColor Cyan
117+
$fileHash = (Get-FileHash -Path zerohour104_gamedata_trimmed.7z -Algorithm SHA256).Hash
118+
Write-Host "Downloaded file SHA256: $fileHash"
119+
Write-Host "Expected file SHA256: $env:EXPECTED_HASH_GENERALSMD"
120+
if ($fileHash -ne $env:EXPECTED_HASH_GENERALSMD) {
121+
Write-Error "Hash verification failed! File may be corrupted or tampered with."
122+
exit 1
123+
}
124+
125+
Write-Host "Extracting Archive" -ForegroundColor Cyan
126+
$extractPath = $env:GENERALSMD_PATH
127+
& 7z x zerohour104_gamedata_trimmed.7z -o"$extractPath"
128+
Remove-Item zerohour104_gamedata_trimmed.7z -Verbose
129+
130+
- name: Set Up Game Data
131+
shell: pwsh
132+
run: |
133+
$source = "$env:GAME_PATH\${{ inputs.game }}"
134+
$destination = "build"
135+
Copy-Item -Path $source\* -Destination $destination -Recurse -Force
136+
137+
- name: Set Generals InstallPath in Registry
138+
shell: pwsh
139+
run: |
140+
# Zero Hour loads some Generals files and needs this registry key to find the
141+
# Generals data files.
142+
143+
$regPath = "HKCU:\SOFTWARE\Electronic Arts\EA Games\Generals"
144+
$installPath = "$env:GENERALS_PATH\"
145+
146+
# Ensure the key exists
147+
if (-not (Test-Path $regPath)) {
148+
New-Item -Path $regPath -Force | Out-Null
149+
}
150+
151+
# Set the InstallPath value
152+
Set-ItemProperty -Path $regPath -Name InstallPath -Value $installPath -Type String
153+
Write-Host "Registry key set: $regPath -> InstallPath = $installPath"
154+
155+
- name: Move Replays and Maps to User Dir
156+
shell: pwsh
157+
run: |
158+
# These files are expected in the user dir, so we move them here.
159+
160+
$source = "${{ inputs.userdata }}\Replays"
161+
$destination = "$env:USERPROFILE\Documents\Command and Conquer Generals Zero Hour Data\Replays"
162+
Write-Host "Move replays to $destination"
163+
New-Item -ItemType Directory -Path $destination -Force | Out-Null
164+
Move-Item -Path "$source\*" -Destination $destination -Force
165+
166+
$source = "${{ inputs.userdata }}\Maps"
167+
$destination = "$env:USERPROFILE\Documents\Command and Conquer Generals Zero Hour Data\Maps"
168+
Write-Host "Move maps to $destination"
169+
New-Item -ItemType Directory -Path $destination -Force | Out-Null
170+
Move-Item -Path "$source\*" -Destination $destination -Force
171+
172+
- name: Run Replay Compatibility Tests
173+
shell: pwsh
174+
run: |
175+
$exePath = "build/generalszh.exe"
176+
$arguments = "-jobs 4 -headless -replay *.rep"
177+
$timeoutSeconds = 10*60
178+
$stdoutPath = "stdout.log"
179+
$stderrPath = "stderr.log"
180+
181+
if (-not (Test-Path $exePath)) {
182+
Write-Host "ERROR: Executable not found at $exePath"
183+
exit 1
184+
}
185+
186+
# Note that the game is a gui application. That means we need to redirect console output to a file
187+
# in order to retrieve it.
188+
# Clean previous logs
189+
Remove-Item $stdoutPath, $stderrPath -ErrorAction SilentlyContinue
190+
191+
# Start the process
192+
Write-Host "Run $exePath $arguments"
193+
$process = Start-Process -FilePath $exePath `
194+
-ArgumentList $arguments `
195+
-RedirectStandardOutput $stdoutPath `
196+
-RedirectStandardError $stderrPath `
197+
-PassThru
198+
199+
# Wait with timeout
200+
$exited = $process.WaitForExit($timeoutSeconds * 1000)
201+
202+
if (-not $exited) {
203+
Write-Host "ERROR: Process still running after $timeoutSeconds seconds. Killing process..."
204+
Stop-Process -Id $process.Id -Force
205+
}
206+
207+
# Read output
208+
Write-Host "=== STDOUT ==="
209+
Get-Content $stdoutPath
210+
211+
if ((Test-Path $stderrPath) -and (Get-Item $stderrPath).Length -gt 0) {
212+
Write-Host "`n=== STDERR ==="
213+
Get-Content $stderrPath
214+
}
215+
216+
if (-not $exited) {
217+
exit 1
218+
}
219+
220+
# Check exit code
221+
$exitCode = $process.ExitCode
222+
223+
# The above doesn't work on all Windows versions. If not, try this: (see https://stackoverflow.com/a/16018287)
224+
#$process.HasExited | Out-Null # Needs to be called for the command below to work correctly
225+
#$exitCode = $process.GetType().GetField('exitCode', 'NonPublic, Instance').GetValue($process)
226+
#Write-Host "exit code $exitCode"
227+
228+
if ($exitCode -ne 0) {
229+
Write-Host "ERROR: Process failed with exit code $exitCode"
230+
exit $exitCode
231+
}
232+
233+
Write-Host "Success!"
234+
235+
- name: Upload Debug Log
236+
if: always()
237+
uses: actions/upload-artifact@v4
238+
with:
239+
name: Replay-Debug-Log-${{ inputs.preset }}
240+
path: build/DebugLogFile*.txt
241+
retention-days: 30
242+
if-no-files-found: ignore

.github/workflows/ci.yml

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ jobs:
4141
generalsmd:
4242
- 'GeneralsMD/**'
4343
shared:
44-
- '.github/workflows/build-toolchain.yml'
45-
- '.github/workflows/ci.yml'
44+
- '.github/workflows/**'
4645
- 'CMakeLists.txt'
4746
- 'CMakePresets.json'
4847
- 'cmake/**'
@@ -100,7 +99,9 @@ jobs:
10099
extras: ${{ matrix.extras }}
101100
secrets: inherit
102101

103-
build-generalsmd:
102+
# Note build-generalsmd is split into two jobs for vc6 and win32 because replaycheck-generalsmd
103+
# only requires the vc6 build and compiling vc6 is much faster than win32
104+
build-generalsmd-vc6:
104105
name: Build GeneralsMD${{ matrix.preset && '' }}
105106
needs: detect-changes
106107
if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generalsmd == 'true' || needs.detect-changes.outputs.shared == 'true' }}
@@ -116,6 +117,25 @@ jobs:
116117
- preset: "vc6-debug"
117118
tools: true
118119
extras: true
120+
- preset: "vc6-releaselog"
121+
tools: true
122+
extras: true
123+
fail-fast: false
124+
uses: ./.github/workflows/build-toolchain.yml
125+
with:
126+
game: "GeneralsMD"
127+
preset: ${{ matrix.preset }}
128+
tools: ${{ matrix.tools }}
129+
extras: ${{ matrix.extras }}
130+
secrets: inherit
131+
132+
build-generalsmd-win32:
133+
name: Build GeneralsMD${{ matrix.preset && '' }}
134+
needs: detect-changes
135+
if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generalsmd == 'true' || needs.detect-changes.outputs.shared == 'true' }}
136+
strategy:
137+
matrix:
138+
include:
119139
- preset: "win32"
120140
tools: true
121141
extras: true
@@ -143,3 +163,20 @@ jobs:
143163
tools: ${{ matrix.tools }}
144164
extras: ${{ matrix.extras }}
145165
secrets: inherit
166+
167+
replaycheck-generalsmd:
168+
name: Replay Check GeneralsMD${{ matrix.preset && '' }}
169+
needs: build-generalsmd-vc6
170+
if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generalsmd == 'true' || needs.detect-changes.outputs.shared == 'true' }}
171+
strategy:
172+
matrix:
173+
include:
174+
- preset: "vc6+t+e"
175+
- preset: "vc6-releaselog+t+e" # optimized build with logging and crashing enabled should be compatible, so we test that here.
176+
fail-fast: false
177+
uses: ./.github/workflows/check-replays.yml
178+
with:
179+
game: "GeneralsMD"
180+
userdata: "GeneralsReplays/GeneralsZH/1.04"
181+
preset: ${{ matrix.preset }}
182+
secrets: inherit

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
# Ignore everything starting with dot, except git files.
1+
# Ignore everything starting with dot, except specific files.
22
.*
3+
!.editorconfig
34
!.gitignore
45
!.gitattributes
56
!.github
7+
!.gitmodules
68

79
*.user
810
*.ncb

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "GeneralsReplays"]
2+
path = GeneralsReplays
3+
url = https://github.com/TheSuperHackers/GeneralsReplays

0 commit comments

Comments
 (0)