Règles de révélation
Par défaut, tous ceux qui se trouvent dans une zone sont masqués les uns pour les autres. Une règle de visibilité définit une exception : des couples de joueurs qui se voient tels qu’ils sont.
L’interface
Section intitulée « L’interface »@FunctionalInterfacepublic interface VisibilityRule { boolean reveals(Player viewer, Player target, RuleContext context);}Une question, une réponse : est-ce que viewer voit target sous sa vraie identité ? Renvoyer false
laisse le déguisement en place.
Les fabriques
Section intitulée « Les fabriques »Reveal rassemble les règles prêtes à l’emploi.
| Fabrique | Révèle une cible quand |
|---|---|
Reveal.sameGroup() | L’observateur et la cible appartiennent au même groupe. |
Reveal.group(String) | La cible appartient à ce groupe. Révélée à tout le monde. |
Reveal.group(Supplier<String>) | Pareil, le groupe étant lu au moment de l’évaluation. |
Reveal.groupsTogether(Supplier<Collection<String>>) | L’observateur et la cible appartiennent tous deux à l’ensemble de groupes. |
Reveal.permission(String) | L’observateur possède cette permission. |
Reveal.target(Predicate<Player>) | La cible correspond, quel que soit l’observateur. |
Reveal.of(BiPredicate<Player, Player>) | Le couple observateur / cible correspond. |
Reveal.never() | Jamais. Tout le monde reste masqué. |
Les deux surcharges de group diffèrent par le moment où l’identifiant est lu. Passez une String
pour un groupe connu une fois pour toutes, et un Supplier quand il change en cours de partie, comme
la faction qui tient un KoTH.
groupsTogether est symétrique là où group ne l’est pas : group révèle ses membres à toute la
zone, tandis que groupsTogether révèle les groupes listés entre eux et à personne d’autre.
Composer
Section intitulée « Composer »Les règles se combinent avec or, and et negate :
VisibilityRule rule = Reveal.sameGroup() .or(Reveal.permission("myserver.staff"));Passer plusieurs règles à reveal(...) est autre chose : elles sont examinées dans l’ordre, et la
première qui correspond décide. Composez avec or quand vous voulez une seule règle, et passez une
liste quand les règles doivent être examinées l’une après l’autre.
Écrire la vôtre
Section intitulée « Écrire la vôtre »Tout ce que les fabriques ne couvrent pas s’écrit en lambda :
.reveal(Reveal.target(player -> player.getGameMode() == GameMode.CREATIVE))Préférez Reveal.target quand la réponse ne dépend que de la cible, et gardez Reveal.of pour les cas
où elle dépend vraiment des deux joueurs. La différence n’est pas cosmétique, la section suivante
explique pourquoi.
Une règle qui lève une exception est ignorée, et SomaHider inscrit l’échec une seule fois par classe de règle plutôt qu’à chaque passe.
Garder les règles économes
Section intitulée « Garder les règles économes »Une règle s’exécute pour chaque couple observateur / cible, plusieurs fois par seconde. Sur une zone chargée, cela représente des milliers d’appels par seconde, sur le thread principal. Deux mécanismes rendent la chose supportable, et les deux dépendent de la façon dont vous écrivez vos règles.
Le premier est le regroupement. Quand toutes les règles d’une zone se décident à partir de la seule
appartenance à un groupe, SomaHider évalue la zone une fois par groupe au lieu d’une fois par
observateur. Toutes les fabriques ci-dessus fonctionnent ainsi, à l’exception de permission et de
of, ainsi que toute composition de celles-ci. Il n’y a rien à configurer : SomaHider le déduit des
règles elles-mêmes. Un seul Reveal.of(...) dans la liste désactive le mécanisme pour toute la zone,
d’où l’intérêt de préférer Reveal.target quand il convient.
Le second est RuleContext.once :
public interface RuleContext { String groupOf(Player player); boolean hasPermission(Player viewer, String node); <T> T once(Supplier<T> supplier);}once évalue un supplier au plus une fois par passe et transmet la même valeur à tous les couples de
cette passe. Servez-vous-en dès qu’une règle lit quelque chose de coûteux qui ne dépend ni de
l’observateur ni de la cible, comme un classement en direct.
private final Supplier<String> currentOwner = () -> koth.getOwner().getId();
VisibilityRule rule = (viewer, target, context) -> context.once(currentOwner).equals(context.groupOf(target));Le cache repose sur l’identité de l’instance : gardez donc le supplier dans un champ. En construire un
nouveau à chaque appel produit une nouvelle clé à chaque fois et ne met rien en cache. Les fabriques à
Supplier de Reveal s’en chargent déjà pour vous.