Skip to content

Player Ignore

Pétrus Pradella edited this page Sep 28, 2026 · 2 revisions

Player Ignore

EverNifeCore does not ignore anybody. It holds the question "does A ignore B?" so a chat plugin, a /tpa plugin and an ignore plugin can agree on the answer without knowing about each other. Until a plugin answers a kind, the answer is no.

Everything lives in br.com.finalcraft.evernifecore.ignore, in common - same API on Bukkit and Hytale.

Kinds

IgnoreKind Hides Also covered by
CHAT every chat line, private messages included -
PRIVATE_MESSAGE /msg, /tell, /r CHAT
TELEPORT_REQUEST /tpa, /tpahere -

Each kind has at most one provider, and each can come from a different plugin. Asking about PRIVATE_MESSAGE also asks the CHAT provider, so a player who ignores someone's whole chat never gets their private messages either - even when the two kinds are implemented by different plugins.

Asking (chat, tpa, ...)

ECIgnores ignores = EverNifeCore.getProviders().getIgnores();

// Chat - the async event, one check per recipient
event.getRecipients().removeIf(r -> ignores.isIgnoring(r.getUniqueId(), sender.getUniqueId(), IgnoreKind.CHAT));

// /msg
if (ignores.isIgnoring(target.getUniqueId(), sender.getUniqueId(), IgnoreKind.PRIVATE_MESSAGE)) {
    return;
}

// /tpa
if (ignores.isIgnoring(target.getUniqueId(), requester.getUniqueId(), IgnoreKind.TELEPORT_REQUEST)) {
    return;
}

The first UUID is the one who ignores, the second the one being ignored. A player never ignores themselves. What the ignored player is told, if anything, is the asking plugin's call.

isIgnoring answers from memory, so a provider may say no for an ignorer who is offline. A caller that can wait - a mail, a party invite, a request queued for later - asks the async variant, which lets the provider load the ignorer's data first:

ignores.isIgnoringAsync(target, sender, IgnoreKind.PRIVATE_MESSAGE).thenAccept(ignoring -> {
    if (!ignoring) deliverMail(target, sender);
});

It walks the same broader kinds, completing true on the first provider that says so. Never join() it on the main or chat thread - that is the storage read isIgnoring exists to avoid.

Answering (an ignore plugin)

private final IIgnoreProvider chatIgnores = (ignorer, ignored) -> cache.isIgnoring(ignorer, ignored);

public void onECPluginEnable() {
    EverNifeCore.getProviders().getIgnores().setProvider(IgnoreKind.CHAT, chatIgnores);
}

public void onECPluginShutdown() {
    EverNifeCore.getProviders().getIgnores().removeProvider(IgnoreKind.CHAT, chatIgnores);
}

To answer for offline ignorers too, override isIgnoringAsync and load there; isIgnoring keeps answering from memory. Without the override the async answer is the synchronous one.

private final IIgnoreProvider chatIgnores = new IIgnoreProvider() {
    @Override
    public boolean isIgnoring(UUID ignorer, UUID ignored) {
        IgnoreData data = PlayerController.getLoadedSection(ignorer, IgnoreData.class);
        return data != null && data.isIgnoring(ignored);
    }

    @Override
    public CompletableFuture<Boolean> isIgnoringAsync(UUID ignorer, UUID ignored) {
        return PlayerController.getPDSection(ignorer, IgnoreData.class)
                .thenApply(data -> data.isIgnoring(ignored));
    }
};
  • Keep the provider in a field. removeProvider only removes the instance you pass, so a plugin that disables after another took the kind over does not evict it. A fresh lambda at disable time removes nothing.
  • Thread-safe and in memory. Chat is checked off the main thread, once per recipient per line. Answer from a cache, never from storage.
  • Policy is yours. Staff bypass, a permission that cannot be ignored - check it inside the provider. The core relays the boolean and nothing else.
  • Setting a kind someone else already provides replaces them and logs a warning.

Clone this wiki locally