PermissionAPI


  • Rédacteurs

    Sommaire

    Introduction

    Depuis la 1.11, Forge a rajouté un package nommé net.minecraftforge.server.permission contenant la classe PermissionAPI qui permet désormais de
    gérer les permissions avec un système interne à Forge.
    Le concept est le suivant: les mods enregistrent des permissions (appelées Nodes) via
    PermissionAPI#registerNode puis, lorsque qu'ils ont besoin de vérifier si un joueur a une permission, ils n'ont qu'utiliser la fonction
    PermissionAPI#hasPermission.
    Pour gérer tout ceci, Forge a besoin d'une classe implémentant l'interface IPermissionHandler, il n'y a qu'une et qu'une seule classe qui peut gérer
    les permissions. Forge met à disposition sa propre classe appelée DefaultPermissionHandler, cependant elle n'est pas très complète et c'est, je pense,
    voulu de la part des développeurs de Forge. Cette classe peut être changée en utilisant PermissionAPI#setPermissionHandler.

    Dans ce tutoriel nous aborderons tout d'abord la façon d'enregistrer les nodes et de vérifier si un joueur a une permission, puis nous nous intéresserons
    à la façon de créer son propre système.

    Pré-requis

    Il n'y a aucun pré-requis à ce tutoriel.

    Code

    Enregistrer ses permissions

    Pour enregistrer vos permissions, il faut appeler la fonction PermissionAPI#registerNode après la phase de pre-initialisation, c'est très important.
    La fonction prend 3 paramètres :

    • Le nom de la node (String) : c'est le nom de votre permission, elle doit être du format modid.subgroup.permission_id, ce n'est pas obligatoire mais
      c'est le format recommandé par Forge. Attention, les nodes sont sensibles à la casse (a != A).
    • Le niveau de permission par défaut (DefaultPermissionLevel) : cela sert à définir qui a cette permission (par défaut), les valeurs possibles sont ALL, OP, NONE, elles font partie de l'enum DefaultPermissionLevel.
    • La description (String) : cet argument vous sert à décrire à quoi sert votre permission.
      Attention : aucun de ces arguments ne peut être null.

    Exemple d'enregistrement d'une permission fictive :

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        PermissionAPI.registerNode("mfftuto.items.laser", DefaultPermissionLevel.OP, "Donne accès à l'utilisation du pistolet laser");
    }
    

    Voilà, c'est tout pour l'enregistrement des permissions.

    Vérifier si un joueur a une permission

    Une fois vos permissions enregistrées, vous pouvez à tout moment appeler la fonction PermissionAPI#hasPermission pour savoir si le joueur passé en
    argument a la permission donnée.

    La fonction prend deux arguments :

    • Le joueur (EntityPlayer) : le joueur que vous voulez tester.
    • La node (String) : la permission à tester.
      Exemple fictif :
    public ActionResult <itemstack>onItemRightClick(World world, EntityPlayer player, EnumHand hand)
    {
        if(PermissionAPI.hasPermission(player, "mfftuto.items.laser")) {
            // On envoie un rayon laser
            // ...
            return new ActionResult(EnumActionResult.SUCCESS, player.getHeldItem(hand));
        }
        return new ActionResult(EnumActionResult.PASS, player.getHeldItem(hand));
    }
    

    On peut aussi utiliser un autre prototype de la fonction :

    public static boolean hasPermission(GameProfile profile, String node, @Nullable IContext context)
    

    L'instance du GameProfile peut-être récupérée depuis l'instance du joueur avec :

    player.getGameProfile();
    

    La node est votre permission.

    Le IContext est un context dans lequel se trouve le joueur, il en existe plusieurs créés par Forge :

    • AreaContext
    • BlockPosContext
    • PlayerContext
    • TargetContext
    • WorldContext
      Je ne parlerai pas des ContextKey car je n'ai pas encore totalement assimilé le fonctionnement.

    Cet argument sera passé à la classe implémentant l'interface IPermissionHandler afin qu'il puisse l'utiliser pour savoir si le joueur possède la permission donnée.

    Exemple :

    public ActionResult <itemstack>onItemRightClick(World world, EntityPlayer player, EnumHand hand)
    {
        if(PermissionAPI.hasPermission(player, "mfftuto.items.laser", new WorldContext(world))) {
            // On envoie un rayon laser
            // ...
            return new ActionResult(EnumActionResult.SUCCESS, player.getHeldItem(hand));
        }
        return new ActionResult(EnumActionResult.PASS, player.getHeldItem(hand));
    }
    

    Les contexts ne sont pas utilisés par la classe DefaultPermissionHandler de Forge mais, comme dit dans l'introduction, je ne pense pas que cette API soit
    faite pour que l'on garde la classe de base. Deuxième information, la fonction PermissionAPI#hasPermission(EntityPlayer player, String node) crée un PlayerContext.

    Créer sa propre implémentation de IPermissionHandle

    L'interface IPermissionHandler vous permet de créer votre propre système pour gérer les permissions.
    Premièrement il vous faut créer une classe implémentant cette interface :

    public class CustomPermissionHandler implements IPermissionHandler {
    
        @Override
        public void registerNode(String node, DefaultPermissionLevel level, String desc) {
    
        }
    
        @Override
        public Collection <string>getRegisteredNodes() {
            return null;
        }
    
        @Override
        public boolean hasPermission(GameProfile profile, String node, IContext context) {
            return false;
        }
    
        @Override
        public String getNodeDescription(String node) {
            return null;
        }
    }
    

    Dans cette classe, la fonction registerNode sera appelée à chaque fois qu'un mod va enregistrer une permission.
    La fonction getRegisteredNodes doit renvoyer toutes les permissions enregistrées.
    La fonction hasPermission doit renvoyer si oui ou non le joueur a la permission donnée.
    Et la fonction getNodeDescription doit renvoyer la description de la permission donnée.

    Je ne vais pas vous faire d'exemple ici, vous pouvez regarder comment gère tout ceci Forge dans la classe DefaultPermissionHandler mais
    le but ici est de faire votre propre système.

    Il vous faudra ensuite définir votre classe comme PermissionHandler durant la phase de pre-initialisation :

    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
        PermissionAPI.setPermissionHandler(new CustomPermissionHandler());
    }
    

    Et c'est tout. Merci d'avoir lu, mettez un pouce bleu et n'hésitez pas à partager :troll: 😉



  • Bravo BRAVO !



  • Salut,

    Premièrement super tuto ! Mais une chose reste floue pour moi, à quoi servent les autres IContext que tu énumères, AreaContext, BlockPosContext, PlayerContext, TargetContext ?
    Quand est-ce qu'il est indispensable de s'en servir ? Car ton exemple ne nous illustre que le WorldContext.


  • Rédacteurs

    Merci, d'après ce que j'ai compris ils permettent de définir le contexte dans lequel le joueur se trouve. Par exemple, le joueur peut-il utiliser l'arme laser quand il est dans telle ou telle zone ?

    
    PermissionAPI.hasPermission(player.getGameProfile(), "mfftuto.item.laser", new AreaContext(player, new AxisAlignedBB(0, 0, 0, 10, 10, 10));
    
    

    Mais comme Forge ne l'utilise pas de base je ne sais pas trop, le mieux reste d'utiliser :

    
    PermissionAPI.hasPermission(player, "mfftuto.item.laser");
    
    

    Tient si ça t'intéresse : https://github.com/MinecraftForge/MinecraftForge/pull/3155

    EDIT : Après avoir fait quelques recherches, je peux définir correctement à quoi servent les contextes. Ils permettent au PermissionHandler d'avoir des précisions sur le joueur.

    Exemples :

    Le joueur peut-il casser un bloc ?
    -> Il est dans l'overworld : ok
    -> Il est dans le nether : non
    Pour différencier ceci : WorldContext

    Le joueur peut-il attaquer ?
    -> La cible est un mouton : oui
    -> La cible n'est pas un mouton : non
    Pour différencier : TargetContext

    Le joueur peut-il se téléporter ?
    -> Il est dans la zone de téléportation : oui
    -> Il n'est pas dans la zone de téléportation : non
    Pour différencier : AreaContext

    Le joueur casser ce bloc ?
    -> Le bloc se trouve en 0,0,0, c'est de la terre et il le casse par en dessous : oui
    -> Sinon : non
    Pour différencier : BlockPosContext

    Mais encore une fois avec PermissionAPI#hasPermission(EntityPlayer player, String node), c'est sûrement le mieux car on crée un PlayerContext qui contient le monde du joueur, sa position, sa cible, etc …



  • D'accord j'ai compris, merci de toutes ces informations qui en aideront plus d'un !