备份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,36 @@
using asap.core;
using UnityEngine;
using System.Threading.Tasks;
using GameCore;
using UnityEngine.AddressableAssets;
public class EventCanAct : AGameAct
{
public static IEventAggregator EventAggregator = new EventAggregator();
public static EventCanParamsCtrl ParamsCtrl;
public static EventCanSystem CanSystem;
// public static EventCanChainPackData ChainPackData;
public static string ActAddressable = "EventCanAct";
public override async Task<bool> StartAsync()
{
Debug.Log("Enter EventCanAct.");
ParamsCtrl = (EventCanParamsCtrl)await Addressables.LoadAssetAsync<object>("EventCanParamsCtrl").Task;
GContext.container.Resolve<IDeferredRewardStashService>().Reset();
CanSystem = new EventCanSystem();
await UIManager.Instance.ShowUILoad(UITypes.EventCanPanel);
if (!GContext.container.Resolve<IFootPrintService>().HasFootPrint(EFootPrint.IsEventCanGuidePoped))
{
await UIManager.Instance.ShowUINotLoading(UITypes.EventCanInfoPanel);
GContext.container.Resolve<IFootPrintService>().UpdateFootPrint(EFootPrint.IsEventCanGuidePoped);
}
return await base.StartAsync();
}
protected override void OnDestroy()
{
UIManager.Instance.DestroyUI(UITypes.EventCanPanel);
// GContext.container.Resolve<IDeferredRewardStashService>().Flush();
Debug.Log("Exit EventCanAct.");
}
}

View File

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

View File

@@ -0,0 +1,149 @@
using UnityEngine;
using UnityEngine.UI;
using System.Threading.Tasks;
using System;
using GameCore;
using asap.core;
public class EventCanCan : MonoBehaviour
{
[SerializeField] private Button btn;
[SerializeField] private GameObject[] goCans;
[SerializeField] private Animation ani;
[SerializeField] private GameObject fxDrop, audioDrop;
private int _idx;
private const string AnimationIdle = "can_idle", AnimationHint = "can_hint",
AnimationOpen = "can_open", AnimationAppear = "can_appear", AnimationDisappear = "can_disappear";
private void Start()
{
btn.onClick.AddListener(OnClick);
}
public void Init(int idx, EventCanCanInfo info)
{
_idx = idx;
gameObject.SetActive(info.DoesExist);
if (!info.DoesExist)
return;
SetColor(info.ColorIdx);
ani.Play(AnimationAppear);
}
public void Init(int idx, bool doShow)
{
_idx = idx;
gameObject.SetActive(doShow);
if (!doShow)
return;
SetRandomColor();
ani.Play(AnimationAppear);
audioDrop.SetActive(true);
fxDrop.SetActive(true);
}
private async void OnClick()
{
var model = GContext.container.Resolve<EventCanModel>();
if ((model.BlockState | EEventCanBlockState.Available) != EEventCanBlockState.Available)
{
// Debug.Log($"[EventCan] Can open blocked: {model.BlockState}");
return;
}
var res = EventCanAct.CanSystem.OpenCan(_idx);
if (res == EEventCanOpenResponse.InsufficientToken)
{
EventCanAct.EventAggregator.Publish(new EventCanInsufficientTicketEvent());
return;
}
if (res == EEventCanOpenResponse.Other)
{
return;
}
var canReward = EventCanAct.CanSystem.GenerateReward();
#if UNITY_EDITOR
if (EventCanAct.ParamsCtrl.IsDebugMode)
{
canReward = new EventCanRewardInfo();
canReward.ItemCount = 1;
canReward.RewardType = EventCanAct.ParamsCtrl.GemType;
canReward.ItemId = 704010001 + (int)EventCanAct.ParamsCtrl.GemType * 1000;
canReward.RewardId = 704010001 + (int)EventCanAct.ParamsCtrl.GemType * 1000;
}
#endif
int oldTaskId = 0;
if (canReward.RewardType == EEventCanRewardType.Blue ||
canReward.RewardType == EEventCanRewardType.Green ||
canReward.RewardType == EEventCanRewardType.Purple ||
canReward.RewardType == EEventCanRewardType.Red)
{
oldTaskId = model.GemTasks[canReward.RewardType].TaskId;
}
EventCanAct.CanSystem.GrantCanReward(canReward);
EventCanGemTaskInfo gemTaskInfoSnapShot = null;
if (canReward.RewardType == EEventCanRewardType.Blue ||
canReward.RewardType == EEventCanRewardType.Green ||
canReward.RewardType == EEventCanRewardType.Purple ||
canReward.RewardType == EEventCanRewardType.Red)
{
gemTaskInfoSnapShot = model.GemTasks[canReward.RewardType].DeepCopy();
if (oldTaskId != gemTaskInfoSnapShot.TaskId)
{
model.BlockState |= EEventCanBlockState.Gem;
// Debug.Log($"<color=red>[EventCan] Gem Block: {model.BlockState}</color>");
}
}
if (canReward.RewardType == EEventCanRewardType.Supply)
{
model.BlockState |= EEventCanBlockState.Supply;
// Debug.Log($"<color=red>[EventCan] Supply Block: {model.BlockState}</color>");
}
// Debug.Log($"[EventCan] Opening can with Gem {gemTaskInfoSnapShot}.");
// Debug.Log($"[EventCan] Opening can with Gem {gemTaskInfoSnapShot.GemType}.");
// Debug.Log($"[EventCan] Opening can with Gem {gemTaskInfoSnapShot.CurrentGemProgress}.");
await PlayAnimationAsync(AnimationOpen);
EventCanAct.EventAggregator.Publish(new EventCanOpenEvent(canReward, transform as RectTransform, gemTaskInfoSnapShot));
if (canReward.RewardType == EEventCanRewardType.Item)
GContext.Publish(new EventRewardFlyStashRequest(canReward.ToItemData(), goCans[0].GetComponent<RectTransform>()));
gameObject.SetActive(false);
}
private void SetColor(int idx)
{
if (idx < 0 || idx >= goCans.Length)
{
Debug.LogError($"[EventCan]idx{idx} out of range {goCans.Length}", this);
return;
}
for (int i = 0; i < goCans.Length; i++)
goCans[i].SetActive(i == idx);
}
private int SetRandomColor()
{
var canIdx = UnityEngine.Random.Range(0, goCans.Length);
for (int i = 0; i < goCans.Length; i++)
goCans[i].SetActive(i == canIdx);
return canIdx;
}
public async Task PlayAnimationAsync(string aniName)
{
ani.Play(aniName);
await Task.Delay(TimeSpan.FromSeconds(ani.GetClip(aniName).length));
}
public void PlayAnimation(string aniName)
{
ani.Play(aniName);
}
public async Task PlayAniamtionWithDelay(string aniName, float delay)
{
await Task.Delay(TimeSpan.FromSeconds(delay));
ani.Play(aniName);
}
}

View File

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

View File

@@ -0,0 +1,518 @@
using asap.core;
using GameCore;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using game;
using cfg;
using System;
public class EventCanModel
{
public int TicketCount, EventId, CycleId, RedirectId, ChainPackProgress;
public EventCanCanInfo[] CanList;
public Dictionary<EEventCanRewardType, EventCanGemTaskInfo> GemTasks;
public EventCanProgressTaskInfo ProgressTaskInfo;
public EventCanRewardInfo[] RewardPool;
public EventCanWeightModifier WeightModifier;
private const int CanColorCount = 4;
public EEventCanBlockState BlockState = EEventCanBlockState.Available;
public static EventCanModel GetModel(int eventId, EventCanPlayfabData pfData = null, EventCanPlayerPreferenceData ppData = null)
{
var res = new EventCanModel();
ppData ??= EventCanPlayerPreferenceData.RandomInit(CanColorCount);
if (pfData == null || pfData.EventId != eventId) //New Event
{
res.EventId = eventId;
res.TicketCount = GContext.container.Resolve<EventCanTableContext>().GetWelcomeGift();
// res.CycleId = ;
// res.RedirectId = ;
res.CanList = new EventCanCanInfo[GContext.container.Resolve<EventCanTableContext>().GetMaxCanCount()];
for (int i = 0; i < res.CanList.Length; i++)
res.CanList[i] = new EventCanCanInfo(true, UnityEngine.Random.Range(0, CanColorCount));
res.GemTasks = GContext.container.Resolve<EventCanTableContext>().InitGemTaskInfo();
res.ProgressTaskInfo = GContext.container.Resolve<EventCanTableContext>().InitProgressTaskInfo();
res.RewardPool = GContext.container.Resolve<EventCanTableContext>().InitRewardPool().ToArray();
res.WeightModifier = new EventCanWeightModifier(GContext.container.Resolve<EventCanTableContext>().GetInitialDrawsSinceLastRewards());
res.ChainPackProgress = 0;
res.ToPlayerPreferenceData().Save();
res.ToPlayfabData().Save();
}
else //read from playfab and playerprefs
{
res.EventId = eventId;
res.TicketCount = pfData.TicketCount;
res.CanList = new EventCanCanInfo[GContext.container.Resolve<EventCanTableContext>().GetMaxCanCount()];
for (int i = 0; i < res.CanList.Length; i++)
{
var doesExist = (pfData.CanState & (1 << i)) != 0;
res.CanList[i] = new EventCanCanInfo(doesExist, ppData.ColorIndices[i]);
}
res.GemTasks = pfData.GemTaskInfo
.ToDictionary(info => (EEventCanRewardType)(info.Key % 1000 / 100),
info => GContext.container.Resolve<EventCanTableContext>().GetGemTaskInfo(info.Key, info.Value));
GContext.container.Resolve<EventCanTableContext>().GetProgressInfoByIdx(pfData.ProgressTaskIdx, out var progressRequired, out var reward);
res.ProgressTaskInfo = EventCanProgressTaskInfo.Init(pfData.ProgressTaskIdx, pfData.ProgressTaskProgress);
res.RewardPool = GContext.container.Resolve<EventCanTableContext>().InitRewardPool().ToArray();
res.WeightModifier = new EventCanWeightModifier(pfData.DrawsSinceLastRewards);
res.ChainPackProgress = pfData.ChainPackProgress;
}
return res;
}
public void InitializeModel(int eventId, EventCanPlayfabData pfData = null, EventCanPlayerPreferenceData ppData = null)
{
ppData ??= EventCanPlayerPreferenceData.RandomInit(CanColorCount);
if (pfData == null || pfData.EventId != eventId) //New Event
{
EventId = eventId;
TicketCount = GContext.container.Resolve<EventCanTableContext>().GetWelcomeGift();
// this.CycleId = ;
// this.RedirectId = ;
CanList = new EventCanCanInfo[GContext.container.Resolve<EventCanTableContext>().GetMaxCanCount()];
for (int i = 0; i < CanList.Length; i++)
CanList[i] = new EventCanCanInfo(true, UnityEngine.Random.Range(0, CanColorCount));
GemTasks = GContext.container.Resolve<EventCanTableContext>().InitGemTaskInfo();
ProgressTaskInfo = GContext.container.Resolve<EventCanTableContext>().InitProgressTaskInfo();
RewardPool = GContext.container.Resolve<EventCanTableContext>().InitRewardPool().ToArray();
WeightModifier = new EventCanWeightModifier(GContext.container.Resolve<EventCanTableContext>().GetInitialDrawsSinceLastRewards());
ChainPackProgress = 0;
ToPlayerPreferenceData().Save();
ToPlayfabData().Save();
}
else //read from playfab and playerprefs
{
EventId = eventId;
TicketCount = pfData.TicketCount;
CanList = new EventCanCanInfo[GContext.container.Resolve<EventCanTableContext>().GetMaxCanCount()];
for (int i = 0; i < CanList.Length; i++)
{
var doesExist = (pfData.CanState & (1 << i)) != 0;
CanList[i] = new EventCanCanInfo(doesExist, ppData.ColorIndices[i]);
}
GemTasks = pfData.GemTaskInfo
.ToDictionary(info => (EEventCanRewardType)(info.Key % 1000 / 100),
info => GContext.container.Resolve<EventCanTableContext>().GetGemTaskInfo(info.Key, info.Value));
GContext.container.Resolve<EventCanTableContext>().GetProgressInfoByIdx(pfData.ProgressTaskIdx, out var progressRequired, out var reward);
ProgressTaskInfo = EventCanProgressTaskInfo.Init(pfData.ProgressTaskIdx, pfData.ProgressTaskProgress);
RewardPool = GContext.container.Resolve<EventCanTableContext>().InitRewardPool().ToArray();
WeightModifier = new EventCanWeightModifier(pfData.DrawsSinceLastRewards);
ChainPackProgress = pfData.ChainPackProgress;
}
}
public bool AddTicket(int count)
{
bool res;
TicketCount += count;
if (TicketCount < 0)
{
TicketCount = 0;
res = false;
}
else
res = true;
ToPlayfabData().Save();
GContext.container.Resolve<FishingEventData>().SaveTransitionData(EventId, TicketCount);
EventCanAct.EventAggregator.Publish(new EventCanTicketUpdate());
return res;
}
public void Log()
{
Debug.Log($"[EventCan] Model: TicketCount {TicketCount}");
foreach (var task in GemTasks.Values)
{
Debug.Log($"[EventCan] GemTask{task.TaskId}: {task.CurrentGemProgress}/{task.TotalGemRequired}");
}
Debug.Log($"[EventCan] ProgressTask: {ProgressTaskInfo.TaskIdx} {ProgressTaskInfo.CurrentProgress}/{ProgressTaskInfo.TotalProgressRequired}");
}
public EventCanPlayfabData ToPlayfabData()
{
int cs = 0;
for (int i = 0; i < CanList.Length; i++)
if (CanList[i].DoesExist)
cs += 1 << i;
var res = new EventCanPlayfabData
{
EventId = EventId,
CycleId = CycleId,
RedirectId = RedirectId,
TicketCount = TicketCount,
CanState = cs,
ChainPackProgress = ChainPackProgress,
ProgressTaskIdx = ProgressTaskInfo.TaskIdx,
ProgressTaskProgress = ProgressTaskInfo.CurrentProgress,
GemTaskInfo = GemTasks.ToDictionary(kv => kv.Value.TaskId, kv => kv.Value.CurrentGemProgress),
DrawsSinceLastRewards = WeightModifier.DrawsSinceLastRewards
};
return res;
}
public EventCanPlayerPreferenceData ToPlayerPreferenceData()
{
var res = new EventCanPlayerPreferenceData
{
ColorIndices = CanList.Select(c => c.ColorIdx).ToArray()
};
return res;
}
}
public class EventCanWeightModifier
{
/// <summary>
/// RewardId, DrawCount
/// </summary>
public Dictionary<int, int> DrawsSinceLastRewards;
public EventCanWeightModifier(Dictionary<int, int> d) => DrawsSinceLastRewards = d;
public void UpdateDrawsSinceLastRewards(int rewardId)
{
foreach (var k in DrawsSinceLastRewards.Keys.ToArray())
if (k == rewardId)
DrawsSinceLastRewards[k] = 0;
else
DrawsSinceLastRewards[k] += 1;
}
public void GetWeightDelta(int rewardId, out int weight, out bool mustGet)
{
if (!GContext.container.Resolve<EventCanTableContext>().GetWeightChangeThreshold(rewardId, out var t))
{
mustGet = false;
weight = 0;
return;
}
if (!DrawsSinceLastRewards.TryGetValue(rewardId, out var drawCount))
{
// Debug.Log($"[EventCan] No draw count found for reward id {rewardId}, init error.");
mustGet = false;
weight = 0;
return;
}
// Debug.Log($"[EventCan] Draw count for reward id {rewardId} is {drawCount}, threshold is {t}");
if (drawCount + 1 >= t.Item2)
{
mustGet = true;
weight = 0;
return;
}
if (drawCount + 1 >= t.Item1)
{
mustGet = false;
weight = GContext.container.Resolve<EventCanTableContext>().GetRewardWeight(rewardId);
return;
}
mustGet = false;
weight = 0;
}
}
public class EventCanRewardInfo
{
public int RewardId;
/// <summary>
/// Used to decide which task to fulfill and whether to calculate dynamic weight
/// </summary>
public EEventCanRewardType RewardType;
public int ItemId;
public int ItemCount;
/// <summary>
/// 0 if this reward has dynamic weight.
/// </summary>
public int BaseWeight;
/// <summary>
/// Returns the item data of the reward.
/// </summary>
/// <returns>Transformed Item Data. Null if the reward is either gem or supply.</returns>
public ItemData ToItemData()
{
if (RewardType == EEventCanRewardType.Supply)
{
Debug.Log($"[EventCan] RewardType {RewardType} is not Item.");
return null;
}
var res = new ItemData(ItemId, ItemCount);
GContext.container.Resolve<PlayerItemData>().ItemTransition(res);
return res;
}
}
public class EventCanCanInfo
{
public bool DoesExist;
public int ColorIdx;
public EventCanCanInfo(bool doesExist, int colorIdx)
{
DoesExist = doesExist;
ColorIdx = colorIdx;
}
}
public class EventCanGemTaskInfo
{
public int TaskId;
public int CurrentGemProgress;
public int TotalGemRequired;
public ItemData Reward;
public int GemIdx => TaskId % 1000 / 100;
public EEventCanRewardType GemType => (EEventCanRewardType)(TaskId % 1000 / 100);
public bool IsCompleted => CurrentGemProgress >= TotalGemRequired;
public void UpdateGemTasks(EventCanRewardInfo info, out ItemData reward, out int oldTaskId)
{
reward = null;
oldTaskId = 0;
if (info.RewardType != EEventCanRewardType.Green
&& info.RewardType != EEventCanRewardType.Blue
&& info.RewardType != EEventCanRewardType.Purple
&& info.RewardType != EEventCanRewardType.Red)
{
Debug.Log($"[EventCan] RewardType {info.RewardType} is not gem.");
return;
}
CurrentGemProgress += info.ItemCount;
if (!IsCompleted)
return;
reward = Reward;
oldTaskId = TaskId;
GContext.container.Resolve<EventCanTableContext>().GetNextGemTaskInfo(this);
}
public EventCanGemTaskInfo DeepCopy()
{
var info = new EventCanGemTaskInfo();
info.TaskId = TaskId;
info.CurrentGemProgress = CurrentGemProgress;
info.TotalGemRequired = TotalGemRequired;
info.Reward = new ItemData(Reward.id, (int)Reward.count);
return info;
}
}
public class EventCanProgressTaskInfo
{
public int TaskIdx;
public int CurrentProgress;
public int TotalProgressRequired;
public ItemData Reward;
public bool IsCompleted => CurrentProgress >= TotalProgressRequired;
public void UpdateProgressTask(out ItemData reward)
{
reward = null;
CurrentProgress++;
if (IsCompleted)
{
reward = Reward;
GContext.container.Resolve<EventCanTableContext>().GetNextProgressTaskInfo(this);
}
}
public static EventCanProgressTaskInfo Init(int TaskIdx, int CurrentProgress)
{
EventCanProgressTaskInfo info = new EventCanProgressTaskInfo();
info.TaskIdx = TaskIdx;
info.CurrentProgress = CurrentProgress;
GContext.container.Resolve<EventCanTableContext>().GetProgressInfoByIdx(TaskIdx, out info.TotalProgressRequired, out info.Reward);
return info;
}
public EventCanProgressTaskInfo DeepCopy()
{
return new EventCanProgressTaskInfo()
{
TaskIdx = TaskIdx,
CurrentProgress = CurrentProgress,
TotalProgressRequired = TotalProgressRequired,
Reward = new ItemData(Reward.id, (int)Reward.count)
};
}
}
public class EventCanPlayfabData
{
public const string PlayFabKey = "EventCan";
private const char Splitter = '|', Comma = ',';
private const int SerializedTokenCount = 11;
public int TicketCount, ProgressTaskIdx, ProgressTaskProgress, EventId, CycleId, RedirectId,
CanState, ChainPackProgress;
/// <summary>
/// GemTaskId, CurrentGemProgress
/// </summary>
public Dictionary<int, int> GemTaskInfo;
/// <summary>
/// RewardId, DrawCount
/// </summary>
public Dictionary<int, int> DrawsSinceLastRewards;
public string Serialize()
{
var sb = new StringBuilder();
sb.Append(TicketCount).Append(Splitter);
sb.Append(EventId).Append(Splitter);
sb.Append(CycleId).Append(Splitter);
sb.Append(RedirectId).Append(Splitter);
sb.Append(CanState).Append(Splitter);
sb.Append(ChainPackProgress).Append(Splitter);
sb.Append(ProgressTaskIdx).Append(Comma).Append(ProgressTaskProgress).Append(Splitter);
foreach (var kv in GemTaskInfo)
sb.Append(kv.Key).Append(Comma).Append(kv.Value).Append(Splitter);
foreach (var kv in DrawsSinceLastRewards)
sb.Append(kv.Key).Append(Comma).Append(kv.Value).Append(Splitter);
// Debug.Log("[EventCan] Serialize: " + sb.ToString());
return sb.ToString();
}
public static EventCanPlayfabData Deserialize(string s)
{
if (s == null || s == "")
return null;
var res = new EventCanPlayfabData();
try
{
var tokens = s.Trim(Splitter).Split(Splitter);
if (tokens.Length < SerializedTokenCount)
throw new Exception($"[EventCan]Wrong amount of parameters. Expect at least {SerializedTokenCount}, but got {tokens.Length} in \"{s}\".");
res.TicketCount = int.Parse(tokens[0]);
res.EventId = int.Parse(tokens[1]);
res.CycleId = int.Parse(tokens[2]);
res.RedirectId = int.Parse(tokens[3]);
res.CanState = int.Parse(tokens[4]);
res.ChainPackProgress = int.Parse(tokens[5]);
res.ProgressTaskIdx = int.Parse(tokens[6].Split(Comma)[0]);
res.ProgressTaskProgress = int.Parse(tokens[6].Split(Comma)[1]);
res.GemTaskInfo = new Dictionary<int, int>();
for (int i = 7; i < 11; i++)
res.GemTaskInfo.Add(int.Parse(tokens[i].Split(Comma)[0]), int.Parse(tokens[i].Split(Comma)[1]));
res.DrawsSinceLastRewards = new Dictionary<int, int>();
for (int i = 11; i < tokens.Length; i++)
res.DrawsSinceLastRewards.Add(int.Parse(tokens[i].Split(Comma)[0]), int.Parse(tokens[i].Split(Comma)[1]));
Debug.Log("[EventCan] Deserialize: " + res);
}
catch (Exception e)
{
Debug.LogError($"[EventCan] Failed to deserialize event can model: {e.Message}\n{e.StackTrace}");
return null;
}
return res;
}
public void Save()
{
var s = Serialize();
PlayFabMgr.Instance.UpdateUserDataValue(PlayFabKey, s);
}
public void Log()
{
Debug.Log($"[EventCan] TicketCount: {TicketCount}\n" +
$"EventId: {EventId}\n" +
$"CycleId: {CycleId}\n" +
$"RedirectId: {RedirectId}\n" +
$"CanState: {CanState}\n" +
$"ProgressTaskIdx: {ProgressTaskIdx}\n" +
$"ProgressTaskProgress: {ProgressTaskProgress}\n"
);
foreach (var kv in GemTaskInfo)
Debug.Log($"GemTaskInfo: {kv.Key}, {kv.Value}");
foreach (var kv in DrawsSinceLastRewards)
Debug.Log($"DrawsSinceLastRewards: {kv.Key}, {kv.Value}");
}
}
public class EventCanPlayerPreferenceData
{
public static string PlayerPrefsKey => "EventCanPlayerPreferenceData" + GContext.container.Resolve<IUserService>().UserId;
public int[] ColorIndices;
public string Serialize()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(ColorIndices);
}
public static EventCanPlayerPreferenceData Deserialize(string s)
{
if (s == null || s == "")
return null;
var data = new EventCanPlayerPreferenceData();
data.ColorIndices = Newtonsoft.Json.JsonConvert.DeserializeObject<int[]>(s);
return data;
}
public void Save()
{
var s = Serialize();
PlayerPrefs.SetString(PlayerPrefsKey, s);
}
public static EventCanPlayerPreferenceData RandomInit(int canColorCount)
{
var res = new EventCanPlayerPreferenceData();
res.ColorIndices = new int[GContext.container.Resolve<EventCanTableContext>().GetMaxCanCount()];
for (int i = 0; i < res.ColorIndices.Length; i++)
{
res.ColorIndices[i] = UnityEngine.Random.Range(0, canColorCount);
}
res.Save();
return res;
}
}
public class EventCanChainPackData : AChainPackData
{
public EventCanChainPackData() { }
public EventCanChainPackData(EventChainPackInfo info, int eventId, ref int chainProgress) : base(eventId, chainProgress)
{
ChainList = info.ChainList;
ExpireTime = info.ExpireTime;
Packs = info.Packs;
}
public void Init(EventChainPackInfo info, int eventId, ref int chainProgress)
{
EventId = eventId;
ChainProgress = chainProgress;
ChainList = info.ChainList;
ExpireTime = info.ExpireTime;
Packs = info.Packs;
}
public override void UploadData()
{
var model = GContext.container.Resolve<EventCanModel>();
model.ChainPackProgress = ChainProgress;
model.ToPlayfabData().Save();
}
}
public class EventCanEntranceBtnData
{
public string BtnIconUrl;
public DateTime ExpiryTime, StartTime;
public TimeSpan RemainingTime => ExpiryTime - ZZTimeHelper.UtcNow();
public bool IsActive => ZZTimeHelper.UtcNow() >= StartTime && ZZTimeHelper.UtcNow() < ExpiryTime;
public int RedPointTicketThreshold;
}
public enum EEventCanRewardType
{
Green = 1,
Blue = 2,
Purple = 3,
Red = 4,
Supply = 5,
Item = 6
}
[Flags]
public enum EEventCanBlockState
{
Available,
Gem,
Supply,
Blocked = Gem | Supply
}

View File

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

View File

@@ -0,0 +1,89 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using asap.core;
using UniRx;
using System;
using System.Collections.Generic;
using game;
using GameCore;
public class EventCanEntranceBtn : EventButtonResource
{
[SerializeField] private Image icon;
[SerializeField] private TMP_Text textTimer;
[SerializeField] private Button button;
private ILoadResourceService _loadResourceService;
private EventCanEntranceBtnData _btnData;
private const string EntranceRedPointKey = "eventcan.enter";
private void Awake()
{
if (GContext.container.Resolve<EventCanTableContext>() == null)
{
gameObject.SetActive(false);
return;
}
var chainPackData = GContext.container.Resolve<EventCanChainPackData>();
_btnData = GContext.container.Resolve<EventCanTableContext>().GetEntranceBtnData();
if (_btnData == null || !_btnData.IsActive)
{
gameObject.SetActive(false);
return;
}
UpdateTimer();
Observable.Interval(TimeSpan.FromSeconds(1f)).Subscribe(UpdateTimer).AddTo(this);
RedPointManager.Instance.SetRedPointState(EntranceRedPointKey,
GContext.container.Resolve<EventCanModel>().TicketCount >= _btnData.RedPointTicketThreshold
|| chainPackData.DoNeedPackRedPoint);
CheckResource(new List<string>() { UITypes.EventCanPanel.Path, EventCanAct.ActAddressable, _btnData.BtnIconUrl });
}
private void Start()
{
button.onClick.AddListener(EnterActAsync);
_loadResourceService = GContext.container.Resolve<ILoadResourceService>();
}
private async void EnterActAsync()
{
try
{
bool isReady = await _loadResourceService.Loads(
new List<string>() { UITypes.EventCanPanel.Path, EventCanAct.ActAddressable });
if (isReady)
{
// Debug.Log($"<color=#22a6f2>[EventCan] Download Ready!</color>");
GContext.Publish(new UnloadActToNextAct { actId = EventCanAct.ActAddressable, TransitionPanel = UITypes.CloudTransitionPanel });
}
else
{
// Debug.Log($"<color=#22a6f2>[EventCan] Download Not Ready!</color>");
var panel = await UIManager.Instance.ShowUI(UITypes.CloudTransitionPanel);
panel.GetComponent<CloudTransitionPanel>()
.SetBtn(true, () => GContext.Publish(new UnloadActToNextAct(EventCanAct.ActAddressable)));
}
}
catch (Exception e)
{
Debug.Log($"<color=#22a6f2>[EventCan] EnterActError: {e.Message}\n{e.StackTrace}</color>");
throw;
}
}
private void UpdateTimer(long _ = 0L)
{
textTimer.text = ConvertTools.ConvertTime2(_btnData.RemainingTime);
if (!_btnData.IsActive)
Destroy(gameObject);
}
protected override void OnLoadEventResource()
{
if (_btnData.IsActive)
{
GContext.container.Resolve<IUIService>().SetImageSprite(icon, _btnData.BtnIconUrl);
gameObject.SetActive(true);
}
}
}

View File

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

View File

@@ -0,0 +1,152 @@
using asap.core;
using UnityEngine;
using UniRx;
using System;
using System.Threading.Tasks;
using GameCore;
using UnityEngine.UI;
public class EventCanGemTaskView : MonoBehaviour
{
[SerializeField] private GameObject[] gems, emptySlots;
Sprite gemSprite;
[SerializeField] private RewardItemNew reward;
private IEventAggregator _eventAggregator;
private EventCanGemTaskInfo _info;
[SerializeField] private RewardFlyBatchController rewardFlyBatchController;
// private RectTransform RewardFlyTarget => emptySlots[_info.CurrentGemProgress].GetComponent<RectTransform>();
private RectTransform GetRewardFlyTarget(int progress)
{
if (progress >= gems.Length || progress < 0)
{
Debug.LogError($"[EventCan] Invalid progress {progress}");
return null;
}
return emptySlots[progress].GetComponent<RectTransform>();
}
private const float _gemPopInterval = 0.5f;
private RewardFlyBatchController _rewardFlyBatchController;
public void Init(EventCanGemTaskInfo info, IEventAggregator ea, RewardFlyBatchController rewardFlyBatchController)
{
gemSprite = gems[0].transform.GetComponent<Image>().sprite;
int i = 0;
while (i < info.CurrentGemProgress)
{
gems[i].SetActive(true);
i++;
}
while (i < gems.Length)
{
gems[i].SetActive(false);
i++;
}
reward.SetData(info.Reward);
_info = info.DeepCopy();
_eventAggregator = ea;
_eventAggregator.GetEvent<EventCanOpenEvent>().Subscribe(OnCanOpen).AddTo(this);
_rewardFlyBatchController = rewardFlyBatchController;
}
private async void OnCanOpen(EventCanOpenEvent e)
{
if (e.RewardInfo.RewardType != _info.GemType)
return;
// if ((model.BlockState & EEventCanBlockState.Gem) == EEventCanBlockState.Gem)
// {
// return;
// }
var taskInfoSnapShot = e.GemTaskInfoSnapShot;
// Debug.Log($"<color=red>[EventCan] -------------SnapShot---------------</color>");
// Debug.Log($"[EventCan] GemType: {taskInfoSnapShot.GemType}");
// Debug.Log($"[EventCan] CurrentProgress: {taskInfoSnapShot.CurrentGemProgress}");
await MakeRewardFly(e, taskInfoSnapShot);
await UpdateGemTask(taskInfoSnapShot);
}
private async Task UpdateGemTask(EventCanGemTaskInfo infoSnapShot)
{
int i;
if (infoSnapShot.TaskId != _info.TaskId)
{
gems[infoSnapShot.TotalGemRequired - 1].SetActive(true);
// await Task.Delay(TimeSpan.FromSeconds(_gemPopInterval));
var clickAwaiter = new TaskCompletionSource<bool>();
var panel = (await UIManager.Instance.ShowUINotLoading(UITypes.EventCanRewardPopupPanel)).GetComponent<EventCanRewardPanel>();
panel.Init(_info.Reward, _info.GemIdx - 1, _eventAggregator, () => clickAwaiter.SetResult(true));
// UIManager.UnblockInput();
await clickAwaiter.Task;
// UIManager.BlockInput();
_info = infoSnapShot;
i = 0;
while (i < gems.Length)
{
gems[i].SetActive(false);
i++;
}
reward.SetData(infoSnapShot.Reward);
var model = GContext.container.Resolve<EventCanModel>();
model.BlockState &= ~EEventCanBlockState.Gem;
Debug.Log($"[EventCan] Gem Unblock: {model.BlockState}");
}
else
{
i = _info.CurrentGemProgress;
// while (i < infoSnapShot.CurrentGemProgress)
// {
// gems[i].SetActive(true);
// i++;
// await Task.Delay(TimeSpan.FromSeconds(_gemPopInterval));
// }
gems[i].SetActive(true);
i++;
while (i < gems.Length)
{
gems[i].SetActive(false);
i++;
}
_info.CurrentGemProgress = infoSnapShot.CurrentGemProgress;
}
// UIManager.UnblockInput();
}
/// <summary>
/// Display RewardFly from can open event
/// </summary>
/// <param name="e">can open event</param>
/// <returns></returns>
private async Task MakeRewardFly(EventCanOpenEvent e, EventCanGemTaskInfo taskInfoSnapShot)
{
try
{
// var rewardFly = Instantiate(rewardFlyPrefab, rewardFlyPrefab.transform.parent).GetComponent<RewardFly>();
var rewardFlyTarget = GetRewardFlyTarget((taskInfoSnapShot.CurrentGemProgress + 2) % 3);
var collectionItemFly = new CollectionItemFly
{
icon = gemSprite,
numStr = "",
sourcePos = e.CanPosition,
destPos = rewardFlyTarget.position,
scale = transform.localScale,
isPlayOpen = true,
isPlayClose = true,
isDestinationRewardStash = false,
targetIconSize = rewardFlyTarget.rect.width
};
var request = new BatchedRewardFlyRequest
{
icon = gemSprite,
StartPoint = new BatchedRewardFlyPoint(e.CanRt),
EndPoint = new BatchedRewardFlyPoint(rewardFlyTarget),
isDestinationRewardStash = false,
AnimationParamIndex = 0
};
await rewardFlyBatchController.OnRewardFlyRequestAsync(request);
}
catch (Exception ex)
{
Debug.Log($"[EventCan] BreakCanError: {ex.Message}\n{ex.StackTrace}");
}
}
}

View File

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

View File

@@ -0,0 +1,231 @@
using asap.core;
using GameCore;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using game;
using UniRx;
using System.Linq;
using DG.Tweening;
using System.Threading.Tasks;
using asap.core.common;
public class EventCanPanel : MonoBehaviour
{
[SerializeField] private Button btnClose, btnInfo, btnPack;
[SerializeField] private TMP_Text textTimer, textTicketCount;
[SerializeField] private EventCanGemTaskView[] gemTaskViews;
[SerializeField] private EventCanProgressTaskView progressTaskView;
[SerializeField] private EventCanCan[] canList;
[SerializeField] private RewardFly rewardFly;
[SerializeField] private Animation basketAside, basketPopup;
[SerializeField] private GameObject goBasketIcon, goCanTrace;
[SerializeField] private DeferredRewardStashButton stashBtn;
[SerializeField] private RewardFlyBatchController rewardFlyBatchController;
private EventCanEntranceBtnData _entranceData;
private IObjectPoolService _objectPoolService;
private int EmptyCanSlotCount => canList.Where(x => !x.isActiveAndEnabled).Count();
private void Start()
{
btnClose.onClick.AddListener(OnClickClose);
btnInfo.onClick.AddListener(OnClickInfo);
btnPack.onClick.AddListener(OnClickPack);
var model = GContext.container.Resolve<EventCanModel>();
for (int i = 0; i < gemTaskViews.Length; i++)
gemTaskViews[i].Init(model.GemTasks[(EEventCanRewardType)(i + 1)], EventCanAct.EventAggregator, rewardFlyBatchController);
progressTaskView.Init(model.ProgressTaskInfo, EventCanAct.EventAggregator);
for (int i = 0; i < canList.Length; i++)
canList[i].Init(i, model.CanList[i]);
EventCanAct.EventAggregator.GetEvent<EventCanOpenEvent>().Subscribe(OnCanOpen).AddTo(this);
OnTicketCountChange();
basketAside.transform.parent.gameObject.SetActive(true);
basketAside.Play(BASKET_IDLE);
basketPopup.transform.parent.gameObject.SetActive(false);
EventCanAct.EventAggregator.GetEvent<EventCanTicketUpdate>().Subscribe(_ => OnTicketCountChange()).AddTo(this);
EventCanAct.EventAggregator.GetEvent<EventCanInsufficientTicketEvent>().Subscribe(_ => OnClickPack()).AddTo(this);
_entranceData = GContext.container.Resolve<EventCanTableContext>().GetEntranceBtnData();
UpdateTimer();
Observable.Interval(System.TimeSpan.FromSeconds(1f)).Subscribe(UpdateTimer).AddTo(this);
var chainPackData = GContext.container.Resolve<EventCanChainPackData>();
RedPointManager.Instance.SetRedPointState(chainPackData.RedPointKey, chainPackData.DoNeedPackRedPoint);
CreateRewardFlyObjectPool();
model.BlockState = EEventCanBlockState.Available;
}
private void UpdateTimer(long _ = 0L)
{
textTimer.text = ConvertTools.ConvertTime2(_entranceData.RemainingTime);
if (!_entranceData.IsActive)
Destroy(gameObject);
}
private void OnCanOpen(EventCanOpenEvent e)
{
OnTicketCountChange();
if (e.RewardInfo.RewardType == EEventCanRewardType.Supply)
{
PlayBasketAppear(e.CanPosition);
PopCans();
}
var model = GContext.container.Resolve<EventCanModel>();
model.ToPlayerPreferenceData().Save();
}
private void OnTicketCountChange()
{
var model = GContext.container.Resolve<EventCanModel>();
textTicketCount.text = model.TicketCount.ToString();
textTicketCount.color = model.TicketCount > 0 ? Color.white : Color.red;
}
private void OnClickClose()
{
ReleaseRewardFlyObjectPool();
GContext.Publish(new UnloadActToNextAct());
}
private async void OnClickInfo()
{
try
{
await UIManager.Instance.ShowUINotLoading(UITypes.EventCanInfoPanel);
}
catch (System.Exception e)
{
Debug.Log($"[EventCan]{e.Message}\n{e.StackTrace}");
}
}
private async void OnClickPack()
{
var chainPackData = GContext.container.Resolve<EventCanChainPackData>();
try
{
// PlayBtnPressedAnimation();
GameObject go;
if (chainPackData.ChainProgress >= chainPackData.ChainListCount)
{
go = await UIManager.Instance.ShowUINotLoading(UITypes.EventCanNormalPackPanel);
var normalPanel = go.GetComponent<GeneralEventNormalPackPanel>();
normalPanel.Init(GContext.container.Resolve<EventCanTableContext>().GetNormalPackInfo());
return;
}
go = await UIManager.Instance.ShowUINotLoading(UITypes.EventCanChainPackPanel);
var panel = go.GetComponent<ChainPackPanel>();
panel.Init(chainPackData);
}
catch (System.Exception e)
{
Debug.Log($"[EventCan]Pack Error: {e.Message}\n{e.StackTrace}");
}
}
private async void PlayBtnPressedAnimation()
{
btnPack.GetComponent<Animator>().Play("Pressed");
await Task.Delay(System.TimeSpan.FromSeconds(0.5f));
btnPack.GetComponent<Animator>().Play("Normal");
}
private const string BASKET_IDLE = "basket_idle", BASKET_IN = "basket_in", BASKET_OUT = "basket_out";
private const string BASKET_FLY_IN = "basket_fly_in", BASKET_FLY_OUT = "basket_fly_out",
BASKET_FLY_LOOP = "basket_fly_loop", BASKET_SHOW = "basket_show";
public void PlayBasketAppear(Vector3 pos)
{
ShowBasketIcoWithDelay(pos, EventCanAct.ParamsCtrl.BasketShowDelay);
// PlayAnimationWithDelay(basketPopup, BASKET_SHOW);
PlayAnimationWithDelay(basketAside, BASKET_OUT, EventCanAct.ParamsCtrl.BasketSlideOutDelay);
PlayAnimationWithDelay(basketPopup, BASKET_FLY_IN, EventCanAct.ParamsCtrl.BasketFlyInDelay);
PlayAnimationWithDelay(basketPopup, BASKET_FLY_LOOP, EventCanAct.ParamsCtrl.BasketFlyLoopDelay);
var newCanCount = EmptyCanSlotCount;
float loopTime = EventCanAct.ParamsCtrl.CanPopupInterval * newCanCount + EventCanAct.ParamsCtrl.CanPopupDuration;
// Debug.Log($"<color=red>[EventCan] {loopTime} = {newCanCount} * {EventCanAct.ParamsCtrl.CanPopupInterval}</color>");
PlayAnimationWithDelay(basketPopup, BASKET_FLY_OUT, EventCanAct.ParamsCtrl.BasketFlyLoopDelay + loopTime);
PlayAnimationWithDelay(basketAside, BASKET_IN, EventCanAct.ParamsCtrl.BasketFlyLoopDelay + loopTime + EventCanAct.ParamsCtrl.BasketSlideInDeltaDelay);
}
public async void PopCans()
{
try
{
await Task.Delay(System.TimeSpan.FromSeconds(EventCanAct.ParamsCtrl.BasketFlyLoopDelay));
var emptyIdxLst = canList
.Select((c, i) => new { isActive = c.isActiveAndEnabled, idx = i })
.Where(x => x.isActive == false)
.Select(x => x.idx)
.OrderBy(x => Random.value);
foreach (var idx in emptyIdxLst)
{
var fx = Instantiate(goCanTrace, goCanTrace.transform.parent);
Vector2 startPos = basketPopup.transform.position;
fx.transform.position = startPos;
fx.SetActive(true);
Vector2 endPos = canList[idx].transform.position;
float dy = startPos.y - endPos.y, t = 0;
Vector2 pivot = new Vector2(endPos.x, startPos.y - dy * 0.2f);
DOTween.To(() => t, x => t = x, 1, EventCanAct.ParamsCtrl.CanPopupDuration)
.OnUpdate(() => fx.transform.position = FtMathUtils.CalculateBezierCurve(t, startPos, pivot, endPos))
.OnComplete(() => { Destroy(fx); canList[idx].Init(idx, true); });
await Task.Delay(System.TimeSpan.FromSeconds(EventCanAct.ParamsCtrl.CanPopupInterval));
}
// UIManager.UnblockInput();
var model = GContext.container.Resolve<EventCanModel>();
model.BlockState &= ~EEventCanBlockState.Supply;
Debug.Log($"[EventCan] Supply Unblock: {model.BlockState}");
}
catch (System.Exception e)
{
Debug.Log($"[EventCan]{e.Message}\n{e.StackTrace}");
}
}
private async void PlayAnimationWithDelay(Animation anim, string name, float delay = 0f)
{
try
{
await Task.Delay(System.TimeSpan.FromSeconds(delay));
anim.transform.parent.gameObject.SetActive(true);
anim.Play(name);
}
catch (System.Exception e)
{
Debug.Log($"[EventCan]{e.Message}\n{e.StackTrace}");
}
}
private async void ShowBasketIcoWithDelay(Vector3 pos, float delay = 0f)
{
try
{
goBasketIcon.transform.position = pos;
await Task.Delay(System.TimeSpan.FromSeconds(delay));
goBasketIcon.SetActive(false);
goBasketIcon.SetActive(true);
await Task.Delay(System.TimeSpan.FromSeconds(EventCanAct.ParamsCtrl.BasketShowDuration));
goBasketIcon.SetActive(false);
}
catch (System.Exception e)
{
Debug.Log($"[EventCan]{e.Message}\n{e.StackTrace}");
}
}
private void CreateRewardFlyObjectPool()
{
_objectPoolService = GContext.container.Resolve<IObjectPoolService>();
_objectPoolService.CreatePool(rewardFly, 0, 10);
}
private void ReleaseRewardFlyObjectPool()
{
_objectPoolService?.DestroyPool(typeof(RewardFly));
}
}
public class EventCanTicketUpdate { }
public class EventCanInsufficientTicketEvent { }

View File

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

View File

@@ -0,0 +1,19 @@
using UnityEngine;
[CreateAssetMenu(fileName = "EventCanParamsCtrl", menuName = "ScriptableObjects/EventCanParamsCtrl")]
public class EventCanParamsCtrl : ScriptableObject
{
[Tooltip("篮子图标出现延迟,从点击开始")] public float BasketShowDelay = 0f;
[Tooltip("篮子图标出现时长")] public float BasketShowDuration = 55f/60f;
[Tooltip("侧边篮子滑出延迟,从点击开始")] public float BasketSlideOutDelay = 0f;
[Tooltip("上方篮子飞入延迟,从点击开始")] public float BasketFlyInDelay = 1f;
[Tooltip("上方篮子循环动画播放延迟,从点击开始")] public float BasketFlyLoopDelay = 2f;
[Tooltip("侧边篮子滑入延迟,从循环动画结束、罐头生成完毕后开始")] public float BasketSlideInDeltaDelay = 0f;
[Tooltip("罐头生成间隔")] public float CanPopupInterval = 0.3f;
[Tooltip("罐头生成时长")] public float CanPopupDuration = 0.5f;
#if UNITY_EDITOR
[Tooltip("DEBUG开启")]public bool IsDebugMode = false;
[Tooltip("DEBUG限定宝石")] public EEventCanRewardType GemType = EEventCanRewardType.Green;
#endif
}

View File

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

View File

@@ -0,0 +1,88 @@
using asap.core;
using DG.Tweening;
using DG.Tweening.Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UniRx;
using System;
using System.Threading.Tasks;
public class EventCanProgressTaskView : MonoBehaviour
{
[SerializeField] private Image progressBar;
[SerializeField] private TMP_Text textProgress;
[SerializeField] private RewardItemNew reward;
private EventCanProgressTaskInfo _info;
private IEventAggregator _eventAggregator;
/// <summary>
/// Prevents multiple task updates
/// </summary>
private bool _isUpdatingTask = false;
public void Init(EventCanProgressTaskInfo info, IEventAggregator ea)
{
float p = info.CurrentProgress / (float)info.TotalProgressRequired;
progressBar.fillAmount = p;
textProgress.text = $"{info.CurrentProgress}/{info.TotalProgressRequired}";
reward.SetData(info.Reward);
_info = info.DeepCopy();
_eventAggregator = ea;
var model = GContext.container.Resolve<EventCanModel>();
_eventAggregator.GetEvent<EventCanOpenEvent>()
.Subscribe(_ => UpdateProgressTask(model.ProgressTaskInfo))
.AddTo(this);
}
public async void UpdateProgressTask(EventCanProgressTaskInfo newInfo)
{
try
{
if (_isUpdatingTask)
return;
string[] tokens;
int currentProgress = 0;
int totalProgressRequired = 0;
TweenerCore<int, int, DG.Tweening.Plugins.Options.NoOptions> tweenText;
TweenerCore<float, float, DG.Tweening.Plugins.Options.FloatOptions> tweenBar;
Sequence sequence;
if (_info.TaskIdx != newInfo.TaskIdx)
{
_isUpdatingTask = true;
tokens = textProgress.text.Split('/');
currentProgress = int.Parse(tokens[0]);
totalProgressRequired = int.Parse(tokens[1]);
tweenText = DOTween.To(() => currentProgress, v => currentProgress = v, totalProgressRequired, 0.5f)
.OnUpdate(() => textProgress.text = $"{currentProgress}/{totalProgressRequired}");
tweenBar = progressBar.DOFillAmount(1, 0.5f);
sequence = DOTween.Sequence();
sequence.Join(tweenText).Join(tweenBar);
await sequence.AsyncWaitForCompletion();
reward.SetReceived(true);
// _eventAggregator.Publish(new EventCanTaskRewardClaimEvent(_info.Reward, reward.gameObject.transform.position));
var request = new EventRewardFlyStashRequest(_info.Reward, reward.icon.GetComponent<RectTransform>());
GContext.Publish(request);
await Task.Delay(TimeSpan.FromSeconds(1f));
progressBar.fillAmount = 0;
await Awaiters.NextFrame;
_info = newInfo.DeepCopy();
reward.SetData(newInfo.Reward);
textProgress.text = $"0/{newInfo.TotalProgressRequired}";
_isUpdatingTask = false;
}
tokens = textProgress.text.Split('/');
currentProgress = int.Parse(tokens[0]);
totalProgressRequired = newInfo.TotalProgressRequired;
tweenText = DOTween.To(() => currentProgress, v => currentProgress = v, newInfo.CurrentProgress, 0.5f)
.OnUpdate(() => textProgress.text = $"{currentProgress}/{totalProgressRequired}");
tweenBar = progressBar.DOFillAmount(newInfo.CurrentProgress / (float)newInfo.TotalProgressRequired, 0.5f);
sequence = DOTween.Sequence();
sequence.Join(tweenText).Join(tweenBar);
await sequence.AsyncWaitForCompletion();
}
catch (Exception e)
{
Debug.LogError($"[EventCan] {e.Message}\n{e.StackTrace}");
}
}
}

View File

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

View File

@@ -0,0 +1,48 @@
using System;
using asap.core;
using GameCore;
using UnityEngine;
using UnityEngine.UI;
public class EventCanRewardPanel : MonoBehaviour
{
[SerializeField] private RewardItemNew reward;
[SerializeField] private GameObject[] gemBanners;
[SerializeField] private Button btnClaim;
private Action _action;
private IEventAggregator _eventAggregator;
private ItemData _rewardItem;
public void Init(ItemData rewardItem, int tunnelIdx, IEventAggregator ea, Action claimMark = null)
{
_rewardItem = rewardItem;
reward.SetData(rewardItem, abbr: true);
for (int i = 0; i < gemBanners.Length; i++)
gemBanners[i].SetActive(i == tunnelIdx);
btnClaim.onClick.AddListener(OnClaim);
_action = claimMark;
_eventAggregator = ea;
}
private void OnClaim()
{
UIManager.Instance.DestroyUI(UITypes.EventCanRewardPopupPanel);
_action?.Invoke();
// _eventAggregator.Publish(
// new EventCanTaskRewardClaimEvent(_rewardItem, reward.gameObject.transform.position));
var request = new EventRewardFlyStashRequest(_rewardItem, reward.icon.GetComponent<RectTransform>());
GContext.Publish(request);
}
}
public class EventCanTaskRewardClaimEvent
{
public ItemData Reward{get; set;}
public Vector3 StartPos{get; set;}
public EventCanTaskRewardClaimEvent(ItemData item, Vector3 pos)
{
Reward = item;
StartPos = pos;
}
}

View File

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

View File

@@ -0,0 +1,164 @@
using UnityEngine;
using System.Collections.Generic;
using asap.core;
using GameCore;
public class EventCanSystem
{
private readonly EventCanModel _model;
public EventCanSystem()
{
_model = GContext.container.Resolve<EventCanModel>();
}
public EEventCanOpenResponse OpenCan(int canIdx)
{
if (_model.TicketCount <= 0)
{
Debug.Log($"[EventCan] No ticket to open can.");
return EEventCanOpenResponse.InsufficientToken;
}
if (!_model.CanList[canIdx].DoesExist)
{
Debug.Log($"[EventCan] Can {canIdx} has been opened.");
return EEventCanOpenResponse.Other;
}
_model.AddTicket(-1);
_model.CanList[canIdx].DoesExist = false;
_model.ToPlayfabData().Save();
return EEventCanOpenResponse.Success;
}
public void GrantCanReward(EventCanRewardInfo rewardInfo)
{
int _evItemId = 0, _evItemNum = 0, _evRewardId = 0, _evRewardNum = 0, _evTaskId = 0, _evItemDrop = 0, _evItemDropNum = 0;
_model.WeightModifier.UpdateDrawsSinceLastRewards(rewardInfo.RewardId);
ItemData progressReward;
_evItemId = rewardInfo.ItemId;
_evItemNum = rewardInfo.ItemCount;
switch (rewardInfo.RewardType)
{
case EEventCanRewardType.Green:
case EEventCanRewardType.Blue:
case EEventCanRewardType.Purple:
case EEventCanRewardType.Red:
// _model.GemTasks[rewardInfo.RewardType].CurrentGemProgress += rewardInfo.ItemCount;
_model.GemTasks[rewardInfo.RewardType].UpdateGemTasks(rewardInfo, out progressReward, out var oldTaskId);
if (progressReward != null)
{
_evTaskId = oldTaskId;
_evItemDrop = progressReward.id;
_evItemDropNum = progressReward.count;
// GContext.container.Resolve<PlayerItemData>().AddItem(progressReward);
GContext.Publish(new DeferredRewardStashService.EventStashItem { Item = progressReward });
}
break;
case EEventCanRewardType.Supply:
RefillCanList();
break;
case EEventCanRewardType.Item:
var r = rewardInfo.ToItemData();
//in case the item needs transformation somehow
_evItemId = r.id;
_evItemNum = r.count;
// GContext.container.Resolve<PlayerItemData>().AddItem(r);
GContext.Publish(new DeferredRewardStashService.EventStashItem { Item = r });
break;
default:
Debug.Log($"[EventCan] Unknown reward type: {rewardInfo.RewardType}");
break;
}
// _model.ProgressTaskInfo.CurrentProgress++;
_model.ProgressTaskInfo.UpdateProgressTask(out progressReward);
if (progressReward != null)
{
_evRewardId = progressReward.id;
_evRewardNum = progressReward.count;
// GContext.container.Resolve<PlayerItemData>().AddItem(progressReward);
GContext.Publish(new DeferredRewardStashService.EventStashItem { Item = progressReward });
}
_model.ToPlayfabData().Save();
// Debug.Log($"<color=red>[EventCan] -------------------Event Tracking---------------------</color>");
// Debug.Log($"[EventCan] item_id: {_evItemId}");
// Debug.Log($"[EventCan] item_num: {_evItemNum}");
// Debug.Log($"[EventCan] reward_id: {_evRewardId}");
// Debug.Log($"[EventCan] reward_num: {_evRewardNum}");
// Debug.Log($"[EventCan] task_id: {_evTaskId}");
// Debug.Log($"[EventCan] item_drop: {_evItemDrop}");
// Debug.Log($"[EventCan] item_dropnum: {_evItemDropNum}");
// Debug.Log($"[EventCan] -------------------End of Event Tracking---------------------");
#if AGG
using (var e = GEvent.GameEvent("event_can"))
{
e.AddContent("item_id", _evItemId)
.AddContent("item_num", _evItemNum)
.AddContent("reward_id", _evRewardId)
.AddContent("reward_num", _evRewardNum)
.AddContent("task_id", _evTaskId)
.AddContent("item_drop", _evItemDrop)
.AddContent("item_dropnum", _evItemDropNum);
}
#endif
}
public EventCanRewardInfo GenerateReward()
{
var weightList = new List<int>();
EventCanRewardInfo rewardInfo, res = null;
for (int i = 0; i < _model.RewardPool.Length; i++)
{
rewardInfo = _model.RewardPool[i];
_model.WeightModifier.GetWeightDelta(rewardInfo.RewardId, out var weightDelta, out var mustGet);
// if (mustGet)
// {
// Debug.Log($"[EventCan] Must get! {rewardInfo.RewardType}.");
// Debug.Log($"[EventCan] Must get! {res is not {RewardType: EEventCanRewardType.Supply}}.");
// }
if (mustGet && res is not { RewardType: EEventCanRewardType.Supply })
res = rewardInfo;
else
weightList.Add(rewardInfo.BaseWeight + weightDelta);
}
if (res != null)
{
// Debug.Log($"[EventCan] Must get! {res.RewardType}.");
return res;
}
var idx = FtMathUtils.GetRandomIdxFromWeightList(weightList);
return _model.RewardPool[idx];
}
public void RefillCanList()
{
// Debug.Log("<color=red>[EventCan] Refill!</color>");
foreach (var canInfo in _model.CanList)
{
canInfo.DoesExist = true;
}
}
}
public class EventCanOpenEvent
{
public EventCanRewardInfo RewardInfo;
public Vector2 CanPosition;
public EventCanGemTaskInfo GemTaskInfoSnapShot = null;
public RectTransform CanRt;
public EventCanOpenEvent(EventCanRewardInfo rewardInfo, RectTransform can, EventCanGemTaskInfo infoSnapShot = null)
{
RewardInfo = rewardInfo;
CanPosition = can.position;
GemTaskInfoSnapShot = infoSnapShot;
CanRt = can;
}
}
public enum EEventCanOpenResponse
{
Success, InsufficientToken, Other
}

View File

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

View File

@@ -0,0 +1,297 @@
using System.Collections.Generic;
using System.Linq;
using asap.core;
using cfg;
using GameCore;
using UnityEngine;
public class EventCanTableContext
{
private Tables _tables;
private EventCanMain _eventCanMain = null;
private TbEventCanRange _totalRewardPool = null;
private FishingEventCycleItem2 _tableCycle = null;
private FishingEvent _tableEvent = null;
private EventCanTableContext(Tables tables, EventCanMain eventCanMain,
FishingEventCycleItem2 tableCycle, FishingEvent tableEvent)
{
_tables = tables;
_eventCanMain = eventCanMain;
_totalRewardPool = _tables.TbEventCanRange;
_tableCycle = tableCycle;
_tableEvent = tableEvent;
}
public EventCanTableContext() { }
public void ReadTables(int eventId)
{
int redirectId, cycleId;
_tables = GContext.container.Resolve<Tables>();
cycleId = _tables.TbFishingEvent[eventId].RedirectID;
redirectId = _tables.TbFishingEventCycleItem2[cycleId].RedirectID;
_tableEvent = _tables.TbFishingEvent[eventId];
_tableCycle = _tables.TbFishingEventCycleItem2[cycleId];
_eventCanMain = _tables.TbEventCanMain[redirectId];
_totalRewardPool = _tables.TbEventCanRange;
return;
}
public List<EventCanRewardInfo> InitRewardPool()
{
var rewardIdList = _eventCanMain.CanRange;
var rewardPool = new List<EventCanRewardInfo>();
EEventCanRewardType rewardType;
int weight;
foreach (var idx in rewardIdList)
{
if (!_totalRewardPool.DataMap.TryGetValue(idx, out var eventCanRange))
{
Debug.Log($"[EventCan]No table data found for reward id {idx}");
continue;
}
if (eventCanRange.Weight <= 0)
continue;
rewardType = GetRewardType(idx);
weight = eventCanRange.MinMax.Count == 2 ? 0 : eventCanRange.Weight;
rewardPool.Add(new EventCanRewardInfo()
{
RewardId = eventCanRange.RangeID,
RewardType = rewardType,
ItemId = eventCanRange.ItemID,
ItemCount = eventCanRange.ItemNum,
BaseWeight = weight
});
}
return rewardPool;
}
public EEventCanRewardType GetRewardType(int rewardId)
{
return (EEventCanRewardType)(rewardId % 10000 / 1000);
}
public bool GetWeightChangeThreshold(int rewardId, out (int rewardAppearDraws, int rewardMustDropDraws) res)
{
if (!_tables.TbEventCanRange.DataMap.TryGetValue(rewardId, out var eventCanRange) || eventCanRange.MinMax.Count != 2)
{
// Debug.Log($"[EventCan]No weigth change data found for reward id {rewardId}");
res = (0, 0);
return false;
}
res = (eventCanRange.MinMax[0], eventCanRange.MinMax[1]);
return true;
}
public int GetRewardWeight(int rewardId)
{
if (!_tables.TbEventCanRange.DataMap.TryGetValue(rewardId, out var eventCanRange))
{
Debug.Log($"[EventCan]No table data found for reward id {rewardId}");
return 0;
}
return eventCanRange.Weight;
}
public Dictionary<EEventCanRewardType, EventCanGemTaskInfo> InitGemTaskInfo()
{
var res = new List<EventCanGemTaskInfo>();
_eventCanMain.GemReward.ForEach(
x =>
{
var gemTask = _tables.TbEventCanGemReward.Get(x);
var rewardItemData = new ItemData(gemTask.ItemDrop, gemTask.ItemDropNum);
GContext.container.Resolve<PlayerItemData>().ItemTransition(rewardItemData);
res.Add(new EventCanGemTaskInfo()
{
TaskId = x,
CurrentGemProgress = 0,
TotalGemRequired = gemTask.GemRequired,
Reward = rewardItemData
});
}
);
return res.ToDictionary(x => (EEventCanRewardType)(x.TaskId % 1000 / 100), x => x);
}
public EventCanGemTaskInfo GetGemTaskInfo(int taskId, int currentGemProgress = 0)
{
// var gemTask = _tables.TbEventCanGemReward.Get(TaskId);
if (!_tables.TbEventCanGemReward.DataMap.TryGetValue(taskId, out var gemTask))
{
Debug.Log($"[EventCan]Gem task id {taskId} not found in gem reward table.");
return null;
}
var rewardItemData = new ItemData(gemTask.ItemDrop, gemTask.ItemDropNum);
GContext.container.Resolve<PlayerItemData>().ItemTransition(rewardItemData);
return new EventCanGemTaskInfo()
{
TaskId = taskId,
CurrentGemProgress = currentGemProgress,
TotalGemRequired = gemTask.GemRequired,
Reward = rewardItemData
};
}
public bool GetNextProgressTaskInfo(EventCanProgressTaskInfo currentTaskInfo)
{
var rewardList = _eventCanMain.CanReward;
var idx = (currentTaskInfo.TaskIdx + 1) % rewardList.Count;
var rewardId = rewardList[idx];
if (!_tables.TbEventCanReward.DataMap.TryGetValue(rewardId, out var eventCanReward))
{
Debug.Log($"[EventCan]No table data found for reward id {rewardId}");
return false;
}
var itemData = new ItemData(eventCanReward.ItemID, eventCanReward.Num);
GContext.container.Resolve<PlayerItemData>().ItemTransition(itemData);
currentTaskInfo.TaskIdx = idx;
currentTaskInfo.CurrentProgress -= currentTaskInfo.TotalProgressRequired;
currentTaskInfo.TotalProgressRequired = eventCanReward.Consume;
currentTaskInfo.Reward = itemData;
return true;
}
public EventCanProgressTaskInfo InitProgressTaskInfo()
{
var eventCanReward = _tables.TbEventCanReward.DataList[0];
var itemData = new ItemData(eventCanReward.ItemID, eventCanReward.Num);
GContext.container.Resolve<PlayerItemData>().ItemTransition(itemData);
return new EventCanProgressTaskInfo()
{
TaskIdx = 0,
CurrentProgress = 0,
TotalProgressRequired = eventCanReward.Consume,
Reward = itemData,
};
}
public bool GetProgressInfoByIdx(int idx, out int ProgressRequired, out ItemData Reward)
{
var taskIdList = _eventCanMain.CanReward;
ProgressRequired = 0;
Reward = null;
if (idx >= taskIdList.Count || idx < 0)
{
Debug.Log($"[EventCan]Idx {idx} out of range {taskIdList.Count}.");
return false;
}
var task = _tables.TbEventCanReward[taskIdList[idx]];
Reward = new ItemData(task.ItemID, task.Num);
GContext.container.Resolve<PlayerItemData>().ItemTransition(Reward);
ProgressRequired = task.Consume;
return true;
}
public bool GetNextGemTaskInfo(EventCanGemTaskInfo currentTaskInfo)
{
var id = currentTaskInfo.TaskId;
if (!_tables.TbEventCanGemReward.DataMap.TryGetValue(id, out var eventCanGemRewardData))
{
Debug.Log($"[EventCan]No table data found for gem reward id {id}");
return false;
}
if (!_tables.TbEventCanGemReward.DataMap.TryGetValue(eventCanGemRewardData.NextTarget, out var newGemRewardData))
{
Debug.Log($"[EventCan]No table data found for gem reward id {eventCanGemRewardData.NextTarget}");
return false;
}
var itemData = new ItemData(newGemRewardData.ItemDrop, newGemRewardData.ItemDropNum);
GContext.container.Resolve<PlayerItemData>().ItemTransition(itemData);
currentTaskInfo.TaskId = newGemRewardData.TaskID;
currentTaskInfo.CurrentGemProgress -= currentTaskInfo.TotalGemRequired;
currentTaskInfo.TotalGemRequired = newGemRewardData.GemRequired;
currentTaskInfo.Reward = itemData;
return true;
}
public int GetMaxCanCount()
{
return _eventCanMain.CanMax;
}
public int GetWelcomeGift()
{
return _tableCycle.WelcomeGift;
}
public Dictionary<int, int> GetInitialDrawsSinceLastRewards()
{
return _eventCanMain.CanRange.Select(id => _tables.TbEventCanRange[id])
.Where(reward => reward.MinMax.Count == 2)
.ToDictionary(reward => reward.RangeID, _ => 0);
}
public EventCanEntranceBtnData GetEntranceBtnData()
{
var res = new EventCanEntranceBtnData();
res.BtnIconUrl = _eventCanMain.Icon;
res.RedPointTicketThreshold = _tableCycle.RedDot;
System.DateTime et = new System.DateTime(), st = new System.DateTime();
try
{
et = System.DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime);
st = System.DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).StartTime);
}
catch (System.Exception e)
{
Debug.Log($"[EventCan] {e.Message}\n{e.StackTrace}");
return null;
}
finally
{
res.ExpiryTime = et;
res.StartTime = st;
}
return res;
}
public EventChainPackInfo GetPackData()
{
var chainList = _tables.TbEventPackManager[_eventCanMain.PackId].VIPPackList[0];
var expireTime = new System.DateTime();
try
{
expireTime = System.DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime);
}
catch (System.Exception e)
{
Debug.Log($"[EventBreak] {e.Message}\n{e.StackTrace}");
return null;
}
var chainListIdSet = chainList.ToHashSet();
var packs = _tables.TbPack.DataList.Where(p => chainListIdSet.Contains(p.ID)).ToArray();//?
return new EventChainPackInfo()
{
ChainList = chainList,
ExpireTime = expireTime,
Packs = packs,
RedPointKey = "eventcan.pack"
};
}
public GeneralEventNormalPackInfo GetNormalPackInfo()
{
var expireTime = new System.DateTime();
try
{
expireTime = System.DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime);
}
catch (System.Exception e)
{
Debug.Log($"[EventBreak] {e.Message}\n{e.StackTrace}");
return null;
}
var packList = _tables.TbEventPackManager[_eventCanMain.PackId2].VIPPackList[0];
return new GeneralEventNormalPackInfo
{
EventId = _tableEvent.ID,
PackLeft = _tables.TbPack[packList[0]],
PackRight = _tables.TbPack[packList[1]],
ExpireTime = expireTime,
};
}
}

View File

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

View File

@@ -0,0 +1,78 @@
using System;
using asap.core;
using cfg;
using GameCore;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using UniRx;
public class GeneralEventNormalPackPanel : MonoBehaviour
{
[SerializeField]
private TMP_Text textTimer, textPriceLeft, textPriceRight, textCountLeft, textCountRight, textDiscount;
[SerializeField] private Button btnClose, btnBuyLeft, btnBuyRight;
private IAPItemList _iapLeft, _iapRight;
private PlayerItemData _playerItemData;
private DateTime _expireTime;
private TimeSpan RemainingTime => _expireTime - ZZTimeHelper.UtcNow();
private int _eventId;
private Pack _packLeft, _packRight;
public void Init(GeneralEventNormalPackInfo info)
{
btnClose.onClick.AddListener(OnClickClose);
_eventId = info.EventId;
_packLeft = info.PackLeft;
_packRight = info.PackRight;
_expireTime = info.ExpireTime;
_playerItemData = GContext.container.Resolve<PlayerItemData>();
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
Observable.Interval(TimeSpan.FromSeconds(1.0f)).Subscribe(_ =>
{
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
if (RemainingTime.TotalSeconds <= 0) OnClickClose();
}).AddTo(this);
_playerItemData.ResolveIapId(_packLeft.IAPID, out _iapLeft, textPriceLeft);
_playerItemData.ResolveIapId(_packRight.IAPID, out _iapRight, textPriceRight);
btnBuyLeft.onClick.AddListener(() => _ = OnClickBuy(_packLeft.DropID, _iapLeft));
btnBuyRight.onClick.AddListener(() => _ = OnClickBuy(_packRight.DropID, _iapRight));
textCountLeft.text =
((int)_playerItemData.GetItemDataByDropId(_packLeft.DropID)[0].count).ToString();
textCountRight.text =
((int)_playerItemData.GetItemDataByDropId(_packRight.DropID)[0].count).ToString();
textDiscount.text = LocalizationMgr.GetFormatTextValue("UI_FishingShopPanel_2", GetDiscountNumber());
}
private int GetDiscountNumber()
{
float discount = _packRight.Rebate * 100;
return (int)discount;
}
private async System.Threading.Tasks.Task OnClickBuy(int dropId, IAPItemList iapItemList)
{
if (RemainingTime.TotalSeconds <= 0)
return;
bool res = await GContext.container.Resolve<PlayerShopData>().OnBuy(dropId,
new ShopBuyTypeData { type = ShopBuyType.EventPack, ID = _eventId }, iapItemList,
_playerItemData.GetItemDataByDropId(dropId));
if (res)
{
GContext.Publish(new EventTicketUpdate());
OnClickClose();
}
}
private void OnClickClose()
{
// RedPointManager.Instance.SetRedPointState(EventShootingRangeData.PackRedPointId, false);
UIManager.Instance.DestroyUI(gameObject.name);
}
}
public class GeneralEventNormalPackInfo
{
public int EventId;
public Pack PackLeft, PackRight;
public DateTime ExpireTime;
}

View File

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