Merge pull request #1477 from AuthMe/1035-handle-alt-accounts-in-commandsYml

1035 handle alt accounts in commands yml
This commit is contained in:
ljacqu
2018-01-17 21:49:29 +01:00
committed by GitHub
15 changed files with 213 additions and 320 deletions
@@ -107,9 +107,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// Login is now finished; we can force all commands
if (isFirstLogin) {
commandManager.runCommandsOnFirstLogin(player);
commandManager.runCommandsOnFirstLogin(player, authsWithSameIp);
}
commandManager.runCommandsOnLogin(player);
commandManager.runCommandsOnLogin(player, authsWithSameIp);
// Send Bungee stuff. The service will check if it is enabled or not.
bungeeSender.connectPlayerOnLogin(player);
@@ -2,7 +2,6 @@ package fr.xephi.authme.settings;
import ch.jalu.configme.migration.PlainMigrationService;
import ch.jalu.configme.properties.Property;
import ch.jalu.configme.properties.StringListProperty;
import ch.jalu.configme.resource.PropertyResource;
import com.google.common.base.MoreObjects;
import fr.xephi.authme.ConsoleLogger;
@@ -19,7 +18,6 @@ import javax.inject.Inject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -39,15 +37,6 @@ public class SettingsMigrationService extends PlainMigrationService {
private final File pluginFolder;
// Stores old commands that need to be migrated to the new commands configuration
// We need to store it in here for retrieval when we build the CommandConfig. Retrieving it from the config.yml is
// not possible since this migration service may trigger config.yml to be resaved. As the old command settings
// don't exist in the code anymore, as soon as config.yml is resaved we lose this information.
private List<String> onLoginCommands = Collections.emptyList();
private List<String> onLoginConsoleCommands = Collections.emptyList();
private List<String> onRegisterCommands = Collections.emptyList();
private List<String> onRegisterConsoleCommands = Collections.emptyList();
@Inject
SettingsMigrationService(@DataFolder File pluginFolder) {
this.pluginFolder = pluginFolder;
@@ -62,8 +51,6 @@ public class SettingsMigrationService extends PlainMigrationService {
changes = true;
}
gatherOldCommandSettings(resource);
// Note ljacqu 20160211: Concatenating migration methods with | instead of the usual ||
// ensures that all migrations will be performed
return changes
@@ -97,35 +84,6 @@ public class SettingsMigrationService extends PlainMigrationService {
return false;
}
// ----------------
// Forced commands relocation (from config.yml to commands.yml)
// ----------------
private void gatherOldCommandSettings(PropertyResource resource) {
onLoginCommands = getStringList(resource, "settings.forceCommands");
onLoginConsoleCommands = getStringList(resource, "settings.forceCommandsAsConsole");
onRegisterCommands = getStringList(resource, "settings.forceRegisterCommands");
onRegisterConsoleCommands = getStringList(resource, "settings.forceRegisterCommandsAsConsole");
}
private List<String> getStringList(PropertyResource resource, String path) {
return new StringListProperty(path).getValue(resource);
}
public List<String> getOnLoginCommands() {
return onLoginCommands;
}
public List<String> getOnLoginConsoleCommands() {
return onLoginConsoleCommands;
}
public List<String> getOnRegisterCommands() {
return onRegisterCommands;
}
public List<String> getOnRegisterConsoleCommands() {
return onRegisterConsoleCommands;
}
// --------
// Specific migrations
@@ -11,9 +11,9 @@ import java.util.Map;
public class CommandConfig {
private Map<String, Command> onJoin = new LinkedHashMap<>();
private Map<String, Command> onLogin = new LinkedHashMap<>();
private Map<String, OnLoginCommand> onLogin = new LinkedHashMap<>();
private Map<String, Command> onSessionLogin = new LinkedHashMap<>();
private Map<String, Command> onFirstLogin = new LinkedHashMap<>();
private Map<String, OnLoginCommand> onFirstLogin = new LinkedHashMap<>();
private Map<String, Command> onRegister = new LinkedHashMap<>();
private Map<String, Command> onUnregister = new LinkedHashMap<>();
private Map<String, Command> onLogout = new LinkedHashMap<>();
@@ -26,11 +26,11 @@ public class CommandConfig {
this.onJoin = onJoin;
}
public Map<String, Command> getOnLogin() {
public Map<String, OnLoginCommand> getOnLogin() {
return onLogin;
}
public void setOnLogin(Map<String, Command> onLogin) {
public void setOnLogin(Map<String, OnLoginCommand> onLogin) {
this.onLogin = onLogin;
}
@@ -42,11 +42,11 @@ public class CommandConfig {
this.onSessionLogin = onSessionLogin;
}
public Map<String, Command> getOnFirstLogin() {
public Map<String, OnLoginCommand> getOnFirstLogin() {
return onFirstLogin;
}
public void setOnFirstLogin(Map<String, Command> onFirstLogin) {
public void setOnFirstLogin(Map<String, OnLoginCommand> onFirstLogin) {
this.onFirstLogin = onFirstLogin;
}
@@ -17,6 +17,7 @@ import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
@@ -32,9 +33,9 @@ public class CommandManager implements Reloadable {
private final List<Tag<Player>> availableTags = buildAvailableTags();
private WrappedTagReplacer<Command, Player> onJoinCommands;
private WrappedTagReplacer<Command, Player> onLoginCommands;
private WrappedTagReplacer<OnLoginCommand, Player> onLoginCommands;
private WrappedTagReplacer<Command, Player> onSessionLoginCommands;
private WrappedTagReplacer<Command, Player> onFirstLoginCommands;
private WrappedTagReplacer<OnLoginCommand, Player> onFirstLoginCommands;
private WrappedTagReplacer<Command, Player> onRegisterCommands;
private WrappedTagReplacer<Command, Player> onUnregisterCommands;
private WrappedTagReplacer<Command, Player> onLogoutCommands;
@@ -71,9 +72,12 @@ public class CommandManager implements Reloadable {
* Runs the configured commands for when a player has logged in successfully.
*
* @param player the player that logged in
* @param otherAccounts account names whose IP is the same as the player's
*/
public void runCommandsOnLogin(Player player) {
executeCommands(player, onLoginCommands.getAdaptedItems(player));
public void runCommandsOnLogin(Player player, List<String> otherAccounts) {
final int numberOfOtherAccounts = otherAccounts.size();
executeCommands(player, onLoginCommands.getAdaptedItems(player),
cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts));
}
/**
@@ -89,9 +93,12 @@ public class CommandManager implements Reloadable {
* Runs the configured commands for when a player logs in the first time.
*
* @param player the player that has logged in for the first time
* @param otherAccounts account names whose IP is the same as the player's
*/
public void runCommandsOnFirstLogin(Player player) {
executeCommands(player, onFirstLoginCommands.getAdaptedItems(player));
public void runCommandsOnFirstLogin(Player player, List<String> otherAccounts) {
final int numberOfOtherAccounts = otherAccounts.size();
executeCommands(player, onFirstLoginCommands.getAdaptedItems(player),
cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts));
}
/**
@@ -113,16 +120,29 @@ public class CommandManager implements Reloadable {
}
private void executeCommands(Player player, List<Command> commands) {
for (Command command : commands) {
final String execution = command.getCommand();
if (Executor.CONSOLE.equals(command.getExecutor())) {
bukkitService.dispatchConsoleCommand(execution);
} else {
bukkitService.dispatchCommand(player, execution);
executeCommands(player, commands, c -> true);
}
private <T extends Command> void executeCommands(Player player, List<T> commands, Predicate<T> predicate) {
for (T command : commands) {
if (predicate.test(command)) {
final String execution = command.getCommand();
if (Executor.CONSOLE.equals(command.getExecutor())) {
bukkitService.dispatchConsoleCommand(execution);
} else {
bukkitService.dispatchCommand(player, execution);
}
}
}
}
private static boolean shouldCommandBeRun(OnLoginCommand command, int numberOfOtherAccounts) {
return (!command.getIfNumberOfAccountsAtLeast().isPresent()
|| command.getIfNumberOfAccountsAtLeast().get() <= numberOfOtherAccounts)
&& (!command.getIfNumberOfAccountsLessThan().isPresent()
|| command.getIfNumberOfAccountsLessThan().get() > numberOfOtherAccounts);
}
@Override
public void reload() {
File file = new File(dataFolder, "commands.yml");
@@ -132,8 +152,8 @@ public class CommandManager implements Reloadable {
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
onJoinCommands = newReplacer(commandConfig.getOnJoin());
onLoginCommands = newReplacer(commandConfig.getOnLogin());
onFirstLoginCommands = newReplacer(commandConfig.getOnFirstLogin());
onLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnLogin());
onFirstLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnFirstLogin());
onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin());
onRegisterCommands = newReplacer(commandConfig.getOnRegister());
onUnregisterCommands = newReplacer(commandConfig.getOnUnregister());
@@ -145,6 +165,14 @@ public class CommandManager implements Reloadable {
(cmd, text) -> new Command(text, cmd.getExecutor()));
}
private WrappedTagReplacer<OnLoginCommand, Player> newOnLoginCmdReplacer(
Map<String, OnLoginCommand> commands) {
return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand,
(cmd, text) -> new OnLoginCommand(text, cmd.getExecutor(), cmd.getIfNumberOfAccountsAtLeast(),
cmd.getIfNumberOfAccountsLessThan()));
}
private List<Tag<Player>> buildAvailableTags() {
return Arrays.asList(
createTag("%p", pl -> pl.getName()),
@@ -5,15 +5,8 @@ import ch.jalu.configme.properties.Property;
import ch.jalu.configme.resource.PropertyResource;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.SettingsMigrationService;
import fr.xephi.authme.util.RandomStringUtils;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Migrates the commands from their old location, in config.yml, to the dedicated commands configuration file.
@@ -25,108 +18,20 @@ class CommandMigrationService implements MigrationService {
static final List<String> COMMAND_CONFIG_PROPERTIES = ImmutableList.of(
"onJoin", "onLogin", "onSessionLogin", "onFirstLogin", "onRegister", "onUnregister", "onLogout");
@Inject
private SettingsMigrationService settingsMigrationService;
CommandMigrationService() {
}
@Override
public boolean checkAndMigrate(PropertyResource resource, List<Property<?>> properties) {
final CommandConfig commandConfig = CommandSettingsHolder.COMMANDS.getValue(resource);
final boolean didMoveCommands = transformOldCommands(commandConfig);
if (didMoveCommands || isFileEmpty(resource)) {
if (isFileEmpty(resource)) {
resource.setValue("", commandConfig);
return true;
}
return false;
}
private boolean isFileEmpty(PropertyResource resource) {
private static boolean isFileEmpty(PropertyResource resource) {
return COMMAND_CONFIG_PROPERTIES.stream().anyMatch(property -> resource.getObject(property) == null);
}
/**
* Adds command settings from their old location (in config.yml) to the given command configuration object.
*
* @param commandConfig the command config object to move old commands to
* @return true if commands have been moved, false if no migration was necessary
*/
@VisibleForTesting
boolean transformOldCommands(CommandConfig commandConfig) {
boolean didMoveCommands = false;
for (MigratableCommandSection section : MigratableCommandSection.values()) {
didMoveCommands |= section.convertCommands(settingsMigrationService, commandConfig);
}
return didMoveCommands;
}
/**
* Enum defining the forced command settings that should be moved from config.yml to the new commands.yml file.
*/
private enum MigratableCommandSection {
ON_JOIN(
SettingsMigrationService::getOnLoginCommands,
Executor.PLAYER,
CommandConfig::getOnLogin),
ON_JOIN_CONSOLE(
SettingsMigrationService::getOnLoginConsoleCommands,
Executor.CONSOLE,
CommandConfig::getOnLogin),
ON_REGISTER(
SettingsMigrationService::getOnRegisterCommands,
Executor.PLAYER,
CommandConfig::getOnRegister),
ON_REGISTER_CONSOLE(
SettingsMigrationService::getOnRegisterConsoleCommands,
Executor.CONSOLE,
CommandConfig::getOnRegister);
private final Function<SettingsMigrationService, List<String>> legacyCommandsGetter;
private final Executor executor;
private final Function<CommandConfig, Map<String, Command>> commandMapGetter;
/**
* Constructor.
*
* @param legacyCommandsGetter getter on MigrationService to get the deprecated command entries
* @param executor the executor of the commands
* @param commandMapGetter the getter for the commands map in the new settings structure to add the old
* settings to after conversion
*/
MigratableCommandSection(Function<SettingsMigrationService, List<String>> legacyCommandsGetter,
Executor executor,
Function<CommandConfig, Map<String, Command>> commandMapGetter) {
this.legacyCommandsGetter = legacyCommandsGetter;
this.executor = executor;
this.commandMapGetter = commandMapGetter;
}
/**
* Adds the commands from the sections' settings migration service to the appropriate place in the new
* command config object.
*
* @param settingsMigrationService settings migration service to read old commands from
* @param commandConfig command config object to add converted commands to
* @return true if there were commands to migrate, false otherwise
*/
boolean convertCommands(SettingsMigrationService settingsMigrationService, CommandConfig commandConfig) {
List<Command> commands = legacyCommandsGetter.apply(settingsMigrationService).stream()
.map(cmd -> new Command(cmd, executor)).collect(Collectors.toList());
if (commands.isEmpty()) {
return false;
}
Map<String, Command> commandMap = commandMapGetter.apply(commandConfig);
commands.forEach(cmd -> commandMap.put(RandomStringUtils.generate(10), cmd));
ConsoleLogger.info("Moving " + commands.size() + " commands of type " + this
+ " from config.yml to commands.yml");
return true;
}
}
}
@@ -49,8 +49,17 @@ public final class CommandSettingsHolder implements SettingsHolder {
" executor: CONSOLE",
"",
"Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, "
+ "onUnregister"
+ "onUnregister",
"",
"For onLogin and onFirstLogin, you can use 'ifNumberOfAccountsLessThan' and 'ifNumberOfAccountsAtLeast'",
"to specify limits to how many accounts a player can have (matched by IP) for a command to be run:",
"onLogin:",
" warnOnManyAccounts:",
" command: 'say Uh oh! %p has many alt accounts!'",
" executor: CONSOLE",
" ifNumberOfAccountsAtLeast: 5"
};
Map<String, String[]> commentMap = new HashMap<>();
commentMap.put("", rootComments);
commentMap.put("onFirstLogin", new String[]{
@@ -0,0 +1,59 @@
package fr.xephi.authme.settings.commandconfig;
import java.util.Optional;
/**
* Configurable command for when a player logs in.
*/
public class OnLoginCommand extends Command {
private Optional<Integer> ifNumberOfAccountsAtLeast;
private Optional<Integer> ifNumberOfAccountsLessThan;
/**
* Default constructor (for bean mapping).
*/
public OnLoginCommand() {
}
/**
* Constructor.
*
* @param command the command to execute
* @param executor the executor of the command
*/
public OnLoginCommand(String command, Executor executor) {
super(command, executor);
}
/**
* Constructor.
*
* @param command the command to execute
* @param executor the executor of the command
* @param ifNumberOfAccountsAtLeast required number of accounts for the command to run
* @param ifNumberOfAccountsLessThan max threshold of accounts, from which the command will not be run
*/
public OnLoginCommand(String command, Executor executor, Optional<Integer> ifNumberOfAccountsAtLeast,
Optional<Integer> ifNumberOfAccountsLessThan) {
super(command, executor);
this.ifNumberOfAccountsAtLeast = ifNumberOfAccountsAtLeast;
this.ifNumberOfAccountsLessThan = ifNumberOfAccountsLessThan;
}
public Optional<Integer> getIfNumberOfAccountsAtLeast() {
return ifNumberOfAccountsAtLeast;
}
public void setIfNumberOfAccountsAtLeast(Optional<Integer> ifNumberOfAccountsAtLeast) {
this.ifNumberOfAccountsAtLeast = ifNumberOfAccountsAtLeast;
}
public Optional<Integer> getIfNumberOfAccountsLessThan() {
return ifNumberOfAccountsLessThan;
}
public void setIfNumberOfAccountsLessThan(Optional<Integer> ifNumberOfAccountsLessThan) {
this.ifNumberOfAccountsLessThan = ifNumberOfAccountsLessThan;
}
}
+8
View File
@@ -25,6 +25,14 @@
# executor: CONSOLE
#
# Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, onUnregister
#
# For onLogin and onFirstLogin, you can use 'ifNumberOfAccountsLessThan' and 'ifNumberOfAccountsAtLeast'
# to specify limits to how many accounts a player can have (matched by IP) for a command to be run:
# onLogin:
# warnOnManyAccounts:
# command: 'say Uh oh! %p has many alt accounts!'
# executor: CONSOLE
# ifNumberOfAccountsAtLeast: 5
# Commands to run for players logging in whose 'last login date' was empty
onFirstLogin: {}
onJoin: {}