Exemple #1
0
        private void GridSearch_Friend()
        {
            int          bestNameLength = int.MaxValue;
            RelayStorage store          = m_netStore;

            if (store == null)
            {
                Log.DebugLog("no storage", Logger.severity.DEBUG);
                return;
            }

            store.SearchLastSeen(seen => {
                IMyCubeGrid grid = seen.Entity as IMyCubeGrid;
                if (grid != null && grid.DisplayName.Length < bestNameLength && grid.DisplayName.LowerRemoveWhitespace().Contains(m_targetGridName) && CanTarget(seen))
                {
                    Grid           = seen;
                    bestNameLength = grid.DisplayName.Length;
                    if (bestNameLength == m_targetGridName.Length)
                    {
                        Log.DebugLog("perfect match LastSeen: " + seen.Entity.getBestName());
                        return(true);
                    }
                }
                return(false);
            });

            if (Grid != null)
            {
                Log.DebugLog("Best match LastSeen: " + Grid.Entity.getBestName());
            }
        }
        /// <summary>
        /// Search every possible ore detector for materials.
        /// </summary>
        /// <param name="requester">Must be able to control OreDetector and have same NetworkStorage</param>
        /// <param name="oreType">Voxel materials to search for</param>
        public static void SearchForMaterial(ShipControllerBlock requester, byte[] oreType, OreSearchComplete onComplete)
        {
            Vector3D     position = requester.CubeBlock.GetPosition();
            RelayStorage storage  = requester.NetworkStorage;

            Static.m_thread.EnqueueAction(() => {
                List <OreDetector> oreDetectors = ResourcePool <List <OreDetector> > .Get();
                Registrar.ForEach((OreDetector detector) => {
                    if (detector.Block.IsWorking && requester.CubeBlock.canControlBlock(detector.Block) && detector.m_netClient.GetStorage() == storage)
                    {
                        oreDetectors.Add(detector);
                    }
                });

                IOrderedEnumerable <OreDetector> sorted = oreDetectors.OrderBy(detector => Vector3D.DistanceSquared(position, detector.Block.GetPosition()));

                foreach (OreDetector detector in sorted)
                {
                    if (detector.GetOreLocations(position, oreType, onComplete))
                    {
                        return;
                    }
                }

                oreDetectors.Clear();
                ResourcePool <List <OreDetector> > .Return(oreDetectors);

                onComplete(false, null, null, null);
            });
        }
Exemple #3
0
 /// <summary>
 /// Read the data from the storage.
 /// </summary>
 public void ReadFromStorage()
 {
     try
     {
         this.Endpoint = RelayStorage.ReadEndpoint();
         this.Groups   = RelayStorage.ReadGroups();
         this.Messages = RelayStorage.ReadMessages();
     }
     catch (Exception)
     {
         // Let's not to crash the client.
     }
 }
Exemple #4
0
 /// <summary>
 /// Save the data into the storage.
 /// </summary>
 public void SaveToStorage()
 {
     try
     {
         RelayStorage.SaveEndpoint(this.Endpoint);
         RelayStorage.SaveGroups(this.Groups);
         RelayStorage.SaveMessages(this.Messages);
     }
     catch (Exception)
     {
         // Let's not to crash the client.
     }
 }
Exemple #5
0
        private void GridUpdate()
        {
            Log.DebugLog("Grid == null", Logger.severity.FATAL, condition: Grid == null);

            if (!Grid.IsValid)
            {
                Log.DebugLog("no longer valid: " + Grid.Entity.getBestName(), Logger.severity.DEBUG);
                Grid = null;
                return;
            }

            if (m_mustBeRecent && !Grid.isRecent())
            {
                Log.DebugLog("no longer recent: " + Grid.Entity.getBestName() + ", age: " + (Globals.ElapsedTime - Grid.LastSeenAt));
                Grid = null;
                return;
            }

            if (!CanTarget(Grid))
            {
                Log.DebugLog("can no longer target: " + Grid.Entity.getBestName(), Logger.severity.DEBUG);
                Grid = null;
                return;
            }

            RelayStorage storage = m_netStore;

            if (storage == null)
            {
                Log.DebugLog("lost storage", Logger.severity.DEBUG);
                Grid = null;
                return;
            }

            LastSeen updated;

            if (!m_netStore.TryGetLastSeen(Grid.Entity.EntityId, out updated))
            {
                Log.AlwaysLog("Where does the good go? Searching for " + Grid.Entity.EntityId, Logger.severity.WARNING);
                Grid = null;
                return;
            }

            //Log.DebugLog("updating grid last seen " + Grid.LastSeenAt + " => " + updated.LastSeenAt, "GridUpdate()");
            Grid = updated;
        }
Exemple #6
0
        private void UpdateLastSeen()
        {
            RelayStorage store = m_controlBlock.NetworkStorage;

            if (store == null)
            {
                Log.DebugLog("failed to get storage", Logger.severity.INFO);
                m_character = null;
                return;
            }

            if (m_character != null)
            {
                if (store.TryGetLastSeen(m_character.Entity.EntityId, out m_character))
                {
                    Log.DebugLog("got updated last seen");
                    return;
                }
                else
                {
                    Log.DebugLog("failed to update last seen", Logger.severity.WARNING);
                    m_character = null;
                    m_timeoutAt = Globals.ElapsedTime + timeout;
                }
            }

            store.SearchLastSeen((LastSeen seen) => {
                Log.DebugLog("seen: " + seen.Entity.getBestName());
                if (seen.Entity is IMyCharacter && seen.Entity.DisplayName.LowerRemoveWhitespace().Contains(m_charName))
                {
                    Log.DebugLog("found a last seen for character");
                    m_character = seen;
                    return(true);
                }
                return(false);
            });

            Log.DebugLog("failed to find a character from last seen", condition: m_character == null);
        }
Exemple #7
0
        /// <summary>
        /// Updates myAntenna and sends LastSeen of this missile to launcher.
        /// </summary>
        private void UpdateNetwork()
        {
            if (myAntenna != null)
            {
                myAntenna.Update100();
            }

            if (m_launcherRelay == null)
            {
                Log.DebugLog("No launcher client", Logger.severity.WARNING);
                return;
            }

            RelayStorage store = m_launcherRelay.GetStorage();

            if (store == null)
            {
                Log.DebugLog("Launcher's net client does not have a storage", Logger.severity.WARNING);
                return;
            }

            //Log.DebugLog("Updating launcher with location of this missile", "UpdateNetwork()");
            store.Receive(new LastSeen(MyEntity, LastSeen.DetectedBy.None));
        }
        private InitialTargetStatus GetInitialTarget()
        {
            if (loadedAmmo == null || loadedAmmo.MissileDefinition == null)
            {
                Log.DebugLog("no ammo");
                return(InitialTargetStatus.NotReady);
            }

            if (m_weaponTarget.Options.TargetGolis.IsValid())
            {
                Log.TraceLog("golis: " + m_weaponTarget.Options.TargetGolis);
                m_weaponTarget.SetTarget(new GolisTarget(CubeBlock, m_weaponTarget.Options.TargetGolis));
                return(InitialTargetStatus.Golis);
            }

            if (m_weaponTarget.CurrentControl != WeaponTargeting.Control.Off && !(m_weaponTarget.CurrentTarget is NoTarget))
            {
                Log.TraceLog("from active weapon, control: " + m_weaponTarget.CurrentControl + ", target: " + m_weaponTarget.CurrentTarget);
                return(InitialTargetStatus.FromWeapon);
            }
            else
            {
                Log.TraceLog("clearing weapon target");
                m_weaponTarget.SetTarget(NoTarget.Instance);
            }

            RelayStorage storage = m_relayPart.GetStorage();

            if (storage == null)
            {
                Log.TraceLog("Failed to get storage for launcher");
                return(InitialTargetStatus.NoStorage);
            }
            else
            {
                ITerminalProperty <float> rangeProperty = CubeBlock.GetProperty("Range") as ITerminalProperty <float>;
                if (rangeProperty == null)
                {
                    Logger.AlwaysLog("rangeProperty == null", Logger.severity.FATAL);
                    return(InitialTargetStatus.NotReady);
                }
                float range = rangeProperty.GetValue(CubeBlock);
                if (range < 1f)
                {
                    range = loadedAmmo.MissileDefinition.MaxTrajectory;
                }
                m_weaponTarget.GetLastSeenTarget(storage, range);
                if (!(m_weaponTarget.CurrentTarget is NoTarget))
                {
                    Log.TraceLog("LastSeen: " + m_weaponTarget.CurrentTarget.Entity.nameWithId());
                    return(InitialTargetStatus.FromWeapon);
                }
                else if (m_weaponTarget.Options.TargetEntityId != 0)
                {
                    return(InitialTargetStatus.NotFoundId);
                }
                else
                {
                    return(InitialTargetStatus.NotFoundAny);
                }
            }
        }
Exemple #9
0
        private void GridSearch_Enemy()
        {
            RelayStorage store = m_netStore;

            if (store == null)
            {
                Log.DebugLog("no storage", Logger.severity.DEBUG);
                return;
            }

            if (m_targetEntityId != 0L)
            {
                LastSeen target;
                if (store.TryGetLastSeen(m_targetEntityId, out target) && CanTarget(target))
                {
                    Grid = target;
                    Log.DebugLog("found target: " + target.Entity.getBestName());
                }
                else
                {
                    Grid = null;
                }
                return;
            }

            List <LastSeen> enemies = ResourcePool <List <LastSeen> > .Get();

            Vector3D position = m_controlBlock.CubeBlock.GetPosition();

            store.SearchLastSeen(seen => {
                if (!seen.IsValid || !seen.isRecent())
                {
                    return(false);
                }

                IMyCubeGrid asGrid = seen.Entity as IMyCubeGrid;
                if (asGrid == null)
                {
                    return(false);
                }
                if (!m_controlBlock.CubeBlock.canConsiderHostile(asGrid))
                {
                    return(false);
                }

                enemies.Add(seen);
                Log.DebugLog("enemy: " + asGrid.DisplayName);
                return(false);
            });

            Log.DebugLog("number of enemies: " + enemies.Count);
            IOrderedEnumerable <LastSeen> enemiesByDistance = enemies.OrderBy(OrderValue != null ? OrderValue : seen => Vector3D.DistanceSquared(position, seen.GetPosition()));

            m_reason = ReasonCannotTarget.None;
            foreach (LastSeen enemy in enemiesByDistance)
            {
                if (CanTarget(enemy))
                {
                    Grid = enemy;
                    Log.DebugLog("found target: " + enemy.Entity.getBestName());
                    enemies.Clear();
                    ResourcePool <List <LastSeen> > .Return(enemies);

                    return;
                }
            }

            Grid = null;
            Log.DebugLog("nothing found");
            enemies.Clear();
            ResourcePool <List <LastSeen> > .Return(enemies);
        }
Exemple #10
0
        /// <summary>
        /// Targets a LastSeen chosen from the given storage, will overrride current target.
        /// </summary>
        /// <param name="storage">NetworkStorage to get LastSeen from.</param>
        public void GetLastSeenTarget(RelayStorage storage, double range)
        {
            if (Globals.UpdateCount < m_nextLastSeenSearch)
            {
                return;
            }
            m_nextLastSeenSearch = Globals.UpdateCount + 100ul;

            if (storage == null)
            {
                //Log.DebugLog("no storage", "GetLastSeenTarget()", Logger.severity.INFO);
                return;
            }

            if (storage.LastSeenCount == 0)
            {
                //Log.DebugLog("no last seen in storage", "GetLastSeenTarget()", Logger.severity.DEBUG);
                return;
            }

            LastSeen     processing;
            IMyCubeBlock targetBlock;

            if (CurrentTarget.Entity != null && storage.TryGetLastSeen(CurrentTarget.Entity.EntityId, out processing) && processing.isRecent())
            {
                LastSeenTarget lst = myTarget as LastSeenTarget;
                if (lst != null && lst.Block != null && !lst.Block.Closed)
                {
                    Log.TraceLog("Updating current last seen target");
                    lst.Update(processing);
                    CurrentTarget = myTarget;
                    return;
                }

                if (ChooseBlock(processing, out targetBlock))
                {
                    Log.TraceLog("Updating current last seen, chose a new block");
                    myTarget      = new LastSeenTarget(processing, targetBlock);
                    CurrentTarget = myTarget;
                    return;
                }
            }

            if (Options.TargetEntityId > 0L)
            {
                if (storage.TryGetLastSeen(Options.TargetEntityId, out processing))
                {
                    Log.TraceLog("Got last seen for entity id");
                    ChooseBlock(processing, out targetBlock);
                    myTarget      = new LastSeenTarget(processing, targetBlock);
                    CurrentTarget = myTarget;
                }
                //else
                //	Log.DebugLog("failed to get last seen from entity id", "GetLastSeenTarget()");
                return;
            }

            processing  = null;
            targetBlock = null;

            if (SEAD)
            {
                throw new NotImplementedException();
                //float highestPowerLevel = 0f;

                //storage.ForEachLastSeen((LastSeen seen) => {
                //	if (seen.isRecent() && Options.CanTargetType(seen.Entity) && CanConsiderHostile(seen.Entity))
                //	{
                //		IMyCubeBlock block;
                //		float powerLevel;
                //		if (RadarEquipment_old.GetRadarEquipment(seen, out block, out powerLevel) && powerLevel > highestPowerLevel)
                //		{
                //			highestPowerLevel = powerLevel;
                //			processing = seen;
                //			targetBlock = block;
                //		}
                //	}
                //});
            }
            else
            {
                Vector3D   myPos       = ProjectilePosition();
                TargetType bestType    = TargetType.LowestPriority;
                double     maxRange    = range * range;
                double     closestDist = maxRange;

                storage.ForEachLastSeen(seen => {
                    TargetType typeOfSeen = TargetingOptions.GetTargetType(seen.Entity);
                    if (typeOfSeen <= bestType && Options.CanTargetType(typeOfSeen) && seen.isRecent() && CanConsiderHostile(seen.Entity))
                    {
                        IMyCubeBlock block;
                        if (!ChooseBlock(seen, out block) || !CheckWeaponsTargeting(typeOfSeen, seen.Entity))
                        {
                            return;
                        }

                        if (typeOfSeen == bestType && targetBlock != null && block == null)
                        {
                            return;
                        }

                        double dist = Vector3D.DistanceSquared(myPos, seen.LastKnownPosition);
                        if ((typeOfSeen < bestType && dist < maxRange) || dist < closestDist)
                        {
                            closestDist = dist;
                            bestType    = typeOfSeen;
                            processing  = seen;
                            targetBlock = block;
                        }
                    }
                });

                Log.DebugLog(() => "chose last seen with entity: " + processing.Entity.nameWithId() + ", block: " + targetBlock.getBestName() + ", type: " + bestType + ", distance squared: " + closestDist + ", position: " + processing.Entity.GetPosition(), condition: processing != null);
                Log.DebugLog("no last seen target found", condition: processing == null);
            }

            if (processing == null)
            {
                if (this is Guided.GuidedMissile)
                {
                    Log.TraceLog("GuidedMissile failed to get LastSeen target, keeping previous");
                    return;
                }

                //Log.DebugLog("failed to get a target from last seen", "GetLastSeenTarget()");
                myTarget      = NoTarget.Instance;
                CurrentTarget = myTarget;
            }
            else
            {
                myTarget      = new LastSeenTarget(processing, targetBlock);
                CurrentTarget = myTarget;
            }
        }
Exemple #11
0
        private void LoadSaveData(Builder_ArmsData data)
        {
            if (data == null)
            {
                Logger.DebugLog("No data to load");
                return;
            }

#pragma warning disable 612, 618
            if (Comparer <Version> .Default.Compare(data.ArmsVersion, default(Version)) == 0)
            {
                Logger.DebugLog("Old version: " + data.ModVersion);
                data.ArmsVersion = new Version(data.ModVersion);
            }
#pragma warning restore 612, 618

            Logger.AlwaysLog("Save version: " + data.ArmsVersion, Rynchodon.Logger.severity.INFO);

            // relay

            Dictionary <Message.Builder_Message, Message> messages = MyAPIGateway.Multiplayer.IsServer ? new Dictionary <Message.Builder_Message, Message>() : null;
            SerializableGameTime.Adjust = new TimeSpan(data.SaveTime);
            foreach (RelayStorage.Builder_NetworkStorage bns in data.AntennaStorage)
            {
                RelayNode node;
                if (!Registrar.TryGetValue(bns.PrimaryNode, out node))
                {
                    Logger.AlwaysLog("Failed to get node for: " + bns.PrimaryNode, Rynchodon.Logger.severity.WARNING);
                    continue;
                }
                RelayStorage store = node.Storage;
                if (store == null)                 // probably always true
                {
                    node.ForceCreateStorage();
                    store = node.Storage;
                    if (store == null)
                    {
                        Logger.AlwaysLog("failed to create storage for " + node.DebugName, Rynchodon.Logger.severity.ERROR);
                        continue;
                    }
                }

                foreach (LastSeen.Builder_LastSeen bls in bns.LastSeenList)
                {
                    LastSeen ls = new LastSeen(bls);
                    if (ls.IsValid)
                    {
                        store.Receive(ls);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to create a valid last seen from builder for " + bls.EntityId, Rynchodon.Logger.severity.WARNING);
                        if (m_failedLastSeen == null)
                        {
                            m_failedLastSeen = new CachingDictionary <long, CachingList <LastSeen.Builder_LastSeen> >();
                            UpdateManager.Register(100, RetryLastSeen);
                        }
                        CachingList <LastSeen.Builder_LastSeen> list;
                        if (!m_failedLastSeen.TryGetValue(bns.PrimaryNode, out list))
                        {
                            list = new CachingList <LastSeen.Builder_LastSeen>();
                            m_failedLastSeen.Add(bns.PrimaryNode, list, true);
                        }
                        list.Add(bls);
                        list.ApplyAdditions();
                    }
                }

                Logger.DebugLog("added " + bns.LastSeenList.Length + " last seen to " + store.PrimaryNode.DebugName, Rynchodon.Logger.severity.DEBUG);

                // messages in the save file belong on the server
                if (messages == null)
                {
                    continue;
                }

                foreach (Message.Builder_Message bm in bns.MessageList)
                {
                    Message msg;
                    if (!messages.TryGetValue(bm, out msg))
                    {
                        msg = new Message(bm);
                        messages.Add(bm, msg);
                    }
                    else
                    {
                        Logger.DebugLog("found linked message", Rynchodon.Logger.severity.TRACE);
                    }
                    if (msg.IsValid)
                    {
                        store.Receive(msg);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to create a valid message from builder for " + bm.DestCubeBlock + "/" + bm.SourceCubeBlock, Rynchodon.Logger.severity.WARNING);
                    }
                }

                Logger.DebugLog("added " + bns.MessageList.Length + " message to " + store.PrimaryNode.DebugName, Rynchodon.Logger.severity.DEBUG);
            }

            // past this point, only synchronized data
            if (!MyAPIGateway.Multiplayer.IsServer)
            {
                data = null;
                return;
            }

            // system disruption

            foreach (Disruption.Builder_Disruption bd in data.SystemDisruption)
            {
                Disruption disrupt;
                switch (bd.Type)
                {
                case "AirVentDepressurize":
                    disrupt = new AirVentDepressurize();
                    break;

                case "CryoChamberMurder":
                    disrupt = new CryoChamberMurder();
                    break;

                case "DisableTurret":
                    disrupt = new DisableTurret();
                    break;

                case "DoorLock":
                    disrupt = new DoorLock();
                    break;

                case "EMP":
                    disrupt = new EMP();
                    break;

                case "GravityReverse":
                    disrupt = new GravityReverse();
                    break;

                case "JumpDriveDrain":
                    disrupt = new JumpDriveDrain();
                    break;

                case "MedicalRoom":
                    disrupt = new MedicalRoom();
                    break;

                case "TraitorTurret":
                    disrupt = new TraitorTurret();
                    break;

                default:
                    Logger.AlwaysLog("Unknown disruption: " + bd.Type, Rynchodon.Logger.severity.WARNING);
                    continue;
                }
                disrupt.Start(bd);
            }

            // autopilot

            if (data.Autopilot != null)
            {
                foreach (ShipAutopilot.Builder_Autopilot ba in data.Autopilot)
                {
                    ShipAutopilot autopilot;
                    if (Registrar.TryGetValue(ba.AutopilotBlock, out autopilot))
                    {
                        autopilot.ResumeFromSave(ba);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to find autopilot block " + ba.AutopilotBlock, Rynchodon.Logger.severity.WARNING);
                    }
                }
            }

            // programmable block

            if (data.ProgrammableBlock != null)
            {
                foreach (ProgrammableBlock.Builder_ProgrammableBlock bpa in data.ProgrammableBlock)
                {
                    ProgrammableBlock pb;
                    if (Registrar.TryGetValue(bpa.BlockId, out pb))
                    {
                        pb.ResumeFromSave(bpa);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to find programmable block " + bpa.BlockId, Rynchodon.Logger.severity.WARNING);
                    }
                }
            }

            // text panel

            if (data.TextPanel != null)
            {
                foreach (TextPanel.Builder_TextPanel btp in data.TextPanel)
                {
                    TextPanel panel;
                    if (Registrar.TryGetValue(btp.BlockId, out panel))
                    {
                        panel.ResumeFromSave(btp);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to find text panel " + btp.BlockId, Rynchodon.Logger.severity.WARNING);
                    }
                }
            }

            // weapon

            if (data.Weapon != null)
            {
                foreach (WeaponTargeting.Builder_WeaponTargeting bwt in data.Weapon)
                {
                    WeaponTargeting targeting;
                    if (WeaponTargeting.TryGetWeaponTargeting(bwt.WeaponId, out targeting))
                    {
                        targeting.ResumeFromSave(bwt);
                    }
                    else
                    {
                        Logger.AlwaysLog("failed to find weapon " + bwt.WeaponId, Rynchodon.Logger.severity.WARNING);
                    }
                }
            }

            // entity values

            if (data.EntityValues != null)
            {
                UpgradeEntityValue.Load(data.EntityValues);
            }

            // sync

            if (data.Sync != null)
            {
                ASync.SetBuilder(data.Sync);
            }

            data = null;
        }
Exemple #12
0
        private void RetryLastSeen()
        {
            foreach (KeyValuePair <long, CachingList <LastSeen.Builder_LastSeen> > storageLastSeen in m_failedLastSeen)
            {
                RelayNode node;
                if (Registrar.TryGetValue(storageLastSeen.Key, out node))
                {
                    RelayStorage store = node.Storage;
                    foreach (LastSeen.Builder_LastSeen builder in storageLastSeen.Value)
                    {
                        if (MyAPIGateway.Entities.EntityExists(builder.EntityId))
                        {
                            LastSeen ls = new LastSeen(builder);
                            if (ls.IsValid)
                            {
                                Logger.DebugLog("Successfully created a LastSeen. Primary node: " + storageLastSeen.Key + ", entity: " + ls.Entity.nameWithId());
                                storageLastSeen.Value.Remove(builder);
                            }
                            else
                            {
                                Logger.AlwaysLog("Unknown failure with last seen", Rynchodon.Logger.severity.ERROR);
                            }
                        }
                        else
                        {
                            Logger.DebugLog("Not yet available: " + builder.EntityId);
                        }
                    }
                    storageLastSeen.Value.ApplyRemovals();
                    if (storageLastSeen.Value.Count == 0)
                    {
                        Logger.DebugLog("Finished with: " + storageLastSeen.Key, Rynchodon.Logger.severity.DEBUG);
                        m_failedLastSeen.Remove(storageLastSeen.Key);
                    }
                    else
                    {
                        Logger.DebugLog("For " + storageLastSeen.Key + ", " + storageLastSeen.Value.Count + " builders remain");
                    }
                }
                else
                {
                    Logger.DebugLog("Failed to get node for " + storageLastSeen.Key, Rynchodon.Logger.severity.WARNING);
                }
            }
            m_failedLastSeen.ApplyRemovals();

            if (m_failedLastSeen.Count() == 0)
            {
                Logger.DebugLog("All LastSeen have been successfully added", Rynchodon.Logger.severity.INFO);
                m_failedLastSeen = null;
                UpdateManager.Unregister(100, RetryLastSeen);
            }
            else
            {
                Logger.DebugLog(m_failedLastSeen.Count() + " primary nodes still have last seen to be added");

                if (Globals.UpdateCount >= 3600)
                {
                    foreach (KeyValuePair <long, CachingList <LastSeen.Builder_LastSeen> > storageLastSeen in m_failedLastSeen)
                    {
                        foreach (LastSeen.Builder_LastSeen builder in storageLastSeen.Value)
                        {
                            Logger.AlwaysLog("Failed to add last seen to world. Primary node: " + storageLastSeen.Key + ", entity ID: " + builder.EntityId, Rynchodon.Logger.severity.WARNING);
                        }
                    }
                    m_failedLastSeen = null;
                    UpdateManager.Unregister(100, RetryLastSeen);
                }
            }
        }