- Split control groups management to its own interface
- Add hotkeys for selecting, creating, adding to and combining with control groups
- Add a ControlGroups widget to manage the player interaction
- Fixed a rounding issue in `WavReader.WaveLength()`.
- Fixed `AudReader.SoundLength()` not resetting the stream position.
- Fixed crashes caused by disposed streams because `LengthInSeconds` would try and calculate the length on the fly. It is now precalculated and cached (making it consistent across all 5 current `ISoundFormat` implementations).
- Fixed a crash in `AudReader.LoadSound()`'s `out Func<Stream> result` because that func would try and access the disposed stream's `Length` property. That works for `SegmentStream`, but not for `FileStream`.
- Fixed frameCount/soundLength label positioning in the AssetBrowser window to avoid text clipping .
Splitting them from one array into separate allows us to then reliably pick how each asset should be presented. Also lets us unhardcode some checks like "if file is .vxl ... else is sprite".
- Extract chat line templates and logic so they can be reused across widgets
- Make text notification styling entirely template driven (by removing chat color configuration and making color optional for `TextNotification`)
- Add a new TextNotificationsDisplay widget (based on and replacing ChatDisplayWidget)
- Add timestamp support to text notifications
Well, 05eb really, but until we implement campaign progression,
calling it 'c' is the easiest way to differentiate it without breaking
our mission title length/alignment conventions.
The trait documentation specified that the speed
and offset values are px/tick, but they have actually
always been treated as px/render.
Fix the update logic and rescale the map definitions
to account for the fixed behaviour.
Forces the chat and performance panels to be re-initialized when a
player transitions to spectators. This ensures that spectators don't
get to see faction themed widgets.