Rate limiting
High-frequency hooks can emit hundreds of events. Deduplicate by semantic event key and enforce a cooldown before showing or playing repeated feedback.
import BigWorld
_last_notice = {}
def _can_notify(key, cooldown=2.0):
now = BigWorld.time()
previous = _last_notice.get(key, -100000.0)
if now - previous < cooldown:
return False
_last_notice[key] = now
return True
Localization and formatting
Resolve complete localized messages with placeholders. Do not expose internal identifiers, raw exception text, or untranslated resource keys to users.
Context awareness
A lobby notification service may not exist in battle, and a battle sound system may disappear during teardown. Missing presentation should not fail the underlying feature.
Native formatter contracts
System-message templates with similar names may require different fields, icons, priorities, and decorators. Inspect the formatter and template before reuse; missing a required field can produce malformed or invisible text.
- Deep-copy payload dictionaries before passing them to a formatter that may mutate them.
- Keep an owned fallback for unknown payload structures.
- Use the system-specific template when its icon or interaction is part of the user experience.
- When replacing only the visible notification, preserve the original server message in notification history unless there is a verified reason not to.
Actionable notifications
Register action handlers through the owning factory, add them to an already-created controller only when necessary, and remove only the handlers owned by the mod. Track the last published message ID and replace it instead of accumulating stale control cards.
Notification clicks often dismiss the card. Republish an updated state on a zero-delay callback after processing the action.
- Treat the returned client message ID as the removal handle. If publishing returns no truthy ID, do not remember it as an active message.
- Some notification controllers build action-handler maps during MVC initialization. Static registration can be enough before that point; late-loaded mods may need to patch the live owner and undo only their own live entries.
- Single-action handlers and multi-action handlers may be keyed differently. Verify how the current controller maps notification type and action name before registering.
Message result helpers
Native result helpers can treat auxiliary data as either extra messages or caller context, depending on its shape. Before passing custom payloads, inspect whether the helper forwards the data to the formatter, expands it into messages, or keeps it for the caller.
Message facades do not acknowledge display
The SystemMessages facade and its registered interface discard the service channel's return value. A None result therefore does not establish failed admission. When GUI operation is disabled, the interface logs the text instead of placing it in a deferred message backlog.
pushI18nMessage sends all supplied keyword arguments to translation, then extracts type, priority and messageData for publication. It does not forward savedData through that convenience path. The client formatter merges messageData over its initial text context, so a supplied text entry replaces the original text; saved template data is a separate field on the direct publication path. Keep translation values, template context and saved action data distinct.
The service channel catches formatter failures before admission. For nonempty output it instead allocates an ID, stores history and increments unread state before firing the ordinary receive event. A listener exception can therefore surface after storage changed. Do not treat every raised publication call as proof that nothing was stored, or blindly retry it as a new notification. These are source and recording-fixture results, not proof of popup display, native delivery timing or real localization behavior.
Common mistakes
- Playing a sound on every frame or repeated property update.
- Using notifications as a substitute for structured logs during development.
- Showing raw server payloads or exceptions to users.
- Calling a lobby notification API from battle teardown.
- Failing initialization because an optional sound resource is missing.
Verification trail
Find current message and sound call sites in the same UI context. Confirm resource existence, localization path, throttling needs, and teardown behavior.