备份CatanBuilding瘦身独立工程

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

View File

@@ -0,0 +1,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
}
}

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace game
{
public interface IAdsService
{
void Init();
//Task<bool> ShowBanner();
void ShowRewarded(AdvertPopupType AadvertPopupType);
}
}

View File

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

View 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); //审核文本
}
}

View File

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

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

View File

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

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

View File

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

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fbb8e914d77c4b7fa83156f737472b48
timeCreated: 1729682925

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b6aa9e490c0b4521a5bee6af57733700
timeCreated: 1729826408

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

View File

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

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

View File

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

View 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">第几大组012</param>
/// <returns>false=A true=B </returns>
bool CheckMMT(int index)
{
int ab = 1 << (index % 3);
return (MMTValue & ab) == ab;
}
}

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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

View 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}" +
$"&register_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; }
}

View File

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

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

View File

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

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

View File

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

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

View File

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

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

View File

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