using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using ExitGames.Client.Photon; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviourPunCallbacks, IOnEventCallback { const int START_WAIT_TIME = 10; const byte GAME_START_CODE = 1; const byte GAME_OVER_CODE = 2; DateTime startedTime = DateTime.UnixEpoch; public bool gameStarted => startedTime != DateTime.UnixEpoch; RaiseEventOptions raiseEventOptions = new RaiseEventOptions { Receivers = ReceiverGroup.All }; public SnakeController p1; public SnakeController p2; public GameObject wonScreen; public GameObject lostScreen; public TMP_Text mp_status_txt; public TMP_Text scoreTxtYou,scoreTxtEnemy; public GameObject fruitPrefab; public List spawnedFruits = new List(); public int maxFruits = 10; public float fruitSpawnInterval = 5f; float fruitSpawnTimer = 0; void Awake(){ p1.gameObject.SetActive(false); p2.gameObject.SetActive(false); } void Start() { scoreTxtEnemy.text = scoreTxtYou.text = "-"; if(!PhotonNetwork.IsConnectedAndReady){ SceneManager.LoadScene(0); } spawnedFruits= new List(); } float startTimer = START_WAIT_TIME; void Update() { if (!gameStarted) { if(Input.GetKeyDown(KeyCode.P)){ StartGame(); } WaitForGameStart(); return; } TimeSpan timeSince = DateTime.Now - startedTime; mp_status_txt.text = timeSince.Minutes + ":" + timeSince.Seconds.ToString("00"); UpdateScores(); if (PhotonNetwork.IsMasterClient) { p1.gameObject.SetActive(true); p2.gameObject.SetActive(false); SpawnFruits(); } else { p1.gameObject.SetActive(false); p2.gameObject.SetActive(true); } } void UpdateScores(){ scoreTxtYou.text = getPlayerScore(PhotonNetwork.LocalPlayer).ToString(); scoreTxtEnemy.text = getPlayerScore(PhotonNetwork.PlayerListOthers.FirstOrDefault()).ToString(); } void SpawnFruits(){ if(spawnedFruits.Count > maxFruits){return;} if(spawnedFruits.Count <4){ //spawn 2 }else{ if(fruitSpawnTimer >0){ fruitSpawnTimer-=Time.deltaTime; return; } } fruitSpawnTimer = fruitSpawnInterval; spawnedFruits.Add(PhotonNetwork.Instantiate(fruitPrefab.name, GetRandomPoint(),Quaternion.identity)); } void WaitForGameStart() { if (PhotonNetwork.CurrentRoom.PlayerCount >= 2) { if (startTimer > 0) { startTimer -= Time.deltaTime; mp_status_txt.text = $"Starting game in {startTimer.ToString("n0")} Seconds"; } else { if (PhotonNetwork.IsMasterClient) { StartGame(); } } } else { startTimer = START_WAIT_TIME; mp_status_txt.text = "Waiting for an opponent"; } } int getPlayerScore(Player p){ return p.CustomProperties.ContainsKey("score") ? (int)p.CustomProperties["score"] : 0; } Vector2 GetRandomPoint(){ SnakeController p = (p1.gameObject.activeSelf) ? p1 : p2; 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); } void StartGame(){ Debug.Log("Sending Raise Event"); PhotonNetwork.RaiseEvent(GAME_START_CODE, 1, raiseEventOptions, SendOptions.SendReliable); startedTime = DateTime.Now; } public void DestroyFruit(Vector2 position){ if(PhotonNetwork.IsMasterClient){ destroyFruit(position); }else{ photonView.RPC("RpcDestroyFruit", RpcTarget.All, position); } } [PunRPC] void RpcDestroyFruit(Vector2 position){ if(PhotonNetwork.IsMasterClient){ destroyFruit(position); } } void destroyFruit(Vector2 position){ // Fruit[] fruits = FindObjectsOfType(); foreach(GameObject fruit in spawnedFruits){ if((Vector2)fruit.transform.position == position){ spawnedFruits.Remove(fruit); PhotonNetwork.Destroy(fruit.gameObject); break; } } } public void OnGameOver(){ PhotonNetwork.RaiseEvent(GAME_OVER_CODE, PhotonNetwork.IsMasterClient ? 0 : 1, raiseEventOptions, SendOptions.SendReliable); } bool gameOver = false; int winnerId = -1; public void OnEvent(EventData photonEvent) { if (photonEvent.Code == GAME_START_CODE) { Debug.Log("Game Started"); startedTime = DateTime.Now; }else if(photonEvent.Code == GAME_OVER_CODE){ Debug.Log("Game Over"); gameOver = true; winnerId = (int)photonEvent.CustomData; if(PhotonNetwork.IsMasterClient){ wonScreen.SetActive(winnerId== 0); lostScreen.SetActive(winnerId != 0); }else{ wonScreen.SetActive(winnerId != 0); lostScreen.SetActive(winnerId== 0); } StartCoroutine(SubmitGameData()); } } public IEnumerator SubmitGameData() { // Create the leaderboard object Leaderboard leaderboard = new Leaderboard { master = scoreTxtYou.text, client = scoreTxtEnemy.text }; // Create the submission object Submission submission = new Submission { gameAddress = GameData.address, playerType = PhotonNetwork.IsMasterClient ? "master" : "client", username = GameData.user_id, winner = gameOver ? (winnerId == 0 ? "master" : "client") : "", leaderboard = leaderboard, score = getPlayerScore(PhotonNetwork.LocalPlayer), game_id = "snakes", publicKey= GameData.pubkey, wager = GameData.wager }; // Convert submission to JSON string json = JsonUtility.ToJson(submission); byte[] jsonData = Encoding.UTF8.GetBytes(json); // Send request to the server using (UnityWebRequest request = new UnityWebRequest($"{Constants.VALIDATOR_URL}submit", "POST")) { request.uploadHandler = new UploadHandlerRaw(jsonData); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); yield return request.SendWebRequest(); #if UNITY_2020_1_OR_NEWER if (request.result == UnityWebRequest.Result.Success) #else if (!request.isNetworkError && !request.isHttpError) #endif { // Debug.Log("Submission successful"); // Debug.Log("Response: " + request.downloadHandler.text); } else { Debug.Log("Error submitting game data:"); Debug.Log(request.error); } } } public IEnumerator SubmitRefundReq() { // Send request to the server using (UnityWebRequest request = new UnityWebRequest($"{Constants.VALIDATOR_URL}requestRefund?gameAddress=" + GameData.address, "GET")) { request.SetRequestHeader("Content-Type", "application/json"); yield return request.SendWebRequest(); #if UNITY_2020_1_OR_NEWER if (request.result == UnityWebRequest.Result.Success) #else if (!request.isNetworkError && !request.isHttpError) #endif { Debug.Log("Refund request submitted successfully"); JSBridge.instance.OnClose(-1); } else { Debug.Log("Error submitting refund request:"); Debug.Log(request.error); } } } }