C
C#ā€¢2y 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ā€¢2y 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ā€¢2y 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ā€¢2y 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ā€¢2y ago
i have dealt with a lot of frustration regarding accurate game loop timing standard C# timers just aren't precise enough
ero
eroā€¢2y ago
they said it's a game's server
Jimmacle
Jimmacleā€¢2y ago
i haven't found a solution that minimizes drift without some amount of spin waiting
Cattywampus
Cattywampusā€¢2y ago
for frame-based engine, yeah you can't just do raw c#
ero
eroā€¢2y ago
that's what periodictimer does
Rainys
RainysOPā€¢2y 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ā€¢2y ago
@Rainys What is your target OS? Does this need to run on Windows or Linux ?
Cattywampus
Cattywampusā€¢2y ago
so is this Unity or nah? you're trying to roll your own engine, right?
Rainys
RainysOPā€¢2y ago
windows is okay, but both would be nice i guess.
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
Each O/S has a specific mechanism for high resolution timers And XPlatform is a pain
Rainys
RainysOPā€¢2y ago
game (client) is made in unity, and the server is a standalone .NET console application, so to answer your question: no
Cattywampus
Cattywampusā€¢2y ago
wut?
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
@BadaBingBadaBoom ?
ero
eroā€¢2y ago
bogus lol
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
?
ero
eroā€¢2y 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ā€¢2y ago
No PeriodicTimer still has performance and drift issues
ero
eroā€¢2y ago
prove it
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
I don't have too lol
ero
eroā€¢2y ago
you can't just make bogus claims without proof lmfao
remmy_clarke_jr
remmy_clarke_jrā€¢2y 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ā€¢2y ago
aight, you're trolling
ero
eroā€¢2y ago
if it wasn't obvious before
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
Wut
Rainys
RainysOPā€¢2y 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ā€¢2y ago
Wouldn't you be better off using an existing event system
ero
eroā€¢2y ago
it's pretty easy to use, too
remmy_clarke_jr
remmy_clarke_jrā€¢2y ago
What protocol does Unity push messages over?
Cattywampus
Cattywampusā€¢2y ago
Dude stop
ero
eroā€¢2y 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ā€¢2y ago
so this just executes the code inside the while loop 50 times every second?
ero
eroā€¢2y ago
yup
Jimmacle
Jimmacleā€¢2y ago
what's the drift on that loop?
Rainys
RainysOPā€¢2y ago
well, thanks, you answered my question :D
Jimmacle
Jimmacleā€¢2y ago
i recommend testing it to make sure the actual wait time doesn't vary too much
ero
eroā€¢2y ago
how should one check the drift, exactly?
Jimmacle
Jimmacleā€¢2y 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ā€¢2y ago
come on, send some code i can test on
Jimmacle
Jimmacleā€¢2y ago
i'm about to leave for work which unfortunately isn't a game studio kek
ero
eroā€¢2y ago
no clue how this would be tested
Jimmacle
Jimmacleā€¢2y ago
just run a stopwatch in the loop and dump the wait time between ticks
ero
eroā€¢2y ago
no shot that's how you tested it LMFAO stopwatches are NOT accurate
Jimmacle
Jimmacleā€¢2y ago
they're more accurate than timers afaik
ero
eroā€¢2y ago
there's a reason we don't just use stopwatches to benchmark code
Jimmacle
Jimmacleā€¢2y ago
okay, what's used?
ero
eroā€¢2y ago
there's so much managed overhead to them BenchmarkDotNet? whatever they use
Jimmacle
Jimmacleā€¢2y ago
what does that use?
ero
eroā€¢2y 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ā€¢2y ago
you complain about stopwatches then you go and use datetime?
ero
eroā€¢2y ago
? surely trolling
Jimmacle
Jimmacleā€¢2y ago
wait, you aren't even timing
ero
eroā€¢2y ago
why would i
Jimmacle
Jimmacleā€¢2y ago
that's the point? to make sure the simulated time matches real world time
ero
eroā€¢2y 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ā€¢2y ago
where are you actually measuring time and not just adding a fixed number in that loop?
ero
eroā€¢2y ago
what's there to measure
Jimmacle
Jimmacleā€¢2y ago
you don't understand this assignment i gotta go to work
ero
eroā€¢2y ago
i think you just don't understand what that code accomplishes lol
Jimmacle
Jimmacleā€¢2y 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ā€¢2y ago
how is this not verifying it if the loop runs for too long and the timer is delayed somehow
Jimmacle
Jimmacleā€¢2y ago
becuase you aren't comparing it with another timing mechanism sigh
ero
eroā€¢2y 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ā€¢2y ago
i trust the stopwatch more than the timer
ero
eroā€¢2y ago
then you just don't know how these things work like period
Jimmacle
Jimmacleā€¢2y ago
you said you don't know how benchmarkdotnet actually times things so i guess we're in the same boat
ero
eroā€¢2y ago
strawman
Jimmacle
Jimmacleā€¢2y 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ā€¢2y ago
BDN uses Perfolizer.Horology.IClock and gets a completely custom clock depending on the target of the benchmark
Jimmacle
Jimmacleā€¢2y 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ā€¢2y ago
"my" timer lol
Jimmacle
Jimmacleā€¢2y 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ā€¢2y ago
ero
eroā€¢2y ago
couldn't be that stopwatch is wrong just impossible
Jimmacle
Jimmacleā€¢2y 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ā€¢2y 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ā€¢2y ago
i mean we can pick something else but i doubt it's off by over 50% that would be entirely unusable
ero
eroā€¢2y ago
this is on my work laptop. i'm sure we'd get another different result on my home pc
Jimmacle
Jimmacleā€¢2y ago
we got different results between us to begin with and i'm on my work pc šŸ‘€
ero
eroā€¢2y ago
i'm saying a third different result
Jimmacle
Jimmacleā€¢2y ago
we already have enough results to know something is significantly off
ero
eroā€¢2y ago
i was just saying man pepeW
Accord
Accordā€¢2y 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.
Want results from more Discord servers?
Add your server