C
C#•3y ago
Rainys

ā” How to limit while loop updates per second amount

What i mean by the name is that: for a console application i'm developing (if you're wondering it's a game's server) i need a function something similar to say, Unity's FixedUpdate(), so that the function only happens somewhere like 50 times a second, because while (true) happens every single frame. or in layman's terms: How do i limit FPS?
85 Replies
Cattywampus
Cattywampus•3y ago
you'd need to implement your own gameloop and no, while(true) and any other loops are NOT every frame even in Unity
Tvde1
Tvde1•3y ago
there is a PeriodicTimer which is pretty good. I don't know about it's accuracy though but it can be set to tick every X milliseconds it does not have the drift that a await Task.Delay(TimeSpan.FromMillisecond(20)) would have
Cattywampus
Cattywampus•3y ago
in the context of gameloop I don' think this would be usable as is, you'd need to calc it based on display refresh rate to get 1 frame timing correctly
Jimmacle
Jimmacle•3y ago
i have dealt with a lot of frustration regarding accurate game loop timing standard C# timers just aren't precise enough
ero
ero•3y ago
they said it's a game's server
Jimmacle
Jimmacle•3y ago
i haven't found a solution that minimizes drift without some amount of spin waiting
Cattywampus
Cattywampus•3y ago
for frame-based engine, yeah you can't just do raw c#
ero
ero•3y ago
that's what periodictimer does
Rainys
RainysOP•3y ago
yeah, all it needs to do is send position data between the client and the server (the client is made in unity, so that's why i'm not that experienced in standalone application C# programming :D)
remmy_clarke_jr
remmy_clarke_jr•3y ago
@Rainys What is your target OS? Does this need to run on Windows or Linux ?
Cattywampus
Cattywampus•3y ago
so is this Unity or nah? you're trying to roll your own engine, right?
Rainys
RainysOP•3y ago
windows is okay, but both would be nice i guess.
remmy_clarke_jr
remmy_clarke_jr•3y ago
Each O/S has a specific mechanism for high resolution timers And XPlatform is a pain
Rainys
RainysOP•3y ago
game (client) is made in unity, and the server is a standalone .NET console application, so to answer your question: no
Cattywampus
Cattywampus•3y ago
wut?
remmy_clarke_jr
remmy_clarke_jr•3y ago
@BadaBingBadaBoom ?
ero
ero•3y ago
bogus lol
remmy_clarke_jr
remmy_clarke_jr•3y ago
?
ero
ero•3y ago
PeriodicTimer is cross platform it's the most precise and modern c# timer unity has its own stuff for handling server stuff, no? or like, there's dedicated libraries for it already
remmy_clarke_jr
remmy_clarke_jr•3y ago
No PeriodicTimer still has performance and drift issues
ero
ero•3y ago
prove it
remmy_clarke_jr
remmy_clarke_jr•3y ago
I don't have too lol
ero
ero•3y ago
you can't just make bogus claims without proof lmfao
remmy_clarke_jr
remmy_clarke_jr•3y ago
But you're welcome to "mess about and find out" You're completely free to believe me or not Its the internet Everything i say could be false šŸ˜›
Cattywampus
Cattywampus•3y ago
aight, you're trolling
ero
ero•3y ago
if it wasn't obvious before
remmy_clarke_jr
remmy_clarke_jr•3y ago
Wut
Rainys
RainysOP•3y ago
i'm using a server system/framework or whatever you want to call it called Riptide. and all it basically does is allows the programmer to send "messages" between the clients and the server. However what should happen with the "messages" is all the programmer's work, but for now my question is what is the best way to implement the fixed update function thing in C# okay, so as i understand i should look into PeriodicTimer?
remmy_clarke_jr
remmy_clarke_jr•3y ago
Wouldn't you be better off using an existing event system
ero
ero•3y ago
it's pretty easy to use, too
remmy_clarke_jr
remmy_clarke_jr•3y ago
What protocol does Unity push messages over?
Cattywampus
Cattywampus•3y ago
Dude stop
ero
ero•3y ago
like your whole program.cs is just like
PeriodicTimer timer = new(TimeSpan.FromSeconds(1d / 50d));

while (await timer.WaitForNextTickAsync())
{
// code to execute on tick
}
PeriodicTimer timer = new(TimeSpan.FromSeconds(1d / 50d));

while (await timer.WaitForNextTickAsync())
{
// code to execute on tick
}
Rainys
RainysOP•3y ago
so this just executes the code inside the while loop 50 times every second?
ero
ero•3y ago
yup
Jimmacle
Jimmacle•3y ago
what's the drift on that loop?
Rainys
RainysOP•3y ago
well, thanks, you answered my question :D
Jimmacle
Jimmacle•3y ago
i recommend testing it to make sure the actual wait time doesn't vary too much
ero
ero•3y ago
how should one check the drift, exactly?
Jimmacle
Jimmacle•3y ago
with a stopwatch i haven't used this specific timer but every other timing mechanism i've tried has been awful for delays less than the length of an average game tick
ero
ero•3y ago
come on, send some code i can test on
Jimmacle
Jimmacle•3y ago
i'm about to leave for work which unfortunately isn't a game studio kek
ero
ero•3y ago
no clue how this would be tested
Jimmacle
Jimmacle•3y ago
just run a stopwatch in the loop and dump the wait time between ticks
ero
ero•3y ago
no shot that's how you tested it LMFAO stopwatches are NOT accurate
Jimmacle
Jimmacle•3y ago
they're more accurate than timers afaik
ero
ero•3y ago
there's a reason we don't just use stopwatches to benchmark code
Jimmacle
Jimmacle•3y ago
okay, what's used?
ero
ero•3y ago
there's so much managed overhead to them BenchmarkDotNet? whatever they use
Jimmacle
Jimmacle•3y ago
what does that use?
ero
ero•3y ago
certainly not stopwatches lmao you can't get nanosecond accuracy with stopwatches
const double Interval = 1d / 50d;

PeriodicTimer timer = new(TimeSpan.FromSeconds(Interval));
DateTime dt = DateTime.Now;

while (await timer.WaitForNextTickAsync())
{
dt = dt.AddSeconds(Interval);
Console.WriteLine($"It is {dt}.");
}
const double Interval = 1d / 50d;

PeriodicTimer timer = new(TimeSpan.FromSeconds(Interval));
DateTime dt = DateTime.Now;

while (await timer.WaitForNextTickAsync())
{
dt = dt.AddSeconds(Interval);
Console.WriteLine($"It is {dt}.");
}
i just did this
Jimmacle
Jimmacle•3y ago
you complain about stopwatches then you go and use datetime?
ero
ero•3y ago
? surely trolling
Jimmacle
Jimmacle•3y ago
wait, you aren't even timing
ero
ero•3y ago
why would i
Jimmacle
Jimmacle•3y ago
that's the point? to make sure the simulated time matches real world time
ero
ero•3y ago
no? that's what that's doing it adds the supposed interval to the start time on each tick if there were a delay in the tick then the printed time would no longer match up with the real world time
Jimmacle
Jimmacle•3y ago
where are you actually measuring time and not just adding a fixed number in that loop?
ero
ero•3y ago
what's there to measure
Jimmacle
Jimmacle•3y ago
you don't understand this assignment i gotta go to work
ero
ero•3y ago
i think you just don't understand what that code accomplishes lol
Jimmacle
Jimmacle•3y ago
you're assuming your timer is waiting as long as you tell it to which in my experience is never true especially with time spans this short the point is to verify it
ero
ero•3y ago
how is this not verifying it if the loop runs for too long and the timer is delayed somehow
Jimmacle
Jimmacle•3y ago
becuase you aren't comparing it with another timing mechanism sigh
ero
ero•3y ago
??? i have a clock on my computer i'm comparing it to that
PeriodicTimer timer = new(TimeSpan.FromSeconds(1d / 50d));
Stopwatch sw = Stopwatch.StartNew();

while (await timer.WaitForNextTickAsync())
{
sw.Stop();
Console.WriteLine($"{sw.ElapsedMilliseconds}");
sw.Restart();
}
PeriodicTimer timer = new(TimeSpan.FromSeconds(1d / 50d));
Stopwatch sw = Stopwatch.StartNew();

while (await timer.WaitForNextTickAsync())
{
sw.Stop();
Console.WriteLine($"{sw.ElapsedMilliseconds}");
sw.Restart();
}
15
15
14
31
15
14
31
15
16
15
30
15
15
14
31
15
14
31
15
16
15
30
hell yeah, so much more accurate! 1 / 50 s is 20 ms by the way
Jimmacle
Jimmacle•3y ago
i trust the stopwatch more than the timer
ero
ero•3y ago
then you just don't know how these things work like period
Jimmacle
Jimmacle•3y ago
you said you don't know how benchmarkdotnet actually times things so i guess we're in the same boat
ero
ero•3y ago
strawman
Jimmacle
Jimmacle•3y ago
that even gets the benefit of average time, you can't take the average here because jitter is an important metric for game loops
ero
ero•3y ago
BDN uses Perfolizer.Horology.IClock and gets a completely custom clock depending on the target of the benchmark
Jimmacle
Jimmacle•3y ago
using System.Diagnostics;

var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(10));
var counter = 0;
var stopwatch = Stopwatch.StartNew();

while (counter < 1000)
{
await timer.WaitForNextTickAsync();
counter++;
}

stopwatch.Stop();
Console.WriteLine($"10 seconds in loop = {stopwatch.Elapsed.TotalSeconds}");
using System.Diagnostics;

var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(10));
var counter = 0;
var stopwatch = Stopwatch.StartNew();

while (counter < 1000)
{
await timer.WaitForNextTickAsync();
counter++;
}

stopwatch.Stop();
Console.WriteLine($"10 seconds in loop = {stopwatch.Elapsed.TotalSeconds}");
10 seconds in loop = 10.9501011 so stopwatch is either very wrong or your timer consistently delays longer than intended
ero
ero•3y ago
"my" timer lol
Jimmacle
Jimmacle•3y ago
you're defending it ĀÆ\_(惄)_/ĀÆ i'm just adding this to my list of timers that aren't accurate enough for game loop synchronization
ero
ero•3y ago
ero
ero•3y ago
couldn't be that stopwatch is wrong just impossible
Jimmacle
Jimmacle•3y ago
so windows performance counters are off by 50%? on my system at least it reports stopwatch resolution to be 100ns which should be more than enough for this test practically every non-busy wait i have tried from timers to sleeps to delays all guarantee a minimum wait time, not an exact time and when you're having them fire every 10-20ms it adds up fast
ero
ero•3y ago
in the end it's all hardware dependent i'm not so much "defending" the timer as i am defending my stance on not using stopwatch to measure anything ever that has too much overhead, no warming up, no optimization
Jimmacle
Jimmacle•3y ago
i mean we can pick something else but i doubt it's off by over 50% that would be entirely unusable
ero
ero•3y ago
this is on my work laptop. i'm sure we'd get another different result on my home pc
Jimmacle
Jimmacle•3y ago
we got different results between us to begin with and i'm on my work pc šŸ‘€
ero
ero•3y ago
i'm saying a third different result
Jimmacle
Jimmacle•3y ago
we already have enough results to know something is significantly off
ero
ero•3y ago
i was just saying man pepeW
Accord
Accord•3y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.

Did you find this page helpful?