1. Tổng quan
- 30 event có trong code: 28 event nghiệp vụ, 1 event lỗi cấu hình skin, 1 event debug.
- Gần như toàn bộ đi qua
game/Source/platform/AnalyticsTrack.cpp (namespace phoenix::analytics), gọi game_beacon::trackEvent. - Ngoại lệ:
ab_exposure, ad_revenue_sdk bắn trong game/game_beacon/GameBeacon.cpp; skin_config_invalid, debug_test_event gọi beacon trực tiếp.
Nơi nhận (sink)
| Nền tảng | Gửi tới | File |
|---|
| Android | Firebase Analytics logEvent | game_beacon/AndroidBeacon.cpp + GameBeaconBridge.java |
| iOS | FIRAnalytics logEventWithName | game_beacon/IosBeacon.mm |
| Web | Firebase JS logEvent (project block-club-4ad1b) | game_beacon/WebBeacon.cpp + game_beacon/web/src.js |
| Desktop macOS | Không gửi (gb_platform_event trả false) | game_beacon/DesktopBeacon.cpp |
Cổng chặn / hàng đợi
- Event trước
game_beacon::initialize() bị bỏ (not_ready). Vì vậy app_launch chụp mốc sớm, bắn sau init. - Consent: chạy thường cấp consent ngay sau init (
AppDelegate.cpp:183). Chưa có consent thì event xếp hàng (tối đa 256), riêng ad_revenue_sdk native thì bị bỏ. - Chế độ QA (
--qa): không cấp consent, không bắn chuỗi launch, không bắn app_session_*. - Giới hạn 19 param/event (25 trừ 6 common). Chế độ strict (chỉ cho event trong plan) không bật (
GAME_BEACON_STRICT không định nghĩa), nên event ngoài plan vẫn gửi. - Log logcat
[TRACK] <event> <json> khi build với -DGAME_BEACON_TRACK_LOG=ON.
2. Common params (tự gắn vào mọi event qua trackEvent)
| Param | Kiểu | Giá trị |
|---|
game_mode | string | classic / adventure khi đang ván; none khi rời bàn. Event tự truyền thì giữ giá trị của event |
schema_version | int | luôn 1 |
event_id | string | UUID v4 sinh lúc track |
environment | string | production khi có khoá MAX thật, còn lại demo |
app_build | int | số build của app |
app_session_id | string | UUID phiên, chỉ có khi đang trong phiên |
Ngoại lệ: ad_revenue_sdk bản web bắn thẳng từ JS, không có common params.
3. Chuỗi khởi động (Launch)
Chỉ bắn khi không phải QA. Mọi mốc có launch_id (UUID mỗi lần mở), start_time (Unix giây, có phần lẻ), duration (giây, từ mốc trước), app_launch_duration (giây, từ app_launch).
| Event | Param riêng | Kích hoạt thật | Ghi chú |
|---|
app_launch | launch_id, start_time | AppDelegate.cpp:176 sau init beacon | Thời điểm chụp ở launchBegin() (dòng 173) |
app_init | mốc | AppDelegate.cpp:229 sau set design resolution | |
load_start | mốc | AppDelegate.cpp:257 | |
load_save | mốc + has_save (0/1), status (0/1) | AppDelegate.cpp:267 | duration = thời gian đọc + parse save phoenix.game.save |
load_end | mốc + status (luôn 1) | AppDelegate.cpp:324 trước startGame() | duration = load_end trừ load_start |
app_ready | mốc + entry_screen | LobbyScreens.cpp:653 (lobby) hoặc BoardPlay.cpp:1960 (tutorial/adventure/classic) | 1 lần mỗi lần mở app |
4. Phiên (Session)
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
app_open | open_type = cold_start / foreground_resume | Bắn kèm mỗi app_session_start | Luôn đi đôi với session_start |
app_session_start | app_session_id, start_reason (cùng giá trị open_type) | AppDelegate.cpp:185 (mở lạnh), :361 (quay lại foreground) | Sinh session id mới mỗi lần |
app_session_end | app_session_id, duration_ms, end_reason = app_background | AppDelegate.cpp:345 khi vào background | Kill app không qua background thì không có |
5. Classic (Endless)
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
round_start | game_mode=classic, round_id (r_<uuid>) | BoardPlay.cpp:937 (Continue sau ván), :1060 (resume ra game over, dựng ván mới), :1078 (ván mới) | Resume ván dở (:1051) không bắn, khôi phục round_id cũ |
round_end | round_id, score, duration (giây chơi), ad_duration (giây xem quảng cáo), moves_count, revive_count, end_reason | BoardPlay.cpp:773 khi game over | end_reason: no_space_left (chết) / finish (bỏ cuộc qua Settings). Không bắn ở skin preview |
6. Adventure (Travel)
Base chung: game_mode=adventure, round_id, level (int), level_id (string số màn), attempts (số lần bắt đầu màn).
| Event | Param thêm | Kích hoạt thật | Ghi chú |
|---|
level_start | base | BoardPlay.cpp:526, :545 | Resume (:531) không bắn |
level_end | success (0/1), reason, duration, ad_duration, moves_count, revive_count, boosters_used | BoardPlay.cpp:768 (win), :770 (no_space_left) | Bỏ cuộc giữa màn không bắn level_end |
level_continue | offer_id, continue_type, duration, revive_count, boosters_used | Popup hồi sinh trong Adventure (xem mục 8) | Thay cho revive_action khi mode adventure. continue_type: quit / watch_ad / timeout |
duration, ad_duration là giây nguyên (cắt phần lẻ). Đồng hồ chơi dừng khi rời bàn, vào background, xem quảng cáo; giá trị lưu UserDefault nên resume vẫn cộng tiếp. moves_count tăng mỗi lần đặt khối (BoardPlay.cpp:723).
7. Tutorial
Base: game_mode=classic, tutorial_id, step_id, tutorial_variant, guide_config_key (nếu có), tutorial_run_id (tr_<uuid>).
| Event | Param thêm | Kích hoạt thật | Ghi chú |
|---|
tutorial_start | base | BoardPlay.cpp:2071 (classic_fixed_guide, step = guideStep, key g_<step>), :2095 (classic_in_game_guide, step 1) | Mỗi (run, id, step) chỉ 1 lần, kể cả dựng lại màn hay mở lại app. Không bắn ở QA |
tutorial_end | duration (giây), completion_source | BoardPlay.cpp:2735 (fixed guide), :2739 (in-game guide, player_place) | Fixed guide: completion_source phân biệt người chơi tự đặt và nút Skip tự đặt (skip_button_auto_place) |
Run mới (newTutorialRun, BoardPlay.cpp:1208): lần đầu chọn biến thể, hoặc ép ?tut=N.
8. Hồi sinh (Revive)
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
revive_offer | round_id, offer_id (rv_<uuid>), score, revive_count, offer_style (standard/countdown) | BoardPlay.cpp:2135 khi mở popup | Rewarded chưa sẵn thì bỏ popup, không bắn |
revive_action (classic) | game_mode, round_id, offer_id, action, score, revive_count | ReviveScreens.cpp:275 (decline), :287/:472 (watch_ad), :513 (timeout) | Score/revive_count lấy theo lúc offer |
revive_success | round_id, offer_id, ad_request_id, score, revive_count | BoardPlay.cpp:2153 sau khi hồi sinh xong | |
watch_ad bắn trước khi quảng cáo hiện, nên không nói lên việc xem xong. Xem xong thật thì nhìn revive_success / ad_reward.
9. Booster
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
use_booster | round_id, level_id (int), booster_type, source (infinite/inventory), remaining_count (bỏ khi infinite) | BoardPropRack.cpp:516 | Chỉ booster Adventure. booster_type: hammer, clear, universal, cannon, hammer_drop. Bắn sau khi dùng thành công (dùng hỏng được hoàn lượt, không bắn) |
10. Thưởng hằng ngày (Daily First Win)
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
daily_reward_claim | reward_id (dfw_<day>), source (claim/ad_double), item_type=revive_card, amount, balance, streak_day, ad_request_id (chỉ khi ad_double) | DailyFirstWinRewardView.cpp:118 (nhận thường), :136 (x2 sau quảng cáo) | |
11. Quảng cáo
Chung: ad_request_id (ad_<uuid>), ad_format (rewarded/interstitial), location (placement). Logic ở Source/ads/AdService.cpp:353 trở đi, có 2 nhánh: MAX thật và demo.
| Event | Param thêm | Kích hoạt thật |
|---|
skl_ad_request | round_id (nếu đang ván) | Mọi lần gọi show (AdService.cpp:359), kể cả khi ad chưa sẵn |
skl_ad_show | | Ngay trước khi show (:394 MAX, :435 demo). Bắt đầu tính ad_duration |
ad_reward | ad_request_id, location | Rewarded thành công (:375, :414) |
skl_ad_close | reward_received (0/1) | Đóng ad thành công (:377, :417) |
skl_ad_display_failed | stage (load/show), error_code | load+not_ready khi ad chưa sẵn (:388, :428); show+max_show_failed/demo_show_failed khi lỗi sau show |
ad_revenue_sdk | ad_mediation=appLovin, ad_network, ad_format, ad_mediation_unit_id, location, value, currency, revenue_precision | Callback doanh thu MAX native (GameBeacon.cpp:726, gọi từ AndroidAds.cpp:66, IosAds.mm:81) |
Placement thật đang dùng:
| Placement | Format | Nơi gọi |
|---|
revive_rewarded | rewarded | ReviveScreens.cpp:289, :474 |
travel_prop_hammer / travel_prop_clear / travel_prop_universal | rewarded | BoardPropRack.cpp:610 (hết lượt booster) |
DailyWinDoubleReward | rewarded | DailyFirstWinRewardView.cpp:125 |
endInsertFail | interstitial | BoardPlay.cpp:888 (thua) |
frontInsertRestart | interstitial | BoardPlay.cpp:926 (chơi lại) |
| banner | banner | AdsCoordinator.cpp:240, không có event nào |
12. A/B và khác
| Event | Param | Kích hoạt thật | Ghi chú |
|---|
ab_exposure | experiment, variant | GameBeacon.cpp:371, khi đọc key Remote Config gắn experiment (getConfigString/Int/Float, dòng 570/587/599) | 1 lần mỗi (key, variant) mỗi phiên; xếp hàng chờ consent |
skin_config_invalid | reason=audio_missing, key | SkinAudioResolver.cpp:139 khi skin thiếu file âm thanh | Ngoài plan, vẫn gửi vì strict tắt |
debug_test_event | source=debug_panel | DebugStatusPanel.cpp:351, nút trong panel debug | Chỉ bấm tay từ debug panel |
13. Nhận xét từ code (chỗ cần lưu ý khi đọc số)
- Adventure bỏ cuộc không có level_end. Màn bị bỏ giữa chừng chỉ có
level_start; tỉ lệ thắng/thua tính theo level_end sẽ thiếu nhóm này. - Revive tách 2 event theo mode. Classic dùng
revive_action (decline), Adventure dùng level_continue (quit). Cùng hành động nhưng tên event và giá trị khác nhau. watch_ad bắn trước khi xem. Không dùng để đếm lượt xem xong.- Banner không có event request/show/close/revenue (trừ revenue MAX native nếu SDK báo).
- Demo không có
ad_revenue_sdk. Nhánh demo chỉ gọi callback nội bộ (fireRevenue, AdService.cpp:119). Environment demo sẽ không có doanh thu. ad_revenue_sdk native bị bỏ khi chưa consent, không xếp hàng như các event khác.ad_revenue_sdk web bắn từ JS mỗi impression, không có value/currency, không có common params, ad_mediation = Google H5 Games Ads.skl_ad_request bắn cả khi ad chưa sẵn, luôn đi kèm skl_ad_display_failed stage load. Fill rate = (request trừ failed load) / request.use_booster chỉ có ở Adventure; level_id ở đây là int, khác level_id string của level_start.app_session_end chỉ khi vào background. App bị kill/crash không có end; phiên web đóng tab có thể thiếu.app_open luôn trùng app_session_start (cùng thời điểm, cùng lý do), nên đếm 1 trong 2.- Đơn vị thời gian lẫn lộn: chuỗi launch dùng giây có phần lẻ; round/level/tutorial dùng giây nguyên (cắt); session dùng
duration_ms. - Desktop không gửi gì; QA mode không gửi gì ra ngoài.
- 2 event ngoài plan vẫn lên Firebase (
skin_config_invalid, debug_test_event) vì strict mode tắt. debug_test_event sẽ lẫn vào dữ liệu production nếu ai bấm trên bản phát hành có debug panel.
Phụ lục: đối chiếu nhanh với plan (thứ yếu)
- 28 event trong
tracking-plan.yaml đều có code bắn. - Code có thêm 2 event ngoài plan:
skin_config_invalid, debug_test_event.