Beispiel #1
0
    def start_game(self):
        log_type    = "INFO"
        log_code    = "Game"
        log_message = "Game beginning"
        log_detail  = 1
        context_id  = self.g_id

        log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

        self.assign_roles()
        self.change_state("waiting")

        log_type    = "INFO"
        log_code    = "Game"
        log_message = "First round: night dawns"
        log_detail  = 3
        context_id  = self.g_id

        log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
        
        self.g_round += 1

        new_event = event.EventFactory.create_event("night", self.g_id, self)

        self.add_event(new_event.e_id)

        self.check_event_queue()
Beispiel #2
0
    def filter_JSON(self, game_json, filters):
        players_json = {}
        get_individuals_filters = []

        for filter_p_ids, filters_to_apply in filters.items():
            get_individuals_filters.append([filter_p_ids])    # convert to a list of individual filters

        # Obtain all players that are in this game_json
        knows_about = self.get_groups(get_individuals_filters, expected_count=len(get_individuals_filters))

        for player in knows_about:
            if player.p_id in filters:
                players_json[player.p_id] = player.as_JSON(player_json={}, attribute_filter=filters[player.p_id])
            else:
                log_type    = "ERROR"
                log_code    = "Game"
                log_message = "You were probably expecting a different p_id. Check the User() init function!"
                log_detail  = 4
                context_id  = self.g_id

                log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

        game_obj = json.loads(game_json)
        game_obj['players'] = players_json
        game_json = json.dumps(game_obj, sort_keys=True, indent=4)

        return game_json
Beispiel #3
0
    def publish_all_games():
        '''Finds all the games currently in redis and returns a JSON of their basic information'''
        data_dict = {}
        games_dict = {}
        all_redis_games = ww_redis_db.keys("g_list:*")

                                                            ############################################################
                                                            # Get all games from redis as a JSON
                                                            ############################################################
        if len(all_redis_games) > 0:
            for redis_game_key in all_redis_games:
                g_id = str(redis_game_key.decode("utf-8")).split(":")[1]
                python_game = Game(g_id)
                
                games_dict["game:"+g_id] = python_game.as_JSON()
        else:
            log_handler.log(
                log_type        = "INFO",
                log_code        = "CurrentDev",
                log_message     = "No games were found in Redis",
                log_detail      = 5
            )
                                                            ############################################################
                                                            # Publish information
                                                            ############################################################
        data_dict["games"] = games_dict
        data_dict["channel"] = "games_list"

        publish_data("lobbyinfo", data_dict)
        return data_dict
Beispiel #4
0
    def __init__(self, p_id=None, session_key=None):
        self.name = ""
        self.g_history = [
        ]  # list of games just been in to assist matchmaking algorithm
        self.location = ""
        self.session_key = ""
        self.broadcastable = []

        self.broadcastable.extend(["name", "location", "p_id"])

        # look for p_id in session
        if session_key:
            self.session = SessionStore(session_key=session_key)
            self.session_key = session_key
            if 'p_id' in self.session:
                p_id = self.session['p_id']

        try:
            # try loading from redis
            self.p_id = p_id
            self.load(p_id)
        except Exception as error:
            log_type = "ERROR"
            log_code = "Player"
            log_message = "Couldn't load user's p_id from redis, putting in default values: " + str(
                error)
            log_detail = 3
            context_id = self.p_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)

            self.name = "Richard"
            self.p_id = str(uuid.uuid4())
            self.location = "outgame"
            self.session = SessionStore(self.session_key)
            self.session_key = self.session.session_key

            self.session['p_id'] = self.p_id
            self.session['location'] = self.location
            self.session.save()

            self.save()

        log_type = "INFO"
        log_code = "Memory"
        log_message = "User initialised and saved"
        log_detail = 7
        context_id = self.p_id

        log_handler.log(log_type=log_type,
                        log_code=log_code,
                        log_message=log_message,
                        log_detail=log_detail,
                        context_id=context_id)
Beispiel #5
0
    def publish_detailed_game(g_id, p_id=None):
        '''Finds the specified game and creates a detailed JSON, optionally filtering for a specific player'''
        data_dict = {}                          # the entire dict to publish
        games_dict = {}                         # the dict containing a single record of the game as a JSON string. Kept as a dict to maintain compatibility with other games_dict parsers
        publish_channel = "game:" + g_id        # default publishing to everyone subscribed to the game
        information_channel = publish_channel   # information will always be a game

                                                            ############################################################
                                                            # Get detailed game as a JSON
                                                            ############################################################
        try:
            redis_game = ww_redis_db.hgetall("g_list:"+g_id)

            if p_id:
                requesting_player = user.Player(p_id)
                publish_channel = "player:" + p_id  # publish only to the requesting player

            if len(redis_game) > 0:
                #g_id is valid
                python_game = Game(g_id)
                full_json = python_game.as_JSON(meta=True, players=True, cur_events=True, hist_events=True)
                if p_id:
                    filtered_json = python_game.filter_JSON(full_json, requesting_player.knows_about)
                    games_dict["game:"+g_id] = filtered_json
                else:
                    games_dict["game:"+g_id] = full_json
            else:
                log_handler.log(
                    log_type        = "ERROR",
                    log_code        = "CurrentDev",
                    log_message     = "No games were found!",
                    log_detail      = 3,
                    context_id      = g_id
                )
                raise ValueError("There are no games in redis")
                                                            ############################################################
                                                            # Publish information
                                                            ############################################################
            data_dict["games"] = games_dict
            data_dict["channel"] = information_channel

            publish_data(publish_channel, data_dict)

            return data_dict

                                                            ############################################################
                                                            # Dismiss the error and log.
                                                            ############################################################
        except:
            logging.exception('')
            log_handler.log(
                log_type        = "ERROR",
                log_code        = "CurrentDev",
                log_message     = "Could not publish this detailed game",
                log_detail      = 3,
                context_id      = g_id
            )
Beispiel #6
0
 def get_player_ids(self):
     log_handler.log(
         log_type        = "ERROR",
         log_code        = "Game",
         log_message     = "Redundant function called",
         log_detail      = 1,
         context_id      = self.g_id
     )
     return self.players
    def remove_callback(self, id, callback_reference):
        self.iol.remove_timeout(timeout=self.callbacks[id][int(callback_reference)])
        self.callbacks[id].pop(int(callback_reference))

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Callbacks",
            log_message     = "Removed callback reference from self.callbacks["+str(id)+"]["+str(callback_reference)+"]",
            log_detail      = 7
        )
    def remove_callback(self, id, callback_reference):
        self.iol.remove_timeout(
            timeout=self.callbacks[id][int(callback_reference)])
        self.callbacks[id].pop(int(callback_reference))

        log_handler.log(
            log_type="INFO",
            log_code="Callbacks",
            log_message="Removed callback reference from self.callbacks[" +
            str(id) + "][" + str(callback_reference) + "]",
            log_detail=7)
Beispiel #9
0
    def change_state(self, state, msg=""):
        self.state = state
        self.save()

        data_dict = {}

        if state == "lobby":
            msg = "waiting for more players. " + msg

        if state == "ready":
            msg = "publishing ready info. " + msg

        if state == "waiting":
            msg = "waiting for event. " + msg

        if state == "new_event":
            new_event = self.get_event_queue()[0]
            msg = "new event starting: " + new_event.e_type + ". " + msg
            data_dict["event"] = new_event.e_type

        if state == "voting":
            msg = "Waiting 10s to collect votes. " + msg

            cur_event = self.get_event_queue()[0]

            data_dict["subjects"] = []
            for player in self.get_groups(cur_event.subjects):
                data_dict["subjects"].append(player.as_JSON())

            data_dict["e_type"] = cur_event.e_type
            data_dict["channel"] = "event info"

            for p_id in cur_event.instigators:
                publish_data("player:"+p_id, data_dict)

        if state == "finished_voting":
            msg = "Votes collected, performing result"

        if state == "game_finished":
            msg = msg + "These guys won: "
            for group in self.get_winners():
                msg = msg + group + ", "

            msg = "-------"+msg.upper()+"-------"

        log_type    = "INFO"
        log_code    = "Game"
        log_message = msg
        log_detail  = 2
        context_id  = self.g_id

        log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
Beispiel #10
0
    def leave_game(self):
        self.session['location'] = "outgame"
        self.location = "outgame"
        self.g_history.append(self.g_id)  # this should really have a timestamp

        self.save()

        log_handler.log(
            log_type="INFO",
            log_code="Player",
            log_message="Updating player location to reflect leaving game",
            log_detail=6,
            context_id=self.p_id)
Beispiel #11
0
    def leave_game(self):
        self.session['location'] = "outgame"
        self.location = "outgame"
        self.g_history.append(self.g_id)    # this should really have a timestamp

        self.save()

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Player",
            log_message     = "Updating player location to reflect leaving game",
            log_detail      = 6,
            context_id      = self.p_id
        )
Beispiel #12
0
    def join_game(self, g_id):
        self.location = "ingame"
        self.session['location'] = "ingame"
        self.g_id = g_id
        self.session['g_id'] = g_id

        self.save()

        log_handler.log(
            log_type="INFO",
            log_code="Player",
            log_message="Updating player location to reflect joining game",
            log_detail=6,
            context_id=self.p_id)
Beispiel #13
0
    def lose_info(self, attribute_filter, p_id=None, info_player=None, lose_all=False):
        # error checking
        if not p_id and not info_player:
            raise ValueError("Either p_id or player needs to be supplied")

        if not p_id and info_player and not isinstance(info_player, Player):
            raise ValueError("supplied player argument must be a Player")

        if not p_id and info_player:
            p_id = info_player.p_id

        if p_id not in self.knows_about:
            warnings.warn("No info held on this character anyway")
            log_type    = "WARNING"
            log_code    = "Player"
            log_message = "Player does not have information on: " + p_id + ". This could be because you're iterating through a loop which removes information from both source and target (see game.end_game())"
            log_detail  = 4
            context_id  = self.p_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
            return

        # populate list with all keys if knows about everything (filter on None)
        if self.knows_about[p_id] is None:
            self.knows_about[p_id] = Player(p_id).broadcastable

        log_type    = "INFO"
        log_message = "Player is losing p_id " + p_id + " from knows_about dict"
        context_id  = self.p_id
        log_code    = "Player"

        log_handler.log(log_type, log_code, log_message, context_id=context_id)
        
        if lose_all:
            log_type    = "INFO"
            log_code    = "Player"
            log_message = "Losing all information on p_id " + p_id
            log_detail  = 4
            context_id  = self.p_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
            self.knows_about.pop(p_id)

        else:
            for attribute in attribute_filter:
                if attribute not in self.broadcastable:
                    raise ValueError("Attribute '"+attribute+"' is not a broadcastable attribute.")
                elif attribute in self.knows_about[p_id]:
                    self.knows_about[p_id].remove(attribute)
                else:
                    log_type    = "INFO"
                    log_code    = "Player"
                    log_message = "attribute: "+attribute+" was not found in this players knows_about list"
                    log_detail  = 4
                    context_id  = self.p_id

                    log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

        self.save()
Beispiel #14
0
    def join_game(self, g_id):
        self.location = "ingame"
        self.session['location'] = "ingame"
        self.g_id = g_id
        self.session['g_id'] = g_id

        self.save()

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Player",
            log_message     = "Updating player location to reflect joining game",
            log_detail      = 6,
            context_id      = self.p_id
        )
Beispiel #15
0
    def __init__(self, p_id=None, session_key=None):
        self.name = ""
        self.g_history = []	# list of games just been in to assist matchmaking algorithm
        self.location = ""
        self.session_key = ""
        self.broadcastable = []

        self.broadcastable.extend(["name", "location", "p_id"])

        # look for p_id in session
        if session_key:
            self.session = SessionStore(session_key=session_key)
            self.session_key = session_key
            if 'p_id' in self.session:
                p_id = self.session['p_id']

        try:
            # try loading from redis
            self.p_id = p_id
            self.load(p_id)
        except Exception as error:
            log_type    = "ERROR"
            log_code    = "Player"
            log_message = "Couldn't load user's p_id from redis, putting in default values: "+str(error)
            log_detail  = 3
            context_id  = self.p_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

            self.name = "Richard"
            self.p_id = str(uuid.uuid4())
            self.location = "outgame"
            self.session = SessionStore(self.session_key)
            self.session_key = self.session.session_key

            self.session['p_id'] = self.p_id
            self.session['location'] = self.location
            self.session.save()

            self.save()

        log_type    = "INFO"
        log_code    = "Memory"
        log_message = "User initialised and saved"
        log_detail  = 7
        context_id  = self.p_id

        log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
Beispiel #16
0
    def vote_result(g_id, e_id):
        parent_game = wwss.game.Game(g_id)
        voting_event = Event.load(g_id, e_id)
        callback_handler.remove_callback(voting_event.e_id, voting_event.voting_callback_reference)

        if voting_event.votes:
            p_id_most_common = Counter(voting_event.votes).most_common(1)

            log_type = "INFO"
            log_code = "Event"
            log_message = "Most common vote was" + p_id_most_common
            log_detail = 5
            context_id = self.e_id

            log_handler.log(
                log_type=log_type,
                log_code=log_code,
                log_message=log_message,
                log_detail=log_detail,
                context_id=context_id,
            )

            voting_event.result_subjects = [p_id_most_common]
        else:
            shuffle(voting_event.subjects)

            log_type = "INFO"
            log_code = "Event"
            log_message = "No votes were given, a random choice has been selected: " + voting_event.subjects[0]
            log_detail = 5
            context_id = e_id

            log_handler.log(
                log_type=log_type,
                log_code=log_code,
                log_message=log_message,
                log_detail=log_detail,
                context_id=context_id,
            )

            voting_event.result_subjects = [voting_event.subjects[0]]

        parent_game.change_state("finished_voting")
        voting_event.save()
        voting_event.finish_event()
        return
    def add_callback(self, id, callback_handler):
        if id in self.callbacks:
            callback_reference = len(self.callbacks[id])
        else:
            self.callbacks[id] = {}
            callback_reference = 0

        self.callbacks[id][callback_reference] = callback_handler

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Callbacks",
            log_message     = "Added callback reference to self.callbacks["+str(id)+"]["+str(callback_reference)+"]",
            log_detail      = 7,
            context_id      = None
        )

        return callback_reference
Beispiel #18
0
    def end_game(self):
        # log game into Relational DB
        
        ## remove players from game
        #leaving_players = list(self.players)
        #for p_id in leaving_players:
        #    self.remove_player(leaving_p_id=p_id)
        #
        ## delete game from redis
        #self.redis_cleanup()

        log_handler.log(
            log_type        = "WARNING",
            log_code        = "CurrentDev",
            log_message     = "Game has been left in a finished state to enable debugging after the game has ended. ",
            log_detail      = 2,
            context_id      = self.g_id
        )
    def add_callback(self, id, callback_handler):
        if id in self.callbacks:
            callback_reference = len(self.callbacks[id])
        else:
            self.callbacks[id] = {}
            callback_reference = 0

        self.callbacks[id][callback_reference] = callback_handler

        log_handler.log(
            log_type="INFO",
            log_code="Callbacks",
            log_message="Added callback reference to self.callbacks[" +
            str(id) + "][" + str(callback_reference) + "]",
            log_detail=7,
            context_id=None)

        return callback_reference
Beispiel #20
0
    def vote_result(g_id, e_id):
        parent_game = wwss.game.Game(g_id)
        voting_event = Event.load(g_id, e_id)
        callback_handler.remove_callback(
            voting_event.e_id, voting_event.voting_callback_reference)

        if voting_event.votes:
            p_id_most_common = Counter(voting_event.votes).most_common(1)

            log_type = "INFO"
            log_code = "Event"
            log_message = "Most common vote was" + p_id_most_common
            log_detail = 5
            context_id = self.e_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)

            voting_event.result_subjects = [p_id_most_common]
        else:
            shuffle(voting_event.subjects)

            log_type = "INFO"
            log_code = "Event"
            log_message = "No votes were given, a random choice has been selected: " + voting_event.subjects[
                0]
            log_detail = 5
            context_id = e_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)

            voting_event.result_subjects = [voting_event.subjects[0]]

        parent_game.change_state("finished_voting")
        voting_event.save()
        voting_event.finish_event()
        return
Beispiel #21
0
    def save(self):
        ww_redis_db.hset("g_list:"+self.g_id, "name", self.name)
        ww_redis_db.hset("g_list:"+self.g_id, "g_round", self.g_round)
        ww_redis_db.hset("g_list:"+self.g_id, "state", self.state)
        ww_redis_db.hset("g_list:"+self.g_id, "max_players", str(self.max_players))
        ww_redis_db.hset("g_list:"+self.g_id, "witch_enabled", str(self.witch_enabled))
        ww_redis_db.hset("g_list:"+self.g_id, "mystic_enabled", str(self.mystic_enabled))

        players_string = cur_events_string = old_events_string = ""
        if self.players:
            players_string = "|".join(self.players)
        ww_redis_db.hset("g_list:"+self.g_id, "players", players_string)
        
        if self.event_queue:
            cur_events_string = "|".join(self.event_queue)
        ww_redis_db.hset("g_list:"+self.g_id, "event_queue", cur_events_string)
        
        if self.event_history:
            old_events_string = "|".join(self.event_history)
        ww_redis_db.hset("g_list:"+self.g_id, "event_history", old_events_string)

        if hasattr(self, 'redis_cleanup_callback_reference'):
            if self.redis_cleanup_callback_reference is not None:
                ww_redis_db.hset("g_list:"+self.g_id, "redis_cleanup_callback_reference", self.redis_cleanup_callback_reference)


        games_dict = {}
        data_dict = {}
        games_dict["json"] = self.as_JSON()

        data_dict["game"] = games_dict
        data_dict["channel"] = "game:"+self.g_id

        publish_data("game:"+self.g_id, data_dict)

        self.saved = True
        
        log_type    = "INFO"
        log_code    = "Memory"
        log_message = "Game has been saved."
        log_detail  = 2
        context_id  = self.g_id

        log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
Beispiel #22
0
    def add_vote(g_id, e_id, p_id_vote, voting_by_p_id=None):
        voting_event = Event.load(g_id, e_id)
        parent_game = wwss.game.Game(g_id)

        log_type = "INFO"
        log_code = "Event"
        log_message = "A player just voted for " + p_id_vote
        log_detail = 7
        context_id = self.e_id

        log_handler.log(
            log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id
        )

        voting_event.votes.append(p_id_vote)

        if len(voting_event.votes) == len(voting_event.voters):
            parent_game.change_state("finished_voting")
            voting_event.vote_result()
Beispiel #23
0
    def get_individuals(self, selection_pool, filters, expected_count=None):
        """
            Removes players from the individuals list that doesn't match the filters.
            Returns a list of individuals that are filtered out of the selection pool
        """
        # loop through Player objects and remove those that don't fit the group as an array
        if not selection_pool:
            selection_pool = self.get_players()

        individuals = selection_pool    # start with all individuals in selection pool

        for filter in filters:
            if not individuals:
                return individuals

            # selecting based on player.state
            if filter in ("alive", "dead", "dying"):
                individuals = [player for player in individuals if player.state == filter]

            # selecting based on last event
            elif filter == "last_event":
                last_event = event.Event.load(self.g_id, self.event_history[0])
                individuals = [player for player in individuals if player.p_id in last_event.result_subjects]

            # selecting based on Class type
            elif inspect.isclass(filter) and issubclass(filter, Character):
                individuals = [player for player in individuals if isinstance(player, filter)]

            # selecting based on uuid string
            elif isinstance(filter, str):
                if uuid.UUID(filter, version=4):
                    individuals = [player for player in individuals if player.p_id == filter]

                    log_type    = "INFO"
                    log_code    = "Game"
                    log_message = "found p_id in game, returning player object"
                    log_detail  = 5
                    context_id  = self.g_id

                    log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

        return individuals
Beispiel #24
0
    def get_groups(self, selectors, expected_count=None):
        """
            Selectors is a list of lists. Each list should contribute to the overall returned group, and each item within the list is used to filter the selection pool.
            Filters can be strings, class objects, or uuids.
            Selectors is a list. Each list is used to retrieve individuals according to the filter list supplied within. This allows you to build up a group with different filters.
            The following selectors retrieve all the alive werewolves and all the dead witches.
            [["alive", Werewolf], ["dead", Witch]]
        """
        selection_pool = self.get_players() # get all players in the game
        group_list = []

                                                            ############################################################
                                                            # Validate parameters
                                                            ############################################################
        if len(selectors) == 0:
            raise ValueError ("No selectors provided for this group call!")
        if (not isinstance(selectors[0], list)):
            selectors = [selectors]
            log_handler.log(
                log_type        = "INFO",
                log_code        = "Game",
                log_message     = "Single selector given, converting to make compatible",
                log_detail      = 6,
                context_id      = self.g_id
            )

                                                            ############################################################
                                                            # Build up group using the filters
                                                            ############################################################
        for filters in selectors:
            selected_list = self.get_individuals(selection_pool=selection_pool, filters=filters)
            for player in selected_list:
                if player not in group_list:
                    group_list.append(player)

        if expected_count and expected_count != len(group_list):
            raise AssertionError

        if expected_count == 1:
            return group_list[0]

        return group_list
Beispiel #25
0
    def add_vote(g_id, e_id, p_id_vote, voting_by_p_id=None):
        voting_event = Event.load(g_id, e_id)
        parent_game = wwss.game.Game(g_id)

        log_type = "INFO"
        log_code = "Event"
        log_message = "A player just voted for " + p_id_vote
        log_detail = 7
        context_id = self.e_id

        log_handler.log(log_type=log_type,
                        log_code=log_code,
                        log_message=log_message,
                        log_detail=log_detail,
                        context_id=context_id)

        voting_event.votes.append(p_id_vote)

        if len(voting_event.votes) == len(voting_event.voters):
            parent_game.change_state("finished_voting")
            voting_event.vote_result()
Beispiel #26
0
    def redis_cleanup(self):
        # players might need updating just to be doubly sure!!
        if hasattr(self, 'redis_cleanup_callback_reference') and self.redis_cleanup_callback_reference:
            callback_handler.remove_callback(self.g_id, self.redis_cleanup_callback_reference)
            self.redis_cleanup_callback_reference = None

        ww_redis_db.delete("g_list:"+self.g_id)

        for e_id in self.event_history:
            ww_redis_db.delete("event:"+e_id)

        for e_id in self.event_queue:
            ww_redis_db.delete("event:"+e_id)

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Redis",
            log_message     = "Events and game has been removed from redis",
            log_detail      = 3,
            context_id      = self.g_id
        )
Beispiel #27
0
 def archive_event(self, old_event_id):
     if old_event_id in self.event_queue:
         self.event_queue.remove(old_event_id)
     else:
         log_handler.log(
             log_type        = "ERROR",
             log_code        = "Game",
             log_message     = "Tried to archive an event that wasn't found in the queue: "+old_event_id,
             log_detail      = 3,
             context_id      = self.g_id
         )
         warnings.warn("Tried to archive an event that wasn't found in the queue: " + old_event_id)
     
     if old_event_id not in self.event_history:
         self.event_history.append(old_event_id)
         log_handler.log(
             log_type        = "INFO",
             log_code        = "Game",
             log_message     = "Archived an event successful - " + old_event_id,
             log_detail      = 5,
             context_id      = self.g_id
         )
     else:
         log_handler.log(
             log_type        = "ERROR",
             log_code        = "Game",
             log_message     = "That event "+old_event_id+" was already in the event_history",
             log_detail      = 3,
             context_id      = self.g_id
         )
     self.save()
Beispiel #28
0
    def assign_roles(self):
        shuffle(self.players)

        temp_characters = []

        werewolves_count = ceil(0.3*self.config['max_players'])

        if self.config['witch_enabled']:
            witch_count = ceil(0.1*self.config['max_players'])
        else:
            witch_count = 0

        for x in range(werewolves_count):
            temp_characters.append(CharacterFactory.create_character("werewolf", p_id=self.players[x]))

        for x in range(werewolves_count, werewolves_count+witch_count):
            temp_characters.append(CharacterFactory.create_character("witch", p_id=self.players[x]))

        for x in range(werewolves_count+witch_count, len(self.players)):
            temp_characters.append(CharacterFactory.create_character("human", p_id=self.players[x]))

        for player in temp_characters:
            player.save()
            log_type    = "INFO"
            log_code    = "Player"
            log_message = "After assigning the roles, this player is " + player.character
            log_detail  = 3
            context_id  = player.p_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

        log_type    = "INFO"
        log_message = "Character roles assigned"
        context_id  = self.g_id
        log_code    = "Game"

        log_handler.log(log_type, log_code, log_message, context_id=context_id)
Beispiel #29
0
    def start(self):
        log_type = "INFO"
        log_code = "Event"
        log_message = "Subjects of the event: " + str(
            self.subjects) + ". Instigators are: " + str(self.instigators)
        log_detail = 3
        context_id = self.e_id

        log_handler.log(log_type=log_type,
                        log_code=log_code,
                        log_message=log_message,
                        log_detail=log_detail,
                        context_id=context_id)

        if not self.subjects or not self.instigators:
            self.finish_event(
            )  # has a 3 second pause to allow async to catch up and prevent needless call stack preservation
            return

        parent_game = wwss.game.Game(self.g_id)
        parent_game.change_state("new_event")

        if len(self.subjects) > 1 or len(self.instigators) > 1:
            if len(self.subjects) != 1 and len(self.instigators) != 1:
                log_type = "INFO"
                log_code = "Event"
                log_message = "Multiple options are available and a vote must be held."
                log_detail = 5
                context_id = self.e_id

                log_handler.log(log_type=log_type,
                                log_code=log_code,
                                log_message=log_message,
                                log_detail=log_detail,
                                context_id=context_id)
                self.hold_vote()

        if len(self.subjects) == 1:
            self.result_subjects = self.subjects

            log_type = "INFO"
            log_code = "Event"
            log_message = "Only one option found, beginning immediately."
            log_detail = 5
            context_id = self.e_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)
            self.finish_event()
Beispiel #30
0
    def start(self):
        log_type = "INFO"
        log_code = "Event"
        log_message = "Subjects of the event: " + str(self.subjects) + ". Instigators are: " + str(self.instigators)
        log_detail = 3
        context_id = self.e_id

        log_handler.log(
            log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id
        )

        if not self.subjects or not self.instigators:
            self.finish_event()  # has a 3 second pause to allow async to catch up and prevent needless call stack preservation
            return

        parent_game = wwss.game.Game(self.g_id)
        parent_game.change_state("new_event")

        if len(self.subjects) > 1 or len(self.instigators) > 1:
            if len(self.subjects) != 1 and len(self.instigators) != 1:
                log_type = "INFO"
                log_code = "Event"
                log_message = "Multiple options are available and a vote must be held."
                log_detail = 5
                context_id = self.e_id

                log_handler.log(
                    log_type=log_type,
                    log_code=log_code,
                    log_message=log_message,
                    log_detail=log_detail,
                    context_id=context_id,
                )
                self.hold_vote()

        if len(self.subjects) == 1:
            self.result_subjects = self.subjects

            log_type = "INFO"
            log_code = "Event"
            log_message = "Only one option found, beginning immediately."
            log_detail = 5
            context_id = self.e_id

            log_handler.log(
                log_type=log_type,
                log_code=log_code,
                log_message=log_message,
                log_detail=log_detail,
                context_id=context_id,
            )
            self.finish_event()
Beispiel #31
0
    def check_event_queue(self):
        self.load(self.g_id)

        if self.state == "game_finished":
            self.end_game()												# tidy up
            return

        if not self.event_queue:                            # add new event based on round
            log_type    = "INFO"
            log_code    = "Game"
            log_message = "No event in queue, adding day/night"
            log_detail  = 5
            context_id  = self.g_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

            self.g_round += 1

            if self.g_round % 2:
                e_type = "night"
            else:
                e_type = "day"

            new_event = event.EventFactory.create_event(e_type, self.g_id, parent_game=self)
            self.add_event(new_event.e_id)

            self.change_state("waiting")
        
        #if self.state == "new_event" or self.state == "waiting":               # work through queue
        if self.state == "waiting":
            log_type    = "INFO"
            log_code    = "Game"
            log_message = "event in the queue, we've been waiting to start"
            log_detail  = 5
            context_id  = self.g_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)

            next_event = event.Event.load(self.g_id, self.event_queue[0])
            next_event.start()
        else:   # if self.state = "new_event"
            log_type    = "INFO"
            log_code    = "Game"
            log_message = "Event in progress, resetting callback but nothing changed"
            log_detail  = 5
            context_id  = self.g_id

            log_handler.log(log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id)
        
        IOLoop.current().call_later(10, self.check_event_queue) # permits constant callback. BUG: never cleaned up as I'm not saving the handler to remove from iol.
Beispiel #32
0
    def finish_event(self):
        parent_game = wwss.game.Game(self.g_id)

        log_type = "INFO"
        log_code = "Event"
        log_message = "Result subjects of the event:" + str(
            self.result_subjects)
        log_detail = 5
        context_id = self.e_id

        log_handler.log(log_type=log_type,
                        log_code=log_code,
                        log_message=log_message,
                        log_detail=log_detail,
                        context_id=context_id)

        if self.result_subjects and (
                self.instigators or self.action_without_instigators
        ):  # only add to history if there is an effect
            parent_game.archive_event(self.e_id)
            log_handler.log(log_type="INFO",
                            log_code="Event",
                            log_message="Event has been archived",
                            log_detail=3,
                            context_id=self.e_id)
        else:
            parent_game.delete_event("event_queue", self.e_id)

            log_type = "INFO"
            log_code = "Event"
            log_message = "This event has been deleted from its game's event_queue"
            log_detail = 5
            context_id = self.e_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)

            ww_redis_db.delete("event:" + self.e_id)

        for p_id in self.result_subjects:  # new events queued will be in reverse order to the order they were added to subjects
            player = wwss.characters.CharacterFactory.create_character(
                character=None, p_id=p_id)
            result = self.action(player)
            if result and isinstance(result, Event):
                result = [
                    result
                ]  # forces into array to allow multiple events by default
            if result and any(
                    isinstance(e, Event)
                    for e in result):  # if result contains any events
                for event in result:
                    [
                        parent_game.add_event(event.e_id, at_front=True)
                        for event in result if isinstance(event, Event)
                    ]  # adds events with the same order they were returned

        if parent_game.get_winners():
            parent_game.change_state("game_finished")
        else:
            parent_game.change_state("waiting")
Beispiel #33
0
    def finish_event(self):
        parent_game = wwss.game.Game(self.g_id)

        log_type = "INFO"
        log_code = "Event"
        log_message = "Result subjects of the event:" + str(self.result_subjects)
        log_detail = 5
        context_id = self.e_id

        log_handler.log(
            log_type=log_type, log_code=log_code, log_message=log_message, log_detail=log_detail, context_id=context_id
        )

        if self.result_subjects and (
            self.instigators or self.action_without_instigators
        ):  # only add to history if there is an effect
            parent_game.archive_event(self.e_id)
            log_handler.log(
                log_type="INFO",
                log_code="Event",
                log_message="Event has been archived",
                log_detail=3,
                context_id=self.e_id,
            )
        else:
            parent_game.delete_event("event_queue", self.e_id)

            log_type = "INFO"
            log_code = "Event"
            log_message = "This event has been deleted from its game's event_queue"
            log_detail = 5
            context_id = self.e_id

            log_handler.log(
                log_type=log_type,
                log_code=log_code,
                log_message=log_message,
                log_detail=log_detail,
                context_id=context_id,
            )

            ww_redis_db.delete("event:" + self.e_id)

        for (
            p_id
        ) in (
            self.result_subjects
        ):  # new events queued will be in reverse order to the order they were added to subjects
            player = wwss.characters.CharacterFactory.create_character(character=None, p_id=p_id)
            result = self.action(player)
            if result and isinstance(result, Event):
                result = [result]  # forces into array to allow multiple events by default
            if result and any(isinstance(e, Event) for e in result):  # if result contains any events
                for event in result:
                    [
                        parent_game.add_event(event.e_id, at_front=True) for event in result if isinstance(event, Event)
                    ]  # adds events with the same order they were returned

        if parent_game.get_winners():
            parent_game.change_state("game_finished")
        else:
            parent_game.change_state("waiting")
Beispiel #34
0
    def lose_info(self,
                  attribute_filter,
                  p_id=None,
                  info_player=None,
                  lose_all=False):
        # error checking
        if not p_id and not info_player:
            raise ValueError("Either p_id or player needs to be supplied")

        if not p_id and info_player and not isinstance(info_player, Player):
            raise ValueError("supplied player argument must be a Player")

        if not p_id and info_player:
            p_id = info_player.p_id

        if p_id not in self.knows_about:
            warnings.warn("No info held on this character anyway")
            log_type = "WARNING"
            log_code = "Player"
            log_message = "Player does not have information on: " + p_id + ". This could be because you're iterating through a loop which removes information from both source and target (see game.end_game())"
            log_detail = 4
            context_id = self.p_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)
            return

        # populate list with all keys if knows about everything (filter on None)
        if self.knows_about[p_id] is None:
            self.knows_about[p_id] = Player(p_id).broadcastable

        log_type = "INFO"
        log_message = "Player is losing p_id " + p_id + " from knows_about dict"
        context_id = self.p_id
        log_code = "Player"

        log_handler.log(log_type, log_code, log_message, context_id=context_id)

        if lose_all:
            log_type = "INFO"
            log_code = "Player"
            log_message = "Losing all information on p_id " + p_id
            log_detail = 4
            context_id = self.p_id

            log_handler.log(log_type=log_type,
                            log_code=log_code,
                            log_message=log_message,
                            log_detail=log_detail,
                            context_id=context_id)
            self.knows_about.pop(p_id)

        else:
            for attribute in attribute_filter:
                if attribute not in self.broadcastable:
                    raise ValueError("Attribute '" + attribute +
                                     "' is not a broadcastable attribute.")
                elif attribute in self.knows_about[p_id]:
                    self.knows_about[p_id].remove(attribute)
                else:
                    log_type = "INFO"
                    log_code = "Player"
                    log_message = "attribute: " + attribute + " was not found in this players knows_about list"
                    log_detail = 4
                    context_id = self.p_id

                    log_handler.log(log_type=log_type,
                                    log_code=log_code,
                                    log_message=log_message,
                                    log_detail=log_detail,
                                    context_id=context_id)

        self.save()
Beispiel #35
0
    def __init__(self, g_id=None, session_key=None, config={}):
        self.state = ""                     # used to track the current operation or state of the game
        self.players = []	                # list of Players
        self.event_queue = []	            # events waiting to happen. Triggered based on Game.state
        self.event_history = []	            # past events
        self.config = Game.default_config   # default inputs potentitally contributed to by a player

        if g_id is None and session_key is not None:
            session_data = SessionStore(session_key=session_key)
            if 'g_id' in session_data:
                g_id = session_data['g_id']

        try:
            self.load(g_id)
        except ValueError as error:
            log_handler.log(
                log_type        = "ERROR",
                log_code        = "Game",
                log_message     = "Creating default game values because: " + str(error),
                log_detail      = 4,
                context_id      = g_id
            )
            ############################################################################################################
            # Default variables
            ############################################################################################################
            self.g_id = str(uuid.uuid4())
            self.g_round = 0
            self.state = "matchmaking"

            ############################################################################################################
            # Verify config
            ############################################################################################################
            if config:
                try:
                                                                ########################################################
                                                                # Convert from string data types
                                                                ########################################################
                    if 'max_players' in config and config['max_players']:
                        config['max_players'] = int(config['max_players'])

                    if 'witch_enabled' in config and config['witch_enabled']:
                        config['witch_enabled'] = {"true": True, "false": False}.get(config['witch_enabled'].lower())

                    if 'mystic_enabled' in config and config['mystic_enabled']:
                        config['mystic_enabled'] = {"true": True, "false": False}.get(config['mystic_enabled'].lower())

                                                                ########################################################
                                                                # Validate/repair contents
                                                                ########################################################
                    validated_config = dict(config)
                    invalid_configs = {}
                    for key, value in config.items():
                        if key not in self.config or value == None:
                            invalid_configs[key] = value
                            del validated_config[key]

                    if invalid_configs:
                        raise ContinueError("Some parameters were changed", error_dict=invalid_configs)

                                                                ########################################################
                                                                # Error handling game config
                                                                ########################################################
                except ValueError as e:
                    validated_config = {}
                    log_handler.log(
                        log_type        = "ERROR",
                        log_code        = "Client",
                        log_message     = "Could not create game config dict, using default: " + str(e),
                        log_detail      = 3
                    )
                except ContinueError as e:
                    log_handler.log(
                        log_type        = "ERROR",
                        log_code        = "Client",
                        log_message     = "Repaired or removed errors: " + str(e) +" "+str(e.error_dict.items()),
                        log_detail      = 3
                    )

                                                                ########################################################
                                                                # Update config
                                                                ########################################################
                for key, value in validated_config.items():
                    if key in self.config:
                        self.config[key] = value
                        log_handler.log(
                            log_type        = "INFO",
                            log_code        = "Game",
                            log_message     = "Added (key)"+key+" to game as (value)"+str(value),
                            log_detail      = 8
                        )
                    else:
                        log_handler.log(
                            log_type        = "ERROR",
                            log_code        = "Game",
                            log_message     = "Invalid configuration for the game: " + str(config.items()),
                            log_detail      = 3
                        )
                        raise ValueError("Invalid configuration for the game")  # shouldn't ever error as it should've been cleared up earlier

            log_handler.log(
                log_type        = "INFO",
                log_code        = "Game",
                log_message     = "Loaded game config: "+str(self.config.items()),
                log_detail      = 5,
            )

                                                            ############################################################
                                                            # Apply config
                                                            ############################################################
            self.name = self.config['name']
            self.max_players = self.config['max_players']
            self.witch_enabled = self.config['witch_enabled']
            self.mystic_enabled = self.config['mystic_enabled']

        ################################################################################################################
        # Variables independent of redis and defaults
        ################################################################################################################
        self.saved = False          # enables chain editing - redundant?
        self.iol = IOLoop.current()	# main tornado loop uses for callbacks. SHOULD NOT BE USED!

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Memory",
            log_message     = "Game initialised",
            log_detail      = 4,
            context_id      = self.g_id
        )
Beispiel #36
0
    def remove_player(self, leaving_p_id=None, leaving_player=None):
        try:
            if leaving_p_id:
                leaving_player = self.get_groups([leaving_p_id], expected_count=1)
                log_handler.log(
                    log_type        = "WARNING",
                    log_code        = "Game",
                    log_message     = "If iterating through and deleting players, you must shallow copy it first!",
                    log_detail      = 10,
                    context_id      = self.g_id
                )
            else:
                leaving_p_id = leaving_player.p_id
                leaving_player = self.get_groups([leaving_p_id], expected_count=1)
        except AssertionError:
            log_handler.log(
                log_type        = "ERROR",
                log_code        = "Game",
                log_message     = "Couldn't find exactly one player with p_id "+leaving_p_id+" in this game",
                log_detail      = 3,
                context_id      = self.g_id
            )
            return

        for ingame_player in self.get_players():
            if leaving_player != ingame_player:
                leaving_player.lose_info(None, info_player=ingame_player, lose_all=True)
                ingame_player.lose_info(None, info_player=leaving_player, lose_all=True)

        while leaving_p_id in self.players:
            self.players.remove(leaving_p_id)

        leaving_player.leave_game()

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Game",
            log_message     = "Player ("+leaving_p_id+") has beem removed from this game",
            log_detail      = 5,
            context_id      = self.g_id
        )

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Player",
            log_message     = "This player has left the game ("+self.g_id+")",
            log_detail      = 4,
            context_id      = leaving_p_id
        )

        # if there are no players left, initiate countdown for redis cleanup, unless there's already a callback for its deletion
        if len(self.players) == 0 and not hasattr(self, 'redis_cleanup_callback_reference') or (hasattr(self, 'redis_cleanup_callback_reference') and not self.redis_cleanup_callback_reference):
            callback_handle = IOLoop.current().call_later(10, self.redis_cleanup)  # self works here because the data the cleanup needs should not change
            self.redis_cleanup_callback_reference = callback_handler.add_callback(self.g_id, callback_handle)

            log_handler.log(
                log_type        = "INFO",
                log_code        = "Redis",
                log_message     = "Initiating game deletion in 10 seconds",
                log_detail      = 5,
                context_id      = self.g_id
            )

        self.save()
Beispiel #37
0
    def add_player(self, joining_p_id=None, joining_player=None):
                                                            ############################################################
                                                            # Initialise player object
                                                            ############################################################
        if joining_p_id:
            joining_player = user.Player(p_id=joining_p_id)
        elif joining_player:
            joining_p_id = joining_player.p_id
        else:
            raise ValueError
                                                            ############################################################
                                                            # Return immediately if the player is already in a game
                                                            ############################################################
        if joining_player.is_ingame():
            log_handler.log(
                log_type        = "ERROR.",
                log_code        = "Player",
                log_message     = "Player: " + joining_player.p_id + "is already in a game: "+ joining_player.g_id,
                log_detail      = 4,
                context_id      = self.g_id
            )
            return
                                                            ############################################################
                                                            # If game was empty and has been scheduled for cleanup,
                                                            # remove the cleanup callback
                                                            ############################################################
        if hasattr(self, 'redis_cleanup_callback_reference') and self.redis_cleanup_callback_reference:
            callback_handler.remove_callback(self.g_id, self.redis_cleanup_callback_reference)
            self.redis_cleanup_callback_reference = None
            log_handler.log(
                log_type        = "INFO",
                log_code        = "Callbacks",
                log_message     = "Preventing game deletion",
                log_detail      = 5,
                context_id      = self.g_id
            )

        if joining_p_id not in self.players:
            self.players.append(joining_p_id)
            self.save() # all changes to the game must be immediately saved! otherwise due to call stacks, this would overwrite the new changes. You could pass by reference, but probably better to call load from redis again

                                                            ############################################################
                                                            # Update known information for all players in the game
                                                            ############################################################
            for ingame_player in self.get_players():
                if joining_player != ingame_player:
                    # give ingame player information about joining player
                    ingame_player.gain_info(['p_id', 'name'], info_player=joining_player)

                    # give joining player information about ingame_players
                    joining_player.gain_info(['p_id', 'name'], info_player=ingame_player)

                                                            ############################################################
                                                            # Save changes for player
                                                            ############################################################
        joining_player.join_game(self.g_id)

        log_handler.log(
            log_type        = "INFO",
            log_code        = "Game",
            log_message     = "Player ("+joining_p_id+") has been added to the game",
            log_detail      = 5,
            context_id      = self.g_id
        )
                                                            ############################################################
                                                            # Check game if game is full, if so begin
                                                            ############################################################
        if len(self.players) >= self.config['max_players']:
            log_handler.log(
                log_type        = "INFO",
                log_code        = "Game",
                log_message     = "Game full, starting now",
                log_detail      = 2,
                context_id      = self.g_id
            )

            self.change_state("ready", "starting game in 3 secs")
            IOLoop.current().call_later(3, self.start_game)     # for production/give a delay

        self.save()