Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.List;
import net.draycia.carbon.api.users.CarbonPlayer;
import net.draycia.carbon.api.util.ChatComponentRenderer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Keyed;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand All @@ -46,13 +45,14 @@ public interface ChatChannel extends Keyed, ChatComponentRenderer {
ChannelPermissions permissions();

/**
* Returns a list of all recipients that will receive messages from the sender.
* Returns the {@link RecipientsResolver} for this channel. The return value is not cached,
* and {@link ChannelPermissions#speechPermitted(CarbonPlayer)} is checked before
* invoking this method.
*
* @param sender the sender of messages
* @return the recipients
* @since 2.0.0
* @return the recipients resolver
* @since 3.0.0
*/
List<Audience> recipients(CarbonPlayer sender);
RecipientsResolver recipientsResolver();

/**
* Messages will be sent in this channel if they start with this prefix.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* CarbonChat
*
* Copyright (c) 2024 Josua Parks (Vicarious)
* Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.draycia.carbon.api.channels;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import net.draycia.carbon.api.CarbonServer;
import net.draycia.carbon.api.users.CarbonPlayer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import org.checkerframework.common.returnsreceiver.qual.This;

/**
* Resolves the recipients for a message from a given sender.
*
* @see ChatChannel#recipientsResolver()
* @see #builder(CarbonServer)
* @since 3.0.0
*/
@FunctionalInterface
public interface RecipientsResolver {

/**
* Resolves the recipients for a message from a given sender.
*
* @param sender the sender to resolve recipients for
* @return resolved recipients
* @since 3.0.0
*/
List<Audience> recipients(CarbonPlayer sender);

/**
* Creates a new combined {@link RecipientsResolver} from this resolver and {@code resolver}.
*
* <p>
* Note that this method does not filter duplicate audiences.
* </p>
*
* @param resolver second resolver
* @return new combined resolver
* @since 3.0.0
*/
default RecipientsResolver and(final RecipientsResolver resolver) {
return sender -> {
final List<Audience> recipients = new ArrayList<>(this.recipients(sender));
recipients.addAll(resolver.recipients(sender));
return recipients;
};
}

/**
* Creates a new {@link Builder}.
*
* @param server server instance
* @return new {@link Builder}
* @since 3.0.0
*/
static Builder builder(final CarbonServer server) {
return new Builder(server);
}

/**
* Mutable builder for {@link RecipientsResolver}.
* <p>
* Custom implementations are supported, however the builder simplifies most use cases.
* </p>
*
* @since 3.0.0
*/
final class Builder {
private final CarbonServer server;
private final List<Predicate<CarbonPlayer>> playerFilters = new ArrayList<>();
private boolean includeConsole;

private Builder(final CarbonServer server) {
this.server = server;
}

/**
* Includes online players with permission to hear the channel that have not left the channel,
* using {@link #players(Predicate)}.
*
* @param channel channel
* @return this builder
* @since 3.0.0
*/
public @This Builder permittedPlayersInChannel(final ChatChannel channel) {
return this.permittedPlayersInChannel(channel.permissions(), channel.key());
}

/**
* Includes online players with permission to hear the channel that have not left the channel,
* using {@link #players(Predicate)}.
*
* @param permissions permissions
* @param channelKey channel
* @return this builder
* @since 3.0.0
*/
public @This Builder permittedPlayersInChannel(final ChannelPermissions permissions, final Key channelKey) {
return this.players(player -> permissions.hearingPermitted(player).permitted()
&& !player.leftChannels().contains(channelKey));
}

/**
* Includes online players matching the predicate in the resolved recipients. Adding multiple predicates
* will include players matching any one of the predicates.
*
* @param filter player filter
* @return this builder
* @since 3.0.0
*/
public @This Builder players(final Predicate<CarbonPlayer> filter) {
this.playerFilters.add(filter);
return this;
}

/**
* Unconditionally includes the console in the resolved recipients.
*
* @return this builder
* @since 3.0.0
*/
public @This Builder console() {
this.includeConsole = true;
return this;
}

/**
* Builds a new {@link RecipientsResolver} from the current state of this builder.
*
* @return new {@link RecipientsResolver} instance
* @since 3.0.0
*/
public RecipientsResolver build() {
final boolean includeConsole = this.includeConsole;
final List<Predicate<CarbonPlayer>> playerFilters = List.copyOf(this.playerFilters);

return sender -> {
final List<Audience> recipients = new ArrayList<>();

if (!playerFilters.isEmpty()) {
for (final CarbonPlayer player : this.server.players()) {
if (playerFilters.stream().anyMatch(filter -> filter.test(player))) {
recipients.add(player);
}
}
}

if (includeConsole) {
recipients.add(this.server.console());
}

return recipients;
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import com.google.inject.Inject;
import io.leangen.geantyref.TypeToken;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -31,6 +30,7 @@
import net.draycia.carbon.api.CarbonServer;
import net.draycia.carbon.api.channels.ChannelPermissions;
import net.draycia.carbon.api.channels.ChatChannel;
import net.draycia.carbon.api.channels.RecipientsResolver;
import net.draycia.carbon.api.users.CarbonPlayer;
import net.draycia.carbon.common.channels.messages.ConfigChannelMessageSource;
import net.draycia.carbon.common.channels.messages.ConfigChannelMessages;
Expand Down Expand Up @@ -165,19 +165,11 @@ public ChannelPermissions permissions() {
}

@Override
public List<Audience> recipients(final CarbonPlayer sender) {
final List<Audience> recipients = new ArrayList<>();

for (final CarbonPlayer player : this.server.players()) {
if (this.permissions().hearingPermitted(player).permitted() && !player.leftChannels().contains(this.key)) {
recipients.add(player);
}
}

// console too!
recipients.add(this.server.console());

return recipients;
public RecipientsResolver recipientsResolver() {
return RecipientsResolver.builder(this.server)
.permittedPlayersInChannel(this)
.console()
.build();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Objects;
import java.util.UUID;
import net.draycia.carbon.api.channels.ChannelPermissions;
import net.draycia.carbon.api.channels.RecipientsResolver;
import net.draycia.carbon.api.users.CarbonPlayer;
import net.draycia.carbon.api.users.Party;
import net.draycia.carbon.common.channels.messages.ConfigChannelMessageSource;
Expand Down Expand Up @@ -66,18 +67,20 @@ public ChannelPermissions permissions() {
}

@Override
public List<Audience> recipients(final CarbonPlayer sender) {
final WrappedCarbonPlayer wrapped = (WrappedCarbonPlayer) sender;
final @Nullable UUID party = wrapped.partyId();
if (party == null) {
if (sender.online()) {
sender.sendMessage(this.messages.cannotUsePartyChannel(sender));
public RecipientsResolver recipientsResolver() {
return sender -> {
final WrappedCarbonPlayer wrapped = (WrappedCarbonPlayer) sender;
final @Nullable UUID party = wrapped.partyId();
if (party == null) {
if (sender.online()) {
sender.sendMessage(this.messages.cannotUsePartyChannel(sender));
}
return new ArrayList<>();
}
return new ArrayList<>();
}
final List<Audience> recipients = super.recipients(sender);
recipients.removeIf(r -> r instanceof WrappedCarbonPlayer p && !Objects.equals(p.partyId(), party));
return recipients;
final List<Audience> recipients = super.recipientsResolver().recipients(sender);
recipients.removeIf(r -> r instanceof WrappedCarbonPlayer p && !Objects.equals(p.partyId(), party));
return recipients;
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected ChatListenerInternal(
final List<KeyedRenderer> renderers = new ArrayList<>();
renderers.add(KeyedRenderer.keyedRenderer(Key.key("carbon", "default"), channel));

final List<Audience> recipients = channel.recipients(sender);
final List<Audience> recipients = channel.recipientsResolver().recipients(sender);

final var chatEvent = new CarbonChatEventImpl(sender, message, recipients, renderers, channel, signedMessage);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private boolean handleMessagePacket(final ChatMessagePacket messagePacket) {

final List<KeyedRenderer> renderers = new ArrayList<>();

final List<Audience> recipients = channel.recipients(sender);
final List<Audience> recipients = channel.recipientsResolver().recipients(sender);
final CarbonChatEventImpl chatEvent = new CarbonChatEventImpl(sender, messagePacket.message(), recipients, renderers, channel, null, false);
this.events.emit(chatEvent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.List;
import java.util.Map;
import net.draycia.carbon.api.channels.ChannelPermissions;
import net.draycia.carbon.api.channels.RecipientsResolver;
import net.draycia.carbon.api.users.CarbonPlayer;
import net.draycia.carbon.api.users.UserManager;
import net.draycia.carbon.common.channels.messages.ConfigChannelMessageSource;
Expand Down Expand Up @@ -71,26 +72,28 @@ public ChannelPermissions permissions() {
}

@Override
public List<Audience> recipients(final CarbonPlayer sender) {
if (!this.hasRelations(sender, Relation.ALLY)) {
if (sender.online()) {
sender.sendMessage(this.messages.cannotUseFactionAllianceChannel(sender));
public RecipientsResolver recipientsResolver() {
return sender -> {
if (!this.hasRelations(sender, Relation.ALLY)) {
if (sender.online()) {
sender.sendMessage(this.messages.cannotUseFactionAllianceChannel(sender));
}

return Collections.emptyList();
}

return Collections.emptyList();
}

final List<Audience> recipients = new ArrayList<>();
for (final Player player : this.alliedPlayersTo(sender)) {
final @Nullable CarbonPlayer carbon = this.users.user(player.getUniqueId()).getNow(null);
if (carbon != null) {
recipients.add(carbon);
final List<Audience> recipients = new ArrayList<>();
for (final Player player : this.alliedPlayersTo(sender)) {
final @Nullable CarbonPlayer carbon = this.users.user(player.getUniqueId()).getNow(null);
if (carbon != null) {
recipients.add(carbon);
}
}
}

recipients.add(this.server.console());
recipients.add(this.server.console());

return recipients;
return recipients;
};
}

private List<Player> alliedPlayersTo(final CarbonPlayer player) {
Expand Down
Loading