internal void SetAgentArrivedAtDestination(UUID id) { lock (m_agentsInTransit) { if (!m_agentsInTransit.ContainsKey(id)) { m_log.WarnFormat( "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but no teleport request is active", m_mod.Scene.RegionInfo.RegionName, id); return; } AgentTransferState currentState = m_agentsInTransit[id]; if (currentState == AgentTransferState.ReceivedAtDestination) { // An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification. m_log.WarnFormat( "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but notification has already previously been received", m_mod.Scene.RegionInfo.RegionName, id); } else if (currentState != AgentTransferState.Transferring) { m_log.ErrorFormat( "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but agent is in state {2}", m_mod.Scene.RegionInfo.RegionName, id, currentState); return; } m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination; } }
/// <summary> /// Updates the state of an agent that is already in transit. /// </summary> /// <param name='id'></param> /// <param name='newState'></param> /// <returns></returns> /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> internal void UpdateInTransit(UUID id, AgentTransferState newState) { lock (m_agentsInTransit) { // Illegal to try and update an agent that's not actually in transit. if (!m_agentsInTransit.ContainsKey(id)) { throw new Exception( string.Format( "Agent with ID {0} is not registered as in transit in {1}", id, m_mod.Scene.RegionInfo.RegionName)); } AgentTransferState oldState = m_agentsInTransit[id]; bool transitionOkay = false; if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) { transitionOkay = true; } else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) { transitionOkay = true; } else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) { transitionOkay = true; } if (transitionOkay) { m_agentsInTransit[id] = newState; } else { throw new Exception( string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); } } }
internal bool WaitForAgentArrivedAtDestination(UUID id) { if (!m_mod.WaitForAgentArrivedAtDestination) { return(true); } lock (m_agentsInTransit) { if (!IsInTransit(id)) { throw new Exception( string.Format( "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", id, m_mod.Scene.RegionInfo.RegionName)); } AgentTransferState currentState = m_agentsInTransit[id]; if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) { throw new Exception( string.Format( "Asked to wait for destination callback for agent with ID {0} in {1} but agent is in state {2}", id, m_mod.Scene.RegionInfo.RegionName, currentState)); } } int count = 200; // There should be no race condition here since no other code should be removing the agent transfer or // changing the state to another other than Transferring => ReceivedAtDestination. while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) { // m_log.Debug(" >>> Waiting... " + count); Thread.Sleep(100); } return(count > 0); }
/// <summary> /// Removes an agent from the transit state machine. /// </summary> /// <param name='id'></param> /// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns> internal bool ResetFromTransit(UUID id) { lock (m_agentsInTransit) { if (m_agentsInTransit.ContainsKey(id)) { AgentTransferState state = m_agentsInTransit[id]; // if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) // { // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed // to be handled properly - ResetFromTransit() could be invoked at any step along the process // m_log.WarnFormat( // "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", // id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); // throw new Exception( // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", // state, AgentTransferState.CleaningUp); // } m_agentsInTransit.Remove(id); // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", // id, m_mod.Scene.RegionInfo.RegionName); return(true); } } // m_log.WarnFormat( // "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", // id, m_mod.Scene.RegionInfo.RegionName); return(false); }
/// <summary> /// Updates the state of an agent that is already in transit. /// </summary> /// <param name='id'></param> /// <param name='newState'></param> /// <returns></returns> /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> internal bool UpdateInTransit(UUID id, AgentTransferState newState) { // m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); bool transitionOkay = false; // We don't want to throw an exception on cancel since this can come it at any time. bool failIfNotOkay = true; // Should be a failure message if failure is not okay. string failureMessage = null; AgentTransferState?oldState = null; lock (m_agentsInTransit) { // Illegal to try and update an agent that's not actually in transit. if (!m_agentsInTransit.ContainsKey(id)) { if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting) { failureMessage = string.Format( "Agent with ID {0} is not registered as in transit in {1}", id, m_mod.Scene.RegionInfo.RegionName); } else { failIfNotOkay = false; } } else { oldState = m_agentsInTransit[id]; if (newState == AgentTransferState.Aborting) { transitionOkay = true; } else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) { transitionOkay = true; } else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) { transitionOkay = true; } else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) { transitionOkay = true; } else { if (newState == AgentTransferState.Cancelling && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) { transitionOkay = true; } else { failIfNotOkay = false; } } if (!transitionOkay) { failureMessage = string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); } } if (transitionOkay) { m_agentsInTransit[id] = newState; // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); } else if (failIfNotOkay) { m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage); throw new Exception(failureMessage); } // else // { // if (oldState != null) // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); // else // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", // id, newState, m_mod.Scene.Name); // } } return(transitionOkay); }
/// <summary> /// Updates the state of an agent that is already in transit. /// </summary> /// <param name='id'></param> /// <param name='newState'></param> /// <returns></returns> /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> internal bool UpdateInTransit(UUID id, AgentTransferState newState) { m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); bool transitionOkay = false; // We don't want to throw an exception on cancel since this can come it at any time. bool failIfNotOkay = true; // Should be a failure message if failure is not okay. string failureMessage = null; AgentTransferState? oldState = null; lock (m_agentsInTransit) { // Illegal to try and update an agent that's not actually in transit. if (!m_agentsInTransit.ContainsKey(id)) { if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting) failureMessage = string.Format( "Agent with ID {0} is not registered as in transit in {1}", id, m_mod.Scene.RegionInfo.RegionName); else failIfNotOkay = false; } else { oldState = m_agentsInTransit[id]; if (newState == AgentTransferState.Aborting) { transitionOkay = true; } else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) { transitionOkay = true; } else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) { transitionOkay = true; } else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) { transitionOkay = true; } else { if (newState == AgentTransferState.Cancelling && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) { transitionOkay = true; } else { failIfNotOkay = false; } } if (!transitionOkay) failureMessage = string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); } if (transitionOkay) { m_agentsInTransit[id] = newState; // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); } else if (failIfNotOkay) { m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage); throw new Exception(failureMessage); } // else // { // if (oldState != null) // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); // else // m_log.DebugFormat( // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", // id, newState, m_mod.Scene.Name); // } } return transitionOkay; }
/// <summary> /// Updates the state of an agent that is already in transit. /// </summary> /// <param name='id'></param> /// <param name='newState'></param> /// <returns></returns> /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> internal void UpdateInTransit(UUID id, AgentTransferState newState) { lock (m_agentsInTransit) { // Illegal to try and update an agent that's not actually in transit. if (!m_agentsInTransit.ContainsKey(id)) throw new Exception( string.Format( "Agent with ID {0} is not registered as in transit in {1}", id, m_mod.Scene.RegionInfo.RegionName)); AgentTransferState oldState = m_agentsInTransit[id]; bool transitionOkay = false; if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) transitionOkay = true; else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) transitionOkay = true; else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) transitionOkay = true; if (transitionOkay) m_agentsInTransit[id] = newState; else throw new Exception( string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); } }