namespace Guru { using System; using System.Collections.Generic; using UnityEngine; /// /// 打点管理 /// public partial class GuruSDK { /// /// 主线关卡类型 /// 只有传入此类型时才会进行 Blevel 的累加 /// public const string LevelTypeMain = "main"; //----------------- 关卡开始类型 --------------------- public const string EventLevelStartModePlay = "play"; public const string EventLevelStartModeReplay = "replay"; public const string EventLevelStartModeContinue= "continue"; //----------------- 关卡结束类型 --------------------- public const string EventLevelEndSuccess = "success"; public const string EventLevelEndFail = "fail"; public const string EventLevelEndExit = "exit"; public const string EventLevelEndTimeout = "timeout"; #region 通用接口 /// /// 自定义事件打点 /// /// /// public static void LogEvent(string eventName, Dictionary data = null) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: LogEvent {eventName} :: Please call first, before you call ."); return; } Analytics.Track(eventName, data); } public static void SetScreen(string screen, string extra = "") { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: SetScreen {screen} :: Please call first, before you call ."); return; } Analytics.SetCurrentScreen(screen, extra); } #endregion #region 游戏打点 /// /// 游戏启动打点 /// /// 关卡Id /// 关卡名称: main_01_9001, daily_challenge_81011 /// 关卡类型: 主线:main /// 配置/谜题/图片/自定义Id: 101120 /// 关卡开始类型: play:开始游戏;replay:重玩;continue:继续游戏 /// 是否重新开始: true/false /// 扩展数据 public static void LogLevelStart(int levelId, string startType = EventLevelStartModePlay, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", bool isReplay = false, Dictionary extra = null) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: LogLevelStart {levelId} :: Please call first, before you call ."); return; } Analytics.LogLevelStart(levelId, levelName, levelType, puzzleId, startType, isReplay, extra); } /// /// 游戏点击 Continue 继续游戏 /// /// /// /// /// /// public static void LogLevelContinue(int levelId, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", Dictionary extra = null) { LogLevelStart(levelId, EventLevelStartModeContinue, levelType, levelName, puzzleId, true, extra:extra); } /// /// 游戏点击 Replay 重玩关卡 /// /// /// /// /// public static void LogLevelReplay(int levelId, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", Dictionary extra = null) { LogLevelStart(levelId, EventLevelStartModeReplay,levelType, levelName, puzzleId, true, extra:extra); } /// /// 关卡结束打点 /// /// 关卡Id /// success:成功;fail:失败;exit:退出;timeout:超时;replay:重玩... /// 关卡类型: 主线:main /// 关卡名称: main_01_9001, daily_challenge_81011 /// 配置/谜题/图片/自定义Id: 101120 /// 关卡完成时长(单位:毫秒) /// 步数(有则上报) /// 分数(有则上报) /// 扩展数据 public static void LogLevelEnd(int levelId, string result = EventLevelEndSuccess, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", int? duration = null, int? step = null, int? score = null, Dictionary extra = null ) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: LogLevelEnd {levelId} :: Please call first, before you call ."); return; } if (InitConfig.AutoRecordFinishedLevels) { if(result == EventLevelEndSuccess){ if(levelType == LevelTypeMain) { if (levelId > Model.SuccessLevelId) Model.SuccessLevelId = levelId; // 自动记录关卡完成次数 } Model.TotalPlayedCount++; // 自动记录关卡总次数 } Analytics.BLevel = Model.SuccessLevelId; // 记录 BLevel Analytics.BPlay = Model.TotalPlayedCount; // 记录 BPlay } Analytics.LogLevelEnd(levelId, result, levelName, levelType, puzzleId, duration, step, score, extra); } /// /// 关卡首次通关 /// /// /// /// /// /// /// public static void LevelFirstEnd(string levelType, string levelName, int level, string result = EventLevelEndSuccess, int? duration = null, Dictionary extra = null) { Analytics.LevelFirstEnd(levelType, levelName, level, result, duration, extra); } /// /// 游戏失败打点 /// 需要为游戏记录详细的失败原因 /// public static void LogLevelFail(int levelId, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", int? duration = null, int? step = null, int? score = null , Dictionary extra = null) { LogLevelEnd(levelId, EventLevelEndFail, levelType, levelName, puzzleId, duration, step, score, extra); } /// /// 因退出关卡导致游戏失败 /// public static void LogLevelFailExit(int levelId, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", int? duration = null, int? step = null, int? score = null, Dictionary extra = null) { LogLevelEnd(levelId, EventLevelEndExit, levelType, levelName, puzzleId, duration, step, score, extra); } /// /// 因关卡超时导致游戏失败 /// public static void LogLevelFailTimeout(int levelId, string levelType = LevelTypeMain, string levelName = "", string puzzleId = "", int? duration = null, int? step = null, int? score = null, Dictionary extra = null) { LogLevelEnd(levelId, EventLevelEndTimeout, levelType, levelName, puzzleId, duration, step, score, extra); } /// /// 玩家(角色)升级事件 /// /// /// /// 扩展数据 public static void LogLevelUp(int playerLevel, string characterName, Dictionary extra = null) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: LogLevelUp {playerLevel} :: Please call first, before you call ."); return; } Analytics.LevelUp(playerLevel, characterName, extra); } /// /// 玩家解锁成就 /// /// /// 扩展数据 public static void LogAchievement(string achievementName, Dictionary extra = null) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: LogAchievement {achievementName} :: Please call first, before you call ."); return; } Analytics.UnlockAchievement(achievementName, extra); } #endregion #region 用户属性 /// /// 提前调用用户属性 /// private static void InitUserProperties() { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: InitUserProperties :: Please call first, before you call ."); return; } Debug.Log($"[SDK] --- PurchasedCount:{Model.PurchasedCount}"); Debug.Log($"[SDK] --- IsIapUser:{Model.IsIapUser}"); SetUserIsIAP(Model.IsIapUser); // 预先设置用户的 IAP User 属性 SetUserBLevel(Model.SuccessLevelId); // 预先设置用户的 BLevel 属性 SetUserBPlay(Model.TotalPlayedCount); // 预先设置用户的 BPlay 属性 if (Model.IsNoAds) SetBuyNoAds(true); // 设置用户已经购买了去广告 } private static HashSet _userPropertyExistKeys = new HashSet(); private static void RecordUserPropertyKey(string key) { if(_userPropertyExistKeys == null) _userPropertyExistKeys = new HashSet(); if(!HasUserPropertyKey(key)) _userPropertyExistKeys.Add(key); } private static bool HasUserPropertyKey(string key) { return _userPropertyExistKeys?.Contains(key) ?? false; } /// /// 设置用户属性 /// /// /// public static void SetUserProperty(string key, string value) { if (!IsInitialSuccess) { UnityEngine.Debug.LogError($"{Tag} :: SetUserProperty {key}:{value} ::Please call first, before you call ."); return; } RecordUserPropertyKey(key); Analytics.SetUserProperty(key, value); } public static void SetUID(string uid) { SetUserProperty(Analytics.PropertyUserID, uid); } public static void SetUserBLevel(int blevel) { SetUserProperty(Analytics.PropertyLevel, $"{blevel}"); } public static void SetUserBPlay(int bplay) { SetUserProperty(Analytics.PropertyPlay, $"{bplay}"); } /// /// 上报用户全部的 Coin (当前值) /// /// public static void SetUserTotalCoins(int totalCoins) { SetUserProperty(Analytics.PropertyCoin, $"{totalCoins}"); } /// /// 上报用户免费金币的 数量 (累加值) /// /// public static void SetUserFreeCoins(int freeCoins) { SetUserProperty(Analytics.PropertyNonIAPCoin, $"{freeCoins}"); } /// /// 上报用户付费金币的 数量 (累加值) /// /// public static void SetUserPaidCoins(int paidCoins) { SetUserProperty(Analytics.PropertyIAPCoin, $"{paidCoins}"); } public static void SetUserExp(int exp) { SetUserProperty(Analytics.PropertyExp, $"{exp}"); } public static void SetUserHp(int hp) { SetUserProperty(Analytics.PropertyHp, $"{hp}"); } public static void SetUserGrade(int grade) { SetUserProperty(Analytics.PropertyGrade, $"{grade}"); } public static void SetUserIsIAP(bool isIapUser) { SetUserProperty(Analytics.PropertyIsIAPUser, isIapUser? "true" : "false"); } public static void SetFirstOpenTime(string timestamp) { SetUserProperty(Analytics.PropertyFirstOpenTime, timestamp); } /// /// 初始化时调用一下所有的属性打点
/// 用户属性文档 ///
private static void UpdateAllUserProperties() { if(!HasUserPropertyKey(Consts.PropertyFirstOpenTime)) SetFirstOpenTime(TimeUtil.GetCurrentTimeStamp().ToString()); // first_open_time if(!HasUserPropertyKey(Consts.PropertyIsIAPUser)) SetUserIsIAP(Model?.IsIapUser ?? false); // is_iap_user if (!HasUserPropertyKey(Consts.PropertyLevel)) SetUserBLevel(Model?.SuccessLevelId ?? 0); // b_level if (!HasUserPropertyKey(Consts.PropertyPlay)) SetUserBLevel(Model?.TotalPlayedCount ?? 0); // b_play if(!HasUserPropertyKey(Consts.PropertyUserID)) SetUserProperty(Consts.PropertyUserID, UID); // user_id if(!HasUserPropertyKey(Consts.PropertyDeviceID)) SetUserProperty(Consts.PropertyDeviceID, DeviceId); // device_id if(!HasUserPropertyKey(Consts.PropertyIAPCoin)) SetUserPaidCoins(0); // iap_coin if(!HasUserPropertyKey(Consts.PropertyNonIAPCoin)) SetUserFreeCoins(0); // non_iap_coin if(!HasUserPropertyKey(Consts.PropertyCoin)) SetUserTotalCoins(0);// coin if (!HasUserPropertyKey(Consts.PropertyGrade)) SetUserGrade(0); // grade if(!HasUserPropertyKey(Consts.PropertyExp)) SetUserExp(0); // exp if(!HasUserPropertyKey(Consts.PropertyHp)) SetUserHp(0); // hp #if UNITY_IOS if(!HasUserPropertyKey(Consts.PropertyATTStatus)) SetUserProperty(Consts.PropertyATTStatus, "notDetermined"); #endif if(!HasUserPropertyKey(Consts.PropertyNotiPerm)) SetUserProperty(Consts.PropertyNotiPerm, "not_determined"); } #endregion #region SDK 打点 /// /// Log SDK boost time /// /// private static void LogSDKInitTime(double time) { Analytics.Track(Consts.EventSDKInfo, new Dictionary() { { "boost_time", time.ToString("F6") }, { Consts.PropertyDeviceID, DeviceId }, { "version", Version} }, new Analytics.EventSetting() { EnableFirebaseAnalytics = true, }); SetUserProperty("sdk_version", Version); } #endregion #region IAP 打点 private static string TryGetFirstProductId() { if (GuruSettings.Instance != null && (GuruSettings.Instance.Products?.Length ?? 0) > 0) { return GuruSettings.Instance.Products[0]?.ProductId ?? ""; } return ""; } private static string TryGetCurrentProductId() { if (GuruIAP.Instance != null && IsIAPReady) { return GuruIAP.Instance.CurrentBuyingProductId; } return ""; } /// /// 当付费页面打开时调用 /// /// 付费页面名称, 默认为 Store /// 列表中首个商品的 ProductId public static void OnIAPPageOpen(string scene = "Store", string productId = "") { if (string.IsNullOrEmpty(productId)) { productId = TryGetFirstProductId(); } Analytics.IAPImp(scene, productId); } /// /// 当付费页面关闭时调用 /// /// /// public static void OnIAPPageClose(string scene = "Store", string productId = "") { if (string.IsNullOrEmpty(productId)) { productId = TryGetCurrentProductId(); } Analytics.IAPClose(scene, productId); } /// /// 当点击 IAP 商品按钮的时候调用 /// /// /// public static void OnIAPClick(string scene = "", string productId = "") { Analytics.IAPClick(scene, productId); } #endregion #region 经济打点 // ************************************************************************************************ // * // * 经济打点 // * 内容详参: https://docs.google.com/spreadsheets/d/1xYSsAjbrwqeJm7panoVzHO0PeGRQVDCR4e2CU9OPEzk/edit#gid=0 // * // ************************************************************************************************ //---------------------------------------- EARN ---------------------------------------- /// /// 基础收入接口. 可直接调用此接口上报相关参数 /// 获取虚拟货币/道具. /// 基础接口, 不推荐项目组直接调用 /// 请直接调用其他对应场景的统计接口 /// /// 货币名称 /// 货币增加值 10 /// 结算后货币总量 20 -> 30 /// 消耗类型, 默认值请赋 reward /// 当前关卡或者人物等级名称 /// 购买道具名称 /// 购买场景如 Store, Workbench, Sign, Ads.... public static void EarnVirtualCurrency(string currencyName, int value, int balance, string category = "", string itemName = "", string levelName = "", string scene = "", Dictionary extra = null) { Analytics.EarnVirtualCurrency(currencyName, value, balance, category, itemName,levelName, scene, extra); } /// /// 赚取组合: 货币+道具 /// /// /// /// /// /// /// /// /// private static void EarnVirtualCurrencyAndProps(string currencyName, int value = 0, int balance = 0, string category = "", string itemName = "", string levelName = "", string scene = Consts.ParameterDefaultScene, string[] props = null, Dictionary extra = null) { //---- Currency ----- if (value > 0) { EarnVirtualCurrency(currencyName, value, balance, category, itemName, levelName, scene, extra); } //---- Props -------- if (null != props) { int i = 0; while (i < props.Length) { EarnVirtualCurrency(props[i], 1, 0, category, itemName, levelName, scene, extra); i++; } } } /// /// 签到奖励. 获得货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// 货币名称 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyBySign(string currencyName, int value = 0, int balance = 0, string levelName = "", string scene = "home", string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryReward; string itemName = "sign"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// IAP 付费购买. 获得货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// IAP 道具名称 /// IAP 道具商品 ID /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyByIAP(string currencyName, string productId, int value = 0, int balance = 0, string levelName = "", string scene = "store", string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryIAP; // string itemName = productId; string itemName = "sku"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// 看广告获取到货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// 货币名称 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyByAds(string currencyName, int value = 0, int balance = 0, string levelName = "", string scene = "store", string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryReward; string itemName = "ads"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// 使用了金币半价 + 看广告获取到货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// 货币名称 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyByPaidAds(string currencyName, int value = 0, int balance = 0, string levelName = "", string scene = Consts.ParameterDefaultScene, string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryBonus; string itemName = "ads"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// 过关奖励获取到货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// 货币名称 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyByLevelComplete(string currencyName, int value = 0, int balance = 0, string levelName = "", string scene = "store", string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryReward; string itemName = "level"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// 通过使用 Currency 购买获得 Prop (记录 Prop 增加的打点, 消费游戏内货币) /// /// 货币名称 /// 获取的道具名称列表 /// 应用场景 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 public static void EarnPropsByVirtualCurrency(string currencyName, string[] props, string scene = Consts.ParameterDefaultScene, int value = 1, int balance = 0, string levelName = "", Dictionary extra = null) { string category = Consts.CurrencyCategoryIGC; string itemName = currencyName; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } /// /// 通过道具交换/合成或得了其他道具 /// /// /// /// /// /// /// public static void EarnPropByProp(string propName, string otherName, string scene = Consts.ParameterDefaultScene, int value = 1, int balance = 0, string levelName = "", Dictionary extra = null) { string category = Consts.CurrencyCategoryIGB; EarnVirtualCurrency(propName, value, balance, category, otherName, levelName, scene, extra); } /// /// 通过转盘或者抽奖, 获取货币/道具 ///
  • 通常类型: Coin 收入
  • ///
  • 特殊类型: Coin + Props (道具列表)
  • ///
  • 特殊类型: Props (道具列表)
  • ///
    /// 货币名称 /// 赚取金额 /// 货币总量(累加后) /// 当前关卡名称 /// 应用场景 /// 获取的道具名称列表 public static void EarnVirtualCurrencyByLottery(string currencyName, int value = 0, int balance = 0, string levelName = "", string scene = "store", string[] props = null, Dictionary extra = null) { string category = Consts.CurrencyCategoryIGB; string itemName = "lottery"; EarnVirtualCurrencyAndProps(currencyName, value, balance, category, itemName, levelName, scene, props, extra); } //---------------------------------------- SPEND ---------------------------------------- /// /// 基础花费虚拟货币/道具 /// 基础接口, 不推荐项目组直接调用 /// 请直接调用其他对应场景的统计接口 /// /// 货币名称 /// 货币消耗值 10 /// 结算后货币总量 30 -> 20 /// 消耗类型, 默认值请赋 reward /// 当前关卡或者人物等级名称 /// 购买道具名称 /// 购买场景如 Store, Workbench, Sign, Ads.... public static void SpendVirtualCurrency(string currencyName, int value, int balance, string category = "", string itemName = "", string levelName = "", string scene = "", Dictionary extra = null) { Analytics.SpendVirtualCurrency(currencyName, value, balance, category, itemName, levelName, scene, extra); } /// /// 消耗货币购买道具 /// /// /// /// /// /// /// public static void SpendVirtualCurrencyWithProp(string currencyName, string prop, int value, int balance, string levelName = "", string scene = "", Dictionary extra = null) { SpendVirtualCurrencyWithProps(currencyName, new string[] {prop}, value, balance, levelName, scene, extra); } /// /// 消耗货币购买道具 (含多个) /// /// /// /// /// /// /// public static void SpendVirtualCurrencyWithProps(string currencyName, string[] props, int value, int balance, string levelName = "", string scene = "", Dictionary extra = null) { string category = Consts.CurrencyCategoryProp; if (props != null && props.Length > 0) { int i = 0; while (i < props.Length) { SpendVirtualCurrency(currencyName, value, balance, category, props[i], levelName, scene, extra); i++; } } } /// /// 消耗货币购买礼包或组合 /// /// /// /// /// /// /// public static void SpendVirtualCurrencyWithBundle(string currencyName, string bundle, int value, int balance, string levelName = "", string scene = "", Dictionary extra = null) { SpendVirtualCurrencyWithBundles(currencyName, new string[] {bundle}, value, balance, levelName, scene, extra); } /// /// 消耗货币购买礼包或组合 (含多个) /// /// /// /// /// /// /// public static void SpendVirtualCurrencyWithBundles(string currencyName, string[] bundles, int value, int balance, string levelName = "", string scene = "", Dictionary extra = null) { string category = Consts.CurrencyCategoryBundle; if (bundles != null && bundles.Length > 0) { int i = 0; while (i < bundles.Length) { SpendVirtualCurrency(currencyName, value, balance, category, bundles[i], levelName, scene, extra); i++; } } } /// /// 消耗物品, 交换其他物品 /// /// /// /// /// /// /// public static void SpendPropWithProp(string propName, string otherName, int value, int balance, string levelName = "", string scene = "", string extraCategory = "", Dictionary extra = null) { string category = string.IsNullOrEmpty(extraCategory) ? Consts.CurrencyCategoryProp : extraCategory; SpendVirtualCurrency(propName, value, balance, category, otherName, levelName, scene, extra); } #endregion #region Crashlytics 接口 public static void CrashLog(string message) { if (!IsFirebaseReady) return; CrashlyticsAgent.Log(message); } public static void CrashException(string message) { if (!IsFirebaseReady) return; CrashlyticsAgent.LogException(message); } public static void CrashException(Exception ex) { if (!IsFirebaseReady) return; CrashlyticsAgent.LogException(ex); } public static void CrashCustomKeys(string key, string value) { if (!IsFirebaseReady) return; CrashlyticsAgent.SetCustomKey(key, value); } #endregion } }