Fix GUI weather: valid IDs, defer & reset
Replace invalid Fallout 4 weather form IDs with valid ones (including fixing Clear from 0002852a -> 0002b52a) and update protocol examples and server presets accordingly. Change the plugin to re-queue/defer server weather payloads when the local assigned player ID is not yet available (so early GUI clicks are not dropped) and add a log entry when deferring. Reset player/host assignment on server startup (_next_player_id = 1 and clear _world_state_host_player_id) to avoid stale host IDs after restarts. Also update changelog and developer log entries describing the fixes and recommended manual testing steps.
This commit is contained in:
@@ -20,9 +20,14 @@ For testing notes, milestone summaries, known issues, and next steps, see [`docs
|
||||
### Fixed
|
||||
- Server GUI weather now runs `fw <8-digit-form-id>` on player 1 only (not editor names), scheduled on the game thread.
|
||||
- Weather `serverWorldState` packets are broadcast to all clients so player 1's game instance always receives them.
|
||||
- Server restart now resets player/host assignment so the first client is `playerId` 1 again, preventing GUI weather from being ignored after restart.
|
||||
- Plugin now defers server weather commands until player assignment is available, preventing initial GUI clicks from being dropped right after connect.
|
||||
- Replaced invalid default GUI weather IDs with valid Fallout 4 weather form IDs so `fw <id>` no longer fails with "Invalid weather ...".
|
||||
- Corrected `Clear` preset ID typo from `0002852a` to valid `0002b52a` (`CommonwealthClear`).
|
||||
|
||||
### Changed
|
||||
- Weather presets store the exact `fw` console argument (8-digit hex); edit `server/world_state_presets.py` only if a preset ID fails in your console.
|
||||
- Updated protocol weather examples/default preset table to match the new valid Fallout 4 preset IDs.
|
||||
- World time no longer re-applies on every `worldState` heartbeat; weather heartbeats continue at ~1 Hz while time stays in sync during normal gameplay.
|
||||
- Reformatted `changelog.md` to follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
|
||||
@@ -9,6 +9,92 @@ failed experiments, successful tests, and next steps.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Replace Invalid GUI Weather IDs
|
||||
|
||||
### Summary
|
||||
Fixed GUI weather presets that were using invalid weather IDs (`00148c..`), which caused Fallout 4 to report `Invalid weather '<id>' for parameter Weather ID.` when running `fw`.
|
||||
|
||||
### Files Changed
|
||||
- `server/world_state_presets.py`
|
||||
- `protocol/server-world-state.md`
|
||||
- `changelog.md`
|
||||
|
||||
### Details
|
||||
- Updated default GUI weather presets to valid Fallout 4 weather form IDs:
|
||||
- Clear: `0002b52a` (corrected from typo `0002852a`)
|
||||
- Cloudy: `001cc186`
|
||||
- Overcast: `001c8556`
|
||||
- Fog: `001c3473`
|
||||
- Rain: `001ca7e4`
|
||||
- Radstorm: `001c3d5e`
|
||||
- Glowing Sea: `000f1033`
|
||||
- Updated protocol examples/documentation to match these IDs.
|
||||
|
||||
### Testing
|
||||
- Not re-tested in-game in this session.
|
||||
- User-provided screenshot confirms previous IDs failed with `Invalid weather` in console.
|
||||
- Recommended: run `fw <each preset id>` manually once, then verify GUI buttons trigger the same IDs.
|
||||
|
||||
### Known Issues
|
||||
- Weather IDs can differ with unusual load-order/mod setups; override presets in `server/world_state_presets.py` if needed.
|
||||
|
||||
### Next Steps
|
||||
- Restart server GUI so it loads updated presets, then test one-click weather changes outdoors.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Reset Player IDs on Server Restart
|
||||
|
||||
### Summary
|
||||
Fixed a restart regression where GUI weather could silently do nothing after server restarts because player IDs and world-state host assignment were not reset between runs.
|
||||
|
||||
### Files Changed
|
||||
- `server/server_core.py`
|
||||
- `changelog.md`
|
||||
|
||||
### Details
|
||||
- Server startup now resets `_next_player_id` to `1`.
|
||||
- Server startup now clears `_world_state_host_player_id` so the first newly connected client becomes the host for that run.
|
||||
- This keeps the plugin's weather gate (`playerId == 1`) aligned after restart.
|
||||
|
||||
### Testing
|
||||
- Not re-tested in-game in this session.
|
||||
- Recommended: start server, connect client, set weather; stop server; start again; reconnect same client and set weather again.
|
||||
|
||||
### Known Issues
|
||||
- None currently known.
|
||||
|
||||
### Next Steps
|
||||
- Rebuild/reload as needed, then verify `CommonwealthOnline.log` shows weather command execution after both first start and restart.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Defer Weather Until Player Assignment
|
||||
|
||||
### Summary
|
||||
Fixed intermittent GUI weather clicks by deferring weather apply when `serverWorldState` arrives before local player assignment is complete.
|
||||
|
||||
### Files Changed
|
||||
- `plugin/src/F4TWorldStateSync.cpp`
|
||||
- `changelog.md`
|
||||
|
||||
### Details
|
||||
- If a weather request arrives before `GetAssignedPlayerId()` is available, the plugin now re-queues that server world-state payload instead of discarding it.
|
||||
- Once assignment completes, player 1 applies the queued weather command normally.
|
||||
- Non-player-1 clients still ignore weather commands as intended.
|
||||
|
||||
### Testing
|
||||
- Not re-tested in-game in this session.
|
||||
- Recommended: connect client, immediately click weather once in GUI, confirm the first click now applies without repeated clicks.
|
||||
|
||||
### Known Issues
|
||||
- None currently known.
|
||||
|
||||
### Next Steps
|
||||
- Verify in logs that early weather packets show a one-time "deferred" message followed by weather command execution after assignment.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-23 - GUI Weather Uses Numeric `fw` ID
|
||||
|
||||
### Summary
|
||||
|
||||
@@ -268,10 +268,11 @@ namespace
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool IsAssignedPlayerOne()
|
||||
void RequeueServerWorldState(F4T::WorldStateSync::PendingServerWorldState a_state)
|
||||
{
|
||||
const auto assignedPlayerId = F4T::RemotePlayerState::GetAssignedPlayerId();
|
||||
return assignedPlayerId && *assignedPlayerId == 1U;
|
||||
const std::scoped_lock lock(g_pendingMutex);
|
||||
g_pendingServerWorldState = std::move(a_state);
|
||||
g_hasPendingServerWorldState = true;
|
||||
}
|
||||
|
||||
bool ShouldSendTimeState(float a_gameHour, float a_gameDaysPassed)
|
||||
@@ -425,7 +426,16 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAssignedPlayerOne()) {
|
||||
const auto assignedPlayerId = F4T::RemotePlayerState::GetAssignedPlayerId();
|
||||
if (!assignedPlayerId) {
|
||||
RequeueServerWorldState(a_state);
|
||||
if (ShouldLog("server_world_state_weather_defer")) {
|
||||
LogInfo("Deferred server weather command until local player assignment is available.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (*assignedPlayerId != 1U) {
|
||||
if (ShouldLog("server_world_state_weather_skip")) {
|
||||
LogInfo("Ignored server weather command on non-player-1 client.");
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ Weather (all clients receive; only player 1 acts):
|
||||
```json
|
||||
{
|
||||
"type": "serverWorldState",
|
||||
"weatherConsoleArg": "00148c45",
|
||||
"weatherFormId": "00148C45",
|
||||
"weatherConsoleArg": "001ca7e4",
|
||||
"weatherFormId": "001CA7E4",
|
||||
"serverTime": 1780212128.301
|
||||
}
|
||||
```
|
||||
@@ -53,13 +53,13 @@ Edit `server/world_state_presets.py` so each preset uses the exact `fw` ID that
|
||||
|
||||
| Label | Default `fw` arg |
|
||||
|-------|------------------|
|
||||
| Clear | `00148c3c` |
|
||||
| Cloudy | `00148c42` |
|
||||
| Overcast | `00148c43` |
|
||||
| Fog | `00148c44` |
|
||||
| Rain | `00148c45` |
|
||||
| Radstorm | `00148c47` |
|
||||
| Glowing Sea | `001b9779` |
|
||||
| Clear | `0002b52a` |
|
||||
| Cloudy | `001cc186` |
|
||||
| Overcast | `001c8556` |
|
||||
| Fog | `001c3473` |
|
||||
| Rain | `001ca7e4` |
|
||||
| Radstorm | `001c3d5e` |
|
||||
| Glowing Sea | `000f1033` |
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
|
||||
@@ -205,6 +205,11 @@ class FalloutTogetherServer:
|
||||
self._server_socket = server_socket
|
||||
self._running = True
|
||||
self._started_at = time.time()
|
||||
# Each server run is a fresh session for player/host assignment.
|
||||
# Without this reset, restarts can leave stale host IDs and player IDs
|
||||
# > 1, which breaks weather commands gated to player 1.
|
||||
self._next_player_id = 1
|
||||
self._world_state_host_player_id = None
|
||||
|
||||
self._log(f"Commonwealth Online server listening on {self.host}:{self.port}")
|
||||
self._log(f"LAN discovery listening on UDP port {DISCOVERY_PORT}")
|
||||
|
||||
@@ -6,13 +6,13 @@ from __future__ import annotations
|
||||
# `fw_console_arg` is passed directly to the in-game `fw` command on player 1
|
||||
# (8-digit hex form ID, not an editor name like CommonwealthRain).
|
||||
WEATHER_PRESETS: list[tuple[str, str]] = [
|
||||
("Clear", "00148c3c"),
|
||||
("Cloudy", "00148c42"),
|
||||
("Overcast", "00148c43"),
|
||||
("Fog", "00148c44"),
|
||||
("Rain", "00148c45"),
|
||||
("Radstorm", "00148c47"),
|
||||
("Glowing Sea", "001b9779"),
|
||||
("Clear", "0002b52a"),
|
||||
("Cloudy", "001cc186"),
|
||||
("Overcast", "001c8556"),
|
||||
("Fog", "001c3473"),
|
||||
("Rain", "001ca7e4"),
|
||||
("Radstorm", "001c3d5e"),
|
||||
("Glowing Sea", "000f1033"),
|
||||
]
|
||||
|
||||
# HHmm values for the in-game `set gamehour to HHmm` console command.
|
||||
|
||||
Reference in New Issue
Block a user