How synchronizate my Timer using Photon?

Hello all!

I made simple Timer script but I want use it in my multiplayer FPS game. So I need synchronize Timer to all players see same time. Can you please help me?

There is my Timer script:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
 
public class Timer : MonoBehaviour
{
    public int timeLeft = 5;
    public Text countdownText;
 
    void Start()
    {
        StartCoroutine("LoseTime");
    }
 
    void Update()
    {
        countdownText.text = ("Time Left = " + timeLeft);
 
        if (timeLeft <= 0)
        {
            StopCoroutine("LoseTime");
            countdownText.text = "Times Up!";
        }
    }
 
    IEnumerator LoseTime()
    {
        while (true)
        {
            yield return new WaitForSeconds(1);
            timeLeft--;
        }
    }
}

Simplest Way to Implement Timer on Multiplayer Game Using Photon.
Apply this Script on the UI with Timer

bool startTimer = false;
double timerIncrementValue;
double startTime;
[SerializeField] double timer = 20;
ExitGames.Client.Photon.Hashtable CustomeValue;

void Start()
    {
        if (PhotonNetwork.player.IsMasterClient)
        {
            CustomeValue = new ExitGames.Client.Photon.Hashtable();
            startTime = PhotonNetwork.time;
            startTimer = true;
            CustomeValue.Add("StartTime", startTime);
            PhotonNetwork.room.SetCustomProperties(CustomeValue);
        }
        else
        {
            startTime = double.Parse(PhotonNetwork.room.CustomProperties["StartTime"].ToString());
            startTimer = true;
        }
    }

void Update()
    {

        if (!startTimer) return;

        timerIncrementValue = PhotonNetwork.time - startTime;

        if (timerIncrementValue >= timer)
        {
           //Timer Completed
           //Do What Ever You What to Do Here
        }
    }

Please Comment if you are facing any Issue.
Thanks.
@juraj123

Hi,

you can use PhotonNetwork.time to create a synchronized timer. When the game begins you can add this value as a Custom Room Property and let each client calculate the timer on their own. Therefore the MasterClient can set this value by using the following code - or similar:

Hashtable ht = new Hashtable {{"StartTime", PhotonNetwork.time}};
PhotonNetwork.room.SetCustomProperties(ht);

You now have to implement a callback called OnPhotonCustomRoomPropertiesChanged. This might look like the following:

public void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged)
{
    object propsTime;
    if (propertiesThatChanged.TryGetValue("StartTime", out propsTime))
    {
        startTime = (double) propsTime;
    }
}

The variable ‘startTime’ is a local variable in my example, ‘gameStarted’ is a bool that describes what its name says - obviously. Having this value each client can calculate a timer on their own by using the following:

public void Update()
{
    if (!gameStarted)
    {
        return;
    }

    // Example for a increasing timer
    incTimer = PhotonNetwork.time - startTime;

    // Example for a decreasing timer
    double roundTime = 300.0;
    decTimer = roundTime - incTimer;
}

My Timer script:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
 
public class Timer : MonoBehaviour
{
    public int timeLeft = 5;
    public Text countdownText;
 
    // Use this for initialization
    void Start()
    {
        StartCoroutine("LoseTime");
    }
 
    // Update is called once per frame
    void Update()
    {
        countdownText.text = ("Time Left = " + timeLeft);
 
        if (timeLeft <= 0)
        {
            StopCoroutine("LoseTime");
            countdownText.text = "Times Up!";
        }
    }
 
    IEnumerator LoseTime()
    {
        while (true)
        {
            yield return new WaitForSeconds(1);
            timeLeft--;
        }
    }
}
[SerializeField] private int _timeLeft;
[SerializeField] private TextMeshPro _countdownText;
private PhotonView _pView;
[HideInInspector] public bool IsTimeFinished = true; 

void Awake()
{      
    _pView = GetComponent<PhotonView>();
}

void Start()
{
    StartCountDown();    
}

public void StartCountDown()
{
    if (PhotonNetwork.IsMasterClient) //butona basılırsa
    {
        IsTimeFinished = false;
        StartCoroutine("LoseTime");
        _countdownText.text = ("Time Left = " + _timeLeft);  
    }
}
  
IEnumerator LoseTime()
{
    while (true)
    {
        yield return new WaitForSeconds(1);
        _pView.RPC("ReduceTime" , RpcTarget.AllBuffered);
    }
}

[PunRPC]
private void ReduceTime()
{
    _timeLeft--;
    _countdownText.text = ("Time Left = " + _timeLeft);
    if (_timeLeft <= 0)
    {
        StopCoroutine("LoseTime");
        _countdownText.text = "Times Up!";
        TimesUp();
    }
}

public void TimesUp()
{
    IsTimeFinished = true;
}