using System.Collections; using System.Collections.Generic; using UnityEngine; using Mirror; using TMPro; using UnityEngine.SceneManagement; public class NetGameManager : NetworkBehaviour { public const int WAITING_TIME = 120; public static NetGameManager instance; public TMP_Text statusText; public TMP_Text scoreText_me; public TMP_Text scoreText_enemy; public GameOverScreen gameOverScreen; public bool gameStarted = false; float waitingTimer = WAITING_TIME; public PlayerType winner = PlayerType.Client; public bool gameOver = false; [Header("MP")] public GameObject fruitPrefab; public List spawnedFruits = new List(); public int maxFruits = 10; public float fruitSpawnInterval = 5f; void Awake() { instance = this; } void Start() { Application.targetFrameRate = 60; } public void UpdateScore(bool isLocalPlayer, int score){ if(isLocalPlayer){ scoreText_me.text = score.ToString(); }else{ scoreText_enemy.text = score.ToString(); } } public bool playerSpawned = false; // Update is called once per frame void Update() { if(!isServer) return; SnakeController[] players = FindObjectsOfType(); if(!gameStarted){ if(players.Length >1){ gameStarted = true; RpcSetGameStarted(true); StartCoroutine(StartGame()); }else{ if(players.Length == 1){ if(waitingTimer >0){ waitingTimer -= Time.deltaTime; SetStatusText("Waiting for another player...\nRemaining time: " + waitingTimer.ToString("F0") + " seconds"); }else{ SetStatusText("Opponent abandoned the game"); GameOver(players[0].playerType); } } } }else{ if(players.Length == 1){ if(playerSpawned){ SetStatusText("Opponent left the game"); GameOver(players[0].playerType); }else{ gameStarted = false; SetStatusText("Waiting for another player..."); } } ManageAndPopulateFruits(); } } [ClientRpc] void RpcSetGameStarted(bool started){ gameStarted = started; } void ManageAndPopulateFruits(){ if(spawnedFruits.Count < maxFruits){ SpawnFruit(); } } void SpawnFruit(){ GameObject fruit = Instantiate(fruitPrefab, GetRandomPoint(), Quaternion.identity); NetworkServer.Spawn(fruit); spawnedFruits.Add(fruit); } public void DestroyFruit(Vector2 position){ int index = -1; for(int i=0; i < spawnedFruits.Count; i++){ if(spawnedFruits[i].transform.position == (Vector3)position){ index = i; break; } } if(index != -1){ NetworkServer.Destroy(spawnedFruits[index]); spawnedFruits.RemoveAt(index); } } Vector2 GetRandomPoint(){ SnakeController p = FindObjectOfType(); float x = p.transform.position.x - (int)(UnityEngine.Random.Range(-p.fieldSize.x/2f, p.fieldSize.x/2f)); float y = p.transform.position.y - (int)(UnityEngine.Random.Range(-p.fieldSize.y/2f, p.fieldSize.y/2f)); return new Vector2(x, y); } public IEnumerator StartGame(){ int counter = 10; SnakeController[] players = FindObjectsOfType(); while(counter > 0){ players = FindObjectsOfType(); if(players.Length <= 1){ yield break; } SetStatusText("Game starts in " + counter); yield return new WaitForSeconds(1f); counter--; } SetStatusText("Game Started"); foreach (SnakeController player in players) { player.StartGame(); } playerSpawned = true; yield return new WaitForSeconds(1f); SetStatusText(""); } void SetStatusText(string text){ if(!isServer){return;} statusText.text = text; RpcSetStatusText(text); } [ClientRpc] void RpcSetStatusText(string text){ statusText.text = text; } public void GameOver(SnakeController player){ winner = player.playerType; GameOver(winner); } public void GameOver(PlayerType winner){ if(gameOver){return;} SetStatusText($"Player {(winner == PlayerType.Master ? "1" : "2")} wins!"); Debug.Log("Game Over " + winner); gameOver = true; string winnerKey = winner == PlayerType.Master ? "master" : "client"; StartCoroutine(CoroutineGameOver(winnerKey)); RpcGameOver(winnerKey); } [ClientRpc] void RpcGameOver(string winnerKey){ bool won = (winnerKey == "master" && GameData.isMaster) || (winnerKey == "client" && !GameData.isMaster); gameOverScreen.Show(won); Debug.Log("Game Over " + winnerKey); } IEnumerator CoroutineGameOver(string winnerKey){ string winnerPubkey = winnerKey == "master" ? GameData.betData.owner : GameData.betData.joiner; string winnerId = winnerKey == "master" ? GameData.betData.owner_id : GameData.betData.joiner_id; int masterScore=0, clientScore =0; Dictionary data = new Dictionary(){ {"gameAddress", GameData.address}, {"winnerPublicKey", winnerPubkey}, {"winnerUsername", winnerId}, {"wager", (GameData.betData.wager * 1e8).ToString()}, {"game_id", GameData.betData.id.ToString()}, {"loserUsername", winnerKey == "master" ? GameData.betData.joiner_id : GameData.betData.owner_id}, {"masterScore", masterScore.ToString()}, {"clientScore", clientScore.ToString()}, {"masterId", GameData.betData.owner_id}, {"clientId", GameData.betData.joiner_id} }; string queryString = "?"; foreach(KeyValuePair entry in data) { queryString += entry.Key + "=" + WWW.EscapeURL(entry.Value) + "&"; } queryString = queryString.TrimEnd('&'); string validator_url = GameData.isDev ? Constants.VALIDATOR_URL_DEV : Constants.VALIDATOR_URL_PROD; string url = validator_url + "finalize" + queryString; Debug.Log("Finalizing game on " + url); WWW www = new WWW(url); yield return www; if(www.error == null){ RpcProcessed(); } Debug.Log("Processed game, quitting in 10 seconds..."); yield return new WaitForSeconds(10f); Application.Quit(); } [ClientRpc] void RpcProcessed(){ gameOverScreen.Processed(); } }