diff --git a/.gitignore b/.gitignore index cc11a1f..e5edd52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ bin/ -.classpath -.project -.settings +build/ +out/ +.gradle/ +.idea +*.iml diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..941fced --- /dev/null +++ b/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'java' + id 'com.github.johnrengelman.shadow' version '7.0.0' +} + +sourceCompatibility = JavaVersion.VERSION_18 +targetCompatibility = JavaVersion.VERSION_18 + +group = project.pacfirstplayed_group +archivesBaseName = project.pacfirstplayed_name +version = project.pacfirstplayed_version + +repositories { + // Paper + maven { url "https://papermc.io/repo/repository/maven-public/" } +} + +configurations { + include + include.canBeResolved = true + compileOnly.extendsFrom(include) +} + +dependencies { + compileOnly "io.papermc.paper:paper-api:${paper_version}" +} + +build { + dependsOn(shadowJar) +} + +shadowJar { + configurations = [project.configurations.include] +} + +tasks.withType(JavaCompile).configureEach { + it.options.encoding = "UTF-8" + it.options.release = 18 +} + +processResources { + filesMatching('plugin.yml') { + expand( + version: version + ) + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..dbee75f --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +pacfirstplayed_group = fr.peaceandcube +pacfirstplayed_name = pacfirstplayed +pacfirstplayed_version = 1.3.0 + +paper_version = 1.19.4-R0.1-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..41d9927 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..fae0804 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..0f82d16 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'PACFirstPlayed' + diff --git a/src/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java b/src/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java deleted file mode 100644 index 45d5ee2..0000000 --- a/src/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.peaceandcube.pacfirstplayed; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitTask; - -import fr.peaceandcube.pacfirstplayed.command.FirstPlayedCommand; -import fr.peaceandcube.pacfirstplayed.command.FpDateCommand; - -public class PACFirstPlayed extends JavaPlugin { - public FileConfiguration config = getConfig(); - - @Override - public void onEnable() { - this.getCommand("firstplayed").setExecutor(new FirstPlayedCommand()); - this.getCommand("fpdate").setExecutor(new FpDateCommand()); - - saveDefaultConfig(); - reloadConfig(); -} - - @Override - public void onDisable() { - - } - - public BukkitTask runTaskAsynchronously(final Runnable run) { - return this.getServer().getScheduler().runTaskAsynchronously(this, run); - } -} diff --git a/src/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java b/src/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java deleted file mode 100644 index 6ee00e4..0000000 --- a/src/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.peaceandcube.pacfirstplayed.command; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.Player; - -import fr.peaceandcube.pacpi.player.PlayerErrors; -import fr.peaceandcube.pacpi.player.PlayerSuggestionProviders; - -public class FirstPlayedCommand implements CommandExecutor, TabExecutor { - public Player player; - public FileConfiguration config = Bukkit.getPluginManager().getPlugin("PACFirstPlayed").getConfig(); - public String date_format = config.getString("date_format"); - public String message_me = config.getString("message_me"); - public String message_other = config.getString("message_other"); - public boolean offline_players = config.getBoolean("offline_players"); - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (args.length == 0 && sender instanceof Player) { - if (!sender.hasPermission("firstplayed.me")) return false; - player = (Player) sender; - sendOwnDate(sender, player); - return true; - } else if (args.length == 1) { - if (!sender.hasPermission("firstplayed.other")) return false; - String target = args[0]; - if (Bukkit.getOnlinePlayers().contains(Bukkit.getPlayer(target))) { - sendOtherDate(sender, Bukkit.getPlayer(target)); - return true; - } else if (offline_players) { - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(target); - if (offlinePlayer.hasPlayedBefore()) { - sendOtherDate(sender, Bukkit.getOfflinePlayer(target)); - return true; - } - } - sender.sendMessage(PlayerErrors.PLAYER_NOT_FOUND); - return true; - } - return false; - } - - public void sendOwnDate(CommandSender sender, OfflinePlayer target) { - long timestamp = target.getFirstPlayed(); - String date = new SimpleDateFormat(date_format).format(new Date(timestamp)); - sender.sendMessage(String.format(ChatColor.LIGHT_PURPLE + message_me, date)); - } - - public void sendOtherDate(CommandSender sender, OfflinePlayer target) { - long timestamp = target.getFirstPlayed(); - String date = new SimpleDateFormat(date_format).format(new Date(timestamp)); - sender.sendMessage(String.format(ChatColor.LIGHT_PURPLE + message_other, target.getName(), date)); - } - - @Override - public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - if (args.length == 1 && sender.hasPermission("firstplayed.other")) { - return PlayerSuggestionProviders.getOnlinePlayers(args[0]); - } - - return new ArrayList<>(); - } -} diff --git a/src/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java b/src/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java deleted file mode 100644 index a1abe68..0000000 --- a/src/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java +++ /dev/null @@ -1,69 +0,0 @@ -package fr.peaceandcube.pacfirstplayed.command; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.configuration.file.FileConfiguration; - -import com.google.common.collect.ImmutableList; - -import fr.peaceandcube.pacfirstplayed.PACFirstPlayed; -import fr.peaceandcube.pacpi.date.DateUtils; - -public class FpDateCommand implements CommandExecutor, TabExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (args.length == 1 && sender.hasPermission("firstplayed.date")) { - - PACFirstPlayed.getPlugin(PACFirstPlayed.class).runTaskAsynchronously(new Runnable() { - final FileConfiguration config = Bukkit.getPluginManager().getPlugin("PACFirstPlayed").getConfig(); - final String playersOnDate = config.getString("players_on_date"); - final String noneOnDate = config.getString("none_on_date"); - - @Override - public void run() { - String playerNames = ""; - int playerCount = 0; - - for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { - long timestamp = player.getFirstPlayed(); - String joinDate = new SimpleDateFormat("dd-MM-yyyy").format(new Date(timestamp)); - - if (joinDate.equals(args[0])) { - playerNames += ChatColor.YELLOW + player.getName() + " "; - playerCount++; - } - } - - if (!playerNames.isEmpty()) { - sender.sendMessage(String.format(ChatColor.LIGHT_PURPLE + this.playersOnDate, playerCount, playerNames)); - } else { - sender.sendMessage(ChatColor.RED + this.noneOnDate); - } - } - }); - - return true; - } - - return false; - } - - @Override - public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - if (args.length == 1) { - return ImmutableList.of(DateUtils.getCurrentYearDay()); - } - return new ArrayList<>(); - } -} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java b/src/main/java/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java new file mode 100644 index 0000000..2caf859 --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/PACFirstPlayed.java @@ -0,0 +1,38 @@ +package fr.peaceandcube.pacfirstplayed; + +import fr.peaceandcube.pacfirstplayed.command.FirstPlayedCommand; +import fr.peaceandcube.pacfirstplayed.command.FpDateCommand; +import fr.peaceandcube.pacfirstplayed.command.PACFirstPlayedCommand; +import fr.peaceandcube.pacfirstplayed.util.Config; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +public class PACFirstPlayed extends JavaPlugin { + public static FileConfiguration config; + + @Override + public void onEnable() { + config = this.getConfig(); + + this.getCommand("firstplayed").setExecutor(new FirstPlayedCommand()); + this.getCommand("fpdate").setExecutor(new FpDateCommand()); + this.getCommand("pacfirstplayed").setExecutor(new PACFirstPlayedCommand()); + + saveDefaultConfig(); + reloadConfig(); + } + + public void runTaskAsynchronously(final Runnable run) { + this.getServer().getScheduler().runTaskAsynchronously(this, run); + } + + public static void reload() { + PACFirstPlayed instance = PACFirstPlayed.getPlugin(PACFirstPlayed.class); + instance.reloadConfig(); + instance.saveDefaultConfig(); + config = instance.getConfig(); + config.options().copyDefaults(true); + instance.saveConfig(); + Config.reload(); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java b/src/main/java/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java new file mode 100644 index 0000000..c369fce --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/command/FirstPlayedCommand.java @@ -0,0 +1,76 @@ +package fr.peaceandcube.pacfirstplayed.command; + +import fr.peaceandcube.pacfirstplayed.util.Config; +import fr.peaceandcube.pacfirstplayed.util.PlayerMessages; +import fr.peaceandcube.pacfirstplayed.util.SuggestionProviders; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +public class FirstPlayedCommand implements CommandExecutor, TabExecutor { + private static final String PERM_FIRSTPLAYED_ME = "peaceandcube.firstplayed.me"; + private static final String PERM_FIRSTPLAYED_OTHER = "peaceandcube.firstplayed.other"; + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 0 && sender instanceof Player player) { + if (sender.hasPermission(PERM_FIRSTPLAYED_ME)) { + sendOwnDate(sender, player); + return true; + } + } else if (args.length == 1) { + if (sender.hasPermission(PERM_FIRSTPLAYED_OTHER)) { + String target = args[0]; + if (Bukkit.getPlayer(target) != null && Bukkit.getOnlinePlayers().contains(Bukkit.getPlayer(target))) { + sendOtherDate(sender, Bukkit.getPlayer(target)); + return true; + } else if (Config.offline_players) { + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(target); + if (offlinePlayer.hasPlayedBefore()) { + sendOtherDate(sender, Bukkit.getOfflinePlayer(target)); + return true; + } + } + sender.sendMessage(PlayerMessages.PLAYER_NOT_FOUND); + return true; + } + } + return false; + } + + public void sendOwnDate(CommandSender sender, OfflinePlayer target) { + long timestamp = target.getFirstPlayed(); + String date = new SimpleDateFormat(Config.date_format).format(new Date(timestamp)); + String message = String.format(Config.message_me, date); + sender.sendMessage(Component.text(message, TextColor.color(0xFF55FF))); + } + + public void sendOtherDate(CommandSender sender, OfflinePlayer target) { + long timestamp = target.getFirstPlayed(); + String date = new SimpleDateFormat(Config.date_format).format(new Date(timestamp)); + String message = String.format(Config.message_other, target.getName(), date); + sender.sendMessage(Component.text(message, TextColor.color(0xFF55FF))); + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (sender.hasPermission(PERM_FIRSTPLAYED_OTHER)) { + if (args.length == 1) { + return SuggestionProviders.getOnlinePlayers(args[0]); + } + } + return List.of(); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java b/src/main/java/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java new file mode 100644 index 0000000..fea0e7b --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/command/FpDateCommand.java @@ -0,0 +1,75 @@ +package fr.peaceandcube.pacfirstplayed.command; + +import fr.peaceandcube.pacfirstplayed.PACFirstPlayed; +import fr.peaceandcube.pacfirstplayed.util.Config; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +public class FpDateCommand implements CommandExecutor, TabExecutor { + private static final String PERM_FPDATE = "peaceandcube.fpdate"; + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender.hasPermission(PERM_FPDATE)) { + if (args.length == 1) { + + PACFirstPlayed.getPlugin(PACFirstPlayed.class).runTaskAsynchronously(new Runnable() { + + @Override + public void run() { + StringBuilder playerNames = new StringBuilder(); + int playerCount = 0; + + for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { + long timestamp = player.getFirstPlayed(); + String joinDate = new SimpleDateFormat("dd-MM-yyyy").format(new Date(timestamp)); + + if (joinDate.equals(args[0])) { + playerNames.append(player.getName()).append(" "); + playerCount++; + } + } + + if (playerNames.length() > 0) { + String message = String.format(Config.playersOnDate, playerCount, playerNames); + sender.sendMessage(Component.text(message, TextColor.color(0xFFFF55))); + } else { + sender.sendMessage(Component.text(Config.noneOnDate, TextColor.color(0xFF5555))); + } + } + }); + + return true; + } + } + return false; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (sender.hasPermission(PERM_FPDATE)) { + if (args.length == 1) { + return List.of(getCurrentYearDay()); + } + } + return List.of(); + } + + public static String getCurrentYearDay() { + Date date = new Date(); + SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); + return format.format(date); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/command/PACFirstPlayedCommand.java b/src/main/java/fr/peaceandcube/pacfirstplayed/command/PACFirstPlayedCommand.java new file mode 100644 index 0000000..ebb6e69 --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/command/PACFirstPlayedCommand.java @@ -0,0 +1,44 @@ +package fr.peaceandcube.pacfirstplayed.command; + +import fr.peaceandcube.pacfirstplayed.PACFirstPlayed; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.stream.Stream; + +public class PACFirstPlayedCommand implements CommandExecutor, TabExecutor { + private static final String PERM_PACFIRSTPLAYED = "peaceandcube.pacfirstplayed"; + private static final TextComponent RELOAD_SUCCESS = Component.text("PACFirstPlayed a été rechargé avec succès", TextColor.color(0x55FF55)); + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender.hasPermission(PERM_PACFIRSTPLAYED)) { + if (args.length == 1) { + if (args[0].equals("reload")) { + PACFirstPlayed.reload(); + sender.sendMessage(RELOAD_SUCCESS); + return true; + } + } + } + return false; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (sender.hasPermission(PERM_PACFIRSTPLAYED)) { + if (args.length == 1) { + return Stream.of("reload").filter(s -> s.startsWith(args[0])).toList(); + } + } + return List.of(); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/util/Config.java b/src/main/java/fr/peaceandcube/pacfirstplayed/util/Config.java new file mode 100644 index 0000000..1169dc0 --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/util/Config.java @@ -0,0 +1,21 @@ +package fr.peaceandcube.pacfirstplayed.util; + +import fr.peaceandcube.pacfirstplayed.PACFirstPlayed; + +public class Config { + public static String date_format = PACFirstPlayed.config.getString("date_format"); + public static String message_me = PACFirstPlayed.config.getString("message_me"); + public static String message_other = PACFirstPlayed.config.getString("message_other"); + public static String playersOnDate = PACFirstPlayed.config.getString("players_on_date"); + public static String noneOnDate = PACFirstPlayed.config.getString("none_on_date"); + public static boolean offline_players = PACFirstPlayed.config.getBoolean("offline_players"); + + public static void reload() { + date_format = PACFirstPlayed.config.getString("date_format"); + message_me = PACFirstPlayed.config.getString("message_me"); + message_other = PACFirstPlayed.config.getString("message_other"); + playersOnDate = PACFirstPlayed.config.getString("players_on_date"); + noneOnDate = PACFirstPlayed.config.getString("none_on_date"); + offline_players = PACFirstPlayed.config.getBoolean("offline_players"); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/util/PlayerMessages.java b/src/main/java/fr/peaceandcube/pacfirstplayed/util/PlayerMessages.java new file mode 100644 index 0000000..67e7fd8 --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/util/PlayerMessages.java @@ -0,0 +1,13 @@ +package fr.peaceandcube.pacfirstplayed.util; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.TextColor; + +public class PlayerMessages { + public static final TextComponent PLAYER_NOT_FOUND = error("Le joueur n'a pas été trouvé"); + + public static TextComponent error(String msg) { + return Component.text(msg, TextColor.color(0xFF5555)); + } +} diff --git a/src/main/java/fr/peaceandcube/pacfirstplayed/util/SuggestionProviders.java b/src/main/java/fr/peaceandcube/pacfirstplayed/util/SuggestionProviders.java new file mode 100644 index 0000000..763afd0 --- /dev/null +++ b/src/main/java/fr/peaceandcube/pacfirstplayed/util/SuggestionProviders.java @@ -0,0 +1,22 @@ +package fr.peaceandcube.pacfirstplayed.util; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class SuggestionProviders { + + public static List getOnlinePlayers(String prefix) { + List players = new ArrayList<>(); + + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.getName().toLowerCase().startsWith(prefix.toLowerCase())) { + players.add(player.getName()); + } + } + + return players; + } +} diff --git a/src/config.yml b/src/main/resources/config.yml similarity index 80% rename from src/config.yml rename to src/main/resources/config.yml index 829af53..cfad248 100644 --- a/src/config.yml +++ b/src/main/resources/config.yml @@ -9,8 +9,8 @@ date_format: dd/MM/yyyy HH:mm:ss message_me: "Tu as rejoint le serveur le %s" message_other: "%s a rejoint le serveur le %s" -players_on_date: "%s joueurs ont rejoint le serveur à cette date : %s" +players_on_date: "%d joueurs ont rejoint le serveur à cette date : %s" none_on_date: "Aucun joueur n'a rejoint le serveur à cette date." -# Whether or not it's possible to see the join date of offline players. +# Whether it's possible to see the join date of offline players. offline_players: true diff --git a/src/plugin.yml b/src/main/resources/plugin.yml similarity index 61% rename from src/plugin.yml rename to src/main/resources/plugin.yml index 9ad37f7..8e9a729 100644 --- a/src/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,33 +1,39 @@ main: fr.peaceandcube.pacfirstplayed.PACFirstPlayed name: PACFirstPlayed description: A plugin showing the date you joined the server -version: 1.2.1 +version: ${version} author: YanisBft website: https://github.com/PeaceAndCubeMC/PACFirstPlayed -api-version: 1.13 - -depend: [pAcPI] +api-version: 1.19 commands: firstplayed: description: Shows when you joined the server aliases: fp - permission: firstplayed.me + permission: peaceandcube.firstplayed.me permission-message: §cYou do not have the permission to use this command. usage: "§eUsage: §r/firstplayed []" fpdate: description: Shows who joined the server on a date - permission: firstplayed.date + permission: peaceandcube.fpdate permission-message: §cYou do not have the permission to use this command. usage: "§eUsage: §r/fpdate " + pacfirstplayed: + description: Reloads the plugin + permission: peaceandcube.pacfirstplayed + permission-message: §cYou do not have the permission to use this command. + usage: "§eUsage: §r/pacfirstplayed reload" permissions: - firstplayed.me: + peaceandcube.firstplayed.me: description: Allows you to get your own join date default: op - firstplayed.other: + peaceandcube.firstplayed.other: description: Allows you to get another player join date default: op - firstplayed.date: + peaceandcube.fpdate: description: Allows to see who joined the server on a date default: op + peaceandcube.pacfirstplayed: + description: Allows you to use /pacfirstplayed command + default: op