示例#1
0
        private Task ExecuteUpdateAsync()
        {
            var timer = new Timer
            {
                Interval  = 1000,
                AutoReset = true
            };

            timer.Elapsed += (sender, args) =>
            {
                if (_ticks > 0)
                {
                    Logger.Debug($"TPS: {_ticks}/{TicksPerSecondLimit} TPT: {_passedTickTime / _ticks} ms PHY: {_physicsTime / _ticks} ms");
                }
                _passedTickTime = 0;
                _ticks          = 0;
            };

            timer.Start();

            Listen(OnTick, PhysicsStep);

            return(Task.Run(async() =>
            {
                _running = true;
                var watch = new Stopwatch();

                while (_running)
                {
                    var players = Players;
                    if (players.Length == 0)
                    {
                        await Task.Delay(1000);
                        continue;
                    }

                    if (_ticks >= TicksPerSecondLimit)
                    {
                        continue;
                    }

                    watch.Restart();

                    // Update all tick tasks in parallel
                    var tickTasks = new List <Task>();
                    foreach (var updatedObject in UpdatedObjects.ToArray())
                    {
                        if (updatedObject.Stuck)
                        {
                            continue;
                        }

                        if (updatedObject.Associate is GameObject gameObject)
                        {
                            if (players.All(p => !p.Perspective.LoadedObjects.Contains(gameObject)))
                            {
                                continue;
                            }
                        }

                        updatedObject.DeltaTime += DeltaTime;
                        if (updatedObject.Frequency != ++updatedObject.Ticks)
                        {
                            continue;
                        }
                        updatedObject.Ticks = 0;

                        tickTasks.Add(Task.Run(async() =>
                        {
                            var start = watch.ElapsedMilliseconds;
                            try
                            {
                                var tickTask = Task.Run(async() =>
                                {
                                    await updatedObject.Delegate(updatedObject.DeltaTime);
                                    updatedObject.Stuck = false;
                                });

                                var delay = Task.Delay(150);
                                await Task.WhenAny(tickTask, delay);
                                var elapsed = watch.ElapsedMilliseconds - start;

                                // Any task that takes more than 3 ticks to complete is considered stuck
                                if (delay.IsCompleted && !tickTask.IsCompleted)
                                {
                                    Logger.Warning($"{updatedObject.Associate} is now defined as stuck!");
                                    updatedObject.Stuck = true;
                                }
                                // Any task that took more than two ticks to execute but less than 3 is considered slow
                                else if (elapsed > 100)
                                {
                                    Logger.Warning($"Slow update: {updatedObject.Associate} in {elapsed}ms");
                                }
                            }
                            catch (Exception e)
                            {
                                Logger.Error(e);
                            }

                            updatedObject.DeltaTime = 0;
                        }));
                    }

                    await Task.WhenAll(tickTasks);
                    await OnTick.InvokeAsync();

                    _ticks++;

                    var passedMs = watch.ElapsedMilliseconds;
                    _passedTickTime += passedMs;

                    // Sync with the system tick clock
                    await Task.Delay((int)Math.Max(1000 / TicksPerSecondLimit - passedMs, 0));

                    passedMs = watch.ElapsedMilliseconds;
                    DeltaTime = passedMs / 1000f;
                }
            }));
        }