mirror of
https://github.com/kangarko/ChatControl.git
synced 2025-03-18 14:39:12 +01:00
Upload 11.1.3
This commit is contained in:
parent
e619da5efd
commit
dd66d55fdc
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
# These are some examples of commonly ignored file patterns.
|
||||
# You should customize this list as applicable to your project.
|
||||
# Learn more about .gitignore:
|
||||
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
||||
|
||||
upsell/
|
||||
chatcontrol-bungeecord/library
|
||||
chatcontrol-velocity/library
|
||||
|
||||
# Node artifact files
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
.classpath
|
||||
.externalToolBuilders/
|
||||
.project
|
||||
.settings/
|
||||
|
||||
# Compiled Java class files
|
||||
*.class
|
||||
|
||||
# Compiled Python bytecode
|
||||
*.py[cod]
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Maven
|
||||
target/
|
||||
dist/
|
||||
|
||||
# JetBrains IDE
|
||||
.idea/
|
||||
|
||||
# Unit test reports
|
||||
TEST*.xml
|
||||
|
||||
# Generated by MacOS
|
||||
.DS_Store
|
||||
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
ftp-settings.yml
|
30
chatcontrol-bukkit/build.xml
Normal file
30
chatcontrol-bukkit/build.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" ?>
|
||||
<project name="ChatControl" default="Build">
|
||||
<target name="Build">
|
||||
<jar jarfile="/Users/kangarko/Test Servers/1.8.8/plugins/${ant.project.name}.jar" basedir="./target/classes/" includes="**/*">
|
||||
<fileset dir="../chatcontrol-core/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-bukkit/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-core/target/classes" />
|
||||
</jar>
|
||||
<jar jarfile="/Users/kangarko/Test Servers/Second 1.8.8/plugins/${ant.project.name}.jar" basedir="./target/classes/" includes="**/*">
|
||||
<fileset dir="../chatcontrol-core/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-bukkit/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-core/target/classes" />
|
||||
</jar>
|
||||
<jar jarfile="/Users/kangarko/Test Servers/1.21/plugins/${ant.project.name}.jar" basedir="./target/classes/" includes="**/*">
|
||||
<fileset dir="../chatcontrol-core/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-bukkit/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-core/target/classes" />
|
||||
</jar>
|
||||
<jar jarfile="/Users/kangarko/Test Servers/Second 1.21/plugins/${ant.project.name}.jar" basedir="./target/classes/" includes="**/*">
|
||||
<fileset dir="../chatcontrol-core/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-bukkit/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-core/target/classes" />
|
||||
</jar>
|
||||
<!--<jar jarfile="/Users/kangarko/Test Servers/Non-Standard/1.21.1/plugins/${ant.project.name}.jar" basedir="./target/classes/" includes="**/*">
|
||||
<fileset dir="../chatcontrol-core/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-bukkit/target/classes" />
|
||||
<fileset dir="../../Foundation/foundation-core/target/classes" />
|
||||
</jar>-->
|
||||
</target>
|
||||
</project>
|
128
chatcontrol-bukkit/pom.xml
Normal file
128
chatcontrol-bukkit/pom.xml
Normal file
@ -0,0 +1,128 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.mineacademy</groupId>
|
||||
<artifactId>chatcontrol-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chatcontrol-bukkit</artifactId>
|
||||
<name>ChatControl</name>
|
||||
<version>11.1.3</version>
|
||||
|
||||
<properties>
|
||||
<main.class>org.mineacademy.chatcontrol.ChatControl</main.class>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy</groupId>
|
||||
<artifactId>chatcontrol-core</artifactId>
|
||||
<version>LATEST</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy</groupId>
|
||||
<artifactId>foundation-bukkit</artifactId>
|
||||
<version>LATEST</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MineAcademy repo -->
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>DiscordSRV</artifactId>
|
||||
<version>1.28.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>dynmap</artifactId>
|
||||
<version>3.7b7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>SimpleClans</artifactId>
|
||||
<version>2.19.3-SNAPSHOT-418</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>TownyChat</artifactId>
|
||||
<version>0.115</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>mcMMO</artifactId>
|
||||
<version>2.1.231</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>EssentialsX</artifactId>
|
||||
<version>2.21.0-SNAPSHOT-1565</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mineacademy.plugin</groupId>
|
||||
<artifactId>AuthMe</artifactId>
|
||||
<version>5.6.0-SNAPSHOT-2622</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>org.mineacademy:foundation-bukkit*</include>
|
||||
<include>org.mineacademy:chatcontrol-core*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.mineacademy.fo</pattern>
|
||||
<shadedPattern>org.mineacademy.chatcontrol.lib</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,401 @@
|
||||
package org.mineacademy.chatcontrol;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.CommandDummy;
|
||||
import org.mineacademy.chatcontrol.command.CommandIgnore;
|
||||
import org.mineacademy.chatcontrol.command.CommandList;
|
||||
import org.mineacademy.chatcontrol.command.CommandMail;
|
||||
import org.mineacademy.chatcontrol.command.CommandMe;
|
||||
import org.mineacademy.chatcontrol.command.CommandMotd;
|
||||
import org.mineacademy.chatcontrol.command.CommandMute;
|
||||
import org.mineacademy.chatcontrol.command.CommandRealName;
|
||||
import org.mineacademy.chatcontrol.command.CommandReply;
|
||||
import org.mineacademy.chatcontrol.command.CommandSay;
|
||||
import org.mineacademy.chatcontrol.command.CommandSpy;
|
||||
import org.mineacademy.chatcontrol.command.CommandTag;
|
||||
import org.mineacademy.chatcontrol.command.CommandTell;
|
||||
import org.mineacademy.chatcontrol.command.CommandToggle;
|
||||
import org.mineacademy.chatcontrol.listener.BookListener;
|
||||
import org.mineacademy.chatcontrol.listener.CommandListener;
|
||||
import org.mineacademy.chatcontrol.listener.PlayerListener;
|
||||
import org.mineacademy.chatcontrol.listener.TabListener;
|
||||
import org.mineacademy.chatcontrol.listener.ThirdPartiesListener;
|
||||
import org.mineacademy.chatcontrol.listener.chat.AdventureChatListener;
|
||||
import org.mineacademy.chatcontrol.listener.chat.LegacyChatListener;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.Colors;
|
||||
import org.mineacademy.chatcontrol.model.Format;
|
||||
import org.mineacademy.chatcontrol.model.Migrator;
|
||||
import org.mineacademy.chatcontrol.model.Newcomer;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.ProxyChat;
|
||||
import org.mineacademy.chatcontrol.model.WarningPoints;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.Database;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.operator.Groups;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessages;
|
||||
import org.mineacademy.chatcontrol.operator.Rules;
|
||||
import org.mineacademy.chatcontrol.operator.Tag;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.FileUtil;
|
||||
import org.mineacademy.fo.MinecraftVersion;
|
||||
import org.mineacademy.fo.MinecraftVersion.V;
|
||||
import org.mineacademy.fo.RandomUtil;
|
||||
import org.mineacademy.fo.command.DebugSubCommand;
|
||||
import org.mineacademy.fo.debug.Debugger;
|
||||
import org.mineacademy.fo.model.HookManager;
|
||||
import org.mineacademy.fo.model.SimpleBook;
|
||||
import org.mineacademy.fo.model.Variable;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.platform.BukkitPlugin;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.region.DiskRegion;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.YamlConfig;
|
||||
import org.mineacademy.fo.visual.VisualizedRegion;
|
||||
|
||||
import github.scarsz.discordsrv.DiscordSRV;
|
||||
|
||||
/**
|
||||
* ChatControl is a simple chat management plugin.
|
||||
*
|
||||
* @since last major code audit November 2024
|
||||
*/
|
||||
public final class ChatControl extends BukkitPlugin {
|
||||
|
||||
@Override
|
||||
public String[] getStartupLogo() {
|
||||
return new String[] {
|
||||
"&c ____ _ _ ____ ___ ____ ____ _ _ ___ ____ ____ _ ",
|
||||
"&4 | |__| |__| | | | | |\\ | | |__/ | | | ",
|
||||
"&4 |___ | | | | | |___ |__| | \\| | | \\ |__| |___",
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPluginLoad() {
|
||||
Variable.PROTOTYPE_PATH = fileName -> {
|
||||
|
||||
// Return different prototypes for different variable types since MESSAGE
|
||||
// variables do not support all keys
|
||||
final File file = FileUtil.createIfNotExists("variables/" + fileName + ".yml");
|
||||
final YamlConfig config = YamlConfig.fromFile(file);
|
||||
final String type = config.getString("Type", "FORMAT").toLowerCase();
|
||||
|
||||
return "prototype/" + "variable-" + ("format".equals(type) ? "format" : "message") + ".yml";
|
||||
};
|
||||
|
||||
// Add Sentry tags
|
||||
Debugger.addSentryTag(() -> {
|
||||
final Map<String, String> tags = new HashMap<>();
|
||||
|
||||
tags.put("db_type", Settings.Database.TYPE.getKey());
|
||||
tags.put("db_player_type", Settings.UUID_LOOKUP ? "uuid" : "name");
|
||||
tags.put("proxy_enabled", Settings.Proxy.ENABLED ? "true" : "false");
|
||||
|
||||
return tags;
|
||||
});
|
||||
|
||||
// Set how to get the region for tools
|
||||
DiskRegion.setCreatedPlayerRegionGetter(player -> SenderCache.from(player).getCreatedRegion());
|
||||
DiskRegion.setCreatedPlayerRegionResetter(player -> SenderCache.from(player).setCreatedRegion(new VisualizedRegion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPluginPreStart() {
|
||||
Migrator.migrateV10Settings(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPluginStart() {
|
||||
this.checkSecureProfile();
|
||||
|
||||
// Update and create tables
|
||||
Database.getInstance().prepareTables();
|
||||
|
||||
// Reload database cache for online players
|
||||
for (final Player player : Remain.getOnlinePlayers()) {
|
||||
final SenderCache senderCache = SenderCache.from(player);
|
||||
|
||||
if (!senderCache.isDatabaseLoaded() && senderCache.getCacheLoadingTask() == null)
|
||||
Database.getInstance().loadAndStoreCache(player, senderCache, cache -> {
|
||||
});
|
||||
}
|
||||
|
||||
// Register third party early to prevent duplication on reload
|
||||
ThirdPartiesListener.registerEvents();
|
||||
|
||||
if (Settings.Ignore.ENABLED)
|
||||
this.registerCommand(new CommandIgnore());
|
||||
|
||||
if (Settings.Mail.ENABLED)
|
||||
this.registerCommand(new CommandMail());
|
||||
|
||||
if (Settings.Me.ENABLED)
|
||||
this.registerCommand(new CommandMe());
|
||||
|
||||
if (Settings.Say.ENABLED)
|
||||
this.registerCommand(new CommandSay());
|
||||
|
||||
if (Settings.ListPlayers.ENABLED)
|
||||
this.registerCommand(new CommandList());
|
||||
|
||||
if (Settings.Motd.ENABLED)
|
||||
this.registerCommand(new CommandMotd());
|
||||
|
||||
if (Settings.Mute.ENABLED)
|
||||
this.registerCommand(new CommandMute());
|
||||
|
||||
if (!Settings.Tag.APPLY_ON.isEmpty())
|
||||
this.registerCommand(new CommandTag());
|
||||
|
||||
if (Settings.Tag.APPLY_ON.contains(Tag.Type.NICK))
|
||||
this.registerCommand(new CommandRealName());
|
||||
|
||||
if (!Settings.Spy.APPLY_ON.isEmpty())
|
||||
this.registerCommand(new CommandSpy());
|
||||
|
||||
if (!Settings.Toggle.APPLY_ON.isEmpty()) {
|
||||
final boolean deregister = !Platform.isPluginInstalled("PvPManager");
|
||||
|
||||
new CommandToggle().register(deregister, deregister);
|
||||
}
|
||||
|
||||
if (Settings.PrivateMessages.ENABLED) {
|
||||
this.registerCommand(new CommandReply());
|
||||
|
||||
new CommandTell().register(!Platform.isPluginInstalled("Towny"));
|
||||
}
|
||||
|
||||
this.registerCommand(new CommandDummy());
|
||||
|
||||
if (Remain.hasAdventureChatEvent() && Settings.CHAT_LISTENER_PRIORITY.getValue())
|
||||
AdventureChatListener.register();
|
||||
else
|
||||
LegacyChatListener.register();
|
||||
|
||||
this.registerEvents(CommandListener.getInstance());
|
||||
this.registerEvents(PlayerListener.getInstance());
|
||||
|
||||
if (Settings.TabComplete.ENABLED && MinecraftVersion.atLeast(V.v1_13))
|
||||
this.registerEvents(TabListener.getInstance());
|
||||
|
||||
if (Remain.hasBookEvent())
|
||||
this.registerEvents(BookListener.getInstance());
|
||||
|
||||
this.loadData();
|
||||
|
||||
// Run tasks
|
||||
WarningPoints.scheduleTask();
|
||||
Newcomer.scheduleTask();
|
||||
ProxyChat.scheduleTask();
|
||||
|
||||
// Add more info to debug zip feature
|
||||
DebugSubCommand.addDebugLines(
|
||||
"Proxy: " + Settings.Proxy.ENABLED,
|
||||
"Database: " + Settings.Database.TYPE);
|
||||
|
||||
if (HookManager.isLiteBansLoaded() && !HookManager.isVaultLoaded())
|
||||
CommonCore.warning("Please install Vault plugin to enable prefix/suffix/group variables since you have LiteBans installed.");
|
||||
|
||||
if (Remain.isFolia() && !HookManager.isProtocolLibLoaded())
|
||||
CommonCore.warning("Please install ProtocolLib when on Folia otherwise parts of the plugin might not work.");
|
||||
|
||||
if (Platform.isPluginInstalled("TAB"))
|
||||
CommonCore.warning("TAB detected. Use %chatcontrol_player_nick_section%, %chatcontrol_player_prefix_section% and %chatcontrol_player_suffix_section% variables in groups.yml to ensure compatibility.");
|
||||
|
||||
if (Platform.isPluginInstalled("InteractiveChat")) {
|
||||
CommonCore.warning("InteractiveChat detected. If having issues, adjust our Chat_Listener_Priority key in settings.yml (try setting it to LOWEST, without -MODERN prefix).");
|
||||
|
||||
if (Settings.Colors.APPLY_ON.contains(Colors.Type.CHAT)) {
|
||||
final File interactiveChatFile = new File(this.getDataFolder().getParent(), "InteractiveChat/config.yml");
|
||||
|
||||
if (interactiveChatFile.exists()) {
|
||||
final YamlConfig interactiveChatConfig = YamlConfig.fromFile(interactiveChatFile);
|
||||
final List<String> formats = interactiveChatConfig.getStringList("Settings.FormattingTags.AdditionalRGBFormats");
|
||||
|
||||
if (formats.contains("#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])"))
|
||||
CommonCore.logFramed(
|
||||
"INCOMPATIBILITY WITH INTERACTIVECHAT DETECTED",
|
||||
"",
|
||||
"ChatControl hex colors are incompatible with the",
|
||||
"Settings.FormattingTags.AdditionalRGBFormats key in",
|
||||
"InteractiveChat's config.yml containing:",
|
||||
"#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])",
|
||||
"",
|
||||
"Either remove that key from InteractiveChat's config.yml",
|
||||
"or remove 'chat' (and possibly others) from Colors.Apply_On",
|
||||
"in ChatControl's settings.yml.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HookManager.isDiscordSRVLoaded() && Settings.Channels.ENABLED && Settings.Discord.ENABLED)
|
||||
if (DiscordSRV.config().getBoolean("DiscordChatChannelMinecraftToDiscord"))
|
||||
CommonCore.logFramed(
|
||||
"Warning: The key DiscordChatChannelMinecraftToDiscord",
|
||||
"is set on true in your DiscordSRV/config.yml file.",
|
||||
"",
|
||||
"Since you have Channels and Discord integration enabled",
|
||||
"in ChatControl, this will produce duplicated messages.",
|
||||
"Set the key to false to resolve this.");
|
||||
|
||||
if (Settings.SHOW_TIPS)
|
||||
CommonCore.log("",
|
||||
"For documentation & tutorial, see:",
|
||||
"&chttps://github.com/kangarko/chatcontrol/wiki",
|
||||
"",
|
||||
"Loaded! Random joke: " + this.getRandomSplash(),
|
||||
"");
|
||||
|
||||
Platform.runTask(() -> {
|
||||
for (final String fileName : Arrays.asList("usermap.csv", "blocked-commands.log")) {
|
||||
final File file = new File(this.getDataFolder(), fileName);
|
||||
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
|
||||
CommonCore.log("Deleted " + fileName + " file. It's no longer used by ChatControl.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if secure profile is enabled
|
||||
*/
|
||||
private void checkSecureProfile() {
|
||||
final File serverProperties = new File("server.properties");
|
||||
final Properties properties = new Properties();
|
||||
|
||||
try {
|
||||
properties.load(new FileInputStream(serverProperties));
|
||||
} catch (final IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
final boolean enforceSecureProfile = Boolean.parseBoolean(properties.getProperty("enforce-secure-profile", "false"));
|
||||
|
||||
if (enforceSecureProfile)
|
||||
CommonCore.warning("It is advised you set 'enforce-secure-profile' to false in server.properties for best performance and improved player privacy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPluginPreReload() {
|
||||
|
||||
// Reload database before its instance is replaced by settings being reloaded
|
||||
Database.getInstance().disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPluginReload() {
|
||||
Variables.setDoubleParse(Settings.Performance.SUPPORT_VARIABLES_IN_VARIABLES);
|
||||
|
||||
this.loadData();
|
||||
|
||||
for (final Player online : Remain.getOnlinePlayers()) {
|
||||
final SenderCache senderCache = SenderCache.from(online);
|
||||
|
||||
if (senderCache.isDatabaseLoaded()) {
|
||||
final WrappedSender wrapped = WrappedSender.fromPlayerCaches(online, PlayerCache.fromCached(online), senderCache);
|
||||
|
||||
if (Settings.Channels.ENABLED)
|
||||
Channel.autoJoin(online, wrapped.getPlayerCache());
|
||||
|
||||
Players.setTablistName(wrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A common call for startup and reloading
|
||||
*/
|
||||
private void loadData() {
|
||||
SimpleBook.copyDefaults();
|
||||
|
||||
// Load parts of the plugin
|
||||
Variable.loadVariables();
|
||||
Channel.loadChannels();
|
||||
Format.loadFormats();
|
||||
|
||||
// Load rule system
|
||||
Rules.getInstance().load();
|
||||
Groups.getInstance().load();
|
||||
PlayerMessages.getInstance().load();
|
||||
|
||||
// Copy sample image but only if folder doesn't exist so people can remove it
|
||||
if (!FileUtil.getFile("images").exists())
|
||||
FileUtil.extractRaw("images/creeper-head.png");
|
||||
}
|
||||
|
||||
/*
|
||||
* Time for some fun!
|
||||
*/
|
||||
private String getRandomSplash() {
|
||||
return RandomUtil.nextItem(
|
||||
"Requires at least 32Gb of RAM! #unfortunatelyNotAJoke #joke",
|
||||
"Never closes database connections #dailyLeaks #patched",
|
||||
"Uses outdated log4j! #joke",
|
||||
"Try '/me is the best' today! #seriously",
|
||||
"Cracked by kangarko (MineAcademy.org) #joke",
|
||||
"Censored for stating the obvious! #elonMusk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getConsoleFilter() {
|
||||
return Settings.ConsoleFilter.ENABLED ? Settings.ConsoleFilter.MESSAGES : new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegexCaseInsensitive() {
|
||||
return Settings.RULES_CASE_INSENSITIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegexUnicode() {
|
||||
return Settings.RULES_UNICODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The inception year -- whoa long time ago!
|
||||
*
|
||||
* @return the year
|
||||
*/
|
||||
@Override
|
||||
public int getFoundedYear() {
|
||||
return 2013;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSentryDsn() {
|
||||
return "https://f3e0e6f4236a18360bf321211866ae6f@o4508048573661184.ingest.us.sentry.io/4508052468269056";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBStatsPluginId() {
|
||||
return 13100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBuiltByBitId() {
|
||||
return 18217;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useFullPlaceholderAPIParser() {
|
||||
return Settings.Performance.SUPPORT_FULL_PLACEHOLDERAPI_SYNTAX;
|
||||
}
|
||||
}
|
@ -0,0 +1,475 @@
|
||||
package org.mineacademy.chatcontrol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.LogType;
|
||||
import org.mineacademy.chatcontrol.model.Mute;
|
||||
import org.mineacademy.chatcontrol.model.PlayerMessageType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.Mail;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessages;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.PlayerUtil;
|
||||
import org.mineacademy.fo.ValidCore;
|
||||
import org.mineacademy.fo.model.LimitedQueue;
|
||||
import org.mineacademy.fo.model.SimpleBook;
|
||||
import org.mineacademy.fo.model.Task;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.visual.VisualizedRegion;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Represents a cache that can work for any command sender,
|
||||
* such as those coming from Discord too.
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SenderCache {
|
||||
|
||||
/**
|
||||
* The internal sender map by unique ID.
|
||||
*/
|
||||
private static final Map<UUID, SenderCache> uniqueCacheMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The sender name
|
||||
*/
|
||||
@Getter
|
||||
private final String senderName;
|
||||
|
||||
/**
|
||||
* Sender's last communication
|
||||
*/
|
||||
private final Map<LogType, Queue<Output>> lastCommunication = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Stores last packets sent, caught by ProtocolLib
|
||||
*
|
||||
* 100 is the maximum chat line count you can view in history
|
||||
* This is used to delete messages
|
||||
*/
|
||||
private final LimitedQueue<String> lastChatPackets = new LimitedQueue<>(100);
|
||||
|
||||
/**
|
||||
* The last time the sender has joined the server or -1 if not set
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private long lastLogin = -1;
|
||||
|
||||
/**
|
||||
* The last time the sender used sound notify successfuly
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private long lastSoundNotify = -1;
|
||||
|
||||
/**
|
||||
* If sender is player - his join location
|
||||
*/
|
||||
@Setter
|
||||
private Location joinLocation;
|
||||
|
||||
/**
|
||||
* Did the sender move from his {@link #joinLocation}
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean movedFromJoin;
|
||||
|
||||
/**
|
||||
* The last sign test, null if not yet set
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Nullable
|
||||
private String[] lastSignText;
|
||||
|
||||
/**
|
||||
* Represents a region the player is currently creating
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private VisualizedRegion createdRegion = new VisualizedRegion();
|
||||
|
||||
/**
|
||||
* Represents an unfinished mail the player writes
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private SimpleBook pendingMail;
|
||||
|
||||
/**
|
||||
* The mail this player is replying to
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Mail pendingMailReply;
|
||||
|
||||
/**
|
||||
* Recent warning messages the sender has received
|
||||
* Used to prevent duplicate warning messages
|
||||
*/
|
||||
@Getter
|
||||
private final Map<UUID, Long> recentWarningMessages = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Was the related {@link PlayerCache} loaded from the database?
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean databaseLoaded = false;
|
||||
|
||||
/**
|
||||
* Is the database currently being queried?
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean queryingDatabase = false;
|
||||
|
||||
/**
|
||||
* Used for AuthMe to delay join message
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String joinMessage;
|
||||
|
||||
/**
|
||||
* Get last reply player
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String replyPlayerName;
|
||||
|
||||
/**
|
||||
* If conversation mode is enabled this holds the player the
|
||||
* sender is conversing with, otherwise null as bull
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String conversingPlayerName;
|
||||
|
||||
/**
|
||||
* When did the player chat in automode last time?
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private long lastAutoModeChat;
|
||||
|
||||
/**
|
||||
* Did we already triggered join flood feature for this player?
|
||||
* Used to limit running commands only once.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean joinFloodActivated;
|
||||
|
||||
/**
|
||||
* The database loading task which might hang on slow db and we need to clean it manually
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Task cacheLoadingTask;
|
||||
|
||||
/**
|
||||
* Ping proxy back that db has loaded and we can now send join message.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean pendingProxyJoinMessage;
|
||||
|
||||
/**
|
||||
* Proxy to show join message
|
||||
*
|
||||
* @param wrapped
|
||||
*/
|
||||
public void sendJoinMessage(final WrappedSender wrapped) {
|
||||
ValidCore.checkBoolean(this.databaseLoaded, "Cannot send join message for " + wrapped.getName() + " since db was not loaded yet!");
|
||||
ValidCore.checkNotNull(this.joinMessage, "Join message must be set!");
|
||||
|
||||
if (Settings.Messages.APPLY_ON.contains(PlayerMessageType.JOIN) && (!Mute.isSomethingMutedIf(Settings.Mute.HIDE_JOINS, wrapped) || Settings.Mute.SOFT_HIDE) && !PlayerUtil.isVanished(wrapped.getPlayer()))
|
||||
Platform.runTask(Settings.Messages.DEFER_JOIN_MESSAGE_BY.getTimeTicks(), () -> PlayerMessages.broadcast(PlayerMessageType.JOIN, wrapped, this.joinMessage));
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
this.pendingProxyJoinMessage = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last chat message, or null if not yet registered
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public String getLastChatMessage() {
|
||||
final Output lastChatOutput = this.getLastChat();
|
||||
|
||||
return lastChatOutput == null ? null : lastChatOutput.getOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last chat output
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Output getLastChat() {
|
||||
final List<Output> lastOutputs = this.getLastOutputs(LogType.CHAT, 1, null);
|
||||
|
||||
return lastOutputs.isEmpty() ? null : lastOutputs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of the last X amount of outputs the sender has issued
|
||||
*
|
||||
* @param type
|
||||
* @param amountInHistory
|
||||
* @param channel
|
||||
* @return
|
||||
*/
|
||||
public List<Output> getLastOutputs(final LogType type, final int amountInHistory, @Nullable final Channel channel) {
|
||||
return this.filterOutputs(type, channel, amountInHistory, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of all outputs issued on or after the given date
|
||||
*
|
||||
* @param type
|
||||
* @param timestamp
|
||||
* @param channel
|
||||
* @return
|
||||
*/
|
||||
public List<Output> getOutputsAfter(final LogType type, final long timestamp, @Nullable final Channel channel) {
|
||||
return this.filterOutputs(type, channel, -1, output -> output.getTime() >= timestamp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a list of inputs by the given type, if the type is chat then also from the given channel,
|
||||
* maximum of the given limit and matching the given filter
|
||||
*/
|
||||
private List<Output> filterOutputs(final LogType type, @Nullable final Channel channel, final int limit, @Nullable final Predicate<Output> filter) {
|
||||
final Queue<Output> allOutputs = this.lastCommunication.get(type);
|
||||
final List<Output> listedOutputs = new ArrayList<>();
|
||||
|
||||
if (allOutputs != null) {
|
||||
final Output[] outputArray = allOutputs.toArray(new Output[allOutputs.size()]);
|
||||
|
||||
// Start from the last output
|
||||
for (int i = allOutputs.size() - 1; i >= 0; i--) {
|
||||
final Output output = outputArray[i];
|
||||
|
||||
// Return if channels set but not equal
|
||||
if (output == null)
|
||||
continue;
|
||||
|
||||
if (output.getChannel() != null && channel != null && !output.getChannel().equals(channel.getName()))
|
||||
continue;
|
||||
|
||||
if (limit != -1 && listedOutputs.size() >= limit)
|
||||
break;
|
||||
|
||||
if (filter != null && !filter.test(output))
|
||||
break;
|
||||
|
||||
listedOutputs.add(output);
|
||||
}
|
||||
}
|
||||
|
||||
// Needed to reverse the entire list now
|
||||
Collections.reverse(listedOutputs);
|
||||
|
||||
return listedOutputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the given chat message from the given channel
|
||||
*
|
||||
* @param input
|
||||
* @param channel
|
||||
*/
|
||||
public void cacheMessage(final String input, final Channel channel) {
|
||||
this.record(LogType.CHAT, input, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the given command
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
public void cacheCommand(final String input) {
|
||||
this.record(LogType.COMMAND, input, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal caching handler method
|
||||
*/
|
||||
private void record(final LogType type, final String input, @Nullable final Channel channel) {
|
||||
final Queue<Output> queue = this.lastCommunication.getOrDefault(type, new LimitedQueue<>(100));
|
||||
final Output record = new Output(System.currentTimeMillis(), input, channel == null ? null : channel.getName());
|
||||
|
||||
queue.add(record);
|
||||
this.lastCommunication.put(type, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last chat packets
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public LimitedQueue<String> getLastChatPackets() {
|
||||
synchronized (this.lastChatPackets) {
|
||||
return this.lastChatPackets;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the join location, throwing exception if not set
|
||||
*
|
||||
* @return the joinLocation
|
||||
*/
|
||||
public Location getJoinLocation() {
|
||||
ValidCore.checkBoolean(this.hasJoinLocation(), "Join location has not been set!");
|
||||
|
||||
return this.joinLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the join location has been set
|
||||
* @return
|
||||
*/
|
||||
public boolean hasJoinLocation() {
|
||||
return this.joinLocation != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the sender is conversing with another player
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasConversingPlayer() {
|
||||
return this.conversingPlayerName != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the sender name to a player is online
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Player toPlayer() {
|
||||
return Bukkit.getPlayerExact(this.senderName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// Static
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return all caches stored in memory
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Iterator<SenderCache> getCaches() {
|
||||
synchronized (uniqueCacheMap) {
|
||||
return uniqueCacheMap.values().iterator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve (or create) a sender cache
|
||||
*
|
||||
* @param sender
|
||||
* @return
|
||||
*/
|
||||
public static SenderCache from(final CommandSender sender) {
|
||||
return from(Platform.toPlayer(sender).getUniqueId(), sender.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve (or create) a sender cache
|
||||
*
|
||||
* @param wrapped
|
||||
* @return
|
||||
*/
|
||||
public static SenderCache from(final WrappedSender wrapped) {
|
||||
return from(wrapped.getUniqueId(), wrapped.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve (or create) a sender cache
|
||||
*
|
||||
* @param senderUid
|
||||
* @param senderName
|
||||
* @return
|
||||
*/
|
||||
public static SenderCache from(final UUID senderUid, final String senderName) {
|
||||
synchronized (uniqueCacheMap) {
|
||||
SenderCache cache = uniqueCacheMap.get(senderUid);
|
||||
|
||||
if (cache == null) {
|
||||
cache = new SenderCache(senderName);
|
||||
|
||||
uniqueCacheMap.put(senderUid, cache);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// Classes
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Represents a given senders output
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static final class Output {
|
||||
|
||||
/**
|
||||
* The default output with -1 time and a blank message
|
||||
*/
|
||||
public static final Output NO_OUTPUT = new Output(-1, "", "");
|
||||
|
||||
/**
|
||||
* The time the message was sent
|
||||
*/
|
||||
private final long time;
|
||||
|
||||
/**
|
||||
* The message content
|
||||
*/
|
||||
private final String output;
|
||||
|
||||
/**
|
||||
* Message channel or null if not associated (such as for commands)
|
||||
*/
|
||||
@Nullable
|
||||
private final String channel;
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.time + " '" + this.output + "' " + this.channel;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when a player joins a channel.
|
||||
*/
|
||||
@Getter
|
||||
public final class ChannelJoinEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The cache of the Dude himself
|
||||
*/
|
||||
private final PlayerCache cache;
|
||||
|
||||
/**
|
||||
* The channel player is joining into
|
||||
*/
|
||||
private final Channel channel;
|
||||
|
||||
/**
|
||||
* The mode player is joining with
|
||||
*/
|
||||
private final ChannelMode mode;
|
||||
|
||||
/**
|
||||
* Enable joining?
|
||||
*/
|
||||
@Setter
|
||||
private boolean cancelled;
|
||||
|
||||
public ChannelJoinEvent(final PlayerCache cache, final Channel channel, final ChannelMode mode) {
|
||||
this.cache = cache;
|
||||
this.channel = channel;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when a player leaves a channel.
|
||||
*/
|
||||
@Getter
|
||||
public final class ChannelLeaveEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The cache of the Dude himself
|
||||
*/
|
||||
private final PlayerCache cache;
|
||||
|
||||
/**
|
||||
* The channel leaving
|
||||
*/
|
||||
private final Channel channel;
|
||||
|
||||
/**
|
||||
* The mode player had
|
||||
*/
|
||||
private final ChannelMode mode;
|
||||
|
||||
/**
|
||||
* Prevent dude leaving?
|
||||
*/
|
||||
@Setter
|
||||
private boolean cancelled;
|
||||
|
||||
public ChannelLeaveEvent(final PlayerCache cache, final Channel channel, final ChannelMode mode) {
|
||||
this.cache = cache;
|
||||
this.channel = channel;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Event for when players send a message to a chat channel.
|
||||
*
|
||||
* This is fired after checker, rules, colors, sound notify etc. has fired.
|
||||
* Cancelling has thus only partial effect and is not recommended.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public final class ChannelPostChatEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The chat channel
|
||||
*/
|
||||
private final Channel channel;
|
||||
|
||||
/**
|
||||
* The player who issued the message
|
||||
*/
|
||||
private final CommandSender sender;
|
||||
|
||||
/**
|
||||
* A list of players receiving this message
|
||||
*/
|
||||
private final Set<Player> recipients;
|
||||
|
||||
/**
|
||||
* The message
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* The formatted message
|
||||
*/
|
||||
private SimpleComponent format;
|
||||
|
||||
/**
|
||||
* The message
|
||||
*/
|
||||
private String consoleFormat;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private final boolean cancelledSilently;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Event for when players send a message to a chat channel.
|
||||
* This is fired before any modifications are made to the message.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class ChannelPreChatEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The chat channel
|
||||
*/
|
||||
private final Channel channel;
|
||||
|
||||
/**
|
||||
* The player who issued the message
|
||||
*/
|
||||
private final CommandSender sender;
|
||||
|
||||
/**
|
||||
* A list of players receiving this message
|
||||
*/
|
||||
private final Set<Player> recipients;
|
||||
|
||||
/**
|
||||
* The message
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public ChannelPreChatEvent(final Channel channel, final CommandSender sender, final String message, final Set<Player> recipients) {
|
||||
this.channel = channel;
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
this.recipients = recipients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Event for when players send a message to a chat channel from another server.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class ChatChannelProxyEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The chat channel
|
||||
*/
|
||||
private final Channel channel;
|
||||
|
||||
/**
|
||||
* The sender name of whom issued the message
|
||||
*/
|
||||
private final String senderName;
|
||||
|
||||
/**
|
||||
* The sender UUID of whom issued the message
|
||||
*/
|
||||
private final UUID senderUid;
|
||||
|
||||
/**
|
||||
* A list of players receiving this message
|
||||
*/
|
||||
private final Set<Player> recipients;
|
||||
|
||||
/**
|
||||
* The formatted message
|
||||
*/
|
||||
@Setter
|
||||
private SimpleComponent formattedMessage;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public ChatChannelProxyEvent(final Channel channel, final String senderName, final UUID senderUid, final SimpleComponent formattedMessage, final Set<Player> recipients) {
|
||||
this.channel = channel;
|
||||
this.senderName = senderName;
|
||||
this.senderUid = senderUid;
|
||||
this.formattedMessage = formattedMessage;
|
||||
this.recipients = recipients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.Checker;
|
||||
import org.mineacademy.chatcontrol.model.Newcomer;
|
||||
import org.mineacademy.chatcontrol.model.RuleType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.model.db.ServerSettings;
|
||||
import org.mineacademy.chatcontrol.operator.Rule;
|
||||
import org.mineacademy.chatcontrol.operator.Rule.RuleCheck;
|
||||
import org.mineacademy.fo.ValidCore;
|
||||
|
||||
/**
|
||||
* The main class of the ChatControl's API.
|
||||
*
|
||||
* @author kangarko
|
||||
*/
|
||||
public final class ChatControlAPI {
|
||||
|
||||
/**
|
||||
* Get if the chat has globally been muted via /mute.
|
||||
*
|
||||
* @return if the chat has been globally muted
|
||||
*/
|
||||
public static boolean isChatMuted() {
|
||||
return ServerSettings.getInstance().isMuted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player cache or complains if the player is not online.
|
||||
*
|
||||
* @param player the player
|
||||
* @return
|
||||
*/
|
||||
public static PlayerCache getCache(final Player player) {
|
||||
ValidCore.checkBoolean(player.isOnline(), "Player " + player.getName() + " must be online to get his cache!");
|
||||
|
||||
return PlayerCache.fromCached(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run antispam, anticaps, time and delay checks as well as rules for the given message
|
||||
*
|
||||
* @param sender
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static Checker checkMessage(final Player sender, final String message) {
|
||||
final Checker checker = Checker.filterChannel(WrappedSender.fromPlayer(sender), message, null);
|
||||
|
||||
return checker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given rules type for the message sent by the player
|
||||
*
|
||||
* @param type
|
||||
* @param sender
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static RuleCheck<?> checkRules(final RuleType type, final Player sender, final String message) {
|
||||
return checkRules(type, sender, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given rules type for the message sent by the player
|
||||
*
|
||||
* @param type
|
||||
* @param sender
|
||||
* @param message
|
||||
* @param channel
|
||||
* @return
|
||||
*/
|
||||
public static RuleCheck<?> checkRules(final RuleType type, final CommandSender sender, final String message, final Channel channel) {
|
||||
return Rule.filter(type, WrappedSender.fromSender(sender), message, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the player is newcomer according to the Newcomer settings.
|
||||
*
|
||||
* @param player the player
|
||||
* @return if ChatControl considers the player a newcomer
|
||||
*/
|
||||
public static boolean isNewcomer(final Player player) {
|
||||
return Newcomer.isNewcomer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given channel is available and loaded.
|
||||
*
|
||||
* @param channelName
|
||||
* @return
|
||||
*/
|
||||
public static boolean isChannelInstalled(final String channelName) {
|
||||
return Channel.isChannelLoaded(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the given channel through the given sender.
|
||||
*
|
||||
* @param sender act as if the given sender issued the chat message
|
||||
* @param channelName
|
||||
* @param message
|
||||
*/
|
||||
public static void sendMessage(final CommandSender sender, final String channelName, final String message) {
|
||||
final Channel channel = Channel.findChannel(channelName);
|
||||
ValidCore.checkNotNull(channel, "Channel '" + channelName + "' is not installed. Use ChatControlAPI#isChannelInstalled to check that first!");
|
||||
|
||||
channel.sendMessage(sender, message);
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
import org.mineacademy.fo.model.SimpleTime;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Event for when something gets muted, either a channel, a player or the server.
|
||||
*
|
||||
* Channel mute = targetChannel is not null
|
||||
* Player mute = targetPlayerName and UUID are not null
|
||||
* Server mute = everything is null
|
||||
*/
|
||||
@Getter
|
||||
public final class MuteEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The type of the mute.
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* The duration of the mute, null if we are UNmuting
|
||||
*/
|
||||
@Nullable
|
||||
@Setter
|
||||
private SimpleTime duration;
|
||||
|
||||
/**
|
||||
* The channel that got muted, or null if the event did not fire for a channel
|
||||
*/
|
||||
@Nullable
|
||||
private Channel targetChannel;
|
||||
|
||||
/**
|
||||
* The player name who got muted, or null if the event did not fire for a player
|
||||
*/
|
||||
@Nullable
|
||||
private String targetPlayerName;
|
||||
|
||||
/**
|
||||
* The player UUID who got muted, or null if the event did not fire for a player
|
||||
*/
|
||||
@Nullable
|
||||
private UUID targetPlayerUniqueId;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
@Setter
|
||||
private boolean cancelled;
|
||||
|
||||
/*
|
||||
* Server mute
|
||||
*/
|
||||
private MuteEvent(final Type type, final SimpleTime duration) {
|
||||
this.type = type;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/*
|
||||
* Channel mute
|
||||
*/
|
||||
private MuteEvent(final Type type, final Channel targetChannel, final SimpleTime duration) {
|
||||
this.type = type;
|
||||
this.targetChannel = targetChannel;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/*
|
||||
* Player mute
|
||||
*/
|
||||
private MuteEvent(final Type type, final String targetPlayerName, final UUID targetPlayerUniqueId, final SimpleTime duration) {
|
||||
this.type = type;
|
||||
this.targetPlayerName = targetPlayerName;
|
||||
this.targetPlayerUniqueId = targetPlayerUniqueId;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a mute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMute() {
|
||||
return this.duration != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an unmute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isUnmute() {
|
||||
return this.duration == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a player mute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPlayerMute() {
|
||||
return this.type == Type.PLAYER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a channel mute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isChannelMute() {
|
||||
return this.type == Type.CHANNEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a server mute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isServerMute() {
|
||||
return this.type == Type.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static MuteEvent server(final SimpleTime duration) {
|
||||
return new MuteEvent(Type.SERVER, duration);
|
||||
}
|
||||
|
||||
public static MuteEvent channel(final Channel targetChannel, final SimpleTime duration) {
|
||||
return new MuteEvent(Type.CHANNEL, targetChannel, duration);
|
||||
}
|
||||
|
||||
public static MuteEvent player(final String targetPlayerName, final UUID targetPlayerUniqueId, final SimpleTime duration) {
|
||||
return new MuteEvent(Type.PLAYER, targetPlayerName, targetPlayerUniqueId, duration);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
SERVER,
|
||||
CHANNEL,
|
||||
PLAYER;
|
||||
}
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.listener.ThirdPartiesListener;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.ValidCore;
|
||||
import org.mineacademy.fo.model.HookManager;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Represents a party for a channel.
|
||||
*/
|
||||
public abstract class Party {
|
||||
|
||||
/**
|
||||
* Registration by name
|
||||
*/
|
||||
private static final Map<String, Party> byName = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This is a channel shown only to players in the same Faction as the sender.
|
||||
*/
|
||||
public static final Party FACTION = new Party("factions-faction") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getOnlineFactionPlayers(sender).contains(receiver);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat for PlotSquared - only shown to players inside the plot.
|
||||
*/
|
||||
public static final Party PLOT = new Party("plotsquared-plot") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getPlotPlayers(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a channel shown only to players in the same Town as the sender.
|
||||
*/
|
||||
public static final Party TOWN = new Party("towny-town") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getTownResidentsOnline(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a channel shown only to players in the same Nation as the sender.
|
||||
*/
|
||||
public static final Party NATION = new Party("towny-nation") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getNationPlayersOnline(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a channel shown only to same ally players as the sender.
|
||||
*/
|
||||
public static final Party ALLY = new Party("towny-ally") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getAllyPlayersOnline(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat for mcMMO - only shown to players within the same party.
|
||||
*/
|
||||
public static final Party MCMMO = new Party("mcmmo-party") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return ThirdPartiesListener.getMcMMOPartyRecipients(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Only chat with other players in the same land
|
||||
*/
|
||||
public static final Party LAND = new Party("lands-land") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return HookManager.getLandPlayers(sender).contains(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Only chat with players belonging to the same island as you
|
||||
* and having the given (or higher rank, from top to bottom)
|
||||
*/
|
||||
public static final Party ISLAND_VISITOR = new Party("bentobox-island-visitor") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> visitors = HookManager.getBentoBoxVisitors(sender);
|
||||
|
||||
return visitors.contains(sender.getUniqueId()) && visitors.contains(receiver.getUniqueId());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_COOP = new Party("bentobox-island-coop") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> coops = HookManager.getBentoBoxCoops(sender);
|
||||
|
||||
return coops.contains(sender.getUniqueId()) && coops.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_TRUSTED = new Party("bentobox-island-trusted") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> trustees = HookManager.getBentoBoxTrustees(sender);
|
||||
|
||||
return trustees.contains(sender.getUniqueId()) && trustees.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_MEMBER = new Party("bentobox-island-member") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> members = HookManager.getBentoBoxMembers(sender);
|
||||
|
||||
return members.contains(sender.getUniqueId()) && members.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_SUBOWNER = new Party("bentobox-island-subowner") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> subowners = HookManager.getBentoBoxSubOwners(sender);
|
||||
|
||||
return subowners.contains(sender.getUniqueId()) && subowners.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_OWNER = new Party("bentobox-island-owner") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> owners = HookManager.getBentoBoxOwners(sender);
|
||||
|
||||
return owners.contains(sender.getUniqueId()) && owners.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_MOD = new Party("bentobox-island-mod") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> mods = HookManager.getBentoBoxMods(sender);
|
||||
|
||||
return mods.contains(sender.getUniqueId()) && mods.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Party ISLAND_ADMIN = new Party("bentobox-island-admin") {
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
final Set<UUID> admins = HookManager.getBentoBoxAdmins(sender);
|
||||
|
||||
return admins.contains(sender.getUniqueId()) && admins.contains(receiver.getUniqueId());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The unique party name
|
||||
*/
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
private Party(final String name) {
|
||||
this.name = name;
|
||||
|
||||
byName.put(name, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the receiver is in the sender's party.
|
||||
*
|
||||
* @param receiver
|
||||
* @param sender
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean isInParty(Player receiver, Player sender);
|
||||
|
||||
/**
|
||||
* Get the unique party name
|
||||
*/
|
||||
@Override
|
||||
public final String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new party into our API.
|
||||
*
|
||||
* @param name
|
||||
* @param isInParty return true or false depending if the first argument (the receiver) is in the second argument's (the sender's) party
|
||||
*/
|
||||
public static void register(final String name, final BiFunction<Player, Player, Boolean> isInParty) {
|
||||
ValidCore.checkBoolean(!byName.containsKey(name), "Party named " + name + " already exists!");
|
||||
|
||||
byName.put(name, new Party(name) {
|
||||
|
||||
@Override
|
||||
public boolean isInParty(final Player receiver, final Player sender) {
|
||||
return isInParty.apply(receiver, sender);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the party from the given name, throwing exception if failed.
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static Party fromKey(final String name) {
|
||||
for (final Map.Entry<String, Party> entry : byName.entrySet())
|
||||
if (entry.getKey().equalsIgnoreCase(name))
|
||||
return entry.getValue();
|
||||
|
||||
throw new IllegalArgumentException("No such channel party: " + name + ". Available: " + CommonCore.join(byName.keySet()));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> getPartiesNames() {
|
||||
return Collections.unmodifiableSet(byName.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Collection<Party> getParties() {
|
||||
return Collections.unmodifiableCollection(byName.values());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is when a player is mentioned in chat.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class PlayerMentionEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The player that mentioned the other player
|
||||
*/
|
||||
private final CommandSender mentioner;
|
||||
|
||||
/**
|
||||
* The player that was mentioned
|
||||
*/
|
||||
private final SyncedCache mentioned;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public PlayerMentionEvent(final CommandSender mentioner, final SyncedCache mentioned) {
|
||||
this.mentioner = mentioner;
|
||||
this.mentioned = mentioned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.PlayerMessageType;
|
||||
import org.mineacademy.chatcontrol.operator.Operator.OperatorCheck;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when a player joins a channel.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public final class PlayerMessageEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The Dude himself, null if timed or demo run
|
||||
*/
|
||||
@Nullable
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* The channel player is joining into
|
||||
*/
|
||||
private final PlayerMessageType type;
|
||||
|
||||
/**
|
||||
* The associated check with this
|
||||
*/
|
||||
private final OperatorCheck<?> check;
|
||||
|
||||
/**
|
||||
* The original message if any, can be null
|
||||
* For example the death event has its own native MC messages returned here
|
||||
*/
|
||||
@Nullable
|
||||
private final String originalMessage;
|
||||
|
||||
/**
|
||||
* Enable joining?
|
||||
*/
|
||||
@Setter
|
||||
private boolean cancelled;
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is when a player is mentioned in chat.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class PlayerPreMentionEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The matched player
|
||||
*/
|
||||
private final SyncedCache player;
|
||||
|
||||
/**
|
||||
* The prefix look for when matching
|
||||
*/
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public PlayerPreMentionEvent(final SyncedCache player, final String prefix) {
|
||||
this.player = player;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when players send a message via /reply or /tell.
|
||||
* <p>
|
||||
* This is fired before all checks are done so you can just cancel the event and manually force the
|
||||
* message to be sent.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class PrePrivateMessageEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The command sender
|
||||
*/
|
||||
private final WrappedSender sender;
|
||||
|
||||
/**
|
||||
* The recipient... may be on this server or on proxy
|
||||
*/
|
||||
private final SyncedCache receiverCache;
|
||||
|
||||
/**
|
||||
* The recipient, null if he's on proxy
|
||||
*/
|
||||
@Nullable
|
||||
private final Player receiver;
|
||||
|
||||
/**
|
||||
* The message being sent
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Should we play the sound?
|
||||
*/
|
||||
private boolean sound;
|
||||
|
||||
/**
|
||||
* Should we allow this event to occur?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public PrePrivateMessageEvent(final WrappedSender sender, final SyncedCache receiverCache, final Player receiver, final String message, final boolean sound) {
|
||||
this.sender = sender;
|
||||
this.receiverCache = receiverCache;
|
||||
this.receiver = receiver;
|
||||
this.message = message;
|
||||
this.sound = sound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.operator.Rule;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when a rule or a handler matches a message.
|
||||
* <p>
|
||||
* The event is fired before the rule edits the message in any way.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class PreRuleMatchEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The sender checked
|
||||
*/
|
||||
private final CommandSender sender;
|
||||
|
||||
/**
|
||||
* The full message
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* The matching rule
|
||||
*/
|
||||
private final Rule rule;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public PreRuleMatchEvent(final CommandSender sender, final String message, final Rule rule) {
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.operator.RuleOperator;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* An event that is executed when a rule replaces a message
|
||||
* either via "then replace" or "then rewrite (in)" operators
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class RuleReplaceEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The sender checked
|
||||
*/
|
||||
private final CommandSender sender;
|
||||
|
||||
/**
|
||||
* The message being matched
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* The replaced match
|
||||
*/
|
||||
private String replacedMatch;
|
||||
|
||||
/**
|
||||
* The matching rule operator
|
||||
*/
|
||||
private final RuleOperator rule;
|
||||
|
||||
/**
|
||||
* Did the rule replace the entire message? True for "then rewrite",
|
||||
* false for "then replace"
|
||||
*/
|
||||
private final boolean wholeMessage;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public RuleReplaceEvent(final CommandSender sender, final String message, final String replacedMatch, final RuleOperator rule, final boolean wholeMessage) {
|
||||
super(!Bukkit.isPrimaryThread());
|
||||
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
this.replacedMatch = replacedMatch;
|
||||
this.rule = rule;
|
||||
this.wholeMessage = wholeMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.SimpleExpansion;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.platform.FoundationPlayer;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
|
||||
// This class is automatically registered if your plugin uses Foundation,
|
||||
// if not then call {@link Variables#addExpansion(SimpleExpansion)} in your onEnable()
|
||||
// manually.
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SampleCustomPlaceholders extends SimpleExpansion {
|
||||
|
||||
@Getter
|
||||
private static final SimpleExpansion instance = new SampleCustomPlaceholders();
|
||||
|
||||
@Override
|
||||
protected SimpleComponent onReplace(FoundationPlayer audience, String identifier) {
|
||||
|
||||
// You can get the Bukkit sender and Players from the audience object
|
||||
final CommandSender sender = audience.getSender();
|
||||
final Player player = audience.isPlayer() ? audience.getPlayer() : null;
|
||||
|
||||
// use {my_variable} or {chatcontrol_my_variable} if using PlaceholderAPI in your messages
|
||||
if ("my_variable".equals(identifier))
|
||||
return SimpleComponent.fromMiniAmpersand("<red>My &evariable");
|
||||
|
||||
else if ("my_section_variable".equals(identifier))
|
||||
return SimpleComponent.fromAmpersand("&cMy variable");
|
||||
|
||||
else if ("my_adventure_variable".equals(identifier))
|
||||
return SimpleComponent.fromAdventure(Component.text("My variable").color(NamedTextColor.RED));
|
||||
|
||||
else if ("my_plaintext_variable".equals(identifier))
|
||||
return SimpleComponent.fromPlain("My variable");
|
||||
|
||||
return null;
|
||||
}
|
||||
}*/
|
@ -0,0 +1,68 @@
|
||||
package org.mineacademy.chatcontrol.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.mineacademy.chatcontrol.model.Spy;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.fo.event.SimpleEvent;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Event for when spying players receive a /spy message.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public final class SpyEvent extends SimpleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* The spy type
|
||||
*/
|
||||
private final Spy.Type type;
|
||||
|
||||
/**
|
||||
* The player who issued the message, may be null if coming from proxy for example
|
||||
*/
|
||||
@Nullable
|
||||
private final WrappedSender sender;
|
||||
|
||||
/**
|
||||
* A list of players receiving this message
|
||||
*/
|
||||
private final Set<Player> recipients;
|
||||
|
||||
/**
|
||||
* The message
|
||||
*/
|
||||
private final SimpleComponent message;
|
||||
|
||||
/**
|
||||
* Is the event cancelled?
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public SpyEvent(final Spy.Type type, final WrappedSender sender, final SimpleComponent message, final Set<Player> recipients) {
|
||||
this.type = type;
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
this.recipients = recipients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
|
||||
public final class CommandDummy extends ChatControlCommand {
|
||||
|
||||
public CommandDummy() {
|
||||
super("dummy");
|
||||
|
||||
this.setMinArguments(0);
|
||||
this.setPermission(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
// This command does nothing, we let people route to it in commands.yml to register it in tab-complete
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.db.Database;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.HookManager;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandIgnore extends ChatControlCommand {
|
||||
|
||||
public CommandIgnore() {
|
||||
super(Settings.Ignore.COMMAND_ALIASES);
|
||||
|
||||
this.setUsage(Lang.component("command-ignore-usage"));
|
||||
this.setDescription(Lang.component("command-ignore-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("command-ignore-usages"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.IGNORE_OTHERS))
|
||||
usages.add(Lang.component("command-ignore-usages-others"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.IGNORE_LIST))
|
||||
usages.add(Lang.component("command-ignore-usages-list"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.IGNORE_LIST) && this.hasPerm(Permissions.Command.IGNORE_OTHERS))
|
||||
usages.add(Lang.component("command-ignore-usages-list-others"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkUsage(this.args.length <= 2);
|
||||
|
||||
final String param = this.args[0];
|
||||
final boolean otherPlayer = this.args.length == 2;
|
||||
|
||||
this.checkBoolean(this.isPlayer() || otherPlayer, Lang.component("command-console-missing-player-name"));
|
||||
|
||||
if (otherPlayer)
|
||||
this.checkPerm(Permissions.Command.IGNORE_OTHERS);
|
||||
|
||||
if ("list".equals(param)) {
|
||||
this.checkPerm(Permissions.Command.IGNORE_LIST);
|
||||
|
||||
this.pollCache(otherPlayer ? this.args[1] : this.audience.getName(), listPlayer -> {
|
||||
this.checkBoolean(!listPlayer.getIgnoredPlayers().isEmpty(), Lang.component("command-ignore-not-ignoring" + (otherPlayer ? "-other" : ""), "player", listPlayer.getPlayerName()));
|
||||
|
||||
final List<String> ignoredPlayerNames = Database.getInstance().getPlayerNamesSync(listPlayer.getIgnoredPlayers());
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-ignore-list-header", "player", listPlayer.getPlayerName()))
|
||||
.setPages(CommonCore.convertList(ignoredPlayerNames, name -> SimpleComponent
|
||||
.fromMiniNative(" <gray>- " + name)
|
||||
.onHover(Lang.component("command-ignore-list-tooltip-stop", "player", name))
|
||||
.onClickRunCmd("/" + this.getLabel() + " " + (otherPlayer ? listPlayer.getPlayerName() + " " : "") + name)))
|
||||
.send(this.audience);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.pollCache(otherPlayer ? this.args[0] : this.audience.getName(), forCache -> {
|
||||
this.pollCache(this.args[otherPlayer ? 1 : 0], targetCache -> {
|
||||
this.checkBoolean(!forCache.getPlayerName().equals(targetCache.getPlayerName()), Lang.component("command-ignore-cannot-ignore-self"));
|
||||
|
||||
final UUID targetId = targetCache.getUniqueId();
|
||||
final boolean ignored = forCache.isIgnoringPlayer(targetId);
|
||||
|
||||
final Player otherOnline = Remain.getPlayerByUUID(targetId);
|
||||
|
||||
if (!ignored && otherOnline != null && otherOnline.isOnline() && otherOnline.hasPermission(Permissions.Bypass.REACH))
|
||||
this.returnTell(Lang.component("command-ignore-cannot-ignore-admin"));
|
||||
|
||||
forCache.setIgnoredPlayer(targetId, !ignored);
|
||||
|
||||
// Hook into CMI/Essentials async to prevent server freeze
|
||||
Platform.runTask(() -> HookManager.setIgnore(forCache.getUniqueId(), targetId, !ignored));
|
||||
|
||||
this.tellSuccess(Lang.component(
|
||||
ignored ? "command-ignore-disable" : "command-ignore-enable" + (otherPlayer ? "-other" : ""),
|
||||
"player", forCache.getPlayerName(),
|
||||
"target", targetCache.getPlayerName()));
|
||||
|
||||
this.updateProxyData(forCache);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord(
|
||||
Players.getPlayerNamesForTabComplete(this.getSender()).stream().filter(name -> !name.equals(this.audience.getName())).collect(Collectors.toList()),
|
||||
Arrays.asList(this.hasPerm(Permissions.Command.IGNORE_LIST) ? "list" : ""));
|
||||
|
||||
if (this.args.length == 2 && this.hasPerm(Permissions.Command.IGNORE_OTHERS))
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.PlaceholderPrefix;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.chatcontrol.settings.Settings.ListPlayers.SortBy;
|
||||
import org.mineacademy.fo.exception.FoException;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.platform.FoundationPlayer;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandList extends ChatControlCommand {
|
||||
|
||||
public CommandList() {
|
||||
super(Settings.ListPlayers.COMMAND_ALIASES);
|
||||
|
||||
this.setUsage(Settings.Proxy.ENABLED ? Lang.component("command-list-usage-server") : SimpleComponent.empty());
|
||||
this.setDescription(Lang.component("command-list-description"));
|
||||
this.setPermission(Permissions.Command.LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("command-list-usage-1-" + (Settings.Proxy.ENABLED ? "network" : "local")));
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
usages.add(Lang.component("command-list-usage-2"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkUsage(this.args.length <= 1);
|
||||
|
||||
final List<SimpleComponent> pages = this.compilePlayers(this.audience);
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-list-header-" + (Settings.Proxy.ENABLED ? "network" : "local"), "pages", pages.size()))
|
||||
.setPages(pages)
|
||||
.send(this.audience);
|
||||
}
|
||||
|
||||
private List<SimpleComponent> compilePlayers(final FoundationPlayer audience) {
|
||||
|
||||
// Group all players by the sorting type
|
||||
final Map<String, List<SyncedCache>> grouppedPlayers = new TreeMap<>(String::compareTo);
|
||||
|
||||
// Cache if sender sees vanished players for best performance
|
||||
final boolean senderSeeVanished = audience.hasPermission(Permissions.Bypass.VANISH);
|
||||
|
||||
// Compile a list of caches and group them
|
||||
for (final SyncedCache syncedCache : SyncedCache.getCaches()) {
|
||||
|
||||
if (syncedCache.isVanished() && !senderSeeVanished)
|
||||
continue;
|
||||
|
||||
final SortBy sorter = Settings.ListPlayers.SORT_BY;
|
||||
String key;
|
||||
|
||||
// Group by the given key
|
||||
if (sorter == SortBy.GROUP)
|
||||
key = syncedCache.getGroup();
|
||||
|
||||
else if (sorter == SortBy.NAME)
|
||||
key = syncedCache.getPlayerName();
|
||||
|
||||
else if (sorter == SortBy.NICK)
|
||||
key = syncedCache.getNameOrNickColorless();
|
||||
|
||||
else if (sorter == SortBy.PREFIX)
|
||||
key = syncedCache.getPrefix();
|
||||
|
||||
else
|
||||
throw new FoException("Sorting by " + Settings.ListPlayers.SORT_BY + " is unsupported for the list command!");
|
||||
|
||||
// Add to our group
|
||||
if (key == null)
|
||||
key = "";
|
||||
|
||||
final List<SyncedCache> caches = grouppedPlayers.getOrDefault(key, new ArrayList<>());
|
||||
caches.add(syncedCache);
|
||||
|
||||
// Save to main group
|
||||
grouppedPlayers.put(key, caches);
|
||||
}
|
||||
|
||||
final List<SimpleComponent> sortedPlayers = new ArrayList<>();
|
||||
int count = 1;
|
||||
|
||||
for (final List<SyncedCache> caches : grouppedPlayers.values()) {
|
||||
Collections.sort(caches, Comparator.comparing(SyncedCache::getPlayerName));
|
||||
|
||||
for (final SyncedCache cache : caches) {
|
||||
final Variables variables = Variables.builder().placeholders(cache.getPlaceholders(PlaceholderPrefix.PLAYER)).placeholder("count", count++);
|
||||
|
||||
final String format = variables.replaceLegacy(Settings.ListPlayers.FORMAT);
|
||||
final List<String> formatHover = variables.replaceLegacyList(Settings.ListPlayers.FORMAT_HOVER);
|
||||
|
||||
sortedPlayers.add(SimpleComponent.fromMiniAmpersand(format).onHoverLegacy(formatHover));
|
||||
}
|
||||
}
|
||||
|
||||
return sortedPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return Settings.Proxy.ENABLED ? this.completeLastWord(SyncedCache.getServers()) : NO_COMPLETE;
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,568 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.conversations.ConversationContext;
|
||||
import org.bukkit.conversations.Prompt;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.mineacademy.chatcontrol.SenderCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Spy;
|
||||
import org.mineacademy.chatcontrol.model.ToggleType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.Database;
|
||||
import org.mineacademy.chatcontrol.model.db.Log;
|
||||
import org.mineacademy.chatcontrol.model.db.Mail;
|
||||
import org.mineacademy.chatcontrol.model.db.Mail.Recipient;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.TimeUtil;
|
||||
import org.mineacademy.fo.conversation.SimplePrompt;
|
||||
import org.mineacademy.fo.exception.FoException;
|
||||
import org.mineacademy.fo.menu.model.ItemCreator;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleBook;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.Tuple;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.platform.FoundationPlayer;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.remain.CompMaterial;
|
||||
import org.mineacademy.fo.remain.CompMetadata;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
public final class CommandMail extends ChatControlCommand {
|
||||
|
||||
public CommandMail() {
|
||||
super(Settings.Mail.COMMAND_ALIASES);
|
||||
|
||||
this.setUsage(Lang.component("command-mail-usage"));
|
||||
this.setDescription(Lang.component("command-mail-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.MAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-mail-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkConsole();
|
||||
|
||||
final String param = this.args[0];
|
||||
final Player player = this.getPlayer();
|
||||
|
||||
final Database database = Database.getInstance();
|
||||
final WrappedSender wrapped = WrappedSender.fromPlayer(player);
|
||||
|
||||
final UUID uuid = wrapped.getUniqueId();
|
||||
final SenderCache senderCache = wrapped.getSenderCache();
|
||||
final PlayerCache playerCache = wrapped.getPlayerCache();
|
||||
|
||||
final SimpleBook pendingBody = CommonCore.getOrDefault(senderCache.getPendingMail(), SimpleBook.newEmptyBook());
|
||||
|
||||
if ("send".equals(param) || "s".equals(param)) {
|
||||
this.checkNotNull(senderCache.getPendingMail(), Lang.component("command-mail-no-pending"));
|
||||
this.checkBoolean(pendingBody.isSigned(), Lang.component("command-mail-no-subject"));
|
||||
this.checkArgs(2, Lang.component("command-mail-no-recipients"));
|
||||
this.checkUsage(this.args.length == 2);
|
||||
|
||||
this.sendMail(wrapped, this.args[1], pendingBody);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if ("autoreply".equals(param) || "autor".equals(param) || "ar".equals(param)) {
|
||||
this.checkArgs(2, Lang.component("command-mail-autoresponder-usage"));
|
||||
|
||||
final String timeRaw = this.joinArgs(1);
|
||||
|
||||
if ("off".equals(timeRaw) || "view".equals(timeRaw)) {
|
||||
this.checkBoolean(playerCache.isAutoResponderValid(), Lang.component("command-mail-autoresponder-disabled"));
|
||||
|
||||
final Tuple<SimpleBook, Long> autoResponder = playerCache.getAutoResponder();
|
||||
|
||||
if ("off".equals(timeRaw)) {
|
||||
playerCache.removeAutoResponder();
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-autoresponder-removed"));
|
||||
} else {
|
||||
autoResponder.getKey().openPlain(wrapped.getAudience());
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-autoresponder",
|
||||
"title", autoResponder.getKey().getTitle(),
|
||||
"date", TimeUtil.getFormattedDateShort(autoResponder.getValue())));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long futureTime;
|
||||
|
||||
try {
|
||||
futureTime = System.currentTimeMillis() + this.findTime(timeRaw).getTimeSeconds() * 1000;
|
||||
|
||||
} catch (final FoException ex) {
|
||||
this.returnTell(Lang.component("command-mail-autoresponder-invalid-time", "time", timeRaw));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If has no email, try updating current auto-responder's date
|
||||
if (senderCache.getPendingMail() == null) {
|
||||
this.checkBoolean(playerCache.hasAutoResponder(), Lang.component("command-mail-autoresponder-missing"));
|
||||
|
||||
playerCache.setAutoResponderDate(futureTime);
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-autoresponder-updated", "date", TimeUtil.getFormattedDateShort(futureTime)));
|
||||
return;
|
||||
}
|
||||
|
||||
this.checkBoolean(pendingBody.isSigned(), Lang.component("command-mail-no-subject"));
|
||||
|
||||
// Save
|
||||
playerCache.setAutoResponder(senderCache.getPendingMail(), futureTime);
|
||||
|
||||
// Remove draft from cache because it was finished
|
||||
senderCache.setPendingMail(null);
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-autoresponder-set", "date", TimeUtil.getFormattedDateShort(futureTime)));
|
||||
return;
|
||||
}
|
||||
|
||||
else if ("open".equals(param) || "forward".equals(param) || "reply".equals(param) || "delete-sender".equals(param) || "delete-recipient".equals(param)) {
|
||||
this.checkArgs(2, "Unique mail ID has not been provided. If this is a bug, please report it. If you are playing hard, play harder!");
|
||||
|
||||
final UUID mailId = UUID.fromString(this.args[1]);
|
||||
|
||||
this.syncCallback(() -> database.findMail(mailId), mail -> {
|
||||
this.checkNotNull(mail, Lang.component("command-mail-delete-invalid"));
|
||||
|
||||
if ("open".equals(param)) {
|
||||
mail.displayTo(this.audience);
|
||||
|
||||
if (!String.join(" ", this.args).contains("-donotmarkasread"))
|
||||
mail.markOpen(player);
|
||||
|
||||
} else if ("forward".equals(param)) {
|
||||
|
||||
// No recipients
|
||||
if (this.args.length == 2)
|
||||
new PromptForwardRecipients(mailId).show(player);
|
||||
|
||||
else if (this.args.length == 3)
|
||||
this.sendMail(wrapped, this.args[2], SimpleBook.clone(mail.getBody(), player.getName()));
|
||||
|
||||
else
|
||||
this.returnInvalidArgs(this.joinArgs(1));
|
||||
}
|
||||
|
||||
else if ("reply".equals(param)) {
|
||||
this.checkConsole();
|
||||
|
||||
senderCache.setPendingMailReply(mail);
|
||||
|
||||
this.getPlayer().chat("/" + this.getLabel() + " new");
|
||||
}
|
||||
|
||||
else if ("delete-sender".equals(param)) {
|
||||
this.checkBoolean(!mail.isSenderDeleted(), Lang.component("command-mail-delete-invalid"));
|
||||
|
||||
mail.setSenderDeleted(true);
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-delete-sender"));
|
||||
}
|
||||
|
||||
else if ("delete-recipient".equals(param)) {
|
||||
this.checkArgs(3, Lang.component("command-mail-delete-no-recipient"));
|
||||
|
||||
final UUID recipientId = UUID.fromString(this.args[2]);
|
||||
final Recipient recipient = mail.findRecipient(recipientId);
|
||||
this.checkNotNull(recipient, Lang.component("command-mail-delete-invalid-recipient", "uuid", recipientId));
|
||||
|
||||
this.checkBoolean(!recipient.isMarkedDeleted(), Lang.component("command-mail-delete-invalid"));
|
||||
|
||||
mail.setDeletedBy(recipient);
|
||||
|
||||
this.tellSuccess(Lang.component("command-mail-delete-recipient"));
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.checkUsage(this.args.length == 1);
|
||||
|
||||
if ("new".equals(param) || "n".equals(param)) {
|
||||
this.checkUsage(this.args.length == 1);
|
||||
this.checkBoolean(CompMaterial.isAir(player.getItemInHand().getType()), Lang.component("command-mail-hand-full"));
|
||||
|
||||
for (final ItemStack stack : player.getInventory().getContents())
|
||||
if (stack != null && CompMetadata.hasMetadata(stack, SimpleBook.TAG))
|
||||
this.returnTell(Lang.component("command-mail-already-drafting"));
|
||||
|
||||
final ItemStack bookItem = ItemCreator
|
||||
.fromBookPlain(pendingBody, true)
|
||||
.name(Lang.legacy("command-mail-item-title"))
|
||||
.lore(Lang.legacy("command-mail-item-tooltip"))
|
||||
.make();
|
||||
|
||||
player.setItemInHand(bookItem);
|
||||
|
||||
if (senderCache.getPendingMailReply() != null)
|
||||
this.tellInfo(Lang.component("command-mail-reply-usage", "player", senderCache.getPendingMailReply().getSenderName()));
|
||||
else
|
||||
this.tellInfo(Lang.component("command-mail-new-usage-" + (senderCache.getPendingMail() == null ? "new" : "pending")));
|
||||
|
||||
} else if ("inbox".equals(param) || "i".equals(param) || "read".equals(param)) {
|
||||
this.syncCallback(() -> database.findMailsTo(uuid), mails -> {
|
||||
final List<SimpleComponent> pages = new ArrayList<>();
|
||||
|
||||
for (final Mail incoming : mails) {
|
||||
final Recipient recipient = incoming.findRecipient(uuid);
|
||||
final boolean read = recipient.isOpened();
|
||||
|
||||
// Hide deleted emails
|
||||
if (recipient.isMarkedDeleted())
|
||||
continue;
|
||||
|
||||
final List<SimpleComponent> openHover = new ArrayList<>();
|
||||
|
||||
openHover.add(Lang.component("command-mail-open-tooltip"));
|
||||
openHover.add(Lang.component("command-mail-open-tooltip-script-" + (read ? "read" : "unread"),
|
||||
"date", TimeUtil.getFormattedDateShort(recipient.getOpenTime())));
|
||||
|
||||
pages.add(SimpleComponent
|
||||
.fromMiniNative("<dark_gray>[" + (read ? "<gray>" : "<dark_green>") + "O<dark_gray>]")
|
||||
.onHover(openHover)
|
||||
.onClickRunCmd("/" + this.getLabel() + " open " + incoming.getUniqueId())
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<gold>R<dark_gray>]")
|
||||
.onHover(Lang.component("command-mail-reply-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " reply " + incoming.getUniqueId())
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<dark_aqua>F<dark_gray>]")
|
||||
.onHover(Lang.component("command-mail-forward-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " forward " + incoming.getUniqueId())
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<red>X<dark_gray>]<white>")
|
||||
.onHover(Lang.component("command-mail-delete-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " delete-recipient " + incoming.getUniqueId() + " " + player.getUniqueId())
|
||||
|
||||
.append(Lang.component("command-mail-inbox-line",
|
||||
"subject", CommonCore.getOrDefault(incoming.getSubject(), ChatUtil.capitalize(Lang.plain("part-blank"))),
|
||||
"sender", CommonCore.getOrDefault(incoming.getSenderName(), ChatUtil.capitalize(Lang.plain("part-unknown"))),
|
||||
"date", TimeUtil.getFormattedDateMonth(incoming.getDate()))));
|
||||
}
|
||||
|
||||
this.checkBoolean(!pages.isEmpty(), Lang.component("command-mail-no-incoming-mail"));
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-mail-inbox-header"))
|
||||
.setPages(pages)
|
||||
.send(this.audience);
|
||||
});
|
||||
|
||||
} else if ("archive".equals(param) || "a".equals(param) || "sent".equals(param)) {
|
||||
this.syncCallback(() -> database.findMailsFrom(uuid), mails -> {
|
||||
final List<SimpleComponent> pages = new ArrayList<>();
|
||||
|
||||
for (final Mail outgoing : mails) {
|
||||
|
||||
// Hide deleted emails
|
||||
if (outgoing.isSenderDeleted() || outgoing.isAutoReply())
|
||||
continue;
|
||||
|
||||
final List<SimpleComponent> statusHover = new ArrayList<>();
|
||||
statusHover.add(Lang.component("command-mail-archive-recipients-tooltip"));
|
||||
|
||||
final List<Recipient> recipients = outgoing.getRecipients();
|
||||
|
||||
int index = 0;
|
||||
for (final String recipientName : database.getPlayerNamesSync(CommonCore.convertList(recipients, Recipient::getUniqueId))) {
|
||||
final Recipient recipient = recipients.get(index);
|
||||
|
||||
statusHover.add(Lang.component("command-mail-archive-tooltip-" + (recipient.isOpened() ? "read" : "unread"), "recipient", recipientName));
|
||||
index++;
|
||||
}
|
||||
|
||||
pages.add(SimpleComponent.empty()
|
||||
|
||||
.appendMiniNative("<dark_gray>[<gold>O<dark_gray>]")
|
||||
.onHover(Lang.component("command-mail-open-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " open " + outgoing.getUniqueId() + " -donotmarkasread")
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<dark_aqua>F<dark_gray>]")
|
||||
.onHover(Lang.component("command-mail-forward-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " forward " + outgoing.getUniqueId())
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<red>X<dark_gray>]")
|
||||
.onHover(Lang.component("command-mail-delete-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " delete-sender " + outgoing.getUniqueId())
|
||||
|
||||
.append(Lang.component("command-mail-archive-line",
|
||||
"subject", outgoing.getSubject(),
|
||||
"recipients", Lang.numberFormat("case-recipient", outgoing.getRecipients().size()),
|
||||
"date", TimeUtil.getFormattedDateMonth(outgoing.getDate())))
|
||||
|
||||
.onHover(statusHover));
|
||||
}
|
||||
|
||||
this.checkBoolean(!pages.isEmpty(), Lang.component("command-mail-archive-no-mail"));
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-mail-archive-header"))
|
||||
.setPages(pages)
|
||||
.send(this.audience);
|
||||
});
|
||||
|
||||
} else
|
||||
this.returnInvalidArgs(param);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the recipients and sends the book email
|
||||
*/
|
||||
private void sendMail(final WrappedSender wrapped, final String recipientsLine, final SimpleBook body) {
|
||||
|
||||
String[] split = recipientsLine.split("\\|");
|
||||
|
||||
// Check for special cases
|
||||
if (split.length == 1) {
|
||||
final String param = split[0].toLowerCase();
|
||||
|
||||
// Send to offline receivers
|
||||
if ("all".equals(param)) {
|
||||
this.checkPerm(Permissions.Command.MAIL_SEND_ALL);
|
||||
|
||||
this.pollCaches(caches -> {
|
||||
this.sendMail0(wrapped, body, caches);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Send to all online network players
|
||||
else if ("online".equals(param)) {
|
||||
this.checkPerm(Permissions.Command.MAIL_SEND_ONLINE);
|
||||
|
||||
split = CommonCore.toArray(Common.getPlayerNames());
|
||||
}
|
||||
}
|
||||
|
||||
final List<PlayerCache> tempRecipients = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
final String recipientName = split[i];
|
||||
|
||||
if (!recipientName.isEmpty()) {
|
||||
final boolean last = i + 1 == split.length;
|
||||
|
||||
this.pollCache(recipientName, recipientCache -> {
|
||||
tempRecipients.add(recipientCache);
|
||||
|
||||
if (last)
|
||||
this.sendMail0(wrapped, body, tempRecipients);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMail0(final WrappedSender wrapped, final SimpleBook body, final List<PlayerCache> recipients) {
|
||||
final Set<String> uniqueNames = new HashSet<>();
|
||||
boolean warned = false;
|
||||
|
||||
// Remove invalid recipients
|
||||
for (final Iterator<PlayerCache> it = recipients.iterator(); it.hasNext();) {
|
||||
final PlayerCache recipient = it.next();
|
||||
final String playerName = recipient.getPlayerName();
|
||||
final boolean isSelf = this.getPlayer().getUniqueId().equals(recipient.getUniqueId());
|
||||
|
||||
// Strip duplicates
|
||||
if (uniqueNames.contains(playerName)) {
|
||||
it.remove();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Disallow when recipients ignores sender
|
||||
if (!this.hasPerm(Permissions.Bypass.REACH) && recipient.isIgnoringPlayer(this.getPlayer().getUniqueId())) {
|
||||
this.tellError(Lang.component("command-mail-send-fail-ignore", "player", playerName));
|
||||
warned = true;
|
||||
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Disallow when recipient has turned mails off
|
||||
if (Settings.Toggle.APPLY_ON.contains(ToggleType.MAIL) && recipient.hasToggledPartOff(ToggleType.MAIL) && !isSelf) {
|
||||
this.tellError(Lang.component("command-mail-send-fail-toggle", "player", playerName));
|
||||
warned = true;
|
||||
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Auto responder > send auto response back to sender
|
||||
if (recipient.isAutoResponderValid() && !isSelf)
|
||||
Platform.runTask(20, () -> Mail.sendAutoReply(recipient.getUniqueId(), this.getPlayer().getUniqueId(), recipient.getAutoResponder().getKey()));
|
||||
|
||||
uniqueNames.add(playerName);
|
||||
}
|
||||
|
||||
// Prepare mail
|
||||
final Mail mail = Mail.send(this.getPlayer(), recipients, body);
|
||||
|
||||
// Broadcast to spying players
|
||||
Spy.broadcastMail(wrapped, recipients, mail);
|
||||
|
||||
// Log
|
||||
Log.logMail(this.getPlayer(), mail);
|
||||
|
||||
// Remove draft from sender because it was finished
|
||||
SenderCache.from(this.getSender()).setPendingMail(null);
|
||||
|
||||
// Try removing the item if it still exists
|
||||
final Player player = this.getPlayer();
|
||||
final ItemStack[] content = player.getInventory().getContents();
|
||||
|
||||
for (int itemIndex = 0; itemIndex < content.length; itemIndex++) {
|
||||
final ItemStack item = content[itemIndex];
|
||||
|
||||
if (item != null && CompMetadata.hasMetadata(player, SimpleBook.TAG))
|
||||
content[itemIndex] = new ItemStack(CompMaterial.AIR.getMaterial());
|
||||
}
|
||||
|
||||
player.getInventory().setContents(content);
|
||||
player.updateInventory();
|
||||
|
||||
if (recipients.isEmpty()) {
|
||||
if (!warned)
|
||||
this.tellError(Lang.component("command-mail-send-fail"));
|
||||
|
||||
} else
|
||||
this.tellSuccess(Lang.component("command-mail-send-success"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord("new", "n", "send", "s", "autor", "inbox", "i", "read", "archive", "a", "sent");
|
||||
|
||||
if (this.args.length == 2)
|
||||
if ("autor".equals(this.args[0]))
|
||||
return this.completeLastWord("view", "off", "3 hours", "7 days");
|
||||
|
||||
else if ("send".equals(this.args[0])) {
|
||||
final List<String> tab = new ArrayList<>();
|
||||
|
||||
if (this.hasPerm(Permissions.Command.MAIL_SEND_ONLINE))
|
||||
tab.add("online");
|
||||
|
||||
if (this.hasPerm(Permissions.Command.MAIL_SEND_ALL))
|
||||
tab.add("all");
|
||||
|
||||
tab.addAll(this.completeLastWordPlayerNames());
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// Classes
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
private static class PromptForwardRecipients extends SimplePrompt {
|
||||
|
||||
/**
|
||||
* The mail that is being forwarded
|
||||
*/
|
||||
private final UUID mailId;
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.conversation.SimplePrompt#getPrompt(org.bukkit.conversations.ConversationContext)
|
||||
*/
|
||||
@Override
|
||||
protected String getPrompt(final ConversationContext ctx) {
|
||||
return Lang.legacy("command-mail-forward-recipients");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.conversation.SimplePrompt#isInputValid(org.bukkit.conversations.ConversationContext, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected boolean isInputValid(final ConversationContext context, final String input) {
|
||||
if (input.isEmpty() || input.equals("|")) {
|
||||
this.tell(Lang.component("command-mail-forward-recipients-invalid", "input", input));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.bukkit.conversations.ValidatingPrompt#acceptValidatedInput(org.bukkit.conversations.ConversationContext, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected Prompt acceptValidatedInput(final ConversationContext context, final String input) {
|
||||
Platform.runTaskAsync(() -> {
|
||||
for (final String playerName : input.split("\\|"))
|
||||
if (!Bukkit.getOfflinePlayer(playerName).hasPlayedBefore()) {
|
||||
this.tell(Lang.component("player-not-stored", "player", playerName));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Send later so that the player is not longer counted as "conversing"
|
||||
Platform.runTask(5, () -> {
|
||||
final FoundationPlayer audience = Platform.toPlayer(this.getPlayer(context));
|
||||
final Variables variables = Variables.builder(audience);
|
||||
|
||||
audience.dispatchCommand(variables.replaceLegacy(Settings.Mail.COMMAND_ALIASES.get(0) + " forward " + this.mailId + " " + input));
|
||||
this.tell(context, variables.replaceLegacy(Lang.legacy("command-mail-forward-success")));
|
||||
});
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.Colors;
|
||||
import org.mineacademy.chatcontrol.model.Format;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.RandomUtil;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandMe extends ChatControlCommand {
|
||||
|
||||
public CommandMe() {
|
||||
super(Settings.Me.COMMAND_ALIASES);
|
||||
|
||||
this.setUsage(Lang.component("command-me-usage"));
|
||||
this.setDescription(Lang.component("command-me-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.ME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-me-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
String message = this.joinArgs(0);
|
||||
|
||||
if (message.equals("is the best")) {
|
||||
this.tell("&k | &r &6You are not the best. Kangarko with his MineAcademy.org thing is the best. Our trained personal has been sent to help you. Expected arrival: " + (5 + RandomUtil.nextInt(10)) + " minutes.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
message = Colors.removeColorsNoPermission(this.getSender(), message, Colors.Type.ME);
|
||||
|
||||
if (Settings.MAKE_CHAT_LINKS_CLICKABLE && this.getSender().hasPermission(Permissions.Chat.LINKS))
|
||||
message = ChatUtil.addMiniMessageUrlTags(message);
|
||||
|
||||
final WrappedSender wrappedSender = WrappedSender.fromAudience(this.audience);
|
||||
final SimpleComponent messageComponent = Variables.builder(this.audience).replaceMessageVariables(SimpleComponent.fromMiniSection(message));
|
||||
|
||||
final Format format = Format.parse(Settings.Me.FORMAT);
|
||||
|
||||
final SimpleComponent formattedMessage = format.build(wrappedSender, CommonCore.newHashMap("message", messageComponent));
|
||||
final UUID senderId = this.isPlayer() ? this.getPlayer().getUniqueId() : CommonCore.ZERO_UUID;
|
||||
final boolean bypassReach = this.hasPerm(Permissions.Bypass.REACH);
|
||||
|
||||
Players.showMe(senderId, bypassReach, formattedMessage);
|
||||
|
||||
if (!this.isPlayer())
|
||||
this.tell(formattedMessage);
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.ME, senderId, bypassReach, formattedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return this.completeLastWordPlayerNames();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SenderCache;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandMotd extends ChatControlCommand {
|
||||
|
||||
public CommandMotd() {
|
||||
super(Settings.Motd.COMMAND_ALIASES);
|
||||
|
||||
this.setMaxArguments(1);
|
||||
this.setUsage(Lang.component("command-motd-usage"));
|
||||
this.setDescription(Lang.component("command-motd-description"));
|
||||
this.setPermission(Permissions.Command.MOTD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("command-motd-usages-self"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.MOTD_OTHERS))
|
||||
usages.add(Lang.component("command-motd-usages-others"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkBoolean(this.isPlayer() || this.args.length == 1, Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollCache(this.args.length == 1 ? this.args[0] : this.audience.getName(), cache -> {
|
||||
this.checkBoolean(SyncedCache.isPlayerConnected(cache.getUniqueId()), Lang.component("player-not-online", "player", cache.getPlayerName()));
|
||||
|
||||
final boolean self = cache.getPlayerName().equals(this.audience.getName());
|
||||
|
||||
if (!self)
|
||||
this.checkPerm(Permissions.Command.MOTD_OTHERS);
|
||||
|
||||
final Player player = Bukkit.getPlayerExact(cache.getPlayerName());
|
||||
|
||||
if (player != null)
|
||||
Players.showMotd(WrappedSender.fromPlayerCaches(player, cache, SenderCache.from(player)), false);
|
||||
|
||||
else if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.MOTD, cache.getUniqueId());
|
||||
|
||||
if (!self)
|
||||
this.tellSuccess(Lang.component("command-motd-success"));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return this.completeLastWordPlayerNames();
|
||||
}
|
||||
}
|
@ -0,0 +1,317 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.MuteType;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.model.db.ServerSettings;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.Messenger;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.TimeUtil;
|
||||
import org.mineacademy.fo.exception.FoException;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.HookManager;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.SimpleTime;
|
||||
import org.mineacademy.fo.model.Tuple;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandMute extends ChatControlCommand {
|
||||
|
||||
public CommandMute() {
|
||||
super(Settings.Mute.COMMAND_ALIASES);
|
||||
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.MUTE);
|
||||
this.setUsage(Lang.component("command-mute-usage"));
|
||||
this.setDescription(Lang.component("command-mute-description"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-mute-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
final MuteType type = this.findEnum(MuteType.class, this.args[0]);
|
||||
|
||||
// Print status
|
||||
if (this.args.length == 1) {
|
||||
final List<SimpleComponent> messages = new ArrayList<>();
|
||||
|
||||
if (type == MuteType.SERVER) {
|
||||
final boolean muted = ServerSettings.getInstance().isMuted();
|
||||
final String remainingTime = TimeUtil.formatTimeShort(ServerSettings.getInstance().getUnmuteTimeRemaining() / 1000);
|
||||
|
||||
messages.add(Lang
|
||||
.component("command-mute-server-" + (muted ? "on" : "off"), "remaining_time", remainingTime)
|
||||
.onHover(Lang.component("command-mute-change-status-tooltip-" + (muted ? "unmute" : "mute"), "remaining_time", remainingTime))
|
||||
.onClickRunCmd("/" + this.getLabel() + " server " + (muted ? "off" : "3m")));
|
||||
|
||||
} else if (type == MuteType.PROXY) {
|
||||
final boolean muted = ServerSettings.isProxyLoaded() ? ServerSettings.getProxy().isMuted() : false;
|
||||
final String remainingTime = ServerSettings.isProxyLoaded() ? TimeUtil.formatTimeShort(ServerSettings.getProxy().getUnmuteTimeRemaining() / 1000) : "0";
|
||||
|
||||
messages.add(Lang
|
||||
.component("command-mute-proxy-" + (muted ? "on" : "off"), "remaining_time", remainingTime)
|
||||
.onHover(Lang.component("command-mute-change-status-tooltip-" + (muted ? "unmute" : "mute"), "remaining_time", remainingTime))
|
||||
.onClickRunCmd("/" + this.getLabel() + " proxy " + (muted ? "off" : "3m")));
|
||||
|
||||
} else if (type == MuteType.CHANNEL)
|
||||
for (final Channel channel : Channel.getChannels()) {
|
||||
final boolean muted = channel.isMuted();
|
||||
final String remainingTime = TimeUtil.formatTimeShort(channel.getUnmuteTimeRemaining() / 1000);
|
||||
|
||||
messages.add(Lang
|
||||
.component("command-mute-player-or-channel-" + (muted ? "on" : "off"), "player_or_channel", channel.getName(), "remaining_time", remainingTime)
|
||||
.onHover(Lang.component("command-mute-change-status-tooltip-" + (muted ? "unmute" : "mute"), "remaining_time", remainingTime))
|
||||
.onClickRunCmd("/" + this.getLabel() + " channel " + channel.getName() + " " + (muted ? "off" : "3m")));
|
||||
}
|
||||
else {
|
||||
this.pollCaches(caches -> {
|
||||
for (final PlayerCache otherCache : caches) {
|
||||
boolean muted = otherCache.isMuted();
|
||||
long remainingTimeLong = Common.getOrDefault(otherCache.getUnmuteTimeRemaining(), 0L);
|
||||
boolean externalMute = false;
|
||||
|
||||
if (!muted) {
|
||||
final Tuple<Boolean, Long> muteTuple = HookManager.getUnmuteTime(otherCache.getUniqueId());
|
||||
|
||||
if (muteTuple.getKey()) {
|
||||
muted = true;
|
||||
remainingTimeLong = muteTuple.getValue() == 0 ? 0 : (muteTuple.getValue() - System.currentTimeMillis());
|
||||
|
||||
externalMute = true;
|
||||
}
|
||||
}
|
||||
|
||||
final String remainingTime;
|
||||
|
||||
if (muted) {
|
||||
if (remainingTimeLong != 0)
|
||||
remainingTime = TimeUtil.formatTimeShort((remainingTimeLong / 1000) + 1);
|
||||
else
|
||||
remainingTime = externalMute ? Lang.legacy("command-mute-external") : Lang.plain("part-unknown");
|
||||
} else
|
||||
remainingTime = Lang.plain("part-none");
|
||||
|
||||
String command;
|
||||
|
||||
if (externalMute) {
|
||||
if (HookManager.isEssentialsLoaded())
|
||||
command = "/essentials:mute " + otherCache.getPlayerName();
|
||||
else
|
||||
command = muted ? "/unmute " + otherCache.getPlayerName() : "/tempmute " + otherCache.getPlayerName() + " 3m";
|
||||
} else
|
||||
command = "/" + this.getLabel() + " player " + otherCache.getPlayerName() + " " + (muted ? "off" : "3m");
|
||||
|
||||
messages.add(Lang
|
||||
.component("command-mute-player-or-channel-" + (muted ? "on" : "off"), "player_or_channel", otherCache.getPlayerName(), "remaining_time", remainingTime)
|
||||
.onHover(Lang.component("command-mute-change-status-tooltip-" + (muted ? "unmute" : "mute"), "remaining_time", remainingTime))
|
||||
.onClickRunCmd(command));
|
||||
}
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-mute-player-status"))
|
||||
.setPages(messages)
|
||||
.send(this.audience);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-mute-status").replace("{type}", type.getLangKey()))
|
||||
.setPages(messages)
|
||||
.send(this.audience);
|
||||
}
|
||||
|
||||
else if (this.args.length >= 2) {
|
||||
final boolean requiresNoExtraArgument = type == MuteType.PROXY || type == MuteType.SERVER;
|
||||
|
||||
this.checkBoolean(this.args.length >= (requiresNoExtraArgument ? 2 : 3), Lang.component("command-mute-no-duration"));
|
||||
|
||||
final String name = requiresNoExtraArgument ? "" : this.args[1];
|
||||
final String reason = CommonCore.joinRange(requiresNoExtraArgument ? 2 : 3, this.args);
|
||||
final String rawDuration = this.args[requiresNoExtraArgument ? 1 : 2];
|
||||
final boolean isOff = "off".equals(rawDuration);
|
||||
|
||||
SimpleTime duration = null;
|
||||
|
||||
if (!isOff)
|
||||
try {
|
||||
final long seconds = TimeUtil.toMilliseconds(rawDuration) / 1000L;
|
||||
|
||||
duration = SimpleTime.fromSeconds((int) seconds);
|
||||
|
||||
} catch (final NumberFormatException ex) {
|
||||
this.returnTell(Lang.component("command-mute-invalid-duration", "input", rawDuration));
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(ex.getMessage());
|
||||
}
|
||||
|
||||
final SimpleComponent muteMessage = Lang.component("command-mute-mute-success-" + (reason.isEmpty() ? "plain" : "reason"),
|
||||
"type", type.getLangKey() + (requiresNoExtraArgument ? "" : " " + name),
|
||||
"duration", rawDuration,
|
||||
"reason", reason,
|
||||
"player", this.audience.getName());
|
||||
|
||||
final SimpleComponent unmuteMessage = Lang.component("command-mute-unmute-success",
|
||||
"type", type.getLangKey() + (requiresNoExtraArgument ? "" : " " + name),
|
||||
"player", this.audience.getName());
|
||||
|
||||
final Set<CommandSender> recipients = new HashSet<>();
|
||||
|
||||
if (type == MuteType.CHANNEL) {
|
||||
final Channel channel = this.findChannel(name);
|
||||
|
||||
this.checkBoolean(isOff || !channel.isMuted(), Lang.component("command-mute-already-muted", "type", ChatUtil.capitalize(type.getKey()), "name", name));
|
||||
this.checkBoolean(!isOff || channel.isMuted(), Lang.component("command-mute-not-muted", "type", ChatUtil.capitalize(type.getKey()), "name", name));
|
||||
|
||||
channel.setMuted(duration);
|
||||
|
||||
recipients.addAll(channel.getOnlinePlayers().keySet());
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.MUTE, type.getKey(), channel.getName(), isOff ? "off" : duration.toString(), (isOff ? unmuteMessage : muteMessage));
|
||||
|
||||
} else if (type == MuteType.PLAYER) {
|
||||
final SimpleTime finalDuration = duration;
|
||||
|
||||
this.pollCache(name, playerCache -> {
|
||||
final SyncedCache syncedCache = SyncedCache.fromUniqueId(playerCache.getUniqueId());
|
||||
|
||||
this.checkBoolean(isOff || !playerCache.isMuted(), Lang.component("command-mute-already-muted", "type", ChatUtil.capitalize(type.getKey()), "name", name));
|
||||
this.checkBoolean(!isOff || playerCache.isMuted(), Lang.component("command-mute-not-muted", "type", ChatUtil.capitalize(type.getKey()), "name", name));
|
||||
|
||||
final Player playerInstance = playerCache.toPlayer();
|
||||
final String targetPlayerName = playerCache.getPlayerName();
|
||||
|
||||
// Check not self
|
||||
if (playerInstance != null) {
|
||||
this.checkBoolean(isOff || !this.isPlayer() || !playerInstance.equals(this.getPlayer()), Lang.component("command-mute-cannot-mute-yourself"));
|
||||
|
||||
recipients.add(playerInstance);
|
||||
}
|
||||
|
||||
if (syncedCache != null)
|
||||
this.checkBoolean(!syncedCache.hasMuteBypass(), Lang.component("command-mute-cannot-mute-admin"));
|
||||
|
||||
// Send to LiteBans
|
||||
if (isOff)
|
||||
HookManager.setLiteBansUnmute(targetPlayerName);
|
||||
else
|
||||
HookManager.setLiteBansMute(targetPlayerName, rawDuration, reason);
|
||||
|
||||
playerCache.setMuted(finalDuration);
|
||||
|
||||
if (Settings.Mute.BROADCAST)
|
||||
recipients.addAll(Remain.getOnlinePlayers());
|
||||
|
||||
final SimpleComponent broadcastMessage = (isOff ? unmuteMessage : muteMessage);
|
||||
|
||||
for (final CommandSender recipient : recipients)
|
||||
Messenger.announce(recipient, broadcastMessage);
|
||||
|
||||
if (Settings.Mute.BROADCAST)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.BROADCAST, Messenger.getAnnouncePrefix().appendPlain(" ").append(broadcastMessage));
|
||||
else
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.MESSAGE, playerCache.getUniqueId(), Messenger.getAnnouncePrefix().appendPlain(" ").append(broadcastMessage));
|
||||
|
||||
if (!this.isPlayer())
|
||||
this.tellInfo(broadcastMessage);
|
||||
|
||||
this.updateProxyData(playerCache);
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
} else if (type == MuteType.SERVER || type == MuteType.PROXY) {
|
||||
|
||||
if (type == MuteType.PROXY && !Settings.Proxy.ENABLED)
|
||||
this.returnTell(Lang.component("command-mute-cannot-mute-proxy-not-enabled"));
|
||||
|
||||
if (type == MuteType.PROXY && !ServerSettings.isProxyLoaded())
|
||||
this.returnTell("Proxy settings not loaded yet.");
|
||||
|
||||
final ServerSettings serverCache = type == MuteType.PROXY ? ServerSettings.getProxy() : ServerSettings.getInstance();
|
||||
|
||||
this.checkBoolean(isOff || !serverCache.isMuted(), Lang.component("command-mute-already-muted-server", "type", ChatUtil.capitalize(type.getKey())));
|
||||
this.checkBoolean(!isOff || serverCache.isMuted(), Lang.component("command-mute-not-muted-server", "type", ChatUtil.capitalize(type.getKey())));
|
||||
|
||||
serverCache.setMuted(duration);
|
||||
recipients.addAll(Remain.getOnlinePlayers());
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.MUTE, type.getKey(), "", isOff ? "off" : duration.toString(), (isOff ? unmuteMessage : muteMessage));
|
||||
|
||||
} else
|
||||
throw new FoException("Unknown mute type: " + type);
|
||||
|
||||
recipients.add(this.getSender());
|
||||
|
||||
for (final CommandSender recipient : recipients)
|
||||
Messenger.announce(recipient, isOff ? unmuteMessage : muteMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
final List<String> timeSuggestions = Arrays.asList("off", "1m", "15m");
|
||||
|
||||
if (this.args.length == 1) {
|
||||
final List<String> keys = new ArrayList<>();
|
||||
|
||||
for (final MuteType type : MuteType.values()) {
|
||||
if (type == MuteType.PROXY && !Settings.Proxy.ENABLED)
|
||||
continue;
|
||||
|
||||
keys.add(type.getKey());
|
||||
}
|
||||
|
||||
return this.completeLastWord(keys);
|
||||
|
||||
}
|
||||
if (this.args.length == 2)
|
||||
if ("server".equals(this.args[0]) || "proxy".equals(this.args[0]))
|
||||
return this.completeLastWord(timeSuggestions);
|
||||
|
||||
else if ("channel".equals(this.args[0]))
|
||||
return this.completeLastWord(Channel.getChannelNames());
|
||||
|
||||
else
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
if (this.args.length == 3 && !"server".equals(this.args[0]))
|
||||
return this.completeLastWord(timeSuggestions);
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.operator.Tag.Type;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandRealName extends ChatControlCommand {
|
||||
|
||||
public CommandRealName() {
|
||||
super(Settings.RealName.COMMAND_ALIASES);
|
||||
|
||||
this.setValidArguments(0, 1);
|
||||
this.setUsage(Lang.component("command-real-name-usage"));
|
||||
this.setDescription(Lang.component("command-real-name-description"));
|
||||
this.setPermission(Permissions.Command.REAL_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkBoolean(this.args.length == 1 || this.isPlayer(), Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollCache(this.args.length == 1 ? this.args[0] : this.audience.getName(), cache -> {
|
||||
final boolean hasNick = Settings.Tag.APPLY_ON.contains(Type.NICK) && cache.hasTag(Type.NICK);
|
||||
|
||||
this.tellInfo(Lang.component("command-real-name-" + (hasNick ? "" : "no-") + "nick",
|
||||
"player", cache.getPlayerName(),
|
||||
"nick", CommonCore.getOrEmpty(cache.getTag(Type.NICK))));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Format;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.PrivateMessage;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandReply extends ChatControlCommand {
|
||||
|
||||
public CommandReply() {
|
||||
super(Settings.PrivateMessages.REPLY_ALIASES);
|
||||
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.REPLY);
|
||||
this.setUsage(Lang.component("command-reply-dosage"));
|
||||
this.setDescription(Lang.component("command-reply-prescription"));
|
||||
this.setAutoHandleHelp(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkConsole();
|
||||
|
||||
final String message = this.joinArgs(0);
|
||||
|
||||
final WrappedSender wrapped = WrappedSender.fromAudience(this.audience);
|
||||
final String replyPlayer = wrapped.getSenderCache().getReplyPlayerName();
|
||||
|
||||
this.checkNotNull(replyPlayer, Lang.component("command-reply-alone"));
|
||||
|
||||
// Handle replying to console
|
||||
if (replyPlayer.equalsIgnoreCase("CONSOLE")) {
|
||||
final Map<String, Object> placeholders = CommonCore.newHashMap(
|
||||
"message", message,
|
||||
"receiver", Lang.legacy("part-console"),
|
||||
"player", Lang.legacy("part-console"),
|
||||
"sender", this.audience.getName());
|
||||
|
||||
this.tell(Format.parse(Settings.PrivateMessages.FORMAT_SENDER).build(wrapped, placeholders));
|
||||
Common.tell(Bukkit.getConsoleSender(), Format.parse(Settings.PrivateMessages.FORMAT_RECEIVER).build(wrapped, placeholders));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final SyncedCache syncedCache = SyncedCache.fromPlayerName(replyPlayer);
|
||||
this.checkNotNull(syncedCache, Lang.component("player-not-online", "player", replyPlayer));
|
||||
|
||||
PrivateMessage.send(wrapped, syncedCache, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return this.completeLastWordPlayerNames();
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Colors;
|
||||
import org.mineacademy.chatcontrol.model.Format;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.ToggleType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandSay extends ChatControlCommand {
|
||||
|
||||
public CommandSay() {
|
||||
super(Settings.Say.COMMAND_ALIASES);
|
||||
|
||||
this.setUsage(Lang.component("command-say-usage"));
|
||||
this.setDescription(Lang.component("command-say-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.SAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-say-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
String message = Colors.removeColorsNoPermission(this.getSender(), this.joinArgs(0), Colors.Type.SAY);
|
||||
|
||||
if (Settings.MAKE_CHAT_LINKS_CLICKABLE && this.getSender().hasPermission(Permissions.Chat.LINKS))
|
||||
message = ChatUtil.addMiniMessageUrlTags(message);
|
||||
|
||||
final WrappedSender wrappedSender = WrappedSender.fromAudience(this.audience);
|
||||
final SimpleComponent messageComponent = Variables.builder(this.audience).replaceMessageVariables(SimpleComponent.fromMiniSection(message));
|
||||
|
||||
final SimpleComponent formattedMessage = Format.parse(Settings.Say.FORMAT).build(wrappedSender, CommonCore.newHashMap("message", messageComponent));
|
||||
|
||||
final UUID senderId = this.isPlayer() ? this.getPlayer().getUniqueId() : CommonCore.ZERO_UUID;
|
||||
final boolean bypassReach = this.hasPerm(Permissions.Bypass.REACH);
|
||||
|
||||
for (final Player online : Players.getOnlinePlayersWithLoadedDb()) {
|
||||
final PlayerCache cache = PlayerCache.fromCached(online);
|
||||
|
||||
if (Settings.Toggle.APPLY_ON.contains(ToggleType.BROADCAST) && cache.hasToggledPartOff(ToggleType.BROADCAST) && !senderId.equals(online.getUniqueId()))
|
||||
continue;
|
||||
|
||||
if (!bypassReach && Settings.Ignore.HIDE_SAY && cache.isIgnoringPlayer(senderId))
|
||||
continue;
|
||||
|
||||
Common.tell(online, formattedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return this.completeLastWordPlayerNames();
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.menu.SpyMenu;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Spy;
|
||||
import org.mineacademy.chatcontrol.model.Spy.Type;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandSpy extends ChatControlCommand {
|
||||
|
||||
public CommandSpy() {
|
||||
super(Settings.Spy.COMMAND_ALIASES);
|
||||
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.SPY);
|
||||
this.setUsage(Lang.component("command-spy-usage"));
|
||||
this.setDescription(Lang.component("command-spy-description"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("command-spy-usages-1"));
|
||||
|
||||
if (Settings.Channels.ENABLED && Settings.Spy.APPLY_ON.contains(Spy.Type.CHAT))
|
||||
usages.add(Lang.component("command-spy-usages-2"));
|
||||
|
||||
usages.add(Lang.component("command-spy-usages-3"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
final String param = this.args[0];
|
||||
|
||||
if ("list".equals(param)) {
|
||||
|
||||
this.pollCaches(caches -> {
|
||||
this.checkBoolean(!caches.isEmpty(), Lang.component("command-spy-no-stored"));
|
||||
|
||||
final List<SimpleComponent> list = new ArrayList<>();
|
||||
|
||||
for (final PlayerCache diskCache : caches) {
|
||||
final boolean spyingSomething = diskCache.isSpyingSomethingEnabled();
|
||||
final String playerName = diskCache.getPlayerName();
|
||||
|
||||
if (spyingSomething)
|
||||
list.add(SimpleComponent
|
||||
.fromMiniNative(" <gray>- ")
|
||||
|
||||
.appendMiniNative("<dark_gray>[<dark_red>X<dark_gray>]")
|
||||
.onHover(Lang.component("command-spy-list-tooltip", "player", playerName))
|
||||
.onClickRunCmd("/" + this.getLabel() + " off " + playerName)
|
||||
|
||||
.appendMiniNative(" <white>" + playerName)
|
||||
.onHover(this.getSpyingStatus(diskCache))
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-spy-list-header"))
|
||||
.setPages(list)
|
||||
.send(this.audience);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ("toggle".equals(param)) {
|
||||
this.checkArgs(2, Lang.component("command-spy-toggle-no-type", "available", Settings.Spy.APPLY_ON));
|
||||
|
||||
final Spy.Type type = this.findEnum(Spy.Type.class, this.args[1], condition -> Settings.Spy.APPLY_ON.contains(condition), Lang.component("command-invalid-type",
|
||||
"type", "spy type",
|
||||
"value", this.args[1],
|
||||
"available", Settings.Spy.APPLY_ON));
|
||||
|
||||
this.checkPerm(Permissions.Spy.TYPE + type.getKey());
|
||||
|
||||
final boolean isChat = type == Type.CHAT;
|
||||
|
||||
Channel channel = null;
|
||||
|
||||
if (isChat) {
|
||||
this.checkArgs(3, Lang.component("command-spy-toggle-no-channel", "available", Channel.getChannelNames()));
|
||||
|
||||
channel = this.findChannel(this.args[2]);
|
||||
}
|
||||
|
||||
final Channel finalChannel = channel;
|
||||
|
||||
this.checkBoolean(this.isPlayer() || this.args.length == (isChat ? 4 : 3), Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollCache(this.args.length == (isChat ? 4 : 3) ? this.args[isChat ? 3 : 2] : this.audience.getName(), cache -> {
|
||||
final boolean isSpying = isChat ? cache.isSpyingChannel(finalChannel) : cache.isSpying(type);
|
||||
|
||||
if (isChat)
|
||||
cache.setSpyingChannel(finalChannel, !isSpying);
|
||||
else
|
||||
cache.setSpying(type, !isSpying);
|
||||
|
||||
this.tellSuccess(Lang.component("command-spy-" + (isSpying ? "disable" : "enable"),
|
||||
"player", cache.getPlayerName(),
|
||||
"type", isChat ? Lang.component("command-spy-type-channel").appendPlain(" " + finalChannel.getName()) : type.getLangKey()));
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.args.length > 2)
|
||||
this.returnInvalidArgs(this.joinArgs(3));
|
||||
|
||||
this.checkBoolean(this.isPlayer() || this.args.length == 2, Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollDiskCacheOrSelf(this.args.length == 2 ? this.args[1] : this.audience.getName(), cache -> {
|
||||
if ("status".equals(param)) {
|
||||
this.checkBoolean(cache.isSpyingSomething(), Lang.component("command-spy-no-spying", "player", cache.getPlayerName()));
|
||||
|
||||
this.tellNoPrefix(Lang.component("command-spy-status-1", "player", cache.getPlayerName()));
|
||||
|
||||
for (final SimpleComponent component : this.getSpyingStatus(cache))
|
||||
this.tellNoPrefix(component);
|
||||
|
||||
this.tellNoPrefix(Lang.component("command-spy-status-2", "player", cache.getPlayerName()));
|
||||
}
|
||||
|
||||
else if ("menu".equals(param)) {
|
||||
this.checkConsole();
|
||||
|
||||
SpyMenu.showTo(cache, this.getPlayer());
|
||||
}
|
||||
|
||||
else if ("off".equals(param)) {
|
||||
this.checkBoolean(cache.isSpyingSomethingEnabled(), Lang.component("command-spy-no-spying", "player", cache.getPlayerName()));
|
||||
|
||||
cache.setSpyingOff();
|
||||
this.updateProxyData(cache);
|
||||
|
||||
this.tellSuccess(Lang.component("command-spy-toggle-off", "player", cache.getPlayerName()));
|
||||
|
||||
} else if ("on".equals(param)) {
|
||||
final boolean atLeastOne = cache.setSpyingOn(cache.toPlayer());
|
||||
this.updateProxyData(cache);
|
||||
|
||||
if (atLeastOne)
|
||||
this.tellSuccess(Lang.component("command-spy-toggle-on", "player", cache.getPlayerName()));
|
||||
else
|
||||
this.tellError(Lang.component("command-spy-cannot-toggle-anything-no-perms", "perm", Permissions.Spy.TYPE + "{type}"));
|
||||
|
||||
} else
|
||||
this.returnInvalidArgs(param);
|
||||
});
|
||||
}
|
||||
|
||||
private List<SimpleComponent> getSpyingStatus(final PlayerCache diskCache) {
|
||||
final List<SimpleComponent> hover = new ArrayList<>();
|
||||
|
||||
if (!diskCache.getSpyingSectors().isEmpty()) {
|
||||
hover.add(Lang.component("command-spy-status-sectors"));
|
||||
|
||||
for (final Spy.Type type : diskCache.getSpyingSectors())
|
||||
if (type != Type.CHAT && Settings.Spy.APPLY_ON.contains(type))
|
||||
hover.add(SimpleComponent.fromMiniAmpersand(" <gray>-<white> " + type.getLangKey()));
|
||||
}
|
||||
|
||||
if (Settings.Spy.APPLY_ON.contains(Spy.Type.CHAT))
|
||||
if (!diskCache.getSpyingChannels().isEmpty()) {
|
||||
if (!hover.isEmpty())
|
||||
hover.add(SimpleComponent.fromMiniNative("<reset>"));
|
||||
|
||||
hover.add(Lang.component("command-spy-status-channel"));
|
||||
|
||||
for (final String channelName : diskCache.getSpyingChannels())
|
||||
hover.add(SimpleComponent.fromMiniNative(" <gray>-<white> " + channelName));
|
||||
}
|
||||
|
||||
return hover;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord("status", "menu", "off", "toggle", "list");
|
||||
|
||||
if (this.args.length == 2 && Arrays.asList("status", "menu", "off", "on").contains(this.args[0]))
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
if (this.args.length > 1 && "toggle".equals(this.args[0])) {
|
||||
if (this.args.length == 2)
|
||||
return this.completeLastWord(Settings.Spy.APPLY_ON);
|
||||
|
||||
if (this.args.length == 3)
|
||||
return "chat".equals(this.args[1]) && Settings.Spy.APPLY_ON.contains(Spy.Type.CHAT) ? this.completeLastWord(Channel.getChannelNames()) : this.completeLastWordPlayerNames();
|
||||
|
||||
if (this.args.length == 4 && "chat".equals(this.args[1]))
|
||||
return this.completeLastWordPlayerNames();
|
||||
}
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.Colors;
|
||||
import org.mineacademy.chatcontrol.model.Migrator;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.operator.Tag;
|
||||
import org.mineacademy.chatcontrol.operator.Tag.TagCheck;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandTag extends ChatControlCommand {
|
||||
|
||||
public CommandTag() {
|
||||
super(Settings.Tag.COMMAND_ALIASES);
|
||||
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.TAG_TYPE.substring(0, Permissions.Command.TAG_TYPE.length() - 1));
|
||||
this.setUsage(Lang.component("command-tag-usage"));
|
||||
this.setDescription(Lang.component("command-tag-description"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-tag-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkConsole();
|
||||
|
||||
final WrappedSender wrapped = WrappedSender.fromPlayer(this.getPlayer());
|
||||
final PlayerCache cache = wrapped.getPlayerCache();
|
||||
|
||||
if ("list".equals(this.args[0])) {
|
||||
if (this.args.length > 1)
|
||||
this.returnInvalidArgs(this.joinArgs(2));
|
||||
|
||||
this.tellInfo(Lang.component("command-tag-your-tags"));
|
||||
|
||||
boolean shownAtLeastOne = false;
|
||||
|
||||
for (final Tag.Type tag : Settings.Tag.APPLY_ON)
|
||||
if (this.hasPerm(Permissions.Command.TAG_TYPE + tag.getKey())) {
|
||||
this.tellNoPrefix(" &7- " + ChatUtil.capitalize(tag.getKey()) + ": &f" + CommonCore.getOrDefault(cache.getTag(tag), Lang.plain("part-none") + "."));
|
||||
|
||||
shownAtLeastOne = true;
|
||||
}
|
||||
|
||||
if (!shownAtLeastOne)
|
||||
this.tellNoPrefix("&7 - " + Lang.plain("part-none"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if ("off".equals(this.args[0])) {
|
||||
this.checkBoolean(!cache.getTags().isEmpty(), Lang.component("command-tag-off-no-tags"));
|
||||
|
||||
for (final Tag.Type tag : Settings.Tag.APPLY_ON)
|
||||
cache.setTag(tag, null);
|
||||
|
||||
Players.setTablistName(wrapped);
|
||||
|
||||
final SimpleComponent message = Lang.component("command-tag-off-all");
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.TAG_UPDATE, Platform.getCustomServerName(), cache.getUniqueId(), cache.toMap(), message);
|
||||
|
||||
this.tellSuccess(message);
|
||||
return;
|
||||
}
|
||||
|
||||
final Tag.Type type = this.findTag(this.args[0]);
|
||||
this.checkPerm(Permissions.Command.TAG_TYPE + type.getKey());
|
||||
|
||||
if (this.args.length == 1) {
|
||||
this.tellInfo(Lang.component("command-tag-status-self",
|
||||
"type", type.getKey(),
|
||||
"tag", CommonCore.getOrDefault(cache.getTag(type), Lang.plain("part-none"))));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String tag = this.joinArgs(1);
|
||||
|
||||
if (tag.contains("&#"))
|
||||
tag = Migrator.convertAmpersandToMiniHex(tag);
|
||||
|
||||
if (tag.contains("#"))
|
||||
tag = Migrator.convertHexToMiniHex(tag);
|
||||
|
||||
// Colorize according to senders permissions
|
||||
tag = Colors.removeColorsNoPermission(this.getSender(), tag, type.getColorType());
|
||||
|
||||
// Apply rules!
|
||||
final TagCheck check = Tag.filter(type, wrapped, tag);
|
||||
tag = check.getMessage();
|
||||
|
||||
this.checkBoolean(!check.isCancelledSilently(), Lang.component("command-tag-not-allowed"));
|
||||
this.setTag(type, cache, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1) {
|
||||
final List<String> tags = new ArrayList<>();
|
||||
|
||||
for (final Tag.Type type : Settings.Tag.APPLY_ON)
|
||||
if (this.hasPerm(Permissions.Command.TAG_TYPE + type.getKey()))
|
||||
tags.add(type.getKey());
|
||||
|
||||
return this.completeLastWord(tags, "list");
|
||||
}
|
||||
|
||||
if (this.args.length == 2)
|
||||
return this.completeLastWord("off");
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mineacademy.chatcontrol.SenderCache;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.PlaceholderPrefix;
|
||||
import org.mineacademy.chatcontrol.model.PrivateMessage;
|
||||
import org.mineacademy.chatcontrol.model.ToggleType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandTell extends ChatControlCommand {
|
||||
|
||||
public CommandTell() {
|
||||
super(Settings.PrivateMessages.TELL_ALIASES);
|
||||
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.TELL);
|
||||
this.setUsage(Lang.component("command-tell-usage"));
|
||||
this.setDescription(Lang.component("command-tell-description"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-tell-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
final boolean isOff = "off".equalsIgnoreCase(this.args[0]);
|
||||
final String message = this.joinArgs(1);
|
||||
|
||||
final WrappedSender wrapped = WrappedSender.fromAudience(this.audience);
|
||||
|
||||
final SyncedCache syncedSenderCache = SyncedCache.fromUniqueId(wrapped.getUniqueId());
|
||||
final SyncedCache syncedReceiverCache = SyncedCache.fromNickColorless(this.args[0]);
|
||||
|
||||
final SenderCache senderCache = wrapped.getSenderCache();
|
||||
|
||||
if (isOff || message.isEmpty()) {
|
||||
this.checkBoolean(Settings.PrivateMessages.AUTOMODE, Lang.component("command-rule-conversation-disabled"));
|
||||
this.checkConsole();
|
||||
|
||||
final String conversingPlayer = senderCache.getConversingPlayerName();
|
||||
|
||||
if (isOff) {
|
||||
this.checkNotNull(conversingPlayer, Lang.component("command-tell-conversation-mode-not-conversing"));
|
||||
final SyncedCache conversingCache = SyncedCache.fromPlayerName(conversingPlayer);
|
||||
|
||||
this.tellSuccess(Lang.component("command-tell-conversation-mode-off", conversingCache == null ? null : conversingCache.getPlaceholders(PlaceholderPrefix.RECEIVER)));
|
||||
senderCache.setConversingPlayerName(null);
|
||||
senderCache.setLastAutoModeChat(0);
|
||||
|
||||
} else {
|
||||
this.checkNotNull(syncedReceiverCache, Lang.component("command-tell-receiver-offline", "receiver_name", this.args[0]));
|
||||
|
||||
final String receiverName = syncedReceiverCache.getPlayerName();
|
||||
final boolean isConversing = receiverName.equals(conversingPlayer);
|
||||
|
||||
if (syncedReceiverCache.isVanished() && !this.hasPerm(Permissions.Bypass.VANISH))
|
||||
this.returnTell(Lang.component("command-tell-receiver-offline", "receiver_name", receiverName));
|
||||
|
||||
final Map<String, Object> placeholders = new HashMap<>();
|
||||
|
||||
placeholders.put("message", message);
|
||||
placeholders.putAll(syncedReceiverCache.getPlaceholders(PlaceholderPrefix.RECEIVER));
|
||||
placeholders.putAll(syncedSenderCache.getPlaceholders(PlaceholderPrefix.SENDER));
|
||||
|
||||
if (this.isPlayer() && !this.hasPerm(Permissions.Bypass.REACH)) {
|
||||
if (Settings.Ignore.ENABLED && Settings.Ignore.STOP_PRIVATE_MESSAGES && syncedReceiverCache.isIgnoringPlayer(this.getPlayer().getUniqueId()))
|
||||
this.returnTell(Lang.component("command-ignore-cannot-pm", placeholders));
|
||||
|
||||
if (Settings.Toggle.APPLY_ON.contains(ToggleType.PRIVATE_MESSAGE) && !this.audience.getName().equals(receiverName) && syncedReceiverCache.hasToggledPartOff(ToggleType.PRIVATE_MESSAGE))
|
||||
this.returnTell(Lang.component("command-toggle-cannot-pm", placeholders));
|
||||
}
|
||||
|
||||
senderCache.setConversingPlayerName(isConversing ? null : receiverName);
|
||||
senderCache.setLastAutoModeChat(0);
|
||||
this.tellSuccess(Lang.component("command-tell-conversation-mode-" + (isConversing ? "off" : "on"), placeholders));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.checkNotNull(syncedReceiverCache, Lang.component("command-tell-receiver-offline", "receiver_name", this.args[0]));
|
||||
|
||||
PrivateMessage.send(wrapped, syncedReceiverCache, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return this.args.length == 1 ? this.completeLastWordPlayerNames() : NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,237 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.ChatControlCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.PlayerMessageType;
|
||||
import org.mineacademy.chatcontrol.model.ToggleType;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessage;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessages;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.ChatUtil;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class CommandToggle extends ChatControlCommand {
|
||||
|
||||
public CommandToggle() {
|
||||
super(Settings.Toggle.COMMAND_ALIASES);
|
||||
|
||||
this.setValidArguments(1, 2);
|
||||
this.setPermission(Permissions.Command.TOGGLE_TYPE.substring(0, Permissions.Command.TOGGLE_TYPE.length() - 1));
|
||||
this.setUsage(Lang.component("command-toggle-usage"));
|
||||
this.setDescription(Lang.component("command-toggle-description"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
Collections.addAll(usages, Lang.component("command-toggle-usages-1",
|
||||
"label", this.getLabel(),
|
||||
"toggle_available", Settings.Toggle.APPLY_ON,
|
||||
"messages_available", Settings.Messages.APPLY_ON));
|
||||
|
||||
if (this.canToggle(ToggleType.CHAT))
|
||||
usages.add(Lang.component("command-toggle-usages-chat"));
|
||||
|
||||
if (this.canToggle(PlayerMessageType.JOIN))
|
||||
usages.add(Lang.component("command-toggle-usages-join"));
|
||||
|
||||
if (this.canToggle(PlayerMessageType.TIMED))
|
||||
usages.add(Lang.component("command-toggle-usages-timed"));
|
||||
|
||||
if (this.canToggle(ToggleType.PRIVATE_MESSAGE))
|
||||
usages.add(Lang.component("command-toggle-usages-private-message"));
|
||||
|
||||
if (this.canToggle(ToggleType.SOUND_NOTIFY))
|
||||
usages.add(Lang.component("command-toggle-usages-sound-notify"));
|
||||
|
||||
usages.add(Lang.component("command-toggle-usages-2"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
this.checkConsole();
|
||||
|
||||
final String typeRaw = this.args[0];
|
||||
|
||||
final PlayerCache cache = PlayerCache.fromCached(this.getPlayer());
|
||||
ToggleType toggleType = null;
|
||||
PlayerMessageType messageType = null;
|
||||
|
||||
try {
|
||||
toggleType = ToggleType.fromKey(typeRaw);
|
||||
|
||||
if (toggleType != null)
|
||||
if (!Settings.Toggle.APPLY_ON.contains(toggleType))
|
||||
toggleType = null;
|
||||
else
|
||||
this.checkPerm(Permissions.Command.TOGGLE_TYPE + toggleType.getKey());
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
messageType = PlayerMessageType.fromKey(typeRaw);
|
||||
|
||||
if (!this.canToggle(messageType))
|
||||
messageType = null;
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
}
|
||||
|
||||
if ("list".equals(typeRaw)) {
|
||||
final List<SimpleComponent> pages = new ArrayList<>();
|
||||
|
||||
if (!Settings.Messages.APPLY_ON.isEmpty()) {
|
||||
for (final Entry<PlayerMessageType, Set<String>> entry : cache.getIgnoredMessages().entrySet())
|
||||
if (this.canToggle(entry.getKey())) {
|
||||
pages.add(Lang.component("command-toggle-list-line", "type", ChatUtil.capitalize(entry.getKey().getToggleLangKey())));
|
||||
|
||||
for (final String groupName : entry.getValue())
|
||||
pages.add(SimpleComponent
|
||||
.fromMiniNative(" <gray>-<white> ")
|
||||
.appendPlain(groupName)
|
||||
.onHover(Lang.component("command-toggle-list-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " " + entry.getKey() + " " + groupName));
|
||||
}
|
||||
|
||||
if (!pages.isEmpty())
|
||||
pages.add(SimpleComponent.empty());
|
||||
}
|
||||
|
||||
if (!Settings.Toggle.APPLY_ON.isEmpty()) {
|
||||
pages.add(Lang.component("command-toggle-list-plugin-part-title"));
|
||||
|
||||
for (final ToggleType playerToggle : ToggleType.values())
|
||||
if (this.canToggle(playerToggle))
|
||||
pages.add(SimpleComponent
|
||||
.fromMiniAmpersand(" <gray>-<white> " + ChatUtil.capitalize(playerToggle.getDescription()) + "<gray>: ")
|
||||
.append(Lang.component("command-toggle-list-plugin-part-" + (cache.hasToggledPartOff(playerToggle) ? "ignoring" : "receiving")))
|
||||
.onHover(Lang.component("command-toggle-list-plugin-part-toggle"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " " + playerToggle.getKey() + " " + cache.getPlayerName())
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
new ChatPaginator()
|
||||
.setPages(pages)
|
||||
.setFoundationHeader(Lang.legacy("command-toggle-list-plugin-part-header", "player", cache.getPlayerName()))
|
||||
.send(this.audience);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.checkBoolean(toggleType != null || messageType != null, Lang.component("command-toggle-invalid-type",
|
||||
"available_toggles", Common.join(Settings.Toggle.APPLY_ON),
|
||||
"available_messages", Common.join(Settings.Messages.APPLY_ON)));
|
||||
|
||||
if (messageType != null) {
|
||||
if (this.args.length == 2) {
|
||||
final PlayerMessage message = this.findMessage(messageType, this.args[1]);
|
||||
final boolean ignoring = cache.isIgnoringMessage(message);
|
||||
this.checkToggle(ignoring);
|
||||
|
||||
cache.setIgnoringMessage(message, !ignoring);
|
||||
this.tellSuccess(Lang.component("command-toggle-ignore-group-" + (ignoring ? "off" : "on"), "type", messageType.getToggleLangKey(), "group", message.getGroup()));
|
||||
}
|
||||
|
||||
else {
|
||||
final boolean ignoring = cache.isIgnoringMessages(messageType);
|
||||
this.checkToggle(ignoring);
|
||||
|
||||
cache.setIgnoringMessages(messageType, !ignoring);
|
||||
this.tellSuccess(Lang.component("command-toggle-ignore-all-" + (ignoring ? "off" : "on"), "type", messageType.getToggleLangKey()));
|
||||
}
|
||||
|
||||
} else {
|
||||
final boolean ignoring = cache.hasToggledPartOff(toggleType);
|
||||
this.checkToggle(ignoring);
|
||||
|
||||
if (toggleType != null && toggleType.equals(ToggleType.PRIVATE_MESSAGE) && !cache.hasManuallyToggledPMs())
|
||||
cache.setManuallyToggledPMs(true);
|
||||
|
||||
cache.setToggledPart(toggleType, !ignoring);
|
||||
this.tellSuccess(Lang.component("command-ignore-part-" + (ignoring ? "off" : "on"), "type", toggleType.getDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkToggle(final boolean ignoring) {
|
||||
this.checkPerm(ignoring ? Permissions.Command.TOGGLE_STATE_OFF : Permissions.Command.TOGGLE_STATE_ON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the toggle is enabled from settings
|
||||
*/
|
||||
private boolean canToggle(final ToggleType type) {
|
||||
return Settings.Toggle.APPLY_ON.contains(type) && this.hasPerm(Permissions.Command.TOGGLE_TYPE + type.getKey());
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the player message is enabled from settings
|
||||
*/
|
||||
private boolean canToggle(final PlayerMessageType type) {
|
||||
return (Settings.Messages.APPLY_ON.contains(type) || (type == PlayerMessageType.SWITCH && Settings.Proxy.ENABLED)) && this.hasPerm(Permissions.Command.TOGGLE_TYPE + type.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
if (this.args.length == 1) {
|
||||
final Set<String> completed = CommonCore.newSet("list");
|
||||
|
||||
for (final PlayerMessageType type : Settings.Messages.APPLY_ON)
|
||||
if (this.canToggle(type))
|
||||
completed.add(type.getKey());
|
||||
|
||||
for (final ToggleType type : Settings.Toggle.APPLY_ON)
|
||||
if (this.canToggle(type))
|
||||
completed.add(type.getKey());
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
if (this.canToggle(PlayerMessageType.SWITCH))
|
||||
completed.add("switch");
|
||||
|
||||
return this.completeLastWord(completed);
|
||||
}
|
||||
|
||||
if (this.args.length == 2) {
|
||||
PlayerMessageType type;
|
||||
|
||||
try {
|
||||
type = PlayerMessageType.fromKey(this.args[0]);
|
||||
|
||||
if (type != null && !this.canToggle(type))
|
||||
return NO_COMPLETE;
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
|
||||
return this.completeLastWord(PlayerMessages.getInstance().getMessageNames(type));
|
||||
}
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,459 @@
|
||||
package org.mineacademy.chatcontrol.command;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SenderCache;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.PlayerMessageType;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.model.RuleType;
|
||||
import org.mineacademy.chatcontrol.model.WrappedSender;
|
||||
import org.mineacademy.chatcontrol.model.db.Database;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.operator.Group;
|
||||
import org.mineacademy.chatcontrol.operator.Groups;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessage;
|
||||
import org.mineacademy.chatcontrol.operator.PlayerMessages;
|
||||
import org.mineacademy.chatcontrol.operator.Rule;
|
||||
import org.mineacademy.chatcontrol.operator.Rules;
|
||||
import org.mineacademy.chatcontrol.operator.Tag;
|
||||
import org.mineacademy.chatcontrol.operator.Tag.Type;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.Common;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.Messenger;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.command.SharedBukkitCommandCore;
|
||||
import org.mineacademy.fo.command.SimpleCommandCore;
|
||||
import org.mineacademy.fo.exception.CommandException;
|
||||
import org.mineacademy.fo.model.CompChatColor;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
public interface SharedChatControlCommandCore extends SharedBukkitCommandCore {
|
||||
|
||||
/**
|
||||
* Return a channel by name or send error message to player if wrong name
|
||||
*
|
||||
* @param channelName
|
||||
* @return
|
||||
*/
|
||||
default Channel findChannel(@NonNull final String channelName) {
|
||||
final Channel channel = Channel.findChannel(channelName);
|
||||
this.checkBoolean(channel != null, Lang.component("command-invalid-channel", "channel", channelName, "available", CommonCore.joinAnd(Channel.getChannelNames())));
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return channel mode by name or send error to player if wrong mode
|
||||
*
|
||||
* @param modeName
|
||||
* @return
|
||||
*/
|
||||
default ChannelMode findMode(@NonNull final String modeName) {
|
||||
try {
|
||||
return ChannelMode.fromKey(modeName);
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-invalid-mode", "mode", modeName, "available", ChannelMode.values()));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rule by the name or send error message to the player
|
||||
*
|
||||
* @param ruleName
|
||||
* @return
|
||||
*/
|
||||
default Rule findRule(final String ruleName) {
|
||||
final List<Rule> namedRules = Rules.getInstance().getRulesWithName();
|
||||
final Rule rule = Rules.getInstance().findRule(ruleName);
|
||||
final String available = namedRules.isEmpty() ? Lang.plain("part-none") : CommonCore.join(namedRules, ", ", Rule::getName);
|
||||
|
||||
this.checkBoolean(ruleName != null && !ruleName.isEmpty(), Lang.component("command-no-rule-name", "available", available));
|
||||
this.checkBoolean(rule != null, Lang.component("command-invalid-rule", "rule", ruleName, "available", available));
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse rule type from name or send error message to the player
|
||||
*
|
||||
* @param typeName
|
||||
* @return
|
||||
*/
|
||||
default RuleType findRuleType(final String typeName) {
|
||||
try {
|
||||
return RuleType.fromKey(typeName);
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-invalid-type", "type", "rule", "value", typeName, "available", RuleType.values()));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rule group by the name or send error message to the player
|
||||
*
|
||||
* @param groupName
|
||||
* @return
|
||||
*/
|
||||
default Group findRuleGroup(final String groupName) {
|
||||
final List<String> groups = Groups.getInstance().getGroupNames();
|
||||
final Group group = Groups.getInstance().findGroup(groupName);
|
||||
final String available = groups.isEmpty() ? Lang.plain("part-none") : CommonCore.join(groups);
|
||||
|
||||
this.checkBoolean(groupName != null && !groupName.isEmpty(), Lang.component("command-no-group-name", "available", available));
|
||||
this.checkBoolean(group != null, Lang.component("command-invalid-group", "group", groupName, "available", available));
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rule by the name or send error message to the player
|
||||
*
|
||||
* @param type
|
||||
* @param groupName
|
||||
* @return
|
||||
*/
|
||||
default PlayerMessage findMessage(final PlayerMessageType type, final String groupName) {
|
||||
final Collection<String> itemNames = PlayerMessages.getInstance().getMessageNames(type);
|
||||
final PlayerMessage items = PlayerMessages.getInstance().findMessage(type, groupName);
|
||||
final String available = itemNames.isEmpty() ? Lang.plain("part-none") : CommonCore.join(itemNames);
|
||||
|
||||
this.checkBoolean(groupName != null && !groupName.isEmpty(), Lang.component("command-no-message-name", "available", available));
|
||||
this.checkBoolean(items != null, Lang.component("command-invalid-type", "type", "message", "value", groupName, "available", available));
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse rule type from name or send error message to the player
|
||||
*
|
||||
* @param typeName
|
||||
* @return
|
||||
*/
|
||||
default PlayerMessageType findMessageType(final String typeName) {
|
||||
try {
|
||||
final PlayerMessageType type = PlayerMessageType.fromKey(typeName);
|
||||
|
||||
if (!Settings.Messages.APPLY_ON.contains(type))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
return type;
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-invalid-type", "type", "message", "value", typeName, "available", PlayerMessageType.values()));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the disk cache for name or if name is null and we are not console then return it for the sender
|
||||
*
|
||||
* @param nameOrNick
|
||||
* @param syncCallback
|
||||
*
|
||||
* @throws CommandException
|
||||
*/
|
||||
default void pollDiskCacheOrSelf(@Nullable final String nameOrNick, final Consumer<PlayerCache> syncCallback) throws CommandException {
|
||||
|
||||
if (nameOrNick == null) {
|
||||
this.checkBoolean(this.isPlayer(), Lang.component("command-console-missing-player-name"));
|
||||
|
||||
syncCallback.accept(PlayerCache.fromCached(this.getPlayer()));
|
||||
return;
|
||||
}
|
||||
|
||||
this.pollCache(nameOrNick, syncCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get a player cache by his name or nick from either
|
||||
* data.db or database. Since this is a blocking operation, we have a synced
|
||||
* callback here.
|
||||
*
|
||||
* @param nameOrNick
|
||||
* @param syncCallback
|
||||
*/
|
||||
default void pollCache(final String nameOrNick, final Consumer<PlayerCache> syncCallback) {
|
||||
final SenderCache senderCache = SenderCache.from(this.getSender());
|
||||
|
||||
// Prevent calling this again when loading
|
||||
senderCache.setQueryingDatabase(true);
|
||||
|
||||
PlayerCache.poll(nameOrNick, cache -> {
|
||||
handleCallbackCommand(this.getSender(),
|
||||
() -> {
|
||||
this.checkBoolean(cache != null, Lang.component("player-not-stored", "player", nameOrNick));
|
||||
|
||||
syncCallback.accept(cache);
|
||||
|
||||
}, () -> {
|
||||
senderCache.setQueryingDatabase(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certain information async and then process this information in the sync callback
|
||||
*
|
||||
* @param <T>
|
||||
* @param asyncGetter
|
||||
* @param syncCallback
|
||||
*/
|
||||
default <T> void syncCallback(final Supplier<T> asyncGetter, final Consumer<T> syncCallback) {
|
||||
final SenderCache senderCache = SenderCache.from(this.getSender());
|
||||
|
||||
// Prevent calling this again when loading
|
||||
senderCache.setQueryingDatabase(true);
|
||||
|
||||
// Run the getter async
|
||||
asyncCallbackCommand(this.getSender(), () -> {
|
||||
final T value = asyncGetter.get();
|
||||
|
||||
// Then run callback on the main thread
|
||||
syncCallbackCommand(this.getSender(),
|
||||
() -> syncCallback.accept(value),
|
||||
() -> senderCache.setQueryingDatabase(false));
|
||||
|
||||
}, () -> senderCache.setQueryingDatabase(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles callback for all caches on disk or database
|
||||
*
|
||||
* @param syncCallback
|
||||
*/
|
||||
default void pollCaches(final Consumer<List<PlayerCache>> syncCallback) {
|
||||
final SenderCache senderCache = SenderCache.from(this.getSender());
|
||||
|
||||
this.tellInfo(Lang.component("command-compiling-data"));
|
||||
|
||||
// Prevent calling this again when loading
|
||||
senderCache.setQueryingDatabase(true);
|
||||
|
||||
PlayerCache.pollAll(caches -> handleCallbackCommand(this.getSender(),
|
||||
() -> syncCallback.accept(caches),
|
||||
() -> senderCache.setQueryingDatabase(false)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse dog tag or send error message to the player
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
default Tag.Type findTag(final String name) {
|
||||
try {
|
||||
final Tag.Type tag = Tag.Type.fromKey(name);
|
||||
|
||||
if (!Settings.Tag.APPLY_ON.contains(tag))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
return tag;
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-invalid-tag", "tag", name, "available", Common.join(Settings.Tag.APPLY_ON)));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special method used for nicks/prefixes/suffixes
|
||||
*
|
||||
* @param type
|
||||
* @param cache
|
||||
* @param tag
|
||||
*/
|
||||
default void setTag(final Tag.Type type, final PlayerCache cache, String tag) {
|
||||
final boolean remove = "off".equals(tag) || tag.equals(cache.getPlayerName());
|
||||
final boolean self = this.getAudience().getName().equals(cache.getPlayerName());
|
||||
|
||||
this.checkBoolean(!remove || cache.hasTag(type), Lang.component("command-tag-no-tag-" + (self ? "self" : "other"),
|
||||
"target", cache.getPlayerName(),
|
||||
"type", type.getKey()));
|
||||
|
||||
final char firstChar = tag.charAt(0);
|
||||
final char lastChar = tag.charAt(tag.length() - 1);
|
||||
|
||||
if (firstChar == '"' || firstChar == '\'')
|
||||
tag = tag.substring(1);
|
||||
|
||||
if (lastChar == '"' || lastChar == '\'')
|
||||
tag = tag.substring(0, tag.length() - 1);
|
||||
|
||||
// Prevent "legacy chars found" error if not parsed
|
||||
if (!Settings.Colors.APPLY_ON.contains(type.getColorType()))
|
||||
tag = CompChatColor.convertLegacyToMini(tag, true);
|
||||
|
||||
final String colorlessTag = SimpleComponent.fromMiniAmpersand(tag).toPlain();
|
||||
|
||||
if (type == Type.NICK)
|
||||
this.checkBoolean(!tag.contains(" "), Lang.component("command-tag-no-spaces"));
|
||||
|
||||
this.checkBoolean(!colorlessTag.isEmpty(), Lang.component("command-tag-no-colors-only"));
|
||||
|
||||
if (type == Tag.Type.NICK && !colorlessTag.equalsIgnoreCase(this.getAudience().getName())) {
|
||||
final String newTagFinal = tag;
|
||||
|
||||
asyncCallbackCommand(this.getSender(), () -> {
|
||||
|
||||
this.checkBoolean(colorlessTag.length() <= Settings.Tag.MAX_NICK_LENGTH, Lang.component("command-tag-exceeded-length",
|
||||
"length", colorlessTag.length(),
|
||||
"max", Settings.Tag.MAX_NICK_LENGTH));
|
||||
|
||||
if (Settings.Tag.NICK_DISABLE_IMPERSONATION) {
|
||||
final OfflinePlayer offline = Bukkit.getOfflinePlayer(colorlessTag);
|
||||
|
||||
this.checkBoolean(!offline.hasPlayedBefore(), Lang.component("command-tag-no-impersonation"));
|
||||
}
|
||||
|
||||
if (!cache.getPlayerName().equals(this.getSender().getName()))
|
||||
this.checkBoolean(!Database.getInstance().isNickUsed(colorlessTag), Lang.component("command-tag-already-used"));
|
||||
|
||||
syncCallbackCommand(this.getSender(), () -> {
|
||||
this.setTag0(type, cache, newTagFinal, remove, self);
|
||||
|
||||
}, () -> {
|
||||
// No final callback
|
||||
});
|
||||
|
||||
}, () -> {
|
||||
// No final callback
|
||||
});
|
||||
}
|
||||
|
||||
else
|
||||
this.setTag0(type, cache, tag, remove, self);
|
||||
}
|
||||
|
||||
default void setTag0(final Tag.Type type, final PlayerCache cache, final String newTag, final boolean remove, final boolean self) {
|
||||
cache.setTag(type, remove ? null : newTag);
|
||||
|
||||
final Player cachePlayer = cache.toPlayer();
|
||||
|
||||
if (cachePlayer != null)
|
||||
Players.setTablistName(WrappedSender.fromPlayerCaches(cachePlayer, cache, SenderCache.from(cachePlayer)));
|
||||
|
||||
final SimpleComponent component = Lang.component("command-tag-" + (remove ? "remove" : "set") + (self ? "-self" : ""),
|
||||
"type", type.getKey(),
|
||||
"tag", newTag,
|
||||
"target", cache.getPlayerName());
|
||||
|
||||
this.tellInfo(component);
|
||||
|
||||
// Notify proxy so that players connected on another server get their tablist updated
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.TAG_UPDATE, Platform.getCustomServerName(), cache.getUniqueId(), cache.toDataSectionOfMap(), component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes all other servers on the network get database updated for
|
||||
* the given player cache
|
||||
*
|
||||
* @param cache
|
||||
* @throws CommandException
|
||||
*/
|
||||
default void updateProxyData(final PlayerCache cache) throws CommandException {
|
||||
this.updateProxyData(cache, SimpleComponent.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes all other servers on the network get database updated for
|
||||
* the given player cache, sending the player the specified message
|
||||
*
|
||||
* @param cache
|
||||
* @param message
|
||||
* @throws CommandException
|
||||
*/
|
||||
default void updateProxyData(@NonNull final PlayerCache cache, @NonNull SimpleComponent message) throws CommandException {
|
||||
final Player messageTarget = cache.toPlayer();
|
||||
|
||||
if (messageTarget != null && !message.isEmpty()) {
|
||||
Messenger.info(messageTarget, message);
|
||||
|
||||
message = SimpleComponent.empty();
|
||||
}
|
||||
|
||||
if (Settings.Proxy.ENABLED)
|
||||
ProxyUtil.sendPluginMessage(ChatControlProxyMessage.DATABASE_UPDATE, Platform.getCustomServerName(), cache.getUniqueId(), cache.toDataSectionOfMap(), message);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SimpleCommandCore#tellInfo(String)
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
void tellInfo(String message);
|
||||
|
||||
/**
|
||||
* @see SimpleCommandCore#tellInfo(SimpleComponent)
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
void tellInfo(SimpleComponent message);
|
||||
|
||||
/*
|
||||
* See below, but everything is wrapped and run async
|
||||
*/
|
||||
static void asyncCallbackCommand(final CommandSender sender, final Runnable callback, final Runnable finallyCallback) {
|
||||
Platform.runTaskAsync(() -> handleCallbackCommand(sender, callback, finallyCallback));
|
||||
}
|
||||
|
||||
/*
|
||||
* See below, but everything is wrapped and run on the main thread
|
||||
*/
|
||||
static void syncCallbackCommand(final CommandSender sender, final Runnable callback, final Runnable finallyCallback) {
|
||||
Platform.runTask(() -> handleCallbackCommand(sender, callback, finallyCallback));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wraps the given callback in try-catch clause and sends all CommandExceptions to the sender,
|
||||
* then runs the finally clause with the finallyCallback
|
||||
*/
|
||||
static void handleCallbackCommand(final CommandSender sender, final Runnable callback, final Runnable finallyCallback) {
|
||||
try {
|
||||
callback.run();
|
||||
|
||||
} catch (final CommandException ex) {
|
||||
ex.sendErrorMessage(Platform.toPlayer(sender));
|
||||
|
||||
} catch (final Throwable t) {
|
||||
Messenger.error(sender, Lang.component("command-error").replaceBracket("error", t.toString()));
|
||||
|
||||
t.printStackTrace();
|
||||
|
||||
throw t;
|
||||
|
||||
} finally {
|
||||
try {
|
||||
finallyCallback.run();
|
||||
|
||||
} catch (final Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.GenericSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.chatcontrol.settings.Settings.Channels;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.annotation.AutoRegister;
|
||||
import org.mineacademy.fo.command.SimpleCommandGroup;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Stores all /channel commands
|
||||
*/
|
||||
@AutoRegister
|
||||
public final class ChannelCommands extends SimpleCommandGroup {
|
||||
|
||||
/**
|
||||
* The singleton of this class
|
||||
*/
|
||||
@Getter
|
||||
private final static SimpleCommandGroup instance = new ChannelCommands();
|
||||
|
||||
/**
|
||||
* Initiaze this class, this must be called after settings have loaded
|
||||
*/
|
||||
private ChannelCommands() {
|
||||
super(Settings.Channels.COMMAND_ALIASES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#getHelpHeader()
|
||||
*/
|
||||
@Override
|
||||
protected String[] getHelpHeader() {
|
||||
return new String[] {
|
||||
"&8",
|
||||
"&8" + CommonCore.chatLineSmooth(),
|
||||
this.getHeaderPrefix() + " Channel Commands",
|
||||
" ",
|
||||
" &2[] &7= " + Lang.plain("command-label-optional-args"),
|
||||
" &6<> &7= " + Lang.plain("command-label-required-args"),
|
||||
" "
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#getHeaderPrefix()
|
||||
*/
|
||||
@Override
|
||||
protected String getHeaderPrefix() {
|
||||
return "<gradient:#db0000:#fb00ff><bold>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#getNoParamsHeader(org.bukkit.command.CommandSender)
|
||||
*/
|
||||
@Override
|
||||
protected List<String> getNoParamsHeader() {
|
||||
final List<String> messages = new ArrayList<>();
|
||||
|
||||
final boolean isPlayer = this.getAudience().isPlayer();
|
||||
final Player player = isPlayer ? (Player) this.getAudience().getPlayer() : null;
|
||||
final PlayerCache cache = isPlayer ? PlayerCache.fromCached(player) : null;
|
||||
|
||||
messages.add("&8" + CommonCore.chatLineSmooth());
|
||||
messages.add(this.getHeaderPrefix() + " " + Lang.plain("channel-header"));
|
||||
messages.add("");
|
||||
|
||||
if (!Settings.Channels.ENABLED) {
|
||||
messages.add(" " + Lang.plain("channel-disabled"));
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
if (isPlayer && Channels.IGNORE_WORLDS.contains(player.getWorld().getName())) {
|
||||
messages.add(" " + Lang.plain("channel-disabled-world").replace("{world}", player.getWorld().getName()));
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
if (Channel.getChannels().isEmpty()) {
|
||||
messages.add(" " + Lang.plain("channel-no-channels"));
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
// Fill in the channels player is in
|
||||
{
|
||||
boolean atLeastOneJoined = false;
|
||||
|
||||
for (final Channel channel : Channel.getChannels()) {
|
||||
final String name = channel.getName();
|
||||
final ChannelMode mode = isPlayer ? cache.getChannelMode(channel) : null;
|
||||
|
||||
SimpleComponent component = SimpleComponent.fromMiniNative("<gray> - " + (mode != null ? "<green>" : "<white>") + name + " ");
|
||||
|
||||
if (mode == null) {
|
||||
if (this.getAudience().hasPermission(Permissions.Channel.JOIN.replace("{channel}", name).replace("{mode}", "write")))
|
||||
component = component
|
||||
.onHover(Lang.component("channel-tooltip-join"))
|
||||
.onClickRunCmd("/" + Settings.Channels.COMMAND_ALIASES.get(0) + " join " + name + " write");
|
||||
} else {
|
||||
if (this.getAudience().hasPermission(Permissions.Channel.LEAVE.replace("{channel}", name)))
|
||||
component = component
|
||||
.onHover(Lang.component("channel-tooltip-leave"))
|
||||
.onClickRunCmd("/" + Settings.Channels.COMMAND_ALIASES.get(0) + " leave " + name);
|
||||
}
|
||||
|
||||
if (mode != null) {
|
||||
component = component.appendMiniNative("<dark_gray>(" + (mode == ChannelMode.WRITE ? "<gold>✎" : "<dark_green>▲") + "<dark_gray>) ");
|
||||
|
||||
if (this.getAudience().hasPermission(Permissions.Channel.JOIN.replace("{channel}", name).replace("{mode}", mode.getKey())))
|
||||
component = component
|
||||
.onHover(Lang.component("channel-tooltip-switch-to-" + (mode == ChannelMode.WRITE ? "read" : "write")))
|
||||
.onClickRunCmd("/" + Settings.Channels.COMMAND_ALIASES.get(0) + " join " + name + " " + (mode == ChannelMode.WRITE ? "read" : "write"));
|
||||
}
|
||||
|
||||
messages.add(component.toMini(null));
|
||||
atLeastOneJoined = true;
|
||||
}
|
||||
|
||||
if (!atLeastOneJoined)
|
||||
messages.add(" &7- &o" + Lang.plain("part-none"));
|
||||
}
|
||||
|
||||
messages.add("&8" + CommonCore.chatLineSmooth());
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#registerSubcommands()
|
||||
*/
|
||||
@Override
|
||||
protected void registerSubcommands() {
|
||||
this.registerSubcommand(ChannelSubCommand.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class used by all channel commands
|
||||
*/
|
||||
public static abstract class ChannelSubCommand extends GenericSubCommand {
|
||||
|
||||
protected ChannelSubCommand(final String sublabel) {
|
||||
super(ChannelCommands.getInstance(), sublabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCommand() {
|
||||
if (!Channels.ENABLED)
|
||||
this.returnTell(Lang.component("channel-disabled"));
|
||||
|
||||
if (this.isPlayer() && Channels.IGNORE_WORLDS.contains(this.getPlayer().getWorld().getName()))
|
||||
this.returnTell(Lang.component("channel-disabled-world", "world", this.getPlayer().getWorld().getName()));
|
||||
|
||||
this.onChannelCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as onCommand but we already checked if channels are enabled
|
||||
*/
|
||||
protected abstract void onChannelCommand();
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.chatcontrol.settings.Settings.Channels;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.Messenger;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class JoinChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public JoinChannelSubCommand() {
|
||||
super("join/j");
|
||||
|
||||
this.setPermission(Permissions.Channel.JOIN.replace(".{channel}.{mode}", ""));
|
||||
this.setUsage(Lang.component("channel-join-usage"));
|
||||
this.setDescription(Lang.component("channel-join-description"));
|
||||
this.setMinArguments(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("channel-join-usages-self"));
|
||||
|
||||
if (this.hasPerm(Permissions.Channel.JOIN_OTHERS))
|
||||
usages.add(Lang.component("channel-join-usages-others"));
|
||||
|
||||
usages.add(Lang.component("channel-join-usages-2"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
this.checkBoolean(this.args.length < 4, this.getUsage());
|
||||
|
||||
final Channel channel = this.findChannel(this.args[0]);
|
||||
final ChannelMode pickedMode = this.args.length >= 2 ? this.findMode(this.args[1]) : ChannelMode.WRITE;
|
||||
|
||||
this.checkBoolean(this.isPlayer() || this.args.length == 3, Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollCache(this.args.length == 3 ? this.args[2] : this.getSender().getName(), cache -> {
|
||||
final boolean self = cache.getPlayerName().equals(this.getSender().getName());
|
||||
final ChannelMode previousMode = cache.getChannelMode(channel);
|
||||
final Channel previousWriteChannel = cache.getWriteChannel();
|
||||
final Player targetPlayerOrNull = Remain.getPlayerByUUID(cache.getUniqueId());
|
||||
|
||||
ChannelMode mode = pickedMode;
|
||||
|
||||
// If no mode is specified and player can only read the channel, default to reading
|
||||
if (this.args.length < 2 && !Channel.canWriteInto(this.getSender(), channel) && Channel.canRead(this.getSender(), channel))
|
||||
mode = ChannelMode.READ;
|
||||
|
||||
this.checkPerm(Permissions.Channel.JOIN.replace("{channel}", channel.getName()).replace("{mode}", mode.getKey()));
|
||||
|
||||
// Check if joining oneself
|
||||
if (!self)
|
||||
this.checkPerm(Permissions.Channel.JOIN_OTHERS);
|
||||
|
||||
// Check if player connected
|
||||
if (Settings.Proxy.ENABLED) {
|
||||
this.checkBoolean(Settings.Database.isRemote(), Lang.component("command-remote-database-required"));
|
||||
this.checkBoolean(SyncedCache.isPlayerConnected(cache.getUniqueId()), Lang.component("player-not-connected-proxy", "player", cache.getPlayerName()));
|
||||
|
||||
} else
|
||||
this.checkNotNull(targetPlayerOrNull, Lang.component("player-not-online", "player", cache.getPlayerName()));
|
||||
|
||||
this.checkBoolean(previousMode != mode, Lang.component("channel-join-already-joined" + (self ? "-self" : ""), "mode", previousMode == null ? "" : previousMode.getKey()));
|
||||
|
||||
// Start compiling message for player
|
||||
SimpleComponent component = previousMode != null
|
||||
? Lang.component("channel-join-switch-success", "channel", channel.getName(), "old_mode", previousMode == null ? "" : previousMode.getKey(), "new_mode", mode.getKey())
|
||||
: Lang.component("channel-join-success", "channel", channel.getName(), "mode", mode.getKey());
|
||||
|
||||
final int readLimit = Settings.Channels.MAX_READ_CHANNELS.getForUUID(cache.getUniqueId());
|
||||
this.checkBoolean(mode != ChannelMode.READ || readLimit > 0, Lang.component("channel-join-read-disabled"));
|
||||
|
||||
boolean save = false;
|
||||
|
||||
// Check limits
|
||||
if (mode == ChannelMode.READ) {
|
||||
int readingChannelsAmount = 0;
|
||||
|
||||
final List<String> channelsPlayerLeft = new ArrayList<>();
|
||||
|
||||
for (final Channel otherReadChannel : cache.getChannels(ChannelMode.READ))
|
||||
if (++readingChannelsAmount >= readLimit) {
|
||||
cache.updateChannelMode(otherReadChannel, null, false);
|
||||
|
||||
channelsPlayerLeft.add(otherReadChannel.getName());
|
||||
save = true;
|
||||
}
|
||||
|
||||
if (!channelsPlayerLeft.isEmpty())
|
||||
component = component.append(Lang.component("channel-join-leave-reading-" + (self ? "you" : "other"),
|
||||
"channels", CommonCore.joinAnd(channelsPlayerLeft),
|
||||
"target", cache.getPlayerName()));
|
||||
}
|
||||
|
||||
// If player has another mode for that channel, remove it first
|
||||
if (previousMode != null) {
|
||||
cache.updateChannelMode(channel, null, false);
|
||||
|
||||
save = true;
|
||||
}
|
||||
|
||||
// Remove the player from old write channel early to avoid errors
|
||||
if (previousWriteChannel != null && mode == ChannelMode.WRITE) {
|
||||
cache.updateChannelMode(previousWriteChannel, null, false);
|
||||
|
||||
save = true;
|
||||
}
|
||||
|
||||
channel.joinPlayer(cache, mode, false);
|
||||
save = true;
|
||||
|
||||
// If player was writing in another write channel, leave him or change mode if set
|
||||
if (previousWriteChannel != null && mode == ChannelMode.WRITE)
|
||||
if (Channels.JOIN_READ_OLD && cache.getChannels(ChannelMode.READ).size() + 1 <= readLimit) {
|
||||
cache.updateChannelMode(previousWriteChannel, ChannelMode.READ, false);
|
||||
save = true;
|
||||
|
||||
} else if (previousMode == null)
|
||||
component = component.append(Lang.component("channel-join-leave-reading-" + (self ? "you" : "other"),
|
||||
"channels", previousWriteChannel.getName(),
|
||||
"target", cache.getPlayerName()));
|
||||
|
||||
if (!Settings.Proxy.ENABLED || !self)
|
||||
this.tellSuccess(component);
|
||||
|
||||
if (!self && targetPlayerOrNull != null && this.isPlayer())
|
||||
Messenger.success(targetPlayerOrNull, component);
|
||||
|
||||
if (save)
|
||||
cache.upsert();
|
||||
|
||||
// Notify proxy so that players connected on another server get their channel updated
|
||||
this.updateProxyData(cache, component);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord(this.isPlayer() ? Channel.getChannelsWithJoinPermission(this.getPlayer()) : Channel.getChannels(), Channel::getName);
|
||||
|
||||
if (this.args.length == 2) {
|
||||
final List<String> modesPlayerHasPermissionFor = new ArrayList<>();
|
||||
|
||||
for (final ChannelMode mode : ChannelMode.values())
|
||||
if (this.hasPerm(Permissions.Channel.JOIN.replace("{channel}", this.args[0]).replace("{mode}", mode.getKey())))
|
||||
modesPlayerHasPermissionFor.add(mode.getKey());
|
||||
|
||||
return this.completeLastWord(modesPlayerHasPermissionFor);
|
||||
}
|
||||
|
||||
if (this.args.length == 3 && this.hasPerm(Permissions.Channel.JOIN_OTHERS))
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.Messenger;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class LeaveChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public LeaveChannelSubCommand() {
|
||||
super("leave/l");
|
||||
|
||||
this.setPermission(Permissions.Channel.LEAVE.replace(".{channel}", ""));
|
||||
this.setUsage(Lang.component("channel-leave-usage"));
|
||||
this.setDescription(Lang.component("channel-leave-description"));
|
||||
this.setValidArguments(1, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
usages.add(Lang.component("channel-leave-usages-self"));
|
||||
|
||||
if (this.hasPerm(Permissions.Channel.LEAVE_OTHERS))
|
||||
usages.add(Lang.component("channel-leave-usages-others"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
final Channel channel = this.findChannel(this.args[0]);
|
||||
|
||||
this.checkBoolean(this.isPlayer() || this.args.length == 2, Lang.component("command-console-missing-player-name"));
|
||||
|
||||
this.pollCache(this.args.length == 2 ? this.args[1] : this.audience.getName(), cache -> {
|
||||
final boolean self = cache.getPlayerName().equals(this.audience.getName());
|
||||
final Set<Channel> oldChannels = cache.getChannels().keySet();
|
||||
final Player playerMaybe = Remain.getPlayerByUUID(cache.getUniqueId());
|
||||
|
||||
this.checkPerm(Permissions.Channel.LEAVE.replace("{channel}", channel.getName()));
|
||||
|
||||
// Check if joining oneself
|
||||
if (!self)
|
||||
this.checkPerm(Permissions.Channel.LEAVE_OTHERS);
|
||||
|
||||
// Check if player connected
|
||||
if (Settings.Proxy.ENABLED) {
|
||||
this.checkBoolean(Settings.Database.isRemote(), Lang.component("command-remote-database-required"));
|
||||
this.checkBoolean(SyncedCache.isPlayerConnected(cache.getUniqueId()), Lang.component("player-not-online", "player", cache.getPlayerName()));
|
||||
|
||||
} else
|
||||
this.checkNotNull(playerMaybe, Lang.component("player-not-online", "player", cache.getPlayerName()));
|
||||
|
||||
if (oldChannels.isEmpty())
|
||||
this.returnTell(Lang.component("channel-leave-no-channel" + (self ? "" : "-other")));
|
||||
|
||||
final List<Channel> channelsPlayerCanLeave = Channel.filterChannelsPlayerCanLeave(cache.getChannels().keySet(), playerMaybe);
|
||||
|
||||
if (!cache.isInChannel(channel.getName())) {
|
||||
if (channelsPlayerCanLeave.isEmpty())
|
||||
this.returnTell(Lang.component("channel-leave-not-joined" + (self ? "" : "-other"), "name", cache.getPlayerName()));
|
||||
else
|
||||
this.returnTell(Lang.component("channel-leave-not-joined-suggest-alt" + (self ? "" : "-other"),
|
||||
"name", cache.getPlayerName(),
|
||||
"channels", CommonCore.join(channelsPlayerCanLeave, ", ", Channel::getName)));
|
||||
}
|
||||
|
||||
final int readLimit = Settings.Channels.MAX_READ_CHANNELS.getForUUID(cache.getUniqueId());
|
||||
|
||||
final boolean hasJoinReadPerm = playerMaybe == null || playerMaybe.hasPermission(Permissions.Channel.JOIN.replace("{channel}", channel.getName()).replace("{mode}", ChannelMode.READ.getKey()));
|
||||
|
||||
// If leaving channel player is not reading and he can read,
|
||||
// turn into reading channel first before leaving completely
|
||||
if (Settings.Channels.JOIN_READ_OLD && hasJoinReadPerm && cache.getChannels(ChannelMode.READ).size() < readLimit && cache.getChannelMode(channel) != ChannelMode.READ) {
|
||||
cache.updateChannelMode(channel, ChannelMode.READ, true);
|
||||
|
||||
this.tellSuccess(Lang.component("channel-leave-switch-to-reading" + (self ? "" : "-other"),
|
||||
"channel", channel.getName(),
|
||||
"target", cache.getPlayerName()));
|
||||
|
||||
if (!self && playerMaybe != null)
|
||||
Messenger.success(playerMaybe, Lang.component("channel-leave-switch-to-reading", "channel", channel.getName()));
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
channel.leavePlayer(cache, true);
|
||||
|
||||
// Mark as manually left
|
||||
cache.markLeftChannel(channel);
|
||||
}
|
||||
|
||||
if (!Settings.Proxy.ENABLED || !self)
|
||||
this.tellSuccess(Lang.component("channel-leave-success" + (self ? "" : "-other"),
|
||||
"channel", channel.getName(), "target", cache.getPlayerName()));
|
||||
|
||||
if (!self && playerMaybe != null && !Settings.Proxy.ENABLED)
|
||||
Messenger.success(playerMaybe, Lang.component("channel-leave-success", "channel", channel.getName()));
|
||||
|
||||
// Notify proxy so that players connected on another server get their channel updated
|
||||
this.updateProxyData(cache, Lang.component("channel-leave-success", "channel", channel.getName()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord((this.isPlayer() ? Channel.getChannelsWithLeavePermission(this.getPlayer()) : Channel.getChannels())
|
||||
.stream()
|
||||
.filter(channel -> !this.isPlayer() || channel.isInChannel(this.getPlayer()))
|
||||
.collect(Collectors.toList()), Channel::getName);
|
||||
|
||||
if (this.args.length == 2 && this.hasPerm(Permissions.Channel.LEAVE_OTHERS))
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.db.PlayerCache;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class ListChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public ListChannelSubCommand() {
|
||||
super("list/ls");
|
||||
|
||||
this.setPermission(Permissions.Channel.LIST);
|
||||
this.setMaxArguments(1);
|
||||
this.setDescription(Lang.component("channel-list-description"));
|
||||
this.setUsage(Lang.component("channel-list-usage"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("channel-list-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
final String selectedChannelName = this.args.length == 1 ? this.args[0] : null;
|
||||
final Channel selectedChannel = selectedChannelName != null ? Channel.findChannel(selectedChannelName) : null;
|
||||
final boolean canSeeOptions = this.hasPerm(Permissions.Channel.LIST_OPTIONS);
|
||||
|
||||
if (selectedChannelName != null)
|
||||
this.checkNotNull(selectedChannel, Lang.component("channel-no-channel", "channel", selectedChannelName, "available", Channel.getChannelNames()));
|
||||
|
||||
this.pollCaches(caches -> {
|
||||
final List<SimpleComponent> messages = new ArrayList<>();
|
||||
final Map<String, Map<String /*player*/, ChannelMode>> allChannelPlayers = new LinkedHashMap<>();
|
||||
|
||||
for (final PlayerCache cache : caches) {
|
||||
final SyncedCache synced = SyncedCache.fromUniqueId(cache.getUniqueId());
|
||||
|
||||
if (synced == null)
|
||||
continue;
|
||||
|
||||
for (final Map.Entry<String, ChannelMode> entry : synced.getChannels().entrySet()) {
|
||||
final String channelName = entry.getKey();
|
||||
final ChannelMode mode = entry.getValue();
|
||||
|
||||
final Map<String /*player*/, ChannelMode> playersInChannel = allChannelPlayers.getOrDefault(channelName, new LinkedHashMap<>());
|
||||
|
||||
playersInChannel.put(cache.getPlayerName(), mode);
|
||||
allChannelPlayers.put(channelName, playersInChannel);
|
||||
}
|
||||
}
|
||||
|
||||
for (final Channel channel : Channel.getChannels()) {
|
||||
|
||||
// Filter channel if parameter is given
|
||||
if (selectedChannel != null && !selectedChannel.equals(channel))
|
||||
continue;
|
||||
|
||||
// Allow one-click un/mute
|
||||
final boolean muted = channel.isMuted();
|
||||
final boolean joined = this.isPlayer() ? channel.isInChannel(this.getPlayer()) : false;
|
||||
|
||||
SimpleComponent channelNameComponent = SimpleComponent.fromMiniNative(" <white>" + channel.getName());
|
||||
|
||||
if (canSeeOptions && this.isPlayer()) {
|
||||
|
||||
if (Settings.Mute.ENABLED)
|
||||
channelNameComponent = channelNameComponent
|
||||
.append(Lang.component("channel-list-" + (muted ? "unmute" : "mute")))
|
||||
.onHover(Lang.component("channel-list-" + (muted ? "unmute-tooltip" : "mute-tooltip")))
|
||||
.onClickRunCmd("/" + Settings.Mute.COMMAND_ALIASES.get(0) + " channel " + channel.getName() + " " + (muted ? "off" : "15m"));
|
||||
|
||||
channelNameComponent = channelNameComponent
|
||||
.append(Lang.component("channel-list-" + (joined ? "leave" : "join")))
|
||||
.onHover(Lang.component("channel-list-" + (joined ? "leave-tooltip" : "join-tooltip")))
|
||||
.onClickRunCmd("/" + Settings.Channels.COMMAND_ALIASES.get(0) + " " + (joined ? "leave" : "join") + " " + channel.getName());
|
||||
}
|
||||
|
||||
messages.add(channelNameComponent);
|
||||
|
||||
final Map<String /*player*/, ChannelMode> channelPlayers = allChannelPlayers.getOrDefault(channel.getName(), new LinkedHashMap<>());
|
||||
|
||||
if (channelPlayers.isEmpty())
|
||||
messages.add(Lang.component("channel-list-no-players"));
|
||||
|
||||
else
|
||||
for (final Entry<String, ChannelMode> entry : channelPlayers.entrySet()) {
|
||||
final String playerName = entry.getKey();
|
||||
final ChannelMode mode = entry.getValue();
|
||||
|
||||
SimpleComponent playerComponent = SimpleComponent.fromMiniNative(" <gray>- ");
|
||||
|
||||
if (canSeeOptions && this.isPlayer())
|
||||
playerComponent = playerComponent
|
||||
.append(Lang.component("channel-list-remove"))
|
||||
.onHover(Lang.component("channel-list-remove-tooltip", "player", playerName))
|
||||
.onClickRunCmd("/" + Settings.Channels.COMMAND_ALIASES.get(0) + " leave " + channel.getName() + " " + playerName);
|
||||
|
||||
playerComponent = playerComponent.append(Lang.component("channel-list-line",
|
||||
"mode_color", mode.getColor().toString(),
|
||||
"mode", mode.getKey(),
|
||||
"mode_colorized", mode.getColor().toString() + mode.getKey(),
|
||||
"player", playerName));
|
||||
|
||||
messages.add(playerComponent);
|
||||
}
|
||||
|
||||
messages.add(SimpleComponent.fromPlain(" "));
|
||||
}
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("channel-list-header" + (Settings.Proxy.ENABLED ? "-network" : "")))
|
||||
.setPages(messages)
|
||||
.send(this.audience);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord(Channel.getChannelNames());
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.fo.exception.EventHandledException;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class SendAsChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public SendAsChannelSubCommand() {
|
||||
super("sendas/sa");
|
||||
|
||||
this.setPermission(Permissions.Channel.SEND_AS.replace(".{channel}", ""));
|
||||
this.setUsage(Lang.component("channel-send-as-usage"));
|
||||
this.setDescription(Lang.component("channel-send-as-description"));
|
||||
this.setMinArguments(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
final Player player = this.findPlayer(this.args[0]);
|
||||
final Channel channel = this.findChannel(this.args[1]);
|
||||
final String message = this.joinArgs(2);
|
||||
|
||||
this.checkPerm(Permissions.Channel.SEND_AS.replace("{channel}", channel.getName()));
|
||||
|
||||
try {
|
||||
channel.sendMessage(player, message);
|
||||
|
||||
} catch (final EventHandledException ex) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (final SimpleComponent component : ex.getComponents())
|
||||
builder.append(component.toLegacySection(null));
|
||||
|
||||
this.tellError(Lang.component("channel-send-as-error", "player", player.getName(), "error", builder.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
|
||||
// Remove proxy players, no support yet
|
||||
return this.completeLastWordPlayerNames()
|
||||
.stream()
|
||||
.filter(name -> Bukkit.getPlayerExact(name) != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (this.args.length == 2)
|
||||
return this.completeLastWord(Channel.getChannelNames());
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class SendChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public SendChannelSubCommand() {
|
||||
super("send/s");
|
||||
|
||||
this.setPermission(Permissions.Channel.SEND.replace(".{channel}", ""));
|
||||
this.setUsage(Lang.component("channel-send-usage"));
|
||||
this.setDescription(Lang.component("channel-send-description"));
|
||||
this.setMinArguments(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
final Channel channel = this.findChannel(this.args[0]);
|
||||
final String message = this.joinArgs(1);
|
||||
|
||||
this.checkPerm(Permissions.Channel.SEND.replace("{channel}", channel.getName()));
|
||||
|
||||
channel.sendMessage(this.getSender(), message);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord(Channel.getChannelNames());
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package org.mineacademy.chatcontrol.command.channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.channel.ChannelCommands.ChannelSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Channel;
|
||||
import org.mineacademy.chatcontrol.model.ChannelMode;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.remain.Remain;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class SetChannelSubCommand extends ChannelSubCommand {
|
||||
|
||||
public SetChannelSubCommand() {
|
||||
super("set");
|
||||
|
||||
this.setPermission(Permissions.Channel.SET);
|
||||
this.setUsage(Lang.component("channel-set-usage"));
|
||||
this.setDescription(Lang.component("channel-set-description"));
|
||||
this.setMinArguments(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("channel-set-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onChannelCommand() {
|
||||
this.pollCache(this.args[0], cache -> {
|
||||
final Player playerMaybe = Remain.getPlayerByUUID(cache.getUniqueId());
|
||||
|
||||
// Check if player connected
|
||||
if (Settings.Proxy.ENABLED) {
|
||||
this.checkBoolean(Settings.Database.isRemote(), Lang.component("command-remote-database-required"));
|
||||
this.checkBoolean(SyncedCache.isPlayerConnected(cache.getUniqueId()), Lang.component("player-not-connected-proxy", "player", cache.getPlayerName()));
|
||||
|
||||
} else
|
||||
this.checkNotNull(playerMaybe, Lang.component("player-not-online", "player", cache.getPlayerName()));
|
||||
|
||||
for (final String channelAndMode : this.joinArgs(1).split("\\|")) {
|
||||
final String[] split = channelAndMode.split(" ");
|
||||
this.checkBoolean(split.length == 2, "Invalid syntax! Usage: /{label} {sublabel} <player> <channel> <mode>|<anotherChannel> <anotherMode>");
|
||||
|
||||
final Channel channel = this.findChannel(split[0]);
|
||||
final ChannelMode mode = "none".equals(split[1]) ? null : this.findMode(split[1]);
|
||||
|
||||
// Cannot have more than 1 write channel
|
||||
if (mode == ChannelMode.WRITE && cache.getWriteChannel() != null)
|
||||
cache.updateChannelMode(cache.getWriteChannel(), null, false);
|
||||
|
||||
// Remove old channel forcefully
|
||||
cache.updateChannelMode(channel, null, false);
|
||||
|
||||
// Then rejoin
|
||||
if (mode != null)
|
||||
channel.joinPlayer(cache, mode, false);
|
||||
|
||||
cache.upsert();
|
||||
|
||||
final SimpleComponent message = mode != null
|
||||
? Lang.component("channel-set-success", "channel", channel.getName(), "player", cache.getPlayerName(), "mode", mode.getKey())
|
||||
: Lang.component("channel-set-success-remove", "channel", channel.getName(), "player", cache.getPlayerName());
|
||||
|
||||
this.tellSuccess(message);
|
||||
}
|
||||
|
||||
// Notify proxy so that players connected on another server get their channel updated
|
||||
this.updateProxyData(cache);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
if (this.args.length == 2)
|
||||
return this.completeLastWord(Channel.getChannels(), Channel::getName);
|
||||
|
||||
if (this.args.length == 3)
|
||||
return this.completeLastWord(ChannelMode.values(), "none");
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,314 @@
|
||||
package org.mineacademy.chatcontrol.command.chatcontrol;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.mineacademy.chatcontrol.SyncedCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.MainSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Announce;
|
||||
import org.mineacademy.chatcontrol.model.Announce.AnnounceType;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.FileUtil;
|
||||
import org.mineacademy.fo.MinecraftVersion;
|
||||
import org.mineacademy.fo.MinecraftVersion.V;
|
||||
import org.mineacademy.fo.ReflectionUtil;
|
||||
import org.mineacademy.fo.collection.SerializedMap;
|
||||
import org.mineacademy.fo.exception.CommandException;
|
||||
import org.mineacademy.fo.model.CompToastStyle;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.remain.CompMaterial;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
|
||||
public final class AnnounceSubCommand extends MainSubCommand {
|
||||
|
||||
/**
|
||||
* The pattern to match key:value pairs in the message
|
||||
*/
|
||||
private static final Pattern ANNOUNCE_PARAM_PATTERN = Pattern.compile("\\b[a-zA-Z]+:[a-zA-Z0-9_]+\\b(?!(?=[^<]*>))");
|
||||
|
||||
public AnnounceSubCommand() {
|
||||
super("announce/a/broadcast/bc");
|
||||
|
||||
this.setUsage(Lang.component("command-announce-usage"));
|
||||
this.setDescription(Lang.component("command-announce-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.ANNOUNCE_TYPE.substring(0, Permissions.Command.ANNOUNCE_TYPE.length() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
final List<SimpleComponent> usages = new ArrayList<>();
|
||||
|
||||
if (this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.CHAT.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-chat"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.IMAGE.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-image"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.TITLE.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-title"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.ACTIONBAR.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-actionbar"));
|
||||
|
||||
if (this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.BOSSBAR.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-bossbar"));
|
||||
|
||||
if (MinecraftVersion.atLeast(V.v1_12) && this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + AnnounceType.TOAST.getKey()))
|
||||
usages.add(Lang.component("command-announce-usage-toast"));
|
||||
|
||||
if (usages.isEmpty())
|
||||
usages.add(Lang.component("command-announce-usage-no-perms"));
|
||||
|
||||
usages.add(Lang.component("command-announce-usage-footer"));
|
||||
|
||||
return SimpleComponent.join(usages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
final AnnounceType type = this.findParam(this.args[0]);
|
||||
this.checkPerm(Permissions.Command.ANNOUNCE_TYPE + type.getKey());
|
||||
|
||||
if (type == AnnounceType.IMAGE)
|
||||
this.checkArgs(3, Lang.component("command-announce-usage-image"));
|
||||
else
|
||||
this.checkArgs(2, Lang.component("command-announce-no-type"));
|
||||
|
||||
final SerializedMap params = new SerializedMap();
|
||||
final String message = this.mapParams(type, params, this.joinArgs(1));
|
||||
|
||||
if (type != AnnounceType.IMAGE)
|
||||
this.checkBoolean(!message.isEmpty(), Lang.component("command-announce-empty"));
|
||||
|
||||
Announce.send(this.getSender(), type, message, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map chat key:value pairs parameters
|
||||
*/
|
||||
private String mapParams(final AnnounceType type, final SerializedMap map, String line) {
|
||||
final Matcher matcher = ANNOUNCE_PARAM_PATTERN.matcher(line);
|
||||
|
||||
if (type == AnnounceType.IMAGE) {
|
||||
final int height = this.findNumber(2, Lang.component("command-announce-image-lines"));
|
||||
this.checkBoolean(height >= 2 && height <= 35, Lang.component("command-announce-invalid-image-height", "min", 2, "max", 35));
|
||||
|
||||
final File imageFile = FileUtil.getFile("images/" + this.args[1]);
|
||||
this.checkBoolean(imageFile.exists(), Lang.component("command-announce-invalid-image", "file", imageFile.toPath().toString()));
|
||||
|
||||
map.put("height", height);
|
||||
map.put("imageFile", imageFile.getName());
|
||||
|
||||
line = CommonCore.joinRange(3, this.args);
|
||||
}
|
||||
|
||||
while (matcher.find()) {
|
||||
final String word = matcher.group();
|
||||
final String[] split = word.split("\\:");
|
||||
|
||||
if (split.length != 2)
|
||||
continue;
|
||||
|
||||
final String key = split[0];
|
||||
Object value = CommonCore.joinRange(1, split);
|
||||
|
||||
if (!type.isCompatible())
|
||||
continue;
|
||||
|
||||
if ("server".equals(key)) {
|
||||
// ok
|
||||
}
|
||||
|
||||
else if (type == AnnounceType.CHAT) {
|
||||
if ("type".equals(key))
|
||||
this.checkBoolean("raw".equals(value), Lang.component("command-announce-invalid-raw-type"));
|
||||
else
|
||||
this.returnTell(Lang.component("command-invalid-param-short", "param", word));
|
||||
}
|
||||
|
||||
else if (type == AnnounceType.TITLE) {
|
||||
if ("stay".equals(key) || "fadein".equals(key) || "fadeout".equals(key))
|
||||
try {
|
||||
value = Integer.parseInt(value.toString());
|
||||
|
||||
} catch (final NumberFormatException ex) {
|
||||
this.returnTell(Lang.component("command-announce-invalid-time-ticks"));
|
||||
}
|
||||
else
|
||||
this.returnTell(Lang.component("command-invalid-param-short", "param", word));
|
||||
}
|
||||
|
||||
else if (type == AnnounceType.BOSSBAR) {
|
||||
if ("time".equals(key))
|
||||
try {
|
||||
value = Integer.parseInt(value.toString());
|
||||
|
||||
} catch (final NumberFormatException ex) {
|
||||
this.returnTell(Lang.component("command-announce-invalid-time-seconds"));
|
||||
}
|
||||
else if ("color".equals(key))
|
||||
try {
|
||||
value = ReflectionUtil.lookupEnum(BossBar.Color.class, value.toString());
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-announce-invalid-key",
|
||||
"key", key,
|
||||
"value", value,
|
||||
"available", BossBar.Color.values()));
|
||||
}
|
||||
else if ("overlay".equals(key))
|
||||
try {
|
||||
value = ReflectionUtil.lookupEnum(BossBar.Overlay.class, value.toString());
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-announce-invalid-key",
|
||||
"key", key,
|
||||
"value", value,
|
||||
"available", BossBar.Overlay.values()));
|
||||
}
|
||||
else
|
||||
this.returnTell(Lang.component("command-invalid-param-short", "param", word));
|
||||
|
||||
} else if (type == AnnounceType.TOAST) {
|
||||
if ("icon".equals(key)) {
|
||||
final CompMaterial material = CompMaterial.fromString(value.toString());
|
||||
this.checkNotNull(material, Lang.component("command-invalid-material", "material", key));
|
||||
|
||||
value = material;
|
||||
|
||||
} else if ("style".equals(key))
|
||||
try {
|
||||
value = CompToastStyle.fromKey(value.toString());
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(Lang.component("command-announce-invalid-key",
|
||||
"key", key,
|
||||
"value", value,
|
||||
"available", CompToastStyle.values()));
|
||||
}
|
||||
else
|
||||
this.returnTell(Lang.component("command-invalid-param-short", "param", word));
|
||||
|
||||
} else if (type == AnnounceType.IMAGE) {
|
||||
// ok
|
||||
|
||||
} else
|
||||
this.returnTell(Lang.component("command-invalid-param-short", "param", word));
|
||||
|
||||
map.put(key, value);
|
||||
line = line.replace(word + (line.contains(word + " ") ? " " : ""), "").trim();
|
||||
}
|
||||
|
||||
return line.trim();
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a parameter by its label and automatically return on error
|
||||
*/
|
||||
private AnnounceType findParam(final String label) {
|
||||
for (final AnnounceType param : AnnounceType.values())
|
||||
if (param.getLabels().contains(label)) {
|
||||
this.checkBoolean(MinecraftVersion.atLeast(param.getMinimumVersion()), "Sending " + param.getKey() + " messages requires Minecraft " + param.getMinimumVersion() + " or greater.");
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
this.returnTell(Lang.component("command-invalid-type", "type", "announcement", "value", label, "available", AnnounceType.getAvailableParams()));
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord(AnnounceType
|
||||
.getAvailableParams()
|
||||
.stream()
|
||||
.filter(type -> this.hasPerm(Permissions.Command.ANNOUNCE_TYPE + type.getKey()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
if (this.args.length >= 2) {
|
||||
final String lastWord = this.args[this.args.length - 1];
|
||||
|
||||
AnnounceType param;
|
||||
|
||||
try {
|
||||
param = this.findParam(this.args[0]);
|
||||
|
||||
} catch (final CommandException ex) {
|
||||
// Do not send tab complete error message to player
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
|
||||
if (!param.isCompatible())
|
||||
return NO_COMPLETE;
|
||||
|
||||
if (lastWord.startsWith("server:"))
|
||||
return this.completeLastWord(SyncedCache.getServers());
|
||||
|
||||
if (param == AnnounceType.TITLE)
|
||||
return this.completeLastWord("stay:", "fadein:", "fadeout:", "server:");
|
||||
|
||||
else if (param == AnnounceType.BOSSBAR) {
|
||||
if (lastWord.startsWith("color:"))
|
||||
return this.completeLastWord(CommonCore.convertArrayToList(BossBar.Color.values(), color -> "color:" + color.toString().toLowerCase()));
|
||||
|
||||
else if (lastWord.startsWith("overlay:"))
|
||||
return this.completeLastWord(CommonCore.convertArrayToList(BossBar.Overlay.values(), color -> "overlay:" + color.toString().toLowerCase()));
|
||||
|
||||
return this.completeLastWord("time:", "color:", "overlay:", "server:");
|
||||
}
|
||||
|
||||
else if (param == AnnounceType.TOAST) {
|
||||
if (lastWord.startsWith("icon:"))
|
||||
return this.completeLastWord(CommonCore.convertArrayToList(CompMaterial.values(), mat -> "icon:" + mat.toString()));
|
||||
|
||||
else if (lastWord.startsWith("style:"))
|
||||
return this.completeLastWord(CommonCore.convertArrayToList(CompToastStyle.values(), mat -> "style:" + mat.toString()));
|
||||
|
||||
return this.completeLastWord("icon:", "style:", "server:");
|
||||
}
|
||||
|
||||
else if (param == AnnounceType.ACTIONBAR)
|
||||
return this.completeLastWord("server:");
|
||||
|
||||
else if (param == AnnounceType.IMAGE)
|
||||
if (this.args.length == 2) {
|
||||
File file = FileUtil.getFile("images/" + this.args[1]);
|
||||
String[] files = file.list();
|
||||
|
||||
if (files == null) {
|
||||
final String path = file.toPath().toString();
|
||||
final int lastDir = path.lastIndexOf('/');
|
||||
|
||||
file = new File(lastDir == -1 ? path : path.substring(0, lastDir));
|
||||
files = file.list();
|
||||
}
|
||||
|
||||
if (file != null)
|
||||
return this.completeLastWord(file.list());
|
||||
}
|
||||
|
||||
else if (this.args.length == 3)
|
||||
return this.completeLastWord("6", "10", "20", "server:");
|
||||
}
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
package org.mineacademy.chatcontrol.command.chatcontrol;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.SenderCache;
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.MainSubCommand;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.FileUtil;
|
||||
import org.mineacademy.fo.TimeUtil;
|
||||
import org.mineacademy.fo.menu.model.ItemCreator;
|
||||
import org.mineacademy.fo.model.ChatPaginator;
|
||||
import org.mineacademy.fo.model.SimpleBook;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.platform.Platform;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class BookSubCommand extends MainSubCommand {
|
||||
|
||||
public BookSubCommand() {
|
||||
super("book");
|
||||
|
||||
this.setUsage(Lang.component("command-book-usage"));
|
||||
this.setDescription(Lang.component("command-book-description"));
|
||||
this.setMinArguments(1);
|
||||
this.setPermission(Permissions.Command.BOOK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-book-usages");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#onCommand()
|
||||
*/
|
||||
@Override
|
||||
protected void onCommand() {
|
||||
|
||||
final String param = this.args[0];
|
||||
final SenderCache senderCache = SenderCache.from(this.getSender());
|
||||
|
||||
if ("new".equals(param)) {
|
||||
this.checkConsole();
|
||||
this.checkBoolean(Settings.Mail.ENABLED, Lang.component("command-book-mail-disabled"));
|
||||
|
||||
this.audience.dispatchCommand(Settings.Mail.COMMAND_ALIASES.get(0) + " new");
|
||||
this.tellSuccess(Lang.component("command-book-new"));
|
||||
}
|
||||
|
||||
else if ("save".equals(param)) {
|
||||
final SimpleBook pendingBook = senderCache.getPendingMail();
|
||||
|
||||
this.checkNotNull(pendingBook, Lang.component("command-book-save-no-book"));
|
||||
this.checkBoolean(pendingBook.isSigned(), Lang.component("command-book-save-not-signed"));
|
||||
this.checkArgs(2, Lang.component("command-book-save-no-name"));
|
||||
this.checkUsage(this.args.length == 2);
|
||||
|
||||
try {
|
||||
pendingBook.save(this.args[1]);
|
||||
senderCache.setPendingMail(null);
|
||||
|
||||
this.tellSuccess(Lang.component("command-book-save", "name", this.args[1]));
|
||||
|
||||
} catch (final IOException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
this.tellError(Lang.component("command-book-save-error", "name", this.args[1], "error", ex.toString()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if ("delete".equals(param)) {
|
||||
this.checkArgs(2, Lang.component("command-book-no-book", "available", SimpleBook.getBookNames()));
|
||||
|
||||
final String bookName = this.args[1];
|
||||
final File bookFile = FileUtil.getFile("books/" + bookName + (bookName.endsWith(".yml") ? "" : ".yml"));
|
||||
this.checkBoolean(bookFile.exists(), Lang.component("command-book-invalid", "name", bookName, "available", SimpleBook.getBookNames()));
|
||||
|
||||
final boolean success = bookFile.delete();
|
||||
|
||||
if (success)
|
||||
this.tellSuccess(Lang.component("command-book-delete", "name", bookName));
|
||||
else
|
||||
this.tellError(Lang.component("command-book-delete-fail", "name", bookName));
|
||||
}
|
||||
|
||||
else if ("open".equals(param) || "give".equals(param) || "load".equals(param)) {
|
||||
this.checkArgs(2, Lang.component("command-book-no-book", "available", SimpleBook.getBookNames()));
|
||||
|
||||
final SimpleBook book;
|
||||
|
||||
try {
|
||||
book = SimpleBook.fromFile(this.args[1]);
|
||||
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
this.returnTell(ex.getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final Player player = this.findPlayerOrSelf(this.args.length == 3 ? this.args[2] : null);
|
||||
final boolean self = player.getName().equals(this.audience.getName());
|
||||
|
||||
if ("open".equals(param)) {
|
||||
book.openColorized(Platform.toPlayer(player));
|
||||
|
||||
if (!self)
|
||||
this.tell(Lang.component("command-book-open", "player", player.getName()));
|
||||
}
|
||||
|
||||
else if ("give".equals(param)) {
|
||||
ItemCreator.fromBookColorized(book, false).give(player);
|
||||
|
||||
this.tell(Lang.component("command-book-give", "player", player.getName()));
|
||||
}
|
||||
|
||||
else if ("load".equals(param)) {
|
||||
senderCache.setPendingMail(book);
|
||||
|
||||
this.tell(Lang.component("command-book-loaded",
|
||||
"name", book.getFileName().replace(".yml", ""),
|
||||
"label", Settings.Mail.COMMAND_ALIASES.get(0)));
|
||||
}
|
||||
}
|
||||
|
||||
else if ("list".equals(param)) {
|
||||
final List<SimpleComponent> pages = new ArrayList<>();
|
||||
|
||||
for (final SimpleBook book : SimpleBook.getBooks())
|
||||
pages.add(SimpleComponent.empty()
|
||||
|
||||
.append(Lang.component("command-book-list-open"))
|
||||
.onHover(Lang.component("command-book-list-open-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " " + this.getSublabel() + " open " + book.getFileName() + " " + this.audience.getName())
|
||||
|
||||
.appendPlain(" ")
|
||||
|
||||
.append(Lang.component("command-book-list-delete"))
|
||||
.onHover(Lang.component("command-book-list-delete-tooltip"))
|
||||
.onClickRunCmd("/" + this.getLabel() + " " + this.getSublabel() + " delete " + book.getFileName())
|
||||
|
||||
.append(Lang.component("command-book-list",
|
||||
"title", book.getTitle(),
|
||||
"author", book.getAuthor(),
|
||||
"date", TimeUtil.getFormattedDateMonth(book.getLastModified())))
|
||||
.onHover(Lang.component("command-book-list-tooltip", "name", book.getFileName()))
|
||||
|
||||
);
|
||||
|
||||
this.checkBoolean(!pages.isEmpty(), Lang.component("command-book-list-none"));
|
||||
|
||||
new ChatPaginator()
|
||||
.setFoundationHeader(Lang.legacy("command-book-list-header"))
|
||||
.setPages(pages)
|
||||
.send(this.audience);
|
||||
|
||||
} else
|
||||
this.returnInvalidArgs(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
|
||||
if (this.args.length == 1)
|
||||
return this.completeLastWord("new", "save", "delete", "open", "give", "list", "load");
|
||||
|
||||
if (this.args.length >= 2 && ("save".equals(this.args[0]) || "delete".equals(this.args[0]) || "open".equals(this.args[0]) || "give".equals(this.args[0]) || "load".equals(this.args[0])))
|
||||
if (this.args.length == 2)
|
||||
return this.completeLastWord(SimpleBook.getBookNames());
|
||||
|
||||
else if (this.args.length == 3 && ("open".equals(this.args[0]) || "give".equals(this.args[0])))
|
||||
return this.completeLastWordPlayerNames();
|
||||
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package org.mineacademy.chatcontrol.command.chatcontrol;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mineacademy.chatcontrol.command.SharedChatControlCommandCore;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.annotation.AutoRegister;
|
||||
import org.mineacademy.fo.command.PermsSubCommand;
|
||||
import org.mineacademy.fo.command.SimpleCommand;
|
||||
import org.mineacademy.fo.command.SimpleCommandGroup;
|
||||
import org.mineacademy.fo.command.SimpleSubCommand;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.platform.BukkitPlugin;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Holds all /chc main commands
|
||||
*/
|
||||
@AutoRegister
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ChatControlCommands extends SimpleCommandGroup {
|
||||
|
||||
/**
|
||||
* The singleton of this class
|
||||
*/
|
||||
@Getter
|
||||
private final static SimpleCommandGroup instance = new ChatControlCommands();
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#getHeaderPrefix()
|
||||
*/
|
||||
@Override
|
||||
protected String getHeaderPrefix() {
|
||||
return "<bold><gradient:#db0000:#fb00ff>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommandGroup#registerSubcommands()
|
||||
*/
|
||||
@Override
|
||||
protected void registerSubcommands() {
|
||||
this.registerSubcommand(MainSubCommand.class);
|
||||
this.registerSubcommand(new PermsSubCommand(Permissions.class));
|
||||
this.registerDefaultSubcommands();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// Classes
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Represents the core for a bunch of other commands having same flags
|
||||
* such as -proxy -silent etc.
|
||||
*/
|
||||
public static abstract class CommandFlagged extends MainSubCommand {
|
||||
|
||||
protected CommandFlagged(final String label, final SimpleComponent usage, final SimpleComponent description) {
|
||||
super(label);
|
||||
|
||||
this.setUsage(usage);
|
||||
this.setDescription(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCommand() {
|
||||
final List<String> params = Arrays.asList(this.args);
|
||||
|
||||
final boolean console = params.contains("-console") || params.contains("-c");
|
||||
final boolean silent = params.contains("-silent") || params.contains("-s");
|
||||
final boolean anonymous = params.contains("-anonymous") || params.contains("-a");
|
||||
final boolean force = params.contains("-force") || params.contains("-f");
|
||||
|
||||
final String reason = String.join(" ", params.stream().filter(param -> param.charAt(0) != '-').collect(Collectors.toList()));
|
||||
|
||||
if (console && (silent || anonymous || force))
|
||||
this.returnTell(Lang.component("command-clear-no-arguments-while-console"));
|
||||
|
||||
if (!console && !silent && !anonymous && !force && !params.isEmpty() && reason.isEmpty())
|
||||
this.returnInvalidArgs(this.joinArgs(1));
|
||||
|
||||
if (silent && !reason.isEmpty())
|
||||
this.returnTell(Lang.component("command-no-reason-while-silent"));
|
||||
|
||||
if (silent && anonymous)
|
||||
this.returnTell(Lang.component("command-no-silent-and-anonymous"));
|
||||
|
||||
this.execute(console, anonymous, silent, force, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this command
|
||||
*
|
||||
* @param console
|
||||
* @param anonymous
|
||||
* @param silent
|
||||
* @param forced
|
||||
*
|
||||
* @param reason
|
||||
*/
|
||||
protected abstract void execute(boolean console, boolean anonymous, boolean silent, boolean forced, String reason);
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#tabComplete()
|
||||
*/
|
||||
@Override
|
||||
protected List<String> tabComplete() {
|
||||
return NO_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the foundation for plugin commands
|
||||
*/
|
||||
public static abstract class ChatControlCommand extends SimpleCommand implements SharedChatControlCommandCore {
|
||||
|
||||
protected ChatControlCommand(final String label) {
|
||||
super(label);
|
||||
}
|
||||
|
||||
protected ChatControlCommand(final List<String> labels) {
|
||||
super(labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#completeLastWordPlayerNames()
|
||||
*/
|
||||
@Override
|
||||
protected final List<String> completeLastWordPlayerNames() {
|
||||
return CommonCore.tabComplete(this.getLastArg(), Players.getPlayerNamesForTabComplete(this.getSender()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#findPlayerInternal(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public final Player findPlayerInternal(final String name) {
|
||||
return Players.findPlayer(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the foundation for plugin commands
|
||||
* used for /channel and /chc subcommands
|
||||
*/
|
||||
public static abstract class MainSubCommand extends GenericSubCommand {
|
||||
|
||||
protected MainSubCommand(final String sublabel) {
|
||||
super(BukkitPlugin.getInstance().getDefaultCommandGroup(), sublabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the foundation for plugin commands
|
||||
* used for /channel and /chc subcommands
|
||||
*/
|
||||
public static abstract class GenericSubCommand extends SimpleSubCommand implements SharedChatControlCommandCore {
|
||||
|
||||
protected GenericSubCommand(final SimpleCommandGroup group, final String sublabel) {
|
||||
super(group, sublabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#completeLastWordPlayerNames()
|
||||
*/
|
||||
@Override
|
||||
protected final List<String> completeLastWordPlayerNames() {
|
||||
return CommonCore.tabComplete(this.getLastArg(), Players.getPlayerNamesForTabComplete(this.getSender()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#findPlayerInternal(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public final Player findPlayerInternal(final String name) {
|
||||
return Players.findPlayer(name);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.mineacademy.chatcontrol.command.chatcontrol;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mineacademy.chatcontrol.command.chatcontrol.ChatControlCommands.CommandFlagged;
|
||||
import org.mineacademy.chatcontrol.model.ChatControlProxyMessage;
|
||||
import org.mineacademy.chatcontrol.model.Permissions;
|
||||
import org.mineacademy.chatcontrol.model.Players;
|
||||
import org.mineacademy.chatcontrol.settings.Settings;
|
||||
import org.mineacademy.fo.CommonCore;
|
||||
import org.mineacademy.fo.Messenger;
|
||||
import org.mineacademy.fo.ProxyUtil;
|
||||
import org.mineacademy.fo.model.SimpleComponent;
|
||||
import org.mineacademy.fo.model.Variables;
|
||||
import org.mineacademy.fo.settings.Lang;
|
||||
|
||||
public final class ClearSubCommand extends CommandFlagged {
|
||||
|
||||
public ClearSubCommand() {
|
||||
super("clear/cl", Lang.component("command-clear-usage"), Lang.component("command-clear-description"));
|
||||
|
||||
this.setPermission(Permissions.Command.CLEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.mineacademy.fo.command.SimpleCommand#getMultilineUsageMessage()
|
||||
*/
|
||||
@Override
|
||||
protected SimpleComponent getMultilineUsage() {
|
||||
return Lang.component("command-clear-usages");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(final boolean console, final boolean anonymous, final boolean silent, final boolean force, final String reason) {
|
||||
|
||||
// Compile message
|
||||
final SimpleComponent announceMessage;
|
||||
|
||||
if (silent)
|
||||
announceMessage = SimpleComponent.empty();
|
||||
else {
|
||||
announceMessage = Lang.component(
|
||||
"command-clear-success" + (Settings.Proxy.ENABLED ? "-network" : "") + (anonymous ? "-anonymous" : "") + (reason.isEmpty() ? "-no-reason" : ""),
|
||||
"player", this.audience.getName(),
|
||||
"reason", reason);
|
||||
}
|
||||
|
||||
// Do the actual clear
|
||||
if (console)
|
||||
for (int i = 0; i < 5000; i++)
|
||||
System.out.println(" ");
|
||||
else
|
||||
Players.clearChat(this.getSender(), announceMessage.isEmpty(), force);
|
||||
|
||||
if (console) {
|
||||
this.checkPerm(Permissions.Command.CLEAR_CONSOLE);
|
||||
final SimpleComponent message = Lang.component("command-clear-success-console" + (reason.isEmpty() ? "-no-reason" : ""),
|
||||
"reason", reason,
|
||||