Also make the poll interval configurable.
For the case of one targeter, the UI scans through the ActorTable to
find the relevant Actor, achieving either a partial or full scan. In
the case of more than one targeter, the UI constructs a Dictionary
mapping ActorId to Actor, then indexes that dictionary for each
targeter. This achieves one full scan, which may or may not be more
efficient than multiple partial scans, depending on where the actors
are located in the table.
The UI must do this because current targeters are no longer guaranteed
to be spawned anymore, especially with a high polling frequency, and
the UI needs accurate information about the targeters' address in
memory.
This has some consequences. First, LocalPlayer is no longer necessary
for rendering the UI, meaning the UI stays open even during loading
screens and other situations where there is no player.
Secondly, the sound effect will play even when the window is closed.
Thirdly, the history will update even when the window is closed.
The last two points will become config options in future.
I would also like to make TargetWatcher run in a task and run perhaps
every 100ms instead of every framework update.