备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c70943931a9d4d4c89d8f687378f5f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca9397553a1e24044ae5e118b50c5c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dbaf5fb72da8a6f4cb1dd6f29cd60b86
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39873ea9f0d504546ab58d2ae5d178fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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];
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2b4a2cd74aff68448085a1c9b5f568a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
public class CertHandler : UnityEngine.Networking.CertificateHandler
{
protected override bool ValidateCertificate(byte[] certificateData)
{
return true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7269d611fae2410885300a7755f4c11
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f6b7f8a5010f4daa82832584171069f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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"
};
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ba3f3f5ca3183a419aa7fd179b03a67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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));
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86c1a73af4778472a9e7fb25ed9adf54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1d3fb87095f0ab4dbc5770f5baced06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1806ed8053370f14d900347897ef8b5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a3bc0fefcb6449c2961668d6a7a1f9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b9bd5b8b9de24984593b2cb1f1aab54e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae9c8daf5f84ae74fadaa7da5289caeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
*/

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ae19f17d9371654aa05c9db637f326c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fa0017cbacf37549a4e495f0b108567
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: