You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-loadsave resolves its argument inside the managed user Save directory, so a file anywhere else has to be copied in before it can be opened. That rules out launching the game directly for a .sav supplied by an operating-system file handler.
Now an absolute path is opened in place while a relative name still resolves from the Save directory, so both forms keep working. FileSystem::isAbsolutePath classifies the argument - a drive root (C:\, C:/), a current-drive or UNC root (leading separator), or a POSIX root - and GameState::getSaveGamePathForRead returns the path untouched when it is absolute. Save writes and the save menu are unaffected; they continue to use the managed directory.
parseLoadSave also gains the argument validation and return value that parseReplay already uses in the same file: reject a name that does not end in .sav, return 2 only when an argument was consumed, and 1 otherwise. Previously it returned 2 unconditionally, so -loadsave with no argument consumed the following token.
Paths containing spaces work when quoted, which is the form an operating-system file handler passes. nextParam is quote-aware: a token beginning with " terminates on the next " rather than on whitespace.
Verified with a bogus path as a control so a pass is distinguishable from "the game started anyway":
case
result
control: bogus absolute path
exits
Save from an absolute path outside the user directory
loads
Save from an absolute path containing spaces (quoted)
loads
Relative Save filename
loads from the managed directory
Save from a UNC path (\\localhost\C$\...)
loads
Save from a POSIX absolute path containing spaces
loads
Todo:
Both games build (z_generals and g_generals)
Absolute path classification covers drive roots, UNC and current-drive roots, and POSIX roots
Save paths outside the user data directory
Paths containing spaces
Windows drive paths and UNC paths
Relative Save filenames still resolve from the managed directory
• Opens absolute -loadsave paths in place across both game variants.
• Preserves managed Save-directory resolution for relative filenames and menu loads.
• Validates .sav arguments and avoids consuming tokens when no filename is supplied.
Diagram
graph TD
A["-loadsave CLI"] --> B{"Valid .sav?"}
B -->|yes| C["Queued save"] --> D{"Absolute path?"}
D -->|yes| E["Selected file"] --> G["Save loader"]
D -->|no| F["Save directory"] --> G
B -->|no| H["Exit error"]
Loading
High-Level Assessment
The centralized path classifier plus read-only GameState resolver is the appropriate approach: it preserves existing write and menu behavior while consistently handling all save read entry points. Using std::filesystem::path was considered, but would introduce broader runtime/toolchain coupling without improving this narrowly scoped integration.
FileSystem.cppClassify Windows and POSIX absolute paths+25/-0
Classify Windows and POSIX absolute paths
• Implements platform-specific absolute-path detection for rooted Windows drive paths, leading-separator Windows paths including UNC forms, and POSIX root paths.
GameState.cppLoad Generals saves from absolute or managed paths+20/-6
Load Generals saves from absolute or managed paths
• Routes existence checks, metadata reads, queued startup loads, and full loads through a read-path resolver. Absolute paths are preserved while relative names continue resolving under the user Save directory.
GameState.cppLoad Zero Hour saves from absolute or managed paths+20/-6
Load Zero Hour saves from absolute or managed paths
• Mirrors the Generals read-path handling across existence checks, metadata inspection, queued startup loading, and full save loading. Existing relative menu filenames remain scoped to the user Save directory.
CommandLine.cppValidate and correctly consume -loadsave arguments+11/-2
Validate and correctly consume -loadsave arguments
• Requires supplied save names to end in '.sav', reports invalid names, and returns the correct consumed-argument count. Missing filenames no longer cause the parser to consume a following token.
This PR allows -loadsave to open absolute save paths directly while preserving managed Save-directory resolution for relative filenames.
Adds platform-specific absolute-path classification to the shared filesystem API.
Routes save existence checks, metadata reads, and full loads through a common read-path resolver in both game variants.
Validates the command-line filename extension and corrects argument-consumption behavior when no filename is supplied.
Confidence Score: 5/5
The PR appears safe to merge with no concrete correctness or security defects identified.
Save paths are resolved consistently at each read boundary, existing relative menu filenames retain managed-directory behavior, absolute command-line paths remain intact, and command-line argument consumption now matches the parser contract.
Important Files Changed
Filename
Overview
Core/GameEngine/Source/Common/CommandLine.cpp
Validates .sav arguments and consumes the filename only when one is present.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
-loadsaveresolves its argument inside the managed user Save directory, so a file anywhere else has to be copied in before it can be opened. That rules out launching the game directly for a.savsupplied by an operating-system file handler.Now an absolute path is opened in place while a relative name still resolves from the Save directory, so both forms keep working.
FileSystem::isAbsolutePathclassifies the argument - a drive root (C:\,C:/), a current-drive or UNC root (leading separator), or a POSIX root - andGameState::getSaveGamePathForReadreturns the path untouched when it is absolute. Save writes and the save menu are unaffected; they continue to use the managed directory.parseLoadSavealso gains the argument validation and return value thatparseReplayalready uses in the same file: reject a name that does not end in.sav, return 2 only when an argument was consumed, and 1 otherwise. Previously it returned 2 unconditionally, so-loadsavewith no argument consumed the following token.Paths containing spaces work when quoted, which is the form an operating-system file handler passes.
nextParamis quote-aware: a token beginning with"terminates on the next"rather than on whitespace.Verified with a bogus path as a control so a pass is distinguishable from "the game started anyway":
\\localhost\C$\...)Todo:
z_generalsandg_generals)