public MachineStateBinding(S state) { this.state = state; this.enter = null; this.exit = null; this.transitions = new List <MachineTransitionBinding <E, S> >(); }
private static BufferedMachine <Event, State> MakeMachine( SteamBot bot, Client client) { Machines.Call connect = () => { bot.Connect(); }; Machines.Call open = () => { bot.SetFriendsOnline(bot.Logon.Username); client.Launch(Games.DotaGameId); }; Machines.Call sayHello = () => { client.SayHello(); }; Machines.Call leaveLobby = () => { if (client.Lobby.connect == null) { client.LeaveLobby(); } else { client.AbandonCurrentGame(); } }; Machines.Call getTicket = () => { client.GetAppTicket(); }; Machines.Call createLobby = () => { client.CreateLobby("cow"); }; Machines.Call joinRadiant = () => { client.JoinLobbySlot( SteamKit2.GC.Dota.Internal.DOTA_GC_TEAM.DOTA_GC_TEAM_GOOD_GUYS); }; Machines.Call startLobby = () => { client.LaunchLobby(); }; Machines.Call getAuth = () => { client.CreateAuthTicket(); client.Auth(); }; Machines.Call beginSession = () => { client.BeginGameServerSession(); }; Machines.Call join = () => { string[] split = client.Lobby.connect.Split(':'); var endpoint = new IPEndPoint(IPAddress.Parse(split[0]), Int16.Parse(split[1])); Lara.Join(new ConnectionDetails() { Endpoint = endpoint, SteamId = bot.Client.SteamID.ConvertToUInt64(), Nickname = bot.Logon.Username, SteamworksSessionId = client.SteamworksSessionId, Ticket = client.TicketForServer, Secret = client.Lobby.pass_key }, new AshlyController()); }; Func <State, Machines.MachineBinding <Event, State> > Start = Machines.Start <Event, State>; Func <State, Machines.MachineStateBinding <Event, State> > In = Machines.In <Event, State>; Func <Event, Machines.MachineTransitionBinding <Event, State> > On = Machines.On <Event, State>; var unbuffered = Start(State.CONCEIVED) .Add(In(State.CONCEIVED) .Add(On(Event.OPEN_REQUEST).Transit(State.CONNECTING_TO_STEAM))) .Add(In(State.CONNECTING_TO_STEAM) .Entry(connect) .Add(On(Event.CONNECTED_TO_STEAM).Transit(State.OPENING)) .Add(On(Event.DISCONNECTED_FROM_STEAM).Call(connect).Transit(State.CONNECTING_TO_STEAM))) .Add(In(State.OPENING) .Entry(open) .Add(On(Event.PLAYING_STATE_OPENED).Transit(State.CONNECTING))) .Add(In(State.CONNECTING) .Entry(sayHello) .Add(On(Event.WELCOMED).Transit(State.GETTING_TICKET)) .Add(On(Event.WELCOMED_STALE_LOBBY).Transit(State.IN_STALE_LOBBY))) .Add(In(State.IN_STALE_LOBBY) .Entry(leaveLobby) .Add(On(Event.LEFT_LOBBY).Transit(State.GETTING_TICKET))) .Add(In(State.GETTING_TICKET) .Entry(getTicket) .Add(On(Event.GOT_APP_TICKET).Transit(State.DOTA_HOME))) .Add(In(State.DOTA_HOME) .Entry(createLobby) .Add(On(Event.CREATED_LOBBY).Transit(State.IN_LOBBY))) .Add(In(State.IN_LOBBY) .Entry(joinRadiant) .Add(On(Event.LOBBY_READY).Transit(State.LOBBY_STARTING))) .Add(In(State.LOBBY_STARTING) .Entry(startLobby) .Add(On(Event.SERVER_RUNNING).Transit(State.GETTING_AUTH))) .Add(In(State.GETTING_AUTH) .Entry(getAuth) .Add(On(Event.GOT_AUTH).Transit(State.GETTING_SESSION))) .Add(In(State.GETTING_SESSION) .Entry(beginSession) .Add(On(Event.GOT_SESSION).Transit(State.JOINING_GAME))) .Add(In(State.JOINING_GAME) .Entry(join)) .Build(); return(new BufferedMachine <Event, State>(unbuffered)); }
public MachineStateBinding <E, S> Exit(Machines.Call exit) { this.exit = exit; return(this); }
public MachineStateBinding <E, S> Entry(Machines.Call enter) { this.enter = enter; return(this); }
public MachineTransitionBinding <E, S> Call(Machines.Call call) { this.call = call; return(this); }
public MachineTransitionBinding(E e) { this.e = e; this.call = null; this.state = null; }
void Connect(ConnectionDetails details, Controller controller) { Active = true; var client = new Client(details.Nickname, details.SteamworksSessionId); var connection = Connection.CreateWith(details); var handshaker = new Handshaker(details, client, connection); var signonProcessor = new SignonProcessor(client, connection); var gameProcessor = new GameProcessor(client, connection); var userCmdGenerator = new UserCmdGenerator(client, connection); controller.Initialize(details.SteamId, client, connection, userCmdGenerator); Machines.Call tick = () => { controller.Tick(); userCmdGenerator.Tick(); client.Created.Clear(); client.Deleted.Clear(); }; Machines.Call joinReset = () => { userCmdGenerator.Reset(); }; var metastates = new Dictionary <SpectateState, Metastate>() { { SpectateState.HANDSHAKE_REQUEST, Metastate.HANDSHAKE }, { SpectateState.HANDSHAKE_CONNECT, Metastate.HANDSHAKE }, { SpectateState.SIGNON_CONNECTED, Metastate.SIGNON }, { SpectateState.SIGNON_NEW, Metastate.SIGNON }, { SpectateState.SIGNON_PRESPAWN, Metastate.SIGNON }, { SpectateState.SIGNON_SPAWN, Metastate.SIGNON }, { SpectateState.SIGNON_FULL, Metastate.GAME }, }; var processors = new Dictionary <Metastate, Processor>() { { Metastate.HANDSHAKE, handshaker }, { Metastate.SIGNON, signonProcessor }, { Metastate.GAME, gameProcessor } }; Func <SpectateState, Machines.MachineBinding <Event, SpectateState> > Start = Machines.Start <Event, SpectateState>; Func <SpectateState, Machines.MachineStateBinding <Event, SpectateState> > In = Machines.In <Event, SpectateState>; Func <Event, Machines.MachineTransitionBinding <Event, SpectateState> > On = Machines.On <Event, SpectateState>; var machine = Start(SpectateState.DISCONNECTED) .Add(In(SpectateState.DISCONNECTED) .Add(On(Event.REQUEST_CONNECT).Transit(SpectateState.HANDSHAKE_REQUEST))) .Add(In(SpectateState.HANDSHAKE_REQUEST) .Entry(handshaker.RequestHandshake) .Add(On(Event.HANDSHAKE_CHALLENGE).Transit(SpectateState.HANDSHAKE_CONNECT)) .Add(On(Event.REJECTED).Transit(SpectateState.REJECTED))) .Add(In(SpectateState.HANDSHAKE_CONNECT) .Entry(handshaker.RespondHandshake) .Add(On(Event.HANDSHAKE_COMPLETE).Transit(SpectateState.SIGNON_CONNECTED)) .Add(On(Event.REJECTED).Transit(SpectateState.REJECTED))) .Add(In(SpectateState.SIGNON_CONNECTED) .Entry(signonProcessor.EnterConnected) .Add(On(Event.GO_NEW).Transit(SpectateState.SIGNON_NEW)) .Add(On(Event.DISCONNECTED).Transit(SpectateState.DISCONNECTED))) .Add(In(SpectateState.SIGNON_NEW) .Entry(signonProcessor.EnterNew) .Add(On(Event.GO_CONNECTED).Transit(SpectateState.SIGNON_CONNECTED)) .Add(On(Event.GO_PRESPAWN).Transit(SpectateState.SIGNON_PRESPAWN)) .Add(On(Event.DISCONNECTED).Transit(SpectateState.DISCONNECTED))) .Add(In(SpectateState.SIGNON_PRESPAWN) .Entry(signonProcessor.EnterPrespawn) .Add(On(Event.GO_SPAWN).Transit(SpectateState.SIGNON_SPAWN)) .Add(On(Event.DISCONNECTED).Transit(SpectateState.DISCONNECTED))) .Add(In(SpectateState.SIGNON_SPAWN) .Entry(signonProcessor.EnterSpawn) .Add(On(Event.BASELINE).Transit(SpectateState.SIGNON_FULL)) .Add(On(Event.DISCONNECTED).Transit(SpectateState.DISCONNECTED))) .Add(In(SpectateState.SIGNON_FULL) .Entry(() => { gameProcessor.EnterGame(); joinReset(); }) .Add(On(Event.TICK).Call(tick)) .Add(On(Event.DISCONNECTED).Transit(SpectateState.DISCONNECTED))) .Add(In(SpectateState.REJECTED)) .Build(); machine.Trigger(Event.REQUEST_CONNECT); long next_tick = DateTime.Now.Ticks; while (machine.State != SpectateState.DISCONNECTED && machine.State != SpectateState.REJECTED) { if (next_tick > DateTime.Now.Ticks) { Thread.Sleep(1); continue; } List <byte[]> outBand = connection.GetOutOfBand(); List <Connection.Message> inBand = connection.GetInBand(); foreach (byte[] message in outBand) { Nullable <Event> e = processors[metastates[machine.State]].Process(message); if (e.HasValue) { machine.Trigger(e.Value); } } foreach (Connection.Message message in inBand) { Nullable <Event> e = processors[metastates[machine.State]].Process(message); if (e.HasValue) { machine.Trigger(e.Value); } } machine.Trigger(Event.TICK); if (client.TickInterval > 0) { next_tick += (uint)(client.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; } } Active = false; if (machine.State == SpectateState.DISCONNECTED) { } else if (machine.State == SpectateState.REJECTED) { } else { throw new Exception("Unknown state " + machine.State); } }