Skip to content

Commit

Permalink
Add channel message cooldowns (#491)
Browse files Browse the repository at this point in the history
* Add cooldown channel setting

* Add missing documentation

* Add cooldown bypass permission
  • Loading branch information
Draycia committed Jun 12, 2024
1 parent e10c587 commit 93b8bc4
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 1 deletion.
28 changes: 28 additions & 0 deletions api/src/main/java/net/draycia/carbon/api/channels/ChatChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,32 @@ public interface ChatChannel extends Keyed, ChatComponentRenderer {
*/
boolean emptyRadiusRecipientsMessage();

/**
* The time in milliseconds between player messages.
* -1 and 0 disable the cooldown for this channel.
*
* @return The message cooldown in millis.
* @since 3.0.0
*/
long cooldown();

/**
* The epoch time (millis) when the player's cooldown expires.
*
* @param player The player
* @return The epoch time (millis) when the player's cooldown expires.
* @since 3.0.0
*/
long playerCooldown(CarbonPlayer player);

/**
* Starts the cooldown timer for the specified player. Duration will be the channel cooldown.
* Returns the player's old cooldown time, if they have one.
*
* @param player The player
* @return The player's old cooldown, or 0 if they don't have one.
* @since 3.0.0
*/
long startCooldown(CarbonPlayer player);

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import net.draycia.carbon.common.messages.placeholders.ComponentPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.IntPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.KeyPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.LongPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.OptionPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.StringPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.UUIDPlaceholderResolver;
Expand Down Expand Up @@ -166,6 +167,7 @@ public CarbonMessages carbonMessages(
final UUIDPlaceholderResolver<Audience> uuidPlaceholderResolver,
final StringPlaceholderResolver<Audience> stringPlaceholderResolver,
final IntPlaceholderResolver<Audience> intPlaceholderResolver,
final LongPlaceholderResolver<Audience> longPlaceholderResolver,
final KeyPlaceholderResolver<Audience> keyPlaceholderResolver,
final BooleanPlaceholderResolver<Audience> booleanPlaceholderResolver,
final CarbonMessageSource carbonMessageSource,
Expand All @@ -182,6 +184,7 @@ public CarbonMessages carbonMessages(
.weightedPlaceholderResolver(UUID.class, uuidPlaceholderResolver, 0)
.weightedPlaceholderResolver(String.class, stringPlaceholderResolver, 0)
.weightedPlaceholderResolver(Integer.class, intPlaceholderResolver, 0)
.weightedPlaceholderResolver(Long.class, longPlaceholderResolver, 0)
.weightedPlaceholderResolver(Key.class, keyPlaceholderResolver, 0)
.weightedPlaceholderResolver(Boolean.class, booleanPlaceholderResolver, 0)
.weightedPlaceholderResolver(Option.class, new OptionPlaceholderResolver<>(), 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import io.leangen.geantyref.TypeToken;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import net.draycia.carbon.api.CarbonServer;
Expand All @@ -41,6 +43,7 @@
import net.draycia.carbon.common.messages.placeholders.ComponentPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.IntPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.KeyPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.LongPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.StringPlaceholderResolver;
import net.draycia.carbon.common.messages.placeholders.UUIDPlaceholderResolver;
import net.draycia.carbon.common.util.Exceptions;
Expand Down Expand Up @@ -111,6 +114,10 @@ public class ConfigChatChannel implements ChatChannel {
because they're out of range from the radius.""")
private boolean emptyRadiusRecipientsMessage = true;

private Map<UUID, Long> cooldowns = new HashMap<>();

private long cooldown = -1;

@Override
public @Nullable String quickPrefix() {
if (this.quickPrefix == null || this.quickPrefix.isBlank()) {
Expand Down Expand Up @@ -185,6 +192,25 @@ public List<Audience> recipients(final CarbonPlayer sender) {
return recipients;
}

@Override
public long cooldown() {
return this.cooldown * 1000; // Seconds to millis
}

@Override
public long playerCooldown(final CarbonPlayer player) {
if (this.cooldown() <= 0) {
return 0;
}

return Objects.requireNonNullElse(this.cooldowns.get(player.uuid()), 0L);
}

public long startCooldown(final CarbonPlayer player) {
final long expiresAt = System.currentTimeMillis() + this.cooldown();
return Objects.requireNonNullElse(this.cooldowns.put(player.uuid(), expiresAt), 0L);
}

@Override
public @NonNull Key key() {
return Objects.requireNonNull(this.key);
Expand Down Expand Up @@ -214,6 +240,7 @@ private ConfigChannelMessages loadMessages() {
.weightedPlaceholderResolver(UUID.class, uuidPlaceholderResolver, 0)
.weightedPlaceholderResolver(String.class, stringPlaceholderResolver, 0)
.weightedPlaceholderResolver(Integer.class, new IntPlaceholderResolver<>(), 0)
.weightedPlaceholderResolver(Long.class, new LongPlaceholderResolver<>(), 0)
.weightedPlaceholderResolver(Key.class, keyPlaceholderResolver, 0)
.weightedPlaceholderResolver(Boolean.class, booleanPlaceholderResolver, 0)
.create(this.getClass().getClassLoader());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ protected ChatListenerInternal(
sender.sendMessage(permitted.reason());
return null;
}

if (!sender.hasPermission("carbon.cooldown.exempt") && channel.cooldown() > 0) {
final long currentMillis = System.currentTimeMillis();
final long expiresAt = channel.playerCooldown(sender);

if (currentMillis < expiresAt) {
// Round up, or the player can be told they have 0 seconds remaining
final long remaining = (long) Math.ceil((double) (expiresAt - currentMillis) / 1000);
this.carbonMessages.channelCooldown(sender, remaining);
return null;
}

channel.startCooldown(sender);
}

String content = this.configManager.primaryConfig().applyChatPlaceholders(messageContent);
content = this.configManager.primaryConfig().applyChatFilters(content);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public interface CarbonMessages {
@Message("channel.joined")
void channelJoined(final Audience audience);

@Message("channel.cooldown")
void channelCooldown(final Audience audience, long remaining);

/*
* =============================================================
* =========================== Mutes ===========================
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.common.messages.placeholders;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.moonshine.placeholder.ConclusionValue;
import net.kyori.moonshine.placeholder.ContinuanceValue;
import net.kyori.moonshine.placeholder.IPlaceholderResolver;
import net.kyori.moonshine.util.Either;
import org.checkerframework.checker.nullness.qual.Nullable;

public class LongPlaceholderResolver<R> implements IPlaceholderResolver<R, Long, Tag> {

@Override
public @Nullable Map<String, Either<ConclusionValue<? extends Tag>, ContinuanceValue<?>>> resolve(
final String placeholderName,
final Long value,
final R receiver,
final Type owner,
final Method method,
final @Nullable Object[] parameters
) {
return Map.of(placeholderName, Either.left(ConclusionValue.conclusionValue(Tag.preProcessParsed(String.valueOf(value)))));
}

}
1 change: 1 addition & 0 deletions common/src/main/resources/locale/messages-en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ whisper.ignoring_all=<red>You cannot send messages while they are ignored!
whisper.to=<click:suggest_command:'/whisper <recipient_username> '><hover:show_text:'Click to start another message to <recipient_display_name>'><gold>[<green>You</green>] -> [<green><recipient_display_name></green>] <message>
whisper.toggled.on=Now receiving private messages.
whisper.toggled.off=No longer receiving private messages.
channel.cooldown=<red>You may use chat again in <remaining> seconds!
channel.radius.empty_recipients=<red>You're not close enough to anyone to send a message
channel.joined=<green>You have rejoined the channel</green>
channel.left=<red>You have left the channel</red>
Expand Down
2 changes: 1 addition & 1 deletion paper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ tasks {
withType(RunServer::class).configureEach {
version.set(libs.versions.minecraft)
downloadPlugins {
url("https://download.luckperms.net/1533/bukkit/loader/LuckPerms-Bukkit-5.4.120.jar")
url("https://download.luckperms.net/1543/bukkit/loader/LuckPerms-Bukkit-5.4.130.jar")
github("MiniPlaceholders", "MiniPlaceholders", libs.versions.miniplaceholders.get(), "MiniPlaceholders-Paper-${libs.versions.miniplaceholders.get()}.jar")
github("MiniPlaceholders", "PlaceholderAPI-Expansion", "1.2.0", "PlaceholderAPI-Expansion-1.2.0.jar")
hangar("PlaceholderAPI", libs.versions.placeholderapi.get())
Expand Down

0 comments on commit 93b8bc4

Please sign in to comment.