备份CatanBuilding瘦身独立工程
This commit is contained in:
222
Assets/Scripts/AOTScripts/AFHelper.cs
Normal file
222
Assets/Scripts/AOTScripts/AFHelper.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using AppsFlyerSDK;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public class AFHelper : MonoBehaviour, IAppsFlyerConversionData, IAppsFlyerUserInvite
|
||||
{
|
||||
public bool DidReceivedDeepLink { get; private set; } // marks if we got a DL and processed it
|
||||
private Dictionary<string, object> _conversionDataDictionary;
|
||||
private Dictionary<string, object> _deepLinkParamsDictionary;
|
||||
|
||||
public bool IsFirstLaunch { get; private set; }
|
||||
public string AFState { get; private set; }
|
||||
public IReadOnlyDictionary<string, object> DeepLinkParamsDictionary => _deepLinkParamsDictionary;
|
||||
public IReadOnlyDictionary<string, object> ConversionDataDictionary => _conversionDataDictionary;
|
||||
public string AttributionData { get; private set; }
|
||||
|
||||
private string _referrerUID;
|
||||
private string _inviteLink;
|
||||
private TaskCompletionSource<string> _tcs;
|
||||
public string StoreLink { get; private set; }
|
||||
|
||||
public bool GetDLReferer(out string pid, out string uid)
|
||||
{
|
||||
pid = null;
|
||||
uid = null;
|
||||
|
||||
if (!DidReceivedDeepLink)
|
||||
return false;
|
||||
if (_deepLinkParamsDictionary == null)
|
||||
return false;
|
||||
|
||||
if (_deepLinkParamsDictionary.TryGetValue("deep_link_value", out var deep_link_value))
|
||||
{
|
||||
if ((string)deep_link_value != "friend_invite")
|
||||
return false;
|
||||
|
||||
if (_deepLinkParamsDictionary.TryGetValue("deep_link_sub2", out var referrer_pid))
|
||||
pid = (string)referrer_pid;
|
||||
if (_deepLinkParamsDictionary.TryGetValue("deep_link_sub1", out var referrer_uid))
|
||||
uid = (string)referrer_uid;
|
||||
|
||||
if (!string.IsNullOrEmpty(pid) && !string.IsNullOrEmpty(uid))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static AFHelper Instance { get; private set; }
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Init(string afkey, string afAppID, string customerUserID, string oneLinkID, bool debugMode = false)
|
||||
{
|
||||
AppsFlyer.setIsDebug(debugMode);
|
||||
AppsFlyer.setAppInviteOneLinkID(oneLinkID);
|
||||
AppsFlyer.initSDK(afkey, afAppID, this);
|
||||
AppsFlyer.setCustomerUserId(customerUserID);
|
||||
AppsFlyer.OnDeepLinkReceived += OnDeepLink;
|
||||
|
||||
#if UNITY_IOS
|
||||
AppsFlyerSDK.AppsFlyer.waitForATTUserAuthorizationWithTimeoutInterval(30);
|
||||
#endif
|
||||
|
||||
AppsFlyer.startSDK();
|
||||
AppsFlyerSDK.AppsFlyerAdRevenue.start();
|
||||
}
|
||||
|
||||
public async Task<string> GenInviteLink(string referrerUID, string referrerPID)
|
||||
{
|
||||
if (referrerUID == _referrerUID && !string.IsNullOrEmpty(_inviteLink))
|
||||
return _inviteLink;
|
||||
_inviteLink = string.Empty;
|
||||
#if UNITY_EDITOR
|
||||
await Awaiters.NextFrame;
|
||||
#else
|
||||
Dictionary<string, string> parameters = new Dictionary<string, string>();
|
||||
parameters.Add("channel", "mobile_share");
|
||||
parameters.Add("campaign", "friend_invite");
|
||||
|
||||
parameters.Add("deep_link_value", "friend_invite");
|
||||
parameters.Add("deep_link_sub1", referrerUID);
|
||||
parameters.Add("deep_link_sub2", referrerPID);
|
||||
// Optional; makes the referrer ID available in the installs raw-data report
|
||||
parameters.Add("af_sub1", referrerPID);
|
||||
|
||||
_tcs = new TaskCompletionSource<string>();
|
||||
AppsFlyer.generateUserInviteLink(parameters, this);
|
||||
_inviteLink = await _tcs.Task;
|
||||
#endif
|
||||
return _inviteLink;
|
||||
}
|
||||
|
||||
#region Implement IAppsFlyerConversionData
|
||||
|
||||
public void onConversionDataSuccess(string conversionData)
|
||||
{
|
||||
Debug.Log("[AFDeepLinkHelper::didReceiveConversionData] success");
|
||||
Dictionary<string, object> conversionDataDictionary = AppsFlyer.CallbackStringToDictionary(conversionData);
|
||||
_conversionDataDictionary = conversionDataDictionary;
|
||||
|
||||
// af_status and is_first_launch always received with onConversionDataSuccess, no need to check if the keys exist
|
||||
AFState = _conversionDataDictionary["af_status"].ToString();
|
||||
IsFirstLaunch = (bool)_conversionDataDictionary["is_first_launch"];
|
||||
}
|
||||
|
||||
public void onConversionDataFail(string error)
|
||||
{
|
||||
Debug.LogWarning("[AFDeepLinkHelper::didReceiveConversionData] error: " + error);
|
||||
_conversionDataDictionary = null;
|
||||
}
|
||||
|
||||
public void onAppOpenAttribution(string attributionData)
|
||||
{
|
||||
Debug.Log("[AFDeepLinkHelper::onAppOpenAttribution] " + attributionData);
|
||||
AttributionData = attributionData;
|
||||
}
|
||||
|
||||
public void onAppOpenAttributionFailure(string error)
|
||||
{
|
||||
Debug.LogWarning("[AFDeepLinkHelper::onAppOpenAttributionFailure] error: " + error);
|
||||
AttributionData = null;
|
||||
}
|
||||
|
||||
#endregion // Implement IAppsFlyerConversionData
|
||||
|
||||
#region Implement IAppsFlyerUserInvite
|
||||
|
||||
public void onInviteLinkGenerated(string link)
|
||||
{
|
||||
if (_tcs != null)
|
||||
{
|
||||
_tcs.SetResult(link);
|
||||
}
|
||||
}
|
||||
|
||||
public void onInviteLinkGeneratedFailure(string error)
|
||||
{
|
||||
if (_tcs != null)
|
||||
{
|
||||
_tcs.SetResult(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void onOpenStoreLinkGenerated(string link)
|
||||
{
|
||||
Debug.Log("[AFDeepLinkHelper::onOpenStoreLinkGenerated] " + link);
|
||||
StoreLink = link;
|
||||
}
|
||||
|
||||
#endregion // Implement IAppsFlyerUserInvite
|
||||
|
||||
|
||||
#region Deeplink
|
||||
|
||||
/** All the DeepLink handling has to be done under the onDeepLink handler **/
|
||||
void OnDeepLink(object sender, EventArgs args)
|
||||
{
|
||||
|
||||
Debug.Log($"[AFDeepLinkHelper::onDeepLink] {args.GetType().Name}");
|
||||
|
||||
if (!(args is DeepLinkEventsArgs deepLinkEventArgs)) return;
|
||||
|
||||
Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink Status {deepLinkEventArgs.status.ToString()}");
|
||||
|
||||
switch (deepLinkEventArgs.status)
|
||||
{
|
||||
case DeepLinkStatus.FOUND:
|
||||
|
||||
DidReceivedDeepLink = true;
|
||||
|
||||
if (deepLinkEventArgs.isDeferred())
|
||||
{
|
||||
Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink is deferred");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"[AFDeepLinkHelper::onDeepLink] This is a direct deep link");
|
||||
}
|
||||
_deepLinkParamsDictionary = GetDeepLinkParamsDictionary(deepLinkEventArgs);
|
||||
break;
|
||||
|
||||
case DeepLinkStatus.NOT_FOUND:
|
||||
Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink not found");
|
||||
break;
|
||||
default:
|
||||
Debug.LogWarning($"[AFDeepLinkHelper::onDeepLink] DeepLink error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the DeepLink params depending on the device OS **/
|
||||
private Dictionary<string, object> GetDeepLinkParamsDictionary(DeepLinkEventsArgs deepLinkEventArgs)
|
||||
{
|
||||
#if UNITY_IOS && !UNITY_EDITOR
|
||||
if (deepLinkEventArgs.deepLink.ContainsKey("click_event") && deepLinkEventArgs.deepLink["click_event"] != null)
|
||||
{
|
||||
return deepLinkEventArgs.deepLink["click_event"] as Dictionary<string, object>;
|
||||
}
|
||||
#elif UNITY_ANDROID && !UNITY_EDITOR
|
||||
return deepLinkEventArgs.deepLink;
|
||||
#endif
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion // Deeplink
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/AFHelper.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/AFHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c70943931a9d4d4c89d8f687378f5f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Assets/Scripts/AOTScripts/AgreementsPolicesPanel.cs
Normal file
81
Assets/Scripts/AOTScripts/AgreementsPolicesPanel.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class AgreementsPolicesPanel : MonoBehaviour, IPointerClickHandler
|
||||
{
|
||||
[SerializeField]
|
||||
private Button aggreementBtn;
|
||||
|
||||
[SerializeField]
|
||||
private Button quitBtn;
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text title;
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text text;
|
||||
|
||||
private const string prf_key = "AgreementsPolicesPanel";
|
||||
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
aggreementBtn.onClick.RemoveAllListeners();
|
||||
quitBtn.onClick.RemoveAllListeners();
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
int linkIndex = TMP_TextUtilities.FindNearestLink(text, Input.mousePosition, null);
|
||||
if (linkIndex != -1)
|
||||
{
|
||||
TMP_LinkInfo linkInfo = text.textInfo.linkInfo[linkIndex];
|
||||
var linkID = linkInfo.GetLinkID();
|
||||
if (linkID == "Privacy")
|
||||
{
|
||||
#if UNITY_IOS
|
||||
linkID = GConstant.V_IOS_Privacy_Policy_URL;
|
||||
#else
|
||||
linkID = GConstant.V_Android_Privacy_Policy_URL;
|
||||
#endif
|
||||
}
|
||||
|
||||
Application.OpenURL(linkID);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAggreementBtnClicked()
|
||||
{
|
||||
Debug.Log("OnaggreementBtnClicked");
|
||||
}
|
||||
|
||||
public async Task<bool> Agreement()
|
||||
{
|
||||
if(PlayerPrefs.HasKey(prf_key))
|
||||
return true;
|
||||
|
||||
gameObject.SetActive(true);
|
||||
|
||||
var taskSource = new TaskCompletionSource<bool>();
|
||||
|
||||
aggreementBtn.onClick.AddListener(() =>
|
||||
{
|
||||
PlayerPrefs.SetInt(prf_key, 1);
|
||||
taskSource.SetResult(true);
|
||||
});
|
||||
|
||||
quitBtn.onClick.AddListener(() => taskSource.SetResult(false));
|
||||
|
||||
var aggree = await taskSource.Task;
|
||||
|
||||
aggreementBtn.onClick.RemoveAllListeners();
|
||||
quitBtn.onClick.RemoveAllListeners();
|
||||
gameObject.SetActive(false);
|
||||
|
||||
return aggree;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/AgreementsPolicesPanel.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/AgreementsPolicesPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca9397553a1e24044ae5e118b50c5c69
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
615
Assets/Scripts/AOTScripts/Boostrap.cs
Normal file
615
Assets/Scripts/AOTScripts/Boostrap.cs
Normal file
@@ -0,0 +1,615 @@
|
||||
// #######
|
||||
// # # #### # # # # # ####
|
||||
// # # # # # # ## # # #
|
||||
// ##### # #### ###### # # # # #
|
||||
// # # # # # # # # # # ###
|
||||
// # # # # # # # # ## # #
|
||||
// # # #### # # # # # ####
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using game;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using System.Collections.Generic;
|
||||
//using HybridCLR;
|
||||
using tysdk;
|
||||
using System.Collections;
|
||||
|
||||
public class Boostrap : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private RootCtx ctx;
|
||||
|
||||
private IConfig config;
|
||||
|
||||
[SerializeField]
|
||||
private BoostrapLoading bsLoading;
|
||||
|
||||
[SerializeField]
|
||||
private SimpleDialog reconnectDialog;
|
||||
|
||||
[SerializeField]
|
||||
|
||||
private SimpleDialog updateDialog;
|
||||
|
||||
[SerializeField]
|
||||
private SimpleDialog updateSugetDialog;
|
||||
|
||||
[SerializeField]
|
||||
private SimpleDialog maintanceDialog;
|
||||
|
||||
[SerializeField]
|
||||
private AgreementsPolicesPanel agreementPanel;
|
||||
|
||||
[SerializeField]
|
||||
private AssetLabelReference preloadGroup;
|
||||
|
||||
private System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
||||
|
||||
private double elapsed;
|
||||
|
||||
void Start()
|
||||
{
|
||||
//This will override OS specific culture
|
||||
//settings and ensure predictable behavior when writing/reading string or text files.
|
||||
System.Globalization.CultureInfo.DefaultThreadCurrentCulture
|
||||
= new System.Globalization.CultureInfo("en-US");
|
||||
ctx.OnInited += OnContextInited;
|
||||
bsLoading.Show();
|
||||
bsLoading.SetProgress(0);
|
||||
bsLoading.SetDownloadSize(-1, -1);
|
||||
}
|
||||
|
||||
// Callback from GContex when its ready
|
||||
private void OnContextInited()
|
||||
{
|
||||
config = GContext.container.Resolve<IConfig>();
|
||||
Boost();
|
||||
ctx.OnInited = null;
|
||||
}
|
||||
|
||||
|
||||
private async void Boost()
|
||||
{
|
||||
Boostrapi18n.Instance.Init();
|
||||
bsLoading.SetInfo(Boostrapi18n.Instance.GetText("msg_initializing"));
|
||||
|
||||
if(! await agreementPanel.Agreement())
|
||||
{
|
||||
RootCtx.ExitGame();
|
||||
return;
|
||||
}
|
||||
|
||||
tysdk.UnityBridgeFunc.RequestATT();
|
||||
|
||||
if (!await CheckNetwork())
|
||||
{
|
||||
await RetryDialog(reconnectDialog, CheckNetwork, "network");
|
||||
}
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
// __ _
|
||||
// _____ _____ _____ _____ ___ ___ _ __ / _(_) __ _ _____ _____ _____
|
||||
//|_____|_____|_____|_____| / __/ _ \| '_ \| |_| |/ _` | |_____|_____|_____|
|
||||
//|_____|_____|_____|_____| | (_| (_) | | | | _| | (_| | |_____|_____|_____|
|
||||
// \___\___/|_| |_|_| |_|\__, |
|
||||
// |___/
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("loading"))
|
||||
{
|
||||
e.AddContent("step", 1);
|
||||
e.AddContent("elapsed", 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
sw.Start();
|
||||
|
||||
// if (!await LoadConfig())
|
||||
// await RetryDialog(reconnectDialog, LoadConfig, "config");
|
||||
var isSuccessLoadRemoteConfigFile = await LoadConfig();
|
||||
|
||||
sw.Stop();
|
||||
elapsed = sw.Elapsed.TotalSeconds;
|
||||
sw.Reset();
|
||||
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("loading"))
|
||||
{
|
||||
e.AddContent("step", 2);
|
||||
e.AddContent("elapsed", elapsed);
|
||||
}
|
||||
#endif
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
|
||||
var maintanceMsg = config.Get(GConstant.K_Maintance, string.Empty);
|
||||
if (!string.IsNullOrEmpty(maintanceMsg))
|
||||
{
|
||||
ShowMantainceDialog(maintanceMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
|
||||
if (!await CheckVerion())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if AGG
|
||||
// Change AGG server
|
||||
var aggserver = config.Get("AGG_SERVER", string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(aggserver))
|
||||
{
|
||||
//更新服务器
|
||||
UnityBridgeFunc.UnityResetServerUrl(aggserver);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
/*
|
||||
*
|
||||
* _ _ _
|
||||
* _____ _____ _____ _____ (_)___ ___ _ __ __| | __ _| |_ __ _ _____ _____ _____
|
||||
*|_____|_____|_____|_____| | / __|/ _ \| '_ \ / _` |/ _` | __/ _` | |_____|_____|_____|
|
||||
*|_____|_____|_____|_____| | \__ \ (_) | | | | | (_| | (_| | || (_| | |_____|_____|_____|
|
||||
* _/ |___/\___/|_| |_| \__,_|\__,_|\__\__,_|
|
||||
* |__/
|
||||
*/
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
|
||||
sw.Start();
|
||||
|
||||
// if (!await UpdateCfg(isSuccessLoadRemoteConfigFile))
|
||||
// await RetryDialog(reconnectDialog, UpdateCfg, "cfg");
|
||||
await UpdateCfg(isSuccessLoadRemoteConfigFile);
|
||||
|
||||
sw.Stop();
|
||||
elapsed = sw.Elapsed.TotalSeconds;
|
||||
sw.Reset();
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("loading"))
|
||||
{
|
||||
e.AddContent("step", 3);
|
||||
e.AddContent("elapsed", elapsed);
|
||||
}
|
||||
#endif //AGG
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
#endif // !UNITY_EDITOR
|
||||
|
||||
/*
|
||||
* _ _ _
|
||||
* _____ _____ _____ _____ / \ __| | __| |_ __ _____ _____ _____
|
||||
*|_____|_____|_____|_____| / _ \ / _` |/ _` | '__| |_____|_____|_____|
|
||||
*|_____|_____|_____|_____| / ___ \ (_| | (_| | | |_____|_____|_____|
|
||||
* /_/ \_\__,_|\__,_|_|
|
||||
*/
|
||||
|
||||
/* sw.Start(); */
|
||||
/**/
|
||||
/* Addressables.WebRequestOverride = (UnityWebRequest request) => request.timeout = 15; */
|
||||
/**/
|
||||
/* while(!await UpdateAsset()) */
|
||||
/* { */
|
||||
/* #if AGG */
|
||||
/* using (var e = GEvent.TackEvent("retry")) */
|
||||
/* { */
|
||||
/* e.AddContent("type", "update"); */
|
||||
/* } */
|
||||
/* #endif */
|
||||
/* Debug.LogWarning("UpdateAsset failed"); */
|
||||
/* } */
|
||||
/**/
|
||||
/* sw.Stop(); */
|
||||
/* elapsed = sw.Elapsed.TotalSeconds; */
|
||||
/* sw.Reset(); */
|
||||
/**/
|
||||
/* #if AGG */
|
||||
/* using (var e = GEvent.TackEvent("loading")) */
|
||||
/* { */
|
||||
/* e.AddContent("step", 5); */
|
||||
/* e.AddContent("elapsed", elapsed); */
|
||||
/* } */
|
||||
/* #endif */
|
||||
|
||||
/*
|
||||
sw.Start();
|
||||
await AfterAssetUpdate();
|
||||
|
||||
sw.Stop();
|
||||
elapsed = sw.Elapsed.TotalSeconds;
|
||||
sw.Reset();
|
||||
*/
|
||||
|
||||
/*
|
||||
* _
|
||||
* _____ _____ _____ _____ ___ ___| |_ _ _ _ __ _____ _____ _____
|
||||
*|_____|_____|_____|_____| / __|/ _ \ __| | | | '_ \ |_____|_____|_____|
|
||||
*|_____|_____|_____|_____| \__ \ __/ |_| |_| | |_) | |_____|_____|_____|
|
||||
* |___/\___|\__|\__,_| .__/
|
||||
* |_|
|
||||
*/
|
||||
|
||||
await AfterAssetUpdateV2();
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("loading"))
|
||||
{
|
||||
e.AddContent("step", 6);
|
||||
e.AddContent("elapsed", elapsed);
|
||||
}
|
||||
#endif
|
||||
//StopUpdateLoadingInfo();
|
||||
await GoToStageV2();
|
||||
}
|
||||
|
||||
private async Task<bool> CheckNetwork()
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
return Application.internetReachability != NetworkReachability.NotReachable;
|
||||
}
|
||||
|
||||
private async Task<bool> LoadConfig()
|
||||
{
|
||||
var success = await config.InitConfig();
|
||||
|
||||
// Change Addressable remote location, using custom assetbundle server
|
||||
var customAddressableRemoteURL = config.Get(GConstant.K_Custom_Addressable, string.Empty);
|
||||
var originAddressableRemoteURL = config.Get(GConstant.K_Origin_Addressable, string.Empty);
|
||||
if (!string.IsNullOrEmpty(customAddressableRemoteURL)
|
||||
&& !string.IsNullOrEmpty(originAddressableRemoteURL))
|
||||
{
|
||||
ctx.ChangeAddressableRemoteUrl(customAddressableRemoteURL, originAddressableRemoteURL);
|
||||
}
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
bsLoading.SetProgress(0.02f);
|
||||
|
||||
Debug.Log($"[Boostrap]::LoadConfig Done success: {success}");
|
||||
return success;
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateCfg(bool isSuccessLoadRemoteConfigFile)
|
||||
{
|
||||
var result = await cfg.Tables.UpdateCfg(config, isSuccessLoadRemoteConfigFile);
|
||||
bsLoading.SetProgress(0.05f);
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<bool> CheckVerion()
|
||||
{
|
||||
var remoteVer = VersionTool.FromString(config.Get(GConstant.K_Ver, string.Empty));
|
||||
var localVer = VersionTool.FromLocal();
|
||||
if (remoteVer > localVer)
|
||||
{
|
||||
updateDialog.Config(new SimpleDialog.Context()
|
||||
{
|
||||
message = Boostrapi18n.Instance.GetText("title_hardupdate"),
|
||||
message2 = Boostrapi18n.Instance.GetText("content_hardupdate"),
|
||||
okAction = () =>
|
||||
{
|
||||
#if UNITY_IOS
|
||||
var url = config.Get(GConstant.K_APP_Store_URL, string.Empty);
|
||||
#else
|
||||
var url = config.Get(GConstant.K_Google_Play_URL, string.Empty);
|
||||
#endif
|
||||
Application.OpenURL(url);
|
||||
RootCtx.ExitGame();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var newVer = config.Get(GConstant.K_Ver_New, string.Empty);
|
||||
if (!string.IsNullOrEmpty(newVer))
|
||||
{
|
||||
var confirm = new TaskCompletionSource<bool>();
|
||||
updateSugetDialog.Config(new SimpleDialog.Context()
|
||||
{
|
||||
message = Boostrapi18n.Instance.GetText("title_hardupdate"),
|
||||
message2 = Boostrapi18n.Instance.GetText("content_hardupdate"),
|
||||
okAction = () =>
|
||||
{
|
||||
|
||||
#if UNITY_IOS
|
||||
var url = config.Get(GConstant.K_APP_Store_URL, string.Empty);
|
||||
#else
|
||||
var url = config.Get(GConstant.K_Google_Play_URL, string.Empty);
|
||||
#endif
|
||||
Application.OpenURL(url);
|
||||
confirm.SetResult(false);
|
||||
RootCtx.ExitGame();
|
||||
},
|
||||
|
||||
closeAction = () =>
|
||||
{
|
||||
confirm.SetResult(true);
|
||||
}
|
||||
});
|
||||
|
||||
return await confirm.Task;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateAsset()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
await Awaiters.NextFrame;
|
||||
return true;
|
||||
#else
|
||||
await Awaiters.NextFrame;
|
||||
bsLoading.SetVersionInfo(VersionTool.FromLocal().ToVerString());
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Log("Start UpdateAsset");
|
||||
//Addressables.WebRequestOverride = (UnityWebRequest request) => request.timeout = 6;
|
||||
List<string> update_catalogs = null;
|
||||
var updateCheckHandle = Addressables.CheckForCatalogUpdates(false);
|
||||
|
||||
update_catalogs = await updateCheckHandle.Task;
|
||||
|
||||
if(updateCheckHandle.OperationException != null || updateCheckHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
Debug.LogError($"update checked failed: { updateCheckHandle.OperationException.Message }");
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(updateCheckHandle);
|
||||
|
||||
if(null != update_catalogs)
|
||||
{
|
||||
Debug.Log($"update catalogs count: {update_catalogs.Count}");
|
||||
}
|
||||
|
||||
if(null != update_catalogs && update_catalogs.Count > 0)
|
||||
{
|
||||
var updateCatalogHandle = Addressables.UpdateCatalogs(update_catalogs, false);
|
||||
await updateCatalogHandle.Task;
|
||||
if(updateCatalogHandle.OperationException != null || updateCatalogHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
Debug.LogError($"update catalogs failed: {updateCatalogHandle.OperationException.Message}");
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(updateCatalogHandle);
|
||||
}
|
||||
|
||||
var locationsHandle = Addressables.LoadResourceLocationsAsync(preloadGroup.labelString);
|
||||
var locations = await locationsHandle.Task;
|
||||
if(locationsHandle.OperationException != null || locationsHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
Debug.LogError($"load resource locations failed: {locationsHandle.OperationException.Message}");
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(locationsHandle);
|
||||
|
||||
var downloadSizeHandle = Addressables.GetDownloadSizeAsync(locations);
|
||||
var downloadSize = await downloadSizeHandle.Task;
|
||||
if(downloadSizeHandle.OperationException != null || downloadSizeHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
Debug.LogError($"get download size failed: {downloadSizeHandle.OperationException.Message}");
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(downloadSizeHandle);
|
||||
|
||||
if(downloadSize > 0)
|
||||
{
|
||||
bsLoading.SetInfo(Boostrapi18n.Instance.GetText("msg_downloading"));
|
||||
var downloadHandle = Addressables.DownloadDependenciesAsync(locations);
|
||||
|
||||
DownloadStatus downloadStatus;
|
||||
long downloadedBytes = 0;
|
||||
float percent = 0;
|
||||
|
||||
while (!downloadHandle.IsDone && downloadHandle.OperationException == null && downloadHandle.Status != AsyncOperationStatus.Failed)
|
||||
{
|
||||
downloadStatus = downloadHandle.GetDownloadStatus();
|
||||
if(downloadStatus.DownloadedBytes > downloadedBytes)
|
||||
downloadedBytes = downloadStatus.DownloadedBytes;
|
||||
if(downloadStatus.Percent > percent)
|
||||
percent = downloadStatus.Percent;
|
||||
bsLoading.SetProgress(percent);
|
||||
bsLoading.SetInfo(Boostrapi18n.Instance.GetText("msg_downloading"));
|
||||
bsLoading.SetDownloadSize(downloadedBytes, downloadStatus.TotalBytes);
|
||||
//bsLoading.SetSubProgress(downloadHandle.PercentComplete);
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
|
||||
if(downloadHandle.OperationException != null)
|
||||
{
|
||||
Debug.LogError($"Download Fail: {downloadHandle.OperationException.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(downloadHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
Debug.LogError($"Download Fail Status: {downloadHandle.Status}");
|
||||
return false;
|
||||
}
|
||||
|
||||
downloadStatus = downloadHandle.GetDownloadStatus();
|
||||
if(downloadStatus.TotalBytes == 0 && downloadStatus.DownloadedBytes == 0)
|
||||
{
|
||||
Debug.LogError($"Download Fail: {downloadStatus.TotalBytes} {downloadStatus.DownloadedBytes}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Addressables.Release(downloadHandle);
|
||||
}
|
||||
|
||||
//bsLoading.SetSubProgress(-1);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Boostrap]::UpdateAsset error: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
//finally
|
||||
//{
|
||||
//Addressables.WebRequestOverride = null;
|
||||
//}
|
||||
|
||||
bsLoading.SetProgress(0.1f);
|
||||
bsLoading.SetInfo(Boostrapi18n.Instance.GetText("msg_loadingresource"));
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
var remoteVer = VersionTool.FromString(config.Get(GConstant.K_Ver, string.Empty));
|
||||
remoteVer.Save();
|
||||
bsLoading.SetVersionInfo(remoteVer.ToVerString());
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private async Task AfterAssetUpdateV2()
|
||||
{
|
||||
bsLoading.SetProgress(0.15f);
|
||||
await SubBoostrap.RegisterServices(ctx.gameObject);
|
||||
bsLoading.SetProgress(0.16f);
|
||||
await SubBoostrap.AfterAssetUpdate(config, bsLoading.SetProgress);
|
||||
bsLoading.SetProgress(0.18f);
|
||||
}
|
||||
|
||||
private async Task GoToStageV2()
|
||||
{
|
||||
Debug.Log("Boostrap Done");
|
||||
|
||||
await SubBoostrap.ShowLoadingScreen(config, ctx.gameObject);
|
||||
await Awaiters.NextFrame;
|
||||
bsLoading.Hide();
|
||||
_ = GContext.container.Resolve<IStageService>().SwitchStageAsync("LoginStage");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private Type _hotUpdateBoostrapType;
|
||||
private async Task AfterAssetUpdate()
|
||||
{
|
||||
var hotUpdateAsset = await LoadDll();
|
||||
bsLoading.SetProgress(0.15f);
|
||||
|
||||
|
||||
Debug.Log($"[Boostrap]::AfterAssetUpdate LoadDll Done");
|
||||
|
||||
_hotUpdateBoostrapType = hotUpdateAsset.GetType("HotUpateBoostrap");
|
||||
|
||||
var task = (Task)_hotUpdateBoostrapType.GetMethod("RegisterServices").Invoke(null, new object[] { ctx.gameObject });
|
||||
await task;
|
||||
|
||||
bsLoading.SetProgress(0.16f);
|
||||
|
||||
var progressAction = Delegate.CreateDelegate(typeof(Action<float>), bsLoading, "SetProgress");
|
||||
|
||||
task = (Task)_hotUpdateBoostrapType.GetMethod("AfterAssetUpdate").Invoke(null, new object[] { config, progressAction });
|
||||
|
||||
await task;
|
||||
|
||||
Debug.Log($"[Boostrap]::AfterAssetUpdate RegisterServices Done");
|
||||
|
||||
bsLoading.SetProgress(0.18f);
|
||||
}
|
||||
|
||||
private async Task<Assembly> LoadDll()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
//Load HotUpdate dll
|
||||
var dllAsset = await Addressables.LoadAssetAsync<TextAsset>("Hotupdate.dll").Task;
|
||||
var bytes = dllAsset.bytes;
|
||||
var hotUpdateAsset = Assembly.Load(bytes);
|
||||
Addressables.Release(dllAsset);
|
||||
|
||||
//Load Aot dll
|
||||
var aotDllTasks = GConstant.AOT_Dlls.Select(aotDllName => Addressables.LoadAssetAsync<TextAsset>(aotDllName).Task);
|
||||
await Task.WhenAll(aotDllTasks);
|
||||
|
||||
var dllLoadTasks = new List<Task>();
|
||||
foreach (var aotDllTask in aotDllTasks)
|
||||
{
|
||||
var aotDllBytes = aotDllTask.Result.bytes;
|
||||
dllLoadTasks.Add(Task.Run(() => {
|
||||
HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(aotDllBytes, HomologousImageMode.SuperSet);
|
||||
}));
|
||||
}
|
||||
await Task.WhenAll(dllLoadTasks);
|
||||
|
||||
#else
|
||||
|
||||
var hotUpdateAsset = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate");
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
#endif
|
||||
return hotUpdateAsset;
|
||||
}
|
||||
|
||||
private async Task GoToStage()
|
||||
{
|
||||
Debug.Log("Boostrap Done");
|
||||
|
||||
var task = (Task)_hotUpdateBoostrapType.GetMethod("ShowLoadingScreen").Invoke(null, new object[] { config });
|
||||
await task;
|
||||
await Awaiters.NextFrame;
|
||||
bsLoading.Hide();
|
||||
_ = GContext.container.Resolve<IStageService>().SwitchStageAsync("LoginStage");
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void OnDestory()
|
||||
{
|
||||
ctx.OnInited -= OnContextInited;
|
||||
}
|
||||
|
||||
private void ShowMantainceDialog(string maintanceMessage)
|
||||
{
|
||||
maintanceDialog.Config(new SimpleDialog.Context()
|
||||
{
|
||||
message = Boostrapi18n.Instance.GetText("title_maintenance"),
|
||||
message2 = string.Format(Boostrapi18n.Instance.GetText("content_maintenance"), maintanceMessage),
|
||||
okAction = () => RootCtx.ExitGame(),
|
||||
});
|
||||
}
|
||||
|
||||
private async Task RetryDialog(SimpleDialog dialog, Func<Task<bool>> func, string retryType)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", retryType);
|
||||
}
|
||||
#endif
|
||||
var retry = new TaskCompletionSource<bool>();
|
||||
dialog.Config(new SimpleDialog.Context()
|
||||
{
|
||||
message = Boostrapi18n.Instance.GetText("subtitle_networkfailed"),
|
||||
message2 = Boostrapi18n.Instance.GetText("content_networkfailed"),
|
||||
okAction = async () => retry.SetResult(await func()),
|
||||
});
|
||||
if (await retry.Task) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/AOTScripts/Boostrap.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/Boostrap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbaf5fb72da8a6f4cb1dd6f29cd60b86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
94
Assets/Scripts/AOTScripts/BoostrapLoading.cs
Normal file
94
Assets/Scripts/AOTScripts/BoostrapLoading.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class BoostrapLoading : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text loadingInfo;
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text versionInfo;
|
||||
|
||||
[SerializeField]
|
||||
private Image progressBar;
|
||||
|
||||
[SerializeField]
|
||||
private Image subProgressBar;
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text ProgressLabel;
|
||||
|
||||
[SerializeField]
|
||||
private TMP_Text DownloadSize;
|
||||
|
||||
public void Show()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void SetVersionInfo(string verStr)
|
||||
{
|
||||
versionInfo.text = verStr;
|
||||
}
|
||||
|
||||
public void SetProgress(float progress)
|
||||
{
|
||||
progressBar.fillAmount = progress;
|
||||
|
||||
var percent_text = (progress * 100f);
|
||||
ProgressLabel.text = $"{percent_text.ToString("0.00")}%";
|
||||
|
||||
//bool visible = progress != 0;
|
||||
bool visible = progress >= 0;
|
||||
progressBar.transform.parent.gameObject.SetActive(visible);
|
||||
ProgressLabel.gameObject.SetActive(visible);
|
||||
}
|
||||
|
||||
private const double byte2mb = 1024 * 1024;
|
||||
|
||||
public void SetProgress(float progress, long downloadBytes, long totalBytes)
|
||||
{
|
||||
bool visible = progress >= 0;
|
||||
progressBar.transform.parent.gameObject.SetActive(visible);
|
||||
ProgressLabel.gameObject.SetActive(visible);
|
||||
|
||||
if(visible)
|
||||
{
|
||||
progressBar.fillAmount = progress;
|
||||
var progressStr = $"{(downloadBytes/byte2mb).ToString("0.00")}MB/{(totalBytes/byte2mb).ToString("0.00")}MB ({(progress * 100f).ToString("0.00")}%)";
|
||||
ProgressLabel.text = progressStr;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSubProgress(float progress)
|
||||
{
|
||||
bool visible = progress >= 0;
|
||||
subProgressBar.gameObject.SetActive(visible);
|
||||
|
||||
if(visible)
|
||||
{
|
||||
subProgressBar.fillAmount = progress;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDownloadSize(long downloadBytes, long totalBytes)
|
||||
{
|
||||
if(downloadBytes <0 || downloadBytes == totalBytes)
|
||||
DownloadSize.text = string.Empty;
|
||||
else
|
||||
DownloadSize.text = $"{(downloadBytes/byte2mb).ToString("0.0")}MB/{(totalBytes/byte2mb).ToString("0.0")}MB";
|
||||
}
|
||||
|
||||
public void SetInfo(string info)
|
||||
{
|
||||
loadingInfo.text = info;
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/BoostrapLoading.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/BoostrapLoading.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39873ea9f0d504546ab58d2ae5d178fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
Assets/Scripts/AOTScripts/Boostrapi18n.cs
Normal file
102
Assets/Scripts/AOTScripts/Boostrapi18n.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
|
||||
public class Boostrapi18n
|
||||
{
|
||||
private static Boostrapi18n _Instance;
|
||||
private Dictionary<string, string[]> textDic;
|
||||
int currentIndex = 2; //default en
|
||||
public Boostrapi18n()
|
||||
{
|
||||
textDic = ReadFromCsv();
|
||||
}
|
||||
public static Boostrapi18n Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Instance == null)
|
||||
{
|
||||
_Instance = new Boostrapi18n();
|
||||
}
|
||||
return _Instance;
|
||||
}
|
||||
}
|
||||
public void Init()
|
||||
{
|
||||
textDic = ReadFromCsv();
|
||||
}
|
||||
private Dictionary<string, string[]> ReadFromCsv()
|
||||
{
|
||||
//read tsv
|
||||
var tsv = BetterStreamingAssets.ReadAllText("boostrapi18n.tsv");
|
||||
textDic = new Dictionary<string, string[]>();
|
||||
var lines = tsv.Split('\n');
|
||||
if (lines.Length < 2) return textDic;
|
||||
var header = lines[0];
|
||||
var headers = header.Split('\t');
|
||||
if (headers.Length < 2) return textDic;
|
||||
|
||||
string Language = "en";
|
||||
|
||||
|
||||
if (!PlayerPrefs.HasKey("Lang"))
|
||||
{
|
||||
CultureInfo info = System.Globalization.CultureInfo.CurrentUICulture;
|
||||
Language = info.TwoLetterISOLanguageName;
|
||||
if (Language == "zh")
|
||||
{
|
||||
if (info.DisplayName.Contains("Simplified"))
|
||||
{
|
||||
Language = "zh_Hans";
|
||||
}
|
||||
else
|
||||
{
|
||||
Language = "zh_Hant";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Language = PlayerPrefs.GetString("Lang");
|
||||
}
|
||||
|
||||
for (int i = 1; i < headers.Length; i++)
|
||||
{
|
||||
//把value[1]里面的"\n","\r","\r\n"替换为""
|
||||
string v = headers[i].Replace("\n", "").Replace("\r", "").Replace("\r\n", "");
|
||||
if (v == "text_" + Language)
|
||||
{
|
||||
currentIndex = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i1 = 1; i1 < lines.Length; i1++)
|
||||
{
|
||||
string line = lines[i1];
|
||||
var values = line.Split('\t');
|
||||
if (values.Length < 2) continue;
|
||||
var key = values[0];
|
||||
string[] value = new string[values.Length - 1];
|
||||
for (int i = 1; i < values.Length; i++)
|
||||
{
|
||||
//把value[1]里面的"\n","\r","\r\n"替换为""
|
||||
string v = values[i].Replace("\n", "").Replace("\r", "").Replace("\r\n", "").Replace("\\r\\n", "\r\n");
|
||||
value[i - 1] = v;
|
||||
//value[i - 1] = values[i];
|
||||
}
|
||||
textDic.TryAdd(key, value);
|
||||
}
|
||||
return textDic;
|
||||
}
|
||||
|
||||
public string GetText(string key)
|
||||
{
|
||||
if (!textDic.ContainsKey(key))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return textDic[key][currentIndex];
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/Boostrapi18n.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/Boostrapi18n.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2b4a2cd74aff68448085a1c9b5f568a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Scripts/AOTScripts/CertHandler.cs
Normal file
7
Assets/Scripts/AOTScripts/CertHandler.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
public class CertHandler : UnityEngine.Networking.CertificateHandler
|
||||
{
|
||||
protected override bool ValidateCertificate(byte[] certificateData)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/CertHandler.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/CertHandler.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7269d611fae2410885300a7755f4c11
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
372
Assets/Scripts/AOTScripts/GConfig.cs
Normal file
372
Assets/Scripts/AOTScripts/GConfig.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using SimpleJSON;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
public static class ConfigExtension
|
||||
{
|
||||
private const string defaultconfig = "9Nf/P8vm2+7Ciph2jH1QnEaHCK3cAl7lNnCJc/uxSKGVqcJgWilN3VgaC/74coHRiRpxEelC2+ia7qcjnHhA3OQN82rcVJOP24pGKrSbSgOIGbH9cCEUhdYRo5vnVgLBqlTS/c/AajowTkN59O0AYxDC7J3jq6ptLXdmuG27JYS9NXOQDkgxpzEpG7JTtczHKxhWAv+9uSzbJRCs16KeusbJX1YtNZM8wjCD9esTv4zXXMIpZPlXb86NjHiI02TakAdHo0plO+Di9n5UCC8/4+QGoKNyQgtvIkzMyoGziO4DOLy/VkfITenFv/+9DY0LmpZGa7Cog89znaYyVMTiC/3R2IefXXh04+8uqmyzeVKqh0grcU9qmz485wCoUl/TM9F8+s1Jhp/eaB/E7luOjc57Kz0Eyw2Qko7Fo+lCaRJE1uex9fB46v0LhddSHCEWw8QERmqG9KcmvG4LsyafupA8kliDzj7a7XIzGrgnNnsMxLgeYsSbNiBvXXESeeNCoqiOQTTBpk/br0QuTHTG2DRxUZZ4KM3SKZtHEZ2bZV2FUS4azFpfDXUGoc86O+xz6hAIMbdKCHyqyEeKMmHIzQI9OlIaa3KGwk+w1eFDUuq4zyTh+qGuClZynanUkfNe8mTmFtBax2f3MJHjGpXJT0VdtY/R+5ZQO0nCU30THfnryG0GURsrv6MQYiQX5hsLqG9Z72ybbbbqIR2rvE2w13DM/tqTb4i/hN0+pbeTKkUpdNIWEsR94Q==";
|
||||
|
||||
private static string RemoteConfigUrl { get; set; }
|
||||
|
||||
public static void Rest(this IConfig config)
|
||||
{
|
||||
RemoteConfigUrl = null;
|
||||
}
|
||||
|
||||
public static async Task<bool> InitConfig(this IConfig config)
|
||||
{
|
||||
JSONNode streamingAssetConfig = null;
|
||||
JSONNode persistConfig = null;
|
||||
bool isSuccessLoadRemoteConfigFile = true;
|
||||
|
||||
if (RemoteConfigUrl == null)
|
||||
{
|
||||
streamingAssetConfig = GetStreamingAssetConfig();
|
||||
persistConfig = GetPersistConfig();
|
||||
}
|
||||
|
||||
if (RemoteConfigUrl == null)
|
||||
{
|
||||
RemoteConfigUrl = string.Format(GConstant.V_Static_Res_URL, VersionTool.PackVer);
|
||||
}
|
||||
|
||||
JSONNode remoteConfig = await GetRemoteConfig();
|
||||
|
||||
if (remoteConfig == null)
|
||||
{
|
||||
var remoteConfigStr = Decrypt(defaultconfig);
|
||||
remoteConfig = JSON.Parse(remoteConfigStr);
|
||||
remoteConfig["Ver"] = VersionTool.FromLocal().ToVerString();
|
||||
isSuccessLoadRemoteConfigFile = false;
|
||||
}
|
||||
|
||||
foreach (var element in remoteConfig)
|
||||
{
|
||||
config.Set(element.Key, element.Value.Value);
|
||||
}
|
||||
|
||||
if (streamingAssetConfig != null)
|
||||
{
|
||||
foreach (var element in streamingAssetConfig)
|
||||
{
|
||||
config.Set(element.Key, element.Value.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (persistConfig != null)
|
||||
{
|
||||
foreach (var element in persistConfig)
|
||||
{
|
||||
config.Set(element.Key, element.Value.Value);
|
||||
}
|
||||
}
|
||||
|
||||
config.Set(GConstant.K_Static_Res_URL, RemoteConfigUrl);
|
||||
|
||||
return isSuccessLoadRemoteConfigFile;
|
||||
}
|
||||
|
||||
|
||||
private static readonly float[] timeoutValues = new float[] { 1, 2, 2 };
|
||||
|
||||
public static async Task<JSONNode> GetRemoteConfig()
|
||||
{
|
||||
UnityEngine.Assertions.Assert.IsNotNull(RemoteConfigUrl, "Config is not inited");
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
var maxRetryTimes = timeoutValues.Length;
|
||||
|
||||
for (int retryTime = 0; retryTime < maxRetryTimes; retryTime++)
|
||||
{
|
||||
var rawConfig = await DoGetRawConfigUWR(timeoutValues[retryTime], retryTime, maxRetryTimes);
|
||||
if (!string.IsNullOrEmpty(rawConfig))
|
||||
{
|
||||
Debug.Log($"<color=orange>Load remote config success {retryTime + 1}/{maxRetryTimes}</color>");
|
||||
return JSON.Parse(rawConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static async Task<string> DoGetRawConfigUWR(float timeoutInSec, int retryTimes, int maxRetryTimes)
|
||||
{
|
||||
using (var req = UnityWebRequest.Get($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}"))
|
||||
{
|
||||
var stopwatch = new System.Diagnostics.Stopwatch();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(timeoutInSec));
|
||||
var ct = cts.Token;
|
||||
stopwatch.Start();
|
||||
req.timeout = (int)timeoutInSec;
|
||||
req.SetRequestHeader("Accept", "application/json");
|
||||
var op = req.SendWebRequest();
|
||||
try
|
||||
{
|
||||
while (!op.isDone && !ct.IsCancellationRequested)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
ct.ThrowIfCancellationRequested();
|
||||
stopwatch.Stop();
|
||||
|
||||
if (req.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
return Decrypt(req.downloadHandler.text);
|
||||
}
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", req.result.ToString());
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", req.error);
|
||||
}
|
||||
#endif // AGG
|
||||
|
||||
Debug.LogWarning($"Load remote config failed {req.result.ToString()} {req.error} {retryTimes + 1}/{maxRetryTimes}");
|
||||
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
req.Abort();
|
||||
stopwatch.Stop();
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", "cancel");
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", req.error ?? "cancel");
|
||||
}
|
||||
#endif // AGG
|
||||
|
||||
Debug.LogWarning($"Load remote config cancel {req.result.ToString()} {req.error} {retryTimes + 1}/{maxRetryTimes}");
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts.Dispose();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
private static async Task<string> DoGetRawConfig(float timeoutInSec, int retryTimes)
|
||||
{
|
||||
var timeout = TimeSpan.FromSeconds(timeoutInSec);
|
||||
var handler = new System.Net.Http.HttpClientHandler(){
|
||||
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
|
||||
};
|
||||
using (var httpClient = new System.Net.Http.HttpClient(handler))
|
||||
{
|
||||
httpClient.Timeout = timeout;
|
||||
var stopwatch = new System.Diagnostics.Stopwatch();
|
||||
|
||||
try
|
||||
{
|
||||
stopwatch.Start();
|
||||
var respon = await httpClient.GetAsync($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}");
|
||||
stopwatch.Stop();
|
||||
|
||||
if (respon.IsSuccessStatusCode)
|
||||
{
|
||||
string remoteConfigStr = await respon.Content.ReadAsStringAsync();
|
||||
await Awaiters.NextFrame;
|
||||
return Decrypt(remoteConfigStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
Debug.LogWarning($"Load remote config failed {respon.StatusCode.ToString()}");
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", respon.StatusCode.ToString());
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("error", "http_request_failed");
|
||||
}
|
||||
#endif//AGG
|
||||
}
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException httpEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.Elapsed;
|
||||
|
||||
var errorMessage = $"HTTP request failed: {httpEx.Message}";
|
||||
if (httpEx.InnerException != null)
|
||||
{
|
||||
errorMessage += $" Inner: {httpEx.InnerException.Message}";
|
||||
if(httpEx.InnerException.InnerException != null)
|
||||
{
|
||||
errorMessage += $" InnerInner: {httpEx.InnerException.InnerException.Message}";
|
||||
}
|
||||
}
|
||||
Debug.LogWarning(errorMessage);
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
|
||||
e.AddContent("reason", "httpEx");
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("error", errorMessage);
|
||||
}
|
||||
#endif//AGG
|
||||
}
|
||||
catch (System.Threading.Tasks.TaskCanceledException timeoutEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.Elapsed;
|
||||
|
||||
Debug.LogWarning($"Request timeout after {timeoutInSec}s: {timeoutEx.Message}");
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
|
||||
e.AddContent("reason", $"timeout");
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("error", timeoutEx.Message);
|
||||
}
|
||||
#endif//AGG
|
||||
}
|
||||
catch (System.Security.Cryptography.CryptographicException cryptoEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.Elapsed;
|
||||
|
||||
Debug.LogError($"Decryption failed: {cryptoEx.Message}");
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", elapsed.TotalMilliseconds);
|
||||
e.AddContent("reason", "cryptoEx");
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("error", cryptoEx.Message);
|
||||
}
|
||||
#endif//AGG
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
var errorMessage = $"Unexpected error loading remote config: {exception.Message}";
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
errorMessage += $" Inner: {exception.InnerException.Message}";
|
||||
}
|
||||
Debug.LogError(errorMessage);
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "config");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", "unexpected_error");
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("error", errorMessage);
|
||||
}
|
||||
#endif//AGG
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* public static async Task<JSONNode> GetRemoteConfig()
|
||||
* {
|
||||
* UnityEngine.Assertions.Assert.IsNotNull(RemoteConfigUrl, "Config is not inited");
|
||||
* var request = UnityWebRequest.Get($"{RemoteConfigUrl}/{GConstant.V_Remote_Config_Path}");
|
||||
* request.timeout = 5;
|
||||
* await request.SendWebRequest();
|
||||
*
|
||||
* if (request.result != UnityWebRequest.Result.Success)
|
||||
* {
|
||||
* return null;
|
||||
* }
|
||||
*
|
||||
* string remoteConfigStr = request.downloadHandler.text;
|
||||
* remoteConfigStr = Decrypt(remoteConfigStr);
|
||||
* return SimpleJSON.JSON.Parse(remoteConfigStr);
|
||||
* }
|
||||
*/
|
||||
|
||||
const string RTMKey = "tbambooz";
|
||||
private static string Decrypt(string text)
|
||||
{
|
||||
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
|
||||
des.Key = Encoding.ASCII.GetBytes(RTMKey);
|
||||
des.IV = Encoding.ASCII.GetBytes(RTMKey);
|
||||
|
||||
ICryptoTransform decryptor = des.CreateDecryptor(des.Key, des.IV);
|
||||
byte[] inputBytes = Convert.FromBase64String(text);
|
||||
byte[] outputBytes = decryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
|
||||
|
||||
return Encoding.UTF8.GetString(outputBytes);
|
||||
}
|
||||
|
||||
private static JSONNode GetStreamingAssetConfig()
|
||||
{
|
||||
var debugConfigPath = GConstant.V_Debug_Config_Path;
|
||||
var text = BetterStreamingAssets.ReadAllText(debugConfigPath);
|
||||
//如果第一个字符是#e,就返回false
|
||||
if (!text.StartsWith("#"))
|
||||
{
|
||||
var debugConfig = SimpleJSON.JSON.Parse(text);
|
||||
if (debugConfig.HasKey(GConstant.K_Static_Res_URL))
|
||||
{
|
||||
RemoteConfigUrl = debugConfig[GConstant.K_Static_Res_URL];
|
||||
Debug.Log($"<color=yellow>Debug Static Res URL => {RemoteConfigUrl}</color>");
|
||||
}
|
||||
return debugConfig;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static JSONNode GetPersistConfig()
|
||||
{
|
||||
var debugConfigPath = Path.Combine(Application.persistentDataPath, GConstant.V_Debug_Config_Path);
|
||||
if (File.Exists(debugConfigPath))
|
||||
{
|
||||
var debugConfig = SimpleJSON.JSON.Parse(File.ReadAllText(debugConfigPath));
|
||||
if (debugConfig.HasKey(GConstant.K_Static_Res_URL))
|
||||
{
|
||||
RemoteConfigUrl = debugConfig[GConstant.K_Static_Res_URL];
|
||||
Debug.Log($"<color=yellow>Debug Static Res URL => {RemoteConfigUrl}</color>");
|
||||
}
|
||||
return debugConfig;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/GConfig.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/GConfig.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f6b7f8a5010f4daa82832584171069f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
99
Assets/Scripts/AOTScripts/GConstant.cs
Normal file
99
Assets/Scripts/AOTScripts/GConstant.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
// #####
|
||||
// # # #### # # #### ##### ## # # #####
|
||||
// # # # ## # # # # # ## # #
|
||||
// # # # # # # #### # # # # # # #
|
||||
// # # # # # # # # ###### # # # #
|
||||
// # # # # # ## # # # # # # ## #
|
||||
// ##### #### # # #### # # # # # #
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------
|
||||
* V_XXXXX for Config Values
|
||||
* K_XXXXX for Config Keys
|
||||
*===============================================================
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class GConstant
|
||||
{
|
||||
public const string V_Debug_Config_Path = "debugconfig.json";
|
||||
|
||||
#if UNITY_ANDROID
|
||||
public const string V_Remote_Config_Path = "androidconfig.json";
|
||||
#elif UNITY_IOS
|
||||
public const string V_Remote_Config_Path = "iosconfig.json";
|
||||
#else
|
||||
public const string V_Remote_Config_Path = "config.json";
|
||||
#endif
|
||||
|
||||
public const string K_Static_Res_URL = "StaticResURL";
|
||||
|
||||
public const string V_Static_Res_URL = "https://128-ft-cdn-aws.arksgame.com/ab/{0}";
|
||||
|
||||
public const string K_Event_API_URL = "EventApiURL";
|
||||
|
||||
public const string K_Maintance = "Maintance";
|
||||
|
||||
public const string K_Ver = "Ver";
|
||||
public const string K_Ver_New = "Ver_New";
|
||||
|
||||
public const string K_PlayFab_Title = "PlayFabTitle";
|
||||
public const string K_PlayFab_TimeOut = "PlayFabTimeOut";
|
||||
|
||||
public const string K_Custom_Addressable = "Custom_Addressable_URL";
|
||||
public const string K_Origin_Addressable = "Origin_Addressable_URL";
|
||||
|
||||
public const string K_Android_Privacy_Policy_URL = "PrivacyPolicy";
|
||||
public const string V_Android_Privacy_Policy_URL = "https://arksgame.com/privacyGoogle.html";
|
||||
|
||||
public const string K_IOS_Privacy_Policy_URL = "PrivacyPolicy";
|
||||
public const string V_IOS_Privacy_Policy_URL = "https://arksgame.com/ps.html";
|
||||
|
||||
public const string K_User_Agreement_URL = "UserAgreement";
|
||||
public const string V_User_Agreement_URL = "https://arksgame.com/terms.html";
|
||||
|
||||
public const string K_APP_Store_URL = "APP_Store_URL";
|
||||
public const string K_Google_Play_URL = "Google_Play_URL";
|
||||
|
||||
public const string V_Debug_PF_Title = "6DC6D";
|
||||
|
||||
public const string K_BuglyAppID = "BuglyAppID";
|
||||
public const string V_BuglyAppID = "af5ac6a2c2";
|
||||
|
||||
public const string K_BuglyAppKey = "BuglyAppKey";
|
||||
public const string V_BuglyAppKey = "5de4f8e4-9552-4bb9-9423-82ce8daf2d6c";
|
||||
|
||||
public const string K_HeartBeat = "HeartBeat";
|
||||
public const string K_FPS = "FPS";
|
||||
|
||||
public const string K_RTMP_ID = "RTMPid";
|
||||
public const string K_RTM_Server_Endpoint = "RTMServerEndpoint";
|
||||
public const string K_RTM_Hmac_Secret = "RTMHmacSecret";
|
||||
|
||||
|
||||
public const string K_FuncUrl = "FuncUrl";
|
||||
public const string V_FuncUrl = "http://192.168.9.101:7071";
|
||||
|
||||
public const string K_FuncKey = "FuncKey";
|
||||
public const string V_FuncKey = "testKey";
|
||||
|
||||
public const string TA_URL = "https://ta-event.bamboogames.fun";
|
||||
public const string TA_APPID = "9876bb56ee484b528064d1db40a57ec4";
|
||||
|
||||
public const string AF_KEY = "rSySeWtvKabfbPZE7Lmx7C";
|
||||
public const string AF_APPID = "6505145935";
|
||||
public const string AF_OneLinkID = "jT1Q";
|
||||
|
||||
public static readonly IReadOnlyList<string> AOT_Dlls = new List<string>()
|
||||
{
|
||||
"mscorlib.dll",
|
||||
"System.dll",
|
||||
"System.Core.dll",
|
||||
"Newtonsoft.Json.dll",
|
||||
"asap.core.dll",
|
||||
"UniRx.dll",
|
||||
"IngameDebugConsole.Runtime.dll"
|
||||
};
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/GConstant.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/GConstant.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ba3f3f5ca3183a419aa7fd179b03a67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
222
Assets/Scripts/AOTScripts/GEvent.cs
Normal file
222
Assets/Scripts/AOTScripts/GEvent.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AppsFlyerSDK;
|
||||
using asap.core;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
public class GEvent : IDisposable
|
||||
{
|
||||
private JObject content = new JObject();
|
||||
private string eventName;
|
||||
private bool afSend = false;
|
||||
private bool gaSend = true;
|
||||
|
||||
private const string TA_APPID_KEY = "ta_appid";
|
||||
private const string TA_URL_KEY = "ta_url";
|
||||
|
||||
private static bool _hasInit = false;
|
||||
public static void Init()
|
||||
{
|
||||
if (_hasInit) return;
|
||||
TaInit();
|
||||
InitAppsFlyer();
|
||||
_hasInit = true;
|
||||
}
|
||||
|
||||
public static void SetProp(string key, object prop)
|
||||
{
|
||||
var props = new Dictionary<string, object>(){{key, prop}};
|
||||
SetProps(props);
|
||||
}
|
||||
|
||||
public static void SetProps(Dictionary<string, object> props)
|
||||
{
|
||||
ThinkingData.Analytics.TDAnalytics.SetSuperProperties( props);
|
||||
tysdk.UnityBridgeFunc.SetGaCommonInfo(Newtonsoft.Json.JsonConvert.SerializeObject(props));
|
||||
}
|
||||
|
||||
public static void SetUserProp(string key, object prop, bool once = false)
|
||||
{
|
||||
var props = new Dictionary<string, object>(){{key, prop}};
|
||||
SetUserProps(props, once);
|
||||
}
|
||||
|
||||
public static void SetUserProps(Dictionary<string, object> props, bool once = false)
|
||||
{
|
||||
if(once)
|
||||
{
|
||||
ThinkingData.Analytics.TDAnalytics.UserSetOnce(props);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThinkingData.Analytics.TDAnalytics.UserSet(props);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitAppsFlyer()
|
||||
{
|
||||
var afKey = GConstant.AF_KEY;
|
||||
var afAppID = GConstant.AF_APPID;
|
||||
var afOneLinkID = GConstant.AF_OneLinkID;
|
||||
var afCustomerUserID = ThinkingData.Analytics.TDAnalytics.GetDistinctId();
|
||||
AFHelper.Instance.Init(afKey, afAppID, afCustomerUserID, afOneLinkID, false);
|
||||
Debug.Log("[GEvent::InitAppsFlyer] AppsFlyer inited");
|
||||
}
|
||||
|
||||
private static void TaInit()
|
||||
{
|
||||
var taAppId = GConstant.TA_APPID;
|
||||
var taUrl = GConstant.TA_URL;
|
||||
var autoTrackEventType = ThinkingData.Analytics.TDAutoTrackEventType.AppStart
|
||||
| ThinkingData.Analytics.TDAutoTrackEventType.AppEnd
|
||||
| ThinkingData.Analytics.TDAutoTrackEventType.AppInstall;
|
||||
|
||||
ThinkingData.Analytics.TDAnalytics.Init(taAppId, taUrl);
|
||||
ThinkingData.Analytics.TDAnalytics.EnableThirdPartySharing(ThinkingData.Analytics.Utils.TDThirdPartyType.APPSFLYER);
|
||||
ThinkingData.Analytics.TDAnalytics.EnableAutoTrack(autoTrackEventType);
|
||||
ThinkingData.Analytics.TDAnalytics.EnableLog(false);
|
||||
|
||||
Debug.Log("[GEvent::TaInit] ThinkingData inited");
|
||||
}
|
||||
|
||||
public static void OnLogin(string userID, string customUserID)
|
||||
{
|
||||
ThinkingData.Analytics.TDAnalytics.Login(customUserID);
|
||||
ThinkingData.Analytics.TDAnalytics.EnableThirdPartySharing(ThinkingData.Analytics.Utils.TDThirdPartyType.APPSFLYER);
|
||||
}
|
||||
|
||||
private GEvent(string eventName, bool afSend = false, bool gaSend = true)
|
||||
{
|
||||
this.eventName = eventName;
|
||||
this.afSend = afSend;
|
||||
this.gaSend = gaSend;
|
||||
}
|
||||
|
||||
public GEvent AddContent(string key, string value)
|
||||
{
|
||||
content[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GEvent AddContent(string key, int value)
|
||||
{
|
||||
content[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GEvent AddContent(string key, bool value)
|
||||
{
|
||||
content[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GEvent AddContent(string key, float value)
|
||||
{
|
||||
content[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GEvent AddContent(string key, JToken value)
|
||||
{
|
||||
content[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GEvent WithGAEvent(string eventName)
|
||||
{
|
||||
this.eventName = eventName;
|
||||
this.afSend = true;
|
||||
this.gaSend = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
Dictionary<string, object> properties = content.ToObject<Dictionary<string, object>>();
|
||||
ThinkingData.Analytics.TDAnalytics.Track(eventName, properties);
|
||||
|
||||
Dictionary<string, string> eventValues = content.ToObject<Dictionary<string, string>>();
|
||||
|
||||
if(afSend)
|
||||
{
|
||||
AppsFlyer.sendEvent(eventName, eventValues);
|
||||
}
|
||||
|
||||
if(gaSend)
|
||||
{
|
||||
TYSdkFacade.Instance.EventTrack((int)GATrackType.GA_TRACK, eventName, Newtonsoft.Json.JsonConvert.SerializeObject(properties));
|
||||
}
|
||||
|
||||
content.RemoveAll();
|
||||
content = null;
|
||||
}
|
||||
|
||||
|
||||
public static GEvent TackEvent(string eventName, bool afSend = false, bool gaSend = true)
|
||||
{
|
||||
return new GEvent(eventName, afSend, gaSend);
|
||||
}
|
||||
|
||||
public static GEvent GameEvent(string eventName, bool afSend = false, bool gaSend = true)
|
||||
{
|
||||
return new GEvent(eventName, afSend, gaSend);
|
||||
}
|
||||
|
||||
public static GEvent SpendCreditEvent(bool afSend = false, bool gaSend = true)
|
||||
{
|
||||
return new GEvent(AFInAppEvents.SPENT_CREDIT, afSend, gaSend);
|
||||
}
|
||||
|
||||
public static GEvent CompleteRegistrationEvent()
|
||||
{
|
||||
return new GEvent(AFInAppEvents.COMPLETE_REGISTRATION, true, true);
|
||||
}
|
||||
|
||||
public static GEvent RegistrationEvent()
|
||||
{
|
||||
return new GEvent(AFInAppEvents.REGSITRATION_METHOD, true, true);
|
||||
}
|
||||
|
||||
public static GEvent LoginEvent()
|
||||
{
|
||||
return new GEvent(AFInAppEvents.LOGIN, true, true);
|
||||
}
|
||||
|
||||
public static GEvent RevenueEvent()
|
||||
{
|
||||
return new GEvent(AFInAppEvents.PURCHASE, true, true);
|
||||
//.WithGAEvent("recharge_state");
|
||||
}
|
||||
|
||||
public static void ADRevenueEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
JObject content = new JObject();
|
||||
content.Add(AFAdRevenueEvent.COUNTRY, MaxSdk.GetSdkConfiguration().CountryCode);
|
||||
content.Add("ad_id", adUnitId);
|
||||
content.Add(AFAdRevenueEvent.AD_TYPE, "Reward");
|
||||
content.Add(AFAdRevenueEvent.PLACEMENT, adInfo.Placement);
|
||||
content.Add("value_micros", adInfo.Revenue);
|
||||
content.ToObject<Dictionary<string, string>>();
|
||||
|
||||
AppsFlyerAdRevenue.logAdRevenue(
|
||||
adInfo.NetworkName,
|
||||
AppsFlyerAdRevenueMediationNetworkType.AppsFlyerAdRevenueMediationNetworkTypeGoogleAdMob,
|
||||
adInfo.Revenue,
|
||||
"USD",
|
||||
content.ToObject<Dictionary<string, string>>());
|
||||
|
||||
|
||||
content.Add("revenue", adInfo.Revenue);
|
||||
content.Add("currency", "USD");
|
||||
content.Add("precision", adInfo.RevenuePrecision);
|
||||
|
||||
ThinkingData.Analytics.TDAnalytics.Track("af_ad_revenue", content.ToObject<Dictionary<string, object>>());
|
||||
AppsFlyer.sendEvent("af_ad_revenue", content.ToObject<Dictionary<string, string>>());
|
||||
TYSdkFacade.Instance.EventTrack((int)GATrackType.GA_TRACK, "af_ad_revenue", Newtonsoft.Json.JsonConvert.SerializeObject(content));
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/GEvent.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/GEvent.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86c1a73af4778472a9e7fb25ed9adf54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
65
Assets/Scripts/AOTScripts/GpuEvaluation.cs
Normal file
65
Assets/Scripts/AOTScripts/GpuEvaluation.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using System.Linq;
|
||||
using tysdk;
|
||||
|
||||
public class GpuEvaluation
|
||||
{
|
||||
private class GpuData
|
||||
{
|
||||
public int tier;
|
||||
public string[] keywords;
|
||||
}
|
||||
|
||||
private static GpuData[] _devdatas;
|
||||
private static GpuData[] DevDatas
|
||||
{
|
||||
get{
|
||||
if(_devdatas == null)
|
||||
{
|
||||
var handle = Addressables.LoadAssetAsync<TextAsset>("gpudata");
|
||||
handle.WaitForCompletion();
|
||||
_devdatas = Newtonsoft.Json.JsonConvert.DeserializeObject<GpuData[]>(handle.Result.text);
|
||||
}
|
||||
return _devdatas;
|
||||
}
|
||||
}
|
||||
|
||||
public static int? GetTier(string deviceName)
|
||||
{
|
||||
foreach (var device in DevDatas)
|
||||
{
|
||||
var keywords = device.keywords;
|
||||
if (keywords.All(k => deviceName.IndexOf(k) >= 0))
|
||||
{
|
||||
var info = string.Join(" ", keywords);
|
||||
Debug.Log($"[GpuEvaluation] Found Match Gpu {info} Tier {device.tier}");
|
||||
#if AGG
|
||||
using(var track = GEvent.TackEvent("GpuEvaluation"))
|
||||
{
|
||||
track.AddContent("record", true);
|
||||
track.AddContent("gpu", deviceName);
|
||||
track.AddContent("tier", device.tier);
|
||||
}
|
||||
#endif
|
||||
return device.tier;
|
||||
}
|
||||
}
|
||||
|
||||
#if AGG
|
||||
using(var track = GEvent.TackEvent("GpuEvaluation"))
|
||||
{
|
||||
track.AddContent("record", false);
|
||||
track.AddContent("gpu", deviceName);
|
||||
track.AddContent("tier", 1);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static int Tier => 3;
|
||||
#else
|
||||
public static int Tier => GetTier(SystemInfo.graphicsDeviceName) ?? 2;
|
||||
#endif
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/GpuEvaluation.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/GpuEvaluation.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1d3fb87095f0ab4dbc5770f5baced06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/Scripts/AOTScripts/Localize.cs
Normal file
49
Assets/Scripts/AOTScripts/Localize.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using asap.core;
|
||||
using System;
|
||||
using TMPro;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GameC
|
||||
{
|
||||
public enum TextType
|
||||
{
|
||||
Text, // UGUI Text
|
||||
TextMeshPro, // TextMeshPro - Text
|
||||
TextMeshPro_UGUI // TextMeshPro - Text(UI)
|
||||
}
|
||||
|
||||
public class Localize : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string key;
|
||||
[SerializeField] private TextType textType = TextType.TextMeshPro_UGUI;
|
||||
|
||||
|
||||
private TMP_Text text_UGUI;
|
||||
|
||||
private IDisposable disposable;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
text_UGUI = gameObject.GetComponent<TextMeshProUGUI>();
|
||||
OnChangeLanguage();
|
||||
}
|
||||
|
||||
|
||||
void OnChangeLanguage()
|
||||
{
|
||||
string localized_text = Boostrapi18n.Instance.GetText(key);
|
||||
|
||||
if (!string.IsNullOrEmpty(localized_text))
|
||||
if (text_UGUI)
|
||||
{
|
||||
text_UGUI.text = localized_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/Localize.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/Localize.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1806ed8053370f14d900347897ef8b5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
47
Assets/Scripts/AOTScripts/PreBoot.cs
Normal file
47
Assets/Scripts/AOTScripts/PreBoot.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
[DefaultExecutionOrder(2)]
|
||||
public class PreBoot : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField]
|
||||
private SimpleDialog reconnectDialog;
|
||||
|
||||
private bool HasNetwork => Application.internetReachability != NetworkReachability.NotReachable;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
BetterStreamingAssets.Initialize();
|
||||
StartCoroutine(CheckNetwork());
|
||||
}
|
||||
|
||||
private void ShowRetryDialog()
|
||||
{
|
||||
reconnectDialog.Config(new SimpleDialog.Context()
|
||||
{
|
||||
message = Boostrapi18n.Instance.GetText("subtitle_networkfailed"),
|
||||
message2 = Boostrapi18n.Instance.GetText("content_networkfailed"),
|
||||
okAction = () => StartCoroutine(CheckNetwork()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private IEnumerator CheckNetwork()
|
||||
{
|
||||
yield return new WaitForSeconds(0.3f);
|
||||
if(!HasNetwork)
|
||||
{
|
||||
ShowRetryDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
GEvent.Init();
|
||||
SceneManager.LoadScene("BoostrapScene");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/PreBoot.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/PreBoot.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a3bc0fefcb6449c2961668d6a7a1f9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
144
Assets/Scripts/AOTScripts/QualityAdapter.cs
Normal file
144
Assets/Scripts/AOTScripts/QualityAdapter.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using asap.core;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UniRx;
|
||||
|
||||
public struct QualityChangedEvt { }
|
||||
|
||||
public class QualityManager
|
||||
{
|
||||
private const string Quality_Level = "QualityLevel";
|
||||
public static void ChangeQuality(int level)
|
||||
{
|
||||
string[] names = QualitySettings.names;
|
||||
if (level >= names.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QualitySettings.SetQualityLevel(level);
|
||||
PlayerPrefs.SetInt(Quality_Level, level);
|
||||
GContext.Publish(new QualityChangedEvt());
|
||||
}
|
||||
|
||||
public static void ChangeQuality(string levelName)
|
||||
{
|
||||
var names = QualitySettings.names;
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (names[i] == levelName)
|
||||
{
|
||||
ChangeQuality(i);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AutoSetQualityLevel()
|
||||
{
|
||||
var level=PlayerPrefs.GetInt(Quality_Level, -1);
|
||||
if (level == -1)
|
||||
{
|
||||
level = GpuEvaluation.Tier;
|
||||
}
|
||||
ChangeQuality(level);
|
||||
}
|
||||
|
||||
public static string[] QualityNames => QualitySettings.names;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class QualityAdapter : MonoBehaviour
|
||||
{
|
||||
[Serializable]
|
||||
private class AdapterData
|
||||
{
|
||||
public GameObject[] enableObjects;
|
||||
public GameObject[] disableObjects;
|
||||
public Renderer renderer;
|
||||
public string[] keywordsToEnable;
|
||||
public string[] keywordsToDisable;
|
||||
public string[] propToEnable;
|
||||
public string[] propToDisable;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private AdapterData[] adapterDatas;
|
||||
|
||||
private IDisposable disposable = null;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
disposable = GContext.OnEvent<QualityChangedEvt>().Subscribe(_ => SetQualityLevel());
|
||||
SetQualityLevel();
|
||||
}
|
||||
|
||||
private void SetQualityLevel()
|
||||
{
|
||||
int level = QualitySettings.GetQualityLevel();
|
||||
if (level >= adapterDatas.Length)
|
||||
{
|
||||
level = adapterDatas.Length - 1;
|
||||
}
|
||||
var adapterData = adapterDatas[level];
|
||||
|
||||
if (adapterData.enableObjects != null)
|
||||
{
|
||||
foreach (var go in adapterData.enableObjects)
|
||||
{
|
||||
go.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (adapterData.disableObjects != null)
|
||||
{
|
||||
foreach (var go in adapterData.disableObjects)
|
||||
{
|
||||
go.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (adapterData.renderer != null)
|
||||
{
|
||||
var mat = adapterData.renderer.material;
|
||||
var keywordsToEnable = adapterData.keywordsToEnable;
|
||||
if (keywordsToEnable != null)
|
||||
{
|
||||
foreach (var keyword in keywordsToEnable)
|
||||
{
|
||||
mat.EnableKeyword(keyword);
|
||||
}
|
||||
}
|
||||
var keywordsToDisable = adapterData.keywordsToDisable;
|
||||
if (keywordsToDisable != null)
|
||||
{
|
||||
foreach (var keyword in keywordsToDisable)
|
||||
{
|
||||
mat.DisableKeyword(keyword);
|
||||
}
|
||||
}
|
||||
var propToEnable = adapterData.propToEnable;
|
||||
if (propToEnable != null)
|
||||
{
|
||||
foreach (var prop in propToEnable)
|
||||
{
|
||||
mat.SetInt(prop, 1);
|
||||
}
|
||||
}
|
||||
var propToDisable = adapterData.propToDisable;
|
||||
if (propToDisable != null)
|
||||
{
|
||||
foreach (var prop in propToDisable)
|
||||
{
|
||||
mat.SetInt(prop, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/QualityAdapter.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/QualityAdapter.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9bd5b8b9de24984593b2cb1f1aab54e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
223
Assets/Scripts/AOTScripts/RootCtx.cs
Normal file
223
Assets/Scripts/AOTScripts/RootCtx.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using asap.core;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class RootCtx : GContext
|
||||
{
|
||||
#if !UNITY_EDITOR && AGG
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log("InitSDK");
|
||||
|
||||
tysdk.TYSdkFacade.Instance.Init();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override async Task SetupAsync()
|
||||
{
|
||||
container.Register<IStageService, StageService>().AsSingleton();
|
||||
//container.Register<IDataService, LubanDataService>().AsSingleton();
|
||||
container.Register<IObjectSerializer, ObjectSerializer>().AsSingleton();
|
||||
container.Register<IConfig, Config>().AsSingleton();
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
BetterStreamingAssets.Initialize();
|
||||
|
||||
// using remote assets locally if exists
|
||||
Addressables.InternalIdTransformFunc += DoIdTransform;
|
||||
|
||||
UnityEngine.Random.InitState((int)System.DateTime.Now.Ticks);
|
||||
// Initialize DOTween with the preferences set in DOTween's Utility Panel
|
||||
DG.Tweening.DOTween.Init();
|
||||
// Set Tweens capacity accordingly based on DOTween warnings
|
||||
DG.Tweening.DOTween.SetTweensCapacity(200, 125);
|
||||
|
||||
Application.lowMemory += OnLowMemory;
|
||||
//SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
Screen.sleepTimeout = SleepTimeout.NeverSleep;
|
||||
}
|
||||
|
||||
//void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
//{
|
||||
//GameDebug.Log("[GameEngine]OnSceneLoaded: Name: {0}, Mode: {1}", scene.name, mode);
|
||||
//SetCamStack();
|
||||
//}
|
||||
|
||||
|
||||
float _lowMemCleanupTime;
|
||||
bool _isUnloadingMem;
|
||||
const float LOW_MEM_CLEANUP_CD = 10f; // in secs
|
||||
|
||||
void OnLowMemory()
|
||||
{
|
||||
GameDebug.LogWarning("[GameEngine]OnLowMemory: Memory is low!");
|
||||
|
||||
// Add a cool-down time to prevent consecutive cleaning up process, which
|
||||
// will cause a long performance hiccup
|
||||
if (!_isUnloadingMem &&
|
||||
Time.realtimeSinceStartup - _lowMemCleanupTime > LOW_MEM_CLEANUP_CD)
|
||||
{
|
||||
StartCoroutine(UnloadMemory());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator UnloadMemory(Action back = null)
|
||||
{
|
||||
GameDebug.Log("[GameEngine]UnloadMemory: Start cleaning up!");
|
||||
|
||||
_isUnloadingMem = true;
|
||||
System.GC.Collect();
|
||||
var op = Resources.UnloadUnusedAssets();
|
||||
|
||||
while (!op.isDone)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
back?.Invoke();
|
||||
_lowMemCleanupTime = Time.realtimeSinceStartup;
|
||||
_isUnloadingMem = false;
|
||||
GameDebug.Log("[GameEngine]UnloadMemory: Cleaning up is done!");
|
||||
}
|
||||
|
||||
private string customAddressableRemoteURL;
|
||||
private string originAddressableRemoteURL;
|
||||
|
||||
public void ChangeAddressableRemoteUrl(string customUrl, string originUrl)
|
||||
{
|
||||
Debug.Log($"[RootCtx::ChangeAddressableRemoteUrl] customUrl: {customUrl}, originUrl: {originUrl}");
|
||||
customAddressableRemoteURL = customUrl;
|
||||
originAddressableRemoteURL = originUrl;
|
||||
Addressables.InternalIdTransformFunc -= DoIdTransform;
|
||||
Addressables.InternalIdTransformFunc += DoIdTransformUsingCustomURL;
|
||||
}
|
||||
|
||||
private const string Remote_Prefix = "http";
|
||||
|
||||
private string DoIdTransformUsingCustomURL(IResourceLocation location)
|
||||
{
|
||||
var id = location.InternalId;
|
||||
if (id.StartsWith(Remote_Prefix))
|
||||
{
|
||||
if (location.ResourceType.IsAssignableFrom(typeof(IAssetBundleResource)))
|
||||
{
|
||||
var primaryKey = location.PrimaryKey;
|
||||
if (BetterStreamingAssets.FileExists(primaryKey))
|
||||
return Path.Combine(Application.streamingAssetsPath, primaryKey);
|
||||
}
|
||||
id = id.Replace(originAddressableRemoteURL, customAddressableRemoteURL);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private string DoIdTransform(IResourceLocation location)
|
||||
{
|
||||
var id = location.InternalId;
|
||||
if (id.StartsWith(Remote_Prefix))
|
||||
{
|
||||
if (location.ResourceType.IsAssignableFrom(typeof(IAssetBundleResource)))
|
||||
{
|
||||
var primaryKey = location.PrimaryKey;
|
||||
if (BetterStreamingAssets.FileExists(primaryKey))
|
||||
return Path.Combine(Application.streamingAssetsPath, primaryKey);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void ExitGame()
|
||||
{
|
||||
PlayerPrefs.Save();
|
||||
Application.runInBackground = false;
|
||||
|
||||
if (Application.platform == RuntimePlatform.Android)
|
||||
{
|
||||
// Calling Application.Quit on some devices will cause ANR, so
|
||||
// directly calling system action instead
|
||||
try
|
||||
{
|
||||
new AndroidJavaClass("java.lang.System").CallStatic("exit", 0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[GameStateMgr]ExitGame: {ex}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool showFPS = false;
|
||||
public static float fps;
|
||||
private static float frameCount;
|
||||
private static float elapse;
|
||||
private GUIStyle _fpsStyle;
|
||||
public GUIStyle fpsStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fpsStyle == null)
|
||||
{
|
||||
int h = Screen.height;
|
||||
_fpsStyle = new GUIStyle();
|
||||
_fpsStyle.alignment = TextAnchor.UpperLeft;
|
||||
_fpsStyle.fontSize = h * 2 / 100;
|
||||
_fpsStyle.normal.textColor = Color.magenta;
|
||||
}
|
||||
return _fpsStyle;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
frameCount++;
|
||||
elapse += Time.unscaledDeltaTime;
|
||||
if (elapse >= 1)
|
||||
{
|
||||
fps = frameCount / elapse;
|
||||
elapse = 0;
|
||||
frameCount = 0;
|
||||
}
|
||||
if (!showFPS) return;
|
||||
|
||||
string text = string.Format("FPS: {0:0.}", fps);
|
||||
int w = Screen.width, h = Screen.height;
|
||||
Rect rect = new Rect(20, h * 0.4f, w * 0.5f, h * 2 / 100);
|
||||
GUI.Label(rect, text, fpsStyle);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
Debug.Log("[RootCtx::OnDestroy]");
|
||||
base.OnDestroy();
|
||||
Addressables.InternalIdTransformFunc = null;
|
||||
Application.lowMemory -= OnLowMemory;
|
||||
root = null;
|
||||
Ready = false;
|
||||
IsInited = false;
|
||||
eventAggregator = new EventAggregator();
|
||||
container.Dispose();
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
public static void DestoryRootCtx()
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(root.gameObject);
|
||||
root = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/AOTScripts/RootCtx.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/RootCtx.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae9c8daf5f84ae74fadaa7da5289caeb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
188
Assets/Scripts/AOTScripts/SimpleDialog.cs
Normal file
188
Assets/Scripts/AOTScripts/SimpleDialog.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
public class SimpleDialog : MonoBehaviour
|
||||
{
|
||||
public class Context
|
||||
{
|
||||
public Action okAction;
|
||||
public Action closeAction;
|
||||
public string message;
|
||||
|
||||
public string message2;
|
||||
public string formatMessage;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Button btn_ok;
|
||||
|
||||
[SerializeField]
|
||||
private Button btn_close;
|
||||
|
||||
[SerializeField]
|
||||
TMP_Text message;
|
||||
|
||||
[SerializeField]
|
||||
TMP_Text message2;
|
||||
|
||||
public string DefaultMessage {get; private set;}
|
||||
|
||||
private Action onOk;
|
||||
|
||||
private Action onClose;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if(message != null)
|
||||
{
|
||||
DefaultMessage = message.text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
btn_ok.onClick.AddListener(OnOkClicked);
|
||||
|
||||
if(btn_close != null)
|
||||
btn_close.onClick.AddListener(OnCloseClicked);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
btn_ok.onClick.RemoveAllListeners();
|
||||
|
||||
if(btn_close != null)
|
||||
btn_close.onClick.RemoveAllListeners();
|
||||
}
|
||||
|
||||
public async void Config(Context context)
|
||||
{
|
||||
this.onOk = context.okAction;
|
||||
this.onClose = context.closeAction;
|
||||
|
||||
gameObject.SetActive(true);
|
||||
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
if(message != null)
|
||||
{
|
||||
message.text = context.message;
|
||||
}
|
||||
|
||||
if(message2!=null)
|
||||
{
|
||||
message2.text = context.message2;;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCloseClicked()
|
||||
{
|
||||
onClose?.Invoke();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnOkClicked()
|
||||
{
|
||||
onOk?.Invoke();
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
private void Close()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
if(message != null) message.text = DefaultMessage;
|
||||
onOk = null;
|
||||
onClose = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public class SimpleDialog : MonoBehaviour
|
||||
{
|
||||
public class Context
|
||||
{
|
||||
public string title;
|
||||
public string message;
|
||||
public string okBtnText;
|
||||
public Action okAction;
|
||||
public Action closeAction;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Text tile;
|
||||
|
||||
[SerializeField]
|
||||
private Text message;
|
||||
|
||||
[SerializeField]
|
||||
private Button btn_ok;
|
||||
|
||||
[SerializeField]
|
||||
private Text btn_ok_text;
|
||||
|
||||
[SerializeField]
|
||||
private Button btn_close;
|
||||
|
||||
private Action onOk;
|
||||
|
||||
private Action onClose;
|
||||
|
||||
private string defaultOkBtnText;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
defaultOkBtnText = btn_ok_text.text;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
btn_ok.onClick.AddListener(OnOkClicked);
|
||||
btn_close.onClick.AddListener(OnCloseClicked);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
btn_ok.onClick.RemoveAllListeners();
|
||||
btn_close.onClick.RemoveAllListeners();
|
||||
}
|
||||
|
||||
public void Config(Context context)
|
||||
{
|
||||
this.tile.text = context.title ?? string.Empty;
|
||||
this.message.text = context.message ?? string.Empty;
|
||||
this.btn_ok_text.text = context.okBtnText ?? defaultOkBtnText;
|
||||
this.onOk = context.okAction;
|
||||
this.onClose = context.closeAction;
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnCloseClicked()
|
||||
{
|
||||
onClose?.Invoke();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnOkClicked()
|
||||
{
|
||||
onOk?.Invoke();
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
private void Close()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
tile.text = string.Empty;
|
||||
message.text = string.Empty;
|
||||
btn_ok_text.text = defaultOkBtnText;
|
||||
onOk = null;
|
||||
onClose = null;
|
||||
}
|
||||
}
|
||||
*/
|
||||
11
Assets/Scripts/AOTScripts/SimpleDialog.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/SimpleDialog.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ae19f17d9371654aa05c9db637f326c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
100
Assets/Scripts/AOTScripts/VersionTool.cs
Normal file
100
Assets/Scripts/AOTScripts/VersionTool.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
public class VersionTool : IComparable<VersionTool>
|
||||
{
|
||||
public const string Build_Ver_File_Name = "buildver.txt";
|
||||
public static string PackVer
|
||||
{
|
||||
get
|
||||
{
|
||||
string[] splitVersion = Application.version.Split('.');
|
||||
return $"{splitVersion[0]}_{splitVersion[1]}";
|
||||
}
|
||||
}
|
||||
|
||||
public int Major { get; private set; }
|
||||
public int Minor { get; private set; }
|
||||
public string Build { get; private set; }
|
||||
|
||||
private VersionTool(int major, int minor, string build)
|
||||
{
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
Build = build;
|
||||
}
|
||||
|
||||
public static VersionTool FromString(string version)
|
||||
{
|
||||
string[] splitVersion = version.Split('.');
|
||||
return new VersionTool(int.Parse(splitVersion[0]), int.Parse(splitVersion[1]), splitVersion[2]);
|
||||
}
|
||||
|
||||
public static VersionTool FromLocal()
|
||||
{
|
||||
string appVerStr = Application.version;
|
||||
string [] splitVersion = appVerStr.Split('.');
|
||||
return new VersionTool(int.Parse(splitVersion[0]), int.Parse(splitVersion[1]), GetLoacalBuild());
|
||||
}
|
||||
|
||||
private static string GetLoacalBuild()
|
||||
{
|
||||
var persisterBVerFile = $"{Application.persistentDataPath}/{Build_Ver_File_Name}";
|
||||
if(File.Exists(persisterBVerFile))
|
||||
{
|
||||
return File.ReadAllText(persisterBVerFile);
|
||||
}
|
||||
if (BetterStreamingAssets.FileExists(Build_Ver_File_Name))
|
||||
return BetterStreamingAssets.ReadAllText(Build_Ver_File_Name);
|
||||
return "None";
|
||||
}
|
||||
|
||||
public int CompareTo(VersionTool other)
|
||||
{
|
||||
int result = Major.CompareTo(other.Major);
|
||||
if (result == 0)
|
||||
{
|
||||
result = Minor.CompareTo(other.Minor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool operator >(VersionTool a, VersionTool b)
|
||||
{
|
||||
return a.CompareTo(b) > 0;
|
||||
}
|
||||
|
||||
public static bool operator <(VersionTool a, VersionTool b)
|
||||
{
|
||||
return a.CompareTo(b) < 0;
|
||||
}
|
||||
public static bool operator ==(VersionTool a, VersionTool b)
|
||||
{
|
||||
return a.CompareTo(b) == 0;
|
||||
}
|
||||
|
||||
public static bool operator !=(VersionTool a, VersionTool b)
|
||||
{
|
||||
return a.CompareTo(b) !=0 ;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Ver {Major}_{Minor}_{Build}";
|
||||
}
|
||||
|
||||
public string ToVerString()
|
||||
{
|
||||
Debug.Log($"{Major}.{Minor}.{Build}");
|
||||
return $"{Major}.{Minor}.{Build}";
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
var persisterBVerFile = $"{Application.persistentDataPath}/{Build_Ver_File_Name}";
|
||||
File.Delete(persisterBVerFile);
|
||||
File.WriteAllText(persisterBVerFile, Build);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/AOTScripts/VersionTool.cs.meta
Normal file
11
Assets/Scripts/AOTScripts/VersionTool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fa0017cbacf37549a4e495f0b108567
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user