Skip to content

tweak(gamestate): Support load save files from absolute paths - #3226

Open
bobtista wants to merge 1 commit into
TheSuperHackers:mainfrom
bobtista:bobtista/feature/load-save-from-absolute-path
Open

tweak(gamestate): Support load save files from absolute paths#3226
bobtista wants to merge 1 commit into
TheSuperHackers:mainfrom
bobtista:bobtista/feature/load-save-from-absolute-path

Conversation

@bobtista

@bobtista bobtista commented Aug 27, 2026

Copy link
Copy Markdown

-loadsave normally resolves its argument inside the managed user Save directory, so a file anywhere else has to be copied there before it can be opened. That prevents an operating-system file handler from launching the game directly for a selected .sav.

Now absolute paths are opened in place while relative names continue to resolve from the Save directory. isAbsolutePath(const char*) in PathUtil.h recognizes a drive root (C:\ or C:/), a current-drive or UNC root (a leading separator), or a POSIX root. GameState::getSaveGamePathForRead preserves absolute paths and resolves relative names through the managed directory. Save writes and the save menu are unchanged.

parseLoadSave now returns 2 only when it consumes an argument and 1 otherwise. Previously it returned 2 unconditionally, so -loadsave without an argument could consume the following token.

Queued save validation runs after the shell is initialized. A wrong extension, missing file, or unreadable file now shows a visible error dialog, and dismissing it leaves the user on the main menu.

Paths containing spaces work when quoted, which is the form an operating-system file handler supplies. nextParam is quote-aware, so a token beginning with " ends at the matching quote rather than at whitespace.

Verified with a bogus path as a control so a successful launch is distinguishable from a successful load:

case result
Invalid save extension shows the load-error dialog; OK returns to the main menu
Missing absolute save path shows the load-error dialog; OK returns to the main menu
Unreadable save file shows the load-error dialog; OK returns to the main menu
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
  • Invalid, missing, and unreadable saves show a visible error
  • Windows drive paths and UNC paths
  • Relative save filenames still resolve from the managed directory
  • Replicate to Generals

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Load CLI save games from absolute paths

✨ Enhancement 🐞 Bug fix 🕐 20-40 Minutes

Grey Divider

AI Description

• 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.

Files changed (7) +79 / -14

Enhancement (6) +68 / -12
FileSystem.hExpose cross-platform absolute-path classification +1/-0

Expose cross-platform absolute-path classification

• Declares a shared helper for distinguishing absolute paths from names relative to managed directories.

Core/GameEngine/Include/Common/FileSystem.h

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.

Core/GameEngine/Source/Common/System/FileSystem.cpp

GameState.hDeclare save-read path resolver for Generals +1/-0

Declare save-read path resolver for Generals

• Adds the GameState API that resolves absolute save paths differently from relative save filenames.

Generals/Code/GameEngine/Include/Common/GameState.h

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.

Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp

GameState.hDeclare save-read path resolver for Zero Hour +1/-0

Declare save-read path resolver for Zero Hour

• Adds the mirrored GameState API for resolving absolute and relative save inputs.

GeneralsMD/Code/GameEngine/Include/Common/GameState.h

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.

GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp

Bug fix (1) +11 / -2
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.

Core/GameEngine/Source/Common/CommandLine.cpp

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown

Greptile Summary

The PR allows startup save loading from absolute paths while retaining managed-save-directory resolution for relative filenames.

  • Adds cross-platform absolute-path classification.
  • Routes save-file reads through a shared path resolver in both game variants.
  • Adds visible validation errors for queued startup saves.
  • Corrects -loadsave argument consumption when no value is present.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
Core/GameEngine/Source/Common/CommandLine.cpp Makes parseLoadSave consume a second token only when an argument is present.
Core/Libraries/Include/Lib/PathUtil.h Adds platform-aware classification for rooted Windows and POSIX paths.
Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Adds absolute-path-aware save reads and visible queued-load validation errors for Generals.
GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Mirrors the save-path and queued-load behavior for Zero Hour.
Generals/Code/GameEngine/Include/Common/GameState.h Declares the new read-path resolver for Generals.
GeneralsMD/Code/GameEngine/Include/Common/GameState.h Declares the corresponding read-path resolver for Zero Hour.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["-loadsave argument"] --> B{"Absolute path?"}
  B -- Yes --> C["Use supplied path"]
  B -- No --> D["Resolve under user Save directory"]
  C --> E["Validate extension and readability"]
  D --> E
  E -- Valid --> F["Load queued save"]
  E -- Invalid --> G["Show error and remain at main menu"]
Loading

Reviews (6): Last reviewed commit: "feat(cli): Load save files from absolute..." | Re-trigger Greptile

Comment thread Core/GameEngine/Source/Common/System/FileSystem.cpp Outdated
Comment thread Core/GameEngine/Source/Common/CommandLine.cpp Outdated
@bobtista
bobtista force-pushed the bobtista/feature/load-save-from-absolute-path branch from f98d734 to dec8476 Compare August 29, 2026 17:49

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code comments need polishing and a reduction in verbosity.

Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Outdated
Comment thread GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Outdated
@xezon xezon added Enhancement Is new feature or request Minor Severity: Minor < Major < Critical < Blocker Saveload Is Saveload/Xfer related labels Aug 31, 2026
@bobtista
bobtista force-pushed the bobtista/feature/load-save-from-absolute-path branch from dec8476 to e7b47bb Compare August 31, 2026 19:52
@xezon xezon changed the title feat(cli): Load save files from absolute paths tweak(gamestate): Support load save files from absolute paths Sep 1, 2026
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
@bobtista
bobtista force-pushed the bobtista/feature/load-save-from-absolute-path branch from e7b47bb to 7271f8e Compare September 1, 2026 15:53
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
@bobtista
bobtista force-pushed the bobtista/feature/load-save-from-absolute-path branch from 7271f8e to 80470fe Compare September 1, 2026 16:15
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
#ifdef _WIN32
const Bool hasDriveLetter = (path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z');
const Bool hasDriveRoot = hasDriveLetter && path[1] == ':' &&
(path[2] == '\\' || path[2] == '/');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too ;)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I checked for more, it was just these two that I can see

@bobtista
bobtista force-pushed the bobtista/feature/load-save-from-absolute-path branch from 80470fe to c24acb2 Compare September 1, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Is new feature or request Minor Severity: Minor < Major < Critical < Blocker Saveload Is Saveload/Xfer related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow -loadsave and -loadreplay to load files from any directory

2 participants