备份CatanBuilding瘦身独立工程
This commit is contained in:
242
Assets/Scripts/Services/AggAdsService.cs
Normal file
242
Assets/Scripts/Services/AggAdsService.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
|
||||
using asap.core;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using UniRx;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class AdsResult
|
||||
{
|
||||
public AdvertPopupType Type;
|
||||
/// <summary>
|
||||
/// //0-成功 1-失败 2 -点击 3-关闭
|
||||
/// </summary>
|
||||
public int Result;
|
||||
}
|
||||
|
||||
public enum AdvertPopupType
|
||||
{
|
||||
None = 0,
|
||||
Shop = 1,
|
||||
Turntable = 2,
|
||||
Showdown = 3,
|
||||
FishingFail = 4,
|
||||
Chest = 5,
|
||||
Aquarium = 6,
|
||||
}
|
||||
public class AggAdsService : IAdsService
|
||||
{
|
||||
|
||||
#if UNITY_IOS
|
||||
private static string AD_Unit_ID = "ec3c8fd688cdb5e2";
|
||||
#else
|
||||
private static string AD_Unit_ID = "c6c49a100de8496c";
|
||||
#endif
|
||||
private static AdvertPopupType currentADType = AdvertPopupType.None;
|
||||
|
||||
private static int retryTime = 0;
|
||||
|
||||
private ISettingService settings;
|
||||
CompositeDisposable disposables;
|
||||
public AggAdsService(ISettingService settings)
|
||||
{
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
|
||||
#if UNITY_IOS
|
||||
MaxSdkiOS.SetExtraParameter("disable_audio_session" , "true");
|
||||
#endif
|
||||
MaxSdkCallbacks.OnSdkInitializedEvent += (MaxSdkBase.SdkConfiguration sdkConfiguration) =>
|
||||
{
|
||||
UnityEngine.Debug.Log($"[MaxSdk::OnSdkInitializedEvent] Init:{sdkConfiguration.IsSuccessfullyInitialized}");
|
||||
};
|
||||
|
||||
IConfig config = GContext.container.Resolve<IConfig>();
|
||||
|
||||
bool debug = !string.IsNullOrEmpty(config.Get("DEBUG", string.Empty));
|
||||
|
||||
MaxSdk.SetVerboseLogging(debug);
|
||||
|
||||
MaxSdk.InitializeSdk();
|
||||
|
||||
MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnRewardedAdLoadedEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnRewardedAdLoadFailedEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdDisplayedEvent += OnRewardedAdDisplayedEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdClickedEvent += OnRewardedAdClickedEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdRevenuePaidEvent += OnRewardedAdRevenuePaidEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdHiddenEvent += OnRewardedAdHiddenEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdDisplayFailedEvent += OnRewardedAdFailedToDisplayEvent;
|
||||
MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnRewardedAdReceivedRewardEvent;
|
||||
|
||||
// levl 40 , first build scene completed
|
||||
disposables?.Dispose();
|
||||
disposables = new CompositeDisposable();
|
||||
RootCtx.OnEvent<OnLvChangeEvent>()
|
||||
.Where(evt => evt.lvl >= 40)
|
||||
.Subscribe(OnLevelChange)
|
||||
.AddTo(disposables);
|
||||
RootCtx.OnEvent<ExchangeFishCount>()
|
||||
.Where(evt => evt.FishCount >= 17)
|
||||
.Subscribe(OnExchangeFishCount)
|
||||
.AddTo(disposables);
|
||||
// Load AD after 40 Lvl
|
||||
//if (!MaxSdk.IsRewardedAdReady(AD_Unit_ID))
|
||||
//{
|
||||
//MaxSdk.LoadRewardedAd(AD_Unit_ID);
|
||||
|
||||
//using (var e = GEvent.GameEvent("ad_request")) { }
|
||||
//}
|
||||
}
|
||||
|
||||
public void ShowRewarded(AdvertPopupType advertPopupType = AdvertPopupType.Shop)
|
||||
{
|
||||
if (advertPopupType == AdvertPopupType.None) return;
|
||||
|
||||
currentADType = advertPopupType;
|
||||
|
||||
using (var e = GEvent.GameEvent("ad_click"))
|
||||
{
|
||||
e.AddContent("ad_placement_id", (int)advertPopupType);
|
||||
}
|
||||
|
||||
if (MaxSdk.IsRewardedAdReady(AD_Unit_ID))
|
||||
{
|
||||
MaxSdk.ShowRewardedAd(AD_Unit_ID, advertPopupType.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
GContext.Publish(new AdsResult() { Result = 1, Type = advertPopupType });
|
||||
|
||||
using (var e = GEvent.GameEvent("ad_show"))
|
||||
{
|
||||
e.AddContent("ad_show_state", 3);
|
||||
e.AddContent("ad_placement_id", (int)currentADType);
|
||||
}
|
||||
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_27"));
|
||||
}
|
||||
}
|
||||
|
||||
private bool loadFired = false;
|
||||
private void OnLevelChange(OnLvChangeEvent evt)
|
||||
{
|
||||
LoadFired();
|
||||
}
|
||||
public void OnExchangeFishCount(ExchangeFishCount evt)
|
||||
{
|
||||
LoadFired();
|
||||
}
|
||||
void LoadFired()
|
||||
{
|
||||
if (!loadFired && !MaxSdk.IsRewardedAdReady(AD_Unit_ID))
|
||||
{
|
||||
disposables?.Dispose();
|
||||
disposables = null;
|
||||
loadFired = true;
|
||||
MaxSdk.LoadRewardedAd(AD_Unit_ID);
|
||||
|
||||
using (var e = GEvent.GameEvent("ad_request")) { }
|
||||
}
|
||||
}
|
||||
private void ChangeAudio(bool adShowing)
|
||||
{
|
||||
ISoundService soundService = GContext.container.Resolve<ISoundService>();
|
||||
ISettingService settingService = GContext.container.Resolve<ISettingService>();
|
||||
|
||||
int vol = adShowing ? 0 : 80;
|
||||
|
||||
if (soundService != null && settingService != null)
|
||||
{
|
||||
if (settingService.Music)
|
||||
{
|
||||
soundService.BGMVol = vol;
|
||||
}
|
||||
|
||||
if (settingService.Sound)
|
||||
{
|
||||
soundService.SFXVol = vol;
|
||||
soundService.VoiceVol = vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region AppLovin Callbacks
|
||||
|
||||
private void OnRewardedAdLoadedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
retryTime = 0;
|
||||
|
||||
using (var e = GEvent.GameEvent("ad_response"))
|
||||
{
|
||||
e.AddContent("ad_loading", 1);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnRewardedAdLoadFailedEvent(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
|
||||
{
|
||||
using (var e = GEvent.GameEvent("ad_response"))
|
||||
{
|
||||
e.AddContent("ad_loading", 0);
|
||||
}
|
||||
retryTime++;
|
||||
int retryDelay = Math.Min(6, retryTime) * 2000;
|
||||
UnityEngine.Debug.LogWarning($"[AggAdsService] OnRewardedAdLoadFailedEvent retry {retryDelay}, {adUnitId}, {errorInfo}");
|
||||
await Task.Delay(retryDelay);
|
||||
MaxSdk.LoadRewardedAd(adUnitId);
|
||||
using (var e = GEvent.GameEvent("ad_request")) { }
|
||||
}
|
||||
|
||||
private void OnRewardedAdDisplayedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
using (var e = GEvent.GameEvent("ad_show"))
|
||||
{
|
||||
e.AddContent("ad_show_state", 1);
|
||||
e.AddContent("ad_placement_id", (int)currentADType);
|
||||
}
|
||||
|
||||
ChangeAudio(true);
|
||||
}
|
||||
|
||||
private void OnRewardedAdFailedToDisplayEvent(string adUnitId, MaxSdkBase.ErrorInfo errorInfo, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
// Rewarded ad failed to display. AppLovin recommends that you load the next ad.
|
||||
GContext.Publish(new AdsResult() { Result = 1, Type = currentADType });
|
||||
MaxSdk.LoadRewardedAd(adUnitId);
|
||||
|
||||
using (var e = GEvent.GameEvent("ad_show"))
|
||||
{
|
||||
e.AddContent("ad_show_state", 2);
|
||||
e.AddContent("ad_placement_id", (int)currentADType);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRewardedAdClickedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo) { }
|
||||
|
||||
private void OnRewardedAdHiddenEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
// Rewarded ad is hidden. Pre-load the next ad
|
||||
MaxSdk.LoadRewardedAd(adUnitId);
|
||||
|
||||
ChangeAudio(false);
|
||||
}
|
||||
|
||||
private void OnRewardedAdReceivedRewardEvent(string adUnitId, MaxSdk.Reward reward, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
GContext.Publish(new AdsResult() { Result = 0, Type = currentADType });
|
||||
}
|
||||
|
||||
private void OnRewardedAdRevenuePaidEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||
{
|
||||
GEvent.ADRevenueEvent(adUnitId, adInfo);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
Assets/Scripts/Services/AggAdsService.cs.meta
Normal file
11
Assets/Scripts/Services/AggAdsService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab900dd213036d3408079ca02fc59b40
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
447
Assets/Scripts/Services/AggIAPService.cs
Normal file
447
Assets/Scripts/Services/AggIAPService.cs
Normal file
@@ -0,0 +1,447 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
using UnityEngine;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using UnityEngine.Networking;
|
||||
using System.Threading;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class AggIAPService : IIAPService
|
||||
{
|
||||
[Inject] public IUserService userService { get; set; }
|
||||
[Inject] public IConfig config { get; set; }
|
||||
[Inject] public ICustomServerMgr svr { get; set; }
|
||||
|
||||
public void Init() { }
|
||||
|
||||
public void Release() { }
|
||||
|
||||
|
||||
#if UNITY_ANDROID
|
||||
private const string payment = "google";
|
||||
#else
|
||||
private const string payment = "apple";
|
||||
#endif
|
||||
|
||||
class IAPConfig
|
||||
{
|
||||
public bool Active { get; set; }
|
||||
public string OrderSvrUrl { get; set; }
|
||||
public string FuncKey { get; set; }
|
||||
}
|
||||
|
||||
|
||||
private async Task<IAPConfig> BeforePurch()
|
||||
{
|
||||
var configRemoteUrl = config.Get<string>(GConstant.K_Static_Res_URL, GConstant.V_Static_Res_URL);
|
||||
string iapConfigUrl = null;
|
||||
//var encrypted = false;
|
||||
|
||||
if (configRemoteUrl == GConstant.V_Static_Res_URL)
|
||||
{
|
||||
iapConfigUrl = String.Format(configRemoteUrl, $"{Application.platform}iapcfg.json");
|
||||
//encrypted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
iapConfigUrl = configRemoteUrl.Replace(VersionTool.PackVer, $"{Application.platform}iapcfg.json");
|
||||
}
|
||||
|
||||
var timeoutValues = new float[]{1,2,4};
|
||||
var maxRetryTimes = timeoutValues.Length;
|
||||
|
||||
for (int retryTime = 0; retryTime < maxRetryTimes; retryTime++)
|
||||
{
|
||||
var iapConfig = await DoGetRawConfig(iapConfigUrl,timeoutValues[retryTime], retryTime, maxRetryTimes);
|
||||
if (iapConfig != null )
|
||||
{
|
||||
Debug.Log($"<color=orange>Load iapConfig success {retryTime + 1}/{maxRetryTimes}</color>");
|
||||
return iapConfig;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private async Task<IAPConfig> DoGetRawConfig(string url, float timeoutInSec, int retryTimes, int maxRetryTimes)
|
||||
{
|
||||
using(var req = UnityWebRequest.Get(url))
|
||||
{
|
||||
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)
|
||||
{
|
||||
var decryptKey = "tbambooz";
|
||||
|
||||
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
|
||||
des.Key = Encoding.ASCII.GetBytes(decryptKey);
|
||||
des.IV = Encoding.ASCII.GetBytes(decryptKey);
|
||||
var rawCfg = req.downloadHandler.text;
|
||||
|
||||
ICryptoTransform decryptor = des.CreateDecryptor(des.Key, des.IV);
|
||||
byte[] inputBytes = Convert.FromBase64String(rawCfg);
|
||||
byte[] outputBytes = decryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
|
||||
rawCfg = Encoding.UTF8.GetString(outputBytes);
|
||||
var iapConfig = JsonConvert.DeserializeObject<IAPConfig>(rawCfg);
|
||||
Debug.Log($"[AggIAPService] DoGetRawConfig Success {url}");
|
||||
return iapConfig;
|
||||
}
|
||||
|
||||
#if AGG
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "iap_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 iap 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", "iap_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<IList<SKUDetail>> GetSKUs()
|
||||
{
|
||||
Debug.Log("[AggIAPService] GetSKUList fetch");
|
||||
var prodList = await TYSdkFacade.Instance.GetSKUList();
|
||||
if (prodList.code != 0)
|
||||
{
|
||||
Debug.LogWarning("[AggIAPService] GetSKUList Failed");
|
||||
return null;
|
||||
}
|
||||
Debug.Log($"[AggIAPService] GetSKUList Success prod Num {prodList.products.Count}");
|
||||
return prodList.products;
|
||||
}
|
||||
|
||||
public async Task<PaymentInfo> Pay(Action<string> OnSuccessFromSdk, string replenishmentDataStr, SKUDetail sku, int count, float usdPrice, JObject extraPurcheInfo)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
GameCore.UIManager.ShowWaitingBlock("AggIAPService::Pay");
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
//======= check iap config
|
||||
var iapCfg = await BeforePurch();
|
||||
if (iapCfg == null)
|
||||
{
|
||||
Debug.LogWarning("Fetch iap cfg fail");
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
SendRechargeEvent(sku, usdPrice, "iapcfg_fail", extraPurcheInfo, count);
|
||||
return new PaymentInfo() { code = "10002" };
|
||||
}
|
||||
else if (!iapCfg.Active)
|
||||
{
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
return new PaymentInfo() { code = "10001" };
|
||||
}
|
||||
//===== check iap config end======
|
||||
|
||||
RTServiceBgFgManager.keepAlive = true;
|
||||
SendRechargeEvent(sku, usdPrice, "start", extraPurcheInfo, count);
|
||||
|
||||
var purchaseInfo = new JObject();
|
||||
purchaseInfo["ver"] = 3;
|
||||
purchaseInfo["pfid"] = userService.UserId;
|
||||
purchaseInfo["sum"] = usdPrice * count;
|
||||
purchaseInfo["customData"] = replenishmentDataStr;
|
||||
|
||||
PaymentInfo paymentInfo = await TYSdkFacade.Instance.Pay(sku, count, usdPrice, purchaseInfo);
|
||||
|
||||
if (!paymentInfo.isSuccessFromSdk)
|
||||
{
|
||||
SendRechargeEvent(sku, usdPrice, "fail", extraPurcheInfo, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnSuccessFromSdk(paymentInfo.orderId);
|
||||
await WaitForSvrOrder(paymentInfo, sku, usdPrice, count, extraPurcheInfo, iapCfg);
|
||||
}
|
||||
|
||||
if (paymentInfo.isSuccess)
|
||||
{
|
||||
await ConfirmOrder(paymentInfo, iapCfg);
|
||||
}
|
||||
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
RTServiceBgFgManager.keepAlive = false;
|
||||
return paymentInfo;
|
||||
}
|
||||
|
||||
private async Task WaitForSvrOrder(PaymentInfo paymentInfo, SKUDetail sku, float usdPrice, int count, JObject extraPurcheInfo, IAPConfig iapCfg)
|
||||
{
|
||||
Debug.Log("[AggIAPService] WaitForSvrOrder");
|
||||
await Awaiters.Seconds(2);
|
||||
|
||||
var startTime = ZZTimeHelper.UtcNow();
|
||||
|
||||
var confirmEvt = new CS_OrderConfirmEvt()
|
||||
{
|
||||
orderId = paymentInfo.orderId,
|
||||
sdkUserId = userService.CustomId
|
||||
}.ToJson();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var result = await IAPPost("csconfirm", iapCfg, confirmEvt);
|
||||
|
||||
Debug.Log("[AggIAPService] WaitForSvrOrder request done");
|
||||
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
|
||||
Debug.Log($"[AggIAPService] WaitForSvrOrder respon {result}");
|
||||
|
||||
var sconfirmEvt = JsonConvert.DeserializeObject<SC_OrderConfirmEvt>(result);
|
||||
|
||||
if (sconfirmEvt.isSuccess)
|
||||
{
|
||||
if (paymentInfo.Check(sconfirmEvt.orderId, sconfirmEvt.productId))
|
||||
{
|
||||
SendRevenueEvent(sku, usdPrice, paymentInfo.orderId, extraPurcheInfo, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendRechargeEvent(sku, usdPrice, "checkfail", extraPurcheInfo, paymentInfo.count);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[AggIAPService] WaitForSvrOrder request error");
|
||||
}
|
||||
|
||||
await Awaiters.Seconds(2);
|
||||
|
||||
if (ZZTimeHelper.UtcNow() - startTime > TimeSpan.FromSeconds(50))
|
||||
{
|
||||
SendRechargeEvent(sku, usdPrice, "timeout", extraPurcheInfo, paymentInfo.count);
|
||||
|
||||
Debug.Log("[AggIAPService] WaitForSvrOrder timeout");
|
||||
break;
|
||||
}
|
||||
|
||||
Debug.Log("[AggIAPService] WaitForSvrOrder retry");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ConfirmOrder(PaymentInfo paymentInfo, IAPConfig iapCfg)
|
||||
{
|
||||
var confirmEvt = new CS_OrderConfirmEvt()
|
||||
{
|
||||
orderId = paymentInfo.orderId,
|
||||
sdkUserId = userService.CustomId
|
||||
}.ToJson();
|
||||
int count = 3;
|
||||
string result;
|
||||
bool re = false;
|
||||
while (count > 0)
|
||||
{
|
||||
count--;
|
||||
result = await IAPPost("receive", iapCfg, confirmEvt);
|
||||
if (bool.TryParse(result, out re) && re)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!re)
|
||||
{
|
||||
paymentInfo.code = "10000";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取未领奖的订单号列表 时间戳
|
||||
/// </summary>
|
||||
/// <param name="day">时间戳 最早订单时间 -1m</param>
|
||||
/// <returns></returns>
|
||||
public async Task<Dictionary<string, string>> GetOrderUnreceived()
|
||||
{
|
||||
var iapCfg = await BeforePurch();
|
||||
|
||||
if (iapCfg == null)
|
||||
{
|
||||
Debug.LogError("Fetch iap cfg fail, on get unreceive order ");
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
var orderUnreceived = new CS_OrderUnreceived()
|
||||
{
|
||||
sdkUserId = userService.CustomId,
|
||||
customData = true
|
||||
}.ToJson();
|
||||
|
||||
string result = await IAPPost("unreceive", iapCfg, orderUnreceived);
|
||||
|
||||
if (string.IsNullOrEmpty(result) || result == "[]")
|
||||
{
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_OrderUnreceived response = JsonConvert.DeserializeObject<SC_OrderUnreceived>(result);
|
||||
return response?.orders;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> ConfirmOrders(List<string> orderIDs)
|
||||
{
|
||||
if (orderIDs == null || orderIDs.Count == 0) return false;
|
||||
|
||||
var confirmEvt = new CS_OrdersConfirmEvt()
|
||||
{
|
||||
orderIds = orderIDs,
|
||||
sdkUserId = userService.CustomId
|
||||
}.ToJson();
|
||||
var iapCfg = await BeforePurch();
|
||||
if (iapCfg == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string result = await IAPPost("receiveorders", iapCfg, confirmEvt);
|
||||
if (string.IsNullOrEmpty(result) || result == "[]" || !bool.TryParse(result, out bool re))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SendRechargeEvent(SKUDetail sku, float usdPrice, string state, JObject extraPurcheInfo, int count = 1)
|
||||
{
|
||||
using (var e = GEvent.TackEvent("recharge_state"))
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("payment_state", state)
|
||||
.AddContent(AFInAppEvents.QUANTITY, count);
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendRevenueEvent(SKUDetail sku, float usdPrice, string orderId, JObject extraPurcheInfo, int count = 1)
|
||||
{
|
||||
using (var e = GEvent.RevenueEvent())
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent(AFInAppEvents.QUANTITY, 1)
|
||||
.AddContent("order_id", orderId)
|
||||
.AddContent("restore", false)
|
||||
.AddContent("payment_state", "finish")
|
||||
.AddContent("af_revenue", sku.ProdPrice * count);
|
||||
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task<string> IAPPost(string route, IAPConfig iapCfg, string bodyString)
|
||||
{
|
||||
var apiurl = config.Get<string>(GConstant.K_Event_API_URL, iapCfg.OrderSvrUrl);
|
||||
if (apiurl == iapCfg.OrderSvrUrl)
|
||||
{
|
||||
|
||||
return await svr.CustomServerPost($"order/{route}", bodyString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.BaseAddress = new System.Uri(iapCfg.OrderSvrUrl);
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||
httpClient.DefaultRequestHeaders.Add("x-functions-key", iapCfg.FuncKey);
|
||||
|
||||
try
|
||||
{
|
||||
var content = new StringContent(bodyString, Encoding.UTF8, "application/json");
|
||||
var response = await httpClient.PostAsync(route, content);
|
||||
string result = await response.Content.ReadAsStringAsync();
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"iap post fail {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Debug.LogError($"iap post fail {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/AggIAPService.cs.meta
Normal file
11
Assets/Scripts/Services/AggIAPService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2974f9c965fe43c468e91d1fbc2d24fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
286
Assets/Scripts/Services/AggRTIAPService.cs
Normal file
286
Assets/Scripts/Services/AggRTIAPService.cs
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
using UnityEngine;
|
||||
using UniRx;
|
||||
using System.Threading;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class AggIAPRTService : IIAPService
|
||||
{
|
||||
[Inject] public IUserService userService { get; set; }
|
||||
[Inject] public IConfig config { get; set; }
|
||||
[Inject] public IRTService rts { get; set; }
|
||||
[Inject] public ICustomServerMgr svr { get; set; }
|
||||
|
||||
private TaskCompletionSource<SC_OrderConfirmEvt> orderConfirmTask;
|
||||
private IDisposable orderCompletedDisposable;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Release();
|
||||
orderCompletedDisposable = rts.OnEvent<SC_OrderConfirmEvt>(OnOrderCompleted);
|
||||
Debug.Log("[AggIAPService] inited SC_OrderConfirmEvt subscription");
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
orderCompletedDisposable?.Dispose();
|
||||
orderCompletedDisposable = null;
|
||||
orderConfirmTask = null;
|
||||
}
|
||||
|
||||
private void OnOrderCompleted(SC_OrderConfirmEvt evt)
|
||||
{
|
||||
Debug.Log($"[AggIAPService] OnOrderCompleted \r\n {evt}");
|
||||
if (orderConfirmTask != null)
|
||||
{
|
||||
orderConfirmTask.SetResult(evt);
|
||||
orderConfirmTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_ANDROID
|
||||
private const string payment = "google";
|
||||
#else
|
||||
private const string payment = "apple";
|
||||
#endif
|
||||
|
||||
public async Task<IList<SKUDetail>> GetSKUs()
|
||||
{
|
||||
Debug.Log("[AggIAPService] GetSKUList fetch");
|
||||
var prodList = await TYSdkFacade.Instance.GetSKUList();
|
||||
if (prodList.code != 0)
|
||||
{
|
||||
Debug.LogWarning("[AggIAPService] GetSKUList Failed");
|
||||
return null;
|
||||
}
|
||||
Debug.Log($"[AggIAPService] GetSKUList Success prod Num {prodList.products.Count}");
|
||||
return prodList.products;
|
||||
}
|
||||
|
||||
public async Task<PaymentInfo> Pay(Action<string> OnSuccessFromSdk,string replenishmentDataStr, SKUDetail sku, int count, float usdPrice, JObject extraPurcheInfo)
|
||||
{
|
||||
if (!rts.IsConnected)
|
||||
{
|
||||
GameCore.UIManager.ShowWaitingBlock("AggIAPService::Pay");
|
||||
try
|
||||
{
|
||||
await rts.Connect();
|
||||
}
|
||||
catch {
|
||||
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
}
|
||||
|
||||
using (var e = GEvent.TackEvent("recharge_state"))
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("payment_state", "disconnected")
|
||||
.AddContent(AFInAppEvents.QUANTITY, count);
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Awaiters.Seconds(3);
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
return new PaymentInfo() { code = "-1", msg = "连接失败" };
|
||||
}
|
||||
|
||||
using (var e = GEvent.TackEvent("recharge_state"))
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("payment_state", "start")
|
||||
.AddContent(AFInAppEvents.QUANTITY, count);
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var purchaseInfo = new JObject();
|
||||
purchaseInfo["ver"] = 1;
|
||||
purchaseInfo["pfid"] = userService.UserId;
|
||||
purchaseInfo["sum"] = usdPrice * count;
|
||||
purchaseInfo["customData"] = replenishmentDataStr;
|
||||
|
||||
orderConfirmTask = new TaskCompletionSource<SC_OrderConfirmEvt>();
|
||||
|
||||
PaymentInfo paymentInfo = await TYSdkFacade.Instance.Pay(sku, count, usdPrice, purchaseInfo);
|
||||
|
||||
if (!paymentInfo.isSuccessFromSdk)
|
||||
{
|
||||
orderConfirmTask = null;
|
||||
using (var e = GEvent.TackEvent("recharge_state"))
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("payment_state", "fail")
|
||||
.AddContent(AFInAppEvents.QUANTITY, count);
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameCore.UIManager.ShowWaitingBlock("AggIAPService::Pay");
|
||||
Debug.Log("[AggIAPService] Pay sdk Success ");
|
||||
using (var cts = new CancellationTokenSource())
|
||||
{
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(30));
|
||||
cts.Token.Register(() => orderConfirmTask.SetCanceled());
|
||||
try
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
|
||||
UnityEngine.Assertions.Assert.IsTrue(rts.IsConnected, "[AggIAPService] RTService is not connected");
|
||||
var evt = await orderConfirmTask.Task;
|
||||
|
||||
if (evt.isSuccess && paymentInfo.Check(evt.orderId, evt.productId))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
string confirmResult = await rts.Publish("CS_OrderConfirmMessage", userService.CustomId, evt.orderId);
|
||||
if (confirmResult == null || !bool.Parse(confirmResult))
|
||||
{
|
||||
Debug.LogWarning("[AggIAPService] CS_OrderConfirmMessage Failed");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[AggIAPService] Publish CS_OrderConfirmMessage Error {e}");
|
||||
}
|
||||
|
||||
using (var e = GEvent.RevenueEvent())
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("restore", false)
|
||||
.AddContent(AFInAppEvents.QUANTITY, 1)
|
||||
.AddContent("order_id", paymentInfo.orderId)
|
||||
.AddContent("payment_state", "finish")
|
||||
.AddContent("af_revenue", sku.ProdPrice * count);
|
||||
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.LogWarning("[AggIAPService] Pay timeout");
|
||||
if (PlayerPrefs.HasKey(IIAPService.UnConfirmedOrder_key))
|
||||
{
|
||||
var unConfirmedOrders = JArray.Parse(PlayerPrefs.GetString(IIAPService.UnConfirmedOrder_key));
|
||||
unConfirmedOrders.Add(paymentInfo.orderId);
|
||||
PlayerPrefs.SetString(IIAPService.UnConfirmedOrder_key, unConfirmedOrders.ToString());
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
using (var e = GEvent.TackEvent("recharge_state"))
|
||||
{
|
||||
e.AddContent(AFInAppEvents.CONTENT_ID, sku.ProdID)
|
||||
.AddContent(AFInAppEvents.PRICE, usdPrice)
|
||||
.AddContent(AFInAppEvents.CURRENCY, sku.price_currency_code)
|
||||
.AddContent("payment", payment)
|
||||
.AddContent("payment_state", "timeout")
|
||||
.AddContent("orderId", paymentInfo.orderId)
|
||||
.AddContent(AFInAppEvents.QUANTITY, count);
|
||||
if (null != extraPurcheInfo)
|
||||
{
|
||||
foreach (var item in extraPurcheInfo)
|
||||
{
|
||||
e.AddContent(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameCore.UIManager.HideWaitingBlock("AggIAPService::Pay");
|
||||
return paymentInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取未领奖的订单号列表 时间戳
|
||||
/// </summary>
|
||||
/// <param name="day">时间戳 最早订单时间 -1m</param>
|
||||
/// <returns></returns>
|
||||
public async Task<Dictionary<string, string>> GetOrderUnreceived()
|
||||
{
|
||||
var orderUnreceived = new CS_OrderUnreceived()
|
||||
{
|
||||
sdkUserId = userService.CustomId,
|
||||
customData = true
|
||||
}.ToJson();
|
||||
|
||||
string result = await svr.CustomServerPost("order/unreceive", orderUnreceived);
|
||||
|
||||
if (string.IsNullOrEmpty(result) || result == "[]")
|
||||
{
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_OrderUnreceived response = Newtonsoft.Json.JsonConvert.DeserializeObject<SC_OrderUnreceived>(result);
|
||||
return response?.orders;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> ConfirmOrders(List<string> orderIDs)
|
||||
{
|
||||
if (orderIDs == null || orderIDs.Count == 0) return false;
|
||||
|
||||
var confirmEvt = new CS_OrdersConfirmEvt()
|
||||
{
|
||||
orderIds = orderIDs,
|
||||
sdkUserId = userService.CustomId
|
||||
}.ToJson();
|
||||
|
||||
string result = await svr.CustomServerPost("order/receiveorders", confirmEvt);
|
||||
if (string.IsNullOrEmpty(result) || result == "[]" || !bool.TryParse(result, out bool re))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
11
Assets/Scripts/Services/AggRTIAPService.cs.meta
Normal file
11
Assets/Scripts/Services/AggRTIAPService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e12c48a5f26a4e9792443878a60b7d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
219
Assets/Scripts/Services/AggUserService.cs
Normal file
219
Assets/Scripts/Services/AggUserService.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using tysdk;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class LoginTypeEvt
|
||||
{
|
||||
public TaskCompletionSource<EAccoutType> loginType = new TaskCompletionSource<EAccoutType>();
|
||||
}
|
||||
|
||||
public class AggUserService : PlayFabUserService
|
||||
{
|
||||
protected override string NewPlayerName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TYSdkFacade.TYAccountInfo == null)
|
||||
return base.NewPlayerName;
|
||||
if (TYSdkFacade.TYAccountInfo.channel == EAccoutType.hwFacebook
|
||||
|| TYSdkFacade.TYAccountInfo.channel == EAccoutType.hwGoogle)
|
||||
if (!string.IsNullOrEmpty(TYSdkFacade.TYAccountInfo.userName))
|
||||
return TYSdkFacade.TYAccountInfo.userName;
|
||||
|
||||
return base.NewPlayerName;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string NewPlayerAvatar
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TYSdkFacade.TYAccountInfo == null)
|
||||
return base.NewPlayerAvatar;
|
||||
if (TYSdkFacade.TYAccountInfo.channel == EAccoutType.hwFacebook
|
||||
/*|| TYSdkFacade.TYAccountInfo.channel == EAccoutType.hwGoogle*/)
|
||||
if (!string.IsNullOrEmpty(TYSdkFacade.TYAccountInfo.avatar))
|
||||
return TYSdkFacade.TYAccountInfo.avatar;
|
||||
|
||||
return base.NewPlayerAvatar;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<ELoginStep> Login(Action<int> progress)
|
||||
{
|
||||
if (IsLogin)
|
||||
{
|
||||
progress?.Invoke(3);
|
||||
return ELoginStep.Done;
|
||||
}
|
||||
|
||||
UnityEngine.Debug.Log("AggUserService Login");
|
||||
|
||||
|
||||
LoginInfo loginInfo = new LoginInfo();
|
||||
if (!TYSdkFacade.IsLoggedIn)
|
||||
{
|
||||
loginInfo = await TYSdkFacade.Instance.LoginByToken();
|
||||
if (!loginInfo.isSuccess)
|
||||
{
|
||||
var evt = new LoginTypeEvt();
|
||||
GContext.Publish(evt);
|
||||
var loginType = await evt.loginType.Task;
|
||||
loginInfo = await TYSdkFacade.Instance.Login(loginType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loginInfo.isSuccess = true;
|
||||
loginInfo.userId = TYSdkFacade.TYAccountInfo.userId;
|
||||
}
|
||||
|
||||
if (!loginInfo.isSuccess) return ELoginStep.Sdk;
|
||||
|
||||
progress.Invoke(1);
|
||||
|
||||
CustomId = loginInfo.StrUserId;
|
||||
|
||||
|
||||
OnInitData += InitData;
|
||||
|
||||
var step = await base.Login(step => progress?.Invoke(step + 1));
|
||||
if (step != ELoginStep.Done)
|
||||
{
|
||||
OnInitData -= InitData;
|
||||
return step;
|
||||
}
|
||||
|
||||
OnInitData -= InitData;
|
||||
|
||||
GEvent.SetProps(new Dictionary<string, object>(){
|
||||
{"pf_id", UserId},
|
||||
{"CreateTime",CreateTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}
|
||||
});
|
||||
|
||||
GEvent.SetUserProps(new Dictionary<string, object>(){
|
||||
{"pf_id", UserId},
|
||||
{"CreateTime",CreateTime.ToString("yyyy-MM-dd HH:mm:ss")}
|
||||
});
|
||||
|
||||
AvatarToPF(TYSdkFacade.TYAccountInfo);
|
||||
|
||||
GEvent.OnLogin(UserId, CustomId);
|
||||
|
||||
if (config.Get<bool>("NewlyCreated", false))
|
||||
{
|
||||
using (var e = GEvent.CompleteRegistrationEvent())
|
||||
{
|
||||
e.AddContent("login_type", TYSdkFacade.TYAccountInfo.channel.ToString());
|
||||
}
|
||||
|
||||
GEvent.SetProps(new Dictionary<string, object>(){
|
||||
{"vip_level", 0}
|
||||
});
|
||||
|
||||
GEvent.SetUserProps(new Dictionary<string, object>(){
|
||||
{"vip_level", 0},
|
||||
{"total_consumption", 0}
|
||||
});
|
||||
|
||||
if(AFHelper.Instance.GetDLReferer(out var pid, out var uid))
|
||||
{
|
||||
UnityEngine.Debug.Log("[AggUserService] deeplink referer:" + pid + " " + uid);
|
||||
|
||||
using (var e = GEvent.GameEvent("deeplink_invited"))
|
||||
{
|
||||
e.AddContent("referrer_uid", uid);
|
||||
e.AddContent("referrer_pid", pid);
|
||||
}
|
||||
|
||||
var refererData = new Dictionary<string, object>()
|
||||
{
|
||||
{"refererPid", pid},
|
||||
{"refererUid", uid},
|
||||
{"playerUid", CustomId}
|
||||
};
|
||||
|
||||
_ = customServerMgr.CustomServerPost("friend/RecoreReferer",
|
||||
Newtonsoft.Json.JsonConvert.SerializeObject(refererData));
|
||||
}
|
||||
}
|
||||
|
||||
using (var e = GEvent.LoginEvent())
|
||||
{
|
||||
e.AddContent("login_type", TYSdkFacade.TYAccountInfo.channel.ToString());
|
||||
e.AddContent("display_name", DisplayName);
|
||||
e.AddContent("avatar_url", AvatarUrl);
|
||||
e.AddContent("linkedAccout", string.Join('#',TYSdkFacade.TYAccountInfo.linkedAccout));
|
||||
}
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
|
||||
public override void Logout()
|
||||
{
|
||||
TYSdkFacade.Instance.Logout();
|
||||
base.Logout();
|
||||
}
|
||||
|
||||
public override async Task<bool> GetLinkState(EAccoutType accoutType)
|
||||
{
|
||||
return await TYSdkFacade.Instance.LinkCheck(accoutType);
|
||||
}
|
||||
|
||||
public override async Task<bool> LinkAccount(EAccoutType accoutType)
|
||||
{
|
||||
bool result = await TYSdkFacade.Instance.LinkAccount(accoutType);
|
||||
if (result)
|
||||
{
|
||||
var _accountInfo = TYSdkFacade.TYAccountInfo;
|
||||
if (_accountInfo != null)
|
||||
{
|
||||
AvatarToPF(_accountInfo);
|
||||
if (_accountInfo.channel == EAccoutType.hwFacebook)
|
||||
{
|
||||
_ = UpdateAvatarUrl(_accountInfo.avatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InitData(IDictionary<string, string> data)
|
||||
{
|
||||
if (data.TryGetValue(EAccoutType.hwGoogle.ToString(), out var google) && google == "1")
|
||||
{
|
||||
TYSdkFacade.TYAccountInfo.linkedAccout.Add(EAccoutType.hwGoogle);
|
||||
}
|
||||
|
||||
if (data.TryGetValue(EAccoutType.hwFacebook.ToString(), out var facebook) && facebook == "1")
|
||||
{
|
||||
TYSdkFacade.TYAccountInfo.linkedAccout.Add(EAccoutType.hwFacebook);
|
||||
}
|
||||
|
||||
if (data.TryGetValue(EAccoutType.Apple.ToString(), out var apple) && apple == "1")
|
||||
{
|
||||
TYSdkFacade.TYAccountInfo.linkedAccout.Add(EAccoutType.Apple);
|
||||
}
|
||||
|
||||
if(TYSdkFacade.TYAccountInfo.channel != EAccoutType.hwGuest && TYSdkFacade.TYAccountInfo.channel != EAccoutType.none)
|
||||
{
|
||||
var channel = TYSdkFacade.TYAccountInfo.channel.ToString();
|
||||
if(!data.ContainsKey(channel))
|
||||
{
|
||||
data.Add(channel, "1");
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(channel, "1");
|
||||
}
|
||||
}
|
||||
|
||||
if (data.TryGetValue("EAccoutUrl", out var data_value))
|
||||
{
|
||||
EAccoutUrl = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(data_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/AggUserService.cs.meta
Normal file
11
Assets/Scripts/Services/AggUserService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e12eca8163fba954598e4a834f5775d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
137
Assets/Scripts/Services/AvatarService.cs
Normal file
137
Assets/Scripts/Services/AvatarService.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using asap.core;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UniRx;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class GetAvatarDataEvent
|
||||
{
|
||||
public string url;
|
||||
public TaskCompletionSource<Sprite> taskCompletionSource = new TaskCompletionSource<Sprite>();
|
||||
}
|
||||
|
||||
public class AvatarService
|
||||
{
|
||||
Dictionary<int, Sprite> code2Pic = new Dictionary<int, Sprite>();
|
||||
|
||||
public string savePath = Application.persistentDataPath + "/DownloadedImages/"; // 保存到持久化数据路径
|
||||
|
||||
public AvatarService()
|
||||
{
|
||||
|
||||
GContext.OnEvent<GetAvatarDataEvent>().Subscribe(SetAsyncImage);
|
||||
}
|
||||
async void SetAsyncImage(GetAvatarDataEvent data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(data.url))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int code = data.url.GetHashCode();
|
||||
if (!code2Pic.TryGetValue(code, out Sprite sprite))
|
||||
{
|
||||
try
|
||||
{
|
||||
sprite = await DownloadImage(data.url, code);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError("图片不存在,下载出错:" + e.Message + "====" + data.url);
|
||||
sprite = null;
|
||||
}
|
||||
}
|
||||
data.taskCompletionSource.SetResult(sprite);
|
||||
}
|
||||
|
||||
Sprite LoadImage(string path)
|
||||
{
|
||||
// 加载图片
|
||||
Texture2D texture = LoadTextureFromPath(path);
|
||||
|
||||
// 将Texture转换为Sprite
|
||||
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
Texture2D LoadTextureFromPath(string path)
|
||||
{
|
||||
byte[] bytes = File.ReadAllBytes(path);
|
||||
Texture2D texture = new Texture2D(256, 256);
|
||||
texture.LoadImage(bytes);
|
||||
return texture;
|
||||
}
|
||||
async Task<Sprite> DownloadImage(string url, int code)
|
||||
{
|
||||
Sprite m_sprite;
|
||||
if (url.Contains("http"))
|
||||
{
|
||||
// 检查本地是否存在图片
|
||||
string fullPath = Path.Combine(savePath, code.ToString());
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
// 在这里加载并使用本地图片
|
||||
code2Pic[code] = LoadImage(fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(15);
|
||||
HttpResponseMessage response = await client.GetAsync(url);
|
||||
|
||||
byte[] imageBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
|
||||
if (!code2Pic.ContainsKey(code))
|
||||
{
|
||||
Texture2D texture = new Texture2D(256, 256);
|
||||
texture.LoadImage(imageBytes);
|
||||
Texture2D tex2d = texture;
|
||||
m_sprite = Sprite.Create(tex2d, new Rect(0, 0, tex2d.width, tex2d.height), new Vector2(0, 0));
|
||||
code2Pic[code] = m_sprite;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 确保保存路径存在
|
||||
if (!Directory.Exists(savePath))
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
}
|
||||
// 保存纹理为PNG文件
|
||||
File.WriteAllBytes(fullPath, imageBytes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"保存图片时出错: {ex.Message} +++ {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"下载图片时出错: {ex.Message} +++ {ex.StackTrace}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSpriteEvent getSpriteEvent = new GetSpriteEvent(url);
|
||||
GContext.Publish(getSpriteEvent);
|
||||
if (!code2Pic.ContainsKey(code))
|
||||
{
|
||||
code2Pic[code] = getSpriteEvent.sprite;
|
||||
}
|
||||
}
|
||||
|
||||
return code2Pic[code];
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/AvatarService.cs.meta
Normal file
11
Assets/Scripts/Services/AvatarService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8158b30fa076af46ade63ce4077da49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
645
Assets/Scripts/Services/ChatService.cs
Normal file
645
Assets/Scripts/Services/ChatService.cs
Normal file
@@ -0,0 +1,645 @@
|
||||
using asap.core;
|
||||
using com.fpnn;
|
||||
using com.fpnn.rtm;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UniRx;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class ChatQuestProcessor : RTMQuestProcessor
|
||||
{
|
||||
public override void SessionClosed(int ClosedByErrorCode)
|
||||
{
|
||||
Debug.Log("SessionClosed errorCode = " + ClosedByErrorCode);
|
||||
}
|
||||
|
||||
public override bool ReloginWillStart(int lastErrorCode, int retriedCount)
|
||||
{
|
||||
Debug.Log("ReloginWillStart lastErrorCode = " + lastErrorCode + ", retriedCount = " + retriedCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Kickout()
|
||||
{
|
||||
Debug.Log("Kickout");
|
||||
}
|
||||
|
||||
public override void KickoutRoom(long roomId)
|
||||
{
|
||||
Debug.Log("KickoutRoom roomId = " + roomId);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ChatMessage : IComparable<ChatMessage>
|
||||
{
|
||||
public ChatMessage(long messageId, long fromUid, string message, long mtime, long cursorId = 0)
|
||||
{
|
||||
this.messageId = messageId;
|
||||
this.fromUid = fromUid;
|
||||
this.message = message;
|
||||
this.mtime = mtime;
|
||||
this.cursorId = cursorId;
|
||||
}
|
||||
public static ChatMessage ConvertoFromRTMMessage(RTMMessage message)
|
||||
{
|
||||
ChatMessage chatDemoMessage = new ChatMessage(message.messageId, message.fromUid, message.stringMessage, message.modifiedTime);
|
||||
return chatDemoMessage;
|
||||
}
|
||||
|
||||
public static ChatMessage ConvertoFromHistoryMessage(HistoryMessage message)
|
||||
{
|
||||
ChatMessage chatDemoMessage = new ChatMessage(message.messageId, message.fromUid, message.stringMessage, message.modifiedTime, message.cursorId);
|
||||
return chatDemoMessage;
|
||||
}
|
||||
|
||||
public int CompareTo(ChatMessage message)
|
||||
{
|
||||
if (mtime > message.mtime)
|
||||
return 1;
|
||||
else if (mtime < message.mtime)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
if (messageId >= message.messageId)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public long messageId;
|
||||
public long fromUid;
|
||||
public string message;
|
||||
public long mtime;
|
||||
public long cursorId;
|
||||
}
|
||||
|
||||
public class ChatMessageCompare : IEqualityComparer<ChatMessage>
|
||||
{
|
||||
public bool Equals(ChatMessage msg1, ChatMessage msg2)
|
||||
{
|
||||
if (msg1.mtime == msg2.mtime && msg1.messageId == msg2.messageId)
|
||||
{
|
||||
if (msg1.cursorId == msg2.cursorId)
|
||||
return true;
|
||||
else if ((msg1.cursorId == 0 && msg2.cursorId != 0) || (msg1.cursorId != 0 && msg2.cursorId == 0))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetHashCode(ChatMessage msg)
|
||||
{
|
||||
if (msg == null)
|
||||
return 0;
|
||||
else
|
||||
return string.Format("{0}_{1}_{2}", msg.mtime, msg.messageId, msg.message).GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ChatConversation
|
||||
{
|
||||
//public Int32 unreadCount;
|
||||
public Int64 lastMessageTime;
|
||||
//public ChatMessage lastMessage;
|
||||
|
||||
//public void AddMessage(ChatMessage message)
|
||||
//{
|
||||
// if (lastMessage == null)
|
||||
// {
|
||||
// lastMessage = message;
|
||||
// return;
|
||||
// }
|
||||
// if (message.mtime > lastMessage.mtime)
|
||||
// {
|
||||
// lastMessage = message;
|
||||
// return;
|
||||
// }
|
||||
// else if (message.mtime == lastMessage.mtime && lastMessage.messageId > message.messageId)
|
||||
// {
|
||||
// lastMessage = message;
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
public class ChatChatData
|
||||
{
|
||||
public Int64 lastId;
|
||||
public List<ChatMessage> messageList;
|
||||
}
|
||||
|
||||
public class ChatChangeEvent
|
||||
{
|
||||
public bool nextContent;
|
||||
public bool push;
|
||||
}
|
||||
|
||||
public enum ChatType
|
||||
{
|
||||
Text = 1,//文本消息
|
||||
System = 2,//系统内提示
|
||||
System2 = 3,//解锁地图
|
||||
Help = 4,//请求照片
|
||||
Emoji = 5,//发送表情
|
||||
HelpEnergy = 6//请求体力帮助
|
||||
}
|
||||
|
||||
public class ChatService : IChatService
|
||||
{
|
||||
private IUserService userService { get; set; }
|
||||
private IConfig config { get; set; }
|
||||
private int sendInterval = 2;
|
||||
long groupConversationId = 0;
|
||||
RTMClient client;
|
||||
ChatConversation chatConversation;
|
||||
ChatChatData chat;
|
||||
|
||||
public ChatService(IUserService userService, IConfig config, cfg.Tables tables)
|
||||
{
|
||||
this.userService = userService;
|
||||
this.config = config;
|
||||
this.sendInterval = tables.TbGlobalConfig.ClubChatLimitTime;
|
||||
ClientEngine.Init();
|
||||
RTMControlCenter.Init();
|
||||
|
||||
}
|
||||
|
||||
private IDisposable disposable;
|
||||
public void WaitingForLogin()
|
||||
{
|
||||
disposable = RootCtx.OnEvent<EvtAPISvrLoginSuccess>().Subscribe(OnApiSvrLoginSuccess);
|
||||
}
|
||||
|
||||
private async void OnApiSvrLoginSuccess(EvtAPISvrLoginSuccess evt)
|
||||
{
|
||||
disposable.Dispose();
|
||||
int retryCount = 0;
|
||||
while(! await LoginRTM())
|
||||
{
|
||||
retryCount++;
|
||||
await Task.Delay(Math.Min(5000 + retryCount * 1000, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> LoginRTM(int timeout = 5)
|
||||
{
|
||||
|
||||
var userIdLong = userService.InternalId;
|
||||
var pid = long.Parse(config.Get(GConstant.K_RTMP_ID, "80000560"));
|
||||
var rtmServerEndpoint = config.Get(GConstant.K_RTM_Server_Endpoint, "rtm-nx-front.ilivedata.com:13321");
|
||||
var hmacSecret = config.Get(GConstant.K_RTM_Hmac_Secret, "7a1ba6bb85a4473d96fa4bf45b01f1dd");
|
||||
ChatQuestProcessor processor = new ChatQuestProcessor();
|
||||
InitProcessor(processor);
|
||||
client = RTMClient.getInstance(rtmServerEndpoint, pid, userIdLong, processor);
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
|
||||
string token = GetToken(pid, hmacSecret, userIdLong, out long ts);
|
||||
|
||||
client.Login((long pid, long uid, bool successful, int errorCode) =>
|
||||
{
|
||||
if (successful)
|
||||
{
|
||||
taskCompletionSource.SetResult(true);
|
||||
//RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
//{
|
||||
// GetConversationList();
|
||||
//});
|
||||
}
|
||||
else
|
||||
{
|
||||
taskCompletionSource.SetResult(false);
|
||||
Debug.Log("Login failed, errorCode = " + errorCode);
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("ilivedata"))
|
||||
{
|
||||
e.AddContent("connection_failure", errorCode)
|
||||
.AddContent("pid", pid)
|
||||
.AddContent("uid", uid)
|
||||
.AddContent("userIdLong", userIdLong);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}, token, ts, timeout);
|
||||
|
||||
return await(taskCompletionSource.Task);
|
||||
}
|
||||
|
||||
string GetToken(long pid, string hmacSecret, long uid, out long ts)
|
||||
{
|
||||
ts = ClientEngine.GetCurrentSeconds();
|
||||
string text = pid.ToString() + ":" + uid.ToString() + ":" + ts.ToString();
|
||||
|
||||
using (var hmacsha256 = new HMACSHA256(Convert.FromBase64String(hmacSecret)))
|
||||
{
|
||||
var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(text));
|
||||
return Convert.ToBase64String(hash);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<HashSet<long>> GetOnlineUsers(List<long> playerIDs)
|
||||
{
|
||||
HashSet<long> longs = new HashSet<long>();
|
||||
|
||||
if(client?.Status != RTMClient.ClientStatus.Connected)
|
||||
return longs;
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<HashSet<long>>();
|
||||
longs = new HashSet<long>(playerIDs);
|
||||
client.GetOnlineUsers((HashSet<long> uids, int errorCode) =>
|
||||
{
|
||||
if (errorCode == 0)
|
||||
{
|
||||
taskCompletionSource.SetResult(uids);
|
||||
}
|
||||
else
|
||||
{
|
||||
taskCompletionSource.SetResult(null);
|
||||
}
|
||||
}, longs);
|
||||
return await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
public void GetConversationList(long groupConversationId)
|
||||
{
|
||||
this.groupConversationId = groupConversationId;
|
||||
|
||||
if(client?.Status != RTMClient.ClientStatus.Connected)
|
||||
return;
|
||||
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
GetConversationList();
|
||||
});
|
||||
}
|
||||
|
||||
void InitProcessor(ChatQuestProcessor processor)
|
||||
{
|
||||
processor.PushGroupChatCallback = OnPushGroupChat;
|
||||
processor.PushGroupMessageCallback = OnPushGroupMessage;
|
||||
//processor.PushMessageCallback = OnPushGroupMessage;
|
||||
//processor.PushChatCallback = OnPushGroupChat;
|
||||
processor.ReloginCompletedCallback = OnRelogin;
|
||||
}
|
||||
|
||||
void OnPushGroupChat(RTMMessage message)
|
||||
{
|
||||
if (message.toId == groupConversationId)
|
||||
{
|
||||
AddMessage(groupConversationId, true);
|
||||
}
|
||||
//else if (message.toId == userIdLong)
|
||||
//{
|
||||
// //个人聊天列表
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
void OnPushGroupMessage(RTMMessage message)
|
||||
{
|
||||
if (message.toId == groupConversationId)
|
||||
{
|
||||
//主界面推送消息
|
||||
|
||||
}
|
||||
//else if (message.toId == userIdLong)
|
||||
//{
|
||||
// //个人聊天列表
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
void OnRelogin(bool successful, bool retryAgain, int errorCode, int retriedCount)
|
||||
{
|
||||
//Debug.Log("OnRelogin successful = " + successful + " retryAgain = " + retryAgain + ", errorCode = " + errorCode + ", retriedCount = " + retriedCount);
|
||||
if (successful && chatConversation != null)
|
||||
{
|
||||
client?.GetGroupUnreadConversationList((List<Conversation> groupConversationList, int errorCode) =>
|
||||
{
|
||||
if (errorCode == 0)
|
||||
{
|
||||
InitConversationList(groupConversationList);
|
||||
}
|
||||
}, startTime: chatConversation.lastMessageTime);
|
||||
}
|
||||
}
|
||||
|
||||
void GetConversationList()
|
||||
{
|
||||
long uid = client.Uid;
|
||||
client?.GetGroupConversationList((List<Conversation> groupConversationList, int errorCode) =>
|
||||
{
|
||||
if (errorCode == 0)
|
||||
{
|
||||
InitConversationList(groupConversationList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InitConversationList(List<Conversation> list)
|
||||
{
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
foreach (Conversation conversation in list)
|
||||
{
|
||||
if (conversation.id == groupConversationId)
|
||||
{
|
||||
if (chatConversation == null)
|
||||
{
|
||||
chatConversation = new ChatConversation();
|
||||
}
|
||||
//chatConversation.unreadCount += conversation.unreadCount;
|
||||
//if (conversation.lastMessage != null && conversation.lastMessage.messageId != 0)
|
||||
// chatConversation.AddMessage(ChatMessage.ConvertoFromHistoryMessage(conversation.lastMessage));
|
||||
UpdateConversationList(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateConversationList(bool push)
|
||||
{
|
||||
if (chatConversation == null)
|
||||
return;
|
||||
//client?.GetGroupMessage((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||||
//{
|
||||
// if (errorCode == 0)
|
||||
// {
|
||||
// InitChat(lastCursorId, messages);
|
||||
// }
|
||||
//}, groupConversationId, true, 10);
|
||||
//两个接口一样 GetGroupMessage多一个指定类型
|
||||
client?.GetGroupChat((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||||
{
|
||||
if (errorCode == 0)
|
||||
{
|
||||
InitChat(lastCursorId, messages, push, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("GetGroupChat errorCode = " + errorCode);
|
||||
}
|
||||
}, groupConversationId, true, 10);
|
||||
}
|
||||
|
||||
void InitChat(long lastId, List<HistoryMessage> messages, bool push, bool nextContent)
|
||||
{
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
if (chat == null)
|
||||
{
|
||||
chat = new ChatChatData();
|
||||
chat.messageList = new List<ChatMessage>();
|
||||
}
|
||||
if (messages != null)
|
||||
{
|
||||
if ((chat.lastId == 0 || lastId < chat.lastId) && lastId != 0)
|
||||
chat.lastId = lastId;
|
||||
|
||||
foreach (HistoryMessage message in messages)
|
||||
{
|
||||
chat.messageList.Add(ChatMessage.ConvertoFromHistoryMessage(message));
|
||||
}
|
||||
chat.messageList = chat.messageList.Distinct(new ChatMessageCompare()).ToList();
|
||||
chat.messageList.Sort();
|
||||
GContext.Publish(new ChatChangeEvent() { nextContent = nextContent, push = push });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async void AddMessage(long conversationId, bool push)
|
||||
{
|
||||
await Task.Delay(100);//服务器聊天记录存储延时
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
if (conversationId == groupConversationId)
|
||||
{
|
||||
if (chatConversation == null)
|
||||
{
|
||||
chatConversation = new ChatConversation();
|
||||
//chatConversation.unreadCount = 1;
|
||||
//chatConversation.lastMessage = message;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// chatConversation.AddMessage(message);
|
||||
//}
|
||||
UpdateConversationList(push);
|
||||
//if (chat == null)
|
||||
// return;
|
||||
//chat.messageList.Add(message);
|
||||
//chat.messageList = chat.messageList.Distinct(new ChatMessageCompare()).ToList();
|
||||
//chat.messageList.Sort();
|
||||
//GContext.Publish(new ChatChangeEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async Task<long> CanSend(string message)
|
||||
{
|
||||
if (groupConversationId == 0)
|
||||
return 0;
|
||||
var taskCompletionSource = new TaskCompletionSource<long>();
|
||||
message = string.Format("{0}#{1}", userService.UserId, message);
|
||||
client?.SendGroupChat((long messageId, long mtime, int errorCode) =>
|
||||
{
|
||||
if (errorCode != 0)
|
||||
{
|
||||
taskCompletionSource.SetResult(0);
|
||||
Debug.Log("SendGroupChat errorCode = " + errorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
taskCompletionSource.SetResult(messageId);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
AddMessage(groupConversationId, false);
|
||||
chatConversation.lastMessageTime = mtime;
|
||||
});
|
||||
}
|
||||
}, groupConversationId, message);
|
||||
long messageId = await taskCompletionSource.Task;
|
||||
return messageId;
|
||||
}
|
||||
|
||||
async Task<long> Send(string message)
|
||||
{
|
||||
if (groupConversationId == 0)
|
||||
return 0;
|
||||
|
||||
if (!CanSend())
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_42"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<long>();
|
||||
message = string.Format("{0}#{1}", userService.UserId, message);
|
||||
client?.SendGroupChat((long messageId, long mtime, int errorCode) =>
|
||||
{
|
||||
if (errorCode != 0)
|
||||
{
|
||||
taskCompletionSource.SetResult(0);
|
||||
Debug.Log("SendGroupChat errorCode = " + errorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
taskCompletionSource.SetResult(messageId);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
AddMessage(groupConversationId, false);
|
||||
chatConversation.lastMessageTime = mtime;
|
||||
});
|
||||
}
|
||||
}, groupConversationId, message);
|
||||
long messageId = await taskCompletionSource.Task;
|
||||
return messageId;
|
||||
}
|
||||
|
||||
Task sendTask = null;
|
||||
private bool CanSend()
|
||||
{
|
||||
if(sendTask == null || sendTask.IsCompleted)
|
||||
{
|
||||
sendTask = Task.Delay(TimeSpan.FromSeconds(sendInterval));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void NextPage()
|
||||
{
|
||||
if (groupConversationId == 0)
|
||||
return;
|
||||
if (chat == null)
|
||||
return;
|
||||
if (chat.messageList.Count >= GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubChatMaxCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
client?.GetGroupChat((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||||
{
|
||||
if (errorCode == 0)
|
||||
{
|
||||
InitChat(lastCursorId, messages, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("GetGroupChat errorCode = " + errorCode);
|
||||
}
|
||||
}, groupConversationId, true, 10, lastId: chat.lastId);
|
||||
}
|
||||
|
||||
public void OnQuit()
|
||||
{
|
||||
chat = null;
|
||||
chatConversation = null;
|
||||
groupConversationId = 0;
|
||||
}
|
||||
|
||||
public void InitChatData()
|
||||
{
|
||||
chat = null;
|
||||
}
|
||||
|
||||
public ChatChatData GetGroupChat()
|
||||
{
|
||||
return chat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析消息类型
|
||||
/// </summary>
|
||||
/// <param name="chat"></param>
|
||||
/// <returns>1.文本消息 2.系统消息(没有点赞)3.系统消息 4.求助帖 5.图片</returns>
|
||||
public string[] ParseChat(string chat)
|
||||
{
|
||||
return chat.Split('#');
|
||||
}
|
||||
|
||||
public async Task<long> SendHelpEnergyMessage(int itemId)
|
||||
{
|
||||
string chat = $"{(int)ChatType.HelpEnergy}#{itemId}";
|
||||
return await CanSend(chat);
|
||||
}
|
||||
|
||||
public void SendEmoji(string chat)
|
||||
{
|
||||
chat = $"{(int)ChatType.Emoji}#{chat}";
|
||||
_ = Send(chat);
|
||||
}
|
||||
|
||||
public async Task<long> SendGetPhotoMessage(string chat)
|
||||
{
|
||||
chat = $"{(int)ChatType.Help}#{chat}";
|
||||
return await CanSend(chat);
|
||||
}
|
||||
|
||||
//谁干了什么
|
||||
public void SendSystemMessage2(string chat)
|
||||
{
|
||||
chat = $"{(int)ChatType.System2}#{chat}";
|
||||
_ = CanSend(chat);
|
||||
}
|
||||
|
||||
//俱乐部系统提示
|
||||
public void SendSystemMessage(string chat)
|
||||
{
|
||||
chat = $"{(int)ChatType.System}#{chat}";
|
||||
_ = CanSend(chat);
|
||||
}
|
||||
|
||||
public async void SendTxTMessage(string chat)
|
||||
{
|
||||
//审核
|
||||
bool value = await TextAudit(chat);
|
||||
if (value)
|
||||
{
|
||||
chat = $"{(int)ChatType.Text}#{chat}";
|
||||
_ = Send(chat);
|
||||
}
|
||||
else
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_33"));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> TextAudit(string text)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
client.TextCheck((TextCheckResult result, int errorCode) =>
|
||||
{
|
||||
if (errorCode != com.fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
taskCompletionSource.SetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.Log(" -- result " + result.result);
|
||||
|
||||
//if (result.tags != null)
|
||||
// Debug.Log(" -- tags.Count " + result.tags.Count);
|
||||
//if (result.wlist != null)
|
||||
// Debug.Log(" -- wlist.Count " + result.wlist.Count);
|
||||
taskCompletionSource.SetResult(result.result == 0);
|
||||
}
|
||||
}, text);
|
||||
return await taskCompletionSource.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/ChatService.cs.meta
Normal file
11
Assets/Scripts/Services/ChatService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b387219dd01e554a99568fe02451a8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
333
Assets/Scripts/Services/ClubModel.cs
Normal file
333
Assets/Scripts/Services/ClubModel.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public enum EClubType : byte
|
||||
{
|
||||
UI_ClubCreatePopupPanel_11 = 0, //open
|
||||
UI_ClubCreatePopupPanel_12 = 1, //application
|
||||
UI_ClubCreatePopupPanel_13 = 2 //invisible
|
||||
}
|
||||
public enum EMemberRole : byte
|
||||
{
|
||||
Owner = 0,
|
||||
Vice = 1,//副会长
|
||||
Member = 2,
|
||||
Elder = 3,//长老
|
||||
//Elite = 4,//精英
|
||||
}
|
||||
|
||||
public class GetSelfClubRequest
|
||||
{
|
||||
#pragma warning disable CS8618
|
||||
public string playerId { get; set; }
|
||||
#pragma warning restore CS8618
|
||||
}
|
||||
public class GetSelfClubResp
|
||||
{
|
||||
[DefaultValue(EMemberRole.Member)]
|
||||
public EMemberRole role { get; set; }
|
||||
public DateTime? signTime { get; set; }
|
||||
public ClubInfo clubInfo { get; set; }
|
||||
public Dictionary<long, string> playerIDs { get; set; }
|
||||
public List<ClubPlayerProfile> clubPlayerProfiles { get; set; }
|
||||
}
|
||||
public class ClubPlayerProfile
|
||||
{
|
||||
public DateTime? lastLoginTime { get; set; }
|
||||
public int level { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public long internalId { get; set; }
|
||||
public long chestIntegral { get; set; }
|
||||
public string avatar { get; set; }
|
||||
public string displayName { get; set; }
|
||||
public EMemberRole role { get; set; } = EMemberRole.Member;
|
||||
}
|
||||
public class GetClubsRequest
|
||||
{
|
||||
//clubName == null 推荐俱乐部
|
||||
public string clubName { get; set; }
|
||||
}
|
||||
public class GetClubsResp
|
||||
{
|
||||
public List<ClubInfo> clubInfo { get; set; }
|
||||
}
|
||||
public class GetClubDetailsRequest
|
||||
{
|
||||
public ulong id { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public bool applyState { get; set; }
|
||||
}
|
||||
public class GetClubDetailsResp
|
||||
{
|
||||
public string ownerID { get; set; }
|
||||
public Dictionary<long, string> playerIDs { get; set; }
|
||||
public List<ClubPlayerProfile> clubPlayerProfiles { get; set; }
|
||||
public bool applyState { get; set; }
|
||||
|
||||
}
|
||||
public class ClubInfo
|
||||
{
|
||||
public ulong id { get; set; }
|
||||
public ClubSettingData clubSettingData { get; set; }
|
||||
|
||||
[DefaultValue(0)]
|
||||
public int points { get; set; }
|
||||
public long chestIntegral { get; set; }
|
||||
[DefaultValue(30)]
|
||||
public int maxMembers { get; set; }
|
||||
public int curMembers { get; set; }
|
||||
}
|
||||
public class ClubSettingData
|
||||
{
|
||||
public string clubName { get; set; }
|
||||
|
||||
public int type { get; set; }
|
||||
public int gradeReq { get; set; }
|
||||
public string description { get; set; }
|
||||
public string icon { get; set; }
|
||||
}
|
||||
public class CreateClubRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public string entityKey { get; set; } = "";
|
||||
|
||||
public ClubSettingData clubSettingData { get; set; }
|
||||
}
|
||||
public class CreateClubResp
|
||||
{
|
||||
public int code { get; set; }//0成功 1已经加入了俱乐部 2 失败
|
||||
public ClubInfo clubInfo { get; set; }
|
||||
}
|
||||
public class UpdateClubRequest
|
||||
{
|
||||
public ulong id { get; set; }
|
||||
public ClubSettingData clubSettingData { get; set; }
|
||||
}
|
||||
public class UpdateClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }
|
||||
}
|
||||
public class ApplyClubRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public string entityKey { get; set; } = "";
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class ApplyClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1等待审核 2已经加入了俱乐部 3俱乐部人数已满 4俱乐部不存在
|
||||
public ClubInfo clubInfo { get; set; }
|
||||
public Dictionary<long, string> playerIDs { get; set; }
|
||||
public List<ClubPlayerProfile> clubPlayerProfiles { get; set; }
|
||||
|
||||
}
|
||||
public class QuitClubRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public string appointId { get; set; }
|
||||
}
|
||||
public class QuitClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1不在俱乐部里 2是会长不能退出俱乐部
|
||||
}
|
||||
public class KickoutClubRequest
|
||||
{
|
||||
public ulong culbId { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public string kickoutId { get; set; }
|
||||
}
|
||||
public class KickoutClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1不在俱乐部里 2不是会长 3被踢的人不在俱乐部里
|
||||
}
|
||||
public class DemoteClubRequest
|
||||
{
|
||||
public ulong culbId { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public string demoteId { get; set; }
|
||||
}
|
||||
public class DemoteClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1不在俱乐部里 2权限不足
|
||||
}
|
||||
public class PromoteClubRequest
|
||||
{
|
||||
public ulong culbId { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public string promoteId { get; set; }
|
||||
public EMemberRole role { get; set; }
|
||||
}
|
||||
public class PromoteClubResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1不在俱乐部里 2权限不足
|
||||
public EMemberRole role { get; set; }
|
||||
}
|
||||
public class ReadClubEventRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
}
|
||||
public class ReadClubEventResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }
|
||||
}
|
||||
public class GetApplyListRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class GetApplyListResp
|
||||
{
|
||||
public List<string> userIDList { get; set; }
|
||||
public List<string> entityKeys { get; set; }
|
||||
public List<ClubPlayerProfile> clubPlayerProfiles { get; set; }
|
||||
}
|
||||
|
||||
public class HandleApplyRequest
|
||||
{
|
||||
public ulong id { get; set; }
|
||||
public string playerId { get; set; }
|
||||
public string entityKey { get; set; } = "";
|
||||
public bool isAgree { get; set; }
|
||||
}
|
||||
public class HandleApplyResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1不在俱乐部里 2不是会长 3申请不存在
|
||||
}
|
||||
public class ClubSinginRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class ClubSinginResp
|
||||
{
|
||||
public int code { get; set; }//0成功 1已经签到 2俱乐部不存在
|
||||
}
|
||||
//捐赠照片
|
||||
public class ClubDonateRequest
|
||||
{
|
||||
//捐赠人ID
|
||||
public string donateId { get; set; }
|
||||
//捐赠消息ID
|
||||
public long cursorId { get; set; }
|
||||
//被捐赠人ID
|
||||
public string playerId { get; set; }
|
||||
public int pictureID { get; set; }
|
||||
public ulong id { get; set; }
|
||||
|
||||
}
|
||||
public class ClubDonateResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }//0成功 1 已经捐赠
|
||||
//捐赠人ID
|
||||
public string donateId { get; set; }
|
||||
}
|
||||
//捐赠状态获取
|
||||
public class GetDonateStatusRequest
|
||||
{
|
||||
public long cursorId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
|
||||
}
|
||||
public class GetDonateStatusResp
|
||||
{
|
||||
public string donateId { get; set; }
|
||||
}
|
||||
public class GetPictureRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public DateTime? removeTime { get; set; }
|
||||
public DateTime? lastTime { get; set; }
|
||||
}
|
||||
public class GetPictureResp
|
||||
{
|
||||
public List<PictureData> pictureDataList { get; set; }
|
||||
public List<EventPopupData> eventPopupDatas { get; set; }
|
||||
}
|
||||
public class EventPopupData
|
||||
{
|
||||
public string playerID { get; set; }
|
||||
public ReportDataType type { get; set; }
|
||||
public int redirectID { get; set; }
|
||||
public string content { get; set; }
|
||||
public DateTime createTime { get; set; }
|
||||
public bool IsRead { get; set; }
|
||||
|
||||
}
|
||||
public class PictureData
|
||||
{
|
||||
public int pictureID { get; set; }
|
||||
public string donateId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class ClubLikeRequest
|
||||
{
|
||||
public long cursorId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
|
||||
}
|
||||
public class ClubLikeResp
|
||||
{
|
||||
//[DefaultValue(0)]
|
||||
//public int count { get; set; }
|
||||
}
|
||||
public class GetLikeCountRequest
|
||||
{
|
||||
public long cursorId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class GetLikeCountResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int count { get; set; }
|
||||
}
|
||||
|
||||
//体力求助赠送
|
||||
public class ClubHelpEnergyRequest
|
||||
{
|
||||
//捐赠人ID
|
||||
public string donateId { get; set; }
|
||||
//捐赠消息ID
|
||||
public long cursorId { get; set; }
|
||||
//被捐赠人ID
|
||||
public string playerId { get; set; }
|
||||
//工会id
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class ClubHelpEnergyResp
|
||||
{
|
||||
[DefaultValue(0)]
|
||||
public int code { get; set; }
|
||||
public string idContent { get; set; }
|
||||
}
|
||||
public class GetHelpEnergyStatusRequest
|
||||
{
|
||||
public long cursorId { get; set; }
|
||||
public ulong id { get; set; }
|
||||
}
|
||||
public class GetHelpEnergyStatusResp
|
||||
{
|
||||
public string idContent { get; set; }
|
||||
}
|
||||
public class MessageChatType
|
||||
{
|
||||
public const string IN = "IN";
|
||||
public const string OUT = "OUT";
|
||||
public const string SI = "SI";
|
||||
public const string DEMOTE = "DEMOTE";
|
||||
public const string PROMOTE = "PROMOTE";
|
||||
public const string CHEST = "CHEST";
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/ClubModel.cs.meta
Normal file
11
Assets/Scripts/Services/ClubModel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee7d9215eedaa53408bb38e3ebdb4ea8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
905
Assets/Scripts/Services/ClubService.cs
Normal file
905
Assets/Scripts/Services/ClubService.cs
Normal file
@@ -0,0 +1,905 @@
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class ClubStateChangeEvent
|
||||
{
|
||||
public int state;
|
||||
public bool joinClub;
|
||||
}
|
||||
public class ClubSttingUpdateEvent
|
||||
{
|
||||
}
|
||||
public class GetClubPlayInfoEvent
|
||||
{
|
||||
public string id;
|
||||
public string name;
|
||||
public string avatarUrl;
|
||||
}
|
||||
public class LureDonateData
|
||||
{
|
||||
public DateTime DonateCountTime { get; set; }
|
||||
public int ClubLureDonateCount { get; set; }//时间加次数
|
||||
public DateTime ClubLureRequestCDEnd { get; set; }
|
||||
}
|
||||
public class ClubService //: IClubService
|
||||
{
|
||||
[Inject]
|
||||
public IUserService userService { get; set; }
|
||||
[Inject]
|
||||
public ICustomServerMgr customServerMgr { get; set; }
|
||||
[Inject]
|
||||
public IChatService chatService { get; set; }
|
||||
public bool IsOpenClubJoined = false;
|
||||
public bool IsOpenClubRed = true;
|
||||
|
||||
public int socialTipforUnlocked;
|
||||
public ClubInfo myClubInfo { get; private set; }
|
||||
//public bool isAdm { get; private set; }
|
||||
public EMemberRole memberRole { get; private set; } = EMemberRole.Member;
|
||||
public DateTime? signTime { get; private set; }
|
||||
|
||||
LureDonateData lureDonateData;
|
||||
public int ClubLureDonateCount => lureDonateData.ClubLureDonateCount;
|
||||
public DateTime ClubLureRequestCDEnd => lureDonateData.ClubLureRequestCDEnd;
|
||||
|
||||
public Dictionary<long, string> internalIdToPlayerId = new Dictionary<long, string>();
|
||||
public ClubItemData ClubItemData;
|
||||
public List<SocialInfoItemData> clubPlayerInfos { get; private set; }
|
||||
public List<EventPopupData> eventPopupDatas { get; private set; } = new List<EventPopupData>();
|
||||
public EventPopupData eventPopupDataClub { get; private set; }
|
||||
public int OpenPanelType = 0;
|
||||
|
||||
public async void OpenFishingSocialPanel(int type)
|
||||
{
|
||||
OpenPanelType = type;
|
||||
await UIManager.Instance.ShowUI(UITypes.FishingSocialPanel);
|
||||
OpenPanelType = 0;
|
||||
}
|
||||
|
||||
public bool CanAccepted
|
||||
{
|
||||
get
|
||||
{
|
||||
return memberRole == EMemberRole.Owner
|
||||
|| memberRole == EMemberRole.Vice
|
||||
|| memberRole == EMemberRole.Elder;
|
||||
}
|
||||
}
|
||||
public bool ApplyState { get; private set; }
|
||||
public bool CanSetting
|
||||
{
|
||||
get
|
||||
{
|
||||
return memberRole == EMemberRole.Owner || memberRole == EMemberRole.Vice;
|
||||
}
|
||||
}
|
||||
public void Init()
|
||||
{
|
||||
if (lureDonateData == null)
|
||||
{
|
||||
lureDonateData = new LureDonateData();
|
||||
lureDonateData.DonateCountTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
lureDonateData.ClubLureDonateCount = 0;
|
||||
lureDonateData.ClubLureRequestCDEnd = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
}
|
||||
if (IsOpenClubJoined)
|
||||
{
|
||||
SetClubRed();
|
||||
}
|
||||
}
|
||||
void SetClubRed()
|
||||
{
|
||||
if (myClubInfo == null)
|
||||
{
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Club, IsOpenClubRed);
|
||||
}
|
||||
else
|
||||
{
|
||||
var timer = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
bool isSign = signTime?.DayOfYear != timer.DayOfYear;
|
||||
bool isCanLure = lureDonateData != null && lureDonateData.ClubLureRequestCDEnd <= timer;
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Club, isCanLure || isSign);
|
||||
}
|
||||
}
|
||||
public void SetLureDonateData(string value)
|
||||
{
|
||||
lureDonateData = Newtonsoft.Json.JsonConvert.DeserializeObject<LureDonateData>(value);
|
||||
}
|
||||
void SaveLureDonateData()
|
||||
{
|
||||
PlayFabMgr.Instance.UpdateUserDataValue("LureDonateData", Newtonsoft.Json.JsonConvert.SerializeObject(lureDonateData));
|
||||
}
|
||||
//刷新体力求助次数
|
||||
public void RefreshLureDonate()
|
||||
{
|
||||
if (lureDonateData.DonateCountTime.Date != ZZTimeHelper.UtcNow().UtcNowOffset().Date)
|
||||
{
|
||||
lureDonateData.DonateCountTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
lureDonateData.ClubLureDonateCount = 0;
|
||||
SaveLureDonateData();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOpenClubRed()
|
||||
{
|
||||
if (IsOpenClubRed)
|
||||
{
|
||||
IsOpenClubRed = false;
|
||||
SetClubRed();
|
||||
PlayFabMgr.Instance.UpdateUserDataValue("IsOpenClubRed", "1");
|
||||
}
|
||||
}
|
||||
public bool IsClubJoined()
|
||||
{
|
||||
return myClubInfo != null;
|
||||
}
|
||||
public void SetClubSignin(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
signTime = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
signTime = DateTime.Parse(value);
|
||||
}
|
||||
}
|
||||
public async void GetSelfClub()
|
||||
{
|
||||
GetSelfClubRequest getSelfClubRequest = new GetSelfClubRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetSelfClub", getSelfClubRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetSelfClubResp getSelfClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetSelfClubResp>(json);
|
||||
myClubInfo = getSelfClubResp.clubInfo;
|
||||
if (myClubInfo != null)
|
||||
{
|
||||
memberRole = getSelfClubResp.role;
|
||||
//signTime = getSelfClubResp.signTime;
|
||||
internalIdToPlayerId = getSelfClubResp.playerIDs;
|
||||
SetClubPlayerProfile(getSelfClubResp.clubPlayerProfiles);
|
||||
chatService.GetConversationList((long)myClubInfo.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memberRole = EMemberRole.Member;
|
||||
myClubInfo = null;
|
||||
}
|
||||
SetClubRed();
|
||||
MyClubInfoChange();
|
||||
}
|
||||
void MyClubInfoChange(bool joinClub = false)
|
||||
{
|
||||
GContext.Publish(new ClubStateChangeEvent() { state = 0, joinClub = joinClub });
|
||||
}
|
||||
public async Task<int> GetOnlineUsers()
|
||||
{
|
||||
HashSet<long> longs = await chatService.GetOnlineUsers(internalIdToPlayerId.Keys.ToList());
|
||||
return longs == null ? 0 : longs.Count;
|
||||
}
|
||||
public async Task<List<ClubInfo>> GetClubs(string clubName)
|
||||
{
|
||||
GetClubsRequest getClubsRequest = new GetClubsRequest()
|
||||
{
|
||||
clubName = clubName,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetClubs", getClubsRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetClubsResp clubDatas = Newtonsoft.Json.JsonConvert.DeserializeObject<GetClubsResp>(json);
|
||||
return clubDatas.clubInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<SocialInfoItemData>> GetClubDetails(ulong clubID, bool applyState = false)
|
||||
{
|
||||
ApplyState = false;
|
||||
GetClubDetailsRequest getClubDetailsRequest = new GetClubDetailsRequest()
|
||||
{
|
||||
id = clubID,
|
||||
playerId = userService.UserId,
|
||||
applyState = applyState,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetClubDetails", getClubDetailsRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetClubDetailsResp clubDetails = Newtonsoft.Json.JsonConvert.DeserializeObject<GetClubDetailsResp>(json);
|
||||
if (clubDetails.playerIDs == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
List<SocialInfoItemData> clubPlayerInfos = new List<SocialInfoItemData>();
|
||||
if (myClubInfo != null && clubID == myClubInfo.id)
|
||||
{
|
||||
internalIdToPlayerId = clubDetails.playerIDs;
|
||||
//internalIds = clubDetails.internalIds;
|
||||
}
|
||||
List<long> longs1 = clubDetails.playerIDs.Keys.ToList();
|
||||
HashSet<long> longs = await chatService.GetOnlineUsers(longs1);
|
||||
List<ClubPlayerProfile> clubPlayerProfiles = clubDetails.clubPlayerProfiles;
|
||||
SetClubPlayerProfile(clubPlayerProfiles);
|
||||
|
||||
for (int i = 0; i < clubPlayerProfiles.Count; i++)
|
||||
{
|
||||
ClubPlayerProfile clubPlayerProfile = clubPlayerProfiles[i];
|
||||
SocialInfoItemData clubPlayerInfo = new SocialInfoItemData();
|
||||
clubPlayerInfo.playFabId = clubPlayerProfile.playerId;
|
||||
userService.GetPlayInfo(clubPlayerInfo.playFabId);
|
||||
clubPlayerInfo.lv = userService.GetPlayerLv(clubPlayerInfo.playFabId);
|
||||
//clubPlayerInfo.rank = i + 1;
|
||||
clubPlayerInfo.isOnline = longs.Contains(clubPlayerProfile.internalId);
|
||||
clubPlayerInfo.role = clubPlayerProfile.role;
|
||||
|
||||
if (clubPlayerProfile.lastLoginTime != null)
|
||||
{
|
||||
clubPlayerInfo.lastLoginTime = (DateTime)clubPlayerProfile.lastLoginTime;
|
||||
}
|
||||
clubPlayerInfos.Add(clubPlayerInfo);
|
||||
}
|
||||
|
||||
clubPlayerInfos.Sort((x, y) =>
|
||||
{
|
||||
//if (y.isOnline != x.isOnline)
|
||||
//{
|
||||
// return y.isOnline.CompareTo(x.isOnline);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
return y.lv.CompareTo(x.lv);
|
||||
}
|
||||
});
|
||||
ApplyState = clubDetails.applyState;
|
||||
return clubPlayerInfos;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<ClubInfo> CreateClub(ClubSettingData clubSettingData)
|
||||
{
|
||||
CreateClubRequest createClubRequest = new CreateClubRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
//entityKey = userService.entityKey.Id,
|
||||
clubSettingData = clubSettingData,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("CreateClub", createClubRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
CreateClubResp createClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<CreateClubResp>(json);
|
||||
if (createClubResp.code != 2)
|
||||
{
|
||||
if (createClubResp.code == 0)
|
||||
{
|
||||
memberRole = EMemberRole.Owner;
|
||||
ShowPromote();
|
||||
}
|
||||
myClubInfo = createClubResp.clubInfo;
|
||||
chatService.GetConversationList((long)myClubInfo.id);
|
||||
internalIdToPlayerId[userService.InternalId] = userService.UserId;
|
||||
MyClubInfoChange(true);
|
||||
return myClubInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myClubInfo = null;
|
||||
}
|
||||
MyClubInfoChange();
|
||||
return myClubInfo;
|
||||
}
|
||||
public async void ShowPromote()
|
||||
{
|
||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.ClubPromoteNoticePopupPanel);
|
||||
var ClubPromoteNoticePopupPanel = go.GetComponent<ClubPromoteNoticePopupPanel>();
|
||||
ClubPromoteNoticePopupPanel.SetRole(memberRole);
|
||||
}
|
||||
public async Task<bool> UpdateClub(ClubSettingData clubSettingData)
|
||||
{
|
||||
UpdateClubRequest updateClubRequest = new UpdateClubRequest()
|
||||
{
|
||||
id = myClubInfo.id,
|
||||
clubSettingData = clubSettingData,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("UpdateClub", updateClubRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
UpdateClubResp createClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateClubResp>(json);
|
||||
if (createClubResp.code == 0)
|
||||
{
|
||||
myClubInfo.clubSettingData = clubSettingData;
|
||||
GContext.Publish(new ClubSttingUpdateEvent());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> ApplyClub(ulong clubID)
|
||||
{
|
||||
memberRole = EMemberRole.Member;
|
||||
ApplyClubRequest applyClubRequest = new ApplyClubRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
//entityKey = userService.entityKey.Id,
|
||||
id = clubID,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("ApplyClub", applyClubRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
ApplyClubResp applyClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ApplyClubResp>(json);
|
||||
if (applyClubResp.code == 0)
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_41"));
|
||||
myClubInfo = applyClubResp.clubInfo;
|
||||
internalIdToPlayerId = applyClubResp.playerIDs;
|
||||
SetClubPlayerProfile(applyClubResp.clubPlayerProfiles);
|
||||
//internalIds = applyClubResp.internalIds;
|
||||
chatService.GetConversationList((long)myClubInfo.id);
|
||||
MyClubInfoChange(true);
|
||||
return true;
|
||||
}
|
||||
else if (applyClubResp.code == 1)
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_44"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_45"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async void HandleApply(bool isAgree, string applyId)
|
||||
{
|
||||
if (isAgree && myClubInfo.curMembers >= myClubInfo.maxMembers)
|
||||
{
|
||||
//人数已满
|
||||
return;
|
||||
}
|
||||
HandleApplyRequest handleApplyRequest = new HandleApplyRequest()
|
||||
{
|
||||
playerId = applyId,
|
||||
//entityKey = entityID,
|
||||
isAgree = isAgree,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
if (applyId == "")
|
||||
{
|
||||
clubPlayerInfos.Clear();
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < clubPlayerInfos.Count; i++)
|
||||
{
|
||||
if (clubPlayerInfos[i].playFabId == applyId)
|
||||
{
|
||||
clubPlayerInfos.RemoveAt(i);
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, clubPlayerInfos.Count > 0
|
||||
&& CanAccepted);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
string json = await customServerMgr.ClubRequest("HandleApply", handleApplyRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
HandleApplyResp handleApplyResp = Newtonsoft.Json.JsonConvert.DeserializeObject<HandleApplyResp>(json);
|
||||
if (handleApplyResp.code == 0)
|
||||
{
|
||||
myClubInfo.curMembers++;
|
||||
GContext.Publish(new ClubSttingUpdateEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void GetApplyList()
|
||||
{
|
||||
clubPlayerInfos = new List<SocialInfoItemData>();
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, false);
|
||||
GetApplyListRequest getApplyListRequest = new GetApplyListRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetApplyList", getApplyListRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetApplyListResp getApplyListResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetApplyListResp>(json);
|
||||
SetClubPlayerProfile(getApplyListResp.clubPlayerProfiles);
|
||||
for (int i = 0; i < getApplyListResp.userIDList.Count; i++)
|
||||
{
|
||||
SocialInfoItemData clubPlayerInfo = new SocialInfoItemData();
|
||||
//clubPlayerInfo.rank = i + 1;
|
||||
//clubPlayerInfo.entityKey = getApplyListResp.entityKeys[i];
|
||||
clubPlayerInfo.playFabId = getApplyListResp.userIDList[i];
|
||||
userService.GetPlayInfo(clubPlayerInfo.playFabId);
|
||||
clubPlayerInfo.lv = userService.GetPlayerLv(clubPlayerInfo.playFabId);
|
||||
clubPlayerInfos.Add(clubPlayerInfo);
|
||||
}
|
||||
clubPlayerInfos.Sort((x, y) => y.lv.CompareTo(x.lv));
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, clubPlayerInfos.Count > 0 && CanAccepted);
|
||||
}
|
||||
}
|
||||
void SetClubPlayerProfile(List<ClubPlayerProfile> clubPlayerProfiles)
|
||||
{
|
||||
if (clubPlayerProfiles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var item in clubPlayerProfiles)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.displayName) || !string.IsNullOrEmpty(item.avatar))
|
||||
{
|
||||
userService.SetPlayInfo(item.playerId, item.displayName, item.avatar);
|
||||
userService.SetPlayerLv(item.playerId, item.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
public async void QuitClub(string appointId = "0")
|
||||
{
|
||||
QuitClubRequest quitClubRequest = new QuitClubRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
appointId = appointId,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("QuitClub", quitClubRequest);
|
||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
//{
|
||||
// QuitClubResp quitClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<QuitClubResp>(json);
|
||||
//}
|
||||
chatService.OnQuit();
|
||||
myClubInfo = null;
|
||||
ClearLikeCursorIds();
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_46"));
|
||||
MyClubInfoChange();
|
||||
}
|
||||
public async void Demote(string playerId)
|
||||
{
|
||||
DemoteClubRequest demoteClubRequest = new DemoteClubRequest()
|
||||
{
|
||||
culbId = myClubInfo.id,
|
||||
demoteId = playerId,
|
||||
playerId = userService.UserId,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("DemoteClub", demoteClubRequest);
|
||||
}
|
||||
public async void Promote(string playerId, EMemberRole role)
|
||||
{
|
||||
PromoteClubRequest promoteClubRequest = new PromoteClubRequest()
|
||||
{
|
||||
culbId = myClubInfo.id,
|
||||
promoteId = playerId,
|
||||
playerId = userService.UserId,
|
||||
role = role,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("PromoteClub", promoteClubRequest);
|
||||
}
|
||||
public async void Kickout(string playerId)
|
||||
{
|
||||
KickoutClubRequest kickoutClubRequest = new KickoutClubRequest()
|
||||
{
|
||||
culbId = myClubInfo.id,
|
||||
kickoutId = playerId,
|
||||
playerId = userService.UserId,
|
||||
};
|
||||
myClubInfo.curMembers--;
|
||||
GContext.Publish(new ClubSttingUpdateEvent());
|
||||
string json = await customServerMgr.ClubRequest("KickoutClub", kickoutClubRequest);
|
||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
//{
|
||||
// KickoutClubResp quitClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<KickoutClubResp>(json);
|
||||
//}
|
||||
}
|
||||
public async void ReadClubEvent()
|
||||
{
|
||||
ReadClubEventRequest readClubEventRequest = new ReadClubEventRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("ReadClubEvent", readClubEventRequest);
|
||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
//{
|
||||
// ReadClubEventResp readClubEventResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ReadClubEventResp>(json);
|
||||
//}
|
||||
}
|
||||
public async void ClubSingin()
|
||||
{
|
||||
signTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
ClubSinginRequest clubSinginRequest = new ClubSinginRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("ClubSingin", clubSinginRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
ClubSinginResp clubSinginResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ClubSinginResp>(json);
|
||||
signTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||
PlayFabMgr.Instance.UpdateUserDataValue("ClubSignin", signTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
if (clubSinginResp.code == 0)
|
||||
{
|
||||
chatService.SendSystemMessage($"{MessageChatType.SI}_{userService.UserId}");
|
||||
//签到成功奖励
|
||||
GContext.container.Resolve<PlayerItemData>().AddItemByDrop(GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubSignReward);
|
||||
GContext.Publish(new ShowData());
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("guild_sign"))
|
||||
{
|
||||
e.AddContent("guild_id", myClubInfo.id)
|
||||
.AddContent("drop_list", GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubSignReward);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SetClubRed();
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> SendGetPhoto(int pictureID)
|
||||
{
|
||||
if (GContext.container.Resolve<AlbumData>().GetPhotoRequestCountByDay(pictureID) > 0)
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_43"));
|
||||
return false;
|
||||
}
|
||||
//messageID
|
||||
long messageID = await chatService.SendGetPhotoMessage(pictureID.ToString());
|
||||
if (messageID > 0)
|
||||
{
|
||||
//记录今日请求pictureID
|
||||
GContext.container.Resolve<AlbumData>().SetPhotoRequestCountByDay(pictureID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SendSystemMessage2(int index)
|
||||
{
|
||||
chatService.SendSystemMessage2($"{userService.UserId}_{index}");
|
||||
}
|
||||
public async Task<string> SendDonatePhoto(string playerId, long cursorId, int pictureID)
|
||||
{
|
||||
ClubDonateRequest clubDonateRequest = new ClubDonateRequest()
|
||||
{
|
||||
donateId = userService.UserId,
|
||||
cursorId = cursorId,
|
||||
playerId = playerId,
|
||||
pictureID = pictureID,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("DonatePhoto", clubDonateRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
ClubDonateResp clubDonateResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ClubDonateResp>(json);
|
||||
if (clubDonateResp.code == 0)
|
||||
{
|
||||
//减去一个照片
|
||||
GContext.container.Resolve<AlbumData>().RemovePictureProgress(pictureID, 1);
|
||||
int gold = GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubDonationCashReward;
|
||||
GContext.container.Resolve<PlayerData>().AddGold((ulong)gold);
|
||||
GContext.Publish(new ShowData(new ItemData() { count = gold, id = 1002 }));
|
||||
|
||||
GContext.Publish(new ShowData());
|
||||
return clubDonateResp.donateId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return clubDonateResp.donateId;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public async Task<string> GetPhotoState(string playerId, long cursorId)
|
||||
{
|
||||
GetDonateStatusRequest DonateStatusRequest = new GetDonateStatusRequest()
|
||||
{
|
||||
//playerId = playerId,
|
||||
cursorId = cursorId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetDonateStatus", DonateStatusRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetDonateStatusResp clubSinginResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetDonateStatusResp>(json);
|
||||
return clubSinginResp.donateId;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取被赠送的照片 以及其他事件
|
||||
/// </summary>
|
||||
///
|
||||
int energyAddCount = 0;
|
||||
public int GetEnergyAddCount()
|
||||
{
|
||||
int count = energyAddCount;
|
||||
energyAddCount = 0;
|
||||
return count;
|
||||
}
|
||||
public async void GetServiceEvent()
|
||||
{
|
||||
energyAddCount = 0;
|
||||
GetPictureRequest getPictureRequest = new GetPictureRequest()
|
||||
{
|
||||
playerId = userService.UserId,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetPictureList", getPictureRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetPictureResp getPictureResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetPictureResp>(json);
|
||||
//var pictureDatas = getPictureResp.pictureDataList;
|
||||
//if (pictureDatas != null && pictureDatas.Count > 0)
|
||||
//{
|
||||
// List<int> pictureIDs = new List<int>();
|
||||
// foreach (var pictureData in pictureDatas)
|
||||
// {
|
||||
// pictureIDs.Add(pictureData.pictureID);
|
||||
// }
|
||||
// GContext.container.Resolve<AlbumData>().AddPictureProgress(pictureIDs);
|
||||
//}
|
||||
eventPopupDatas = getPictureResp.eventPopupDatas;
|
||||
if (eventPopupDatas != null && eventPopupDatas.Count > 0)
|
||||
{
|
||||
IReportService reportService = GContext.container.Resolve<IReportService>();
|
||||
var playerData = GContext.container.Resolve<PlayerData>();
|
||||
var tables = GContext.container.Resolve<Tables>();
|
||||
//CampData campData = GContext.container.Resolve<CampData>();
|
||||
foreach (var eventPopupData in eventPopupDatas)
|
||||
{
|
||||
if (eventPopupData.type == ReportDataType.Heist)
|
||||
{
|
||||
long content = long.Parse(eventPopupData.content);
|
||||
if (content < 0)
|
||||
{
|
||||
content = -content;
|
||||
}
|
||||
//=====新规则=====
|
||||
long newContent = content / 100;
|
||||
long rangeT = content % 100;
|
||||
float range = Mathf.Clamp(rangeT, 5, 15) * 0.1f;
|
||||
|
||||
|
||||
int m = Mathf.Min(tables.TbGlobalConfig.BottleCashParamLimit, (int)newContent);
|
||||
float mg = (1 + playerData.benefitsCashMag) * (1 + playerData.benefitsCashMagLimited);
|
||||
m = Mathf.RoundToInt(m * mg * range);
|
||||
|
||||
//=====新规则=====
|
||||
eventPopupData.content = m.ToString();
|
||||
}
|
||||
|
||||
if (eventPopupData.IsRead == false)
|
||||
{
|
||||
if (eventPopupData.type == ReportDataType.Energy)
|
||||
{
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("guild_request_lures_reward"))
|
||||
{
|
||||
e.AddContent("donate_userid_list", eventPopupData.content)
|
||||
.AddContent("reward_hook", GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubLureDonateReward);
|
||||
if (myClubInfo != null)
|
||||
{
|
||||
e.AddContent("guild_id", myClubInfo.id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//事件弹窗
|
||||
//添加体力
|
||||
playerData.SetEnergy(playerData.Energy + GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubLureDonateReward);
|
||||
energyAddCount++;
|
||||
}
|
||||
else if (eventPopupData.type == ReportDataType.Club)
|
||||
{
|
||||
//工会事件,只在工会界面调用,弹窗展示之后才设置为已读
|
||||
eventPopupDataClub = eventPopupData;
|
||||
}
|
||||
else if (eventPopupData.type == ReportDataType.Aquarium)
|
||||
{
|
||||
reportService.AddReport(new ReportData()
|
||||
{
|
||||
type = eventPopupData.type,
|
||||
id = eventPopupData.redirectID,
|
||||
playFabId = eventPopupData.playerID,
|
||||
content = eventPopupData.content,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
//可能扣钱
|
||||
if (eventPopupData.type == ReportDataType.Heist && playerData.gold > 0)
|
||||
{
|
||||
int content = int.Parse(eventPopupData.content);
|
||||
|
||||
reportService.AddReport(new ReportData()
|
||||
{
|
||||
type = eventPopupData.type,
|
||||
id = eventPopupData.redirectID,
|
||||
playFabId = eventPopupData.playerID,
|
||||
content = eventPopupData.content,
|
||||
});
|
||||
|
||||
ulong gold = (ulong)content;
|
||||
if (gold >= playerData.gold)
|
||||
{
|
||||
playerData.SetGold(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerData.SetGold(playerData.gold - gold);
|
||||
}
|
||||
}
|
||||
else if (eventPopupData.type == ReportDataType.Bomb)
|
||||
{
|
||||
reportService.AddReport(new ReportData()
|
||||
{
|
||||
type = eventPopupData.type,
|
||||
id = eventPopupData.redirectID,
|
||||
playFabId = eventPopupData.playerID,
|
||||
content = eventPopupData.content,
|
||||
});
|
||||
GContext.container.Resolve<CampDataMM>().SetIsFix(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (energyAddCount > 0)
|
||||
{
|
||||
GContext.container.Resolve<IFaceUIService>().AddFaceCustomUIData(UITypes.EventReportPopupPanel, true);
|
||||
}
|
||||
CurRewardQCount curRewardQCount = new CurRewardQCount();
|
||||
GContext.Publish(curRewardQCount);
|
||||
int faceCount = GContext.container.Resolve<IFaceUIService>().GetFaceUICount();
|
||||
if (curRewardQCount.count <= 0 && faceCount <= 0)
|
||||
{
|
||||
ShowHomeReport();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ShowHomeReport()
|
||||
{
|
||||
ReportData reportData = GContext.container.Resolve<IReportService>().GetReportData();
|
||||
if (reportData != null)
|
||||
{
|
||||
GContext.Publish(reportData);
|
||||
}
|
||||
}
|
||||
//消息点赞相关
|
||||
List<long> LikeCursorIds;
|
||||
string LikeCursorIdsKey = "LikeCursorIds";
|
||||
void ClearLikeCursorIds()
|
||||
{
|
||||
LikeCursorIds = null;
|
||||
PlayerPrefs.DeleteKey(LikeCursorIdsKey);
|
||||
}
|
||||
public async void SendLike(long cursorId)
|
||||
{
|
||||
ClubLikeRequest clubLikeRequest = new ClubLikeRequest()
|
||||
{
|
||||
cursorId = cursorId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("ClubLike", clubLikeRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
ClubLikeResp clubSinginResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ClubLikeResp>(json);
|
||||
LikeCursorIds.Add(cursorId);
|
||||
PlayerPrefs.SetString(LikeCursorIdsKey, Newtonsoft.Json.JsonConvert.SerializeObject(LikeCursorIds));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool, int)> GetLikeCount(long cursorId)
|
||||
{
|
||||
GetLikeCountRequest LikeCountRequest = new GetLikeCountRequest()
|
||||
{
|
||||
cursorId = cursorId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
LikeCursorIds = Newtonsoft.Json.JsonConvert.DeserializeObject<List<long>>(PlayerPrefs.GetString(LikeCursorIdsKey, "[]"));
|
||||
bool isLike = LikeCursorIds.Contains(cursorId);
|
||||
int count = 0;
|
||||
if (isLike)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
string json = await customServerMgr.ClubRequest("GetLikeCount", LikeCountRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetLikeCountResp clubSinginResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetLikeCountResp>(json);
|
||||
count = clubSinginResp.count;
|
||||
}
|
||||
return (isLike, count);
|
||||
}
|
||||
//体力求助相关
|
||||
//聊天消息
|
||||
public async Task<bool> SendHelpEnergy()
|
||||
{
|
||||
//messageID
|
||||
long messageID = await chatService.SendHelpEnergyMessage(1001);
|
||||
if (messageID > 0)
|
||||
{
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("guild_request_lures"))
|
||||
{
|
||||
e.AddContent("guild_id", myClubInfo.id);
|
||||
}
|
||||
#endif
|
||||
//记录今日请求 体力互助
|
||||
lureDonateData.ClubLureRequestCDEnd = ZZTimeHelper.UtcNow().UtcNowOffset().
|
||||
AddHours(GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubLureRequestCd);
|
||||
SaveLureDonateData();
|
||||
SetClubRed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//服务器消息状态
|
||||
public async Task<string> SendHelpOthersEnergy(string playerId, long cursorId)
|
||||
{
|
||||
ClubHelpEnergyRequest clubHelpEnergyRequest = new ClubHelpEnergyRequest()
|
||||
{
|
||||
donateId = userService.UserId,
|
||||
cursorId = cursorId,
|
||||
playerId = playerId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
lureDonateData.ClubLureDonateCount++;
|
||||
string json = await customServerMgr.ClubRequest("ClubHelpEnergy", clubHelpEnergyRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("guild_donate_lures"))
|
||||
{
|
||||
e.AddContent("guild_id", myClubInfo.id)
|
||||
.AddContent("to_user_id", playerId)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
ClubHelpEnergyResp clubHelpEnergyResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ClubHelpEnergyResp>(json);
|
||||
SaveLureDonateData();
|
||||
return clubHelpEnergyResp.idContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
lureDonateData.ClubLureDonateCount--;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public async Task<string> GetHelpEnergyState(long cursorId)
|
||||
{
|
||||
GetHelpEnergyStatusRequest helpEnergyRequest = new GetHelpEnergyStatusRequest()
|
||||
{
|
||||
cursorId = cursorId,
|
||||
id = myClubInfo.id,
|
||||
};
|
||||
string json = await customServerMgr.ClubRequest("GetHelpEnergyStatus", helpEnergyRequest);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
GetHelpEnergyStatusResp helpEnergyResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetHelpEnergyStatusResp>(json);
|
||||
return helpEnergyResp.idContent;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Services/ClubService.cs.meta
Normal file
11
Assets/Scripts/Services/ClubService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c3fc6d525c26e14caabe4275f3bb816
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
122
Assets/Scripts/Services/DataService.cs
Normal file
122
Assets/Scripts/Services/DataService.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace game.data
|
||||
{
|
||||
public interface IDataService
|
||||
{
|
||||
public Task Init();
|
||||
public T GetTable<T>();
|
||||
}
|
||||
|
||||
public class LubanDataService : IDataService
|
||||
{
|
||||
private Dictionary<Type, object> tableMap;
|
||||
|
||||
public T GetTable<T>()
|
||||
{
|
||||
if (tableMap.TryGetValue(typeof(T), out var table))
|
||||
{
|
||||
return (T)table;
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public async Task Init()
|
||||
{
|
||||
tableMap = new Dictionary<Type, object>();
|
||||
|
||||
// addr:json map
|
||||
var rawDataMap = new Dictionary<string, string>();
|
||||
var opMap = new Dictionary<string, AsyncOperationHandle<TextAsset>>();
|
||||
|
||||
var props = typeof(cfg.Tables).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var addrs = props.Select(_ => _.Name.ToLower());
|
||||
|
||||
foreach (var addr in addrs)
|
||||
{
|
||||
var op = Addressables.LoadAssetAsync<TextAsset>(addr);
|
||||
opMap.Add(addr, op);
|
||||
}
|
||||
|
||||
await Task.WhenAll(opMap.Values.Select(_ => _.Task));
|
||||
|
||||
var tables = new cfg.Tables(
|
||||
tableName => SimpleJSON.JSON.Parse(opMap[tableName].Result.text)
|
||||
);
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
tableMap.Add(prop.PropertyType, prop.GetValue(tables));
|
||||
}
|
||||
|
||||
foreach (var kv in opMap)
|
||||
{
|
||||
Addressables.Release(kv.Value);
|
||||
}
|
||||
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DataServiceExtensions
|
||||
{
|
||||
public static cfg.MapData GetMapData(this IDataService service, int id)
|
||||
{
|
||||
return service.GetTable<cfg.TbMapData>()[id];
|
||||
}
|
||||
|
||||
public static cfg.FishData GetFishData(this IDataService service, int id)
|
||||
{
|
||||
var fishData = service.GetTable<cfg.TbFishData>();
|
||||
|
||||
if (!fishData.DataMap.ContainsKey(id))
|
||||
{
|
||||
return fishData.DataList[0];
|
||||
}
|
||||
|
||||
return fishData[id];
|
||||
}
|
||||
|
||||
public static cfg.RodData GetRodData(this IDataService service, int id)
|
||||
{
|
||||
var fishRodData = service.GetTable<cfg.TbRodData>();
|
||||
if (!fishRodData.DataMap.ContainsKey(id))
|
||||
{
|
||||
return fishRodData.DataList[0];
|
||||
}
|
||||
|
||||
return fishRodData[id];
|
||||
}
|
||||
|
||||
public static cfg.AlbumExchange GetAlbumExchange(this IDataService service, int id)
|
||||
{
|
||||
return service.GetTable<cfg.TbAlbumExchange>().GetOrDefault(id);
|
||||
}
|
||||
|
||||
public static cfg.Item GetItemData(this IDataService service, int id)
|
||||
{
|
||||
return service.GetTable<cfg.TbItem>().GetOrDefault(id);
|
||||
}
|
||||
|
||||
public static string GetItemIconName(this IDataService service, int id)
|
||||
{
|
||||
var item = service.GetTable<cfg.TbItem>();
|
||||
if (!item.DataMap.ContainsKey(id))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return item[id].Icon;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
11
Assets/Scripts/Services/DataService.cs.meta
Normal file
11
Assets/Scripts/Services/DataService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 151336f521e58ab41b6b70b0ad33b63c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
237
Assets/Scripts/Services/DeferredRewardStashService.cs
Normal file
237
Assets/Scripts/Services/DeferredRewardStashService.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System.Collections.Generic;
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using game;
|
||||
using GameCore;
|
||||
using UniRx;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
public interface IDeferredRewardStashService
|
||||
{
|
||||
public void DisposeSubscriptions();
|
||||
public void Reset();
|
||||
public void Flush();
|
||||
public void UploadData();
|
||||
public void LoadData();
|
||||
public IReadOnlyList<ItemData> Items { get; }
|
||||
public bool IsEmpty { get; }
|
||||
}
|
||||
|
||||
public class DeferredRewardStashService : IDeferredRewardStashService
|
||||
{
|
||||
private readonly TbItem _itemTable = GContext.container.Resolve<Tables>().TbItem;
|
||||
private readonly PlayerItemData _playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||||
private CompositeDisposable _disposables;
|
||||
private List<ItemData> _items;
|
||||
public IReadOnlyList<ItemData> Items => _items;
|
||||
public bool IsEmpty => _items is not { Count: > 0 };
|
||||
private const string Key = "DeferredRewardStashService", Comma = ",", Splitter = "|";
|
||||
|
||||
// private readonly HashSet<int> _excludeList = new HashSet<int>
|
||||
// {
|
||||
// 310020000,
|
||||
// 310030000,
|
||||
// 310040000,
|
||||
// 320020000,
|
||||
// 320030000,
|
||||
// 320040000,
|
||||
// };
|
||||
|
||||
/// <summary>
|
||||
/// Temporary usage to exclude handbag from showing, and showing only.
|
||||
/// </summary>
|
||||
// private bool IsItemHandBag(ItemData item)
|
||||
// {
|
||||
// var itemLine = _itemTable.GetOrDefault(item.id);
|
||||
// if (itemLine == null)
|
||||
// return false;
|
||||
// return itemLine.Type == 9 && itemLine.SubType == 7;
|
||||
// }
|
||||
|
||||
public DeferredRewardStashService()
|
||||
{
|
||||
_disposables = new CompositeDisposable();
|
||||
GContext.OnEvent<EventStashDrop>().Subscribe(StashItemsByDrop).AddTo(_disposables);
|
||||
GContext.OnEvent<EventStashItems>().Subscribe(StashItems).AddTo(_disposables);
|
||||
GContext.OnEvent<EventStashDropList>().Subscribe(StashItemsByDropList).AddTo(_disposables);
|
||||
GContext.OnEvent<EventStashItem>().Subscribe(e => StashItem(e.Item)).AddTo(_disposables);
|
||||
}
|
||||
|
||||
public void DisposeSubscriptions()
|
||||
{
|
||||
_disposables.Dispose();
|
||||
_disposables = null;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_items = new List<ItemData>();
|
||||
//_items.Clear();
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
Debug.Log("[DeferredRewardStashService] Flush.");
|
||||
string textValue = LocalizationMgr.GetText("UI_MiniBattlePass_DivePopupPanel_8");
|
||||
RewardType rewardType = RewardType.FishBoxFly;
|
||||
if (IsEmpty)
|
||||
{
|
||||
rewardType = RewardType.FishBoxFlyRestore;
|
||||
textValue = LocalizationMgr.GetText("UI_FishingRewardPanel_101042");
|
||||
LoadData();
|
||||
}
|
||||
if (IsEmpty)
|
||||
return;
|
||||
ShowData showData = new ShowData(_items, rewardType);
|
||||
showData.textValue = textValue;
|
||||
//UI_FishingRewardPanel_101041
|
||||
GContext.Publish(showData);
|
||||
_playerItemData.AddItem(_items);
|
||||
Reset();
|
||||
UploadData();
|
||||
}
|
||||
|
||||
private void StashItemsByDropList(EventStashDropList e)
|
||||
{
|
||||
foreach (var dropId in e.DropList)
|
||||
{
|
||||
var items = _playerItemData.GetItemDataByDropId(dropId);
|
||||
foreach (var item in items)
|
||||
{
|
||||
StashItem(item);
|
||||
}
|
||||
}
|
||||
UploadData();
|
||||
}
|
||||
|
||||
private void StashItemsByDrop(EventStashDrop e)
|
||||
{
|
||||
var items = _playerItemData.GetItemDataByDropId(e.DropId);
|
||||
foreach (var item in items)
|
||||
{
|
||||
StashItem(item);
|
||||
}
|
||||
UploadData();
|
||||
}
|
||||
|
||||
private void StashItems(EventStashItems e)
|
||||
{
|
||||
var items = e.Items;
|
||||
foreach (var item in items)
|
||||
{
|
||||
StashItem(item);
|
||||
}
|
||||
UploadData();
|
||||
}
|
||||
|
||||
private void StashItem(ItemData item)
|
||||
{
|
||||
if (!_itemTable.DataMap.ContainsKey(item.id))
|
||||
{
|
||||
//Debug.LogError($"Item id {item.id} not found in item table.");
|
||||
return;
|
||||
}
|
||||
// Debug.Log($"[RewardStash] Item {item.id} * {item.count} Stashed.");
|
||||
var itemDropPackageItems = GetItemDropPackageItemList(item);
|
||||
if (itemDropPackageItems != null && itemDropPackageItems.Count > 0)
|
||||
{
|
||||
foreach (var dropItem in itemDropPackageItems)
|
||||
{
|
||||
_items.Add(dropItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_items.Add(item);
|
||||
}
|
||||
|
||||
UploadData();
|
||||
// _playerItemData.AddItem(item);
|
||||
}
|
||||
List<ItemData> GetItemDropPackageItemList(ItemData itemData)
|
||||
{
|
||||
Item item = _itemTable.GetOrDefault(itemData.id);
|
||||
if (item.Type == 9)
|
||||
{
|
||||
switch (item.SubType)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
case 4:
|
||||
case 7:
|
||||
return _playerItemData.GetItemDropPackageItemList(item.RedirectID, itemData.count);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private string Serialize()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var item in _items)
|
||||
sb.Append(item.id + Comma + (int)item.count + Splitter);
|
||||
if (sb.Length > 0)
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private List<ItemData> Deserialize(string s)
|
||||
{
|
||||
if (s == null || s == "")
|
||||
return new List<ItemData>();
|
||||
var items = s.Split(Splitter);
|
||||
var res = new List<ItemData>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var split = item.Split(Comma);
|
||||
if (split.Length != 2)
|
||||
{
|
||||
Debug.LogWarning($"[DeferredRewardStashService]Wrong amount of parameters in \"{item}\".");
|
||||
continue;
|
||||
}
|
||||
var id = int.Parse(split[0]);
|
||||
var count = int.Parse(split[1]);
|
||||
var itemData = new ItemData(id, count);
|
||||
res.Add(itemData);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void UploadData()
|
||||
{
|
||||
var s = Serialize();
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
||||
}
|
||||
|
||||
public void LoadData()
|
||||
{
|
||||
Reset();
|
||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return;
|
||||
_items = Deserialize(s);
|
||||
}
|
||||
|
||||
public class EventStashItems
|
||||
{
|
||||
public List<ItemData> Items;
|
||||
}
|
||||
|
||||
public class EventStashDrop
|
||||
{
|
||||
public int DropId;
|
||||
}
|
||||
|
||||
public class EventStashDropList
|
||||
{
|
||||
public List<int> DropList;
|
||||
}
|
||||
|
||||
public class EventStashItem
|
||||
{
|
||||
public ItemData Item;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/DeferredRewardStashService.cs.meta
Normal file
11
Assets/Scripts/Services/DeferredRewardStashService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8129be316bb57dd4088e9d09a62d7635
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Scripts/Services/DevAdsService.cs
Normal file
23
Assets/Scripts/Services/DevAdsService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using asap.core;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class DevAdsService : IAdsService
|
||||
{
|
||||
public void Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ShowRewarded(AdvertPopupType advertPopupType = AdvertPopupType.Shop)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
GContext.Publish(new AdsResult() { Result = 0, Type = advertPopupType });
|
||||
|
||||
#else
|
||||
GContext.Publish(new AdsResult() { Result = 1, Type = advertPopupType });
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/DevAdsService.cs.meta
Normal file
11
Assets/Scripts/Services/DevAdsService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abae019c8e688304ba2e2e44aca21838
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
75
Assets/Scripts/Services/DevIAPService.cs
Normal file
75
Assets/Scripts/Services/DevIAPService.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
//using asap.core;
|
||||
//using cfg;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
public class DevIAPService : IIAPService
|
||||
{
|
||||
[Inject]
|
||||
public IRTService rts { get; set; }
|
||||
|
||||
private IDisposable disposable;
|
||||
|
||||
public async Task<IList<SKUDetail>> GetSKUs()
|
||||
{
|
||||
var IAPList = GContext.container.Resolve<Tables>().TbIAPItemList.DataList;
|
||||
var result = new List<SKUDetail>();
|
||||
foreach (var iap in IAPList)
|
||||
{
|
||||
result.Add(new SKUDetail
|
||||
{
|
||||
productId = iap.ProductId1,
|
||||
title = iap.ID.ToString(),
|
||||
price = $"US${iap.PaymentAmount}",
|
||||
});
|
||||
}
|
||||
await Awaiters.NextFrame;
|
||||
return result; ;
|
||||
}
|
||||
|
||||
|
||||
public async Task<PaymentInfo> Pay(Action<string> OnSuccessFromSdk,string replenishmentDataStr, SKUDetail sku, int count, float usdPrice, JObject extraPurcheInfo)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
return new PaymentInfo() { code = "0" };
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
disposable?.Dispose();
|
||||
disposable = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
|
||||
Release();
|
||||
disposable = rts.OnEvent<SC_OrderConfirmEvt>(OnOrderCompleted);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string,string>> GetOrderUnreceived()
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
return new Dictionary<string,string>();
|
||||
}
|
||||
|
||||
private void OnOrderCompleted(SC_OrderConfirmEvt evt)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[AggIAPService] OnOrderCompleted \r\n {evt}");
|
||||
}
|
||||
|
||||
public async Task<bool> ConfirmOrders(List<string> orderIDs)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/DevIAPService.cs.meta
Normal file
11
Assets/Scripts/Services/DevIAPService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 809159bc43d7ab1488ec42c23599e799
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
64
Assets/Scripts/Services/EmptyMailServices.cs
Normal file
64
Assets/Scripts/Services/EmptyMailServices.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class EmptyMailService : IInGameMailService
|
||||
{
|
||||
public bool IsUnlock{
|
||||
get{
|
||||
return false;
|
||||
}
|
||||
set{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DelMail(GameMail mail)
|
||||
{
|
||||
await Task.Yield();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DelMail(GameMail[] mails = null)
|
||||
{
|
||||
await Task.Yield();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task FetchMail()
|
||||
{
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
public IList<GameMail> GetAllMail()
|
||||
{
|
||||
return new List<GameMail>();
|
||||
}
|
||||
|
||||
public void Init() { }
|
||||
|
||||
public async Task<bool> MarkRead(GameMail mail)
|
||||
{
|
||||
await Task.Yield();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> MarkRead(GameMail[] mails = null)
|
||||
{
|
||||
await Task.Yield();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset() { }
|
||||
|
||||
public async Task<bool> TakeReward(GameMail mail) {
|
||||
await Task.Yield();
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> TakeReward(GameMail[] mails = null)
|
||||
{
|
||||
await Task.Yield();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/EmptyMailServices.cs.meta
Normal file
11
Assets/Scripts/Services/EmptyMailServices.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5fd7da63f4214e758117188a73fb779
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
51
Assets/Scripts/Services/FootPrintService.cs
Normal file
51
Assets/Scripts/Services/FootPrintService.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
public interface IFootPrintService
|
||||
{
|
||||
public EFootPrint FootPrint { get; }
|
||||
public void UpdateFootPrint(EFootPrint newState);
|
||||
public void UploadData();
|
||||
public void LoadData(string data);
|
||||
public bool HasFootPrint(EFootPrint state);
|
||||
}
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
public class FootPrintService : IFootPrintService
|
||||
{
|
||||
private EFootPrint _footPrint;
|
||||
public EFootPrint FootPrint => _footPrint;
|
||||
public void UpdateFootPrint(EFootPrint newState)
|
||||
{
|
||||
_footPrint |= newState;
|
||||
UploadData();
|
||||
}
|
||||
|
||||
public void UploadData()
|
||||
{
|
||||
var data = (ulong)_footPrint;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue("FootPrint", data.ToString());
|
||||
}
|
||||
|
||||
public void LoadData(string data)
|
||||
{
|
||||
_footPrint = (EFootPrint) ulong.Parse(data);
|
||||
}
|
||||
|
||||
public bool HasFootPrint(EFootPrint state)
|
||||
{
|
||||
return (_footPrint & state) == state;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Record Status. Max out at 64th record.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum EFootPrint : int
|
||||
{
|
||||
HasCommunityGuidancePanelBeenOpened = 1 << 0,
|
||||
IsFaceBookRewardClaimed = 1 << 1,
|
||||
IsInstagramRewardClaimed = 1 << 2,
|
||||
IsDiscordRewardClaimed = 1 << 3,
|
||||
IsTiktokRewardClaimed = 1 << 4,
|
||||
IsYouTubeRewardClaimed = 1 << 5,
|
||||
IsEventCanGuidePoped = 1 << 6,
|
||||
}
|
||||
11
Assets/Scripts/Services/FootPrintService.cs.meta
Normal file
11
Assets/Scripts/Services/FootPrintService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 682887235afb1d8458a63267fc985d0b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
166
Assets/Scripts/Services/FriendModel.cs
Normal file
166
Assets/Scripts/Services/FriendModel.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class BFriendInfo
|
||||
{
|
||||
public string PlayFabId { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string AvatarUrl { get; set; }
|
||||
public int Level { get; set; }
|
||||
}
|
||||
|
||||
public class AddFriendReq
|
||||
{
|
||||
public BFriendInfo MySelf { get; set; }
|
||||
public int MyFriendCount { get; set; }
|
||||
public string FriendPlayFabId { get; set; }
|
||||
}
|
||||
|
||||
public class AddFriendResp
|
||||
{
|
||||
public int Code { get; set; } // 1:添加好友成功;-1:我的好友已满;-2:对方好友已满;-3:获取对方好友列表失败;-4:我加对方好友失败;-5:对方加我好友失败;2:已经添加过对方好友;
|
||||
public string Msg { get; set; }
|
||||
}
|
||||
|
||||
public class AcceptFriendReq
|
||||
{
|
||||
public int Status { get; set; } // 1:同意邀请;2:忽略
|
||||
public string PlayFabId { get; set; }
|
||||
public string FriendPlayFabId { get; set; }
|
||||
}
|
||||
|
||||
public class AcceptFriendResp
|
||||
{
|
||||
public int Code { get; set; } // 1:成功;2:忽略;-4:我加对方好友失败;-5:对方加我好友失败;
|
||||
public string Msg { get; set; }
|
||||
}
|
||||
|
||||
public class SearchFriendReq
|
||||
{
|
||||
public string PlayFabId { get; set; }
|
||||
}
|
||||
|
||||
public class SearchFriendResp
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Msg { get; set; }
|
||||
public BFriendInfo? Info { get; set; }
|
||||
}
|
||||
|
||||
public class GetHomePageReq
|
||||
{
|
||||
public string PlayFabId { get; set; }
|
||||
public int PageNo { get; set; }
|
||||
}
|
||||
|
||||
public class GetHomePageResp
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Msg { get; set; }
|
||||
public string[]? Friends { get; set; }
|
||||
public BFriendInfo[]? RecommendedList { get; set; }
|
||||
}
|
||||
|
||||
public class GetRecommendedFriendsReq
|
||||
{
|
||||
public string PlayFabId { get; set; }
|
||||
public int PageNo { get; set; }
|
||||
}
|
||||
|
||||
public class GetRecommendedFriendsResp
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Msg { get; set; }
|
||||
public BFriendInfo[]? RecommendedList { get; set; }
|
||||
}
|
||||
|
||||
public class GetInvitedListResp
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Msg { get; set; }
|
||||
public string[] Friends { get; set; }
|
||||
}
|
||||
|
||||
public class GetInvitedListCountResp
|
||||
{
|
||||
public int DeepLinkInvitedCount { get; set; }
|
||||
public int FriendInvitedCount { get; set; }
|
||||
}
|
||||
|
||||
public class NotifyFriendInvitedCount
|
||||
{
|
||||
public DateTime TimeStamp { get; set; }
|
||||
}
|
||||
|
||||
public class SocialFriendListChangedData
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class FriendRecommendedListData
|
||||
{
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
public List<FriendAddItemData> RecommendedList { get; set; }
|
||||
}
|
||||
|
||||
public class IsFriendWaitingForAcceptReq
|
||||
{
|
||||
public string PlayFabId { get; set; }
|
||||
public string FriendPlayFabId { get; set; }
|
||||
}
|
||||
|
||||
public class IsFriendWaitingForAcceptResp
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Msg { get; set; }
|
||||
}
|
||||
|
||||
public enum FriendAddPanelBackendOperationFromType
|
||||
{
|
||||
FromTypeInvalid,
|
||||
FromTypeInvited,
|
||||
FromTypeRecommended
|
||||
}
|
||||
|
||||
public class FriendHelper
|
||||
{
|
||||
public const int Friend_Add_Item_Type_Invited_TitleBar = 1;
|
||||
public const int Friend_Add_Item_Type_Invited_Item = 2;
|
||||
public const int Friend_Add_Item_Type_Recommended_TitleBar = 3;
|
||||
public const int Friend_Add_Item_Type_Recommended_Item = 4;
|
||||
|
||||
public const int Code_OK = 1; // 消息成功
|
||||
public const int Code_Encounter_Fatal_Error = -1000; // 遇到致命问题,一般是遇到异常
|
||||
|
||||
public const int Code_SearchFriend_PlayFab_Error = -1; // 搜索好友遇到PlayFab问题,失败
|
||||
|
||||
public const int Code_AcceptFriend_IAddFriend_Failed_PlayFabError = -4; // 同意好友邀请,我加对方失败,PlayFab问题
|
||||
public const int Code_AcceptFriend_FriendAddMe_Failed_PlayFabError = -5; // 同意好友邀请,对方加我失败,PlayFab问题
|
||||
public const int Code_AcceptFriend_Ignore_OK = 2; // 忽略好友邀请成功
|
||||
|
||||
public const int Code_AddFriend_AddFriendDirectly_OK = 1; // 邀请好友,对方也要邀请过自己,直接互相加为好友
|
||||
public const int Code_AddFriend_HaveAddedBefore_OK = 2; // 邀请好友,已经邀请过对方为好友
|
||||
public const int Code_AddFriend_IHaveNoLimit = -1; // 邀请好友,我的好友列表已满,我没有额度
|
||||
public const int Code_AddFriend_FriendHaveNoLimit = -2; // 邀请好友,对方的好友列表已满,好友没有额度
|
||||
public const int Code_AddFriend_GetFriendList_Failed_PlayFabError = -3; // 邀请好友,获取好友列表失败,PlayFab问题
|
||||
public const int Code_AddFriend_IAddFriend_Failed_PlayFabError = -4; // 邀请好友,我加对方失败,PlayFab问题
|
||||
public const int Code_AddFriend_FriendAddMe_Failed_PlayFabError = -5; // 邀请好友,对方加我失败,PlayFab问题
|
||||
|
||||
public const int Code_IsFriendWaitingForAccept_Wrong = -1; // 当前用户不处于被邀请状态
|
||||
|
||||
public const int Accept_Type_Accept = 1; // 接受好友邀请
|
||||
public const int Accept_Type_Ignore = 2; // 忽略好友邀请
|
||||
|
||||
public const string FriendRecommendedListDataKey = "FRLDK"; // 推荐好友列表存储本地用的Key
|
||||
|
||||
public static void FixBFriendInfoData(BFriendInfo info)
|
||||
{
|
||||
if (info == null) return;
|
||||
if (info.AvatarUrl == null) info.AvatarUrl = "";
|
||||
if (info.DisplayName == null) info.DisplayName = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/FriendModel.cs.meta
Normal file
11
Assets/Scripts/Services/FriendModel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce4195e0835eb5243bd0381adb869894
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
472
Assets/Scripts/Services/FriendService.cs
Normal file
472
Assets/Scripts/Services/FriendService.cs
Normal file
@@ -0,0 +1,472 @@
|
||||
using asap.core;
|
||||
using asap.playfab.async;
|
||||
using GameCore;
|
||||
using PlayFab.ClientModels;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class FriendService
|
||||
{
|
||||
[Inject]
|
||||
public IUserService userService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public ICustomServerMgr customServerMgr { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IRTService rts { get; set; }
|
||||
|
||||
[Inject]
|
||||
public cfg.Tables tables { get; set; }
|
||||
|
||||
public const string InviteLinkRewardCountKey = "InviteLinkRewardCount";
|
||||
IDisposable linkCompletedDisposable;
|
||||
|
||||
public void GetFriendData()
|
||||
{
|
||||
//GetFriendLeaderboard();
|
||||
GetFriendList();
|
||||
//GetInvitedListCount();
|
||||
}
|
||||
|
||||
#region 邀请Link相关
|
||||
public int InviteLinkNumber { private set; get; }
|
||||
int InviteLinkRewardCount = 0;
|
||||
|
||||
|
||||
void SetLinkAwardData()
|
||||
{
|
||||
List<cfg.Invite> invites = tables.TbInvite.DataList;
|
||||
//已经领取奖励的数量
|
||||
string receiveRewardCountStr = PlayFabMgr.Instance.GetLocalData(InviteLinkRewardCountKey);
|
||||
int.TryParse(receiveRewardCountStr, out InviteLinkRewardCount);
|
||||
int canRewardCount = InviteLinkRewardCount;
|
||||
for (int i = InviteLinkRewardCount; i < invites.Count; i++)
|
||||
{
|
||||
//领取奖励
|
||||
if (invites[i].NumInvite <= InviteLinkNumber)
|
||||
{
|
||||
canRewardCount = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Invite, canRewardCount > InviteLinkRewardCount);
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("invite_increase"))
|
||||
{
|
||||
e.AddContent("inviteprogress", InviteLinkNumber)
|
||||
.AddContent("rewardprogress", InviteLinkRewardCount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public int OnReceiveLinkAward()
|
||||
{
|
||||
int canRewardCount = InviteLinkRewardCount;
|
||||
List<cfg.Invite> invites = tables.TbInvite.DataList;
|
||||
List<int> DropIDs = new List<int>();
|
||||
for (int i = InviteLinkRewardCount; i < invites.Count; i++)
|
||||
{
|
||||
//领取奖励
|
||||
if (invites[i].NumInvite <= InviteLinkNumber)
|
||||
{
|
||||
canRewardCount = i + 1;
|
||||
DropIDs.Add(invites[i].DropID);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (InviteLinkRewardCount != canRewardCount)
|
||||
{
|
||||
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(DropIDs, scope: 1);
|
||||
GContext.Publish(new ShowData());
|
||||
InviteLinkRewardCount = canRewardCount;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(InviteLinkRewardCountKey, InviteLinkRewardCount.ToString());
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Invite, false);
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("invite_reward"))
|
||||
{
|
||||
e.AddContent("inviteprogress", InviteLinkNumber)
|
||||
.AddContent("rewardprogress", InviteLinkRewardCount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return InviteLinkRewardCount;
|
||||
}
|
||||
#endregion 邀请Link相关
|
||||
|
||||
#region 判断是否好友
|
||||
public bool IsFriend(string playFabID)
|
||||
{
|
||||
if (m_FriendList == null || m_FriendList.Count < 1 || string.IsNullOrEmpty(playFabID)) return false;
|
||||
|
||||
foreach (var friend in m_FriendList)
|
||||
{
|
||||
if (friend.playFabId.Equals(playFabID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 获取好友列表
|
||||
private List<LeadboardItemData> m_FriendList = new List<LeadboardItemData>();
|
||||
public List<LeadboardItemData> FriendList { get { return m_FriendList; } }
|
||||
public async void GetFriendLeaderboard()
|
||||
{
|
||||
string leaderboardNaem = LeadboardData.leadboardLevelName;
|
||||
int maxCount = 100;
|
||||
|
||||
GetFriendLeaderboardRequest getFriendLeaderboardRequest =
|
||||
new GetFriendLeaderboardRequest()
|
||||
{
|
||||
StartPosition = 0,
|
||||
StatisticName = leaderboardNaem,
|
||||
MaxResultsCount = maxCount,
|
||||
ProfileConstraints = new PlayerProfileViewConstraints()
|
||||
{
|
||||
ShowAvatarUrl = true,
|
||||
ShowDisplayName = true,
|
||||
ShowLastLogin = true
|
||||
}
|
||||
};
|
||||
var result =
|
||||
await PlayFabClientAsyncAPI.GetFriendLeaderboardAsync(getFriendLeaderboardRequest);
|
||||
var leaderboard = result?.Leaderboard;
|
||||
if (leaderboard != null)
|
||||
{
|
||||
int count = leaderboard.Count;
|
||||
if (count > 0)
|
||||
{
|
||||
string userId = GContext.container.Resolve<IUserService>().UserId;
|
||||
List<LeadboardItemData> list = new List<LeadboardItemData>();
|
||||
|
||||
foreach (var item in leaderboard)
|
||||
{
|
||||
if (userId.Equals(item.PlayFabId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LeadboardItemData friend = new LeadboardItemData();
|
||||
if (string.IsNullOrEmpty(item.Profile.DisplayName))
|
||||
{
|
||||
item.Profile.DisplayName = userService.GetDefaultName(item.PlayFabId);
|
||||
}
|
||||
//item.StatValue = item.StatValue / LeadboardData.LV_MODELING;
|
||||
friend.SetData(item);
|
||||
list.Add(friend);
|
||||
|
||||
userService.SetPlayInfo(item.PlayFabId, item.Profile.DisplayName, item.Profile.AvatarUrl);
|
||||
}
|
||||
m_FriendList = list;
|
||||
#if AGG
|
||||
GEvent.SetProp("friends_count", count);
|
||||
GEvent.SetUserProp("friends_count", count);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
public async void GetFriendList()
|
||||
{
|
||||
GetFriendsListRequest getFriendsListRequest = new GetFriendsListRequest
|
||||
{
|
||||
ProfileConstraints = new PlayerProfileViewConstraints()
|
||||
{
|
||||
ShowAvatarUrl = true,
|
||||
ShowDisplayName = true,
|
||||
ShowStatistics = true,
|
||||
ShowLastLogin = true,
|
||||
}
|
||||
};
|
||||
|
||||
var result = await PlayFabClientAsyncAPI.GetFriendsListAsync(getFriendsListRequest);
|
||||
var list = result?.Friends;
|
||||
if (list != null)
|
||||
{
|
||||
string userId = GContext.container.Resolve<IUserService>().UserId;
|
||||
List<LeadboardItemData> leadboardList = new List<LeadboardItemData>();
|
||||
int count = list.Count;
|
||||
foreach (FriendInfo friendInfo in list)
|
||||
{
|
||||
if (friendInfo.Profile == null) continue;
|
||||
var listStatistic = friendInfo.Profile.Statistics;
|
||||
if (listStatistic == null) continue;
|
||||
|
||||
if (userId.Equals(friendInfo.FriendPlayFabId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(friendInfo.Profile.DisplayName))
|
||||
{
|
||||
friendInfo.Profile.DisplayName = userService.GetDefaultName(friendInfo.FriendPlayFabId);
|
||||
}
|
||||
|
||||
int level = 0;
|
||||
foreach (var item in listStatistic)
|
||||
{
|
||||
if (item == null) continue;
|
||||
if (item.Name == LeadboardData.leadboardLevelName)
|
||||
{
|
||||
//level = item.Value / LeadboardData.LV_MODELING;
|
||||
level = item.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
userService.SetPlayInfo(friendInfo.FriendPlayFabId, friendInfo.Profile.DisplayName, friendInfo.Profile.AvatarUrl);
|
||||
|
||||
LeadboardItemData friendData = new LeadboardItemData();
|
||||
friendData.playFabId = friendInfo.FriendPlayFabId;
|
||||
friendData.displayName = friendInfo.Profile.DisplayName;
|
||||
friendData.avatarUrl = friendInfo.Profile.AvatarUrl;
|
||||
friendData.LastLogin = friendInfo.Profile.LastLogin;
|
||||
friendData.value = level;
|
||||
friendData.position = 0;
|
||||
friendData.rank = 0;
|
||||
|
||||
leadboardList.Add(friendData);
|
||||
}
|
||||
|
||||
leadboardList.Sort((item1, item2) =>
|
||||
{
|
||||
return item2.value.CompareTo(item1.value);
|
||||
});
|
||||
|
||||
count = leadboardList.Count;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
LeadboardItemData itemData = leadboardList[i];
|
||||
itemData.position = i;
|
||||
itemData.rank = i + 1;
|
||||
}
|
||||
|
||||
m_FriendList = leadboardList;
|
||||
|
||||
GContext.Publish<SocialFriendListChangedData>(new SocialFriendListChangedData());
|
||||
#if AGG
|
||||
GEvent.SetProp("friends_count", count);
|
||||
GEvent.SetUserProp("friends_count", count);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 邀请好友
|
||||
public async Task<string> AddFriend(string playfabID)
|
||||
{
|
||||
int count = m_FriendList.Count;
|
||||
AddFriendReq getFriendListReq = new AddFriendReq()
|
||||
{
|
||||
MySelf = new BFriendInfo
|
||||
{
|
||||
PlayFabId = userService.UserId,
|
||||
AvatarUrl = userService.AvatarUrl,
|
||||
DisplayName = userService.DisplayName,
|
||||
Level = GContext.container.Resolve<PlayerData>().lv
|
||||
},
|
||||
MyFriendCount = count,
|
||||
FriendPlayFabId = playfabID,
|
||||
};
|
||||
|
||||
FriendHelper.FixBFriendInfoData(getFriendListReq.MySelf);
|
||||
|
||||
return await customServerMgr.FriendRequest("AddFriend", getFriendListReq);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 搜索好友
|
||||
public async Task<string> SearchFriend(string playfabID)
|
||||
{
|
||||
SearchFriendReq searchFriendReq = new SearchFriendReq()
|
||||
{
|
||||
PlayFabId = playfabID
|
||||
};
|
||||
|
||||
return await customServerMgr.FriendRequest("SearchFriend", searchFriendReq);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 接受好友邀请/忽略好友邀请
|
||||
// status:1:同意邀请;2:忽略, playfabID 接受/忽略 friendPlayFabID 的邀请
|
||||
public async Task<string> AcceptFriend(int status, string playfabID, string friendPlayFabID)
|
||||
{
|
||||
AcceptFriendReq acceptFriendReq = new AcceptFriendReq()
|
||||
{
|
||||
Status = status,
|
||||
PlayFabId = playfabID,
|
||||
FriendPlayFabId = friendPlayFabID
|
||||
};
|
||||
|
||||
return await customServerMgr.FriendRequest("AcceptFriend", acceptFriendReq);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 好友主页
|
||||
public async Task<string> GetHomePage(string playfabID, int pageNo)
|
||||
{
|
||||
GetHomePageReq getHomePageReq = new GetHomePageReq()
|
||||
{
|
||||
PlayFabId = playfabID,
|
||||
PageNo = pageNo
|
||||
};
|
||||
|
||||
return await customServerMgr.FriendRequest("GetHomePage", getHomePageReq);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 好友邀请列表&推荐列表
|
||||
public async Task<string> GetRecommendedFriends(string playfabID, int pageNo)
|
||||
{
|
||||
GetRecommendedFriendsReq acceptFriendReq = new GetRecommendedFriendsReq()
|
||||
{
|
||||
PlayFabId = playfabID,
|
||||
PageNo = pageNo
|
||||
};
|
||||
|
||||
return await customServerMgr.FriendRequest("GetRecommendedFriends", acceptFriendReq);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 获取申请成为我的朋友的列表
|
||||
public async Task<string> GetInvitedList()
|
||||
{
|
||||
return await customServerMgr.FriendRequest("GetInvitedList", "");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 获取邀请自己的列表数量
|
||||
public async void GetInvitedListCount()
|
||||
{
|
||||
string json = await customServerMgr.FriendRequest("GetInvitedListCount", "");
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
GetInvitedListCountResp getRecommendedFriendsResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetInvitedListCountResp>(json);
|
||||
if (getRecommendedFriendsResp != null)
|
||||
{
|
||||
if (getRecommendedFriendsResp.FriendInvitedCount >= 0)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Friend_Add, getRecommendedFriendsResp.FriendInvitedCount > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[FriendService::GetInvitedListCount] FriendInvitedCount Failed:");
|
||||
}
|
||||
|
||||
if (getRecommendedFriendsResp.DeepLinkInvitedCount > 0)
|
||||
{
|
||||
InviteLinkNumber = getRecommendedFriendsResp.DeepLinkInvitedCount;
|
||||
SetLinkAwardData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 邀请码处理
|
||||
const string chars = "0M4KL3FZSTG8XCY5E6VW179A2UBDHQRIJNOP";
|
||||
readonly ulong baseLength = (ulong)chars.Length;
|
||||
public string EncryptUlongToInvitationCode(ulong number)
|
||||
{
|
||||
StringBuilder encoded = new StringBuilder();
|
||||
while (number > 0)
|
||||
{
|
||||
encoded.Insert(0, chars[(int)(number % baseLength)]);
|
||||
number /= baseLength;
|
||||
}
|
||||
return encoded.ToString().PadLeft(14, chars[0]); // Pad with '0' if necessary
|
||||
}
|
||||
public ulong DecryptInvitationCodeToUlong(string invitationCode)
|
||||
{
|
||||
ulong number = 0;
|
||||
foreach (char c in invitationCode)
|
||||
{
|
||||
number *= baseLength;
|
||||
number += (ulong)chars.IndexOf(c);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
public string GetInvitationCodeByPlayFabID(string playFabID)
|
||||
{
|
||||
ulong code = Convert.ToUInt64(playFabID, 16);
|
||||
string invitationCode = EncryptUlongToInvitationCode(code);
|
||||
|
||||
return InsertFormat(invitationCode, 3, "-");
|
||||
}
|
||||
public string InsertFormat(string input, int interval, string value)
|
||||
{
|
||||
for (int i = interval; i < input.Length; i += interval + 1)
|
||||
input = input.Insert(i, value);
|
||||
return input;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获得X天内登录过的活跃好友数量
|
||||
|
||||
public int GetActiveFriendCount(int xDays)
|
||||
{
|
||||
return FriendList.Count(data =>
|
||||
data.LastLogin is not null &&
|
||||
ZZTimeHelper.UtcNow() - data.LastLogin <= TimeSpan.FromDays(xDays));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 判断当前用户是否处于被邀请状态
|
||||
public async Task<string> IsFriendWaitingForAccept(string playfabID, string friendPlayfabID)
|
||||
{
|
||||
IsFriendWaitingForAcceptReq req = new IsFriendWaitingForAcceptReq()
|
||||
{
|
||||
PlayFabId = playfabID,
|
||||
FriendPlayFabId = friendPlayfabID
|
||||
};
|
||||
|
||||
return await customServerMgr.FriendRequest("IsFriendWaitingForAccept", req);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 后台操作
|
||||
List<FriendAddPanelBackendOperation> m_FriendAddPanelBackendOperationList = new List<FriendAddPanelBackendOperation>();
|
||||
public void StartInvite(string playfabID)
|
||||
{
|
||||
var backendOperation = new FriendAddPanelBackendOperation();
|
||||
m_FriendAddPanelBackendOperationList.Add(backendOperation);
|
||||
backendOperation.StartInvite(playfabID, OnInviteCallback);
|
||||
}
|
||||
public void OnInviteCallback(FriendAddPanelBackendOperation backendOperation, string playfabID, int code)
|
||||
{
|
||||
if (backendOperation != null)
|
||||
{
|
||||
backendOperation.Clear();
|
||||
m_FriendAddPanelBackendOperationList.Remove(backendOperation);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Release()
|
||||
{
|
||||
linkCompletedDisposable?.Dispose();
|
||||
linkCompletedDisposable = null;
|
||||
|
||||
m_FriendAddPanelBackendOperationList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/FriendService.cs.meta
Normal file
11
Assets/Scripts/Services/FriendService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f866992db9bbb94c950f0784a239314
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Assets/Scripts/Services/HeartBeat.cs
Normal file
84
Assets/Scripts/Services/HeartBeat.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using tysdk;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
|
||||
public class HeartBeat
|
||||
{
|
||||
[Inject]
|
||||
public IStageService stageService {get; set;}
|
||||
|
||||
[Inject]
|
||||
public IConfig config {get; set;}
|
||||
|
||||
private IDisposable disposable;
|
||||
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
//UnityEngine.Debug.Log("HeartBeat Init");
|
||||
disposable = GContext.OnEvent<StageLoadEvent>()
|
||||
.Where(e => e.state == EStageLoadState.Loaded && e.stageId == "FishingStage")
|
||||
.Subscribe(OnFishingStageLoad);
|
||||
Application.focusChanged += OnFocusChanged;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
disposable.Dispose();
|
||||
Application.focusChanged -= OnFocusChanged;
|
||||
if(tokenSource != null)
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFocusChanged(bool focused)
|
||||
{
|
||||
if(focused)
|
||||
{
|
||||
if(tokenSource == null && stageService.GetStage("FishingStage") != null)
|
||||
{
|
||||
tokenSource = new CancellationTokenSource();
|
||||
StartHeartBeat(tokenSource.Token);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tokenSource != null)
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFishingStageLoad(StageLoadEvent @event)
|
||||
{
|
||||
disposable.Dispose();
|
||||
tokenSource = new CancellationTokenSource();
|
||||
StartHeartBeat(tokenSource.Token);
|
||||
//UnityEngine.Debug.Log("HeartBeat Start");
|
||||
}
|
||||
|
||||
private async void StartHeartBeat(CancellationToken token)
|
||||
{
|
||||
int interval =(int) config.GetFloat("HeartBeat", 60);
|
||||
try{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
using(var e = GEvent.TackEvent("HeartBeat", gaSend : false)){
|
||||
e.AddContent("FPS", game.RootCtx.fps);
|
||||
}
|
||||
await Task.Delay(interval * 1000);
|
||||
//UnityEngine.Debug.Log("HeartBeat");
|
||||
}
|
||||
}
|
||||
catch (System.Exception){}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/HeartBeat.cs.meta
Normal file
11
Assets/Scripts/Services/HeartBeat.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 466ef7c2f07964b4b86d43110a310300
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Assets/Scripts/Services/IAPService.cs
Normal file
76
Assets/Scripts/Services/IAPService.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public interface IIAPService
|
||||
{
|
||||
const string UnConfirmedOrder_key = "UnConfirmedOrder";
|
||||
|
||||
Task<IList<SKUDetail>> GetSKUs();
|
||||
|
||||
Task<PaymentInfo> Pay(Action<string> OnSuccessFromSdk,string replenishmentDataStr, SKUDetail sku, int count, float usdPrice, JObject extraPurcheData);
|
||||
|
||||
Task<Dictionary<string, string>> GetOrderUnreceived();
|
||||
|
||||
Task<bool> ConfirmOrders(List<string> orderIDs);
|
||||
|
||||
void Release();
|
||||
void Init();
|
||||
}
|
||||
|
||||
public class SC_OrderConfirmEvt
|
||||
{
|
||||
public bool isSuccess;
|
||||
public string orderId;
|
||||
public string productId;
|
||||
public string errorMessage;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class CS_OrderConfirmEvt
|
||||
{
|
||||
public string orderId;
|
||||
public string sdkUserId;
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class CS_OrdersConfirmEvt
|
||||
{
|
||||
public List<string> orderIds { get; set; }
|
||||
public string sdkUserId { get; set; }
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class CS_OrderUnreceived
|
||||
{
|
||||
public string sdkUserId;
|
||||
public bool customData;
|
||||
public string ToJson()
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class SC_OrderUnreceived
|
||||
{
|
||||
public Dictionary<string,string> orders { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Services/IAPService.cs.meta
Normal file
11
Assets/Scripts/Services/IAPService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08e674316bfbd864dac8d05610beb4af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/Services/IAdsService.cs
Normal file
10
Assets/Scripts/Services/IAdsService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
namespace game
|
||||
{
|
||||
public interface IAdsService
|
||||
{
|
||||
void Init();
|
||||
//Task<bool> ShowBanner();
|
||||
void ShowRewarded(AdvertPopupType AadvertPopupType);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/IAdsService.cs.meta
Normal file
11
Assets/Scripts/Services/IAdsService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 094f3f166e0f2fc4bbba3ba84c459138
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Scripts/Services/IChatService.cs
Normal file
25
Assets/Scripts/Services/IChatService.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public interface IChatService
|
||||
{
|
||||
//Task LoginRTM(int timeOut); //登录云上曲率服务器
|
||||
void WaitingForLogin();
|
||||
void GetConversationList(long groupConversationId); //登出云上曲率服务器
|
||||
Task<HashSet<long>> GetOnlineUsers(List<long> playerIDs); //获取在线用户
|
||||
ChatChatData GetGroupChat();
|
||||
void OnQuit();
|
||||
void InitChatData();
|
||||
void NextPage(); //下一页 上滑
|
||||
string[] ParseChat(string chat); //解析消息
|
||||
void SendTxTMessage(string chat); //发送文本消息
|
||||
void SendEmoji(string chat); //发送表情
|
||||
void SendSystemMessage(string chat); //发送系统提示
|
||||
void SendSystemMessage2(string chat); //发送系统提示
|
||||
Task<long> SendGetPhotoMessage(string chat); //发送求助帖
|
||||
Task<long> SendHelpEnergyMessage(int itemId); //发送体力求助帖
|
||||
Task<bool> TextAudit(string text); //审核文本
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/IChatService.cs.meta
Normal file
11
Assets/Scripts/Services/IChatService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8b86a5f1bb8e034eb7552c01cc3d0b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
162
Assets/Scripts/Services/ILocalNotificationService.cs
Normal file
162
Assets/Scripts/Services/ILocalNotificationService.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Unity.Notifications;
|
||||
using asap.core;
|
||||
using GameCore;
|
||||
using System.Linq;
|
||||
using cfg;
|
||||
using UniRx;
|
||||
using Notification = Unity.Notifications.Notification;
|
||||
|
||||
public interface ILocalNotificationService
|
||||
{
|
||||
public System.Threading.Tasks.Task Init();
|
||||
public bool IsNoticeOpen { get; }
|
||||
public void OpenSettings();
|
||||
public void ScheduleOneTimeNotification(int notificationID, DateTime fireTime, string title, string text);
|
||||
public void ScheduleDailyNotification(int notificationID, DateTime fireTime, string title, string text);
|
||||
public void ClearAllNotification();
|
||||
public void ClearNotification(int notificationID);
|
||||
public void ScheduleDefaultNotification();
|
||||
}
|
||||
|
||||
|
||||
public class LocalNotificationService : ILocalNotificationService
|
||||
{
|
||||
private List<cfg.Notification> _notificationList;
|
||||
|
||||
#if UNITY_ANDROID
|
||||
public bool IsNoticeOpen =>
|
||||
Unity.Notifications.Android.AndroidNotificationCenter.UserPermissionToPost ==
|
||||
Unity.Notifications.Android.PermissionStatus.Allowed;
|
||||
#else
|
||||
public bool IsNoticeOpen => Unity.Notifications.iOS.iOSNotificationCenter.GetNotificationSettings().AuthorizationStatus ==
|
||||
Unity.Notifications.iOS.AuthorizationStatus.Authorized;
|
||||
#endif
|
||||
|
||||
|
||||
public LocalNotificationService()
|
||||
{
|
||||
_notificationList = GContext.container.Resolve<cfg.Tables>().TbNotification.DataList;
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task Init()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
await System.Threading.Tasks.Task.Yield();
|
||||
#else
|
||||
Debug.Log("[LocalNotificationService::Init]");
|
||||
|
||||
var args = NotificationCenterArgs.Default;
|
||||
args.AndroidChannelId = "default";
|
||||
args.AndroidChannelName = "Notifications";
|
||||
args.AndroidChannelDescription = "Main notifications";
|
||||
NotificationCenter.Initialize(args);
|
||||
|
||||
Debug.Log("[LocalNotificationService::Init] Channel Inited");
|
||||
|
||||
await NotificationCenter.RequestPermission();
|
||||
ScheduleDefaultNotification();
|
||||
GContext.OnEvent<EventRankData>().Subscribe(ScheduleRankNotification);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ClearAllNotification()
|
||||
{
|
||||
rankNotifyScheduled = false;
|
||||
NotificationCenter.CancelAllScheduledNotifications();
|
||||
NotificationCenter.CancelAllDeliveredNotifications();
|
||||
}
|
||||
|
||||
public void ClearNotification(int notificationID)
|
||||
{
|
||||
if (!IsNoticeOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationCenter.CancelScheduledNotification(notificationID);
|
||||
NotificationCenter.CancelDeliveredNotification(notificationID);
|
||||
}
|
||||
|
||||
public void OpenSettings()
|
||||
{
|
||||
NotificationCenter.OpenNotificationSettings();
|
||||
}
|
||||
|
||||
public void ScheduleDailyNotification(int notificationID, DateTime fireTime, string title, string text)
|
||||
{
|
||||
if (!IsNoticeOpen)
|
||||
{
|
||||
Debug.Log("[LocalNotificationService::ScheduleDailyNotification] Not Open");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationCenter.CancelScheduledNotification(notificationID);
|
||||
NotificationCenter.CancelDeliveredNotification(notificationID);
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = title,
|
||||
Text = text,
|
||||
Identifier = notificationID
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification,
|
||||
new NotificationDateTimeSchedule(fireTime, NotificationRepeatInterval.Daily));
|
||||
}
|
||||
|
||||
public void ScheduleOneTimeNotification(int notificationID, DateTime fireTime, string title, string text)
|
||||
{
|
||||
if (!IsNoticeOpen) return;
|
||||
NotificationCenter.CancelScheduledNotification(notificationID);
|
||||
NotificationCenter.CancelDeliveredNotification(notificationID);
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = title,
|
||||
Text = text,
|
||||
Identifier = notificationID
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification,
|
||||
new NotificationDateTimeSchedule(fireTime, NotificationRepeatInterval.OneTime));
|
||||
}
|
||||
|
||||
public void ScheduleDefaultNotification()
|
||||
{
|
||||
if (!IsNoticeOpen) return;
|
||||
Debug.Log("[LocalNotificationService::SendNotification] Daily");
|
||||
var dailyNotification = _notificationList.Where(x => x.Type == 0);
|
||||
foreach (var item in dailyNotification)
|
||||
{
|
||||
var dateTime = DateTime.SpecifyKind(DateTime.Parse(item.NotTime), DateTimeKind.Utc);
|
||||
ScheduleDailyNotification(item.ID, dateTime.ToLocalTime(), LocalizationMgr.GetText(item.Title_l10n_key),
|
||||
LocalizationMgr.GetText(item.Content_l10n_key));
|
||||
}
|
||||
|
||||
Debug.Log("[LocalNotificationService::SendNotification] Daily Done");
|
||||
}
|
||||
|
||||
private bool rankNotifyScheduled = false;
|
||||
|
||||
private void ScheduleRankNotification(EventRankData evt)
|
||||
{
|
||||
if (rankNotifyScheduled || !IsNoticeOpen) return;
|
||||
|
||||
Debug.Log("[LocalNotificationService::SendNotification] RankEvent");
|
||||
|
||||
var notification = _notificationList.FirstOrDefault(x => x.Type == 1);
|
||||
if (notification == null) return;
|
||||
|
||||
// var fireTime = ConvertTools.GetDateTimeYMD(ZZTimeHelper.UtcNow().UtcNowOffset());
|
||||
// var dayTime = DateTime.Parse(notification.NotTime);
|
||||
// fireTime = fireTime.AddDays(1).AddHours(dayTime.Hour).AddMinutes(dayTime.Minute).AddSeconds(dayTime.Second);
|
||||
var now = ZZTimeHelper.UtcNow();
|
||||
var fireTime = DateTime.SpecifyKind(DateTime.Parse(notification.NotTime), DateTimeKind.Utc);
|
||||
fireTime = fireTime.AddDays(now <= fireTime ? 0 : 1);
|
||||
Debug.Log($"<color=#00d6b9>Try schedule Rank Notification at {fireTime}.</color>");
|
||||
ScheduleOneTimeNotification(notification.ID, fireTime.ToLocalTime(),
|
||||
LocalizationMgr.GetText(notification.Title_l10n_key),
|
||||
LocalizationMgr.GetText(notification.Content_l10n_key));
|
||||
rankNotifyScheduled = true;
|
||||
Debug.Log("[LocalNotificationService::SendRankEventNotification] ");
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/ILocalNotificationService.cs.meta
Normal file
11
Assets/Scripts/Services/ILocalNotificationService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d7f6df73c7a854499dd68c91426261a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Scripts/Services/IReportService.cs
Normal file
23
Assets/Scripts/Services/IReportService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
public enum ReportDataType : byte
|
||||
{
|
||||
Bomb = 0,
|
||||
Heist = 1,
|
||||
Picture = 2,
|
||||
Energy = 3,
|
||||
Club = 4,//redirectID 1:被踢出 2:会长被踢出 3:会长被踢出之后被任命4:被升职 5:被降职
|
||||
Aquarium = 5,
|
||||
}
|
||||
|
||||
public class ReportData
|
||||
{
|
||||
public ReportDataType type;
|
||||
public int id;
|
||||
public string playFabId;
|
||||
public string content { get; set; }
|
||||
}
|
||||
public interface IReportService
|
||||
{
|
||||
void AddReport(ReportData reportData);
|
||||
ReportData GetReportData();
|
||||
ReportData GetAquariumReportData();
|
||||
}
|
||||
11
Assets/Scripts/Services/IReportService.cs.meta
Normal file
11
Assets/Scripts/Services/IReportService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63ead682802fa954e9c5549277493756
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
416
Assets/Scripts/Services/InGameMail.cs
Normal file
416
Assets/Scripts/Services/InGameMail.cs
Normal file
@@ -0,0 +1,416 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GameCore;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
/// <summary>
|
||||
/// 邮件类型枚举
|
||||
/// </summary>
|
||||
public enum EMailType
|
||||
{
|
||||
Global,
|
||||
Personal,
|
||||
AutoDelivery,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮件状态标志枚举
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum EMailState
|
||||
{
|
||||
None = 1 << 0, // 通知未读
|
||||
HasRead = 1 << 1, // 已读通知
|
||||
RewardTaken = 1 << 2, // 奖励已领取,表示用户已经领取了通知中的奖励
|
||||
HasDeleted = 1 << 3, // 通知已删除
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 游戏内邮件服务接口
|
||||
/// </summary>
|
||||
public interface IInGameMailService
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否解锁邮件功能。
|
||||
/// </summary>
|
||||
bool IsUnlock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化邮件服务。
|
||||
/// </summary>
|
||||
void Init();
|
||||
|
||||
/// <summary>
|
||||
/// 重置邮件服务。
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取新邮件。
|
||||
/// </summary>
|
||||
/// <returns>一个任务,表示邮件获取操作。</returns>
|
||||
Task FetchMail();
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取所有游戏邮件。
|
||||
/// </summary>
|
||||
/// <returns>一个任务,包含一个列表,列表中包含所有游戏邮件。</returns>
|
||||
IList<GameMail> GetAllMail();
|
||||
|
||||
/// <summary>
|
||||
/// 异步标记指定邮件为已读。
|
||||
/// </summary>
|
||||
/// <param name="mail">要标记为已读的邮件。</param>
|
||||
/// <returns>一个任务,表示邮件标记操作是否成功。</returns>
|
||||
Task<bool> MarkRead(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 异步标记指定邮件为已读。
|
||||
/// </summary>
|
||||
/// <param name="mails">要标记为已读的邮件。null 标记搜有已读</param>
|
||||
/// <returns>一个任务,表示邮件标记操作是否成功。</returns>
|
||||
Task<bool> MarkRead(GameMail[] mails = null);
|
||||
|
||||
/// <summary>
|
||||
/// 异步删除指定邮件。
|
||||
/// </summary>
|
||||
/// <param name="mail">要删除的邮件。</param>
|
||||
/// <returns>一个任务,表示邮件删除操作是否成功。</returns>
|
||||
Task<bool> DelMail(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 异步删除指定邮件。
|
||||
/// </summary>
|
||||
/// <param name="mails">要删除的邮件。null 删除所有已读邮件</param>
|
||||
/// <returns>一个任务,表示邮件删除操作是否成功。</returns>
|
||||
Task<bool> DelMail(GameMail[] mails = null);
|
||||
|
||||
/// <summary>
|
||||
/// 异步领取指定邮件的奖励。
|
||||
/// </summary>
|
||||
/// <param name="mail">要领取奖励的邮件。</param>
|
||||
/// <returns>一个任务,表示奖励领取操作是否成功。</returns>
|
||||
Task<bool> TakeReward(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 异步领取指定邮件的奖励。
|
||||
/// </summary>
|
||||
/// <param name="mails">要领取奖励的邮件。领取所有奖励</param>
|
||||
/// <returns>一个任务,表示奖励领取操作是否成功。</returns>
|
||||
Task<bool> TakeReward(GameMail[] mails = null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮件缓存类
|
||||
/// </summary>
|
||||
public class MailCache
|
||||
{
|
||||
private Dictionary<string,GameMail> _dicMails;
|
||||
private Dictionary<string,cfg.AutoDeliveryMail> _autoDeliveryMail;
|
||||
|
||||
private string _mail_key;
|
||||
private string _sync_time_key;
|
||||
private string _userId;
|
||||
|
||||
public MailCache(cfg.TbAutoDeliveryMail tbAutoDeliveryMail)
|
||||
{
|
||||
_autoDeliveryMail = tbAutoDeliveryMail.DataMap
|
||||
.ToDictionary(e => e.Key.ToString(), v => v.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定用户的邮件缓存
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
public void Load(string userId)
|
||||
{
|
||||
if (userId != this._userId)
|
||||
{
|
||||
Debug.Log($"load mail cache for user: {userId}");
|
||||
this._userId = userId;
|
||||
_mail_key = $"mail_cache__{userId}";
|
||||
_sync_time_key = $"mail_sync_Time_{userId}";
|
||||
var jdata = PlayerPrefs.GetString(_mail_key, string.Empty);
|
||||
_dicMails = string.IsNullOrEmpty(jdata) ?
|
||||
new Dictionary<string, GameMail>()
|
||||
: JsonConvert.DeserializeObject<Dictionary<string, GameMail>>(jdata);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
this._userId = null;
|
||||
_mail_key = null;
|
||||
_sync_time_key = null;
|
||||
_dicMails = null;
|
||||
}
|
||||
|
||||
public DateTime? LastSyncTime
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
return PlayerPrefs.HasKey(_sync_time_key) ?
|
||||
DateTime.Parse(PlayerPrefs.GetString(_sync_time_key)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对邮件列表进行排序
|
||||
/// </summary>
|
||||
/// <param name="mails">邮件列表</param>
|
||||
private void SortMails(List<GameMail> mails)
|
||||
{
|
||||
//by send time Desc
|
||||
mails.Sort((a, b) => b.SendTime.CompareTo(a.SendTime));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存邮件缓存到持久化存储
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
var jdata = JsonConvert.SerializeObject(_dicMails);
|
||||
PlayerPrefs.SetString(_mail_key, jdata);
|
||||
PlayerPrefs.SetString(_sync_time_key, ZZTimeHelper.UtcNow().ToString());
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
public void UpdateSyncTime()
|
||||
{
|
||||
PlayerPrefs.SetString(_sync_time_key, ZZTimeHelper.UtcNow().ToString());
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 缓存单封邮件
|
||||
/// </summary>
|
||||
/// <param name="mail">邮件对象</param>
|
||||
public void Cache(GameMail mail)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
if(_dicMails.ContainsKey(mail.Id))
|
||||
{
|
||||
_dicMails[mail.Id].Copy(mail);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillMail(mail);
|
||||
_dicMails.Add(mail.Id, mail);
|
||||
}
|
||||
}
|
||||
|
||||
private void FillMail(GameMail mail)
|
||||
{
|
||||
if (mail.Type == EMailType.AutoDelivery)
|
||||
{
|
||||
var mailData = _autoDeliveryMail[mail.Id];
|
||||
mail.Title = LocalizationMgr.GetText(mailData.Title_l10n_key);
|
||||
mail.Content = LocalizationMgr.GetText(mailData.Content_l10n_key);
|
||||
mail.From = LocalizationMgr.GetText(mailData.Inscribe_l10n_key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存多封邮件
|
||||
/// </summary>
|
||||
/// <param name="mails">邮件集合</param>
|
||||
public void Cache(IEnumerable<GameMail> mails)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
foreach (var mail in mails)
|
||||
{
|
||||
Cache(mail);
|
||||
}
|
||||
}
|
||||
|
||||
public GameMail GetMail(string id)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
if (_dicMails.TryGetValue(id, out var mail))
|
||||
{
|
||||
return mail;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasMail(string id)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
return _dicMails.ContainsKey(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有未过期且未删除的邮件
|
||||
/// </summary>
|
||||
/// <returns>邮件列表</returns>
|
||||
public IList<GameMail> GetAll()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
var now = ZZTimeHelper.UtcNow();
|
||||
var mails = _dicMails.Values
|
||||
.Where(m => m.ExpireTime > now && !m.IsDeleted)
|
||||
.ToList();
|
||||
SortMails(mails);
|
||||
return mails;
|
||||
}
|
||||
|
||||
public int UnreadMailCount
|
||||
{
|
||||
get{
|
||||
#if UNITY_EDITOR
|
||||
Assert.IsNotNull(_userId);
|
||||
#endif
|
||||
var utcNow = ZZTimeHelper.UtcNow();
|
||||
return _dicMails.Values.Count(m =>
|
||||
m.ExpireTime > utcNow
|
||||
&& !m.IsDeleted
|
||||
&& (!m.IsRead || !m.HasReward));
|
||||
}
|
||||
}
|
||||
|
||||
public string PrintCacheMails()
|
||||
{
|
||||
return JsonConvert.SerializeObject(_dicMails,Formatting.Indented);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮件处理器接口
|
||||
/// </summary>
|
||||
public interface IMailHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取游戏邮件列表
|
||||
/// </summary>
|
||||
/// <returns>游戏邮件列表的枚举</returns>
|
||||
Task<bool> FetchMail();
|
||||
|
||||
/// <summary>
|
||||
/// 发送邮件
|
||||
/// </summary>
|
||||
/// <returns>发送是否成功</returns>
|
||||
Task<bool> SendMail(MailInfo[] mailInfos);
|
||||
|
||||
/// <summary>
|
||||
/// 将指定邮件标记为已读
|
||||
/// </summary>
|
||||
/// <param name="mail">邮件</param>
|
||||
/// <returns>标记是否成功</returns>
|
||||
Task<bool> MarkAsRead(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 将多个指定邮件标记为已读
|
||||
/// </summary>
|
||||
/// <param name="mails">邮件数组, null 标记所有为已读</param>
|
||||
/// <returns>标记是否成功</returns>
|
||||
Task<bool> MarkAsRead(GameMail[] mails = null);
|
||||
|
||||
/// <summary>
|
||||
/// 领取指定邮件的奖励
|
||||
/// </summary>
|
||||
/// <param name="mail">邮件</param>
|
||||
/// <returns>领取是否成功</returns>
|
||||
Task<bool> TakeReward(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 领取多个指定邮件的奖励
|
||||
/// </summary>
|
||||
/// <param name="mails">邮件数组, null 领取所有奖励</param>
|
||||
/// <returns>领取是否成功</returns>
|
||||
Task<bool> TakeReward(GameMail[] mails= null);
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定邮件
|
||||
/// </summary>
|
||||
/// <param name="mail">邮件</param>
|
||||
/// <returns>删除是否成功</returns>
|
||||
Task<bool> DeleteMail(GameMail mail);
|
||||
|
||||
/// <summary>
|
||||
/// 删除多个指定邮件
|
||||
/// </summary>
|
||||
/// <param name="mails">邮件数组, null 删除所有 已读邮件</param>
|
||||
/// <returns>删除是否成功</returns>
|
||||
Task<bool> DeleteMail(GameMail[] mails = null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏邮件类
|
||||
/// </summary>
|
||||
public class GameMail
|
||||
{
|
||||
// 邮件ID,用于唯一标识一封邮件
|
||||
public string Id { get; set; }
|
||||
|
||||
// 邮件类型,表示邮件的性质或用途
|
||||
public EMailType Type { get; set; }
|
||||
|
||||
// 邮件发送时间,记录邮件发送的时刻
|
||||
public DateTime SendTime { get; set; }
|
||||
|
||||
// 邮件过期时间,表示邮件有效的截止时间
|
||||
public DateTime ExpireTime { get; set; }
|
||||
|
||||
// 邮件状态,表示邮件当前的各种状态(如是否已读、是否删除等)
|
||||
public EMailState State { get; set; }
|
||||
|
||||
// 邮件标题,简短概括邮件内容的主题
|
||||
public string Title { get; set; }
|
||||
|
||||
// 邮件发送方,记录邮件发送方
|
||||
public string From { get; set; }
|
||||
|
||||
// 邮件内容,详细描述邮件的信息
|
||||
public string Content { get; set; }
|
||||
|
||||
// 邮件附带的物品ID数组,表示邮件可能附带的物品或奖励
|
||||
public int[] DropIds { get; set; }
|
||||
|
||||
// 判断邮件是否含有附带物品
|
||||
public bool HasDrops => DropIds != null && DropIds.Length > 0;
|
||||
|
||||
// 判断邮件是否含有奖励,如果含有附带物品且奖励未被领取,则返回true
|
||||
public bool HasReward => !HasDrops || (State & EMailState.RewardTaken) == EMailState.RewardTaken;
|
||||
|
||||
// 判断邮件是否已被阅读
|
||||
public bool IsRead => (State & EMailState.HasRead) == EMailState.HasRead;
|
||||
|
||||
// 判断邮件是否已被删除
|
||||
public bool IsDeleted => (State & EMailState.HasDeleted) == EMailState.HasDeleted;
|
||||
|
||||
public void Copy(GameMail mail)
|
||||
{
|
||||
Id = mail.Id;
|
||||
Type = mail.Type;
|
||||
SendTime = mail.SendTime;
|
||||
ExpireTime = mail.ExpireTime;
|
||||
State = mail.State;
|
||||
Title = mail.Title;
|
||||
From = mail.From;
|
||||
Content = mail.Content;
|
||||
DropIds = mail.DropIds;
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Services/InGameMail.cs.meta
Normal file
3
Assets/Scripts/Services/InGameMail.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbb8e914d77c4b7fa83156f737472b48
|
||||
timeCreated: 1729682925
|
||||
502
Assets/Scripts/Services/InGameMailHandler.cs
Normal file
502
Assets/Scripts/Services/InGameMailHandler.cs
Normal file
@@ -0,0 +1,502 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using game;
|
||||
using GameCore;
|
||||
using Newtonsoft.Json;
|
||||
using UniRx;
|
||||
|
||||
public class FetchMailRequest
|
||||
{
|
||||
public DateTime? lastSyncTime;
|
||||
}
|
||||
|
||||
public class FetchMailResp
|
||||
{
|
||||
public bool success;
|
||||
public List<GameMail> mails;
|
||||
public string error;
|
||||
}
|
||||
|
||||
public class MailStateInfo
|
||||
{
|
||||
public string Id {get; set;}
|
||||
public EMailState state {get; set;}
|
||||
|
||||
public MailStateInfo(GameMail mail, EMailState newState)
|
||||
{
|
||||
Id = mail.Id.ToString();
|
||||
state = mail.State | newState;
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateMailStateRequest
|
||||
{
|
||||
public MailStateInfo[] mailStates;
|
||||
}
|
||||
|
||||
public class UpdateMailStateResp
|
||||
{
|
||||
public bool success;
|
||||
public MailStateInfo[] states;
|
||||
}
|
||||
|
||||
public class FetchMailEvt
|
||||
{
|
||||
DateTime TimeStamp;
|
||||
}
|
||||
|
||||
public class MailInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public EMailType Type { get; set; }
|
||||
|
||||
public int expireDays { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string From { get; set; }
|
||||
|
||||
public string Content { get; set; }
|
||||
|
||||
public int[] DropIds { get; set; }
|
||||
}
|
||||
|
||||
public class SendMailRequest
|
||||
{
|
||||
public MailInfo[] mailInfos;
|
||||
}
|
||||
|
||||
public class SendMailResp
|
||||
{
|
||||
public bool success;
|
||||
public List<GameMail> mails;
|
||||
public string error;
|
||||
}
|
||||
|
||||
public class AutoMailData
|
||||
{
|
||||
public string Id;
|
||||
public int levelMin;
|
||||
public int levelMax;
|
||||
public DateTime accountCreateTime;
|
||||
public DateTime loginTimeMin;
|
||||
public DateTime loginTimeMax;
|
||||
public int expireDays;
|
||||
public int DropID;
|
||||
|
||||
public AutoMailData(cfg.AutoDeliveryMail mail)
|
||||
{
|
||||
Id = mail.MailID.ToString();
|
||||
levelMin = mail.AccountLevelRange[0];
|
||||
levelMax = mail.AccountLevelRange[1] == -1 ? int.MaxValue : mail.AccountLevelRange[1];
|
||||
accountCreateTime = DateTime.Parse(mail.AccountCreateTimestamp);
|
||||
loginTimeMin = DateTime.Parse(mail.LoginTimestampRange[0]);
|
||||
loginTimeMax = DateTime.Parse(mail.LoginTimestampRange[1]);
|
||||
DropID = mail.DropID;
|
||||
expireDays = mail.ExpireDay;
|
||||
}
|
||||
|
||||
public bool IsSatisfy(DateTime loginTime, DateTime CreateTime, int level)
|
||||
{
|
||||
return loginTime >= loginTimeMin && loginTime <= loginTimeMax
|
||||
&& CreateTime < accountCreateTime
|
||||
&& level >= levelMin && level <= levelMax;
|
||||
}
|
||||
|
||||
public MailInfo ToMailInfo()
|
||||
{
|
||||
return new MailInfo {
|
||||
Id = Id.ToString(),
|
||||
Type = EMailType.AutoDelivery,
|
||||
DropIds = new[] { DropID },
|
||||
expireDays = expireDays
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class MailUrls
|
||||
{
|
||||
public const string Fetch = "mail/fetch";
|
||||
public const string UpdateState = "mail/updateState";
|
||||
public const string Send = "mail/send";
|
||||
}
|
||||
|
||||
public class InGameMailService : IInGameMailService
|
||||
{
|
||||
private MailCache _mailCache;
|
||||
private IMailHandler _handler;
|
||||
private List<AutoMailData> _autoMailDatas;
|
||||
|
||||
private CompositeDisposable _disposables;
|
||||
|
||||
private bool _forceFetch = false;
|
||||
|
||||
//private const int Fetch_Interval = 3;
|
||||
|
||||
public bool IsUnlock { get; set; }
|
||||
|
||||
|
||||
public InGameMailService(ICustomServerMgr customServerMgr, cfg.Tables tables)
|
||||
{
|
||||
this._mailCache = new MailCache(tables.TbAutoDeliveryMail);
|
||||
this._handler = new BaseMailHandler(_mailCache, customServerMgr) ;
|
||||
_autoMailDatas = tables.TbAutoDeliveryMail.DataList
|
||||
.Select(x => new AutoMailData(x)).ToList();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
var userService = GContext.container.Resolve<IUserService>();
|
||||
_mailCache.Load(userService.UserId);
|
||||
|
||||
_disposables = new CompositeDisposable();
|
||||
|
||||
var minActiveLevel = _autoMailDatas.Min(x => x.levelMin) -1;
|
||||
|
||||
if(userService.IsAuthorized)
|
||||
_handler.FetchMail();
|
||||
else
|
||||
GContext.OnEvent<game.EvtAPISvrLoginSuccess>().Subscribe(_ => _handler.FetchMail()).AddTo(_disposables);
|
||||
|
||||
GContext.OnEvent<OnLvChangeEvent>()
|
||||
.Skip(1)
|
||||
.Where(x => x.lvl >= minActiveLevel)
|
||||
.Subscribe(OnLevelChange)
|
||||
.AddTo(_disposables);
|
||||
|
||||
//GContext.OnEvent<RestartShowHomeUIEvent>()
|
||||
//.Skip(1)
|
||||
//.Subscribe(OnHomeUIShow)
|
||||
//.AddTo(_disposables);
|
||||
|
||||
var rtService = GContext.container.Resolve<IRTService>();
|
||||
|
||||
rtService.OnEvent<FetchMailEvt>(async evt => await _handler.FetchMail())
|
||||
.AddTo(_disposables);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_mailCache?.Unload();
|
||||
_disposables?.Dispose();
|
||||
_disposables = null;
|
||||
}
|
||||
|
||||
public async Task FetchMail()
|
||||
{
|
||||
await _handler.FetchMail();
|
||||
}
|
||||
|
||||
public IList<GameMail> GetAllMail()
|
||||
{
|
||||
return _mailCache.GetAll();
|
||||
}
|
||||
|
||||
public async Task<bool> MarkRead(GameMail mail)
|
||||
{
|
||||
return await _handler.MarkAsRead(mail);
|
||||
}
|
||||
|
||||
public async Task<bool> MarkRead(GameMail[] mails = null)
|
||||
{
|
||||
return await _handler.MarkAsRead(mails);
|
||||
}
|
||||
|
||||
public async Task<bool> DelMail(GameMail mail)
|
||||
{
|
||||
return await _handler.DeleteMail(mail);
|
||||
}
|
||||
|
||||
public async Task<bool> DelMail(GameMail[] mails = null)
|
||||
{
|
||||
return await _handler.DeleteMail(mails);
|
||||
}
|
||||
|
||||
public async Task<bool> TakeReward(GameMail mail)
|
||||
{
|
||||
return await _handler.TakeReward(mail);
|
||||
}
|
||||
|
||||
public async Task<bool> TakeReward(GameMail[] mails)
|
||||
{
|
||||
return await _handler.TakeReward(mails);
|
||||
}
|
||||
|
||||
private void OnLevelChange(OnLvChangeEvent evt)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Debug.Log("[InGameMailService] OnLevelChange");
|
||||
#endif
|
||||
GenAutoDeliveryMail();
|
||||
}
|
||||
|
||||
//private async void OnHomeUIShow(RestartShowHomeUIEvent evt)
|
||||
//{
|
||||
|
||||
//#if UNITY_EDITOR
|
||||
//var deltaTime = _mailCache.LastSyncTime == null ? 0 : (ZZTimeHelper.UtcNow() - _mailCache.LastSyncTime.Value).TotalSeconds;
|
||||
//UnityEngine.Debug.Log($"[InGameMailService] OnHomeUIShow deltaTime {deltaTime}");
|
||||
//#endif
|
||||
//if(_mailCache.LastSyncTime == null
|
||||
//|| _forceFetch
|
||||
//|| ZZTimeHelper.UtcNow() - _mailCache.LastSyncTime.Value > TimeSpan.FromMinutes(Fetch_Interval))
|
||||
//{
|
||||
//if(await _handler.FetchMail())
|
||||
//{
|
||||
//_forceFetch = false;
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
private async void GenAutoDeliveryMail()
|
||||
{
|
||||
var playerData = GContext.container.Resolve<PlayerData>();
|
||||
var userData = GContext.container.Resolve<IUserService>();
|
||||
|
||||
var mailsToSend = _autoMailDatas.Where(m => !_mailCache.HasMail(m.Id)
|
||||
&& m.IsSatisfy(userData.LoginTime, userData.CreateTime, playerData.lv))
|
||||
.Select(m => m.ToMailInfo())
|
||||
.ToArray();
|
||||
|
||||
if(mailsToSend.Length > 0)
|
||||
{
|
||||
if(await _handler.SendMail(mailsToSend))
|
||||
{
|
||||
_forceFetch = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
var mailids = mailsToSend.Select(m => m.Id);
|
||||
var mailidsStr = string.Join(',', mailids);
|
||||
UnityEngine.Debug.Log($"[InGameMailService] GenAutoDeliveryMail {mailidsStr}");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void PrintCacheMail()
|
||||
{
|
||||
UnityEngine.Debug.Log(_mailCache.PrintCacheMails());
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseMailHandler : IMailHandler
|
||||
{
|
||||
protected MailCache _cache;
|
||||
protected ICustomServerMgr _customServerMgr;
|
||||
|
||||
public BaseMailHandler(MailCache cache, ICustomServerMgr customServerMgr)
|
||||
{
|
||||
this._cache = cache;
|
||||
this._customServerMgr = customServerMgr;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> FetchMail()
|
||||
{
|
||||
try
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Debug.Log($"[InGameMailService] Start Fetch Mails");
|
||||
#endif
|
||||
var req = new FetchMailRequest()
|
||||
{
|
||||
lastSyncTime = _cache.LastSyncTime
|
||||
};
|
||||
|
||||
var result = await _customServerMgr.CustomServerPost(MailUrls.Fetch, JsonConvert.SerializeObject(req));
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
var resp = JsonConvert.DeserializeObject<FetchMailResp>(result);
|
||||
if (resp.success )
|
||||
{
|
||||
if(resp.mails != null && resp.mails.Count > 0)
|
||||
{
|
||||
_cache.Cache(resp.mails);
|
||||
_cache.Save();
|
||||
var UnreadMailCount = _cache.UnreadMailCount;
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Unread_Mail, UnreadMailCount > 0, UnreadMailCount);
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Debug.Log($"[InGameMailService] FetchMail {UnreadMailCount} LastSyncTime = {_cache.LastSyncTime}");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache.UpdateSyncTime();
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Debug.Log($"[InGameMailService] No Mails Fetch Fetched LastSyncTime = {_cache.LastSyncTime}");
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"[InGameMailService] FetchMail Failed {resp.error} ");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogException(e);
|
||||
}
|
||||
|
||||
UnityEngine.Debug.LogWarning("[InGameMailService] FetchMail Failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> SendMail(MailInfo[] mailInfos)
|
||||
{
|
||||
try
|
||||
{
|
||||
var req = new SendMailRequest()
|
||||
{
|
||||
mailInfos = mailInfos
|
||||
};
|
||||
|
||||
var result = await _customServerMgr.CustomServerPost(MailUrls.Send, JsonConvert.SerializeObject(req));
|
||||
if (result != null)
|
||||
{
|
||||
var resp = JsonConvert.DeserializeObject<SendMailResp>(result);
|
||||
if (!resp.success)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"[InGameMailService] SendMail Failed {resp.error} ");
|
||||
}
|
||||
return resp.success;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogError(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual async Task<bool> UpdateMailState(GameMail[] mails, EMailState state)
|
||||
{
|
||||
var req = new UpdateMailStateRequest()
|
||||
{
|
||||
mailStates = mails.Select(m => new MailStateInfo(m, state)).ToArray()
|
||||
};
|
||||
|
||||
var result = await _customServerMgr.CustomServerPost(MailUrls.UpdateState, JsonConvert.SerializeObject(req));
|
||||
if (result != null)
|
||||
{
|
||||
var resp = JsonConvert.DeserializeObject<UpdateMailStateResp>(result);
|
||||
if (resp.success)
|
||||
{
|
||||
foreach(var s in req.mailStates)
|
||||
{
|
||||
var mail = _cache.GetMail(s.Id);
|
||||
if (mail != null) mail.State = s.state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<bool> MarkAsRead(GameMail mail)
|
||||
{
|
||||
if (mail.IsRead) return false;
|
||||
|
||||
var result = await UpdateMailState(new[] { mail }, EMailState.HasRead);
|
||||
if(result) _cache.Save();
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> MarkAsRead(GameMail[] mails = null)
|
||||
{
|
||||
if (mails == null)
|
||||
{
|
||||
mails = _cache.GetAll()
|
||||
.Where(m => !m.IsRead)
|
||||
.ToArray();
|
||||
}
|
||||
return await UpdateMailState( mails, EMailState.HasRead);
|
||||
}
|
||||
|
||||
public async Task<bool> TakeReward(GameMail mail)
|
||||
{
|
||||
if (!mail.HasDrops || mail.HasReward)
|
||||
return false;
|
||||
|
||||
var result = await UpdateMailState(new[] { mail }, EMailState.RewardTaken);
|
||||
if (result)
|
||||
{
|
||||
_cache.Save();
|
||||
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(mail.DropIds.ToList());
|
||||
GContext.Publish(new ShowData());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> TakeReward(GameMail[] mails = null)
|
||||
{
|
||||
if (mails == null)
|
||||
{
|
||||
mails = _cache.GetAll()
|
||||
.Where(m => m.HasDrops && !m.HasReward)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
mails = mails.Where(m => m.HasDrops && !m.HasReward)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if(mails.Length == 0 ) return false;
|
||||
|
||||
var result = await UpdateMailState( mails, EMailState.HasRead);
|
||||
if (result)
|
||||
{
|
||||
_cache.Save();
|
||||
var drops = mails.Where(m => m.HasReward)
|
||||
.SelectMany(m => m.DropIds).ToList();
|
||||
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(drops);
|
||||
GContext.Publish(new ShowData());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteMail(GameMail mail)
|
||||
{
|
||||
if (mail.IsDeleted)
|
||||
return false;
|
||||
|
||||
var result = await UpdateMailState(new[] { mail }, EMailState.HasDeleted);
|
||||
if(result) _cache.Save();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteMail(GameMail[] mails = null)
|
||||
{
|
||||
if (mails == null)
|
||||
{
|
||||
mails = _cache.GetAll()
|
||||
.Where(m => m.IsRead && m.HasReward )
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
mails = mails.Where(m => !m.IsDeleted)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (mails.Length == 0) return false;
|
||||
|
||||
var result = await UpdateMailState(mails, EMailState.HasDeleted);
|
||||
if(result) _cache.Save();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Services/InGameMailHandler.cs.meta
Normal file
3
Assets/Scripts/Services/InGameMailHandler.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6aa9e490c0b4521a5bee6af57733700
|
||||
timeCreated: 1729826408
|
||||
473
Assets/Scripts/Services/LoadResourceService.cs
Normal file
473
Assets/Scripts/Services/LoadResourceService.cs
Normal file
@@ -0,0 +1,473 @@
|
||||
using asap.core;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
public interface ILoadResourceService
|
||||
{
|
||||
Task<bool> Load(string label);
|
||||
Task<bool> Loads(List<string> label);
|
||||
//后台排队静默下载
|
||||
void Load(List<string> label);
|
||||
/// <summary>
|
||||
/// 登陆游戏预下载地图资源
|
||||
/// </summary>
|
||||
/// <param name="assetName"></param>
|
||||
/// <param name="progress"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> Loading(List<string> assetName, System.Action<float> progress);
|
||||
//检查是否需要下载资源,不下载
|
||||
Task<bool> CheckResource(string label);
|
||||
Task<bool> CheckResourceLoadQueue(string key, List<string> label);
|
||||
Task<bool> CheckResourceLoadQueue(List<string> label);
|
||||
string curName { get; }
|
||||
string oldName { get; }
|
||||
}
|
||||
public class LoadResourceData
|
||||
{
|
||||
public string name;
|
||||
public AsyncOperationHandle downloadOp;
|
||||
}
|
||||
public struct LoadEventResourceEvent
|
||||
{
|
||||
public string key;
|
||||
public List<string> label;
|
||||
public bool isSucceeded;
|
||||
}
|
||||
public class LoadProgressEvent
|
||||
{
|
||||
public string name;
|
||||
public float progress;
|
||||
public float totalDownloadSize;
|
||||
public bool isSucceeded;
|
||||
public bool isFailed;
|
||||
}
|
||||
public class LoadResourceService : ILoadResourceService
|
||||
{
|
||||
[Inject]
|
||||
public IConfig config { get; set; }
|
||||
Dictionary<string, AsyncOperationHandle> loadResourceDatas = new Dictionary<string, AsyncOperationHandle>();
|
||||
LinkedList<string> loadQueue = new LinkedList<string>();
|
||||
LinkedList<LoadEventResourceEvent> loadEventQueue = new LinkedList<LoadEventResourceEvent>();
|
||||
bool LoadEventResourceing = false;
|
||||
Dictionary<string, bool> loadRecord = new Dictionary<string, bool>();
|
||||
//检查资源是否需要更新
|
||||
public string curName { get; private set; }
|
||||
public string oldName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登陆游戏预下载地图资源
|
||||
/// </summary>
|
||||
/// <param name="assetName"></param>
|
||||
/// <param name="progress"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> Loading(List<string> assetName, System.Action<float> progress)
|
||||
{
|
||||
if (!loadResourceDatas.ContainsKey(assetName[0]))
|
||||
{
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(assetName, Addressables.MergeMode.Union);
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
|
||||
if (totalDownloadSize > 1024)
|
||||
{
|
||||
AsyncOperationHandle download = Addressables.DownloadDependenciesAsync(locations.Select(_ => _.PrimaryKey), Addressables.MergeMode.Union);
|
||||
loadResourceDatas[assetName[0]] = download;
|
||||
}
|
||||
Addressables.Release(locationsOp);
|
||||
}
|
||||
bool result = true;
|
||||
if (loadResourceDatas.ContainsKey(assetName[0]))
|
||||
{
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("Preload_start"))
|
||||
{
|
||||
e.AddContent("expected_assets", string.Join(',', assetName));
|
||||
}
|
||||
#endif
|
||||
float percent = 0;
|
||||
LoadingScreen.SetLoadingInfo(LocalizationMgr.GetText("UI_ToastPanel_26"));
|
||||
|
||||
AsyncOperationHandle downloadOp = loadResourceDatas[assetName[0]];
|
||||
DateTime startTime = DateTime.Now;
|
||||
LoadingScreen.SetSubProgress(0, "");
|
||||
LoadingScreen.ShowSubProgressBar();
|
||||
while (!downloadOp.IsDone && downloadOp.Status != AsyncOperationStatus.Failed)
|
||||
{
|
||||
var downloadStatus = downloadOp.GetDownloadStatus();
|
||||
if (downloadStatus.Percent > percent)
|
||||
percent = downloadStatus.Percent;
|
||||
progress?.Invoke(percent);
|
||||
LoadingScreen.SetSubProgress(percent, GetSizeByBytes(downloadStatus.TotalBytes, percent));
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
LoadingScreen.HideSubProgressBar();
|
||||
loadResourceDatas.Remove(assetName[0]);
|
||||
if (downloadOp.Status == AsyncOperationStatus.Failed
|
||||
|| downloadOp.OperationException != null)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
DateTime endTime = DateTime.Now;
|
||||
Debug.Log($"Preload finished, result:{result}, time cost:{(endTime - startTime).TotalSeconds}s");
|
||||
#if AGG
|
||||
using (var e = GEvent.GameEvent("Preload_finish"))
|
||||
{
|
||||
e.AddContent("status", result ? "Succeeded" : "Failed")
|
||||
.AddContent("duration_ms", (endTime - startTime).TotalMilliseconds);
|
||||
if (downloadOp.OperationException != null)
|
||||
{
|
||||
e.AddContent("error", downloadOp.OperationException.Message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Addressables.Release(downloadOp);
|
||||
}
|
||||
progress?.Invoke(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private const float byte2mb = 1024 * 1024;
|
||||
private string GetSizeByBytes(long total, float percent)
|
||||
{
|
||||
return $"{(percent * total / byte2mb).ToString("0.0")}MB/{(total / byte2mb).ToString("0.0")}MB";
|
||||
}
|
||||
|
||||
private string GetSizeByBytes(long total)
|
||||
{
|
||||
return $"{(total / byte2mb).ToString("0.00")}MB";
|
||||
}
|
||||
|
||||
public async Task<bool> Load(string label)
|
||||
{
|
||||
try
|
||||
{
|
||||
oldName = label;
|
||||
if (loadResourceDatas.ContainsKey(label))
|
||||
{
|
||||
curName = label;
|
||||
return false;
|
||||
}
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(label);
|
||||
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
||||
if (totalDownloadSize > 1)
|
||||
{
|
||||
Load(label, totalDownloadSize, locations.Select(_ => _.PrimaryKey).ToList());
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(locationsOp);
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
||||
Debug.LogError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public async Task<bool> Loads(List<string> labels)
|
||||
{
|
||||
try
|
||||
{
|
||||
oldName = labels[0];
|
||||
if (loadResourceDatas.ContainsKey(labels[0]))
|
||||
{
|
||||
curName = labels[0];
|
||||
return false;
|
||||
}
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(labels, Addressables.MergeMode.Union);
|
||||
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Loads");
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Loads");
|
||||
if (totalDownloadSize > 1)
|
||||
{
|
||||
Load(labels[0], totalDownloadSize, locations.Select(_ => _.PrimaryKey).ToList());
|
||||
return false;
|
||||
}
|
||||
Addressables.Release(locationsOp);
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Loads");
|
||||
Debug.LogError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> CheckResource(string label)
|
||||
{
|
||||
try
|
||||
{
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(label);
|
||||
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
||||
Addressables.Release(locationsOp);
|
||||
if (totalDownloadSize > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
||||
Debug.LogError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async void Load(List<string> label)
|
||||
{
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(label, Addressables.MergeMode.Union);
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
if (totalDownloadSize > 0)
|
||||
{
|
||||
for (int i = 0; locations.Count > i; i++)
|
||||
{
|
||||
//判断 loadQueue 是否包含当前资源
|
||||
if (loadQueue.Contains(locations[i].PrimaryKey))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
loadQueue.AddLast(locations[i].PrimaryKey);
|
||||
if (loadQueue.Count == 1)
|
||||
{
|
||||
LoadKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
Addressables.Release(locationsOp);
|
||||
}
|
||||
async void Load(string name, float totalDownloadSize, IList<string> keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
curName = name;
|
||||
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union);
|
||||
loadResourceDatas[name] = downloadOp;
|
||||
LoadProgressEvent loadProgressEvent = new LoadProgressEvent() { name = name, progress = downloadOp.GetDownloadStatus().Percent, totalDownloadSize = totalDownloadSize };
|
||||
while (!downloadOp.IsDone && downloadOp.Status != AsyncOperationStatus.Failed)
|
||||
{
|
||||
if (name == curName)
|
||||
{
|
||||
loadProgressEvent.progress = downloadOp.GetDownloadStatus().Percent;
|
||||
loadProgressEvent.totalDownloadSize = totalDownloadSize;
|
||||
GContext.Publish(loadProgressEvent);
|
||||
}
|
||||
await Awaiters.Seconds(0.2f);
|
||||
}
|
||||
|
||||
if (name == curName)
|
||||
{
|
||||
if (downloadOp.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
loadProgressEvent.progress = 1.0001f;
|
||||
loadProgressEvent.isSucceeded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
loadProgressEvent.isFailed = true;
|
||||
}
|
||||
loadProgressEvent.totalDownloadSize = totalDownloadSize;
|
||||
GContext.Publish(loadProgressEvent);
|
||||
}
|
||||
try
|
||||
{
|
||||
OnLoadGameEvent(downloadOp, string.Join(',', keys));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
|
||||
Addressables.Release(downloadOp);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
loadResourceDatas.Remove(name);
|
||||
}
|
||||
async void LoadKey()
|
||||
{
|
||||
while (loadQueue.Count > 0)
|
||||
{
|
||||
string key = loadQueue.First.Value;
|
||||
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(key);
|
||||
await downloadOp.Task;
|
||||
|
||||
OnLoadGameEvent(downloadOp, key);
|
||||
|
||||
Addressables.Release(downloadOp);
|
||||
await Awaiters.NextFrame;
|
||||
loadQueue.RemoveFirst();
|
||||
}
|
||||
}
|
||||
public async Task<bool> CheckResourceLoadQueue(List<string> label)
|
||||
{
|
||||
string key = string.Join(",", label);
|
||||
return await ResourceLoadQueue(key, label);
|
||||
}
|
||||
public async Task<bool> CheckResourceLoadQueue(string key, List<string> label)
|
||||
{
|
||||
bool NoCheckResource = config.Get("NoCheckResource", "0") == "1";
|
||||
if (NoCheckResource)
|
||||
return true;
|
||||
return await ResourceLoadQueue(key, label);
|
||||
}
|
||||
async Task<bool> ResourceLoadQueue(string key, List<string> label)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (loadRecord.ContainsKey(key))
|
||||
{
|
||||
return loadRecord[key];
|
||||
}
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(label, Addressables.MergeMode.Union);
|
||||
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
||||
var locations = await locationsOp.Task;
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
||||
Addressables.Release(locationsOp);
|
||||
if (totalDownloadSize > 1)
|
||||
{
|
||||
loadRecord[key] = false;
|
||||
LoadEventResourceEvent loadEventData = new LoadEventResourceEvent();
|
||||
loadEventData.key = key;
|
||||
loadEventData.label = label;
|
||||
LoadEventResource(loadEventData);
|
||||
return false;
|
||||
}
|
||||
loadRecord[key] = true;
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
loadRecord.Remove(key);
|
||||
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
||||
Debug.LogError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// 排队下载活动资源
|
||||
/// </summary>
|
||||
/// <param name="loadEventData"></param>
|
||||
void LoadEventResource(LoadEventResourceEvent loadEventData)
|
||||
{
|
||||
if (loadEventData.label == null || loadEventData.label.Count == 0)
|
||||
return;
|
||||
loadEventQueue.AddLast(loadEventData);
|
||||
if (loadEventQueue.Count == 1)
|
||||
{
|
||||
LoadEventKey();
|
||||
}
|
||||
}
|
||||
async void LoadEventKey()
|
||||
{
|
||||
LoadEventResourceing = true;
|
||||
while (loadEventQueue.Count > 0)
|
||||
{
|
||||
LoadEventResourceEvent loadEventData = loadEventQueue.First.Value;
|
||||
if (loadEventData.label == null || loadEventData.label.Count == 0)
|
||||
{
|
||||
loadEventQueue.RemoveFirst();
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
var locationsOp = Addressables.LoadResourceLocationsAsync(loadEventData.label, Addressables.MergeMode.Union);
|
||||
var locations = await locationsOp.Task;
|
||||
Addressables.Release(locationsOp);
|
||||
|
||||
// 检查locations是否有效
|
||||
if (locations == null || locations.Count == 0)
|
||||
{
|
||||
Debug.Log("未找到任何资源位置");
|
||||
loadEventData.isSucceeded = false;
|
||||
GContext.Publish(loadEventData);
|
||||
loadEventQueue.RemoveFirst();
|
||||
continue;
|
||||
}
|
||||
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
||||
if (totalDownloadSize > 0)
|
||||
{
|
||||
var keys = locations.Select(_ => _.PrimaryKey).ToList();
|
||||
string keyStr = string.Join(",", keys);
|
||||
Debug.Log($"资源名称:{keyStr}");
|
||||
Debug.Log($"资源大小:{GetSizeByBytes(totalDownloadSize)}");
|
||||
|
||||
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union);
|
||||
await downloadOp.Task;
|
||||
await Awaiters.NextFrame;
|
||||
OnLoadGameEvent(downloadOp, keyStr);
|
||||
bool isSucceeded = downloadOp.Status == AsyncOperationStatus.Succeeded;
|
||||
loadEventData.isSucceeded = isSucceeded;
|
||||
GContext.Publish(loadEventData);
|
||||
if (isSucceeded)
|
||||
{
|
||||
loadRecord[loadEventData.key] = isSucceeded;
|
||||
}
|
||||
else
|
||||
{
|
||||
loadRecord.Remove(loadEventData.key);
|
||||
}
|
||||
Addressables.Release(downloadOp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"资源大小:{0}");
|
||||
await Awaiters.NextFrame;
|
||||
loadEventData.isSucceeded = true;
|
||||
GContext.Publish(loadEventData);
|
||||
loadRecord[loadEventData.key] = true;
|
||||
}
|
||||
loadEventQueue.RemoveFirst();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"资源下载: {e.Message} {e.StackTrace}");
|
||||
loadEventData.isSucceeded = false;
|
||||
GContext.Publish(loadEventData);
|
||||
loadRecord.Remove(loadEventData.key);
|
||||
loadEventQueue.RemoveFirst();
|
||||
Debug.Log($"错误下载活动资源队列 count == {loadEventQueue.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void OnLoadGameEvent(AsyncOperationHandle downloadOp, string key)
|
||||
{
|
||||
if (downloadOp.Status == AsyncOperationStatus.Failed || downloadOp.OperationException != null)
|
||||
{
|
||||
Exception exception = downloadOp.OperationException;
|
||||
using (var e = GEvent.GameEvent("resource_load_finish"))
|
||||
{
|
||||
e.AddContent("status", "Failed")
|
||||
.AddContent("keys", key)
|
||||
;
|
||||
if (exception != null)
|
||||
{
|
||||
e.AddContent("error", exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Services/LoadResourceService.cs.meta
Normal file
11
Assets/Scripts/Services/LoadResourceService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49e213064e9ab8a48ade09d9058eefa5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
198
Assets/Scripts/Services/LocalizationMgr.cs
Normal file
198
Assets/Scripts/Services/LocalizationMgr.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System.Collections.Generic;
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using game;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization;
|
||||
using UnityEngine.Localization.Settings;
|
||||
|
||||
// TODO Refactor namespace to game
|
||||
namespace GameCore
|
||||
{
|
||||
public class ChangeLanguageEvent
|
||||
{
|
||||
public string lang;
|
||||
}
|
||||
// TODO Refactor To Service
|
||||
public static class LocalizationMgr
|
||||
{
|
||||
public static string[] LanguageLanguages;
|
||||
public static List<string> enumLanguage;
|
||||
public static List<string> languagePackList;
|
||||
public static int LanguageIndex { get; private set; } = 1;
|
||||
|
||||
static int unitOfWeight;
|
||||
static List<string> unitOfWeightStrs = new List<string> { "UI_FishingRewardPanel_101017", "UI_FishingRewardPanel_101039" };
|
||||
static List<double> unitOfWeightValues = new List<double> { 1, 2.20462262f };
|
||||
static string unitOfWeightStr = "UI_FishingRewardPanel_101017";
|
||||
static double unitOfWeightValue = 1f;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
TbLanguageConfig languageConfig = GContext.container.Resolve<cfg.Tables>().TbLanguageConfig;
|
||||
List<LanguageConfig> _dataMap = languageConfig.DataList;
|
||||
enumLanguage = new List<string>();// GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.LanguageList;
|
||||
languagePackList = new List<string>(); //GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.LanguagePackList;
|
||||
for (int i = 0; i < _dataMap.Count; i++)
|
||||
{
|
||||
enumLanguage.Add(_dataMap[i].ID);
|
||||
languagePackList.Add(_dataMap[i].LanGroup);
|
||||
}
|
||||
|
||||
LanguageLanguages = new string[enumLanguage.Count];
|
||||
for (int i = 0; i < enumLanguage.Count; i++)
|
||||
{
|
||||
if (enumLanguage[i] == "zh_Hans")
|
||||
{
|
||||
LanguageLanguages[i] = "中文 (简体)";
|
||||
}
|
||||
else if (enumLanguage[i] == "zh_Hant")
|
||||
{
|
||||
LanguageLanguages[i] = "中文 (繁體)";
|
||||
}
|
||||
else
|
||||
{
|
||||
LanguageLanguages[i] = System.Globalization.CultureInfo.GetCultureInfo(enumLanguage[i]).NativeName;
|
||||
}
|
||||
}
|
||||
SetUnitOfWeight();
|
||||
SetLanguage();
|
||||
}
|
||||
|
||||
static async void SetLanguage()
|
||||
{
|
||||
ISettingService setting = GContext.container.Resolve<ISettingService>();
|
||||
ILoadResourceService loadResourceService = GContext.container.Resolve<ILoadResourceService>();
|
||||
int index = enumLanguage.IndexOf(setting.Lang);
|
||||
if (index == -1)
|
||||
{
|
||||
index = 1;
|
||||
}
|
||||
string languagePack = languagePackList[index];
|
||||
bool isInit = await loadResourceService.CheckResource(languagePack);
|
||||
if (!isInit || !enumLanguage.Contains(setting.Lang))
|
||||
{
|
||||
setting.Lang = GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.LanguageSetting;
|
||||
index = enumLanguage.IndexOf(setting.Lang);
|
||||
}
|
||||
if (index == -1)
|
||||
{
|
||||
index = 1;
|
||||
}
|
||||
LanguageIndex = index;// language;
|
||||
|
||||
await LocalizationSettings.InitializationOperation.Task;
|
||||
string lang = setting.Lang.Replace('_', '-');
|
||||
Locale locale = LocalizationSettings.AvailableLocales.GetLocale(lang);
|
||||
if (locale == null)
|
||||
{
|
||||
Debug.LogError($"未找到语言包: {setting.Lang}");
|
||||
return;
|
||||
}
|
||||
LocalizationSettings.SelectedLocale = locale;
|
||||
}
|
||||
|
||||
public static async void SetLanguageAsync(int languageIndex)
|
||||
{
|
||||
|
||||
ISettingService setting = GContext.container.Resolve<ISettingService>();
|
||||
setting.Lang = enumLanguage[languageIndex];
|
||||
LanguageIndex = languageIndex;
|
||||
IUserService iUService = GContext.container.Resolve<IUserService>();
|
||||
await LocalizationSettings.InitializationOperation.Task;
|
||||
string lang = setting.Lang.Replace('_', '-');
|
||||
Locale locale = LocalizationSettings.AvailableLocales.GetLocale(lang);
|
||||
if (locale == null)
|
||||
{
|
||||
Debug.LogError($"未找到语言包: {setting.Lang}");
|
||||
return;
|
||||
}
|
||||
await iUService.UpdateLanguage(setting.Lang);
|
||||
LocalizationSettings.SelectedLocale = locale;
|
||||
GContext.Publish(new ChangeLanguageEvent());
|
||||
}
|
||||
|
||||
private static cfg.TbText table;
|
||||
private static cfg.TbText TbText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == table)
|
||||
{
|
||||
table = GContext.container.Resolve<cfg.Tables>()?.TbText;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetText(string text_key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text_key))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
text_key = text_key.Replace(" ", "");
|
||||
if (TbText != null)
|
||||
{
|
||||
var text_value = TbText.GetOrDefault(text_key);
|
||||
if (text_value != null)
|
||||
{
|
||||
return text_value.GetText(enumLanguage[LanguageIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameDebug.LogError($"[LocalizationMgr]GetText: Not found text_key {text_key} in TbText!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameDebug.LogError($"[LocalizationMgr]GetText: Not found tables in DataManager!");
|
||||
}
|
||||
|
||||
return text_key;
|
||||
}
|
||||
public static void SetUnitOfWeight()
|
||||
{
|
||||
var setting = GContext.container.Resolve<ISettingService>();
|
||||
unitOfWeight = setting.UnitOfWeight;
|
||||
if (unitOfWeight >= unitOfWeightStrs.Count)
|
||||
{
|
||||
unitOfWeight = unitOfWeightStrs.Count - 1;
|
||||
Debug.LogError($"[LocalizationMgr]SetUnitOfWeight: Not found unitOfWeight {unitOfWeight} in TbText!");
|
||||
}
|
||||
unitOfWeightStr = unitOfWeightStrs[unitOfWeight];
|
||||
unitOfWeightValue = unitOfWeightValues[unitOfWeight];
|
||||
}
|
||||
|
||||
public static string GetWeight(double num, bool keep = false)
|
||||
{
|
||||
num *= unitOfWeightValue;
|
||||
if (num < 1000)
|
||||
{
|
||||
return GetFormatTextValue(
|
||||
unitOfWeightStr,
|
||||
ConvertTools.GetNumberStringRetain(num, keep));
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetFormatTextValue(
|
||||
unitOfWeightStr,
|
||||
ConvertTools.GetNumberString((ulong)num, keep));
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFormatTextValue(string text_key, params object[] str)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
return GetText(text_key).SafeFormat(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.LogError($"Localization Format Text Error :{text_key}");
|
||||
return text_key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/LocalizationMgr.cs.meta
Normal file
11
Assets/Scripts/Services/LocalizationMgr.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46d6437fdfd6a2c4c89d9e69cb8f5064
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
80
Assets/Scripts/Services/MMTService.cs
Normal file
80
Assets/Scripts/Services/MMTService.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using game;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MMTService
|
||||
{
|
||||
[Inject]
|
||||
public Tables _tables { set; get; }
|
||||
public int MMTValue { private set; get; }
|
||||
public string MMTStr { private set; get; }
|
||||
public List<int> FixedFish
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tables.TbGlobalConfig.FixedFish;
|
||||
}
|
||||
}
|
||||
public bool CanShowHand { set; get; } = true;
|
||||
public bool mmt = false;
|
||||
public bool mmc = false;
|
||||
public bool mmBuilding = false;
|
||||
public string Init(int MMTValue)
|
||||
{
|
||||
this.MMTValue = MMTValue;
|
||||
var mmDatas = _tables.TbMMTInit.DataList;
|
||||
string MMType = "";
|
||||
mmt = false;
|
||||
mmc = false;
|
||||
for (int i = 0; i < mmDatas.Count; i++)
|
||||
{
|
||||
MMTInit data = mmDatas[i];
|
||||
//B组修改
|
||||
bool isB = false;
|
||||
#if UNITY_ANDROID
|
||||
if (CheckMMT(data.ID - 1))
|
||||
{
|
||||
isB = true;
|
||||
switch (data.MMTType)
|
||||
{
|
||||
///IOS 不做MMTest
|
||||
case "MMBeginnerPack":
|
||||
mmt = true;
|
||||
break;
|
||||
case "MMCollectingTargetPack":
|
||||
mmc = true;
|
||||
break;
|
||||
case "MMBuildingType":
|
||||
mmBuilding = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (isB)
|
||||
{
|
||||
MMType = MMType + "B";
|
||||
}
|
||||
else
|
||||
{
|
||||
MMType = MMType + "A";
|
||||
}
|
||||
}
|
||||
MMTStr = MMType;
|
||||
return MMType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查分组
|
||||
/// </summary>
|
||||
/// <param name="index">第几大组0,1,2</param>
|
||||
/// <returns>false=A true=B </returns>
|
||||
bool CheckMMT(int index)
|
||||
{
|
||||
int ab = 1 << (index % 3);
|
||||
return (MMTValue & ab) == ab;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/MMTService.cs.meta
Normal file
11
Assets/Scripts/Services/MMTService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7484a7820b604caebb98c6c398b8e60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
248
Assets/Scripts/Services/RTService.cs
Normal file
248
Assets/Scripts/Services/RTService.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using System.Net;
|
||||
using asap.core;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Newtonsoft.Json;
|
||||
using UniRx;
|
||||
using GameCore;
|
||||
using game;
|
||||
|
||||
public interface IRTService
|
||||
{
|
||||
public void WaitForAPISvrLogin();
|
||||
public Task Connect();
|
||||
public Task Disconnect();
|
||||
public bool IsConnected { get; }
|
||||
public IDisposable OnEvent<T>(Action<T> handler);
|
||||
public Task<string> Publish(string methodName, string arg1);
|
||||
public Task<string> Publish(string methodName, string arg1, string arg2);
|
||||
//public void Reset();
|
||||
public void Release();
|
||||
}
|
||||
|
||||
public class SignalRService : IRTService
|
||||
{
|
||||
private HubConnection _hubConnection;
|
||||
private ICustomServerMgr _serverMgr;
|
||||
private HashSet<Type> _bindedEvent;
|
||||
private IEventAggregator _eventAgg;
|
||||
private string _url;
|
||||
private Dictionary<string, Action<string>> _cachedEvents;
|
||||
|
||||
public SignalRService(ICustomServerMgr serverMgr, IConfig config)
|
||||
{
|
||||
this._serverMgr = serverMgr;
|
||||
var baseUrl = config.Get<string>(GConstant.K_Event_API_URL, string.Empty);
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Assertions.Assert.IsTrue(!string.IsNullOrEmpty(baseUrl));
|
||||
#endif
|
||||
_url = baseUrl + "gamehub";
|
||||
_eventAgg = new EventAggregator();
|
||||
_cachedEvents = new Dictionary<string, Action<string>>();
|
||||
_bindedEvent = new HashSet<Type>();
|
||||
}
|
||||
|
||||
public void WaitForAPISvrLogin()
|
||||
{
|
||||
GContext.OnEvent<game.EvtAPISvrLoginSuccess>().Subscribe(OnApiSvrLoginSuccess);
|
||||
}
|
||||
|
||||
private async void OnApiSvrLoginSuccess(EvtAPISvrLoginSuccess evt)
|
||||
{
|
||||
try{
|
||||
Reset();
|
||||
await Connect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
if (_hubConnection != null)
|
||||
{
|
||||
_hubConnection.StopAsync();
|
||||
_hubConnection.DisposeAsync();
|
||||
_hubConnection = null;
|
||||
}
|
||||
|
||||
if (_bindedEvent != null)
|
||||
{
|
||||
_bindedEvent.Clear();
|
||||
_bindedEvent = null;
|
||||
}
|
||||
|
||||
if (_eventAgg != null)
|
||||
{
|
||||
_eventAgg = null;
|
||||
}
|
||||
|
||||
if(_cachedEvents != null)
|
||||
{
|
||||
_cachedEvents.Clear();
|
||||
_cachedEvents = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if (_hubConnection != null)
|
||||
{
|
||||
_hubConnection.StopAsync();
|
||||
_hubConnection.DisposeAsync();
|
||||
_hubConnection = null;
|
||||
}
|
||||
|
||||
var cookie = _serverMgr.Cookie;
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(_url, option => option.Cookies = cookie)
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
_hubConnection.Reconnected += OnHubConnected;
|
||||
|
||||
_hubConnection.On<string,string, string>("ForceQuit", ForceQuit);
|
||||
|
||||
if (_bindedEvent != null)
|
||||
{
|
||||
_bindedEvent.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_bindedEvent = new HashSet<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
private Task OnHubConnected(string connectionId)
|
||||
{
|
||||
if(_cachedEvents.Count > 0)
|
||||
{
|
||||
foreach(var kv in _cachedEvents)
|
||||
{
|
||||
_hubConnection.On<string>(kv.Key, kv.Value);
|
||||
}
|
||||
_cachedEvents.Clear();
|
||||
}
|
||||
_hubConnection.Reconnected -= OnHubConnected;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public bool IsConnected => _hubConnection != null && _hubConnection.State == HubConnectionState.Connected;
|
||||
|
||||
public async Task Connect()
|
||||
{
|
||||
if(_hubConnection == null)
|
||||
{
|
||||
Debug.LogWarning("[RTService] hubConnection is null");
|
||||
return;
|
||||
}
|
||||
|
||||
//UnityEngine.Assertions.Assert.IsNotNull(_hubConnection, "[RTService] hubConnection is null");
|
||||
if (_hubConnection.State == HubConnectionState.Disconnected)
|
||||
{
|
||||
await _hubConnection.StartAsync();
|
||||
Debug.Log($"[RTService] Connected to SignalR server {_hubConnection.State == HubConnectionState.Connected}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Disconnect()
|
||||
{
|
||||
if(_hubConnection == null)
|
||||
{
|
||||
Debug.LogWarning("[RTService] hubConnection is null");
|
||||
return;
|
||||
}
|
||||
|
||||
//UnityEngine.Assertions.Assert.IsNotNull(_hubConnection, "[RTService] hubConnection is null");
|
||||
if (_hubConnection.State == HubConnectionState.Connected)
|
||||
{
|
||||
await _hubConnection.StopAsync();
|
||||
Debug.Log($"[RTService] Disconnected to SignalR server {_hubConnection.State == HubConnectionState.Disconnected}");
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable OnEvent<T>(Action<T> handler)
|
||||
{
|
||||
var methodName = typeof(T).Name;
|
||||
|
||||
if(!_bindedEvent.Contains(typeof(T)))
|
||||
{
|
||||
_bindedEvent.Add(typeof(T));
|
||||
if(IsConnected)
|
||||
{
|
||||
_hubConnection.On<string>(methodName, data => {
|
||||
var result =JsonConvert.DeserializeObject<T>(data);
|
||||
_eventAgg.Publish(result);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedEvents[methodName] = data => {
|
||||
|
||||
var result =JsonConvert.DeserializeObject<T>(data);
|
||||
_eventAgg.Publish(result);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return _eventAgg.GetEvent<T>().Subscribe(handler);
|
||||
}
|
||||
|
||||
public async Task<string> Publish(string methodName, string arg1)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<string>(methodName, arg1);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> Publish(string methodName, string arg1, string arg2)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<string>(methodName, arg1, arg2);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async void ForceQuit(string titleKey, string infoKey, string btnKey)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.NoticeConfirmPopupPanel);
|
||||
var noticeConfirmPopupPanel = go.GetComponent<NoticeConfirmPopupPanel>();
|
||||
string title = LocalizationMgr.GetText(titleKey ?? "UI_NoticePopupPanel_3");
|
||||
string info = LocalizationMgr.GetText(infoKey ?? "UI_NoticePopupPanel_4");
|
||||
string label = LocalizationMgr.GetText(btnKey ?? "UI_COMMON_confirm");
|
||||
noticeConfirmPopupPanel.Init(1, title, info, onClickLeft: Restart, onClose: Restart, btn_left_text: label);
|
||||
}
|
||||
|
||||
private async void Restart()
|
||||
{
|
||||
await LoadingScreen.Show();
|
||||
await GContext.container.Resolve<IStageService>().SwitchStageAsync("QuitStage");
|
||||
}
|
||||
|
||||
public async void Test()
|
||||
{
|
||||
Debug.Log("[RTService] Test invoking");
|
||||
var returnValue = await _hubConnection.InvokeAsync<string>("Test","arg1", "arg2");
|
||||
Debug.Log($"[RTService] Test invoked Value {returnValue}");
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Services/RTService.cs.meta
Normal file
11
Assets/Scripts/Services/RTService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6680abfdcadbf4a2db27f12961943508
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
90
Assets/Scripts/Services/RTServiceBgFgManager.cs
Normal file
90
Assets/Scripts/Services/RTServiceBgFgManager.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using game;
|
||||
using GameCore;
|
||||
using UnityEngine;
|
||||
|
||||
public class RTServiceBgFgManager : MonoBehaviour
|
||||
{
|
||||
public static bool keepAlive = false;
|
||||
|
||||
private async void OnApplicationFocus(bool focus)
|
||||
{
|
||||
if (focus)
|
||||
{
|
||||
var rtService = GContext.container.Resolve<IRTService>();
|
||||
var userService = GContext.container.Resolve<IUserService>();
|
||||
var mailService = GContext.container.Resolve<IInGameMailService>();
|
||||
if(rtService != null && userService != null && userService.IsLogin)
|
||||
{
|
||||
if(await NeedReboot())
|
||||
{
|
||||
RebootAlert();
|
||||
}
|
||||
else {
|
||||
try
|
||||
{
|
||||
await rtService.Connect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
await mailService.FetchMail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationPause(bool pause)
|
||||
{
|
||||
if (pause && !keepAlive)
|
||||
{
|
||||
var rtService = GContext.container.Resolve<IRTService>();
|
||||
var userService = GContext.container.Resolve<IUserService>();
|
||||
if(rtService != null && userService != null && userService.IsLogin)
|
||||
{
|
||||
rtService.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void RebootAlert()
|
||||
{
|
||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.NoticeConfirmPopupPanel);
|
||||
var noticeConfirmPopupPanel = go.GetComponent<NoticeConfirmPopupPanel>();
|
||||
string title = LocalizationMgr.GetText("UI_NoticePopupPanel_3");
|
||||
string info = LocalizationMgr.GetText("UI_NoticePopupPanel_4");
|
||||
string label = LocalizationMgr.GetText("UI_COMMON_confirm");
|
||||
noticeConfirmPopupPanel.Init(1, title, info, onClickLeft: RootCtx.ExitGame, onClose: RootCtx.ExitGame, btn_left_text: label);
|
||||
}
|
||||
|
||||
private async Task<bool> NeedReboot()
|
||||
{
|
||||
var userService = GContext.container.Resolve<IUserService>();
|
||||
var config = GContext.container.Resolve<IConfig>();
|
||||
|
||||
if(userService == null || !userService.IsLogin)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config == null) return false;
|
||||
|
||||
var loginTime = userService.LoginTime;
|
||||
var duration = ZZTimeHelper.UtcNow() - loginTime;
|
||||
if(duration.Days >=1)
|
||||
{
|
||||
var localVer = VersionTool.FromLocal();
|
||||
var remoteConfig = await ConfigExtension.GetRemoteConfig();
|
||||
if(remoteConfig == null) return false;
|
||||
var remoteVerStr = remoteConfig[GConstant.K_Ver];
|
||||
var remoteVer = VersionTool.FromString(remoteVerStr);
|
||||
return remoteVer > localVer || remoteVer.Build != localVer.Build;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/RTServiceBgFgManager.cs.meta
Normal file
11
Assets/Scripts/Services/RTServiceBgFgManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fc53d6ebea56406d8f406cda0cd5f18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
134
Assets/Scripts/Services/RedeemCodeService.cs
Normal file
134
Assets/Scripts/Services/RedeemCodeService.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
using asap.core;
|
||||
using game;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
public class RedeemCodeService
|
||||
{
|
||||
public class CheckRedemptionKeyRequest
|
||||
{
|
||||
public string playerID;
|
||||
public string Key { get; set; }
|
||||
}
|
||||
|
||||
public class CheckRedemptionKeyResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// RedeemSucc:DropID RegisterDayNotEnough:NeedDays
|
||||
/// </summary>
|
||||
public int Code;
|
||||
public ECheckValidateResult Result;
|
||||
}
|
||||
|
||||
public enum ECheckValidateResult
|
||||
{
|
||||
invalid = 0,
|
||||
success,
|
||||
hasRedeemed,
|
||||
expired,
|
||||
NotFound,
|
||||
MaxRedeemCount,
|
||||
BusyServer,
|
||||
RegisterDayNotEnough,
|
||||
}
|
||||
|
||||
|
||||
#region Field&&Property ༼ つ ◕_◕ ༽つ--ฅʕ•̫͡•ʔฅ
|
||||
|
||||
public bool IsUnlock = false;
|
||||
|
||||
public DateTime nextRedeemTime;
|
||||
|
||||
private HttpClient _funcClient;
|
||||
private string _funcKey;
|
||||
private IConfig _config;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Function ( =∩王∩= )m~~o(=•ェ•=)m
|
||||
|
||||
public RedeemCodeService(IConfig config)
|
||||
{
|
||||
this._config = config;
|
||||
var url = config.Get<string>(GConstant.K_FuncUrl, "");
|
||||
_funcKey = config.Get<string>(GConstant.K_FuncKey, "");
|
||||
if(string.IsNullOrEmpty(_funcKey)||string.IsNullOrEmpty(url))
|
||||
{
|
||||
Debug.LogError("FuncUrl or FuncKey is Null");
|
||||
return;
|
||||
}
|
||||
|
||||
_funcClient = new HttpClient();
|
||||
_funcClient.BaseAddress = new System.Uri(url);
|
||||
_funcClient.DefaultRequestHeaders.Add("x-functions-key", _funcKey);
|
||||
_funcClient.Timeout = TimeSpan.FromSeconds(15);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns>0:success 1:invalide 2:hasUsed 3:timeExpired</returns>
|
||||
public async Task<CheckRedemptionKeyResponse> CheckRedemptionKeyValidate(string key)
|
||||
{
|
||||
var response = new CheckRedemptionKeyResponse();
|
||||
// var cdKeys = GContext.container.Resolve<Tables>().TbCDKey.DataMap;
|
||||
|
||||
// var dropID = -1;
|
||||
|
||||
if ( string.IsNullOrEmpty(key) )
|
||||
{
|
||||
response.Result = ECheckValidateResult.invalid;
|
||||
return response;
|
||||
}
|
||||
var result = await CheckRedmptionKeyVallidateInServer(key);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<CheckRedemptionKeyResponse> CheckRedmptionKeyVallidateInServer(string key)
|
||||
{
|
||||
var checkValidateRequest = new CheckRedemptionKeyRequest
|
||||
{
|
||||
Key = key,
|
||||
playerID = GContext.container.Resolve<IUserService>().UserId,
|
||||
};
|
||||
|
||||
//Request
|
||||
var reqJson = JsonConvert.SerializeObject(checkValidateRequest);
|
||||
var reqContent = new StringContent(reqJson, Encoding.UTF8, "application/json");
|
||||
|
||||
var postResponse= await _funcClient.PostAsync("api/CheckRedeemCodeValiad", reqContent);
|
||||
|
||||
//Response
|
||||
var respJson = "";
|
||||
|
||||
if ( postResponse.IsSuccessStatusCode )
|
||||
{
|
||||
respJson= await postResponse.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
//error
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"[RedemptionKey error] {postResponse.StatusCode}");
|
||||
UnityEngine.Debug.LogError($"[RedemptionKey content][{respJson}]");
|
||||
}
|
||||
if ( string.IsNullOrEmpty(respJson) )
|
||||
{
|
||||
var response = new CheckRedemptionKeyResponse();
|
||||
response.Result = ECheckValidateResult.invalid;
|
||||
return response;
|
||||
}
|
||||
|
||||
//success
|
||||
return JsonConvert.DeserializeObject<CheckRedemptionKeyResponse>(respJson);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
*/
|
||||
11
Assets/Scripts/Services/RedeemCodeService.cs.meta
Normal file
11
Assets/Scripts/Services/RedeemCodeService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 019a293bfdf543c4baa31b84d5d2af55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Services/ReportService.cs
Normal file
33
Assets/Scripts/Services/ReportService.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class ReportService : IReportService
|
||||
{
|
||||
Queue<ReportData> reportQueue = new Queue<ReportData>();
|
||||
Queue<ReportData> aquariumReportQueue = new Queue<ReportData>();
|
||||
|
||||
public void AddReport(ReportData reportData)
|
||||
{
|
||||
if (reportData.type == ReportDataType.Aquarium)
|
||||
{
|
||||
aquariumReportQueue.Enqueue(reportData);
|
||||
}
|
||||
reportQueue.Enqueue(reportData);
|
||||
}
|
||||
|
||||
public ReportData GetReportData()
|
||||
{
|
||||
if (reportQueue.Count > 0)
|
||||
{
|
||||
return reportQueue.Dequeue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public ReportData GetAquariumReportData()
|
||||
{
|
||||
if (aquariumReportQueue.Count > 0)
|
||||
{
|
||||
return aquariumReportQueue.Dequeue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/ReportService.cs.meta
Normal file
11
Assets/Scripts/Services/ReportService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 694680fb105f31946859cef90bdb0d73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
147
Assets/Scripts/Services/SettingService.cs
Normal file
147
Assets/Scripts/Services/SettingService.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using Game;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public interface ISettingService
|
||||
{
|
||||
bool Music { get; set; }
|
||||
bool Sound { get; set; }
|
||||
bool Vibration { get; set; }
|
||||
bool Notice { get; }
|
||||
string Lang { get; set; }
|
||||
int UnitOfWeight { get; set; }
|
||||
}
|
||||
|
||||
public class DefaultSettingService : ISettingService
|
||||
{
|
||||
bool _music;
|
||||
bool _sound;
|
||||
bool _vibration;
|
||||
string _lang;
|
||||
int _unitOfWeight = 1;
|
||||
|
||||
public bool Music
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != _music)
|
||||
{
|
||||
PlayerPrefs.SetInt("Music", value ? 1 : 0);
|
||||
_music = value;
|
||||
GContext.Publish(new SoundMuteEvent(0));
|
||||
}
|
||||
}
|
||||
get { return _music; }
|
||||
}
|
||||
|
||||
public bool Sound
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != _sound)
|
||||
{
|
||||
PlayerPrefs.SetInt("Sound", value ? 1 : 0);
|
||||
_sound = value;
|
||||
GContext.Publish(new SoundMuteEvent(1));
|
||||
}
|
||||
}
|
||||
get { return _sound; }
|
||||
}
|
||||
|
||||
public bool Vibration
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != _vibration)
|
||||
{
|
||||
PlayerPrefs.SetInt("Vibration", value ? 1 : 0);
|
||||
_vibration = value;
|
||||
}
|
||||
}
|
||||
|
||||
get { return _vibration; }
|
||||
}
|
||||
|
||||
public bool Notice
|
||||
{
|
||||
get
|
||||
{
|
||||
return GContext.container.Resolve<ILocalNotificationService>().IsNoticeOpen;
|
||||
}
|
||||
}
|
||||
|
||||
public string Lang
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != _lang)
|
||||
{
|
||||
PlayerPrefs.SetString("Lang", value);
|
||||
_lang = value;
|
||||
}
|
||||
}
|
||||
get { return _lang; }
|
||||
}
|
||||
public int UnitOfWeight
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != _unitOfWeight)
|
||||
{
|
||||
PlayerPrefs.SetInt("UnitOfWeight", value);
|
||||
_unitOfWeight = value;
|
||||
}
|
||||
}
|
||||
get { return _unitOfWeight; }
|
||||
}
|
||||
|
||||
public void Init(cfg.Tables tables)
|
||||
{
|
||||
if (!PlayerPrefs.HasKey("Music"))
|
||||
{
|
||||
var globalConfig = tables.TbGlobalConfig;
|
||||
Music = globalConfig.MusicSetting;
|
||||
Sound = globalConfig.SoundSetting;
|
||||
Vibration = true;
|
||||
CultureInfo info = System.Globalization.CultureInfo.CurrentUICulture;
|
||||
string Language = info.TwoLetterISOLanguageName;
|
||||
if (Language == "zh")
|
||||
{
|
||||
if (info.DisplayName.Contains("Simplified"))
|
||||
{
|
||||
Language = "zh_Hans";
|
||||
}
|
||||
else
|
||||
{
|
||||
Language = "zh_Hant";
|
||||
}
|
||||
}
|
||||
Lang = Language;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_music = PlayerPrefs.GetInt("Music") == 1;
|
||||
_sound = PlayerPrefs.GetInt("Sound") == 1;
|
||||
_vibration = PlayerPrefs.GetInt("Vibration") == 1;
|
||||
_lang = PlayerPrefs.GetString("Lang");
|
||||
_unitOfWeight = PlayerPrefs.GetInt("UnitOfWeight");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> AskPermission()
|
||||
{
|
||||
var result = new TaskCompletionSource<bool>();
|
||||
var callbacks = new UnityEngine.Android.PermissionCallbacks();
|
||||
callbacks.PermissionGranted += (x) => result.SetResult(true);
|
||||
callbacks.PermissionDeniedAndDontAskAgain += (x) => result.SetResult(false);
|
||||
callbacks.PermissionDenied += (x) => result.SetResult(false);
|
||||
UnityEngine.Android.Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS", callbacks);
|
||||
return await result.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/SettingService.cs.meta
Normal file
11
Assets/Scripts/Services/SettingService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66df633f2d189ac4e989aa7461e126bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
56
Assets/Scripts/Services/SmallGameModel.cs
Normal file
56
Assets/Scripts/Services/SmallGameModel.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace game
|
||||
{
|
||||
public enum EnemyType : byte
|
||||
{
|
||||
Bomb = 0,
|
||||
Heist = 1,
|
||||
Aquarium = 2,
|
||||
}
|
||||
public class SetCampIDRequest
|
||||
{
|
||||
public string playerID;
|
||||
public int campID;
|
||||
}
|
||||
public class SetCampIDResponse
|
||||
{
|
||||
}
|
||||
public class GetCampIDRequest
|
||||
{
|
||||
public List<string> playerIDs;
|
||||
}
|
||||
public class GetCampIDResponse
|
||||
{
|
||||
public Dictionary<string, int> campIDs;
|
||||
}
|
||||
/// <summary>
|
||||
/// 敌人
|
||||
/// </summary>
|
||||
public class SetEnemyIDRequest
|
||||
{
|
||||
public string playerID;
|
||||
public string enemyID;
|
||||
public EnemyType enemyType;
|
||||
public int albumEventID;
|
||||
public string content;
|
||||
}
|
||||
public class SetEnemyIDResponse
|
||||
{
|
||||
}
|
||||
public class GetEnemyIDRequest
|
||||
{
|
||||
public string playerID;
|
||||
public EnemyType enemyType;
|
||||
public int albumEventID;
|
||||
}
|
||||
public class GetEnemyIDResponse
|
||||
{
|
||||
public EnemyType enemyType;
|
||||
public List<string> enemyIDs;
|
||||
public List<int> campID;
|
||||
//public List<float> scoreList;
|
||||
//public List<string> avatar { get; set; }
|
||||
//public List<string> displayName { get; set; }
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/SmallGameModel.cs.meta
Normal file
11
Assets/Scripts/Services/SmallGameModel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b99ef6c57964fc24f84a2236de49270a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
232
Assets/Scripts/Services/SurveyService.cs
Normal file
232
Assets/Scripts/Services/SurveyService.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using asap.core;
|
||||
using game;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
public class SurveyService
|
||||
{
|
||||
const string SurveyUrl = "https://pt93-tyqnr.qijihdhk.com/";
|
||||
const string SurveyData = "SurveyData";
|
||||
const string SurveyReadSidData = "SurveyReadSidData";
|
||||
|
||||
ICustomServerMgr customServerMgr;
|
||||
IUserService userService;
|
||||
cfg.Tables tables;
|
||||
MatchlistData matchlistData { get; set; }
|
||||
List<string> receivedReward = new List<string>();
|
||||
List<string> readSid = new List<string>();
|
||||
public SurveyService(ICustomServerMgr customServerMgr, IUserService userService, cfg.Tables tables)
|
||||
{
|
||||
this.customServerMgr = customServerMgr;
|
||||
this.userService = userService;
|
||||
this.tables = tables;
|
||||
string surveyData = PlayFabMgr.Instance.GetLocalData(SurveyData);
|
||||
if (!string.IsNullOrEmpty(surveyData))
|
||||
{
|
||||
receivedReward = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(surveyData);
|
||||
}
|
||||
string surveyReadSidData = PlayFabMgr.Instance.GetLocalData(SurveyReadSidData);
|
||||
if (!string.IsNullOrEmpty(surveyReadSidData))
|
||||
{
|
||||
readSid = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(surveyReadSidData);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 拉取问卷
|
||||
/// </summary>
|
||||
public async void PostSurveyMatchlist()
|
||||
{
|
||||
try
|
||||
{
|
||||
PlayerData playerData = GContext.container.Resolve<PlayerData>();
|
||||
if (playerData.lv < tables.TbGlobalConfig.SurveyLevelRequire)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int register_days = (ZZTimeHelper.UtcNow() - userService.CreateTime).Days;
|
||||
float totalPay = GContext.container.Resolve<PlayerShopData>().GetBuyPaymentAmount();
|
||||
|
||||
PostMatchlist post = new PostMatchlist
|
||||
{
|
||||
uid = userService.CustomId,//"318904",//
|
||||
register_days = register_days,
|
||||
language = userService.Language,
|
||||
totalPay = totalPay,
|
||||
level = playerData.lv,
|
||||
vip = playerData.vip
|
||||
};
|
||||
matchlistData = null;
|
||||
string boby = Newtonsoft.Json.JsonConvert.SerializeObject(post);
|
||||
string url = $"{SurveyUrl}api/dwsurvey/anon/response/matchList.do?appId=17&platformName=ft";
|
||||
string json = await customServerMgr.CustomServerPost(url, boby);
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
matchlistData = Newtonsoft.Json.JsonConvert.DeserializeObject<MatchlistData>(json);
|
||||
}
|
||||
//设置红点
|
||||
SetRedPoint();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("PostSurveyMatchlist:" + e);
|
||||
}
|
||||
|
||||
}
|
||||
public string Sid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (matchlistData != null && matchlistData.resultCode == 200 && matchlistData.data.Length > 0)
|
||||
{
|
||||
return matchlistData.data[0].sid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public int Award
|
||||
{
|
||||
get
|
||||
{
|
||||
if (matchlistData != null && matchlistData.resultCode == 200 && matchlistData.data.Length > 0)
|
||||
{
|
||||
string award = matchlistData.data[0].award;
|
||||
if (int.TryParse(award, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
void SetRedPoint()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Sid) || readSid.Contains(Sid))
|
||||
{
|
||||
RedPointManager.Instance.SetRedPointState("menu.survey", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
RedPointManager.Instance.SetRedPointState("menu.survey", true);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 请求答题的链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetSurveyAnswer()
|
||||
{
|
||||
string url = $"{SurveyUrl}static/diaowen/answer-p.html?";
|
||||
string register_days = (ZZTimeHelper.UtcNow() - userService.CreateTime).Days.ToString();
|
||||
string totalPay = GContext.container.Resolve<PlayerShopData>().GetBuyPaymentAmount().ToString();
|
||||
PlayerData playerData = GContext.container.Resolve<PlayerData>();
|
||||
url += $"sid={Sid}" +
|
||||
"&platform=ft" +
|
||||
$"&uid={userService.CustomId}" +
|
||||
$"&language={userService.Language}" +
|
||||
$"®ister_days={register_days}" +
|
||||
$"&extraInfo={playerData.lv}" +
|
||||
$"&totalPay={totalPay}";
|
||||
//标记已读
|
||||
readSid.Add(Sid);
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(SurveyReadSidData, Newtonsoft.Json.JsonConvert.SerializeObject(readSid));
|
||||
//设置红点
|
||||
SetRedPoint();
|
||||
return url;
|
||||
}
|
||||
/// <summary>
|
||||
/// 检查是否能领奖
|
||||
/// </summary>
|
||||
public async void GetSurveyCheckAnswer()
|
||||
{
|
||||
try
|
||||
{
|
||||
string sid = Sid;
|
||||
string url = $"{SurveyUrl}api/dwsurvey/anon/response/checkAnswer.do?";
|
||||
url += $"uid={userService.CustomId}&surveySid={sid}&appId=17&platformName=ft";
|
||||
|
||||
//#if UNITY_EDITOR
|
||||
// //测试
|
||||
// url = "https://pt93-tyqnr.qijihdhk.com/api/dwsurvey/anon/response/checkAnswer.do?surveySid=8zij9i5&uid=1&platformName=ft&appId=17";
|
||||
//#endif
|
||||
matchlistData = null;
|
||||
|
||||
string json = await customServerMgr.GetStringAsync(url);
|
||||
if (receivedReward.Contains(sid))
|
||||
{
|
||||
//Debug.Log("已经领过奖:" + json);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||
{
|
||||
SurveyCheckAnswerResult data = Newtonsoft.Json.JsonConvert.DeserializeObject<SurveyCheckAnswerResult>(json);
|
||||
if (data.resultCode == 200 && data.data != null)
|
||||
{
|
||||
SurveyCheckAnswerData surveyCheckAnswerData = Newtonsoft.Json.JsonConvert.DeserializeObject<SurveyCheckAnswerData>(data.data);
|
||||
var SurveyReward = tables.TbGlobalConfig.SurveyReward;
|
||||
string awardStr = surveyCheckAnswerData.award;
|
||||
if (int.TryParse(awardStr, out int award))
|
||||
{
|
||||
if (!SurveyReward.Contains(award))
|
||||
{
|
||||
Debug.LogError("问卷奖励错误: " + awardStr);
|
||||
award = SurveyReward[0];
|
||||
}
|
||||
GContext.container.Resolve<PlayerItemData>().AddItemByDrop(award);
|
||||
GContext.Publish(new ShowData());
|
||||
receivedReward.Add(sid);
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(SurveyData, Newtonsoft.Json.JsonConvert.SerializeObject(receivedReward));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("问卷奖励错误: " + awardStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("GetSurveyCheckAnswer:" + e);
|
||||
}
|
||||
|
||||
}
|
||||
class PostMatchlist
|
||||
{
|
||||
public string uid { get; set; }
|
||||
public int register_days { get; set; }
|
||||
public string language { get; set; }
|
||||
public float totalPay { get; set; }
|
||||
public int level { get; set; }
|
||||
public int vip { get; set; }
|
||||
}
|
||||
}
|
||||
public class MatchlistData
|
||||
{
|
||||
public int resultCode { get; set; }
|
||||
public string resultMsg { get; set; }
|
||||
public MatchlistDataInfo[] data { get; set; }
|
||||
}
|
||||
public class MatchlistDataInfo
|
||||
{
|
||||
public string award { get; set; }
|
||||
public string defaultLanguage { get; set; }
|
||||
public string[] languages { get; set; }
|
||||
public string surveyNameText { get; set; }
|
||||
public string id { get; set; }
|
||||
public string creatDate { get; set; }
|
||||
public string sid { get; set; }
|
||||
public string title { get; set; }
|
||||
public string introduce { get; set; }
|
||||
}
|
||||
|
||||
public class SurveyCheckAnswerResult
|
||||
{
|
||||
public int resultCode { get; set; }
|
||||
public string resultMsg { get; set; }
|
||||
public string data { get; set; }
|
||||
}
|
||||
public class SurveyCheckAnswerData
|
||||
{
|
||||
public string award { get; set; }
|
||||
public string extraInfo { get; set; }
|
||||
}
|
||||
11
Assets/Scripts/Services/SurveyService.cs.meta
Normal file
11
Assets/Scripts/Services/SurveyService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c560dba35e283c54ebc265de1d2f5ca1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
580
Assets/Scripts/Services/Tables.cs
Normal file
580
Assets/Scripts/Services/Tables.cs
Normal file
@@ -0,0 +1,580 @@
|
||||
using asap.core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.SharpZipLib.Zip;
|
||||
using System.Net;
|
||||
using UnityEngine.Networking;
|
||||
using System.Threading;
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
public sealed partial class Tables
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public static async System.Threading.Tasks.Task<Tables> InitEditor(Action<float> progress)
|
||||
{
|
||||
var cwd = Directory.GetParent(Directory.GetCurrentDirectory());
|
||||
var dir = Path.Combine(cwd.FullName, "cfgData");
|
||||
|
||||
var tables = new cfg.Tables(
|
||||
tableName => SimpleJSON.JSON.Parse(File.ReadAllText(Path.Combine(dir, $"{tableName}.json")))
|
||||
);
|
||||
await Task.Yield();
|
||||
progress.Invoke(1f);
|
||||
await Task.Yield();
|
||||
return tables;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static async System.Threading.Tasks.Task<Tables> Init(Action<float> progress)
|
||||
{
|
||||
|
||||
var dir = Path.Combine(Application.persistentDataPath, "cfgData");
|
||||
var verFilePath = Path.Combine(dir, "conf_ver.txt");
|
||||
var ver = File.ReadAllText(verFilePath).Trim();
|
||||
Debug.Log($"cfg init ver {ver}");
|
||||
var zipFilePath = Path.Combine(dir, $"{ver}.zip");
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Assertions.Assert.IsTrue(File.Exists(zipFilePath), $"File {zipFilePath} not found");
|
||||
#endif
|
||||
progress.Invoke(0f);
|
||||
|
||||
var p = (VersionTool.PackVer.Replace("_", "") + ver).Substring(0, 8);
|
||||
var map = await Task.Run<Dictionary<string, string>>(() => GetEntryContent(zipFilePath, p));
|
||||
|
||||
|
||||
progress.Invoke(0.5f);
|
||||
await Task.Yield();
|
||||
|
||||
var tables = new cfg.Tables(
|
||||
tableName => SimpleJSON.JSON.Parse(map[tableName])
|
||||
);
|
||||
|
||||
progress.Invoke(1f);
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> GetEntryContent(string zipPath, string p)
|
||||
{
|
||||
var map = new Dictionary<string, string>();
|
||||
var memoryStream = new MemoryStream();
|
||||
using (var zip = new ZipFile(zipPath))
|
||||
{
|
||||
zip.Password = p;
|
||||
foreach (ZipEntry entry in zip)
|
||||
{
|
||||
if (entry.Name.EndsWith(".json"))
|
||||
{
|
||||
using (var stream = zip.GetInputStream(entry))
|
||||
{
|
||||
memoryStream.SetLength(0);
|
||||
memoryStream.Position = 0;
|
||||
stream.CopyTo(memoryStream);
|
||||
var content = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||||
map.Add(Path.GetFileNameWithoutExtension(entry.Name), content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryStream.Close();
|
||||
memoryStream.Dispose();
|
||||
return map;
|
||||
}
|
||||
|
||||
//public static async System.Threading.Tasks.Task<Tables> Init(Action<float> progress)
|
||||
//{
|
||||
//var rawDataMap = new Dictionary<string, string>();
|
||||
//var opMap = new Dictionary<string, AsyncOperationHandle<TextAsset>>();
|
||||
|
||||
//var props = typeof(Tables).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
//var addrs = props.Select(_ => _.Name.ToLower()).ToList();
|
||||
|
||||
//foreach (var addr in addrs)
|
||||
//{
|
||||
//var op = Addressables.LoadAssetAsync<TextAsset>(addr);
|
||||
//opMap.Add(addr, op);
|
||||
//}
|
||||
|
||||
//var tasks = opMap.Values.Select(_ => _.Task);
|
||||
//var total = (float)tasks.Count();
|
||||
//while (true)
|
||||
//{
|
||||
//var completed = tasks.Count(_ => _.IsCompleted);
|
||||
//if (completed == total)
|
||||
//{
|
||||
//progress.Invoke(1f);
|
||||
//break;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//progress.Invoke(completed / total);
|
||||
//}
|
||||
//await Awaiters.NextFrame;
|
||||
//}
|
||||
|
||||
//var tables = new cfg.Tables(
|
||||
//tableName => SimpleJSON.JSON.Parse(opMap[tableName].Result.text)
|
||||
//);
|
||||
|
||||
//foreach (var kv in opMap)
|
||||
//{
|
||||
//Addressables.Release(kv.Value);
|
||||
//}
|
||||
|
||||
//progress.Invoke(1f);
|
||||
|
||||
//return tables;
|
||||
//}
|
||||
//
|
||||
|
||||
private static void EnsureDefaultCfgFileExists(out string dir, out string persistCfgFile)
|
||||
{
|
||||
//Copy build-in cfg to persistentDataPath is not exists
|
||||
dir = Path.Combine(Application.persistentDataPath, "cfgData");
|
||||
persistCfgFile = Path.Combine(dir, "conf_ver.txt");
|
||||
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Debug.Log($"create dir {dir}");
|
||||
Directory.CreateDirectory(dir);
|
||||
var files = BetterStreamingAssets.GetFiles("cfgData");
|
||||
foreach (var file in files)
|
||||
{
|
||||
var savePath = Path.Combine(dir, Path.GetFileName(file));
|
||||
if (File.Exists(savePath)) File.Delete(savePath);
|
||||
Debug.Log($"copy {file} to {savePath}");
|
||||
File.WriteAllBytes(savePath, BetterStreamingAssets.ReadAllBytes(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static readonly List<(float vtimeout, float ztimeout)> timeoutValues = new() { (1, 3), (2, 5), (2, 5) };
|
||||
public static async Task<bool> UpdateCfg(IConfig config, bool isSuccessLoadRemoteConfigFile)
|
||||
{
|
||||
EnsureDefaultCfgFileExists(out var dir, out var persistCfgFile);
|
||||
|
||||
if (!isSuccessLoadRemoteConfigFile)
|
||||
return true;
|
||||
|
||||
var maxRetryTimes = timeoutValues.Count;
|
||||
|
||||
for (int retryTime = 0; retryTime < maxRetryTimes; retryTime++)
|
||||
{
|
||||
(var vtimeout, var ztimeout) = timeoutValues[retryTime];
|
||||
|
||||
if (await DoUpdateCfgUWR(config, dir, persistCfgFile, (int)MathF.Ceiling(vtimeout), (int)MathF.Ceiling(ztimeout), retryTime, maxRetryTimes))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<bool> DoUpdateCfgUWR(
|
||||
IConfig config,
|
||||
string dir, string persistCfgFile,
|
||||
int verFileTimeoutInSec, int cfgDataTimeoutInSec,
|
||||
int retryTimes, int maxRetryTimes)
|
||||
{
|
||||
var stopwatch = new System.Diagnostics.Stopwatch();
|
||||
string localVer = File.ReadAllText(persistCfgFile).Trim();
|
||||
string remoteVer = localVer;
|
||||
var staticResUrl = config.Get<string>(GConstant.K_Static_Res_URL, GConstant.V_Static_Res_URL);
|
||||
var remoteVerUrl = $"{staticResUrl}/cfgData/conf_ver.txt";
|
||||
using (var verReq = UnityWebRequest.Get(remoteVerUrl))
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(verFileTimeoutInSec));
|
||||
var ct = cts.Token;
|
||||
verReq.timeout = verFileTimeoutInSec;
|
||||
verReq.SetRequestHeader("Accept", "application/json");
|
||||
stopwatch.Start();
|
||||
var op = verReq.SendWebRequest();
|
||||
try
|
||||
{
|
||||
while (!op.isDone && !ct.IsCancellationRequested)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
ct.ThrowIfCancellationRequested();
|
||||
stopwatch.Stop();
|
||||
if (verReq.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
Debug.LogWarning($"Load cfg Ver file failed {verReq.result.ToString()} {verReq.error} {retryTimes + 1}/{maxRetryTimes}");
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfgver");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", verReq.result.ToString());
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", verReq.error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
remoteVer = verReq.downloadHandler.text.Trim();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
verReq.Abort();
|
||||
Debug.LogWarning($"Load cfg Ver file cancel {verFileTimeoutInSec}s {retryTimes + 1}/{maxRetryTimes}");
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfgver");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", "cancel");
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", verReq.error ?? "cancel");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteVer == localVer) return true;
|
||||
|
||||
var remoteCfgUrl = $"{staticResUrl}/cfgData/{remoteVer}.zip";
|
||||
var savePath = Path.Combine(dir, $"{remoteVer}.zip");
|
||||
using (var cfgReq = UnityWebRequest.Get(remoteCfgUrl))
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(cfgDataTimeoutInSec));
|
||||
var ct = cts.Token;
|
||||
cfgReq.timeout = cfgDataTimeoutInSec;
|
||||
cfgReq.downloadHandler = new DownloadHandlerFile(savePath, false);
|
||||
stopwatch.Reset();
|
||||
stopwatch.Restart();
|
||||
var op = cfgReq.SendWebRequest();
|
||||
try
|
||||
{
|
||||
while (!op.isDone && !ct.IsCancellationRequested)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
ct.ThrowIfCancellationRequested();
|
||||
stopwatch.Stop();
|
||||
if (cfgReq.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
if (File.Exists(savePath)) File.Delete(savePath);
|
||||
|
||||
Debug.LogWarning($"Load cfg file failed {cfgReq.result.ToString()} {cfgReq.error} {retryTimes + 1}/{maxRetryTimes}");
|
||||
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", cfgReq.result.ToString());
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", cfgReq.error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (File.Exists(persistCfgFile)) File.Delete(persistCfgFile);
|
||||
File.WriteAllText(persistCfgFile, remoteVer);
|
||||
Debug.Log($"cfg is updated from {localVer} to {remoteVer}");
|
||||
return true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
cfgReq.Abort();
|
||||
stopwatch.Stop();
|
||||
Debug.LogWarning($"Load cfg file cancel {cfgDataTimeoutInSec}s {retryTimes + 1}/{maxRetryTimes}");
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", stopwatch.ElapsedMilliseconds);
|
||||
e.AddContent("reason", "cancel");
|
||||
e.AddContent("skip", retryTimes >= maxRetryTimes - 1);
|
||||
e.AddContent("error", cfgReq.error ?? "cancel");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
private static async Task<bool> DoUpdateCfg(
|
||||
IConfig config,
|
||||
string dir, string persistCfgFile,
|
||||
int verFileTimeoutInSec, int cfgDataTimeoutInSec,
|
||||
int retryTimes)
|
||||
{
|
||||
|
||||
var stopwatch = new System.Diagnostics.Stopwatch();
|
||||
var content = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string localVer = File.ReadAllText(persistCfgFile).Trim();
|
||||
var staticResUrl = config.Get<string>(GConstant.K_Static_Res_URL, GConstant.V_Static_Res_URL);
|
||||
if (staticResUrl.Equals(GConstant.V_Static_Res_URL))
|
||||
{
|
||||
staticResUrl = string.Format(GConstant.V_Static_Res_URL, VersionTool.PackVer);
|
||||
}
|
||||
var remoteVerUrl = $"{staticResUrl}/cfgData/conf_ver.txt";
|
||||
content = "conf_ver";
|
||||
|
||||
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 HttpClient(handler))
|
||||
{
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(verFileTimeoutInSec);
|
||||
stopwatch.Start();
|
||||
var verFileRespon = await httpClient.GetAsync(remoteVerUrl);
|
||||
stopwatch.Stop();
|
||||
|
||||
if (verFileRespon.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
Debug.LogWarning($"Load cfg Ver file failed {verFileRespon.StatusCode.ToString()}");
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", verFileRespon.StatusCode.ToString());
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var remoteVer = (await verFileRespon.Content.ReadAsStringAsync()).Trim();
|
||||
|
||||
if (remoteVer != localVer)
|
||||
{
|
||||
var remoteCfgUrl = $"{staticResUrl}/cfgData/{remoteVer}.zip";
|
||||
content = "cfgzip";
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(cfgDataTimeoutInSec);
|
||||
stopwatch.Reset();
|
||||
stopwatch.Start();
|
||||
var remoteCfgRespon = await httpClient.GetAsync(remoteCfgUrl);
|
||||
stopwatch.Stop();
|
||||
|
||||
if (remoteCfgRespon.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
Debug.LogWarning($"Load cfg zip file failed {remoteCfgRespon.StatusCode.ToString()}");
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", remoteCfgRespon.StatusCode.ToString());
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("content", content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var savePath = Path.Combine(dir, $"{remoteVer}.zip");
|
||||
var remoteCfg = await remoteCfgRespon.Content.ReadAsByteArrayAsync();
|
||||
|
||||
if (File.Exists(savePath)) File.Delete(savePath);
|
||||
await File.WriteAllBytesAsync(savePath, remoteCfg);
|
||||
|
||||
if (File.Exists(persistCfgFile)) File.Delete(persistCfgFile);
|
||||
File.WriteAllText(persistCfgFile, remoteVer);
|
||||
Debug.Log($"cfg is updated from {localVer} to {remoteVer}");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException httpEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
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);
|
||||
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", "httpEx");
|
||||
e.AddContent("error", httpEx.Message);
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("content", content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (System.Threading.Tasks.TaskCanceledException timeoutEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
Debug.LogWarning($"Request timeout after {verFileTimeoutInSec}s: {timeoutEx.Message}");
|
||||
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", "timeout");
|
||||
e.AddContent("error", timeoutEx.Message);
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("content", content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (System.IO.IOException ioEx)
|
||||
{
|
||||
if (stopwatch.IsRunning)
|
||||
stopwatch.Stop();
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
Debug.LogWarning($"IO operation failed: {ioEx.Message}");
|
||||
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", "io_exception");
|
||||
e.AddContent("error", ioEx.Message);
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("content", content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (stopwatch.IsRunning) stopwatch.Stop();
|
||||
var elapsed = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
var errorMessage = $"Unexpected error loading cfg: {exception.Message}";
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
errorMessage += $" Inner: {exception.InnerException.Message}";
|
||||
}
|
||||
Debug.LogError(errorMessage);
|
||||
|
||||
using (var e = GEvent.TackEvent("retry"))
|
||||
{
|
||||
e.AddContent("type", "cfg");
|
||||
e.AddContent("duration_ms", elapsed);
|
||||
e.AddContent("reason", "unexpected_error");
|
||||
e.AddContent("error", exception.Message);
|
||||
e.AddContent("skip", retryTimes >= 2);
|
||||
e.AddContent("content", content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
||||
//private async Task ExtractCfg(string ver)
|
||||
//{
|
||||
//var zipFilePath = Path.Combine(Application.persistentDataPath, $"{ver}.zip");
|
||||
//var saveDir = Path.Combine(Application.persistentDataPath, "cfgData");
|
||||
//if (Directory.Exists(saveDir))
|
||||
//{
|
||||
//Directory.Delete(saveDir, true);
|
||||
//}
|
||||
//await Task.Run(() => ZipFile.ExtractToDirectory(zipFilePath, Application.persistentDataPath));
|
||||
//File.Delete(zipFilePath);
|
||||
//}
|
||||
}
|
||||
|
||||
public static class TablesExtensions
|
||||
{
|
||||
public static cfg.MapData GetMapData(this Tables tables, int id)
|
||||
{
|
||||
return tables.TbMapData[id];
|
||||
}
|
||||
|
||||
public static cfg.FishData GetFishData(this Tables tables, int id)
|
||||
{
|
||||
var fishData = tables.TbFishData;
|
||||
|
||||
if (!fishData.DataMap.ContainsKey(id))
|
||||
{
|
||||
return fishData.DataList[0];
|
||||
}
|
||||
|
||||
return fishData[id];
|
||||
}
|
||||
|
||||
public static cfg.RodData GetRodData(this Tables tables, int id)
|
||||
{
|
||||
var fishRodData = tables.TbRodData;
|
||||
if (!fishRodData.DataMap.ContainsKey(id))
|
||||
{
|
||||
return fishRodData.DataList[0];
|
||||
}
|
||||
|
||||
return fishRodData[id];
|
||||
}
|
||||
|
||||
public static cfg.AlbumExchange GetAlbumExchange(this Tables tables, int id)
|
||||
{
|
||||
return tables.TbAlbumExchange.GetOrDefault(id);
|
||||
}
|
||||
|
||||
public static cfg.Item GetItemData(this Tables tables, int id)
|
||||
{
|
||||
return tables.TbItem[id];
|
||||
}
|
||||
|
||||
public static string GetItemIconName(this Tables tables, int id)
|
||||
{
|
||||
var item = tables.TbItem;
|
||||
if (!item.DataMap.ContainsKey(id))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return item[id].Icon;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class Text
|
||||
{
|
||||
public string GetText(string code)
|
||||
{
|
||||
string text = json["text_" + code];
|
||||
return string.IsNullOrEmpty(text) ? TextEn : text;
|
||||
}
|
||||
}
|
||||
public sealed partial class ShopPackManager
|
||||
{
|
||||
public int MaxPurchaseNew
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MaxPurchase == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return MaxPurchase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/Tables.cs.meta
Normal file
11
Assets/Scripts/Services/Tables.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e9ff2d9b0855be4b8e4249d3e7a211d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
Assets/Scripts/Services/TileNewsManager.cs
Normal file
61
Assets/Scripts/Services/TileNewsManager.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using asap.core;
|
||||
using asap.playfab.async;
|
||||
using PlayFab.ClientModels;
|
||||
using System.Threading.Tasks;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class TitleNewsEvent
|
||||
{
|
||||
public TaskCompletionSource<TitleNewsItem> titleNewsItemAwait = new TaskCompletionSource<TitleNewsItem>();
|
||||
public TitleNewsItem titleNewsItem;
|
||||
public bool show;
|
||||
}
|
||||
public class TileNewsManager
|
||||
{
|
||||
public TitleNewsItem News;
|
||||
public TileNewsManager()
|
||||
{
|
||||
News = null;
|
||||
GContext.OnEvent<TitleNewsEvent>().Subscribe(ReadTitleNews);
|
||||
}
|
||||
async void ReadTitleNews(TitleNewsEvent titleNewsEvent)
|
||||
{
|
||||
titleNewsEvent.titleNewsItem = News;
|
||||
bool isRod = false;
|
||||
GetTitleNewsResult result = await PlayFabClientAsyncAPI.GetTitleNewsAsync(new PlayFab.ClientModels.GetTitleNewsRequest());
|
||||
if (result != null && result.News != null && result.News.Count > 0)
|
||||
{
|
||||
News = result.News[0];
|
||||
string newsValue = PlayerPrefs.GetString("TitleNewsEvent");
|
||||
string timeStr = News.Timestamp.ToString();
|
||||
if (newsValue != timeStr)
|
||||
{
|
||||
IUserService userService = GContext.container.Resolve<IUserService>();
|
||||
if (userService.CreateTime < News.Timestamp)
|
||||
{
|
||||
isRod = true;
|
||||
}
|
||||
}
|
||||
titleNewsEvent.titleNewsItemAwait.SetResult(result.News[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
News = null;
|
||||
titleNewsEvent.titleNewsItemAwait.SetResult(null);
|
||||
}
|
||||
if (titleNewsEvent.show)
|
||||
{
|
||||
if (News != null)
|
||||
{
|
||||
PlayerPrefs.SetString("TitleNewsEvent", News.Timestamp.ToString());
|
||||
}
|
||||
isRod = false;
|
||||
}
|
||||
RedPointManager.Instance.SetRedPointState(RedPointName.Announcement, isRod);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/TileNewsManager.cs.meta
Normal file
11
Assets/Scripts/Services/TileNewsManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 664ba1d2e61458241a87ecbc656e48dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
376
Assets/Scripts/Services/UIService.cs
Normal file
376
Assets/Scripts/Services/UIService.cs
Normal file
@@ -0,0 +1,376 @@
|
||||
using asap.core;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.UI;
|
||||
using UniRx;
|
||||
using System.Threading.Tasks;
|
||||
using game;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
public class GetSpriteEvent
|
||||
{
|
||||
public string spriteName;
|
||||
public string panelName;
|
||||
public Sprite sprite;
|
||||
public GetSpriteEvent()
|
||||
{
|
||||
|
||||
}
|
||||
public GetSpriteEvent(string spriteName, string panelName = "")
|
||||
{
|
||||
this.spriteName = spriteName;
|
||||
this.panelName = panelName;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IShowImageData
|
||||
{
|
||||
public string spriteName { set; get; }
|
||||
|
||||
public Image image { set; get; }
|
||||
|
||||
public void SetImage(Sprite sprite);
|
||||
}
|
||||
|
||||
public interface IUIService
|
||||
{
|
||||
Task LoadAtlas();
|
||||
Task SetImageSprite(Image image, string spriteName, string panelName = "");
|
||||
/// <summary>
|
||||
/// 同一个 image 组件 重复赋值,使用此方法
|
||||
/// </summary>
|
||||
/// <param name="imageData"></param>
|
||||
/// <param name="panelName"></param>
|
||||
/// <returns></returns>
|
||||
Task SetImageSprite(IShowImageData imageData, string panelName = "");
|
||||
void ReleaseSpriteDic(string dicName);
|
||||
Task SetHeadImage(Image image, string spriteName);
|
||||
Sprite GetSprite(string spriteName, string panelName = "");
|
||||
}
|
||||
public class AtlasReference
|
||||
{
|
||||
public AsyncOperationHandle<SpriteAtlas> handle;
|
||||
public SpriteAtlas spriteAtlas;
|
||||
public int referenceCount;
|
||||
}
|
||||
public class UIService : IUIService
|
||||
{
|
||||
private Dictionary<string, Dictionary<string, Sprite>> _spriteDict = new Dictionary<string, Dictionary<string, Sprite>>();
|
||||
Dictionary<string, AtlasReference> atlasReference = new Dictionary<string, AtlasReference>();
|
||||
SpriteAtlas atlasDic;
|
||||
string preloadAtlasName = "UIResAtlas";
|
||||
string defaultAvatar;
|
||||
public async Task LoadAtlas()
|
||||
{
|
||||
cfg.Tables table = GContext.container.Resolve<cfg.Tables>();
|
||||
|
||||
var tbAvatar = table.TbUserAvatar.GetOrDefault(table.TbGlobalConfig.InitAvatar);
|
||||
if (tbAvatar != null)
|
||||
{
|
||||
defaultAvatar = tbAvatar.Avatar;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultAvatar = table.TbUserAvatar.DataMap[0].Avatar;
|
||||
}
|
||||
|
||||
if (atlasDic != null)
|
||||
{
|
||||
Addressables.Release(atlasDic);
|
||||
}
|
||||
var atlas = await Addressables.LoadAssetAsync<SpriteAtlas>(preloadAtlasName).Task;
|
||||
if (atlas != null)
|
||||
{
|
||||
atlasDic = atlas;
|
||||
}
|
||||
GContext.OnEvent<GetSpriteEvent>().Subscribe(OnGetSprite);
|
||||
GetAvatarDataEvent getAvatarDataEvent = new GetAvatarDataEvent();
|
||||
getAvatarDataEvent.url = GContext.container.Resolve<IUserService>().AvatarUrl;
|
||||
GContext.Publish(getAvatarDataEvent);
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置头像 存在网图
|
||||
/// </summary>
|
||||
/// <param name="icon_head">Image 组件</param>
|
||||
/// <param name="url">头像网址 或者本地名称</param>
|
||||
public async Task SetHeadImage(Image icon_head, string url)
|
||||
{
|
||||
if (icon_head == null)
|
||||
{
|
||||
Debug.LogError("SetHeadImage icon_head null");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
url = defaultAvatar;
|
||||
}
|
||||
if (icon_head != null && url.Contains("http"))
|
||||
{
|
||||
icon_head.sprite = GetSprite(defaultAvatar);
|
||||
}
|
||||
|
||||
GetAvatarDataEvent getAvatarDataEvent = new GetAvatarDataEvent();
|
||||
getAvatarDataEvent.url = url;
|
||||
GContext.Publish(getAvatarDataEvent);
|
||||
var sprite = await getAvatarDataEvent.taskCompletionSource.Task;
|
||||
if (icon_head != null && sprite != null)
|
||||
{
|
||||
icon_head.sprite = sprite;
|
||||
}
|
||||
}
|
||||
void OnGetSprite(GetSpriteEvent getSpriteEvent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(getSpriteEvent.spriteName))
|
||||
{
|
||||
getSpriteEvent.sprite = GetSprite(getSpriteEvent.spriteName, getSpriteEvent.panelName);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSpriteDic(string dicName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dicName) || !_spriteDict.TryGetValue(dicName, out var value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var item in value)
|
||||
{
|
||||
string[] spriteNames = item.Key.Split('_');
|
||||
if (spriteNames.Length > 1 && spriteNames[0] == "separate")
|
||||
{
|
||||
Addressables.Release(item.Value);
|
||||
}
|
||||
else if (spriteNames.Length > 2 && spriteNames[0] == "atlas")
|
||||
{
|
||||
if (atlasReference.TryGetValue(spriteNames[1], out var AR))
|
||||
{
|
||||
AR.referenceCount--;
|
||||
if (AR.referenceCount == 0)
|
||||
{
|
||||
AR.spriteAtlas = null;
|
||||
Addressables.Release(AR.handle);
|
||||
atlasReference.Remove(spriteNames[1]);
|
||||
Debug.Log($"ReleaseAtlas {spriteNames[1]} ===> Panel {dicName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
value.Clear();
|
||||
_spriteDict.Remove(dicName);
|
||||
}
|
||||
|
||||
public async Task SetImageSprite(Image image, string spriteName, string panelName = "")
|
||||
{
|
||||
if (image == null)
|
||||
{
|
||||
Debug.LogError($"image null spriteName {spriteName}");
|
||||
return;
|
||||
}
|
||||
ShowImageData imageData = new ShowImageData(image, spriteName);
|
||||
await SetImageSprite(imageData, panelName);
|
||||
}
|
||||
public async Task SetImageSprite(IShowImageData imageData, string panelName = "")
|
||||
{
|
||||
if (imageData == null || imageData.image == null)
|
||||
{
|
||||
Debug.LogError($"image null spriteName {imageData?.spriteName}");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(panelName))
|
||||
{
|
||||
panelName = BasePanel.PanelName;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(imageData.spriteName))
|
||||
{
|
||||
try
|
||||
{
|
||||
await SetSprite(imageData, panelName);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"SetImageSprite error: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取默认图集里面的图片
|
||||
/// </summary>
|
||||
/// <param name="spriteName"></param>
|
||||
/// <param name="panelName"></param>
|
||||
/// <returns></returns>
|
||||
public Sprite GetSprite(string spriteName, string panelName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(panelName))
|
||||
{
|
||||
panelName = BasePanel.PanelName;
|
||||
}
|
||||
Sprite value;
|
||||
if (_spriteDict.TryGetValue(panelName, out var sprites))
|
||||
{
|
||||
if (sprites.TryGetValue(spriteName, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprites = new Dictionary<string, Sprite>();
|
||||
_spriteDict.Add(panelName, sprites);
|
||||
}
|
||||
|
||||
value = atlasDic?.GetSprite(spriteName);
|
||||
if (value != null)
|
||||
{
|
||||
sprites[spriteName] = value;
|
||||
return value;
|
||||
}
|
||||
GameDebug.LogWarning("spriteName===>" + spriteName + " panelName===>" + panelName);
|
||||
return null;
|
||||
}
|
||||
async Task SetSprite(IShowImageData imageData, string panelName)
|
||||
{
|
||||
string spriteName = imageData.spriteName;
|
||||
string[] spriteNames = spriteName.Split('_');
|
||||
if (spriteNames.Length > 1 && spriteNames[0] == "separate" && spriteNames[1] == "icon")
|
||||
{
|
||||
panelName = "icon";
|
||||
}
|
||||
if (string.IsNullOrEmpty(panelName))
|
||||
{
|
||||
panelName = "HomePanel";
|
||||
}
|
||||
Sprite value;
|
||||
if (_spriteDict.TryGetValue(panelName, out var sprites))
|
||||
{
|
||||
if (sprites.TryGetValue(spriteName, out value))
|
||||
{
|
||||
imageData.SetImage(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprites = new Dictionary<string, Sprite>();
|
||||
_spriteDict.Add(panelName, sprites);
|
||||
}
|
||||
|
||||
|
||||
if (spriteNames.Length > 1 && spriteNames[0] == "separate")
|
||||
{
|
||||
await LoadSprite(imageData, sprites);
|
||||
return;
|
||||
}
|
||||
else if (spriteNames.Length > 2 && spriteNames[0] == "atlas")
|
||||
{
|
||||
LoadSpriteAtlas(imageData, spriteNames[1], sprites);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = atlasDic?.GetSprite(spriteName);
|
||||
if (value != null)
|
||||
{
|
||||
sprites[spriteName] = value;
|
||||
imageData.SetImage(value);
|
||||
return;
|
||||
}
|
||||
Debug.LogWarning("spriteName===>" + spriteName + " panelName===>" + panelName);
|
||||
}
|
||||
}
|
||||
async Task LoadSprite(IShowImageData imageData, Dictionary<string, Sprite> sprites)
|
||||
{
|
||||
string spriteName = imageData.spriteName;
|
||||
var sprite = await Addressables.LoadAssetAsync<Sprite>(spriteName).Task;
|
||||
if (sprite != null)
|
||||
{
|
||||
sprites[spriteName] = sprite;
|
||||
|
||||
imageData.SetImage(sprite);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("spriteName===>" + spriteName);
|
||||
}
|
||||
}
|
||||
void LoadSpriteAtlas(IShowImageData imageData, string sName, Dictionary<string, Sprite> sprites)
|
||||
{
|
||||
if (!atlasReference.TryGetValue(sName, out var AR))
|
||||
{
|
||||
Debug.Log("ReleaseAtlas Load Start ===>" + sName);
|
||||
AR = new AtlasReference();
|
||||
atlasReference.Add(sName, AR);
|
||||
AR.handle = Addressables.LoadAssetAsync<SpriteAtlas>("UIResAtlas_" + sName);
|
||||
AR.handle.Completed += (handle) =>
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
if (AR.spriteAtlas == null)
|
||||
{
|
||||
AR.spriteAtlas = handle.Result;
|
||||
}
|
||||
Debug.Log("ReleaseAtlas Load Succeeded ===>" + sName);
|
||||
SetSpriteSpriteName(imageData, AR, sprites);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("ReleaseAtlas Load Failed ===>" + sName);
|
||||
Addressables.Release(AR.handle);
|
||||
atlasReference.Remove(sName);
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AR.spriteAtlas != null)
|
||||
{
|
||||
SetSpriteSpriteName(imageData, AR, sprites);
|
||||
}
|
||||
else
|
||||
{
|
||||
AR.handle.Completed += (handle) =>
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
if (AR.spriteAtlas == null)
|
||||
{
|
||||
AR.spriteAtlas = handle.Result;
|
||||
}
|
||||
SetSpriteSpriteName(imageData, AR, sprites);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("ReleaseAtlas Completed Failed ===>" + sName);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
void SetSpriteSpriteName(IShowImageData imageData, AtlasReference AR, Dictionary<string, Sprite> sprites)
|
||||
{
|
||||
string spriteName = imageData.spriteName;
|
||||
if (imageData.image != null)
|
||||
{
|
||||
if (!sprites.ContainsKey(spriteName))
|
||||
{
|
||||
var value = AR.spriteAtlas.GetSprite(spriteName);
|
||||
if (value != null)
|
||||
{
|
||||
sprites[spriteName] = value;
|
||||
AR.referenceCount++;
|
||||
|
||||
imageData.SetImage(sprites[spriteName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("spriteName===>" + spriteName + " spriteAtlas===>" + AR.spriteAtlas.name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
imageData.SetImage(sprites[spriteName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/UIService.cs.meta
Normal file
11
Assets/Scripts/Services/UIService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 600d7b774adc7c043a828441b8cf0e89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
701
Assets/Scripts/Services/UserService.cs
Normal file
701
Assets/Scripts/Services/UserService.cs
Normal file
@@ -0,0 +1,701 @@
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using PlayFab;
|
||||
using asap.playfab.async;
|
||||
using PlayFab.ClientModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using GameCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using tysdk;
|
||||
using UniRx;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public enum ELoginStep
|
||||
{
|
||||
PlayFab,
|
||||
Sdk,
|
||||
Api,
|
||||
Done
|
||||
}
|
||||
|
||||
public class LoginRequest
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public PlayerProfile playerProfile { get; set; }
|
||||
}
|
||||
|
||||
public class PlayerProfile
|
||||
{
|
||||
public int Level { get; set; }
|
||||
public string Avatar { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
|
||||
public class EvtAPISvrLoginSuccess
|
||||
{
|
||||
public string playerId { get; set; }
|
||||
public uint internalId { get; set; }
|
||||
}
|
||||
|
||||
public class EvtAPISvrUnauthorized { }
|
||||
|
||||
public interface IUserService
|
||||
{
|
||||
Task<ELoginStep> Login(Action<int> progress);
|
||||
void Logout();
|
||||
bool IsLogin { get; }
|
||||
bool IsAuthorized { get; }
|
||||
DateTime LoginTime { get; }
|
||||
DateTime CreateTime { get; }
|
||||
Task<string> ChangeDisplayName(string newName);
|
||||
string DisplayName { get; }
|
||||
string AvatarUrl { get; }
|
||||
Dictionary<string, string> EAccoutUrl { get; }
|
||||
EntityKey entityKey { get; }
|
||||
Task<string> UpdateAvatarUrl(string url);
|
||||
string UserId { get; }
|
||||
string CustomId { get; }
|
||||
uint InternalId { get; }
|
||||
string ContinentCode { get; }
|
||||
string CountryCode { get; }
|
||||
double CreateTotalSeconds();
|
||||
string Language { get; }
|
||||
Task<string> UpdateLanguage(string code);
|
||||
|
||||
Task<bool> LinkAccount(EAccoutType accoutType);
|
||||
Task<bool> GetLinkState(EAccoutType accoutType);
|
||||
void SetPlayerLv(string playFabId, int lv);
|
||||
Task<(string, int)> GetPlayLv(string playFabId);
|
||||
int GetPlayerLv(string playFabId);
|
||||
|
||||
PlayInfo GetPlayInfo(string id);
|
||||
void ClearPlayInfos();
|
||||
void SetPlayInfo(string playFabId, string name, string avatarUrl);
|
||||
string GetDefaultName(string id);
|
||||
void UpdateProfile();
|
||||
void UpdateProfileLv();
|
||||
}
|
||||
|
||||
public class PlayFabUserService : IUserService
|
||||
{
|
||||
[Inject]
|
||||
public IConfig config { get; set; }
|
||||
|
||||
[Inject]
|
||||
public ICustomServerMgr customServerMgr { get; set; }
|
||||
|
||||
public bool IsLogin => PlayFabClientAPI.IsClientLoggedIn();
|
||||
|
||||
public bool IsAuthorized => InternalId != 0;
|
||||
|
||||
public DateTime LoginTime { get; protected set; }
|
||||
|
||||
public DateTime CreateTime { get; protected set; }
|
||||
|
||||
public string DisplayName { get; protected set; }
|
||||
|
||||
public string AvatarUrl { get; protected set; }
|
||||
public Dictionary<string, string> EAccoutUrl { get; protected set; }
|
||||
public string Language { get; protected set; }
|
||||
|
||||
public string UserId { get; protected set; }
|
||||
public EntityKey entityKey { get; protected set; }
|
||||
public string CustomId { get; set; }
|
||||
public uint InternalId { get; protected set; }
|
||||
public string ContinentCode { get; protected set; }
|
||||
public string CountryCode { get; protected set; }
|
||||
protected virtual string NewPlayerName => $"Angler#{CustomId}";
|
||||
|
||||
protected Action<IDictionary<string, string>> OnInitData;
|
||||
|
||||
protected virtual string NewPlayerAvatar => string.Empty;
|
||||
private bool IsApiServerLogin => InternalId != 0;
|
||||
int MMTestValue;//0=>A 原来的 对照组 1=>B 新的实验组
|
||||
const string MMTestKey = "MMTest";
|
||||
const string MMTestSubKey = "MMPack";
|
||||
const string MMTestSubKey2 = "MMB";
|
||||
public string GetDefaultName(string id)
|
||||
{
|
||||
return $"Angler#{id[0..5]}";
|
||||
}
|
||||
|
||||
public PlayFabUserService()
|
||||
{
|
||||
GContext.OnEvent<EvtAPISvrUnauthorized>().Subscribe(_ => LoginApiServer());
|
||||
}
|
||||
|
||||
public virtual async Task<ELoginStep> Login(Action<int> progress)
|
||||
{
|
||||
if (IsLogin)
|
||||
{
|
||||
progress?.Invoke(2);
|
||||
return ELoginStep.Done;
|
||||
}
|
||||
|
||||
if (!PlayFabClientAPI.IsClientLoggedIn())
|
||||
{
|
||||
if (!await LoginPlayFab())
|
||||
return ELoginStep.PlayFab;
|
||||
}
|
||||
|
||||
SetMMTestValue();
|
||||
|
||||
GContext.container.Resolve<IChatService>().WaitingForLogin();
|
||||
|
||||
LoginApiServer();
|
||||
|
||||
progress?.Invoke(2);
|
||||
return ELoginStep.Done;
|
||||
}
|
||||
|
||||
void SetMMTestValue()
|
||||
{
|
||||
if (MMTestValue == -1)
|
||||
{
|
||||
//int id = (int)(InternalId / 2) * 2 + 1;
|
||||
//int AB = (int)(id % 8);
|
||||
// convert UserId string to ulong
|
||||
var ulongUserId = ulong.Parse(UserId, System.Globalization.NumberStyles.HexNumber);
|
||||
int AB = (int)(ulongUserId % 8);
|
||||
MMTestValue = AB;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey2}#{MMTestValue}");
|
||||
}
|
||||
string ab = GContext.container.Resolve<MMTService>().Init(MMTestValue);
|
||||
GEvent.SetUserProp("MMTestValue", ab, true);
|
||||
Debug.Log($"UserId:{UserId} MMTestValue :0b{Convert.ToString(MMTestValue, 2)} MMTestValueString:{ab}");
|
||||
}
|
||||
public void GMMMT(int value)
|
||||
{
|
||||
MMTestValue = value;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey2}#{MMTestValue}");
|
||||
string ab = GContext.container.Resolve<MMTService>().Init(MMTestValue);
|
||||
GEvent.SetUserProp("MMTestValue", ab, true);
|
||||
Debug.Log($"UserId:{UserId} MMTestValue :0b{Convert.ToString(MMTestValue, 2)} MMTestValueString:{ab}");
|
||||
}
|
||||
private async Task<bool> LoginPlayFab()
|
||||
{
|
||||
PlayFabSettings.TitleId = config.Get<string>(GConstant.K_PlayFab_Title, GConstant.V_Debug_PF_Title);
|
||||
PlayFab.Internal.PlayFabWebRequest.SkipCertificateValidation();
|
||||
|
||||
var timeout = config.Get<int>(GConstant.K_PlayFab_TimeOut, 0);
|
||||
if (timeout != 0)
|
||||
{
|
||||
PlayFabSettings.RequestTimeout = timeout;
|
||||
}
|
||||
|
||||
var sw = new System.Diagnostics.Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var info_request_parameters = new GetPlayerCombinedInfoRequestParams
|
||||
{
|
||||
GetUserAccountInfo = true,
|
||||
GetUserData = true,
|
||||
GetPlayerProfile = true,
|
||||
ProfileConstraints = new PlayerProfileViewConstraints()
|
||||
{
|
||||
ShowAvatarUrl = true,
|
||||
ShowDisplayName = true,
|
||||
ShowLocations = true,
|
||||
}
|
||||
};
|
||||
|
||||
LoginResult loginResult = null;
|
||||
|
||||
|
||||
if (CustomId != string.Empty)
|
||||
{
|
||||
var request = new LoginWithCustomIDRequest
|
||||
{
|
||||
CustomId = CustomId,
|
||||
CreateAccount = true,
|
||||
InfoRequestParameters = info_request_parameters,
|
||||
};
|
||||
Debug.Log($"[UserService::LoginPlayFab] LoginWithCustomIDAsync customId:{CustomId}");
|
||||
loginResult = await PlayFabClientAsyncAPI.LoginWithCustomIDAsync(request);
|
||||
Debug.Log($"[UserService::LoginPlayFab] LoginWithCustomIDAsync result:{loginResult != null}");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#if UNITY_IOS
|
||||
CustomId = UnityEngine.iOS.Device.advertisingIdentifier;
|
||||
var request = new LoginWithIOSDeviceIDRequest
|
||||
{
|
||||
DeviceId = UnityEngine.iOS.Device.advertisingIdentifier,
|
||||
OS = "iOS",
|
||||
DeviceModel = UnityEngine.iOS.Device.generation.ToString(),
|
||||
CreateAccount = true,
|
||||
InfoRequestParameters = info_request_parameters,
|
||||
};
|
||||
|
||||
loginResult = await PlayFabClientAsyncAPI.LoginWithIOSDeviceIDAsync(request);
|
||||
|
||||
#elif UNITY_ANDROID
|
||||
|
||||
CustomId = SystemInfo.deviceUniqueIdentifier;
|
||||
var request = new LoginWithAndroidDeviceIDRequest
|
||||
{
|
||||
AndroidDeviceId = SystemInfo.deviceUniqueIdentifier,
|
||||
AndroidDevice = SystemInfo.deviceModel,
|
||||
CreateAccount = true,
|
||||
InfoRequestParameters = info_request_parameters,
|
||||
};
|
||||
|
||||
loginResult = await PlayFabClientAsyncAPI.LoginWithAndroidDeviceIDAsync(request);
|
||||
|
||||
#else
|
||||
CustomId = Application.identifier;
|
||||
var request = new LoginWithCustomIDRequest
|
||||
{
|
||||
AndroidDeviceId = Application.identifier,
|
||||
CreateAccount = true,
|
||||
InfoRequestParameters = info_request_parameters,
|
||||
};
|
||||
loginResult = await PlayFabClientAsyncAPI.LoginWithCustomIDAsync(request);
|
||||
#endif
|
||||
}
|
||||
sw.Stop();
|
||||
if (loginResult == null) return false;
|
||||
|
||||
Debug.Log($"LoginPlayFab elapsed={sw.Elapsed.TotalSeconds}");
|
||||
sw.Reset();
|
||||
|
||||
|
||||
entityKey = loginResult.EntityToken.Entity;
|
||||
if (!loginResult.NewlyCreated)
|
||||
{
|
||||
DisplayName = loginResult.InfoResultPayload.PlayerProfile?.DisplayName ?? string.Empty;
|
||||
AvatarUrl = loginResult.InfoResultPayload.PlayerProfile?.AvatarUrl ?? string.Empty;
|
||||
ContinentCode = loginResult.InfoResultPayload.PlayerProfile?.Locations[0]?.ContinentCode?.ToString() ?? "UNKNOW";
|
||||
CountryCode = loginResult.InfoResultPayload.PlayerProfile?.Locations[0]?.CountryCode?.ToString();
|
||||
|
||||
config.Set("NewlyCreated", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw.Start();
|
||||
|
||||
GetPlayerProfileRequest getPlayerProfileRequest = new GetPlayerProfileRequest()
|
||||
{
|
||||
ProfileConstraints = new PlayerProfileViewConstraints()
|
||||
{
|
||||
//ShowAvatarUrl = true,
|
||||
//ShowDisplayName = true,
|
||||
ShowLocations = true,
|
||||
}
|
||||
};
|
||||
var data = await PlayFabClientAsyncAPI.GetPlayerProfileAsync(getPlayerProfileRequest);
|
||||
//DisplayName = data.PlayerProfile.DisplayName;
|
||||
//AvatarUrl = data.PlayerProfile.AvatarUrl;
|
||||
ContinentCode = data?.PlayerProfile.Locations[0]?.ContinentCode?.ToString() ?? "UNKNOW";
|
||||
CountryCode = data?.PlayerProfile.Locations[0]?.CountryCode?.ToString();
|
||||
sw.Stop();
|
||||
Debug.Log($"LoginPlayFab GetPlayerProfile elapsed={sw.Elapsed.TotalSeconds}");
|
||||
sw.Reset();
|
||||
|
||||
config.Set("NewlyCreated", true);
|
||||
}
|
||||
|
||||
UserId = loginResult.PlayFabId;
|
||||
if (string.IsNullOrEmpty(DisplayName))
|
||||
{
|
||||
sw.Start();
|
||||
DisplayName = await ChangeDisplayName(NewPlayerName);
|
||||
sw.Stop();
|
||||
Debug.Log($"LoginPlayFab ChangeDisplayName elapsed={sw.Elapsed.TotalSeconds}");
|
||||
sw.Reset();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(AvatarUrl))
|
||||
{
|
||||
sw.Start();
|
||||
/*AvatarUrl = */
|
||||
await UpdateAvatarUrl(NewPlayerAvatar);
|
||||
sw.Stop();
|
||||
Debug.Log($"LoginPlayFab update avatar elapsed={sw.Elapsed.TotalSeconds}");
|
||||
sw.Reset();
|
||||
}
|
||||
//BuglyAgent.SetUserId(UserId);
|
||||
var setting = GContext.container.Resolve<ISettingService>();
|
||||
await UpdateLanguage(setting.Lang);
|
||||
|
||||
var playfabUserData = loginResult.InfoResultPayload?.UserData;
|
||||
|
||||
CreateTime = loginResult.InfoResultPayload.AccountInfo.Created.ToUniversalTime();
|
||||
var tokenExpiration = loginResult.EntityToken.TokenExpiration?.ToUniversalTime();
|
||||
if (tokenExpiration.HasValue)
|
||||
{
|
||||
LoginTime = tokenExpiration.Value.ToUniversalTime() - TimeSpan.FromDays(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoginTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
ZZTimeHelper.AdjustTime(LoginTime);
|
||||
ZZTimeHelper.WathForcusChange();
|
||||
|
||||
//InitData should invoke after local time adjusted.
|
||||
//save login time to local storage.
|
||||
InitData(playfabUserData, UserId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private bool tryLoginApiSvr = false;
|
||||
|
||||
private async void LoginApiServer()
|
||||
{
|
||||
if (tryLoginApiSvr)
|
||||
return;
|
||||
tryLoginApiSvr = true;
|
||||
|
||||
var sw = new System.Diagnostics.Stopwatch();
|
||||
|
||||
PlayerProfile playerProfile = new PlayerProfile()
|
||||
{
|
||||
Avatar = AvatarUrl,
|
||||
DisplayName = DisplayName,
|
||||
Level = GContext.container.Resolve<PlayerData>().lv
|
||||
};
|
||||
|
||||
LoginRequest loginRequest = new LoginRequest()
|
||||
{
|
||||
playerId = UserId,
|
||||
playerProfile = playerProfile
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var apiLoginResponse = await customServerMgr.AccountRequest("Login", loginRequest);
|
||||
sw.Stop();
|
||||
Debug.Log($"LoginApiServer elapsed={sw.Elapsed.TotalSeconds}");
|
||||
|
||||
if (string.IsNullOrEmpty(apiLoginResponse))
|
||||
return;
|
||||
|
||||
var result = JObject.Parse(apiLoginResponse);
|
||||
if ((byte)result["state"] == 0)
|
||||
{
|
||||
InternalId = (uint)result["internalId"];
|
||||
GContext.Publish(new EvtAPISvrLoginSuccess()
|
||||
{
|
||||
playerId = UserId,
|
||||
internalId = InternalId
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
InternalId = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
InternalId = 0;
|
||||
}
|
||||
|
||||
tryLoginApiSvr = false;
|
||||
}
|
||||
|
||||
public async virtual Task<bool> LinkAccount(EAccoutType accoutType)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
//测试
|
||||
//#if UNITY_EDITOR
|
||||
// var _accountInfo = new TYSdkFacade.AccountInfo()
|
||||
// {
|
||||
// channel = accoutType,
|
||||
// avatar = "https://tse2-mm.cn.bing.net/th/id/OIP-C.s4x0YU7qC-oat3mnyubG5gAAAA?rs=1&pid=ImgDetMain",
|
||||
// };
|
||||
// AvatarToPF(_accountInfo);
|
||||
|
||||
// if (_accountInfo.channel == EAccoutType.hwFacebook)
|
||||
// {
|
||||
// _ = UpdateAvatarUrl(_accountInfo.avatar);
|
||||
// }
|
||||
//#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void AvatarToPF(TYSdkFacade.AccountInfo accountInfo)
|
||||
{
|
||||
if (accountInfo != null
|
||||
&& (accountInfo.channel == EAccoutType.hwFacebook
|
||||
|| accountInfo.channel == EAccoutType.hwGoogle)
|
||||
&& !string.IsNullOrEmpty(accountInfo.avatar))
|
||||
{
|
||||
if (EAccoutUrl == null)
|
||||
{
|
||||
EAccoutUrl = new Dictionary<string, string>();
|
||||
}
|
||||
EAccoutUrl[accountInfo.channel.ToString()] = accountInfo.avatar;
|
||||
string EAccoutUrlStr = Newtonsoft.Json.JsonConvert.SerializeObject(EAccoutUrl);
|
||||
PlayFabMgr.Instance.UpdateUserDataValue("EAccoutUrl", EAccoutUrlStr);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitData(Dictionary<string, UserDataRecord> datas, string userId)
|
||||
{
|
||||
var comparedData = PlayFabMgr.Instance.CompareDatas(datas, userId);
|
||||
if (comparedData != null)
|
||||
{
|
||||
MMTestValue = 0;
|
||||
if (!comparedData.ContainsKey(MMTestKey))
|
||||
{
|
||||
if (config.Get<bool>("NewlyCreated", false))
|
||||
{
|
||||
//新用户设置MMTest
|
||||
MMTestValue = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//老用户设置MMTest
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey2}#{MMTestValue}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string mmTestValue = comparedData[MMTestKey];
|
||||
string[] mmTestValueData = mmTestValue.Split('#');
|
||||
if (mmTestValueData.Length > 1 && mmTestValueData[0] == MMTestSubKey)
|
||||
{
|
||||
int.TryParse(mmTestValueData[1], out int value);
|
||||
MMTestValue = value & 0b110;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey2}#{MMTestValue}");
|
||||
}
|
||||
else if (mmTestValueData.Length > 1 && mmTestValueData[0] == MMTestSubKey2)
|
||||
{
|
||||
|
||||
int.TryParse(mmTestValueData[1], out int value);
|
||||
MMTestValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
MMTestValue = 0;
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey2}#{MMTestValue}");
|
||||
}
|
||||
}
|
||||
GContext.container.Resolve<PlayerData>().LoadPlayerData(comparedData);
|
||||
OnInitData?.Invoke(comparedData);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Logout()
|
||||
{
|
||||
|
||||
UserId = null;
|
||||
InternalId = 0;
|
||||
DisplayName = null;
|
||||
AvatarUrl = null;
|
||||
PlayFabClientAPI.ForgetAllCredentials();
|
||||
}
|
||||
|
||||
public virtual async Task<string> ChangeDisplayName(string newName)
|
||||
{
|
||||
var originName = string.IsNullOrEmpty(DisplayName) ? NewPlayerName : DisplayName;
|
||||
var result = await PlayFabClientAsyncAPI.UpdateUserTitleDisplayNameAsync(new UpdateUserTitleDisplayNameRequest
|
||||
{
|
||||
DisplayName = newName
|
||||
});
|
||||
if (result == null)
|
||||
return originName;
|
||||
DisplayName = result.DisplayName;
|
||||
GContext.Publish(new ChangeAvatarEvent());
|
||||
UpdateProfileName();
|
||||
return DisplayName;
|
||||
}
|
||||
|
||||
public virtual async Task<string> UpdateAvatarUrl(string url)
|
||||
{
|
||||
var originUrl = AvatarUrl;
|
||||
|
||||
Debug.Log("UpdateAvatarUrlAsync originUrl:" + originUrl + " url " + url);
|
||||
|
||||
if (string.IsNullOrEmpty(url)) return originUrl;
|
||||
if (url == originUrl)
|
||||
{
|
||||
return originUrl;
|
||||
}
|
||||
var result = await PlayFabClientAsyncAPI.UpdateAvatarUrlAsync(new UpdateAvatarUrlRequest
|
||||
{
|
||||
ImageUrl = url
|
||||
});
|
||||
Debug.Log("UpdateAvatarUrlAsync :" + result);
|
||||
if (result == null) return originUrl;
|
||||
AvatarUrl = url;
|
||||
GContext.Publish(new ChangeAvatarEvent());
|
||||
UpdateProfileAvatar();
|
||||
return url;
|
||||
}
|
||||
|
||||
public virtual async Task<string> UpdateLanguage(string code)
|
||||
{
|
||||
if (Language == code)
|
||||
{
|
||||
return Language;
|
||||
}
|
||||
PlayFab.ProfilesModels.SetProfileLanguageRequest setProfileLanguageRequest = new PlayFab.ProfilesModels.SetProfileLanguageRequest()
|
||||
{
|
||||
Language = code.Replace('_', '-')
|
||||
};
|
||||
|
||||
var result = await PlayFabProfilesAsyncAPI.SetProfileLanguageAsync(setProfileLanguageRequest);
|
||||
if (result != null)
|
||||
Language = code;
|
||||
return Language;
|
||||
}
|
||||
|
||||
public double CreateTotalSeconds()
|
||||
{
|
||||
return (ZZTimeHelper.UtcNow() - CreateTime).TotalSeconds;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> GetLinkState(EAccoutType accoutType)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
return false;
|
||||
}
|
||||
public void UpdateProfile()
|
||||
{
|
||||
PlayerProfile playerProfile = new PlayerProfile();
|
||||
playerProfile.Avatar = AvatarUrl;
|
||||
playerProfile.DisplayName = DisplayName;
|
||||
playerProfile.Level = GContext.container.Resolve<PlayerData>().lv;
|
||||
LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile };
|
||||
customServerMgr.AccountRequest("UpdateProfile", loginRequest);
|
||||
}
|
||||
public void UpdateProfileLv()
|
||||
{
|
||||
PlayerProfile playerProfile = new PlayerProfile();
|
||||
playerProfile.Level = GContext.container.Resolve<PlayerData>().lv;
|
||||
LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile };
|
||||
customServerMgr.AccountRequest("UpdateProfile", loginRequest);
|
||||
}
|
||||
void UpdateProfileName()
|
||||
{
|
||||
PlayerProfile playerProfile = new PlayerProfile();
|
||||
playerProfile.DisplayName = DisplayName;
|
||||
LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile };
|
||||
customServerMgr.AccountRequest("UpdateProfile", loginRequest);
|
||||
}
|
||||
void UpdateProfileAvatar()
|
||||
{
|
||||
PlayerProfile playerProfile = new PlayerProfile();
|
||||
playerProfile.Avatar = AvatarUrl;
|
||||
LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile };
|
||||
customServerMgr.AccountRequest("UpdateProfile", loginRequest);
|
||||
}
|
||||
#region 其他玩家头像昵称缓存
|
||||
|
||||
Dictionary<string, PlayInfo> PlayInfos = new Dictionary<string, PlayInfo>();
|
||||
Dictionary<string, int> PlayLvs = new Dictionary<string, int>();
|
||||
public async Task<(string, int)> GetPlayLv(string playFabId)
|
||||
{
|
||||
if (!PlayLvs.ContainsKey(playFabId))
|
||||
{
|
||||
var resultUserData = await PlayFabClientAsyncAPI.GetUserDataAsync(new GetUserDataRequest()
|
||||
{
|
||||
PlayFabId = playFabId,
|
||||
Keys = new List<string>() { "Lv" }
|
||||
});
|
||||
if (resultUserData != null)
|
||||
{
|
||||
string level = resultUserData.Data.TryGetValue("Lv", out var value) ? value.Value : "1";
|
||||
PlayLvs[playFabId] = int.Parse(level);
|
||||
}
|
||||
}
|
||||
int lv = PlayLvs[playFabId];
|
||||
|
||||
return (playFabId, lv);
|
||||
}
|
||||
public int GetPlayerLv(string playFabId)
|
||||
{
|
||||
return PlayLvs.ContainsKey(playFabId) ? PlayLvs[playFabId] : 1;
|
||||
}
|
||||
|
||||
public void SetPlayerLv(string playFabId, int lv)
|
||||
{
|
||||
if (playFabId == UserId)
|
||||
{
|
||||
lv = GContext.container.Resolve<PlayerData>().lv;
|
||||
}
|
||||
PlayLvs[playFabId] = lv;
|
||||
}
|
||||
|
||||
public void ClearPlayInfos()
|
||||
{
|
||||
PlayInfos.Clear();
|
||||
PlayLvs.Clear();
|
||||
}
|
||||
|
||||
public PlayInfo GetPlayInfo(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!PlayInfos.ContainsKey(id))
|
||||
{
|
||||
PlayInfo playInfo = new PlayInfo();
|
||||
playInfo.name = GetDefaultName(id);
|
||||
PlayInfos.Add(id, playInfo);
|
||||
SetPlayInfo(id, playInfo);
|
||||
}
|
||||
return PlayInfos[id];
|
||||
}
|
||||
|
||||
async void SetPlayInfo(string playFabId, PlayInfo playInfo)
|
||||
{
|
||||
if (playFabId == UserId)
|
||||
{
|
||||
playInfo.name = DisplayName;
|
||||
playInfo.avatarUrl = AvatarUrl;
|
||||
GContext.Publish(new GetClubPlayInfoEvent() { id = playFabId, name = playInfo.name, avatarUrl = playInfo.avatarUrl });
|
||||
return;
|
||||
}
|
||||
var resultUserTitle = await PlayFabClientAsyncAPI.GetPlayerProfileAsync(new GetPlayerProfileRequest()
|
||||
{
|
||||
PlayFabId = playFabId,
|
||||
ProfileConstraints = new PlayerProfileViewConstraints()
|
||||
{
|
||||
ShowDisplayName = true,
|
||||
ShowLocations = true,
|
||||
ShowAvatarUrl = true,
|
||||
}
|
||||
});
|
||||
if (resultUserTitle?.PlayerProfile != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(resultUserTitle?.PlayerProfile.DisplayName))
|
||||
{
|
||||
playInfo.name = resultUserTitle?.PlayerProfile.DisplayName;
|
||||
}
|
||||
playInfo.avatarUrl = resultUserTitle?.PlayerProfile.AvatarUrl;
|
||||
GContext.Publish(new GetClubPlayInfoEvent() { id = playFabId, name = playInfo.name, avatarUrl = playInfo.avatarUrl });
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPlayInfo(string playFabId, string name, string avatarUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = GetDefaultName(playFabId);
|
||||
}
|
||||
PlayInfo playInfo = new PlayInfo();
|
||||
playInfo.name = name;
|
||||
playInfo.avatarUrl = avatarUrl;
|
||||
PlayInfos[playFabId] = playInfo;
|
||||
}
|
||||
#endregion 其他玩家头像昵称缓存
|
||||
}
|
||||
|
||||
public class PlayInfo
|
||||
{
|
||||
public string name;
|
||||
public string avatarUrl;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Services/UserService.cs.meta
Normal file
11
Assets/Scripts/Services/UserService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a51b38800198264d9269d3cb573c907
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user