using DG.Tweening; using IVDataFormat; using IVServerFormat; using System.Collections; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.UI; public class PassMgr : MonoBehaviour { #region Const private static PassMgr curMgr = null; #endregion Const #region UI [Header("UI")] [SerializeField] private TextMeshProUGUI txtMainT; private GameObject goMainBadge; [SerializeField] private Canvas canvasUI; private ButtonIV[] btnTabs; private GameObject[] goTabBadges; private ButtonIV[] btnPages; private GameObject[] goPageBadges; private ButtonIV btnGetReward; private ButtonIV btnBuy; private GameObject goPaidLock; private TextMeshProUGUI txtTime, txtProgressT, txtProgress, txtDesc1, txtDesc2, txtBuy; private RectTransform rtrfTime; [SerializeField] private EScrController escrPass; private EScrPass passItemLast; #endregion UI #region Variables private int iLoading = 1; private bool bReLocalize = true; private bool bInitNeed = true; private int iMoveToTab = -1; private int iSelectedTab = -1; private int iSelectedType = -1; private eCondition selectedCond = eCondition.None; private int iSelectedPage = 0; private dPass selectedPass = null; private bool bRefreshNeed = false; private EnhancedUI.SmallList passList; private string strPrePath = null; private AsyncOperationHandle handleImg; private Sequence seqTime = null; #endregion Variables #region Base public static void SLocalize(bool bmain) { if (curMgr != null) curMgr.Localize(bmain); } private void Localize(bool bmain) { if (bmain) { txtMainT.text = LocalizationText.GetText("pass_title"); goMainBadge = txtMainT.transform.parent.Find("badge").gameObject; } else { bReLocalize = false; Transform trfui = canvasUI.transform; trfui.Find("txtT").GetComponent().text = LocalizationText.GetText("pass_title"); for (int i = 0; i < btnTabs.Length; i++) btnTabs[i].transform.Find("txt").GetComponent().text = LocalizationText.GetText(FormatString.CombineAllString("pass", (i + 1).ToString())); trfui.Find("txtfree").GetComponent().text = FormatString.CombineAll(LocalizationText.GetText("all_free"),LocalizationText.GetText("pass_title")); trfui.Find("txtpaid").GetComponent().text = FormatString.CombineAll(LocalizationText.GetText("all_paid"), LocalizationText.GetText("pass_title")); trfui.Find("txtBuyTip").GetComponent().text = LocalizationText.GetText("shop_refund2"); trfui.Find("txtBuyTip").GetChild(0).GetChild(0).GetComponent().text = LocalizationText.GetText("all_see"); btnGetReward.transform.GetChild(0).GetComponent().text = LocalizationText.GetText("all_getall"); if (selectedCond != eCondition.None) { string strcond = ((int)selectedCond).ToString(); txtProgressT.text = LocalizationText.GetText(FormatString.CombineAllString("passcond", strcond)); txtDesc1.text = LocalizationText.GetText(FormatString.CombineAllString("passdesc1_", strcond)); //txtDesc2.text = } } } // 설정에서 언어 변경 시 처리. public static void SReLocalize() { curMgr.Localize(true); curMgr.bReLocalize = true; } // 백버튼 처리. public static bool SCloseMenu() { return curMgr.CloseMenu(); } private bool CloseMenu() { // 게임 시작 후 열린적 없음. if (bInitNeed) return false; if (canvasUI.enabled) { ClosePass(); return true; } return false; } private void Awake() { curMgr = this; } void Start() { iLoading--; } private void Init() { Transform trfui = canvasUI.transform; btnTabs = trfui.Find("tabWrapLeft").GetComponentsInChildren(true); goTabBadges = new GameObject[btnTabs.Length]; for (int i = 0; i < goTabBadges.Length; i++) goTabBadges[i] = btnTabs[i].transform.Find("badge").gameObject; btnPages = trfui.Find("pages").GetComponentsInChildren(true); goPageBadges = new GameObject[btnPages.Length]; for (int i = 0; i < goPageBadges.Length; i++) { goPageBadges[i] = btnPages[i].transform.Find("badge").gameObject; btnPages[i].transform.GetChild(0).GetComponent().text = (i + 1).ToString(); } txtProgressT = trfui.Find("txtProgressT").GetComponent(); txtProgress = txtProgressT.transform.Find("txtProgress").GetComponent(); txtDesc1 = trfui.Find("txtDesc1").GetComponent(); txtDesc2 = trfui.Find("txtDesc2").GetComponent(); txtTime = trfui.Find("txtTime").GetComponent(); rtrfTime = txtTime.transform.GetChild(0).GetComponent(); goPaidLock = trfui.Find("imgplock").gameObject; btnBuy = trfui.Find("btnBuy").GetComponent(); txtBuy = btnBuy.transform.GetChild(0).GetComponent(); btnGetReward = trfui.Find("btnGetReward").GetComponent(); passList = new EnhancedUI.SmallList(); escrPass.LoadDatas(passList); passItemLast = trfui.Find("PassItem").GetComponent(); passItemLast.InitCell(); } #endregion Base #region UI public static bool SOpenPassEvent() { if (curMgr.iLoading > 0) return false; curMgr.iMoveToTab = 0; curMgr.OpenPass(); return true; } public void OpenPass() { if (iLoading > 0) return; iLoading++; if (bInitNeed) { bInitNeed = false; Init(); } if (bReLocalize) Localize(false); // 이벤트 패스 존재 여부에 따라서 버튼 표시. btnTabs[0].gameObject.SetActive(DataHandler.TryGetPass(cGoods.PassTypeEvent, 0, out dPass _)); if (iMoveToTab < 0) iMoveToTab = 0; if (iMoveToTab == 0 && !btnTabs[0].gameObject.activeSelf) iMoveToTab = 1; if (iMoveToTab != iSelectedTab) { if (iMoveToTab == 0) TabEvent(); else if (iMoveToTab == 1) TabMonster(); else if (iMoveToTab == 2) TabLevel(); else if (iMoveToTab == 3) TabStage(); } else { // 패스 창 열때 이미지 불러오기. //if (!selectedPass.path.Equals(strPrePath)) //{ // CoverCamera.Hold(); // strPrePath = selectedPass.path; // Addressables.LoadAssetAsync(selectedPass.path).Completed += ALoadImgComp; //} SetBadge(false); bRefreshNeed = selectedPass.endAt < new System.DateTime(2099, 1, 1) || selectedPass.refreshAt < selectedPass.endAt; SetSeqTime(false, bRefreshNeed); escrPass.scroller.RefreshActiveCellViews(); passItemLast.RefreshCellView(); txtProgress.text = FormatString.TextConditionValue(selectedCond, selectedPass.progress); } escrPass.SetFloat(1f); passItemLast.SetFloat(1f); StartCoroutine(nameof(CoShineEffect)); canvasUI.enabled = true; GameUIMgr.SSetMainUiOn(false); BattleMgr.SSetBattleUiOn(false); BattleMgr.SSetClearFailUiOn(false); BattleMgr.Instance.SetCameraOn(false); SoundMgr.Instance.PlaySfx(SoundName.BtnPress); iLoading--; } public void ClosePass() { if (!canvasUI.enabled) return; if (iLoading > 0) return; iLoading++; SetSeqTime(bRefreshNeed, false); bRefreshNeed = false; StopCoroutine("CoShineEffect"); canvasUI.enabled = false; GameUIMgr.SSetMainUiOn(true); BattleMgr.SSetBattleUiOn(true); BattleMgr.SSetClearFailUiOn(true); BattleMgr.Instance.SetCameraOn(true); // 패스 창 닫을때 리소스 해제. strPrePath = null; //imgPass.color = Global.CLR_Trans; //imgPass.sprite = null; //if (handleImg.IsValid()) //{ // Addressables.Release(handleImg); // AddressableMgr.SAddUnload(); //} SoundMgr.Instance.PlaySfx(SoundName.BtnPress); iLoading--; } // 시계 연출. private void SetSeqTime(bool bprev, bool bnext) { if (bprev == bnext) return; if (bprev) { if (bRefreshNeed) seqTime.Kill(); } else { Vector3 v3left = new Vector3(0f, 0f, 5f); Vector3 v3right = new Vector3(0f, 0f, -5f); seqTime = DOTween.Sequence() .SetUpdate(true) .Append(rtrfTime.DOLocalRotate(v3right, 0.05f)) .Append(rtrfTime.DOLocalRotate(v3left, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3right, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3left, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3right, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3left, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3right, 0.1f)) .Append(rtrfTime.DOLocalRotate(v3left, 0.1f)) .Append(rtrfTime.DOLocalRotate(Vector3.zero, 0.05f)) .AppendInterval(1.5f) .SetLoops(-1) .Play(); } } // 반짝이는 연출. private IEnumerator CoShineEffect() { float fvalue = 1f; while (true) { escrPass.SetFloat(fvalue); passItemLast.SetFloat(fvalue); yield return YieldInstructionCache.WaitForSeconds(0.05f); fvalue -= 0.08f; if (fvalue < 0f) { fvalue = 1f; yield return YieldInstructionCache.WaitForSeconds(3f); } } } #endregion UI #region Tab // 이벤트 패스. public void TabEvent() { if(DataHandler.TryGetPass(cGoods.PassTypeEvent, 0, out dPass targetPass)) TabPass(0, cGoods.PassTypeEvent, targetPass.condType); } // 일회성 패스 - 몬스터 탭. public void TabMonster() { TabPass(1, cGoods.PassTypeOne, eCondition.MonsterCnt); } // 일회성 패스 - 레벨 탭. public void TabLevel() { TabPass(2, cGoods.PassTypeOne, eCondition.PlayerLv); } // 일회성 패스 - 스테이지 탭. public void TabStage() { TabPass(3, cGoods.PassTypeOne, eCondition.StageClear); } // 탭. private void TabPass(int index, int passtype, eCondition condtype) { if (iSelectedTab == index) return; if (iSelectedTab >= 0) { btnTabs[iSelectedTab].interactable = true; } iMoveToTab = index; iSelectedTab = index; iSelectedType = passtype; selectedCond = condtype; string strcond = ((int)selectedCond).ToString(); btnTabs[iSelectedTab].interactable = false; DataHandler.TryGetPass(iSelectedType, selectedCond, out selectedPass); SetBadge(false); SoundMgr.Instance.PlaySfx(SoundName.BtnPress); txtProgressT.text = LocalizationText.GetText(FormatString.CombineAllString("passcond", strcond)); txtDesc1.text = LocalizationText.GetText(FormatString.CombineAllString("passdesc1_", strcond)); // 페이지 표시. int imaxpage = selectedPass.levels.Length <= selectedPass.passUnit ? 0 : ((selectedPass.levels.Length - 1) / selectedPass.passUnit + 1); for (int k = 0; k < btnPages.Length; k++) { btnPages[k].gameObject.SetActive(k < imaxpage); } // 표시할 페이지 계산. if (imaxpage > 0) { int ipageindex = imaxpage - 1; for (int k = 0; k < imaxpage; k++) { int imaxindexexc = (k + 1) * selectedPass.passUnit; if (selectedPass.isPaid[k]) { // 유료패스 활성화 상태이며, 페이지에서 수령한 항목이 페이지의 마지막 항목 이전일 경우. if (selectedPass.haveLvPaids[k] < imaxindexexc) { ipageindex = k; break; } } else { // 페이지에서 수령한 항목이 페이지의 마지막 항목 이전일 경우. if (selectedPass.haveLvFrees[k] < imaxindexexc) { ipageindex = k; break; } } } TabPage(ipageindex); } else { TabPage(0); } txtProgress.text = FormatString.TextConditionValue(selectedCond, selectedPass.progress); // 2099년 이전에 종료되는 패스이거나, 갱신일시가 종료일시보다 이전일 경우에는 남은 시간 표시. bool brefresh = selectedPass.endAt < new System.DateTime(2099, 1, 1) || selectedPass.refreshAt < selectedPass.endAt; SetSeqTime(bRefreshNeed, brefresh); bRefreshNeed = brefresh; if (bRefreshNeed) { txtTime.text = FormatString.TextLeftTimeDHMS(selectedPass.refreshAt); txtTime.gameObject.SetActive(true); } else { txtTime.gameObject.SetActive(false); } } #endregion Tab #region Page public void TabPage(int index) { if (iSelectedPage >= 0) btnPages[iSelectedPage].interactable = true; iSelectedPage = index; if (iSelectedPage >= 0) btnPages[iSelectedPage].interactable = false; // 항목 수량 조정. int iminindexinc = iSelectedPage * selectedPass.passUnit; int imaxindexexc = (iSelectedPage + 1) * selectedPass.passUnit; if (imaxindexexc > selectedPass.levels.Length) imaxindexexc = selectedPass.levels.Length; int ilen = imaxindexexc - iminindexinc; SoundMgr.Instance.PlaySfx(SoundName.BtnPress); // 마지막 단계는 제일 우측 고정. ilen--; while (passList.Count < ilen) passList.Add(passList.Count); while (passList.Count > ilen) passList.RemoveEnd(); escrPass.scroller.ReloadData(); passItemLast.SetData(ilen); if (btnPages[0].gameObject.activeSelf) btnGetReward.interactable = goPageBadges[iSelectedPage].activeSelf; else btnGetReward.interactable = goTabBadges[iSelectedTab].activeSelf; // 유료 패스. if (selectedPass.isPaid[iSelectedPage]) { txtBuy.text = LocalizationText.GetText("all_buycomp"); btnBuy.enabled = false; goPaidLock.SetActive(false); } else { txtBuy.text = DataHandler.GetShopPrice(selectedPass.shopIds[iSelectedPage], 1); btnBuy.enabled = true; goPaidLock.SetActive(true); } } public static dPass SGetPass() { return curMgr.selectedPass; } public static dPassLevel SGetLevel(int index) { return curMgr.GetLevel(index); } // 아이템 인덱스를 받아서 현재 페이지-인덱스에 맞는 패스 레벨 정보를 리턴. private dPassLevel GetLevel(int index) { int iaddindex = iSelectedPage * selectedPass.passUnit; return selectedPass.levels[index + iaddindex]; } // 현재 선택된 페이지 인덱스 리턴. public static int SGetPageIndex(int index) { return curMgr.iSelectedPage; } public static int SGetLevelIndex(int index) { return curMgr.GetLevelIndex(index); } // 아이템 인덱스를 받아서 현재 페이지-인덱스에 맞는 레벨 인덱스를 리턴. private int GetLevelIndex(int index) { int iaddindex = iSelectedPage * selectedPass.passUnit; return index + iaddindex; } #endregion Page #region Refresh & Badge public static void SUpdateOneSec() { if (curMgr != null) curMgr.UpdateOneSec(); } // 초당 갱신. private void UpdateOneSec() { // 패스 창이 열려있으며, 제한 시간이 있을 경우. if (bRefreshNeed) txtTime.text = FormatString.TextLeftTimeDHMS(selectedPass.refreshAt); } public static void SResetPass() { if (curMgr != null) curMgr.ResetPass(); } // 이벤트/반복 패스 갱신. private void ResetPass() { // 패스 창이 열려있지 않으면 메인 뱃지 표시만 갱신. if (bInitNeed || !canvasUI.enabled) { SetBadge(true); return; } iLoading++; // 이벤트 패스 존재 여부에 따라서 버튼 표시. btnTabs[0].gameObject.SetActive(DataHandler.TryGetPass(cGoods.PassTypeEvent, 0, out dPass _)); if (iSelectedTab == 0 && !btnTabs[0].gameObject.activeSelf) TabMonster(); // 유료 패스. if (selectedPass.isPaid[iSelectedPage]) { txtBuy.text = LocalizationText.GetText("all_buycomp"); btnBuy.enabled = false; goPaidLock.SetActive(false); } else { txtBuy.text = DataHandler.GetShopPrice(selectedPass.shopIds[iSelectedPage], 1); btnBuy.enabled = true; goPaidLock.SetActive(true); } SetBadge(false); escrPass.scroller.RefreshActiveCellViews(); passItemLast.RefreshCellView(); iLoading--; } // 패스 목록 새로고침. private void RefreshPass(int passtype, eCondition condtype) { if (canvasUI.enabled && !bInitNeed && passtype == iSelectedType && condtype == selectedCond) { SetBadge(false, passtype, condtype); txtProgress.text = FormatString.TextConditionValue(selectedCond, selectedPass.progress); escrPass.scroller.RefreshActiveCellViews(); passItemLast.RefreshCellView(); } else { SetBadge(true, passtype, condtype); } } public static void SSetBadge(bool bmainonly, int passtype = -1, eCondition condtype = eCondition.None) { if (curMgr != null) curMgr.SetBadge(bmainonly, passtype, condtype); } // 뱃지 표시. private void SetBadge(bool bmainonly, int passtype = -1, eCondition condtype = eCondition.None) { // 메인 뱃지만 표시 갱신. if (bmainonly) { // 이벤트 패스가 열려있으며, 전체 갱신이거나 이벤트 갱신일 경우. if (DataHandler.TryGetPass(cGoods.PassTypeEvent, eCondition.None, out dPass _)) { DataHandler.CalcPassProgress(cGoods.PassTypeEvent, eCondition.None); // 획득 가능 상태. bool brewavail = DataHandler.IsPassRewardAvail(cGoods.PassTypeEvent, eCondition.None); if (brewavail) { goMainBadge.SetActive(true); return; } } // 일회성 패스. eCondition[] condtypes = new eCondition[3] { eCondition.MonsterCnt, eCondition.PlayerLv, eCondition.StageClear }; for (int i = 0; i < condtypes.Length; i++) { DataHandler.CalcPassProgress(cGoods.PassTypeOne, condtypes[i]); // 획득 가능 상태. bool brewavail = DataHandler.IsPassRewardAvail(cGoods.PassTypeOne, condtypes[i]); if (brewavail) { goMainBadge.SetActive(true); return; } } goMainBadge.SetActive(false); return; } bool bbadge = false; if (condtype != eCondition.None) bbadge = goMainBadge.activeSelf; // 이벤트 패스가 열려있으며, 전체 갱신이거나 이벤트 갱신일 경우. if (DataHandler.TryGetPass(cGoods.PassTypeEvent, 0, out dPass _) && (passtype < 0 || passtype == cGoods.PassTypeEvent)) { DataHandler.CalcPassProgress(cGoods.PassTypeEvent, condtype); bool brewavail = DataHandler.IsPassRewardAvail(cGoods.PassTypeEvent, condtype); bbadge |= brewavail; goTabBadges[0].SetActive(brewavail); } // 전체 갱신이거나 일회성 패스 갱신일 경우. if (passtype < 0 || passtype == cGoods.PassTypeOne) { eCondition[] condtypes = new eCondition[3] { eCondition.MonsterCnt, eCondition.PlayerLv, eCondition.StageClear }; for (int i = 0; i < condtypes.Length; i++) { if (condtype != eCondition.None && condtype != condtypes[i]) continue; DataHandler.CalcPassProgress(cGoods.PassTypeOne, condtypes[i]); // 획득 가능 상태 갱신. bool brewavail = DataHandler.IsPassRewardAvail(cGoods.PassTypeOne, condtypes[i]); bbadge |= brewavail; goTabBadges[i + 1].SetActive(brewavail); } } // 세부 페이지가 있을 경우. if (selectedPass.passUnit < selectedPass.levels.Length) { int imaxpage = selectedPass.haveLvFrees.Length; for (int k = 0; k < imaxpage; k++) { goPageBadges[k].SetActive(DataHandler.IsPassRewardAvail(selectedPass.passType, selectedPass.condType, k)); } btnGetReward.interactable = goPageBadges[iSelectedPage].activeSelf; } else { btnGetReward.interactable = goTabBadges[iSelectedTab].activeSelf; } goMainBadge.SetActive(bbadge); } #endregion Refresh & Badge #region Method Reward public static void SGetPassReward() { curMgr.GetPassReward(); } // 보상 받기. public void GetPassReward() { if (iLoading > 0) return; if (Application.internetReachability == NetworkReachability.NotReachable) { GameUIMgr.SOpenPopup1Button(LocalizationText.GetText(Global.STR_CheckNetwork)); return; } iLoading++; CoverCamera.Hold(); // 페이지 별로 보상 받기 기능. DataHandler.CalcPassProgress(iSelectedType, selectedCond); txtProgress.text = FormatString.TextConditionValue(selectedCond, selectedPass.progress); nIdLvInfo data = new nIdLvInfo(); data.sid = selectedPass.id; data.cnt = iSelectedPage; data.lv = selectedPass.availLevel; int imaxindexexc = (iSelectedPage + 1) * selectedPass.passUnit; if (data.lv > imaxindexexc) data.lv = imaxindexexc; SoundMgr.Instance.PlaySfx(SoundName.BtnPress); SvConnectManager.Instance.RequestSvPost(true, 0, UrlApi.GetUrl(UrlApi.PassReward), typeof(nPassRewardReturn), APassRewardSucc, APassRewardFail, data, false); } // 보상 받기 통신 실패. private void APassRewardFail(SvError error, object request) { CoverCamera.Release(); iLoading--; } // 보상 받기 통신 성공. private void APassRewardSucc(object result, object request) { nPassRewardReturn data = result as nPassRewardReturn; if (data == null) { APassRewardFail(new SvError(eErrorCode.NULL_OR_EMPTY), request); return; } DataHandler.AddGoods(data.result, data.playCurrency, true); int imaxindexexc = (iSelectedPage + 1) * selectedPass.passUnit; if (imaxindexexc > selectedPass.availLevel) imaxindexexc = selectedPass.availLevel; DataHandler.RecvPassReward(iSelectedType, selectedCond, iSelectedPage, imaxindexexc); SetBadge(false); escrPass.scroller.RefreshActiveCellViews(); passItemLast.RefreshCellView(); DataHandler.SaveData(); GameUIMgr.SOpenPopupGoods(data.result); CoverCamera.Release(); iLoading--; } #endregion Method Reward #region Method Buy // 유료 패스 구매. public void BuyPass() { if (iLoading > 0) return; #if VER_CASH_VISIBLE if (selectedPass.shopIds[iSelectedPage] < 0) return; iLoading++; CoverCamera.Hold(); SoundMgr.Instance.PlaySfx(SoundName.BtnPress); btnBuy.enabled = false; //nGoods data = new nGoods(cGoods.TPass, selectedPass.id, iSelectedPage); //SvConnectManager.Instance.RequestSvPost(true, 0, UrlApi.GetUrl(UrlApi.Property), typeof(nGoodsGet), AGetPropertySucc, AGetPropertyFail, data, true); ShopMgr.STryBuy(selectedPass.shopIds[iSelectedPage]); #else GameUIMgr.SOpenPopup1Button(LocalizationText.GetText(Global.STR_Prepare)); #endif } public static void SSuccBuyPass(int passid, int pageindex) { if (curMgr != null) curMgr.SuccBuyPass(passid, pageindex); } // 유료 패스 구매 완료. private void SuccBuyPass(int passid, int pageindex) { txtBuy.text = LocalizationText.GetText("all_buycomp"); btnBuy.enabled = false; goPaidLock.SetActive(false); if(DataHandler.TryGetPassById(passid, out dPass pass)) { DataHandler.BuyPass(pass.passType, pass.condType, pageindex); RefreshPass(pass.passType, pass.condType); } CoverCamera.Release(); iLoading--; } public static void SFailBuyPass() { if (curMgr != null) curMgr.FailBuyPass(); } // 유료 패스 구매 실패. private void FailBuyPass() { btnBuy.enabled = true; CoverCamera.Release(); iLoading--; } #endregion Method Buy #region Buy Test // 테스트 재화 획득 통신 실패. private void AGetPropertyFail(SvError error, object request) { FailBuyPass(); } // 테스트 재화 획득 통신 성공. private void AGetPropertySucc(object result, object request) { nGoodsGet data = result as nGoodsGet; if (data == null) { AGetPropertyFail(new SvError(eErrorCode.NULL_OR_EMPTY), request); return; } nGoods goods = request as nGoods; SuccBuyPass(goods.propertyId, (int)goods.propertyCount); } #endregion Buy Test }