If Maximum == Minimum but 'crates' < Maximum, the formula would simply return min + 1 regardless of max being identical to min.
Only adding 1 more crate if Maximum is higher than Minimum fixes that.
... for looped sequences.
PlayCustomAnimationRepeating looping back into itself via Action instead of simply using Animation.PlayRepeating is weird, and in fact causes a slight 'desync' in animation speed with Animation.PlayRepeating in at least one downstream mod.
This allows activities to perform necessary cleanups on actor
death/disposal, for example by running OnLastRun directly,
which would otherwise be skipped when the actor dies or is disposed
through other means.
modify ChooseInitialMap to throw NoAvailalbeMaps exception if no maps were loaded.
implement Utilities.TryWithPrompt - safe execution of a provided action with ability to prompt user on error.
When I downloaded the assets for Red Alert through the Quick Install I noticed the progress bar proceed and display a recognizable message: `Downloading from … 1.47/12 MB (12%)`. This was fine.
When I downloaded the assets for one of the other games, maybe Dune 2000, there was obviously no total download size available. I was an unexpected message: `Downloading from … 1.47/NaN (NaN%)`
The code handling network progress events seems to be aware of the possibility that no full download size exists but it doesn't update the message. In this path I'm proposing that we display a separate messaging indicating that we don't know how much more we have to download for these cases.
Of the alternative ways to implement this I chose to move the reassignment of `getStatusText` into the conditional structures to preserve the existing choice. The message was qualitatively different and so I felt it worthwhile to create entirely different closures vs. doing something like this…
```cs
getStatusText = () => ( Double.isNaN( dataTotal ) ? "Downloading {1} of unknown amount" : "Downloading {1}/{2}" ).F( … );
```
Generating the sync report takes ~twice as long as
a normal tick, and occurs once every 3 ticks.
These reports record of all of the synced state
(separate to the sync hash, which is still calculated)
in order to generate the syncreport.log of the game
desyncs. This perf overhead is completely unnecessary
when we know that we won't have other syncreports to
compare against (singleplayer, replays).
Disabling report generation in these cases gives
us an easy 40% average tick-time win.