Пример #1
0
 public void WaitOne()
 {
     _lock.AcquireExclusive();
     _waiters = 1;
     _lock.AcquireExclusive();
     _lock.ReleaseExclusive();
 }
Пример #2
0
        private void AddNetworkObject(NetworkId networkID, IMyNetObject obj)
        {
            IMyNetObject foundObj;

            networkObjectLock.AcquireExclusiveUsing();
            if (!m_networkIDToObject.TryGetValue(networkID, out foundObj))
            {
                m_networkIDToObject.Add(networkID, obj);
                m_objectToNetworkID.Add(obj, networkID);

                var proxyTarget = obj as IMyProxyTarget;
                if (proxyTarget != null)
                {
                    Debug.Assert(proxyTarget.Target != null, "IMyProxyTarget.Target is null!");
                    Debug.Assert(!m_proxyToTarget.ContainsKey(proxyTarget.Target), "Proxy is already added to list!");
                    if (proxyTarget.Target != null && !m_proxyToTarget.ContainsKey(proxyTarget.Target))
                    {
                        m_proxyToTarget.Add(proxyTarget.Target, proxyTarget);
                    }
                }
            }
            else
            {
                if (obj != null && foundObj != null)
                {
                    MyLog.Default.WriteLine("Replicated object already exists adding : " + obj.ToString() + " existing : " + foundObj.ToString() + " id : " + networkID.ToString());
                }
                Debug.Fail("Replicated object already exists!");
            }
            networkObjectLock.ReleaseExclusive();
        }
Пример #3
0
 private static void ReleaseLock()
 {
     while (_lock?.TryAcquireExclusive() == false)
     {
         _lock?.ReleaseExclusive();
     }
     _lock?.ReleaseExclusive();
 }
Пример #4
0
        /// <summary>
        ///     Invokes actions on the game thread, and blocks until completion
        /// </summary>
        /// <param name="action"></param>
        public static void InvokeBlocking(Action action)
        {
            var threadLock = new FastResourceLock();

            if (!SessionClosing)
            {
                ThreadLocks.Add(threadLock);
            }

            threadLock.AcquireExclusive();
            try
            {
                MyAPIGateway.Utilities.InvokeOnGameThread(() =>
                {
                    try
                    {
                        var invokeBlock = Profiler.Start(FullName, nameof(InvokeBlocking));
                        action();
                        invokeBlock.End();
                    }
                    catch (Exception ex)
                    {
                        Logging.Instance.WriteLine("Exception on blocking game thread invocation: " + ex);

                        if (!SessionClosing && ShipyardCore.Debug)
                        {
                            throw;
                        }
                    }
                    finally
                    {
                        threadLock.ReleaseExclusive();
                    }
                });
            }
            catch (Exception ex)
            {
                Logging.Instance.WriteLine("Exception in Utilities.InvokeBlocking: " + ex);
                threadLock.ReleaseExclusive();

                if (!SessionClosing && ShipyardCore.Debug)
                {
                    throw;
                }
            }

            threadLock.AcquireExclusive();
            threadLock.ReleaseExclusive();

            if (!SessionClosing)
            {
                ThreadLocks.Remove(threadLock);
            }
        }
Пример #5
0
        private void RefreshInternalData()
        {
            if (!SandboxGameAssemblyWrapper.Instance.IsGameStarted)
            {
                return;
            }
            if (WorldManager.Instance.IsWorldSaving)
            {
                return;
            }
            if (WorldManager.Instance.InternalGetResourceLock() == null)
            {
                return;
            }
            if (WorldManager.Instance.InternalGetResourceLock().Owned)
            {
                return;
            }

            if (IsDynamic)
            {
                try
                {
                    //Lock the main data
                    m_resourceLock.AcquireExclusive();

                    RefreshRawData();

                    //Lock all of the raw data
                    m_rawDataHashSetResourceLock.AcquireExclusive();
                    m_rawDataListResourceLock.AcquireExclusive();
                    m_rawDataObjectBuilderListResourceLock.AcquireExclusive();

                    //Refresh the main data
                    LoadDynamic();

                    //Unlock all of the raw data
                    m_rawDataHashSetResourceLock.ReleaseExclusive();
                    m_rawDataListResourceLock.ReleaseExclusive();
                    m_rawDataObjectBuilderListResourceLock.ReleaseExclusive();

                    //Unlock the main data
                    m_resourceLock.ReleaseExclusive();
                }
                catch (Exception ex)
                {
                    LogManager.ErrorLog.WriteLine(ex);
                }
            }
        }
Пример #6
0
        internal void Close()
        {
            try
            {
                if (m_writer != null)
                {
                    if (m_writeCache.Length > 0)
                    {
                        m_writer.WriteLine(m_writeCache);
                    }

                    m_writer.Flush();
                    m_writer.Close();
                    m_writer = null;
                }

                m_instance = null;
                if (m_lock != null)
                {
                    m_lock.ReleaseExclusive();
                    m_lock = null;
                }
            }
            catch { }
        }
Пример #7
0
        public void InitFromGrids(MyObjectBuilder_CubeGrid primaryGrid, ICollection <MyObjectBuilder_CubeGrid> allGrids)
        {
            try
            {
                if (!m_lock.TryAcquireExclusive())
                {
                    m_lock.AcquireExclusive();
                    if (m_initFromGrid)
                    {
                        return;
                    }
                }
                // References to BlockInfo aren't threadsafe, so create a new one for this purpose.
                var blockInfo = new BlockSetInfo();
                ComputeBlockMap(primaryGrid, allGrids, blockInfo);
                ComputeReservedSpace(primaryGrid, allGrids, blockInfo);
                ComputeMountPoints(primaryGrid, allGrids, blockInfo);
                blockInfo.UpdateCache();
                BlockSetInfo = blockInfo;

                m_initFromGrid = true;
            }
            finally
            {
                m_lock.ReleaseExclusive();
            }
        }
Пример #8
0
        /// <summary>
        /// For logging WARNING and higher severity.
        /// </summary>
        /// <param name="level">severity level</param>
        /// <param name="methodName">calling method</param>
        /// <param name="toLog">message to log</param>
        /// <param name="primaryState">class specific, appears before secondary state in log</param>
        /// <param name="secondaryState">class specific, appears before message in log</param>
        public void log(severity level, string methodName, string toLog, string primaryState = null, string secondaryState = null)
        {
            if (closed)
            {
                return;
            }
            lock_log.AcquireExclusive();
            try {
                if (logWriter == null)
                {
                    if (MyAPIGateway.Utilities == null || !createLog())
                    {
                        return;                         // cannot log
                    }
                }
                if (f_gridName != null)
                {
                    gridName = f_gridName.Invoke();
                }
                if (primaryState == null)
                {
                    if (f_state_primary != null)
                    {
                        default_primary = f_state_primary.Invoke();
                    }
                    primaryState = default_primary;
                }
                if (secondaryState == null)
                {
                    if (f_state_secondary != null)
                    {
                        default_secondary = f_state_secondary.Invoke();
                    }
                    secondaryState = default_secondary;
                }

                if (toLog == null)
                {
                    toLog = "no message";
                }
                if (numLines >= maxNumLines)
                {
                    return;
                }

                numLines++;
                appendWithBrackets(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff"));
                appendWithBrackets(level.ToString());
                appendWithBrackets(gridName);
                appendWithBrackets(className);
                appendWithBrackets(methodName);
                appendWithBrackets(primaryState);
                appendWithBrackets(secondaryState);
                stringCache.Append(toLog);

                logWriter.WriteLine(stringCache);
                logWriter.Flush();
                stringCache.Clear();
            } catch { } finally { lock_log.ReleaseExclusive(); }
        }
Пример #9
0
        public static void InvokeOnGameThreadBlocking(Action action, ILogging logger = null)
        {
            var mutex = new FastResourceLock();

            mutex.AcquireExclusive();
            MyAPIGateway.Utilities.InvokeOnGameThread(WrapAction(() =>
            {
                try
                {
                    action();
                }
                finally
                {
                    mutex.ReleaseExclusive();
                }
            }, logger));
            mutex.AcquireExclusive();
            mutex.ReleaseExclusive();
        }
Пример #10
0
        /// <summary>
        /// Closes all existing logs.
        /// Should be called at the end of each session and when game is closing.
        /// </summary>
        public static void Close()
        {
            Lock.AcquireExclusive();

            foreach (var assembly in ModLogs.Keys)
            {
                Log("Closing log", Severity.Level.INFO, "SEPC.Logging", assembly: assembly);
            }

            WriteItems();

            foreach (ModLog modLog in ModLogs.Values)
            {
                modLog.Close();
            }

            LogItems.Clear();
            ModLogs.Clear();
            StringCache.Clear();

            Lock.ReleaseExclusive();
        }
Пример #11
0
        private static int GetStructSize(Type structType)
        {
            int size;

#if SIZE_CACHE_USE_RESOURCE_LOCK
            _sizeCacheLock.AcquireShared();

            if (_sizeCache.ContainsKey(structType))
            {
                size = _sizeCache[structType];
                _sizeCacheLock.ReleaseShared();
            }
            else
            {
                _sizeCacheLock.ReleaseShared();

                size = Marshal.SizeOf(structType);
                _sizeCacheLock.AcquireExclusive();

                try
                {
                    if (!_sizeCache.ContainsKey(structType))
                    {
                        _sizeCache.Add(structType, size);
                    }
                }
                finally
                {
                    _sizeCacheLock.ReleaseExclusive();
                }
            }

            return(size);
#else
            lock (_sizeCache)
            {
                if (_sizeCache.ContainsKey(structType))
                {
                    size = _sizeCache[structType];
                }
                else
                {
                    _sizeCache.Add(structType, size = Marshal.SizeOf(structType));
                }

                return(size);
            }
#endif
        }
Пример #12
0
        private int SpawnNewBotInternal(MyAgentDefinition agentDefinition, Vector3D? spawnPosition = null, bool createdByPlayer = false)
        {
            m_lock.AcquireExclusive();
            foreach (var player in Sync.Players.GetOnlinePlayers())
            {
                if (player.Id.SteamId == Sync.MyId && player.Id.SerialId > m_lastBotId)
                {
                    m_lastBotId = player.Id.SerialId;
                }
            }
            m_lastBotId++;
            var lastBotId = m_lastBotId;
            m_lock.ReleaseExclusive();

            m_processQueue.Enqueue(new AgentSpawnData(agentDefinition, lastBotId, spawnPosition, createdByPlayer));

            return lastBotId;
        }
Пример #13
0
        private void Update_OnThread()
        {
            try
            {
                m_nearbyEntities.Clear();
                m_nearbyRange = 0f;
                myLastSeen.Clear();
                detectedObjects_list.Clear();
                if (detectedObjects_hash != null)
                {
                    detectedObjects_hash.Clear();
                }

                if (!IsWorking)
                {
                    if (PowerLevel_Current > 0)
                    {
                        PowerLevel_Current += myDefinition.PowerDecrease;
                    }
                    ClearJamming();
                    return;
                }

                UpdatePowerLevel();

                if (IsJammer)
                {
                    JamRadar();
                }

                if (IsRadar)
                {
                    ActiveDetection();
                }

                if (myDefinition.PassiveDetect_Jamming > 0)
                {
                    PassiveDetection(false);
                }

                if (myDefinition.PassiveDetect_Radar > 0)
                {
                    PassiveDetection(true);
                }

                if (detectedObjects_list.Count > 0)
                {
                    detectedObjects_list.Sort();
                    int transmit = Math.Min(detectedObjects_list.Count, myDefinition.MaxTargets_Tracking);
                    for (int i = 0; i < transmit; i++)
                    {
                        DetectedInfo detFo = detectedObjects_list[i];
                        myLastSeen.Add(new LastSeen(detFo.Entity, detFo.Times, detFo.Info));
                        //Log.DebugLog("created last seen for: " + detFo.Entity.getBestName());
                    }
                    //Log.DebugLog("sending to storage: " + myLastSeen.Count);
                    m_node.Storage.Receive(myLastSeen);
                }
            }
            catch (Exception ex)
            {
                Log.AlwaysLog("Exception: " + ex, Logger.severity.ERROR);
                CubeBlock.EnableGameThread(false);
            }
            finally
            { myLock.ReleaseExclusive(); }
        }
Пример #14
0
        private void ResolveAddresses(string id, bool remote, IPAddress address)
        {
            string hostName = null;
            bool   inCache  = false;

            // Last minute check of the cache.

            _resolveCacheLock.AcquireShared();

            try
            {
                if (_resolveCache.ContainsKey(address))
                {
                    hostName = _resolveCache[address];
                    inCache  = true;
                }
            }
            finally
            {
                _resolveCacheLock.ReleaseShared();
            }

            // If it wasn't in the cache, resolve the address.
            if (!inCache)
            {
                try
                {
                    hostName = Dns.GetHostEntry(address).HostName;
                }
                catch (SocketException)
                {
                    // Host was not found.
                    return;
                }

                // Update the cache.

                _resolveCacheLock.AcquireExclusive();

                try
                {
                    // Add the name if not present already.
                    if (!string.IsNullOrEmpty(hostName))
                    {
                        if (!_resolveCache.ContainsKey(address))
                        {
                            _resolveCache.Add(address, hostName);
                        }
                    }
                }
                finally
                {
                    _resolveCacheLock.ReleaseExclusive();
                }
            }

            _messageQueue.Enqueue(new AddressResolveMessage
            {
                Id       = id,
                Remote   = remote,
                HostName = hostName
            });
        }
Пример #15
0
 public void Dispose()
 {
     m_profiler.OnHistorySafe();
     m_lock.ReleaseExclusive();
     m_lock = null;
 }
Пример #16
0
        private void CommitInternal()
        {
            Debug.Assert(!EnableAsserts || OwnerThread == Thread.CurrentThread);
            Debug.Assert(m_currentProfilingStack.Count == 0, "CommitFrame cannot be called when there are some opened blocks, it must be outside blocks!");
            m_currentProfilingStack.Clear();

            if (m_blocksToAdd.Count > 0)
            {
                using (m_historyLock.AcquireExclusiveUsing())
                {
                    foreach (var block in m_blocksToAdd)
                    {
                        if (block.Value.Parent != null)
                        {
                            block.Value.Parent.Children.Add(block.Value);
                        }
                        else
                        {
                            m_rootBlocks.Add(block.Value);
                        }

                        m_profilingBlocks.Add(block.Key, block.Value);
                    }
                    m_blocksToAdd.Clear();
                    Interlocked.Exchange(ref m_remainingWindow, UPDATE_WINDOW - 1); // We have lock, no one is in draw, reset window
                }
            }
            else if (m_historyLock.TryAcquireExclusive())
            {
                Interlocked.Exchange(ref m_remainingWindow, UPDATE_WINDOW - 1); // We have lock, no one is in draw, reset window
                m_historyLock.ReleaseExclusive();
            }
            else if (Interlocked.Decrement(ref m_remainingWindow) < 0)
            {
                // Window is empty, wait for lock and reset it
                using (m_historyLock.AcquireExclusiveUsing())
                {
                    Interlocked.Exchange(ref m_remainingWindow, UPDATE_WINDOW - 1); // We have lock, no one is in draw, reset window
                }
            }

            int callCount = 0;

            m_levelLimit = m_newLevelLimit;

            int writeFrame = (m_lastFrameIndex + 1) % MyProfiler.MAX_FRAMES;

            foreach (MyProfiler.MyProfilerBlock profilerBlock in m_profilingBlocks.Values)
            {
                callCount += profilerBlock.NumCalls;

                profilerBlock.ManagedMemory[writeFrame] = profilerBlock.ManagedDeltaMB;
                if (MemoryProfiling)
                {
                    profilerBlock.ProcessMemory[writeFrame] = profilerBlock.ProcessDeltaMB;
                }
                profilerBlock.NumCallsArray[writeFrame] = profilerBlock.NumCalls;
                profilerBlock.CustomValues[writeFrame]  = profilerBlock.CustomValue;
                profilerBlock.Miliseconds[writeFrame]   = (float)profilerBlock.Elapsed.Miliseconds;

                // Unused
                profilerBlock.averageMiliseconds = 0.9f * profilerBlock.averageMiliseconds + 0.1f * (float)profilerBlock.Elapsed.Miliseconds;
                //profilerBlock.NumChildCalls = profilerBlock.GetNumChildCalls();

                profilerBlock.Clear();
            }

            TotalCalls[writeFrame] = callCount;
            m_lastFrameIndex       = writeFrame;
        }
Пример #17
0
        /// <summary>
        /// Run the autopilot
        /// </summary>
        private void UpdateThread()
        {
            if (!lock_execution.TryAcquireExclusive())
            {
                return;
            }
            try
            {
                if (Globals.UpdateCount > m_nextCustomInfo)
                {
                    m_nextCustomInfo = Globals.UpdateCount + 10ul;
                    UpdateCustomInfo();
                }

                switch (m_state)
                {
                case State.Disabled:
                    if (CheckControl())
                    {
                        m_state = State.Enabled;
                    }
                    return;

                case State.Enabled:
                    if (CheckControl())
                    {
                        break;
                    }
                    m_state = State.Disabled;
                    return;

                case State.Player:
                    // wait for player to give back control, do not reset
                    if (MyAPIGateway.Players.GetPlayerControllingEntity(m_controlledGrid) == null)
                    {
                        m_state = State.Enabled;
                    }
                    return;

                case State.Halted:
                    if (!m_block.AutopilotControl || Globals.ElapsedTime > m_endOfHalt)
                    {
                        m_state = State.Disabled;
                    }
                    return;

                case State.Closed:
                    return;

                default:
                    throw new Exception("Case not implemented: " + m_state);
                }

                if (MyAPIGateway.Players.GetPlayerControllingEntity(m_controlledGrid) != null)
                {
                    m_state = State.Player;
                    return;
                }

                EnemyFinder ef = m_navSet.Settings_Current.EnemyFinder;
                if (ef != null)
                {
                    ef.Update();
                }

                if (m_navSet.Settings_Current.WaitUntil > Globals.ElapsedTime)
                {
                    return;
                }

                if (MoveAndRotate())
                {
                    return;
                }

                if (m_autopilotActions != null)
                {
                    while (true)
                    {
                        if (!m_autopilotActions.MoveNext())
                        {
                            Log.DebugLog("finder: " + m_navSet.Settings_Current.EnemyFinder);
                            m_autopilotActions = null;
                            return;
                        }
                        m_autopilotActions.Current.Invoke(m_pathfinder);
                        if (m_navSet.Settings_Current.WaitUntil > Globals.ElapsedTime)
                        {
                            Log.DebugLog("now waiting until " + m_navSet.Settings_Current.WaitUntil);
                            return;
                        }
                        if (m_navSet.Settings_Current.NavigatorMover != null)
                        {
                            Log.DebugLog("now have a navigator mover: " + m_navSet.Settings_Current.NavigatorMover);
                            return;
                        }
                    }
                }

                if (RotateOnly())
                {
                    return;
                }

                TimeSpan nextInstructions = m_previousInstructions + TimeSpan.FromSeconds(m_navSet.Settings_Current.Complaint != InfoString.StringId.None || ef != null ? 60d : 1d);
                if (nextInstructions > Globals.ElapsedTime)
                {
                    Log.DebugLog("Delaying instructions until " + nextInstructions, Logger.severity.INFO);
                    m_navSet.Settings_Task_NavWay.WaitUntil = nextInstructions;
                    return;
                }
                Log.DebugLog("enqueing instructions", Logger.severity.DEBUG);
                m_previousInstructions = Globals.ElapsedTime;

                m_autopilotActions = m_commands.GetActions();

                if (m_autopilotActions == null || m_autopilotActions.IsEmpty)
                {
                    ReleaseControlledGrid();
                }
                m_navSet.OnStartOfCommands();
                m_mover.MoveAndRotateStop(false);

                if (m_commands.HasSyntaxErrors)
                {
                    m_navSet.Settings_Task_NavWay.WaitUntil = Globals.ElapsedTime + TimeSpan.FromMinutes(1d);
                }
            }
            catch (Exception ex)
            {
                Log.AlwaysLog("Commands: " + m_commands.Commands, Logger.severity.DEBUG);
                Log.AlwaysLog("Exception: " + ex, Logger.severity.ERROR);
                m_state = State.Halted;
            }
            finally
            { lock_execution.ReleaseExclusive(); }
        }
Пример #18
0
        /// <summary>
        /// Rebuilds our conveyor dictionary.  This lets us check if two entities are connected by conveyors quickly.
        /// </summary>
        /// <param name="entities"></param>
        public static void RebuildConveyorList(HashSet <IMyEntity> entities)
        {
            if (!m_busyLock.TryAcquireExclusive())
            {
                Logging.Instance.WriteLine(string.Format("REBUILD Busy.  Last Rebuild: {0}s", (DateTime.Now - m_lastRebuild).TotalSeconds));
                return;
            }

            m_lastRebuild = DateTime.Now;
            DateTime start = DateTime.Now;

            try
            {
                m_conveyorCache.Clear();
                m_conveyorConnected.Clear();
                foreach (IMyEntity entity in entities)
                {
                    if (!(entity is IMyCubeGrid))
                    {
                        continue;
                    }

                    MyCubeGrid grid = (MyCubeGrid)entity;
                    if (grid.Closed || grid.Physics == null)
                    {
                        continue;
                    }

                    MyObjectBuilder_CubeGrid gridObject = (MyObjectBuilder_CubeGrid)grid.GetObjectBuilder();

                    if (gridObject == null || gridObject.ConveyorLines == null)
                    {
                        continue;
                    }

                    foreach (MyObjectBuilder_ConveyorLine line in gridObject.ConveyorLines)
                    {
                        IMySlimBlock slimBlockStart = grid.GetCubeBlock((Vector3I)line.StartPosition);
                        if (slimBlockStart == null || slimBlockStart.FatBlock == null || !slimBlockStart.FatBlock.IsFunctional)
                        {
                            continue;
                        }

                        IMySlimBlock slimBlockEnd = grid.GetCubeBlock((Vector3I)line.EndPosition);
                        if (slimBlockEnd == null || slimBlockEnd.FatBlock == null || !slimBlockEnd.FatBlock.IsFunctional)
                        {
                            continue;
                        }

                        ConnectConveyorBlocks(slimBlockStart, slimBlockEnd);
                    }

                    if (m_conveyorConnected.ContainsKey(grid.EntityId))
                    {
                        long[] connectedBlockId = m_conveyorConnected[grid.EntityId];
                        m_conveyorConnected.Remove(grid.EntityId);
                        ConnectConveyorBlocks(connectedBlockId);
                    }
                }

                foreach (KeyValuePair <long, long[]> p in m_conveyorConnected)
                {
                    ConnectConveyorBlocks(p.Value);
                }

                var creatingCache = new Dictionary <long, HashSet <long> >(m_conveyorCache);
                using (m_lock.AcquireExclusiveUsing())
                {
                    m_creatingCache = creatingCache;
                }
            }
            catch (Exception ex)
            {
                Logging.Instance.WriteLine(String.Format("RebuildConveyorList: {0}", ex.ToString()));
            }
            finally
            {
                m_busyLock.ReleaseExclusive();
                Logging.Instance.WriteLine(string.Format("REBUILD Inventory: {0}ms", (DateTime.Now - start).TotalMilliseconds));
            }
        }
Пример #19
0
        /// <summary>
        /// Test a path between current position and destination.
        /// </summary>
        private void TestPath(Vector3D destination, MyEntity ignoreEntity, byte runId, bool isAlternate, bool tryAlternates, bool slowDown = false)
        {
            m_logger.debugLog("m_navBlock == null", Logger.severity.FATAL, condition: m_navBlock == null);

            if (runId != m_runId)
            {
                m_logger.debugLog("destination changed, abort", Logger.severity.DEBUG);
                return;
            }

            if (!lock_testPath.TryAcquireExclusive())
            {
                m_logger.debugLog("Already running, requeue (destination:" + destination + ", ignoreEntity: " + ignoreEntity.getBestName() + ", runId :" + runId
                                  + ", isAlternate: " + isAlternate + ", tryAlternates: " + tryAlternates + ", slowDown: " + slowDown + ")");
                LockedQueue <Action> queue = isAlternate ? m_pathLow : m_pathHigh;
                queue.Enqueue(() => TestPath(destination, ignoreEntity, runId, isAlternate, tryAlternates));
                return;
            }
            try
            {
                if (m_grid != m_navBlock.Grid)
                {
                    m_logger.debugLog("Grid has changed, from " + m_grid.getBestName() + " to " + m_navBlock.Grid.getBestName() + ", nav block: " + m_navBlock.Block.getBestName(), Logger.severity.WARNING);
                    return;
                }
                m_logger.debugLog("Running, (destination:" + destination + ", ignoreEntity: " + ignoreEntity.getBestName() + ", runId :" + runId
                                  + ", isAlternate: " + isAlternate + ", tryAlternates: " + tryAlternates + ", slowDown: " + slowDown + ")");

                MyEntity obstructing;
                Vector3? pointOfObstruction;

                if (!isAlternate && !m_ignoreAsteroid)
                {
                    if (slowDown)
                    {
                        if ((m_planetCheckSpeed.CurrentState & PlanetChecker.State.Blocked) != 0)
                        {
                            float speed = Vector3.Distance(m_planetCheckSpeed.ObstructionPoint, m_navBlock.WorldPosition) * 0.1f;
                            if (speed < 1f)
                            {
                                speed = 1f;
                            }
                            m_navSet.Settings_Task_NavWay.SpeedTarget = speed;
                            m_logger.debugLog("Path blocked by planet, set SpeedTarget to " + speed + ", obstructed by planet", Logger.severity.TRACE);
                            return;
                        }
                    }
                    else
                    {
                        if ((m_planetCheckDest.CurrentState & PlanetChecker.State.Blocked) != 0 &&
                            // planet checker is using an older displacement so verify that obstruction is closer than destination
                            Vector3D.DistanceSquared(m_navBlock.WorldPosition, m_planetCheckDest.ObstructionPoint) < Vector3D.DistanceSquared(m_navBlock.WorldPosition, destination))
                        {
                            m_logger.debugLog("path blocked by planet, to destination: " + (destination - m_navBlock.WorldPosition) + ", to obstruction: " + (m_planetCheckDest.ObstructionPoint - m_navBlock.WorldPosition));

                            if (m_pathState < PathState.Searching)
                            {
                                m_pathState = PathState.Searching;
                            }
                            obstructing = m_planetCheckDest.gravcomp;

                            Vector3 direction = Vector3.Normalize(m_navBlock.WorldPosition - obstructing.GetCentre());
                            pointOfObstruction = m_planetCheckDest.ObstructionPoint + direction * 1e3f;

                            float distance = Vector3.Distance(m_navBlock.WorldPosition, pointOfObstruction.Value);

                            MoveObstruction = obstructing;
                            m_pathHigh.Clear();
                            ClearAltPath();
                            if ((m_planetCheckDest.CurrentState & PlanetChecker.State.BlockedPath) != 0)
                            {
                                FindAlternate_AroundObstruction(pointOfObstruction.Value - m_navBlock.WorldPosition, new Vector3[] { direction }, 1e4f, runId);
                            }
                            else                             // blocked by gravity
                            {
                                FindAlternate_AroundObstruction(pointOfObstruction.Value - m_navBlock.WorldPosition, new Vector3[] { direction }, 1e6f, runId);
                            }
                            m_pathLow.Enqueue(() => {
                                if (m_altPath_AlternatesFound != 0)
                                {
                                    SetWaypoint();
                                }
                                RunItem();
                            });
                            m_pathLow.Enqueue(() => m_pathState = PathState.Path_Blocked);

                            return;
                        }
                    }
                }

                // for alternates, check that it can be better than current value
                if (isAlternate)
                {
                    float distToWaypointSquared = (float)Vector3D.DistanceSquared(m_navBlock.WorldPosition, destination);
                    if (distToWaypointSquared * WaypointDistanceBias * WaypointDistanceBias > m_altPath_PathValue * m_altPath_PathValue)
                    {
                        m_logger.debugLog("no point in checking alternate path, bias is too high", Logger.severity.TRACE);
                        m_logger.debugLog("no alternate, yet path value is set", Logger.severity.ERROR, condition: m_altPath_AlternatesFound == 0);
                        IncrementAlternatesFound();
                        return;
                    }
                }

                if (m_pathChecker.TestFast(m_navBlock, destination, m_ignoreAsteroid, ignoreEntity, m_landing))
                {
                    m_logger.debugLog("path is clear (fast)", Logger.severity.TRACE);
                    PathClear(ref destination, runId, isAlternate, slowDown);
                    return;
                }

                if (m_pathChecker.TestSlow(out obstructing, out pointOfObstruction))
                {
                    m_logger.debugLog("path is clear (slow)", Logger.severity.TRACE);
                    PathClear(ref destination, runId, isAlternate, slowDown);
                    return;
                }

                if (runId != m_runId)
                {
                    m_logger.debugLog("destination changed, abort", Logger.severity.DEBUG);
                    return;
                }

                if (slowDown)
                {
                    float speed = Vector3.Distance(pointOfObstruction.Value, m_navBlock.WorldPosition) * 0.1f;
                    if (speed < 1f)
                    {
                        speed = 1f;
                    }
                    IMyEntity destEntity = m_navSet.Settings_Current.DestinationEntity;
                    if (destEntity != null)
                    {
                        destEntity = destEntity.GetTopMostParent();
                    }
                    if (obstructing.GetTopMostParent() == destEntity)
                    {
                        m_navSet.Settings_Task_NavWay.SpeedMaxRelative = speed;
                        m_logger.debugLog("Set SpeedMaxRelative to " + speed + ", obstructing: " + obstructing.getBestName() + ", DestinationEntity: " + m_navSet.Settings_Current.DestinationEntity.getBestName(), Logger.severity.TRACE);
                    }
                    else
                    {
                        m_navSet.Settings_Task_NavWay.SpeedTarget = speed;
                        m_logger.debugLog("Set SpeedTarget to " + speed + ", obstructing: " + obstructing.getBestName() + ", DestinationEntity: " + m_navSet.Settings_Current.DestinationEntity.getBestName(), Logger.severity.TRACE);
                    }
                    return;
                }

                if (m_pathState < PathState.Searching)
                {
                    m_pathState = PathState.Searching;
                }

                m_logger.debugLog("path is blocked by " + obstructing.getBestName() + " at " + pointOfObstruction + ", ignoreEntity: " + ignoreEntity.getBestName(), isAlternate ? Logger.severity.TRACE : Logger.severity.DEBUG);
                m_logger.debugLog("grid: " + obstructing.GetTopMostParent().DisplayName, isAlternate ? Logger.severity.TRACE : Logger.severity.DEBUG, condition: obstructing is IMyCubeBlock);

                if (isAlternate && m_altPath_AlternatesFound != 0)
                {
                    IncrementAlternatesFound();
                }

                if (tryAlternates)
                {
                    //float angle = m_navSet.Settings_Current.DistanceAngle;
                    //if (angle > 0.1f && CanRotate)
                    //{
                    //	m_logger.debugLog("wait for rotation", "TestPath()");
                    //	return;
                    //}

                    if (m_navSet.Settings_Task_NavEngage.NavigatorMover != m_navSet.Settings_Current.NavigatorMover)
                    {
                        m_logger.debugLog("obstructed while flying to a waypoint, throwing it out and starting over", Logger.severity.DEBUG);
                        m_navSet.OnTaskComplete_NavWay();
                        return;
                    }

                    ClearAltPath();
                    MoveObstruction = obstructing;
                    TryAlternates(runId, pointOfObstruction.Value, obstructing);
                }
            }
            finally
            {
                lock_testPath.ReleaseExclusive();
                RunItem();
            }
        }