602 lines
19 KiB
C#
602 lines
19 KiB
C#
using UnityEngine;
|
|
using DG.Tweening;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEngine.Networking;
|
|
using UnityEngine.UI;
|
|
public class GameOverCanvas : MonoBehaviour
|
|
{
|
|
public bool showOnLoad = false;
|
|
CanvasGroup canvasGroup;
|
|
[Header("Intro items")]
|
|
public RectTransform[] middleScalingItems;
|
|
public RectTransform[] comingFromMiddle;
|
|
public RectTransform[] prizeFrames;
|
|
public RectTransform[] comingDown;
|
|
|
|
Dictionary<RectTransform, Vector3> OriginalPositions;
|
|
Dictionary<RectTransform, Vector3> OriginalScales;
|
|
|
|
[Header("Values")]
|
|
public TMP_Text p1_name;
|
|
public TMP_Text p1_l10;
|
|
public TMP_Text p2_name;
|
|
public TMP_Text p2_l10;
|
|
|
|
public GameObject p1_red,p2_red,p1_blue,p2_blue;
|
|
public Image p1_icon, p2_icon;
|
|
public Sprite redIcon, blueIcon;
|
|
|
|
public RectTransform p1_winner, p2_winner;
|
|
[Header("Game Over Data")]
|
|
public Button btnRematch;
|
|
public Button btnLeave;
|
|
public TMP_Text rematchWarningLoser;
|
|
public TMP_Text txtBetRC;
|
|
public TMP_Text txtRewardRC;
|
|
public TMP_Text txtRewardCC;
|
|
public TMP_Text countdownTxt;
|
|
string returningToMenuText;
|
|
|
|
public float returnToMenuCountdown = 15f;
|
|
|
|
/// <summary>Each player needs at least 2.0 RC (20 coin units) to rematch.</summary>
|
|
const int MinimumRematchRcCoins = 20;
|
|
|
|
[Header("Bet Limit")]
|
|
public TMP_Text txtBetLimitWarning;
|
|
public CanvasGroup betLimitAdjustPanel;
|
|
//minVal: 2, max Val 500, when its 500, show ∞ on the text
|
|
public Slider betLimitSlider;
|
|
public TMP_Text txtBetLimitSliderValue;
|
|
public Button btnBetLimitAdjustAccept;
|
|
public Button btnBetLimitAdjustCancel;
|
|
|
|
const string PersonalBetLimitPrefsKey = "WalkInvest.PersonalBetLimit";
|
|
const int BetLimitMin = 2;
|
|
const int BetLimitMax = 500;
|
|
const int BetLimitUnlimited = 500;
|
|
|
|
[Header("Rematch panel")]
|
|
public CanvasGroup rematchPanel;
|
|
public RectTransform rematchPopup;
|
|
public TMP_Text txtMyRCBalance, txtOpponentRCBalance;
|
|
public TMP_Text txtSelectedBet;
|
|
public Slider betSlider;
|
|
public Button btnConfirmBet;
|
|
public Button btnCancelBet;
|
|
|
|
|
|
public static GameOverCanvas instance;
|
|
|
|
void Awake()
|
|
{
|
|
instance = this;
|
|
canvasGroup = GetComponent<CanvasGroup>();
|
|
Hide();
|
|
|
|
CollectOriginalPositionsAndScales();
|
|
|
|
returningToMenuText = countdownTxt.text;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
if(showOnLoad){
|
|
if(LevelLoadManager.instance == null){ //Load dummy data for testing
|
|
LevelLoadManager.myPlayer = new MatchmadePlayer(){Name = "test p1", l10_wins = 3, l10_losses = 1};
|
|
LevelLoadManager.opponentPlayer = new MatchmadePlayer(){Name = "test p2", l10_wins = 1, l10_losses = 3};
|
|
}
|
|
Show(Team.Red, Team.Red, 3, 1);
|
|
}
|
|
|
|
btnRematch.onClick.AddListener(OnBtnRematchClicked);
|
|
btnLeave.onClick.AddListener(OnBtnLeaveGameClicked);
|
|
|
|
betSlider.onValueChanged.AddListener(OnBetSliderValueChanged);
|
|
|
|
btnConfirmBet.onClick.AddListener(OnBetAccepted);
|
|
btnCancelBet.onClick.AddListener(OnBetCancelled);
|
|
|
|
SetupBetLimitUi();
|
|
}
|
|
|
|
void SetupBetLimitUi()
|
|
{
|
|
if (betLimitSlider != null)
|
|
{
|
|
betLimitSlider.minValue = BetLimitMin;
|
|
betLimitSlider.maxValue = BetLimitMax;
|
|
betLimitSlider.wholeNumbers = true;
|
|
betLimitSlider.onValueChanged.AddListener(OnBetLimitSliderValueChanged);
|
|
}
|
|
|
|
if (btnBetLimitAdjustAccept != null)
|
|
btnBetLimitAdjustAccept.onClick.AddListener(OnBetLimitAdjustAccepted);
|
|
if (btnBetLimitAdjustCancel != null)
|
|
btnBetLimitAdjustCancel.onClick.AddListener(CloseBetLimitAdjuster);
|
|
|
|
var warningButton = txtBetLimitWarning != null
|
|
? txtBetLimitWarning.GetComponentInChildren<Button>()
|
|
: null;
|
|
if (warningButton != null)
|
|
warningButton.onClick.AddListener(OpenBetLimitAdjuster);
|
|
}
|
|
|
|
public static int GetPersonalBetLimit()
|
|
{
|
|
return PlayerPrefs.GetInt(PersonalBetLimitPrefsKey, BetLimitUnlimited);
|
|
}
|
|
|
|
static void SetPersonalBetLimit(int limitCoins)
|
|
{
|
|
limitCoins = Mathf.Clamp(limitCoins, BetLimitMin, BetLimitMax);
|
|
PlayerPrefs.SetInt(PersonalBetLimitPrefsKey, limitCoins);
|
|
PlayerPrefs.Save();
|
|
}
|
|
|
|
static string FormatBetLimitLabel(int limitCoins)
|
|
{
|
|
if (limitCoins >= BetLimitUnlimited)
|
|
return "∞";
|
|
return CoinHelper.FormatString(limitCoins) + " RC";
|
|
}
|
|
|
|
static string FormatBetLimitWarningText(int limitCoins) =>
|
|
"Max Bet : " + FormatBetLimitLabel(limitCoins);
|
|
|
|
void UpdateBetLimitWarningText()
|
|
{
|
|
if (txtBetLimitWarning != null)
|
|
txtBetLimitWarning.text = FormatBetLimitWarningText(GetPersonalBetLimit());
|
|
}
|
|
|
|
void OnBetLimitSliderValueChanged(float value)
|
|
{
|
|
if (txtBetLimitSliderValue != null)
|
|
txtBetLimitSliderValue.text = FormatBetLimitLabel(Mathf.RoundToInt(value));
|
|
}
|
|
|
|
void ApplyBetLimitVisibility()
|
|
{
|
|
bool isLoser = myTeam != winningTeam;
|
|
if (txtBetLimitWarning != null)
|
|
txtBetLimitWarning.gameObject.SetActive(isLoser);
|
|
if (!isLoser)
|
|
return;
|
|
UpdateBetLimitWarningText();
|
|
}
|
|
|
|
public void OpenBetLimitAdjuster()
|
|
{
|
|
if (betLimitAdjustPanel == null)
|
|
return;
|
|
|
|
int limit = GetPersonalBetLimit();
|
|
if (betLimitSlider != null)
|
|
betLimitSlider.SetValueWithoutNotify(limit);
|
|
OnBetLimitSliderValueChanged(limit);
|
|
|
|
betLimitAdjustPanel.DOFade(1, 0.25f);
|
|
betLimitAdjustPanel.blocksRaycasts = true;
|
|
betLimitAdjustPanel.interactable = true;
|
|
}
|
|
|
|
public void CloseBetLimitAdjuster()
|
|
{
|
|
if (betLimitAdjustPanel == null)
|
|
return;
|
|
|
|
betLimitAdjustPanel.DOFade(0, 0.25f);
|
|
betLimitAdjustPanel.blocksRaycasts = false;
|
|
betLimitAdjustPanel.interactable = false;
|
|
}
|
|
|
|
void OnBetLimitAdjustAccepted()
|
|
{
|
|
if (betLimitSlider != null)
|
|
SetPersonalBetLimit(Mathf.RoundToInt(betLimitSlider.value));
|
|
UpdateBetLimitWarningText();
|
|
CloseBetLimitAdjuster();
|
|
}
|
|
|
|
void OnBetAccepted(){
|
|
NetPlayer.localPlayer.AcceptRematch((int)betSlider.value);
|
|
rematchPanel.interactable=false;
|
|
}
|
|
|
|
void OnBetCancelled(){
|
|
NetPlayer.localPlayer.AcceptRematch(0);
|
|
rematchPanel.interactable=false;
|
|
rematchPanel.blocksRaycasts=false;
|
|
rematchPanel.DOFade(0,0.3f).SetEase(Ease.InOutBack);
|
|
}
|
|
|
|
void OnBetSliderValueChanged(float value){
|
|
txtSelectedBet.text = CoinHelper.FormatString((int)value);
|
|
}
|
|
|
|
void OnBtnRematchClicked(){
|
|
if (!BothPlayersHaveMinimumRematchRc())
|
|
return;
|
|
NetPlayer.localPlayer.RequestRematch();
|
|
SetRematchPendingState(true);
|
|
}
|
|
|
|
public void OnRematchRequested(){
|
|
if(winningTeam == myTeam){
|
|
//Only i can initiate the rematch, so here we go
|
|
ShowRematchPanel();
|
|
}else{
|
|
rematchWarningLoser.text = "Waiting for opponent to accept";
|
|
}
|
|
}
|
|
|
|
void SetRematchPendingState(bool val){
|
|
btnRematch.interactable = false;
|
|
btnLeave.interactable = !val;
|
|
if(val){
|
|
StopCoroutine(countdownCoroutine);
|
|
countdownTxt.text = "";
|
|
}else{
|
|
countdownCoroutine = StartCoroutine(CoroutineCountdown());
|
|
}
|
|
}
|
|
|
|
|
|
void OnBtnLeaveGameClicked(){
|
|
LevelLoadManager.instance.Leave();
|
|
}
|
|
|
|
void CollectOriginalPositionsAndScales(){
|
|
OriginalPositions = new Dictionary<RectTransform, Vector3>();
|
|
OriginalScales = new Dictionary<RectTransform, Vector3>();
|
|
foreach (var item in comingFromMiddle)
|
|
{
|
|
OriginalPositions.Add(item, item.position);
|
|
OriginalScales.Add(item, item.localScale);
|
|
}
|
|
foreach (var item in middleScalingItems)
|
|
{
|
|
if(!OriginalPositions.ContainsKey(item)){
|
|
OriginalPositions.Add(item, item.position);
|
|
}
|
|
if(!OriginalScales.ContainsKey(item)){
|
|
OriginalScales.Add(item, item.localScale);
|
|
}
|
|
}
|
|
|
|
foreach (var item in comingDown)
|
|
{
|
|
if(!OriginalPositions.ContainsKey(item)){
|
|
OriginalPositions.Add(item, item.position);
|
|
}
|
|
if(!OriginalScales.ContainsKey(item)){
|
|
OriginalScales.Add(item, item.localScale);
|
|
}
|
|
}
|
|
|
|
foreach (var item in prizeFrames)
|
|
{
|
|
if(!OriginalPositions.ContainsKey(item)){
|
|
OriginalPositions.Add(item, item.position);
|
|
}
|
|
if(!OriginalScales.ContainsKey(item)){
|
|
OriginalScales.Add(item, item.localScale);
|
|
}
|
|
}
|
|
}
|
|
void Hide(){
|
|
canvasGroup.alpha = 0;
|
|
canvasGroup.blocksRaycasts = false;
|
|
canvasGroup.interactable = false;
|
|
|
|
rematchPanel.alpha=0;
|
|
rematchPanel.blocksRaycasts = false;
|
|
rematchPanel.interactable = false;
|
|
|
|
if (betLimitAdjustPanel != null)
|
|
{
|
|
betLimitAdjustPanel.alpha = 0;
|
|
betLimitAdjustPanel.blocksRaycasts = false;
|
|
betLimitAdjustPanel.interactable = false;
|
|
}
|
|
}
|
|
|
|
Team winningTeam;
|
|
Team myTeam;
|
|
public void Setup(Team winningTeam, Team myTeam, int redScore, int blueScore){
|
|
this.winningTeam = winningTeam;
|
|
this.myTeam = myTeam;
|
|
p1_winner.gameObject.SetActive(false);
|
|
p2_winner.gameObject.SetActive(false);
|
|
if(myTeam == Team.Red){
|
|
p1_red.SetActive(true);
|
|
p1_blue.SetActive(false);
|
|
p2_red.SetActive(false);
|
|
p2_blue.SetActive(true);
|
|
|
|
p1_icon.sprite = redIcon;
|
|
p2_icon.sprite = blueIcon;
|
|
}else{
|
|
p1_red.SetActive(false);
|
|
p1_blue.SetActive(true);
|
|
p2_red.SetActive(true);
|
|
p2_blue.SetActive(false);
|
|
|
|
p1_icon.sprite = blueIcon;
|
|
p2_icon.sprite = redIcon;
|
|
}
|
|
|
|
p1_name.text = LevelLoadManager.myPlayer.Name;
|
|
p2_name.text = LevelLoadManager.opponentPlayer.Name;
|
|
p1_l10.text = $"L10 {LevelLoadManager.myPlayer.l10_wins}-{LevelLoadManager.myPlayer.l10_losses}";
|
|
p2_l10.text = $"L10 {LevelLoadManager.opponentPlayer.l10_wins}-{LevelLoadManager.opponentPlayer.l10_losses}";
|
|
|
|
if(myTeam == winningTeam){
|
|
p1_winner.gameObject.SetActive(true);
|
|
p2_winner.gameObject.SetActive(false);
|
|
}else{
|
|
p1_winner.gameObject.SetActive(false);
|
|
p2_winner.gameObject.SetActive(true);
|
|
}
|
|
|
|
ApplyBetLimitVisibility();
|
|
}
|
|
|
|
float rcPrize = 0;
|
|
public void Show(Team winningTeam, Team myTeam, int redScore, int blueScore){
|
|
Setup(winningTeam, myTeam, redScore, blueScore);
|
|
|
|
canvasGroup.blocksRaycasts = true;
|
|
canvasGroup.interactable = true;
|
|
|
|
foreach (var item in middleScalingItems)
|
|
{
|
|
item.localScale = new Vector3(0, item.localScale.y, item.localScale.z);
|
|
}
|
|
foreach (var item in comingFromMiddle)
|
|
{
|
|
item.position = new Vector3(Screen.width/2f,OriginalPositions[item].y);
|
|
item.localScale = new Vector3(0, OriginalScales[item].y, OriginalScales[item].z);
|
|
}
|
|
foreach (var item in comingDown)
|
|
{
|
|
item.position = new Vector3(OriginalPositions[item].x, 0.3f);
|
|
item.localScale = new Vector3(OriginalScales[item].x, 0, OriginalScales[item].z);
|
|
}
|
|
|
|
foreach (var item in prizeFrames)
|
|
{
|
|
item.localScale = new Vector3(0, 0, 0);
|
|
}
|
|
|
|
if(winningTeam == myTeam){
|
|
rcPrize = CoinHelper.Format(GameManager.MatchRcPrizeCoins);
|
|
}
|
|
|
|
UpdateRematchAvailability();
|
|
|
|
StartCoroutine(CoroutineShow());
|
|
|
|
StartCoroutine(CoroutineFetchAndUpdateBalances());
|
|
}
|
|
|
|
IEnumerator CoroutineShow(){
|
|
float fadeInTime = 0.5f;
|
|
float scaleTime = 0.2f;
|
|
float moveTime = 0.3f;
|
|
canvasGroup.DOFade(1, fadeInTime).SetEase(Ease.InOutBack);
|
|
yield return new WaitForSeconds(fadeInTime);
|
|
|
|
foreach (var item in middleScalingItems)
|
|
{
|
|
item.DOScale(OriginalScales[item], scaleTime).SetEase(Ease.InOutBack);
|
|
}
|
|
|
|
yield return new WaitForSeconds(scaleTime * 0.5f);
|
|
foreach (var item in comingFromMiddle)
|
|
{
|
|
item.DOMove(OriginalPositions[item], moveTime).SetEase(Ease.InOutBack);
|
|
item.DOScale(OriginalScales[item], scaleTime).SetEase(Ease.InOutBack);
|
|
}
|
|
|
|
yield return new WaitForSeconds(scaleTime * 0.5f);
|
|
|
|
foreach (var item in prizeFrames)
|
|
{
|
|
item.DOScale(Vector3.one, scaleTime).SetEase(Ease.InOutBack);
|
|
}
|
|
|
|
yield return new WaitForSeconds(scaleTime * 0.5f);
|
|
|
|
//Rewards
|
|
StartCoroutine(CoroutineSetTextNumber(rcPrize, txtRewardRC, 10, "N1", "+", " RC"));
|
|
StartCoroutine(CoroutineSetTextNumber(100, txtRewardCC, 100, "N0", "+", " CC"));
|
|
|
|
txtBetRC.text = CoinHelper.FormatString(GameManager.MatchRcPrizeCoins) + " RC";
|
|
|
|
yield return new WaitForSeconds(1f);
|
|
|
|
foreach (var item in comingDown)
|
|
{
|
|
item.DOMove(OriginalPositions[item], 0.3f).SetEase(Ease.InOutBack);
|
|
item.DOScale(OriginalScales[item], 0.3f).SetEase(Ease.InOutBack);
|
|
}
|
|
|
|
|
|
|
|
countdownCoroutine = StartCoroutine(CoroutineCountdown());
|
|
}
|
|
Coroutine countdownCoroutine;
|
|
|
|
IEnumerator CoroutineSetTextNumber(float number, TMP_Text text, float speed = 100f, string formatting = "N0", string prefix = "", string suffix = ""){
|
|
float t=0;
|
|
while(t < number){
|
|
t+=Time.deltaTime*speed;
|
|
text.text = prefix + t.ToString(formatting) + suffix;
|
|
yield return null;
|
|
}
|
|
text.text = prefix + number.ToString(formatting) + suffix;
|
|
}
|
|
|
|
|
|
IEnumerator CoroutineCountdown(){
|
|
TextColorFlash textColorFlash = countdownTxt.GetComponent<TextColorFlash>();
|
|
while(returnToMenuCountdown > 0){
|
|
returnToMenuCountdown--;
|
|
countdownTxt.text = returningToMenuText.Replace("{t}", returnToMenuCountdown.ToString("N0"));
|
|
if(returnToMenuCountdown < 5){
|
|
textColorFlash.duration = 5;
|
|
}
|
|
yield return new WaitForSecondsRealtime(1f);
|
|
}
|
|
|
|
|
|
LevelLoadManager.instance.Leave();
|
|
}
|
|
|
|
|
|
public void ShowRematchPanel(){
|
|
SetRematchPendingState(true);
|
|
StartCoroutine(CoroutineShowRematchPanel());
|
|
|
|
betSlider.maxValue = (LevelLoadManager.myPlayer.rc < LevelLoadManager.opponentPlayer.rc) ? LevelLoadManager.myPlayer.rc : LevelLoadManager.opponentPlayer.rc;
|
|
betSlider.value = betSlider.maxValue / 2;
|
|
betSlider.minValue = Mathf.Clamp(betSlider.maxValue /10f,5,10000);
|
|
}
|
|
|
|
IEnumerator CoroutineShowRematchPanel(){
|
|
rematchPopup.localScale = new Vector3(0, 0, 0);
|
|
rematchPanel.blocksRaycasts = true;
|
|
rematchPanel.interactable = true;
|
|
rematchPanel.DOFade(1, 0.3f).SetEase(Ease.InOutBack);
|
|
yield return new WaitForSeconds(0.1f);
|
|
|
|
rematchPopup.DOScale(1, 0.2f).SetEase(Ease.OutBack);
|
|
yield return new WaitForSeconds(0.2f);
|
|
}
|
|
|
|
|
|
public void OnRematchCancelled(){
|
|
btnRematch.interactable=false;
|
|
btnLeave.interactable=true;
|
|
|
|
rematchWarningLoser.text = "Rematch declined.";
|
|
StartCoroutine(CoroutineHideRematchPanel());
|
|
|
|
countdownCoroutine = StartCoroutine(CoroutineCountdown());
|
|
}
|
|
|
|
IEnumerator CoroutineHideRematchPanel(){
|
|
rematchPopup.DOScale(0, 0.2f).SetEase(Ease.InBack);
|
|
yield return new WaitForSeconds(0.2f);
|
|
rematchPanel.DOFade(0, 0.3f).SetEase(Ease.InOutBack);
|
|
yield return new WaitForSeconds(0.3f);
|
|
}
|
|
|
|
IEnumerator CoroutineFetchAndUpdateBalances()
|
|
{
|
|
var my = LevelLoadManager.myPlayer;
|
|
var opp = LevelLoadManager.opponentPlayer;
|
|
|
|
string baseUrl = (GameManager.DedicatedInternalApiBase ?? "").TrimEnd('/');
|
|
if (string.IsNullOrEmpty(baseUrl) || my == null || opp == null)
|
|
{
|
|
ApplyRcBalancesToUi(null);
|
|
yield break;
|
|
}
|
|
|
|
if (my.UserId > 0)
|
|
yield return FetchPlayerRcAndApply(baseUrl, my);
|
|
if (opp.UserId > 0 && opp.UserId != my.UserId)
|
|
yield return FetchPlayerRcAndApply(baseUrl, opp);
|
|
|
|
ApplyRcBalancesToUi(null);
|
|
}
|
|
|
|
void ApplyRcBalancesToUi(string loadingPlaceholder)
|
|
{
|
|
var my = LevelLoadManager.myPlayer;
|
|
var opp = LevelLoadManager.opponentPlayer;
|
|
string myText = loadingPlaceholder ?? (my != null ? CoinHelper.FormatString((int)my.rc) : "0.0 RC");
|
|
string oppText = loadingPlaceholder ?? (opp != null ? CoinHelper.FormatString((int)opp.rc) : "0.0 RC");
|
|
|
|
if (txtMyRCBalance != null)
|
|
txtMyRCBalance.text = myText;
|
|
if (txtOpponentRCBalance != null)
|
|
txtOpponentRCBalance.text = oppText;
|
|
|
|
if (loadingPlaceholder == null)
|
|
UpdateRematchAvailability();
|
|
}
|
|
|
|
static int GetRcCoins(MatchmadePlayer player) =>
|
|
player == null ? 0 : Mathf.Max(0, Mathf.FloorToInt(player.rc));
|
|
|
|
bool BothPlayersHaveMinimumRematchRc()
|
|
{
|
|
return GetRcCoins(LevelLoadManager.myPlayer) >= MinimumRematchRcCoins
|
|
&& GetRcCoins(LevelLoadManager.opponentPlayer) >= MinimumRematchRcCoins;
|
|
}
|
|
|
|
void UpdateRematchAvailability()
|
|
{
|
|
if (winningTeam == myTeam)
|
|
{
|
|
btnRematch.interactable = false;
|
|
if (rematchWarningLoser != null)
|
|
rematchWarningLoser.text = "Only the loser can request a rematch";
|
|
return;
|
|
}
|
|
|
|
if (!BothPlayersHaveMinimumRematchRc())
|
|
{
|
|
btnRematch.interactable = false;
|
|
if (rematchWarningLoser != null)
|
|
rematchWarningLoser.text = "Not enough RC";
|
|
return;
|
|
}
|
|
|
|
btnRematch.interactable = true;
|
|
if (rematchWarningLoser != null)
|
|
rematchWarningLoser.text = "";
|
|
}
|
|
|
|
IEnumerator FetchPlayerRcAndApply(string baseUrl, MatchmadePlayer player)
|
|
{
|
|
string url = $"{baseUrl}/players/{player.UserId}/rc";
|
|
using (var req = UnityWebRequest.Get(url))
|
|
{
|
|
yield return req.SendWebRequest();
|
|
|
|
if (req.responseCode != 200)
|
|
{
|
|
Logger.Log($"Player RC fetch HTTP {(int)req.responseCode}: {req.error} {url}");
|
|
yield break;
|
|
}
|
|
|
|
string text = req.downloadHandler != null ? req.downloadHandler.text : "";
|
|
if (string.IsNullOrEmpty(text))
|
|
yield break;
|
|
|
|
var resp = JsonUtility.FromJson<PlayerRcApiResponse>(text);
|
|
if (resp != null && resp.ok)
|
|
player.rc = resp.rc;
|
|
else if (resp != null && !string.IsNullOrEmpty(resp.error))
|
|
Logger.Log($"Player RC fetch: {resp.error} ({url})");
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
class PlayerRcApiResponse
|
|
{
|
|
public bool ok;
|
|
public int player_id;
|
|
public float rc;
|
|
public string error;
|
|
}
|
|
}
|