Block Club: báo cáo event tracking thực tế trong game

Nguồn: đọc trực tiếp code đang bắn event (không dựa file Excel/CSV/YAML).
Nhánh bundle-skin, ngày 04/11/2026.

1. Tổng quan

Nơi nhận (sink)

Nền tảngGửi tớiFile
AndroidFirebase Analytics logEventgame_beacon/AndroidBeacon.cpp + GameBeaconBridge.java
iOSFIRAnalytics logEventWithNamegame_beacon/IosBeacon.mm
WebFirebase JS logEvent (project block-club-4ad1b)game_beacon/WebBeacon.cpp + game_beacon/web/src.js
Desktop macOSKhông gửi (gb_platform_event trả false)game_beacon/DesktopBeacon.cpp

Cổng chặn / hàng đợi

2. Common params (tự gắn vào mọi event qua trackEvent)

ParamKiểuGiá trị
game_modestringclassic / adventure khi đang ván; none khi rời bàn. Event tự truyền thì giữ giá trị của event
schema_versionintluôn 1
event_idstringUUID v4 sinh lúc track
environmentstringproduction khi có khoá MAX thật, còn lại demo
app_buildintsố build của app
app_session_idstringUUID 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).

EventParam riêngKích hoạt thậtGhi chú
app_launchlaunch_id, start_timeAppDelegate.cpp:176 sau init beaconThời điểm chụp ở launchBegin() (dòng 173)
app_initmốcAppDelegate.cpp:229 sau set design resolution
load_startmốcAppDelegate.cpp:257
load_savemốc + has_save (0/1), status (0/1)AppDelegate.cpp:267duration = thời gian đọc + parse save phoenix.game.save
load_endmốc + status (luôn 1)AppDelegate.cpp:324 trước startGame()duration = load_end trừ load_start
app_readymốc + entry_screenLobbyScreens.cpp:653 (lobby) hoặc BoardPlay.cpp:1960 (tutorial/adventure/classic)1 lần mỗi lần mở app

4. Phiên (Session)

EventParamKích hoạt thậtGhi chú
app_openopen_type = cold_start / foreground_resumeBắn kèm mỗi app_session_startLuôn đi đôi với session_start
app_session_startapp_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_endapp_session_id, duration_ms, end_reason = app_backgroundAppDelegate.cpp:345 khi vào backgroundKill app không qua background thì không có

5. Classic (Endless)

EventParamKích hoạt thậtGhi chú
round_startgame_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_endround_id, score, duration (giây chơi), ad_duration (giây xem quảng cáo), moves_count, revive_count, end_reasonBoardPlay.cpp:773 khi game overend_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).

EventParam thêmKích hoạt thậtGhi chú
level_startbaseBoardPlay.cpp:526, :545Resume (:531) không bắn
level_endsuccess (0/1), reason, duration, ad_duration, moves_count, revive_count, boosters_usedBoardPlay.cpp:768 (win), :770 (no_space_left)Bỏ cuộc giữa màn không bắn level_end
level_continueoffer_id, continue_type, duration, revive_count, boosters_usedPopup 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>).

EventParam thêmKích hoạt thậtGhi chú
tutorial_startbaseBoardPlay.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_endduration (giây), completion_sourceBoardPlay.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)

EventParamKích hoạt thậtGhi chú
revive_offerround_id, offer_id (rv_<uuid>), score, revive_count, offer_style (standard/countdown)BoardPlay.cpp:2135 khi mở popupRewarded chưa sẵn thì bỏ popup, không bắn
revive_action (classic)game_mode, round_id, offer_id, action, score, revive_countReviveScreens.cpp:275 (decline), :287/:472 (watch_ad), :513 (timeout)Score/revive_count lấy theo lúc offer
revive_successround_id, offer_id, ad_request_id, score, revive_countBoardPlay.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

EventParamKích hoạt thậtGhi chú
use_boosterround_id, level_id (int), booster_type, source (infinite/inventory), remaining_count (bỏ khi infinite)BoardPropRack.cpp:516Chỉ 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)

EventParamKích hoạt thậtGhi chú
daily_reward_claimreward_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.

EventParam thêmKích hoạt thật
skl_ad_requestround_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_showNgay trước khi show (:394 MAX, :435 demo). Bắt đầu tính ad_duration
ad_rewardad_request_id, locationRewarded thành công (:375, :414)
skl_ad_closereward_received (0/1)Đóng ad thành công (:377, :417)
skl_ad_display_failedstage (load/show), error_codeload+not_ready khi ad chưa sẵn (:388, :428); show+max_show_failed/demo_show_failed khi lỗi sau show
ad_revenue_sdkad_mediation=appLovin, ad_network, ad_format, ad_mediation_unit_id, location, value, currency, revenue_precisionCallback doanh thu MAX native (GameBeacon.cpp:726, gọi từ AndroidAds.cpp:66, IosAds.mm:81)

Placement thật đang dùng:

PlacementFormatNơi gọi
revive_rewardedrewardedReviveScreens.cpp:289, :474
travel_prop_hammer / travel_prop_clear / travel_prop_universalrewardedBoardPropRack.cpp:610 (hết lượt booster)
DailyWinDoubleRewardrewardedDailyFirstWinRewardView.cpp:125
endInsertFailinterstitialBoardPlay.cpp:888 (thua)
frontInsertRestartinterstitialBoardPlay.cpp:926 (chơi lại)
bannerbannerAdsCoordinator.cpp:240, không có event nào

12. A/B và khác

EventParamKích hoạt thậtGhi chú
ab_exposureexperiment, variantGameBeacon.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_invalidreason=audio_missing, keySkinAudioResolver.cpp:139 khi skin thiếu file âm thanhNgoài plan, vẫn gửi vì strict tắt
debug_test_eventsource=debug_panelDebugStatusPanel.cpp:351, nút trong panel debugChỉ bấm tay từ debug panel

13. Nhận xét từ code (chỗ cần lưu ý khi đọc số)

  1. 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.
  2. 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.
  3. watch_ad bắn trước khi xem. Không dùng để đếm lượt xem xong.
  4. Banner không có event request/show/close/revenue (trừ revenue MAX native nếu SDK báo).
  5. 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.
  6. ad_revenue_sdk native bị bỏ khi chưa consent, không xếp hàng như các event khác.
  7. 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.
  8. 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.
  9. use_booster chỉ có ở Adventure; level_id ở đây là int, khác level_id string của level_start.
  10. 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.
  11. 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.
  12. Đơ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.
  13. Desktop không gửi gì; QA mode không gửi gì ra ngoài.
  14. 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)