/// <inheritdoc />
        public void DisposeComponents(EntityUid uid)
        {
            foreach (var kvTypeDict in _dictComponents)
            {
                if (kvTypeDict.Value.TryGetValue(uid, out var comp))
                {
                    #if EXCEPTION_TOLERANCE
                    try
                    {
#endif

                    comp.Running = false;
#if EXCEPTION_TOLERANCE
                }
                catch (Exception e)
                {
                    _runtimeLog.LogException(e,
                                             $"DisposeComponents comp.Running=false, owner={uid}, type={comp.GetType()}");
                }
#endif
                }
            }

            foreach (var kvTypeDict in _dictComponents)
            {
                // because we are iterating over references instead of instances, and a comp instance
                // can have multiple references, we filter out already deleted instances.
                if (kvTypeDict.Value.TryGetValue(uid, out var comp) && !comp.Deleted)
                {
                    RemoveComponentDeferred(comp, true);
                }
            }
        }
Beispiel #2
0
        // Parameter is used only on release.
        // ReSharper disable once UnusedParameter.Global
        public void Update(float frameTime, IRuntimeLog runtimeLog)
        {
            if (IsActive)
            {
                _timeCounter -= (int)(frameTime * 1000);

                if (_timeCounter <= 0)
                {
#if EXCEPTION_TOLERANCE
                    try
#endif
                    {
                        OnFired();
                    }
#if EXCEPTION_TOLERANCE
                    catch (Exception e)
                    {
                        runtimeLog.LogException(e, "Timer Callback");
                    }
#endif

                    if (IsRepeating)
                    {
                        _timeCounter = Time;
                    }
                    else
                    {
                        IsActive = false;
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        ///     Start running the loop. This function will block for as long as the loop is Running.
        ///     Set Running to false to exit the loop and return from this function.
        /// </summary>
        public void Run()
        {
            if (_timing.TickRate <= 0)
            {
                throw new InvalidOperationException("TickRate must be greater than 0.");
            }

            Running = true;

            FrameEventArgs realFrameEvent;
            FrameEventArgs simFrameEvent;

            _timing.ResetRealTime();

            while (Running)
            {
                // maximum number of ticks to queue before the loop slows down.
                var maxTime = TimeSpan.FromTicks(_timing.TickPeriod.Ticks * MaxQueuedTicks);

                var accumulator = _timing.RealTime - _lastTick;

                // If the game can't keep up, limit time.
                if (accumulator > maxTime)
                {
                    // limit accumulator to max time.
                    accumulator = maxTime;

                    // pull lastTick up to the current realTime
                    // This will slow down the simulation, but if we are behind from a
                    // lag spike hopefully it will be able to catch up.
                    _lastTick = _timing.RealTime - maxTime;

                    // announce we are falling behind
                    if ((_timing.RealTime - _lastKeepUp).TotalSeconds >= 15.0)
                    {
                        Logger.WarningS("eng", "MainLoop: Cannot keep up!");
                        _lastKeepUp = _timing.RealTime;
                    }
                }

                _timing.StartFrame();
                realFrameEvent = new FrameEventArgs((float)_timing.RealFrameTime.TotalSeconds);
#if EXCEPTION_TOLERANCE
                try
#endif
                {
                    // process Net/KB/Mouse input
                    Input?.Invoke(this, realFrameEvent);
                }
#if EXCEPTION_TOLERANCE
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Input");
                }
#endif
                _timing.InSimulation = true;
                var tickPeriod = CalcTickPeriod();


                // run the simulation for every accumulated tick
                while (accumulator >= tickPeriod)
                {
                    accumulator -= tickPeriod;
                    _lastTick   += tickPeriod;

                    // only run the simulation if unpaused, but still use up the accumulated time
                    if (_timing.Paused)
                    {
                        continue;
                    }

                    // update the simulation
                    simFrameEvent = new FrameEventArgs((float)_timing.FrameTime.TotalSeconds);
#if EXCEPTION_TOLERANCE
                    var threw = false;
                    try
                    {
#endif
                    if (EnableMetrics)
                    {
                        using (_frameTimeHistogram.NewTimer())
                        {
                            Tick?.Invoke(this, simFrameEvent);
                        }
                    }
                    else
                    {
                        Tick?.Invoke(this, simFrameEvent);
                    }
#if EXCEPTION_TOLERANCE
                }
                catch (Exception exp)
                {
                    threw = true;
                    _runtimeLog.LogException(exp, "GameLoop Tick");
                    _tickExceptions += 1;

                    if (_tickExceptions > MaxSoftLockExceptions && DetectSoftLock)
                    {
                        Logger.FatalS("eng",
                                      "MainLoop: 10 consecutive exceptions inside GameLoop Tick, shutting down!");
                        Running = false;
                    }
                }

                if (!threw)
                {
                    _tickExceptions = 0;
                }
#endif
                    _timing.CurTick = new GameTick(_timing.CurTick.Value + 1);
                    tickPeriod      = CalcTickPeriod();

                    if (SingleStep)
                    {
                        _timing.Paused = true;
                    }
                }

                // if not paused, save how close to the next tick we are so interpolation works
                if (!_timing.Paused)
                {
                    _timing.TickRemainder = accumulator;
                }

                _timing.InSimulation = false;

                // update out of the simulation

#if EXCEPTION_TOLERANCE
                try
#endif
                {
                    Update?.Invoke(this, realFrameEvent);
                }
#if EXCEPTION_TOLERANCE
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Update");
                }
#endif

                // render the simulation
#if EXCEPTION_TOLERANCE
                try
#endif
                {
                    Render?.Invoke(this, realFrameEvent);
                }
#if EXCEPTION_TOLERANCE
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Render");
                }
#endif

                // Set sleep to 1 if you want to be nice and give the rest of the timeslice up to the os scheduler.
                // Set sleep to 0 if you want to use 100% cpu, but still cooperate with the scheduler.
                // do not call sleep if you want to be 'that thread' and hog 100% cpu.
                if (SleepMode != SleepMode.None)
                {
                    Thread.Sleep((int)SleepMode);
                }
            }
        }
Beispiel #4
0
        private void HandleEntityState(IComponentManager compMan, IEntity entity, EntityState curState,
                                       EntityState nextState)
        {
            var compStateWork = new Dictionary <uint, (ComponentState curState, ComponentState nextState)>();
            var entityUid     = entity.Uid;

            if (curState?.ComponentChanges != null)
            {
                foreach (var compChange in curState.ComponentChanges)
                {
                    if (compChange.Deleted)
                    {
                        if (compMan.TryGetComponent(entityUid, compChange.NetID, out var comp))
                        {
                            compMan.RemoveComponent(entityUid, comp);
                        }
                    }
                    else
                    {
                        if (compMan.HasComponent(entityUid, compChange.NetID))
                        {
                            continue;
                        }

                        var newComp = (Component)_compFactory.GetComponent(compChange.ComponentName);
                        newComp.Owner = entity;
                        compMan.AddComponent(entity, newComp, true);
                    }
                }
            }

            if (curState?.ComponentStates != null)
            {
                foreach (var compState in curState.ComponentStates)
                {
                    compStateWork[compState.NetID] = (compState, null);
                }
            }

            if (nextState?.ComponentStates != null)
            {
                foreach (var compState in nextState.ComponentStates)
                {
                    if (compStateWork.TryGetValue(compState.NetID, out var state))
                    {
                        compStateWork[compState.NetID] = (state.curState, compState);
                    }
                    else
                    {
                        compStateWork[compState.NetID] = (null, compState);
                    }
                }
            }

            foreach (var kvStates in compStateWork)
            {
                if (!compMan.TryGetComponent(entityUid, kvStates.Key, out var component))
                {
                    var eUid                  = entityUid;
                    var eExpectedNetUid       = kvStates.Key;
                    var eRegisteredNetUidName = _compFactory.GetRegistration(eExpectedNetUid).Name;
                    DebugTools.Assert($"Component does not exist for state: entUid={eUid}, expectedNetId={eExpectedNetUid}, expectedName={eRegisteredNetUidName}");
                    continue;
                }

                try
                {
                    component.HandleComponentState(kvStates.Value.curState, kvStates.Value.nextState);
                }
                catch (Exception e)
                {
                    var wrapper = new ComponentStateApplyException(
                        $"Failed to apply comp state: entity={component.Owner}, comp={component.Name}", e);
#if EXCEPTION_TOLERANCE
                    _runtimeLog.LogException(wrapper, "Component state apply");
#else
                    throw wrapper;
#endif
                }
            }
        }
Beispiel #5
0
        private void HandleEntityState(IComponentManager compMan, IEntity entity, EntityState?curState,
                                       EntityState?nextState)
        {
            var compStateWork = new Dictionary <uint, (ComponentState?curState, ComponentState?nextState)>();
            var entityUid     = entity.Uid;

            if (curState?.ComponentChanges != null)
            {
                foreach (var compChange in curState.ComponentChanges)
                {
                    if (compChange.Deleted)
                    {
                        if (compMan.TryGetComponent(entityUid, compChange.NetID, out var comp))
                        {
                            compMan.RemoveComponent(entityUid, comp);
                        }
                    }
                    else
                    {
                        if (compMan.HasComponent(entityUid, compChange.NetID))
                        {
                            continue;
                        }

                        var newComp = (Component)_compFactory.GetComponent(compChange.ComponentName !);
                        newComp.Owner = entity;
                        compMan.AddComponent(entity, newComp, true);
                    }
                }
            }

            if (curState?.ComponentStates != null)
            {
                foreach (var compState in curState.ComponentStates)
                {
                    compStateWork[compState.NetID] = (compState, null);
                }
            }

            if (nextState?.ComponentStates != null)
            {
                foreach (var compState in nextState.ComponentStates)
                {
                    if (compStateWork.TryGetValue(compState.NetID, out var state))
                    {
                        compStateWork[compState.NetID] = (state.curState, compState);
                    }
                    else
                    {
                        compStateWork[compState.NetID] = (null, compState);
                    }
                }
            }

            foreach (var(netId, (cur, next)) in compStateWork)
            {
                if (compMan.TryGetComponent(entityUid, netId, out var component))
                {
                    try
                    {
                        component.HandleComponentState(cur, next);
                    }
                    catch (Exception e)
                    {
                        var wrapper = new ComponentStateApplyException(
                            $"Failed to apply comp state: entity={component.Owner}, comp={component.Name}", e);
#if EXCEPTION_TOLERANCE
                        _runtimeLog.LogException(wrapper, "Component state apply");
#else
                        throw wrapper;
#endif
                    }
                }
                else
                {
                    // The component can be null here due to interp.
                    // Because the NEXT state will have a new component, but this one doesn't yet.
                    // That's fine though.
                    if (cur == null)
                    {
                        continue;
                    }

                    var eUid = entityUid;
                    var eRegisteredNetUidName = _compFactory.GetRegistration(netId).Name;
                    DebugTools.Assert(
                        $"Component does not exist for state: entUid={eUid}, expectedNetId={netId}, expectedName={eRegisteredNetUidName}");
                }
            }
        }
Beispiel #6
0
        /// <summary>
        ///     Start running the loop. This function will block for as long as the loop is Running.
        ///     Set Running to false to exit the loop and return from this function.
        /// </summary>
        public void Run()
        {
            if (_timing.TickRate <= 0)
            {
                throw new InvalidOperationException("TickRate must be greater than 0.");
            }

            Running = true;

            // maximum number of ticks to queue before the loop slows down.
            var maxTime = TimeSpan.FromTicks(_timing.TickPeriod.Ticks * MaxQueuedTicks);

            var realFrameEvent = new MutableFrameEventArgs(0);
            var simFrameEvent  = new MutableFrameEventArgs(0);

            _timing.ResetRealTime();

            while (Running)
            {
                var accumulator = _timing.RealTime - _lastTick;

                // If the game can't keep up, limit time.
                if (accumulator > maxTime)
                {
                    // limit accumulator to max time.
                    accumulator = maxTime;

                    // pull lastTick up to the current realTime
                    // This will slow down the simulation, but if we are behind from a
                    // lag spike hopefully it will be able to catch up.
                    _lastTick = _timing.RealTime - maxTime;

                    // announce we are falling behind
                    if ((_timing.RealTime - _lastKeepUp).TotalSeconds >= 15.0)
                    {
                        Logger.Warning("[ENG] MainLoop: Cannot keep up!");
                        _lastKeepUp = _timing.RealTime;
                    }
                }
                _timing.StartFrame();

                realFrameEvent.SetDeltaSeconds((float)_timing.RealFrameTime.TotalSeconds);

                try
                {
                    // process Net/KB/Mouse input
                    Input?.Invoke(this, realFrameEvent);
                }
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Input");
                }
                _timing.InSimulation = true;

                // run the simulation for every accumulated tick
                while (accumulator >= _timing.TickPeriod)
                {
                    accumulator -= _timing.TickPeriod;
                    _lastTick   += _timing.TickPeriod;

                    // only run the simulation if unpaused, but still use up the accumulated time
                    if (_timing.Paused)
                    {
                        continue;
                    }

                    // update the simulation
                    simFrameEvent.SetDeltaSeconds((float)_timing.FrameTime.TotalSeconds);
                    try
                    {
                        Tick?.Invoke(this, simFrameEvent);
                    }
                    catch (Exception exp)
                    {
                        _runtimeLog.LogException(exp, "GameLoop Tick");
                    }
                    _timing.CurTick++;

                    if (SingleStep)
                    {
                        _timing.Paused = true;
                    }
                }

                // if not paused, save how close to the next tick we are so interpolation works
                if (!_timing.Paused)
                {
                    _timing.TickRemainder = accumulator;
                }

                _timing.InSimulation = false;

                // update out of the simulation
                simFrameEvent.SetDeltaSeconds((float)_timing.FrameTime.TotalSeconds);
                try
                {
                    Update?.Invoke(this, simFrameEvent);
                }
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Update");
                }

                // render the simulation
                try
                {
                    Render?.Invoke(this, realFrameEvent);
                }
                catch (Exception exp)
                {
                    _runtimeLog.LogException(exp, "GameLoop Render");
                }
                // Set sleep to 1 if you want to be nice and give the rest of the timeslice up to the os scheduler.
                // Set sleep to 0 if you want to use 100% cpu, but still cooperate with the scheduler.
                // do not call sleep if you want to be 'that thread' and hog 100% cpu.
                if (SleepMode != SleepMode.None)
                {
                    Thread.Sleep((int)SleepMode);
                }
            }
        }