Your first goal is simple: make the client load one file and
write one unmistakable line to game.log. Once that works, add only one visible
behavior and learn when it starts and stops.
Choose a comfortable depth
The sidebar setting hides pages above your selected maximum difficulty.
Your goal on this page
Choose one small, visible behavior and define when it starts and stops. You are not expected to know every client system yet.
The shortest useful beginner path
- Open First Mod & Safe Patching and create the tiny loader example.
- Launch the client, wait for the garage, and confirm the message in
game.log. - Restart the client and repeat the same test before adding settings, UI, networking, or persistence.
- Continue with Level 1: Configurable Garage Greeting. The ten production tutorials turn the loader check into complete mods while gradually introducing events, battles, Gameface, persistence, integration, analytics, and replay-safe telemetry.
Beginner translations
| Guide term | Plain meaning |
|---|---|
| Hook | Run your code before or after a game function without replacing the complete game file. |
| Lifecycle | When an account, battle, view, cache, or other object appears, is usable, and disappears. |
| Context | The active part of the client, such as login, garage, battle, or replay. |
| Ready | The object exists and the specific data or service you need has finished loading. |
| Cleanup | Cancel callbacks, remove listeners, close UI, and forget references when their context ends. |
How the client changes around your mod
Client starts
↓ your mod file is imported
Login screen
↓ account session is created
Garage
↓ garage views are destroyed
Battle loading
↓ battle avatar and arena become ready
Battle
↓ battle objects are destroyed
Garage is created again
A mod can stay loaded through this entire sequence while the game objects it uses are repeatedly created and destroyed. That is why code must wait for the right moment and release temporary objects afterwards.
Describe the first feature in plain language
State the visible result
Write one sentence describing what the player should see or what local behavior should change. Do not combine several features yet.
Name the runtime context
Say where it should work: login, garage, battle, replay, one window, or the whole account session.
Choose one source of truth
Find the game object or event that actually provides the value instead of copying it from whichever screen happens to show it.
Write the stop condition
Disconnect, account switch, arena exit, view destruction, setting disabled, request failure, or completion.
Use a controller, not scattered globals
One owner makes duplicate prevention and teardown much easier. Save exact handler identities and callback IDs on that owner.
class FeatureController(object):
def __init__(self):
self._started = False
self._callback_id = None
self._generation = 0
self._on_sync = self._handle_sync
def start(self):
if self._started:
return
self._started = True
self._generation += 1
player_events.onClientUpdated += self._on_sync
def stop(self):
if not self._started:
return
self._started = False
self._generation += 1
player_events.onClientUpdated -= self._on_sync
self._cancel_callback()
self._destroy_view()
def _handle_sync(self, diff):
if not self._started:
return
self.refresh(diff)
Separate local display from server-changing actions
Visual-only
Local text, markers, colors, projections, layout, filters, and read-only summaries.
Local state
Saved positions, preferences, caches, and user-created presets.
Server-changing
Requests that activate, claim, purchase, select, ready, or otherwise alter account or prebattle state.
Get one visible result first
Before designing a large system, confirm that a correctly packaged mod_*.py module
loads and produces one observable effect. Continue with First Mod &
Safe Patching for the loader path, lifecycle functions, wrappers, callbacks,
compilation, and packaging.
Build in this order
- Confirm the current client API and the event that owns readiness.
- Create the smallest behavior without persistence or automation.
- Add teardown immediately and test repeated start/stop.
- Add delayed work with cancellation and stale-context guards.
- Add persistence, validation, diagnostics, and optional fallbacks.
- Test disconnect, battle transitions, view rebuilds, reloads, and missing dependencies.
Failure should be narrow
try:
from optional_feature.controller import get_controller
except ImportError:
get_controller = None
def try_start_optional_feature():
if get_controller is None:
logger.info('Optional integration is unavailable')
return False
try:
controller = get_controller()
return controller is not None
except Exception:
logger.exception('Optional integration failed to initialize')
return False