Photon Server + Plugins + PUN
Options
StarKist
✭
Hi there,
I'm currently using PUN for my game, which is limiting to my case since I want to be able to have dozens/hunderds of players in the same world (MMoish)..
Atm I limit the number of players per room to 10. Also cheating is relatively simple since the authority is at best a master client.
My question is, can I use Photon Server + Plugins + PUN to run an a server that hosts hundreds of players? Or do the plugins stuff with the callbacks on the server work on for room based stuff?
Thanks ahead,
Michael.
I'm currently using PUN for my game, which is limiting to my case since I want to be able to have dozens/hunderds of players in the same world (MMoish)..
Atm I limit the number of players per room to 10. Also cheating is relatively simple since the authority is at best a master client.
My question is, can I use Photon Server + Plugins + PUN to run an a server that hosts hundreds of players? Or do the plugins stuff with the callbacks on the server work on for room based stuff?
Thanks ahead,
Michael.
0
Comments
-
@StarKist yes, that is what I'm saying, but do not forget about interest management otherwise your clients will be overwhelmed by the number of messages
And one more note, there is no support for this in default implementation, you have to intercept messages and rebroadcast them your self
best,
ilya0 -
@chvetsov I see, nice, yes I'm aware of interest management...
I saw something about intercepting RPCs from PUN using Photon Server by implementing custom decoding of RaiseEvent on the server side..
Any idea how hard it would be to convert from PUN where the master client is the authority to having the master server intercept RPCs and Call RPCs on the clients instead?
Instead of implementing a completely custom protocol from scratch?
Thanks for the info,
Michael.0 -
@chvetsov Bumping this with a new question:
If I want to control bots on the server, is it a good idea to use a Timer:
timer = PluginHost.CreateTimer(
ScheduledEvent,
1000,
2000);
To implement the bots behavior? for example let the Timer run 30 times a second or so?
looping through the bots and have them broadcast updates to the recipients according to the interest management?
Another option is to run a headless unity client along the server that will control the bots, that will make a lot of things easier, however, I wonder how much worse would the performance be in relation to running is purely on photon server..
Thanks,
Michael.
0 -
In general, you may go in either way. Timers and Unity Host will work because you want just one world per GS. The current version of self-hosted unity takes a lot of resources, but they are going to make it better.
With timers, I would probably use a slightly different way. I would create the timer at the end of logic. Timers are calling your method slightly irregular plus your logic also may take different time. You may take all this into account and schedule timer to a shorter time, for instance. So that calculation will be more smooth.
Check what does better suit your needs
best,
ilya0 -
Hmm so creating a timer 30 times a second is ok?
From what you are saying I understand that the timer calls my function and then waits for it to end before timing the next call (in the case of a periodical timer), rather than an interrupt like timer, is that right?
0 -
Well, to be honest, 30 times per second on the server is too much. I mean from the server logic point of view. usually, it is ok if it ticks 10 times per second
>From what you are saying I understand that the timer calls my function and then waits for it to end before timing the next call (in the case of a periodical timer), rather than an interrupt like timer, is that right?
yes, that is right. every new timer callback will be executed only when previous finishes
best,
ilya0 -
When I say 30 ticks per second I mean the server-side only calculations, rather than broadcast to clients...
I need to think if it makes sense to run the server-side calculation faster than the sending rate at all, since updates like position can be as slow as 5-10 updates per second, while other events, like "attack" can be handled in an "event driven" manner - meaning immediately on arrival without waiting for the next tick.0 -
that all makes sense
best,
ilya0 -
@chvetsov
New question:
What would be a good way to store the player list on the server in the plugin?
I can see the pluginHost.GameActors, now I want to extend that for much more information related to the game, like positions, rotations, hp, and all that.
Is creating a List/Array of players with my information and a pointer to the IActor for each of them ok? or is there a better way?
Thanks,
Michael.0 -
>Is creating a List/Array of players with my information and a pointer to the IActor for each of them ok? or is there a better way?
no, there is nothing built-in. Except for properties, but they are not quick enough to access them.
best,
ilya0 -
Next Question:
Is there a master server thing where it wont let players create new rooms and return
"Operation failed: OperationResponse 227: ReturnCode: 32762" if the CPU usage on the server machine is high?
I notice clients can't create new rooms when I see the next log:
"2018-10-23 22:31:45,510 [44] INFO Photon.Common.LoadBalancer.LoadShedding.FeedbackController - Transit CpuUsage from High to Highest with input 90
2018-10-23 22:31:45,513 [44] INFO Photon.Common.LoadBalancer.LoadShedding.WorkloadController - FeedbackLevel changed: old=High, new=Highest"
Or is this a coincidence and I get that error for another reason?
Thanks,
Michael.0 -
@chvetsov, Implementing server side ticks now using PluginHost.CreateOneTimeTimer(Update, nextUpdateIn);
I set the next code up:private int goalUpdateInterval = 50; // tick every 50ms (20 fps)
void Update()
{
// start stopwatch to measure how much time the update call takes to run
stopwatch.Restart();
// *************************************************************************
// Update body
// *************************************************************************
// run update tick on all players
UpdatePlayers();
Debug.WriteLine("diff: " + (previousMs - (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond)));
previousMs = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
// *************************************************************************
// Update body - End
// *************************************************************************
// calculate in how much time we should invoke the next update call according to how much
// time passed since the beggining of this update call
stopwatch.Stop();
elapsedTime = (int)stopwatch.ElapsedMilliseconds;
Debug.WriteLine("elapsedTime: "+elapsedTime);
if(elapsedTime > goalUpdateInterval) {
nextUpdateIn = 0;
deltaTime = elapsedTime/1000f;
} else {
nextUpdateIn = goalUpdateInterval - elapsedTime;
deltaTime = goalUpdateInterval/1000f;
}
frameNum++;
// set the time for the next Update call
sst_UpdateTimer = myPlugin.PluginHost.CreateOneTimeTimer(Update, nextUpdateIn);
}
The output is:elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -64
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -60
diff: 0
elapsedTime: 3
diff: -48
elapsedTime: 0
diff: -58
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -63
diff: 0
elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -62
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -63
diff: 0
elapsedTime: 3
diff: -47
elapsedTime: 0
diff: -60
elapsedTime: 0
diff: -60
elapsedTime: 1
diff: -62
diff: 0
elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -62
elapsedTime: 0
diff: -65
elapsedTime: 0
diff: -59
diff: 0
elapsedTime: 3
diff: -60
elapsedTime: 1
What I would expect to see is diff: -50 on average, since thats what I configured for goalUpdateInterval;
but I get about 10-12 extra ms, which I feel is rather unacceptable.
Could you give me a hint on why that happens and how can I make it accurate? down to the ms?
Thanks,
Michael.0 -
@chvetsov, Hi,
I'm implementing the server side ticks now using a Timer.
The code I have atm is:private int goalUpdateInterval = 50; // tick every 50ms (20 fps)
void Update()
{
// start stopwatch to measure how much time the update call takes to run
stopwatch.Restart();
// *************************************************************************
// Update body
// *************************************************************************
// run update tick on all players
UpdatePlayers();
Debug.WriteLine("diff: " + (previousMs - (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond)));
previousMs = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
// *************************************************************************
// Update body - End
// *************************************************************************
// calculate in how much time we should invoke the next update call according to how much
// time passed since the beggining of this update call
stopwatch.Stop();
elapsedTime = (int)stopwatch.ElapsedMilliseconds;
Debug.WriteLine("elapsedTime: "+elapsedTime);
if(elapsedTime > goalUpdateInterval) {
nextUpdateIn = 0;
deltaTime = elapsedTime/1000f;
} else {
nextUpdateIn = goalUpdateInterval - elapsedTime;
deltaTime = goalUpdateInterval/1000f;
}
frameNum++;
// set the time for the next Update call
sst_UpdateTimer = myPlugin.PluginHost.CreateOneTimeTimer(Update, nextUpdateIn);
}
The output for this code is:diff: -56
diff: 0
elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -64
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -60
diff: 0
elapsedTime: 3
diff: -48
elapsedTime: 0
diff: -58
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -63
diff: 0
elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -62
elapsedTime: 0
diff: -63
elapsedTime: 0
diff: -63
diff: 0
elapsedTime: 3
diff: -47
elapsedTime: 0
diff: -60
elapsedTime: 0
diff: -60
elapsedTime: 1
diff: -62
diff: 0
elapsedTime: 1
diff: -61
elapsedTime: 0
diff: -62
elapsedTime: 0
diff: -65
The output I'd expect to see however is diff: -50 on avg.
I cant figure out where I get the extra 10-15 ms from since I do try to compensate for the runtime of the update loop itself.
Could you give me a hint on whats happening and how to make it accurate? preferably down to the ms?
Thanks,
Michael.0 -
The thing is that when a timer is fired task is enqueued into a fiber. The fiber may have some tasks, that is why you may see this delays
best,
Ilya0 -
I see, can I then run a thread where the update function happens with lock{} on shared memory? or is it going to break things?0
-
well, yes, 30-50 it will be able. if this is all you need then it is fine
best
ilya0