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
}
}