def register_plugin(self, plugin, name=None):
        """
        Register a plugin instance. Merges engine methods and plugin actions.
        """
        if name is None:
            name = plugin.__class__.__name__
        self.plugins.append(plugin)
        self.plugin_names.add(name)

        for dep in tupley(plugin.AMETHYST_ENGINE_DEPENDS):
            if dep not in self.plugin_names:
                raise PluginCompatibilityException(
                    "Plugin {} requires plugin {}".format(name, dep))

        for attr in tupley(plugin.AMETHYST_ENGINE_METHODS):
            meth = attr[1:] if attr.startswith("_") else attr
            if plugin.amethyst_method_prefix:
                meth = "{}{}".format(plugin.amethyst_method_prefix, meth)
            if plugin.amethyst_method_suffix:
                meth = "{}{}".format(meth, plugin.amethyst_method_suffix)

            if hasattr(self, meth):
                raise PluginCompatibilityException(
                    "Engine already has a method '{}' (attempted override by {})"
                    .format(meth, name))
            self._register_method(meth, getattr(plugin, attr))

        plugin.on_assign_to_game(self)
 def _grant(self, game, player_nums, actions):
     for p in tupley(player_nums):
         if p not in self.grants:
             self.grants[p] = dict()
         for a in tupley(actions):
             self.grants[p][a.id] = a
     game.notify(
         None,
         Notice(
             source=self.id,
             type=NoticeType.GRANT,
             data=dict(player_nums=player_nums, actions=actions),
         ))
    def notify_immediate(self, player_nums, notice):
        """
        Send a notice to one or more players.

        If player_nums is None, sends to all players.
        """
        if player_nums is None:
            player_nums = tuple(self.notified.keys())
        for p in tupley(player_nums):
            if p in self.notified:
                for pair in self.notified[p]:
                    pair[0] += 1
                    pair[1](self, pair[0], p, notice)
 def expire(self, game, filters=FILTER_ALL):
     if filters is not None:
         self._expire(game, tupley(filters))
     return self
 def get_state(self, player_num):
     d = copy.deepcopy(self.dict)
     d['plugin_state'] = [
         p.get_state(player_num) for p in tupley(d.pop('plugins', []))
     ]
     return d