- Home /
Independent countdown on server-side
Hello I'm trying to make an independent countdown on a server-side. Basically when a host creates the game and logs in the countdown begins, it starts only on his side but "counter" can be seen by all clients. How can I accomplish that? I want authoritative countdown to happen only on server side but when it reaches 0, something happens to all the clients. I was messing around with Coroutines but everytime client logs in it creates his own countdown coroutine. Cheers!
Are you using the Network$$anonymous$$anager or NetworkLobby$$anonymous$$anager class? How do you start the host?
Yes, I'm using Network$$anonymous$$anager and probably I'm going to use Lobby$$anonymous$$anager as well. How do I start the host? With HUD? ^^" I think I don't understand what u mean :(
Answer by phineliner · Dec 09, 2015 at 08:04 PM
As you seem to use the default NetworkManager Component, I suggest you to write your own NetworkManager Component, which derives from NetworkManager. NetworkManager provides many callbacks, that can be overriden and used (so do NetworkBehaviours, too). See also http://docs.unity3d.com/Manual/UNetManager.html the "Customization" Section or http://docs.unity3d.com/ScriptReference/Networking.NetworkManager.html for a full list.
E.g. you can override the "OnStartServer" to begin countdown on server site. Everytime you count down, you notify all the clients by ClientRpc.
Edit:
As you stated you don't want to use a playerObject for this, you need to spawn a NetworkBehaviour Object manually. You can do this by calling NetworkServer.Spawn(gameobject) on the server, which spawns the respective object on all connected clients. To make this work, your NetworkManager needs a prefab of that gameobject in its list of SpawnAble Prefabs (see inspector).
Example:
public class MyNetworkManager : NetworkManager {
public const int COUNTDOWN_TIME = 5;
//this should be registered as spawnable prefab in your networkmanager inspector
//and also should have the MyNetworkScript-Component attached
[SerializeField] GameObject myNetworkScriptPrefab;
private MyNetworkScript scriptInstance;
//this is executed on the server when it (or host) is started.
public override OnStartServer()
{
//instantiate prefab on server / host
GameObject myNetworkScriptObject = Instantiate(myNetworkScriptPrefab);
scriptInstance = myNetworkScriptObject.GetComponent<MyNetworkScript>();
//this causes to instantiate the same object on the connected clients
NetworkServer.Spawn(myNetworkScriptObject );
//start countdown coroutine. Here might occur a race condition, if the object is not finished
//spawning on client yet. you have to experiment with that.
StartCoroutine(CountdownRoutine());
}
//this will also run on the server, since a server site method starts the routine
//you could also put the [Server] tag here, which throws a warning if client calls it
public IEnumerator CountdownRoutine()
{
float remainingTime = COUNTDOWN_TIME;
int currentCountDown = COUNTDOWN_TIME;
while (currentCountDown > 0)
{
yield return null;
//to avoid flooding the network, we only inform clients when change
//the number of plain seconds
int newFloorTime = Mathf.FloorToInt(remainingTime);
if (newFloorTime != currentCountDown)
{
currentCountDown = newFloorTime;
//notify clients about the changed countdown value
scriptInstance.RpcUpdateCountdown(currentCountDown);
}
remainingTime -= Time.deltaTime;
}
//do something after coundown finished, e.g. change scene
ServerChangeScene(onlineScene);
//or call another Rpc which informs the clients about countdown finished
}
}
public class MyNetworkScript : NetworkBehaviour
{
//this will be called on the respective clients to do something with the given countdown value.
//Note: [ClientRpc] can only be called in NetworkBehaviours. Thus, you need a reference
//to a NetworkBehaviour object, which provides this rpc method.
[ClientRpc]
public void RpcUpdateCountdown(int countdown)
{
//Display countdown or do something with the value
//If you use a UI.Text or something here, be sure to have it referenced by the client.
//therefore you could override OnClientStart for example
}
}
Edit:
I didn't test the code. Mistakes / Race conditions might occur, but you should get the idea.
What about that RpcUpdateCountdown? I mean what about it's scope, you write that it must be on a client owned networkscript so how can I call it inside Network$$anonymous$$anager?
Oh sorry, I confused it with the [Command] tag, where clients send commands to server side. those must be in client owned networkscripts (like the script attached to your player prefab of the networkmanager). However, ClientRpc should work just fine from within the $$anonymous$$yNetwork$$anonymous$$anager. I updated my answer. Did you try it?
Sorry I haven't tried it yet, I will do it today when I come back home :) Anyway I was just curious how can I call the script outside the Network$$anonymous$$anager without referencing to it :P Anyway it looks good so I think it will work without troubles, I will accept the answer when I get it tested and let you know. Cheers!
So maybe more detailed question from me. How can I reference all clients from this script for example? Like I got an non-player object and I want it to target every single connected player? Should I store them somehow when they log in or is there any method to do that?
Sorry that it took so long but I tested it today, I changed it a little bit for testing but the most important part is that I get the idea and it works as I wanted! :) Thanks a lot!
Your answer
Follow this Question
Related Questions
UI Canvas only showing up on server. 1 Answer
Question about RPC's and Unity 1 Answer
Unity networking tutorial? 6 Answers
How can I use NetworkServer.connections? 0 Answers
Authoritative server strategy 0 Answers