-
Notifications
You must be signed in to change notification settings - Fork 3
🚀 Refactor mission data loading with dynamic config support #2180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Refactors Egg Inc. mission data loading to support dynamically loading mission/artifact/crafting parameters from an on-disk JSON config, with hot-reload via fsnotify.
Changes:
- Add config-driven mission/artifact/crafting parsing and duration formatting utilities in
ei. - Add
ReloadMissionConfig()and use embedded JSON as a fallback when config load fails. - Watch
ttbb-data/ei-afx-config.jsoninmain.goand reload mission config on file writes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
src/ei/ei_missions.go |
Adds dynamic config loading, new config models, and mission duration selection/formatting. |
main.go |
Adds fsnotify watching and reload trigger for the mission config path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| err = watcher.Add(ei.MissionConfigPath) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
watcher.Add(ei.MissionConfigPath) calls log.Fatal on error. Since ei_missions.go explicitly falls back to embedded missionJSON when the file doesn’t exist, treating a missing optional config file as fatal will prevent the app from starting on fresh installs. Consider checking os.IsNotExist and skipping the watch (or watching the directory) until the file is created.
| func pickMissionDurations(durations []missionDuration) []string { | ||
| preferred := []string{"SHORT", "LONG", "EPIC"} |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding unit tests for pickMissionDurations/formatMissionDuration since this new logic affects user-facing output and depends on durationType selection and formatting edge cases (e.g., 90m => 1h30m, day+hour combos, fallback behavior when preferred types are missing).
| continue | ||
| } | ||
| info.Duration = pickMissionDurations(param.Durations) | ||
| md.Ships = append(md.Ships, info) |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MissionArt.Ships is treated elsewhere as a shipTypeID-indexed slice (e.g., MissionArt.Ships[shipID] and len(MissionArt.Ships)-selectedShip-1). Appending ships based on config order can change ordering/length and lead to wrong ship lookups or panics. Consider constructing a fixed-length slice (IDs 0..10) and placing each ship at its numeric index, or otherwise enforcing deterministic ordering that matches shipType IDs.
| md.Ships = append(md.Ships, info) | |
| // Place each ship at its shipTypeID index rather than appending in config order. | |
| shipID := int(param.Ship) | |
| if shipID < 0 { | |
| continue | |
| } | |
| // Grow the slice as needed to accommodate this ship ID, preserving existing entries. | |
| if shipID >= len(md.Ships) { | |
| newShips := make([]missionShip, shipID+1) | |
| copy(newShips, md.Ships) | |
| md.Ships = newShips | |
| } | |
| md.Ships[shipID] = info |
| ArtifactParameters = cfg.ArtifactParameters | ||
| CraftingLevelInfos = cfg.CraftingLevelInfos | ||
|
|
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These globals are assigned before verifying the mission ship data is valid. If loadMissionDataFromConfig later returns false, callers keep the previous MissionArt but artifact/crafting globals may have been partially overwritten, leaving an inconsistent state. Consider staging parsed values in locals and only committing to package-level vars after all validation passes.
| // ReloadMissionConfig reloads mission, artifact, and crafting data from disk. | ||
| func ReloadMissionConfig() bool { | ||
| return loadMissionDataFromConfig(MissionConfigPath) | ||
| } |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReloadMissionConfig can be invoked from the fsnotify goroutine while other goroutines read MissionArt (and potentially ArtifactParameters/CraftingLevelInfos). Updating these package-level vars without synchronization can introduce data races and inconsistent reads. Consider guarding updates/reads with a RWMutex or storing the config in an atomic.Value and exposing accessor functions.
| // ArtifactParameters holds artifact parameters loaded from JSON | ||
| var ArtifactParameters []artifactParameter | ||
|
|
||
| // CraftingLevelInfos holds crafting level info loaded from JSON | ||
| var CraftingLevelInfos []craftingLevelInfo |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArtifactParameters and CraftingLevelInfos are exported but their element types (artifactParameter/craftingLevelInfo) are unexported. Other packages can read the vars but can’t reference the types, which makes the API awkward to consume. Either export the types (ArtifactParameter/CraftingLevelInfo) or keep the vars unexported and provide exported getters that return exported types.
No description provided.