private StateMachine<ImportFinancialGuaranteeStatus, Trigger> CreateStateMachine() { var stateMachine = new StateMachine<ImportFinancialGuaranteeStatus, Trigger>(() => Status, s => Status = s); stateMachine.OnTransitioned(OnTransitionAction); completeTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Complete); stateMachine.Configure(ImportFinancialGuaranteeStatus.ApplicationReceived) .Permit(Trigger.Complete, ImportFinancialGuaranteeStatus.ApplicationComplete); stateMachine.Configure(ImportFinancialGuaranteeStatus.ApplicationComplete) .OnEntryFrom(completeTrigger, OnComplete) .Permit(Trigger.Approve, ImportFinancialGuaranteeStatus.Approved) .Permit(Trigger.Refuse, ImportFinancialGuaranteeStatus.Refused); stateMachine.Configure(ImportFinancialGuaranteeStatus.Approved) .Permit(Trigger.Release, ImportFinancialGuaranteeStatus.Released); return stateMachine; }
public Story(EntityWorld world) { Acts = new List<IStoryAct>(new[] { new ActOne() }); State = new StateMachine<StoryUpdateFunction, string>(Acts[0].Master); State.OnTransitioned(OnTransition); for (int i = 0; i < Acts.Count; i++) { var act = Acts[i]; act.ConfigureStates(State); State.Configure(act.Master) .Permit(Triggers.NextAct, i < Acts.Count - 1 ? (StoryUpdateFunction)Acts[i + 1].Master : EndOfStory); } World = world; State.Fire(ActOne.Triggers.Start); }
/// <summary> /// Main client thread. /// </summary> private void ClientThread() { _gameState.Reset(); _connection = DotaGameConnection.CreateWith(_details); _handshake = new DotaHandshake(_details, _gameState, _connection); _signon = new DotaSignon(_gameState, _connection, _details); _game = new DotaGame(_gameState, _connection); _commandGenerator = new UserCmdGenerator(_gameState, _connection); foreach (var cont in Controllers) cont.Initialize(_details.SteamId, _gameState, _commandGenerator); long handshake_requested = 0; long handshake_giveup = new TimeSpan(0, 0, 0, 10).Ticks; // Map states in the StateMachine to handlers var metastates = new Dictionary<States, Metastates>() { { States.HANDSHAKE_REQUEST, Metastates.HANDSHAKE }, { States.HANDSHAKE_CONNECT, Metastates.HANDSHAKE }, { States.CONNECTED, Metastates.SIGNON }, { States.LOADING, Metastates.SIGNON }, { States.PRESPAWN, Metastates.SIGNON }, { States.SPAWN, Metastates.SIGNON }, { States.PLAY, Metastates.GAME }, }; var processors = new Dictionary<Metastates, IHandler>() { { Metastates.HANDSHAKE, _handshake }, { Metastates.SIGNON, _signon }, { Metastates.GAME, _game } }; _stateMachine = new StateMachine<States, Events>(States.DISCONNECTED); //temporary shit _stateMachine.OnTransitioned(transition => { if (transition.Source == transition.Destination) return; Callback?.Invoke(this, new CallbackEventArgs(new DotaGameClient.SessionStateTransition(transition.Source, transition.Destination))); }); _stateMachine.OnUnhandledTrigger((states, events) => { Console.WriteLine("Unhandled trigger: " + events.ToString("G")); }); var disconnected = new Action(() => { if (_connection == null) return; Running = true; Stop(); }); _stateMachine.Configure(States.DISCONNECTED) .Ignore(Events.TICK) .Ignore(Events.DISCONNECTED) .OnEntry(disconnected) .Permit(Events.REQUEST_CONNECT, States.HANDSHAKE_REQUEST); _stateMachine.Configure(States.HANDSHAKE_REJECTED) .Permit(Events.DISCONNECTED, States.DISCONNECTED) .OnEntry(() => { Callback?.Invoke(this, new CallbackEventArgs(new DotaGameClient.HandshakeRejected(_handshake.rejected_reason))); _stateMachine.Fire(Events.DISCONNECTED); }); _stateMachine.Configure(States.HANDSHAKE_REQUEST) .OnEntry(() => handshake_requested = DateTime.Now.Ticks) .OnEntry(_handshake.RequestHandshake) .Ignore(Events.TICK) .Permit(Events.HANDSHAKE_CHALLENGE, States.HANDSHAKE_CONNECT) .Permit(Events.REJECTED, States.HANDSHAKE_REJECTED) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.HANDSHAKE_CONNECT) .OnEntry(_handshake.RespondHandshake) .Ignore(Events.TICK) .PermitReentry(Events.HANDSHAKE_CHALLENGE) // possibly re-enter? .Permit(Events.HANDSHAKE_COMPLETE, States.CONNECTED) .Permit(Events.REJECTED, States.HANDSHAKE_REJECTED) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.CONNECTED) .OnEntry(_signon.EnterConnected) .Ignore(Events.TICK) .Permit(Events.LOADING_START, States.LOADING) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.LOADING) .OnEntry(_signon.EnterNew) .Ignore(Events.TICK) .Permit(Events.CONNECTED, States.CONNECTED) .Permit(Events.PRESPAWN_START, States.PRESPAWN) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.PRESPAWN) .OnEntry(_signon.EnterPrespawn) .Ignore(Events.TICK) .Permit(Events.SPAWNED, States.SPAWN) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.SPAWN) .OnEntry(_signon.EnterSpawn) .Ignore(Events.TICK) .Permit(Events.BASELINE, States.PLAY) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Configure(States.PLAY) .OnEntryFrom(Events.BASELINE, () => { _game.EnterGame(); _commandGenerator.Reset(); }) .OnEntryFrom(Events.TICK, () => { _gameState.Update(); foreach(var cont in Controllers) cont.Tick(); _commandGenerator.Tick(); _gameState.Created.Clear(); _gameState.Deleted.Clear(); }) .PermitReentry(Events.TICK) .Permit(Events.DISCONNECTED, States.DISCONNECTED); _stateMachine.Fire(Events.REQUEST_CONNECT); long next_tick = DateTime.Now.Ticks; while (Running && _stateMachine.State != States.DISCONNECTED && _stateMachine.State != States.HANDSHAKE_REJECTED) { try { if (next_tick > DateTime.Now.Ticks) { Thread.Sleep(1); continue; } if (_stateMachine == null) break; if (_stateMachine.State == States.HANDSHAKE_REQUEST && (DateTime.Now.Ticks - handshake_requested) > handshake_giveup) { _stateMachine.Fire(Events.DISCONNECTED); continue; } if (_connection.state == DotaGameConnection.State.Closed) { _stateMachine.Fire(Events.DISCONNECTED); continue; } if (_connection == null) break; List<byte[]> outBand = _connection.GetOutOfBand(); List<DotaGameConnection.Message> inBand = _connection.GetInBand(); foreach (byte[] message in outBand) { Nullable<Events> e = processors[metastates[_stateMachine.State]].Handle(message); if (e.HasValue) { _stateMachine.Fire(e.Value); } } foreach (DotaGameConnection.Message message in inBand) { Nullable<Events> e = processors[metastates[_stateMachine.State]].Handle(message); if (e.HasValue) { _stateMachine.Fire(e.Value); } } _stateMachine.Fire(Events.TICK); if (_gameState.TickInterval > 0) { next_tick += (uint)(_gameState.TickInterval * 1000 * 10000 /* ticks per ms */); } else { next_tick += 50 * 1000; } int remain = (int)(next_tick - DateTime.Now.Ticks) / 10000; if (remain > 0) { Thread.Sleep(1); } else if (remain < 0) { next_tick = DateTime.Now.Ticks; } } catch (Exception ex) { Callback?.Invoke(this, new CallbackEventArgs(new DotaGameClient.LogMessage("Ignored error in session loop, " + ex.Message))); } } if (Running) Stop(); }
private void ConfigureStateMachine() { _fsm = new StateMachine<State, Trigger>(State.Unmonitored); _fsm.OnTransitioned(OnStateMachineTransitioned); _fsm.Configure(State.Unmonitored) .Permit(Trigger.Watch, State.Connecting) .OnEntry(OnUnmonitoredState); _fsm.Configure(State.Monitored) .Permit(Trigger.Unwatch, State.Unmonitored) .OnEntry(OnMonitoredState); _fsm.Configure(State.Disconnected) .SubstateOf(State.Monitored) .PermitReentry(Trigger.Disconnect) .Permit(Trigger.Connect, State.Connecting) .OnEntry(OnDisconnectedState); _fsm.Configure(State.Connecting) .SubstateOf(State.Disconnected) .Permit(Trigger.Connected, State.Connected) .OnEntry(OnConnectingState); _fsm.Configure(State.Restarting) .SubstateOf(State.Disconnected) .Permit(Trigger.Connected, State.Connected); _fsm.Configure(State.Upgrading) .SubstateOf(State.Disconnected) .Permit(Trigger.Connected, State.Connected); _fsm.Configure(State.Connected) .SubstateOf(State.Monitored) .Permit(Trigger.Restart, State.Restarting) .Permit(Trigger.Upgrade, State.Upgrading) .Permit(Trigger.Disconnect, State.Disconnected) .Permit(Trigger.Disconnected, State.Disconnected) .OnEntry(OnConnectedState) .OnExit(OnConnectedStateExit); }
private StateMachine<NotificationStatus, Trigger> CreateStateMachine() { var stateMachine = new StateMachine<NotificationStatus, Trigger>(() => Status, s => Status = s); receivedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.NotificationReceived); commencedTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.AssessmentCommenced); completeTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.NotificationComplete); transmitTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Transmit); acknowledgedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Acknowledged); withdrawTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.Withdraw); objectTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.Object); withdrawConsentTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.WithdrawConsent); consentedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Consent); archiveTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Archive); stateMachine.OnTransitioned(OnTransitionAction); stateMachine.Configure(NotificationStatus.NotSubmitted) .Permit(Trigger.Submit, NotificationStatus.Submitted) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.Submitted) .SubstateOf(NotificationStatus.InDetermination) .OnEntryFrom(Trigger.Submit, OnSubmit) .Permit(Trigger.NotificationReceived, NotificationStatus.NotificationReceived); stateMachine.Configure(NotificationStatus.NotificationReceived) .SubstateOf(NotificationStatus.InDetermination) .OnEntryFrom(receivedTrigger, OnReceived) .PermitIf(Trigger.AssessmentCommenced, NotificationStatus.InAssessment, () => Dates.PaymentReceivedDate.HasValue) .Permit(Trigger.Object, NotificationStatus.Objected); stateMachine.Configure(NotificationStatus.InAssessment) .SubstateOf(NotificationStatus.InDetermination) .OnEntryFrom(commencedTrigger, OnInAssessment) .Permit(Trigger.NotificationComplete, NotificationStatus.ReadyToTransmit) .Permit(Trigger.Object, NotificationStatus.Objected); stateMachine.Configure(NotificationStatus.ReadyToTransmit) .SubstateOf(NotificationStatus.InDetermination) .OnEntryFrom(completeTrigger, OnCompleted) .Permit(Trigger.Transmit, NotificationStatus.Transmitted) .Permit(Trigger.Object, NotificationStatus.Objected); stateMachine.Configure(NotificationStatus.Transmitted) .SubstateOf(NotificationStatus.InDetermination) .OnEntryFrom(transmitTrigger, OnTransmitted) .Permit(Trigger.Acknowledged, NotificationStatus.DecisionRequiredBy) .Permit(Trigger.Object, NotificationStatus.Objected); stateMachine.Configure(NotificationStatus.DecisionRequiredBy) .OnEntryFrom(acknowledgedTrigger, OnAcknowledged) .Permit(Trigger.Unlock, NotificationStatus.Unlocked) .Permit(Trigger.Consent, NotificationStatus.Consented) .Permit(Trigger.Object, NotificationStatus.Objected) .Permit(Trigger.Withdraw, NotificationStatus.Withdrawn) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.InDetermination) .Permit(Trigger.Withdraw, NotificationStatus.Withdrawn) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.Withdrawn) .OnEntryFrom(withdrawTrigger, OnWithdrawn) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.Objected) .OnEntryFrom(objectTrigger, OnObjected) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.Consented) .OnEntryFrom(consentedTrigger, OnConsented) .Permit(Trigger.WithdrawConsent, NotificationStatus.ConsentWithdrawn) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.ConsentWithdrawn) .OnEntryFrom(withdrawConsentTrigger, OnConsentWithdrawn) .Permit(Trigger.Archive, NotificationStatus.FileClosed); stateMachine.Configure(NotificationStatus.Unlocked) .SubstateOf(NotificationStatus.InDetermination) .Permit(Trigger.Resubmit, NotificationStatus.Reassessment); stateMachine.Configure(NotificationStatus.Reassessment) .SubstateOf(NotificationStatus.InDetermination) .Permit(Trigger.AcceptChanges, NotificationStatus.DecisionRequiredBy) .Permit(Trigger.RejectChanges, NotificationStatus.Unlocked); stateMachine.Configure(NotificationStatus.FileClosed) .OnEntryFrom(archiveTrigger, OnFileClosed); return stateMachine; }
private StateMachine<FinancialGuaranteeStatus, Trigger> CreateStateMachine() { var stateMachine = new StateMachine<FinancialGuaranteeStatus, Trigger>(() => Status, s => Status = s); completedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Completed); approvedTrigger = stateMachine.SetTriggerParameters<ApprovalData>(Trigger.Approved); refusedTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.Refused); releasedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Released); stateMachine.Configure(FinancialGuaranteeStatus.ApplicationReceived) .Permit(Trigger.Completed, FinancialGuaranteeStatus.ApplicationComplete); stateMachine.Configure(FinancialGuaranteeStatus.ApplicationComplete) .OnEntryFrom(completedTrigger, OnCompleted) .PermitIf(Trigger.Approved, FinancialGuaranteeStatus.Approved, () => CompletedDate.HasValue) .PermitIf(Trigger.Refused, FinancialGuaranteeStatus.Refused, () => CompletedDate.HasValue); stateMachine.Configure(FinancialGuaranteeStatus.Approved) .OnEntryFrom(approvedTrigger, OnApproved) .Permit(Trigger.Released, FinancialGuaranteeStatus.Released) .Permit(Trigger.Superseded, FinancialGuaranteeStatus.Superseded); stateMachine.Configure(FinancialGuaranteeStatus.Refused) .OnEntryFrom(refusedTrigger, OnRefused); stateMachine.Configure(FinancialGuaranteeStatus.Released) .OnEntryFrom(releasedTrigger, OnReleased); stateMachine.OnTransitioned(OnTransitionAction); return stateMachine; }
private StateMachine<MovementStatus, Trigger> CreateStateMachine() { var stateMachine = new StateMachine<MovementStatus, Trigger>(() => Status, s => Status = s); submittedTrigger = stateMachine.SetTriggerParameters<Guid>(Trigger.Submit); internallySubmittedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.SubmitInternal); completedTrigger = stateMachine.SetTriggerParameters<DateTime, Guid, Guid>(Trigger.Complete); internallyCompletedTrigger = stateMachine.SetTriggerParameters<DateTime, Guid>(Trigger.CompleteInternal); acceptedTrigger = stateMachine.SetTriggerParameters<AcceptedTriggerParameters>(Trigger.Receive); internallyAcceptedTrigger = stateMachine.SetTriggerParameters<InternallyAcceptedTriggerParameters>(Trigger.ReceiveInternal); stateMachine.OnTransitioned(OnTransitionAction); stateMachine.Configure(MovementStatus.New) .Permit(Trigger.Submit, MovementStatus.Submitted); stateMachine.Configure(MovementStatus.Submitted) .OnEntryFrom(submittedTrigger, OnSubmitted) .OnEntryFrom(internallySubmittedTrigger, OnInternallySubmitted) .Permit(Trigger.Receive, MovementStatus.Received) .Permit(Trigger.ReceiveInternal, MovementStatus.Received) .Permit(Trigger.Reject, MovementStatus.Rejected) .Permit(Trigger.Cancel, MovementStatus.Cancelled); stateMachine.Configure(MovementStatus.Received) .OnEntryFrom(acceptedTrigger, OnReceived) .OnEntryFrom(internallyAcceptedTrigger, OnInternallyReceived) .Permit(Trigger.Complete, MovementStatus.Completed) .Permit(Trigger.CompleteInternal, MovementStatus.Completed); stateMachine.Configure(MovementStatus.Completed) .OnEntryFrom(completedTrigger, OnCompleted) .OnEntryFrom(internallyCompletedTrigger, OnInternallyCompleted); stateMachine.Configure(MovementStatus.Captured) .Permit(Trigger.ReceiveInternal, MovementStatus.Received) .Permit(Trigger.Reject, MovementStatus.Rejected) .Permit(Trigger.SubmitInternal, MovementStatus.Submitted); return stateMachine; }
private StateMachine<ImportNotificationStatus, Trigger> CreateStateMachine() { var stateMachine = new StateMachine<ImportNotificationStatus, Trigger>(() => Status, s => Status = s); stateMachine.OnTransitioned(OnTransition); receivedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Receive); fullyPaidTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.FullyPaid); beginAssessmentTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.BeginAssessment); completeNotificationTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.CompleteNotification); acknowledgeTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Acknowledge); consentedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.Consent); withdrawConsentTrigger = stateMachine.SetTriggerParameters<DateTime, string>(Trigger.WithdrawConsent); fileClosedTrigger = stateMachine.SetTriggerParameters<DateTime>(Trigger.FileClosed); stateMachine.Configure(ImportNotificationStatus.New) .Permit(Trigger.Receive, ImportNotificationStatus.NotificationReceived); stateMachine.Configure(ImportNotificationStatus.NotificationReceived) .OnEntryFrom(receivedTrigger, OnReceived) .Permit(Trigger.Submit, ImportNotificationStatus.AwaitingPayment) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.AwaitingPayment) .SubstateOf(ImportNotificationStatus.Submitted) .Permit(Trigger.FullyPaid, ImportNotificationStatus.AwaitingAssessment) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.AwaitingAssessment) .SubstateOf(ImportNotificationStatus.Submitted) .OnEntryFrom(fullyPaidTrigger, OnFullyPaid) .Permit(Trigger.BeginAssessment, ImportNotificationStatus.InAssessment) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.InAssessment) .OnEntryFrom(beginAssessmentTrigger, OnAssessmentStarted) .Permit(Trigger.CompleteNotification, ImportNotificationStatus.ReadyToAcknowledge) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.ReadyToAcknowledge) .OnEntryFrom(completeNotificationTrigger, OnNotificationCompleted) .Permit(Trigger.Acknowledge, ImportNotificationStatus.DecisionRequiredBy) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.DecisionRequiredBy) .OnEntryFrom(acknowledgeTrigger, OnAcknowledged) .Permit(Trigger.Consent, ImportNotificationStatus.Consented) .Permit(Trigger.Object, ImportNotificationStatus.Objected) .Permit(Trigger.Withdraw, ImportNotificationStatus.Withdrawn) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.Consented) .OnEntryFrom(consentedTrigger, OnConsented) .Permit(Trigger.WithdrawConsent, ImportNotificationStatus.ConsentWithdrawn) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.ConsentWithdrawn) .OnEntryFrom(withdrawConsentTrigger, OnConsentWithdrawn) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.Objected) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.Withdrawn) .Permit(Trigger.FileClosed, ImportNotificationStatus.FileClosed); stateMachine.Configure(ImportNotificationStatus.FileClosed) .OnEntryFrom(fileClosedTrigger, OnFileClosed); return stateMachine; }