Aller au contenu

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.

@FunctionalInterface
public 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.

Reveal rassemble les règles prêtes à l’emploi.

FabriqueRé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.

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.

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.

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.