475 lines
14 KiB
C#
475 lines
14 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using TMPro;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
|
|
public class MainMenuManager : MonoBehaviour
|
|
{
|
|
public const string MainMenuSceneName = "MainMenu";
|
|
|
|
const string CryptoAddressPrefsKey = "MainMenu.CryptoAddress";
|
|
/// <summary>500 CC fee to process a withdrawal.</summary>
|
|
const int WithdrawalFeeCc = 500;
|
|
/// <summary>$20 USD = 20.0 RC, stored in DB as 80 rc coins (4 coins per 1.0 RC).</summary>
|
|
const int MinimumWithdrawalRcCoins = 80;
|
|
|
|
[Header("Stats")]
|
|
[SerializeField] private GameObject statsPanel;
|
|
[SerializeField] private TMP_Text usernameText;
|
|
[SerializeField] private TMP_Text ccText;
|
|
[SerializeField] private TMP_Text rcText;
|
|
|
|
[Header("Screens")]
|
|
public GameObject mainMenuScreen;
|
|
public GameObject gameModesScreen;
|
|
public GameObject dummyBuyScreen;
|
|
public GameObject withdrawalScreen;
|
|
public GameObject settingsScreen;
|
|
|
|
[Header("Play")]
|
|
public Button btnPlay;
|
|
public Button btnTutorial;
|
|
public TMP_Text rcPlayText;
|
|
public TMP_Text entryFeeTxt;
|
|
public TMP_Text rcPrizeTxt;
|
|
[SerializeField] string tutorialGameScene = GameTutorialManager.DefaultGameSceneName;
|
|
|
|
[Header("Dummy Buy")]
|
|
public Button btnBuyUsd5;
|
|
public Button btnBuyUsd20;
|
|
public Button btnBuyUsd50;
|
|
|
|
[Header("Withdrawal")]
|
|
public Button btnWithdrawal;
|
|
public Button btnPaste;
|
|
public TMP_InputField inputCryptoAddress;
|
|
public TMP_Text txtWithdrawStatus;
|
|
private bool isCoinBuyInProgress;
|
|
|
|
[Header("Settings")]
|
|
public ProfileInfoFetcher profileInfoFetcher;
|
|
public TMP_Text txtUsername;
|
|
public TMP_Text txtEmail;
|
|
public TMP_Text txtAge,txtMatches,txtWinRatio;
|
|
public TMP_Text txtId;
|
|
public Button btnLogout;
|
|
|
|
[Header("Audio")]
|
|
public ToggleButton toggleSfx;
|
|
public ToggleButton toggleMusic;
|
|
|
|
/// <summary>Default play cost (coin units) if <c>/settings</c> is not loaded yet.</summary>
|
|
const int FallbackEntryFeeCoins = 21;
|
|
|
|
int _matchEntryFeeCoins = FallbackEntryFeeCoins;
|
|
|
|
public static MainMenuManager instance;
|
|
|
|
void Awake()
|
|
{
|
|
if(LoginManager.instance==null){
|
|
SceneManager.LoadScene(0);
|
|
}
|
|
instance = this;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
LoginManager.OnUserDataUpdated += OnUserUpdated;
|
|
|
|
usernameText.text = "";
|
|
ccText.text = "";
|
|
rcText.text = "";
|
|
LoginManager.instance.GetUserData((success, error, user) => {
|
|
if (success)
|
|
{
|
|
OnUserUpdated(user);
|
|
RefreshSettingsProfile();
|
|
}
|
|
else
|
|
{
|
|
if (btnPlay != null)
|
|
btnPlay.interactable = false;
|
|
if (rcPlayText != null)
|
|
rcPlayText.text = string.IsNullOrEmpty(error) ? "Could not load profile. Try again." : error;
|
|
}
|
|
});
|
|
|
|
RefreshSettingsProfile();
|
|
|
|
btnBuyUsd5.onClick.AddListener(() => OnBuy(RcPack.Usd5));
|
|
btnBuyUsd20.onClick.AddListener(() => OnBuy(RcPack.Usd20));
|
|
btnBuyUsd50.onClick.AddListener(() => OnBuy(RcPack.Usd50));
|
|
|
|
if (inputCryptoAddress != null)
|
|
{
|
|
inputCryptoAddress.text = PlayerPrefs.GetString(CryptoAddressPrefsKey, string.Empty);
|
|
inputCryptoAddress.onValueChanged.AddListener(OnCryptoAddressChanged);
|
|
}
|
|
|
|
UpdateWithdrawalStatus();
|
|
|
|
if (btnPaste != null)
|
|
btnPaste.onClick.AddListener(OnPasteFromClipboard);
|
|
|
|
btnPlay.onClick.AddListener(OnPlay);
|
|
if (btnTutorial != null && btnTutorial != btnPlay)
|
|
btnTutorial.onClick.AddListener(OnPlayTutorial);
|
|
|
|
toggleSfx.onToggleValueChanged.AddListener(OnToggleSfx);
|
|
toggleMusic.onToggleValueChanged.AddListener(OnToggleMusic);
|
|
|
|
toggleSfx.SetIsOn(AudioManager.instance.IsSFXOn());
|
|
toggleMusic.SetIsOn(AudioManager.instance.IsMusicOn());
|
|
|
|
if (btnLogout != null)
|
|
btnLogout.onClick.AddListener(OnLogout);
|
|
|
|
if (!LevelLoadManager.BlocksMainMenuSettingsBootstrap)
|
|
StartCoroutine(CoBootstrapSettingsWithoutLoader());
|
|
}
|
|
|
|
void OnDestroy(){
|
|
LoginManager.OnUserDataUpdated -= OnUserUpdated;
|
|
toggleSfx.onToggleValueChanged.RemoveListener(OnToggleSfx);
|
|
toggleMusic.onToggleValueChanged.RemoveListener(OnToggleMusic);
|
|
if (btnTutorial != null && btnTutorial != btnPlay)
|
|
btnTutorial.onClick.RemoveListener(OnPlayTutorial);
|
|
if (btnLogout != null)
|
|
btnLogout.onClick.RemoveListener(OnLogout);
|
|
}
|
|
|
|
void OnLogout()
|
|
{
|
|
if (MessageBoxDialog.IsAvailable)
|
|
{
|
|
MessageBoxDialog.Show(
|
|
"Log out?",
|
|
"You will need to sign in again to play.",
|
|
confirmed =>
|
|
{
|
|
if (confirmed)
|
|
ConfirmLogout();
|
|
});
|
|
return;
|
|
}
|
|
|
|
ConfirmLogout();
|
|
}
|
|
|
|
void ConfirmLogout()
|
|
{
|
|
LoginManager.Logout();
|
|
SceneManager.LoadScene(0);
|
|
}
|
|
|
|
void OnToggleSfx(bool isOn)
|
|
{
|
|
AudioManager.instance.SetSfxVolume(isOn ? 1f : 0f);
|
|
}
|
|
|
|
void OnToggleMusic(bool isOn)
|
|
{
|
|
AudioManager.instance.SetMusicVolume(isOn ? 1f : 0f);
|
|
}
|
|
|
|
void OnPlay()
|
|
{
|
|
if (LoginManager.CurrentUser == null)
|
|
{
|
|
Debug.LogError("Play blocked: user profile not loaded.");
|
|
return;
|
|
}
|
|
if (LoginManager.CurrentUser.rc < _matchEntryFeeCoins)
|
|
{
|
|
string fee = CoinHelper.FormatString(_matchEntryFeeCoins) + " RC";
|
|
if (MessageBoxDialog.IsAvailable)
|
|
{
|
|
MessageBoxDialog.Show(
|
|
"Not enough RC",
|
|
"You need " + fee + " to play. Buy more RC and try again.");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Not enough RC to play");
|
|
}
|
|
return;
|
|
}
|
|
if (CupidLobby.instance == null)
|
|
{
|
|
Debug.LogError("Play blocked: CupidLobby is missing from this scene.");
|
|
return;
|
|
}
|
|
CupidLobby.instance.Matchmake();
|
|
}
|
|
|
|
public void OnPlayTutorial()
|
|
{
|
|
if (LoginManager.CurrentUser == null)
|
|
{
|
|
Debug.LogError("Tutorial blocked: user profile not loaded.");
|
|
return;
|
|
}
|
|
if (LevelLoadManager.instance == null)
|
|
{
|
|
Debug.LogError("Tutorial blocked: LevelLoadManager is missing.");
|
|
return;
|
|
}
|
|
StartCoroutine(CoLaunchTutorial());
|
|
}
|
|
|
|
IEnumerator CoLaunchTutorial()
|
|
{
|
|
MatchmadePlayer myPlayer = GameTutorialManager.CreateMyPlayerFromUser(LoginManager.CurrentUser);
|
|
MatchmadePlayer cpuPlayer = GameTutorialManager.CreateCpuOpponent();
|
|
|
|
yield return GameTutorialManager.CoFetchPlayerL10(myPlayer);
|
|
|
|
GameTutorialManager.PrepareLaunch(myPlayer, cpuPlayer);
|
|
LevelLoadManager.LoadLevel(tutorialGameScene);
|
|
}
|
|
|
|
void OnCryptoAddressChanged(string value)
|
|
{
|
|
PlayerPrefs.SetString(CryptoAddressPrefsKey, value ?? string.Empty);
|
|
PlayerPrefs.Save();
|
|
UpdateWithdrawalStatus();
|
|
}
|
|
|
|
void UpdateWithdrawalStatus(UserData user = null)
|
|
{
|
|
if (txtWithdrawStatus == null)
|
|
return;
|
|
UserData u = user ?? LoginManager.CurrentUser;
|
|
if (u == null)
|
|
return;
|
|
|
|
if (inputCryptoAddress != null && string.IsNullOrWhiteSpace(inputCryptoAddress.text))
|
|
{
|
|
txtWithdrawStatus.text = "Enter a valid wallet address to withdraw safely.";
|
|
return;
|
|
}
|
|
if (u.rc < MinimumWithdrawalRcCoins)
|
|
{
|
|
txtWithdrawStatus.text = "Your RC balance is below the minimum withdrawal amount ($20 USD / 20.0 RC).";
|
|
return;
|
|
}
|
|
if (u.cc < WithdrawalFeeCc)
|
|
{
|
|
txtWithdrawStatus.text = "Withdrawal costs 500 CC. Your CC balance is below 500 CC.";
|
|
return;
|
|
}
|
|
txtWithdrawStatus.text = string.Empty;
|
|
}
|
|
|
|
void OnPasteFromClipboard()
|
|
{
|
|
if (inputCryptoAddress == null)
|
|
return;
|
|
string clip = GUIUtility.systemCopyBuffer;
|
|
if (!string.IsNullOrEmpty(clip))
|
|
inputCryptoAddress.text = clip;
|
|
}
|
|
|
|
void OnBuy(string packId){
|
|
if (isCoinBuyInProgress)
|
|
return;
|
|
|
|
isCoinBuyInProgress = true;
|
|
SetCoinBuyButtonsInteractable(false);
|
|
|
|
LoginManager.instance.PurchaseRcPack(packId, (success, error) => {
|
|
if(success){
|
|
OnUserUpdated(LoginManager.CurrentUser);
|
|
AudioManager.instance.PlayCoinsSfx();
|
|
}
|
|
|
|
isCoinBuyInProgress = false;
|
|
SetCoinBuyButtonsInteractable(true);
|
|
});
|
|
}
|
|
|
|
void SetCoinBuyButtonsInteractable(bool interactable)
|
|
{
|
|
if (btnBuyUsd5 != null)
|
|
btnBuyUsd5.interactable = interactable;
|
|
if (btnBuyUsd20 != null)
|
|
btnBuyUsd20.interactable = interactable;
|
|
if (btnBuyUsd50 != null)
|
|
btnBuyUsd50.interactable = interactable;
|
|
}
|
|
|
|
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
|
|
}
|
|
|
|
void OnUserUpdated(UserData user){
|
|
usernameText.text = user.username;
|
|
ccText.text = user.cc.ToString("N0") + " CC";
|
|
rcText.text = CoinHelper.FormatString(user.rc) + " RC";
|
|
|
|
if (rcPlayText != null)
|
|
rcPlayText.text = "";
|
|
if (btnPlay != null)
|
|
btnPlay.interactable = true;
|
|
|
|
UpdateWithdrawalStatus(user);
|
|
}
|
|
|
|
/// <summary>Called by <see cref="LevelLoadManager"/> so the loading overlay stays until matchmaker settings are refreshed.</summary>
|
|
public IEnumerator FinishLoadingScreenAndApplySettings()
|
|
{
|
|
yield return CoReadyMatchmakerSettingsThenApply();
|
|
}
|
|
|
|
IEnumerator CoBootstrapSettingsWithoutLoader()
|
|
{
|
|
yield return null;
|
|
yield return CoReadyMatchmakerSettingsThenApply();
|
|
}
|
|
|
|
IEnumerator CoReadyMatchmakerSettingsThenApply()
|
|
{
|
|
const float endpointWaitSec = 30f;
|
|
float deadline = Time.realtimeSinceStartup + endpointWaitSec;
|
|
while (!Cupid.IsEndpointReady && Time.realtimeSinceStartup < deadline)
|
|
yield return null;
|
|
|
|
yield return Cupid.CoRefreshSettings();
|
|
|
|
ApplyMatchmakerFeeUi();
|
|
|
|
if (LoginManager.CurrentUser != null)
|
|
OnUserUpdated(LoginManager.CurrentUser);
|
|
}
|
|
|
|
void ApplyMatchmakerFeeUi()
|
|
{
|
|
if (Cupid.Settings == null)
|
|
{
|
|
_matchEntryFeeCoins = FallbackEntryFeeCoins;
|
|
if (entryFeeTxt != null)
|
|
entryFeeTxt.text = "—";
|
|
if (rcPrizeTxt != null)
|
|
rcPrizeTxt.text = "—";
|
|
return;
|
|
}
|
|
|
|
CupidSettings s = Cupid.Settings;
|
|
_matchEntryFeeCoins = s.entry_fee > 0 ? s.entry_fee : FallbackEntryFeeCoins;
|
|
|
|
if (entryFeeTxt != null)
|
|
{
|
|
entryFeeTxt.text = s.entry_fee > 0
|
|
? CoinHelper.FormatString(s.entry_fee) + " RC"
|
|
: "—";
|
|
}
|
|
if (rcPrizeTxt != null)
|
|
{
|
|
rcPrizeTxt.text = s.rc_prize > 0
|
|
? CoinHelper.FormatString(s.rc_prize) + " RC"
|
|
: "—";
|
|
}
|
|
}
|
|
|
|
|
|
void SetStatsPanelVisible(bool visible)
|
|
{
|
|
if (statsPanel == null)
|
|
return;
|
|
statsPanel.SetActive(visible);
|
|
Transform topPanel = statsPanel.transform.parent;
|
|
if (topPanel != null)
|
|
topPanel.gameObject.SetActive(visible);
|
|
}
|
|
|
|
public void ShowMainMenuScreen(){
|
|
SetStatsPanelVisible(true);
|
|
mainMenuScreen.SetActive(true);
|
|
gameModesScreen.SetActive(false);
|
|
dummyBuyScreen.SetActive(false);
|
|
withdrawalScreen.SetActive(false);
|
|
settingsScreen.SetActive(false);
|
|
}
|
|
|
|
public void ShowGameModesScreen(){
|
|
SetStatsPanelVisible(true);
|
|
mainMenuScreen.SetActive(false);
|
|
gameModesScreen.SetActive(true);
|
|
dummyBuyScreen.SetActive(false);
|
|
withdrawalScreen.SetActive(false);
|
|
settingsScreen.SetActive(false);
|
|
}
|
|
|
|
public void ShowDummyBuyScreen(){
|
|
SetStatsPanelVisible(false);
|
|
mainMenuScreen.SetActive(false);
|
|
gameModesScreen.SetActive(false);
|
|
dummyBuyScreen.SetActive(true);
|
|
withdrawalScreen.SetActive(false);
|
|
settingsScreen.SetActive(false);
|
|
}
|
|
|
|
public void ShowWithdrawalScreen(){
|
|
SetStatsPanelVisible(false);
|
|
mainMenuScreen.SetActive(false);
|
|
gameModesScreen.SetActive(false);
|
|
dummyBuyScreen.SetActive(false);
|
|
withdrawalScreen.SetActive(true);
|
|
settingsScreen.SetActive(false);
|
|
UpdateWithdrawalStatus();
|
|
}
|
|
|
|
public void ShowSettingsScreen(){
|
|
SetStatsPanelVisible(false);
|
|
mainMenuScreen.SetActive(false);
|
|
gameModesScreen.SetActive(false);
|
|
dummyBuyScreen.SetActive(false);
|
|
withdrawalScreen.SetActive(false);
|
|
settingsScreen.SetActive(true);
|
|
RefreshSettingsProfile();
|
|
}
|
|
|
|
void RefreshSettingsProfile()
|
|
{
|
|
if (profileInfoFetcher == null)
|
|
return;
|
|
|
|
UserData user = LoginManager.CurrentUser;
|
|
if (user == null)
|
|
return;
|
|
|
|
profileInfoFetcher.GetPlayerProfile(user.id, (success, error, profile) =>
|
|
{
|
|
if (!success || profile == null)
|
|
{
|
|
Debug.LogWarning("Settings profile fetch failed: " + (error ?? "unknown"));
|
|
return;
|
|
}
|
|
ApplySettingsProfile(profile);
|
|
});
|
|
}
|
|
|
|
void ApplySettingsProfile(PlayerProfileApiResponse profile)
|
|
{
|
|
if (txtUsername != null)
|
|
txtUsername.text = profile.username ?? "";
|
|
if (txtEmail != null)
|
|
txtEmail.text = profile.email ?? "";
|
|
if (txtId != null)
|
|
txtId.text = profile.player_id.ToString();
|
|
if (txtAge != null)
|
|
txtAge.text = profile.days_since_registration.ToString();
|
|
if (txtMatches != null)
|
|
txtMatches.text = profile.matches_played.ToString();
|
|
if (txtWinRatio != null)
|
|
txtWinRatio.text = (profile.win_ratio * 100f).ToString("0.#") + "%";
|
|
}
|
|
|
|
}
|