Skip to content

Commit

Permalink
feat(cmd): add non-disruptive /schat reload command
Browse files Browse the repository at this point in the history
Adds #10
  • Loading branch information
Silthus committed Nov 14, 2021
1 parent 3e956ec commit 486eb48
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 27 deletions.
14 changes: 12 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ default settings. Copy and adjust it to your needs.

## Commands

Your players won't need to remember any commands. All they need to do is click on the various UI elements in the chat.
For example: clicking on a channel will set the channel as active.
### Player Commands

Your players won't need to remember any commands. All they need to do is click on the various UI elements in the chat, *
e.g. clicking on a channel will set the channel as active*. However, here are the commands if you like typing:

| Commands | Alias | Permission | Description |
| -------- | ----- | ---------- | ----------- |
Expand All @@ -26,6 +28,12 @@ For example: clicking on a channel will set the channel as active.
| `/schat channel message <channel> <message>` | `/ch <channel> <message>` | `schat.player.channel.quickmessage` | Sends a message to the given channel without switching to it. |
| `/tell <player> [message]` | `/m`, `/w`, `/msg`, `/pm`, `/qm`, `/dm` | `schat.player.directmessage` | Sends a message to the given player or opens the conversation. |

### Admin Commands

| Commands | Alias | Permission | Description |
| -------- | ----- | ---------- | ----------- |
| `/schat reload` | | `schat.admin.reload` | Reloads the sChat config and all channels that have changes. This is non disruptive and will not touch unchanged channels. |

## Permissions

| Permission | Description |
Expand All @@ -36,6 +44,8 @@ For example: clicking on a channel will set the channel as active.
| `schat.player.channel.leave` | Allows the player to leave channels. |
| `schat.player.channel.quickmessage` | Enables the player to send quick messages (`/ch <channel> <message>`) to channels he is allowed to write in. |
| `schat.player.directmessage` | Allows the player to send direct messages (`/dm <player> <message>`) to other players. |
| `schat.admin` | This permission groups all admin permissions nested under the `schat.admin.*` permissions. OPs get this by default. |
| `schat.admin.reload` | Allows performing the `/schat reload` command to reload the plugin. |

### Channel Permissions

Expand Down
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ spigot {
'schat.player.directmessage': true
]
}
'schat.admin' {
description 'Contains all admin permissions for sChat.'
defaults 'op'
children = [
'schat.admin.reload': true
]
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/silthus/chat/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public final class Constants {
public static final String PERMISSION_PLAYER_CHANNEL_LEAVE = "schat.player.channel.leave";
public static final String PERMISSION_PLAYER_CHANNEL_QUICKMESSAGE = "schat.player.channel.quickmessage";
public static final String PERMISSION_PLAYER_DIRECT_MESSAGE = "schat.player.directmessage";
public static final String PERMISSION_ADMIN_RELOAD = "schat.admin.reload";

public static class Targets {

Expand Down Expand Up @@ -77,6 +78,7 @@ public static class Language {
public static final String JOINED_CHANNEL = "joined-channel";
public static final String LEAVE_CHANNEL = "leave-channel";
public static final String INVALID_CONVERSATION = "invalid-conversation";
public static final String PLUGIN_RELOADED = "plugin-reloaded";
}

public static class Errors {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/silthus/chat/Conversation.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ default Type getType() {
return Type.fromConversation(this);
}

void close();

enum Type {
CHANNEL,
DIRECT,
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/net/silthus/chat/SChat.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public final class SChat extends JavaPlugin {
private PluginConfig pluginConfig;
private Metrics metrics;

@Setter(AccessLevel.PACKAGE)
private ChannelRegistry channelRegistry;
private ChatterManager chatterManager;
private ConversationManager conversationManager;
Expand All @@ -94,6 +95,17 @@ public SChat(
testing = true;
}

public void reload() {
reloadConfig();

final PluginConfig oldConfig = getPluginConfig();
pluginConfig = PluginConfig.fromConfig(getConfig());

if (oldConfig.equals(pluginConfig)) return;

getChannelRegistry().load(getPluginConfig());
}

@Override
public void onEnable() {
if (!isTesting() && isNotPaperMC()) {
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/net/silthus/chat/commands/SChatCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ public SChatCommands(SChat plugin) {
this.plugin = plugin;
}

@Subcommand("reload")
@CommandPermission(PERMISSION_ADMIN_RELOAD)
public void reload() {
plugin.reload();
success(PLUGIN_RELOADED);
}

@Subcommand("conversations")
public class ConversationCommands extends BaseCommand {

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/net/silthus/chat/config/PluginConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@

package net.silthus.chat.config;

import lombok.Data;
import lombok.NonNull;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.extern.java.Log;
import net.silthus.chat.Constants;
Expand All @@ -33,8 +32,10 @@
import static java.util.stream.Collectors.toMap;

@Data
@Builder
@Accessors(fluent = true)
@Log(topic = Constants.PLUGIN_NAME)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class PluginConfig {

public static PluginConfig fromConfig(ConfigurationSection config) {
Expand All @@ -44,6 +45,7 @@ public static PluginConfig fromConfig(ConfigurationSection config) {
private final Defaults defaults;
private final ConsoleConfig console;
private final PrivateChatConfig privateChat;
@Singular
private final Map<String, ChannelConfig> channels;

private PluginConfig(@NonNull ConfigurationSection config) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,10 @@ public int compareTo(@NonNull Conversation o) {
.thenComparing(Identity::getName)
.compare(this, o);
}

@Override
public void close() {
getTargets().forEach(target -> target.unsubscribe(this));
targets.clear();
}
}
6 changes: 5 additions & 1 deletion src/main/java/net/silthus/chat/conversations/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@ public static Channel channel(String identifier, ChannelConfig config) {
return SChat.instance().getChannelRegistry().getOrCreate(identifier, config);
}

private final ChannelConfig config;
private ChannelConfig config;

Channel(String identifier) {
this(identifier, ChannelConfig.defaults());
}

Channel(String identifier, ChannelConfig config) {
super(identifier);
setConfig(config);
}

public void setConfig(ChannelConfig config) {
this.config = config;
if (config.name() != null)
setDisplayName(Component.text(config.name()));
Expand Down
35 changes: 26 additions & 9 deletions src/main/java/net/silthus/chat/conversations/ChannelRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import lombok.extern.java.Log;
import net.kyori.adventure.text.Component;
import net.silthus.chat.Constants;
import net.silthus.chat.Conversation;
import net.silthus.chat.SChat;
import net.silthus.chat.config.ChannelConfig;
import net.silthus.chat.config.PluginConfig;
Expand All @@ -33,7 +34,7 @@

@Log(topic = Constants.PLUGIN_NAME)
@AllArgsConstructor
public final class ChannelRegistry implements Iterable<Channel> {
public class ChannelRegistry implements Iterable<Channel> {

private final SChat plugin;
private final Map<String, Channel> channels = Collections.synchronizedMap(new HashMap<>());
Expand Down Expand Up @@ -77,6 +78,14 @@ public Channel getOrCreate(@NonNull String identifier, ChannelConfig config) {
return channels.computeIfAbsent(identifier.toLowerCase(), s -> new Channel(s, config));
}

public Channel get(@NonNull String identifier) {
return channels.get(identifier.toLowerCase());
}

public Channel create(@NonNull String identifier, @NonNull ChannelConfig config) {
return channels.compute(identifier, (s, channel) -> new Channel(identifier, config));
}

public int size() {
return channels.size();
}
Expand All @@ -91,31 +100,39 @@ public boolean contains(Channel channel) {
}

public void clear() {
channels.values().forEach(channel -> channel.getTargets().forEach(target -> target.unsubscribe(channel)));
channels.values().forEach(Conversation::close);
channels.clear();
}

public void load(@NonNull PluginConfig config) {
clear();
loadChannels(config);
}

private void loadChannels(@NonNull PluginConfig config) {
config.channels().entrySet().stream()
.map(entry -> Channel.channel(entry.getKey(), entry.getValue()))
.forEach(this::add);
for (Map.Entry<String, ChannelConfig> entry : config.channels().entrySet()) {
if (contains(entry.getKey())) {
get(entry.getKey()).setConfig(entry.getValue());
} else {
create(entry.getKey(), entry.getValue());
}
}
final Set<String> channelsToRemove = new HashSet<>(channels.keySet());
channelsToRemove.removeAll(config.channels().keySet());
channelsToRemove.forEach(this::remove);
}

public void add(@NonNull Channel channel) {
this.channels.put(channel.getName(), channel);
}

public boolean remove(@NonNull Channel channel) {
return this.channels.remove(channel.getName(), channel);
public void remove(@NonNull Channel channel) {
remove(channel.getName());
}

public Channel remove(String identifier) {
if (identifier == null) return null;
return this.channels.remove(identifier.toLowerCase());
final Channel channel = this.channels.remove(identifier.toLowerCase());
if (channel != null) channel.close();
return channel;
}
}
3 changes: 0 additions & 3 deletions src/main/resources/config.default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ defaults:
console:
# This is the channel the console will send chat messages to.
default_channel: global
private_chats:
# set false to only allow private chats on the active server
global: true
# Define your list of channels here.
channels:
# The id of the channel must be unique across your server network.
Expand Down
3 changes: 0 additions & 3 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ defaults:
console:
# This is the channel the console will send chat messages to.
default_channel: global
private_chats:
# set false to only allow private chats on the active server
global: true
# Define your list of channels here.
channels:
# The id of the channel must be unique across your server network.
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/lang_en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ commands:
joined-channel: "&7You joined the channel: &6{channel}&7."
leave-channel: "&7You left the channel: &6{channel}&7."
invalid-conversation: "The conversation you tried to join does not exist."
cannot-send-to-self: "You can't send messages to yourself."
cannot-send-to-self: "You can't send messages to yourself."
plugin-reloaded: "sChat and all channel configs have been reloaded."
49 changes: 49 additions & 0 deletions src/test/java/net/silthus/chat/SChatTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@

import co.aikar.commands.BukkitCommandManager;
import net.kyori.adventure.text.Component;
import net.silthus.chat.config.ChannelConfig;
import net.silthus.chat.config.PluginConfig;
import net.silthus.chat.conversations.Channel;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

class SChatTest extends TestBase {

Expand Down Expand Up @@ -82,4 +88,47 @@ void writes_defaultConfig() {
assertThat(config).exists();
assertThat(defaultConfig).exists();
}

@Nested
class Reload {

@BeforeEach
void setUp() {

plugin.setChannelRegistry(spy(plugin.getChannelRegistry()));
}

@Test
void reload_loadsNewConfigYAML() {
loadTestConfig("reload-test.yml");
final PluginConfig oldConfig = plugin.getPluginConfig();
plugin.reload();
final PluginConfig newConfig = plugin.getPluginConfig();

assertThat(oldConfig).isNotEqualTo(newConfig);
assertThat(newConfig)
.extracting(PluginConfig::defaults)
.extracting(PluginConfig.Defaults::channel)
.extracting(
ChannelConfig::autoJoin,
ChannelConfig::protect,
ChannelConfig::canLeave
).contains(
true,
true,
false
);
}

@Test
void reloadsChannels_ifConfigChanged() {
plugin.reload();
verify(plugin.getChannelRegistry(), never()).load(any());

loadTestConfig("reload-test.yml");
plugin.reload();
verify(plugin.getChannelRegistry()).load(any());
}
}

}
11 changes: 11 additions & 0 deletions src/test/java/net/silthus/chat/TestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;

Expand All @@ -71,6 +75,7 @@ public void setUp() {
plugin.setChatPacketQueue(spy(new ChatPacketQueue(plugin)));
setupVaultMock();
setupBungeecordMock();
plugin.setChannelRegistry(spy(plugin.getChannelRegistry()));

}

Expand Down Expand Up @@ -181,4 +186,10 @@ protected Collection<Message> randomMessages(int count) {
protected String cleaned(@NonNull String message) {
return ChatColor.stripColor(message.stripLeading());
}

@SneakyThrows
protected void loadTestConfig(String name) {
final File config = new File(plugin.getDataFolder(), "config.yml");
Files.copy(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResourceAsStream(name)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
Loading

0 comments on commit 486eb48

Please sign in to comment.