| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import '../src/syncbase/settings_manager.dart' show SettingsManager; |
| import 'create_game.dart' as cg; |
| import 'croupier_settings.dart' show CroupierSettings; |
| import 'game/game.dart' |
| show Game, GameType, GameStartData, stringToGameType, gameTypeToString; |
| |
| enum CroupierState { Welcome, ChooseGame, JoinGame, ArrangePlayers, PlayGame } |
| |
| typedef void NoArgCb(); |
| |
| class Croupier { |
| CroupierState state; |
| SettingsManager settings_manager; |
| CroupierSettings settings; // null, but loaded asynchronously. |
| Map<int, |
| CroupierSettings> settings_everyone; // empty, but loaded asynchronously |
| Map<String, GameStartData> games_found; // empty, but loads asynchronously |
| Map<int, int> players_found; // empty, but loads asynchronously |
| Game game; // null until chosen |
| NoArgCb informUICb; |
| |
| // Futures to use in order to cancel scans and advertisements. |
| Future _scanFuture; |
| Future _advertiseFuture; |
| |
| bool debugMode = false; // whether to show debug buttons or not |
| |
| Croupier() { |
| state = CroupierState.Welcome; |
| settings_everyone = new Map<int, CroupierSettings>(); |
| games_found = new Map<String, GameStartData>(); |
| players_found = new Map<int, int>(); |
| settings_manager = new SettingsManager( |
| _updateSettingsEveryoneCb, _updateGamesFoundCb, _updatePlayerFoundCb); |
| |
| settings_manager.load().then((String csString) { |
| settings = new CroupierSettings.fromJSONString(csString); |
| if (this.informUICb != null) { |
| this.informUICb(); |
| } |
| settings_manager.createSettingsSyncgroup(); // don't wait for this future. |
| }); |
| } |
| |
| // Updates the settings_everyone map as people join the main Croupier syncgroup |
| // and change their settings. |
| void _updateSettingsEveryoneCb(String key, String json) { |
| settings_everyone[int.parse(key)] = |
| new CroupierSettings.fromJSONString(json); |
| if (this.informUICb != null) { |
| this.informUICb(); |
| } |
| } |
| |
| void _updateGamesFoundCb(String gameAddr, String jsonData) { |
| if (jsonData == null) { |
| games_found.remove(gameAddr); |
| } else { |
| GameStartData gsd = new GameStartData.fromJSONString(jsonData); |
| games_found[gameAddr] = gsd; |
| } |
| if (this.informUICb != null) { |
| this.informUICb(); |
| } |
| } |
| |
| void _updatePlayerFoundCb(String playerID, String playerNum) { |
| int id = int.parse(playerID); |
| if (playerNum == null) { |
| games_found.remove(id); |
| } else { |
| int playerNumber = int.parse(playerNum); |
| players_found[id] = playerNumber; |
| |
| // If the player number changed was ours, then set it on our game. |
| if (id == settings.userID) { |
| game.playerNumber = playerNumber; |
| } |
| } |
| if (this.informUICb != null) { |
| this.informUICb(); |
| } |
| } |
| |
| // Sets the next part of croupier state. |
| // Depending on the originating state, data can contain extra information that we need. |
| void setState(CroupierState nextState, var data) { |
| switch (state) { |
| case CroupierState.Welcome: |
| // data should be empty. |
| assert(data == null); |
| break; |
| case CroupierState.ChooseGame: |
| if (data == null) { |
| // Back button pressed. |
| break; |
| } |
| assert(nextState == CroupierState.ArrangePlayers); |
| |
| // data should be the game id here. |
| GameType gt = data as GameType; |
| game = cg.createGame(gt, 0, this.debugMode, |
| isCreator: true); // Start as player 0 of whatever game type. |
| |
| _advertiseFuture = settings_manager |
| .createGameSyncgroup(gameTypeToString(gt), game.gameID) |
| .then((GameStartData gsd) { |
| // Only the game chooser should be advertising the game. |
| return settings_manager.advertiseSettings(gsd); |
| }); // don't wait for this future. |
| |
| break; |
| case CroupierState.JoinGame: |
| // Note that if we were in join game, we must have been scanning. |
| _scanFuture.then((_) { |
| settings_manager.stopScanSettings(); |
| _scanFuture = null; |
| }); |
| |
| if (data == null) { |
| // Back button pressed. |
| break; |
| } |
| |
| // data would probably be the game id again. |
| GameStartData gsd = data as GameStartData; |
| game = cg.createGame( |
| stringToGameType(gsd.type), gsd.playerNumber, this.debugMode, |
| gameID: gsd.gameID); // Start as player 0 of whatever game type. |
| String sgName; |
| games_found.forEach((String name, GameStartData g) { |
| if (g == gsd) { |
| sgName = name; |
| } |
| }); |
| assert(sgName != null); |
| |
| settings_manager.joinGameSyncgroup(sgName, gsd.gameID); |
| break; |
| case CroupierState.ArrangePlayers: |
| // Note that if we were arranging players, we might have been advertising. |
| if (_advertiseFuture != null) { |
| _advertiseFuture.then((_) { |
| settings_manager.stopAdvertiseSettings(); |
| _advertiseFuture = null; |
| }); |
| } |
| |
| // data should be empty. |
| // All rearrangements affect the Game's player number without changing app state. |
| break; |
| case CroupierState.PlayGame: |
| // data should be empty. |
| // The signal to start really isn't anything special. |
| break; |
| default: |
| assert(false); |
| } |
| |
| // A simplified way of clearing out the games and players found. |
| // They will need to be re-discovered in the future. |
| if (nextState == CroupierState.Welcome) { |
| games_found = new Map<String, GameStartData>(); |
| players_found = new Map<int, int>(); |
| } else if (nextState == CroupierState.JoinGame) { |
| // Start scanning for games since that's what's next for you. |
| _scanFuture = |
| settings_manager.scanSettings(); // don't wait for this future. |
| } |
| |
| state = nextState; |
| } |
| } |