The trick you always run into with Unity, is that the only context under which your code runs is during script callbacks.
This basically means that eventually somewhere, you must have a GameObject in a scene with a MonoBehaviour attached to said object that calls the code you want to run repeatedly.
Aside from the fact that there is no StartCoroutine available other than in the instance of a class inheriting from MonoBehaviour, you have the problem that you need to have code execute every frame or so to check on something. There's no real way around this other than by making a MonoBehaviour, just embrace it.
A common pattern is to create a singleton-esque GameObject that either has DontDestroyOnLoad called on it, or is recreated as needed for each scene. You could even designate one object as a "coroutine bucket" that isn't tied to a specific class or anything. Literally an empty MonoBehaviour whose sole purpose in life is to start coroutines.
You can quickly solve this problem by making your Server class a MonoBehaviour:
And then by adding a singleton property:
private static Server ServerObject {
get {
if (_serverObject == null) {
var gameObj = new GameObject("Server Object");
_serverObject = gameObj.AddComponent<Server>();
GameObject.DontDestroyOnLoad(_serverObject); // Optional
}
return _serverObject;
}
}
private static Server _serverObject;
(Singletons are gross, but it's a necessary evil in this circumstance)
And then by changing all your StartCoroutine
calls to be called on the singleton MonoBehaviour instance:
public static void DeviceSeen(DeviceSeenCallback callBack) {
this.ServerObject.StartCoroutine(DoDeviceSeen(callBack));
}
GoKit uses this pattern and makes a single GameObject named "Go" that processes all the logic for tweens. Since Unity doesn't provide a way to specify scripts that run regularly without being attached to a game object, this is the best we can do.
If your Server class would maintain a lot of state, or it's not essential that it remain part of th escene, it may be advisable that you don't call DontDestroyOnLoad
on it. If the scene changes and the ServerObject game object is deleted, subsequent checks to _serverObject will come up as null and thus be reinstantiated (since Unity overloads the null conversion operator).