PlayTimes-OG v1.0
This commit is contained in:
1 parent
f01ec9a0d9
commit
8acf6ee912
12 files changed
+925
-1862
No files matched your search
@@ -1,982 +0,0 @@
|
||||
/*
|
||||
* This Metrics class was auto-generated and can be copied into your project if you are
|
||||
* not using a build tool like Gradle or Maven for dependency management.
|
||||
*
|
||||
* IMPORTANT: You are not allowed to modify this class, except changing the package.
|
||||
*
|
||||
* Disallowed modifications include but are not limited to:
|
||||
* - Remove the option for users to opt-out
|
||||
* - Change the frequency for data submission
|
||||
* - Obfuscate the code (every obfuscator should allow you to make an exception for specific files)
|
||||
* - Reformat the code (if you use a linter, add an exception)
|
||||
*
|
||||
* Violations will result in a ban of your plugin and account from bStats.
|
||||
*/
|
||||
package me.codedred.playtimes;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
private final MetricsBase metricsBase;
|
||||
|
||||
/**
|
||||
* Creates a new Metrics instance.
|
||||
*
|
||||
* @param plugin Your plugin instance.
|
||||
* @param serviceId The id of the service. It can be found at <a
|
||||
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(JavaPlugin plugin, int serviceId) {
|
||||
this.plugin = plugin;
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(
|
||||
plugin.getDataFolder().getParentFile(),
|
||||
"bStats"
|
||||
);
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true);
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
config.addDefault("logFailedRequests", false);
|
||||
config.addDefault("logSentData", false);
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
// Inform the server owners about bStats
|
||||
config
|
||||
.options()
|
||||
.header(
|
||||
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" +
|
||||
"many people use their plugin and their total player count. It's recommended to keep bStats\n" +
|
||||
"enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" +
|
||||
"performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" +
|
||||
"anonymous."
|
||||
)
|
||||
.copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
// Load the data
|
||||
boolean enabled = config.getBoolean("enabled", true);
|
||||
String serverUUID = config.getString("serverUuid");
|
||||
boolean logErrors = config.getBoolean("logFailedRequests", false);
|
||||
boolean logSentData = config.getBoolean("logSentData", false);
|
||||
boolean logResponseStatusText = config.getBoolean(
|
||||
"logResponseStatusText",
|
||||
false
|
||||
);
|
||||
metricsBase =
|
||||
new MetricsBase(
|
||||
"bukkit",
|
||||
serverUUID,
|
||||
serviceId,
|
||||
enabled,
|
||||
this::appendPlatformData,
|
||||
this::appendServiceData,
|
||||
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
|
||||
plugin::isEnabled,
|
||||
(message, error) ->
|
||||
this.plugin.getLogger().log(Level.WARNING, message, error),
|
||||
message -> this.plugin.getLogger().log(Level.INFO, message),
|
||||
logErrors,
|
||||
logSentData,
|
||||
logResponseStatusText
|
||||
);
|
||||
}
|
||||
|
||||
/** Shuts down the underlying scheduler service. */
|
||||
public void shutdown() {
|
||||
metricsBase.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
metricsBase.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void appendPlatformData(JsonObjectBuilder builder) {
|
||||
builder.appendField("playerAmount", getPlayerAmount());
|
||||
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
|
||||
builder.appendField("bukkitVersion", Bukkit.getVersion());
|
||||
builder.appendField("bukkitName", Bukkit.getName());
|
||||
builder.appendField("javaVersion", System.getProperty("java.version"));
|
||||
builder.appendField("osName", System.getProperty("os.name"));
|
||||
builder.appendField("osArch", System.getProperty("os.arch"));
|
||||
builder.appendField("osVersion", System.getProperty("os.version"));
|
||||
builder.appendField(
|
||||
"coreCount",
|
||||
Runtime.getRuntime().availableProcessors()
|
||||
);
|
||||
}
|
||||
|
||||
private void appendServiceData(JsonObjectBuilder builder) {
|
||||
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
|
||||
}
|
||||
|
||||
private int getPlayerAmount() {
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed from an array to a collection,
|
||||
// This fixes java.lang.NoSuchMethodError:
|
||||
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
Method onlinePlayersMethod = Class
|
||||
.forName("org.bukkit.Server")
|
||||
.getMethod("getOnlinePlayers");
|
||||
return onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? (
|
||||
(Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())
|
||||
).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception e) {
|
||||
// Just use the new method if the reflection failed
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetricsBase {
|
||||
|
||||
/** The version of the Metrics class. */
|
||||
public static final String METRICS_VERSION = "3.0.2";
|
||||
|
||||
private static final String REPORT_URL =
|
||||
"https://bStats.org/api/v2/data/%s";
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private final String platform;
|
||||
|
||||
private final String serverUuid;
|
||||
|
||||
private final int serviceId;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
|
||||
|
||||
private final Consumer<Runnable> submitTaskConsumer;
|
||||
|
||||
private final Supplier<Boolean> checkServiceEnabledSupplier;
|
||||
|
||||
private final BiConsumer<String, Throwable> errorLogger;
|
||||
|
||||
private final Consumer<String> infoLogger;
|
||||
|
||||
private final boolean logErrors;
|
||||
|
||||
private final boolean logSentData;
|
||||
|
||||
private final boolean logResponseStatusText;
|
||||
|
||||
private final Set<CustomChart> customCharts = new HashSet<>();
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Creates a new MetricsBase class instance.
|
||||
*
|
||||
* @param platform The platform of the service.
|
||||
* @param serviceId The id of the service.
|
||||
* @param serverUuid The server uuid.
|
||||
* @param enabled Whether or not data sending is enabled.
|
||||
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all platform-specific data.
|
||||
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all service-specific data.
|
||||
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
|
||||
* used to delegate the data collection to a another thread to prevent errors caused by
|
||||
* concurrency. Can be {@code null}.
|
||||
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
|
||||
* @param errorLogger A consumer that accepts log message and an error.
|
||||
* @param infoLogger A consumer that accepts info log messages.
|
||||
* @param logErrors Whether or not errors should be logged.
|
||||
* @param logSentData Whether or not the sent data should be logged.
|
||||
* @param logResponseStatusText Whether or not the response status text should be logged.
|
||||
*/
|
||||
public MetricsBase(
|
||||
String platform,
|
||||
String serverUuid,
|
||||
int serviceId,
|
||||
boolean enabled,
|
||||
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
|
||||
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
|
||||
Consumer<Runnable> submitTaskConsumer,
|
||||
Supplier<Boolean> checkServiceEnabledSupplier,
|
||||
BiConsumer<String, Throwable> errorLogger,
|
||||
Consumer<String> infoLogger,
|
||||
boolean logErrors,
|
||||
boolean logSentData,
|
||||
boolean logResponseStatusText
|
||||
) {
|
||||
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(
|
||||
1,
|
||||
task -> new Thread(task, "bStats-Metrics")
|
||||
);
|
||||
// We want delayed tasks (non-periodic) that will execute in the future to be
|
||||
// cancelled when the scheduler is shutdown.
|
||||
// Otherwise, we risk preventing the server from shutting down even when
|
||||
// MetricsBase#shutdown() is called
|
||||
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
this.scheduler = scheduler;
|
||||
this.platform = platform;
|
||||
this.serverUuid = serverUuid;
|
||||
this.serviceId = serviceId;
|
||||
this.enabled = enabled;
|
||||
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
|
||||
this.appendServiceDataConsumer = appendServiceDataConsumer;
|
||||
this.submitTaskConsumer = submitTaskConsumer;
|
||||
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
|
||||
this.errorLogger = errorLogger;
|
||||
this.infoLogger = infoLogger;
|
||||
this.logErrors = logErrors;
|
||||
this.logSentData = logSentData;
|
||||
this.logResponseStatusText = logResponseStatusText;
|
||||
checkRelocation();
|
||||
if (enabled) {
|
||||
// WARNING: Removing the option to opt-out will get your plugin banned from
|
||||
// bStats
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
this.customCharts.add(chart);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
private void startSubmitting() {
|
||||
final Runnable submitTask = () -> {
|
||||
if (!enabled || !checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown();
|
||||
return;
|
||||
}
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept(this::submitData);
|
||||
} else {
|
||||
this.submitData();
|
||||
}
|
||||
};
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven
|
||||
// distribution of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into
|
||||
// the initial and second delay.
|
||||
// WARNING: You must not modify and part of this Metrics class, including the
|
||||
// submit delay or frequency!
|
||||
// WARNING: Modifying this code will get your plugin banned on bStats. Just
|
||||
// don't do it!
|
||||
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
|
||||
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
|
||||
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
|
||||
scheduler.scheduleAtFixedRate(
|
||||
submitTask,
|
||||
initialDelay + secondDelay,
|
||||
1000 * 60 * 30,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
|
||||
private void submitData() {
|
||||
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder);
|
||||
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder);
|
||||
JsonObjectBuilder.JsonObject[] chartData = customCharts
|
||||
.stream()
|
||||
.map(customChart ->
|
||||
customChart.getRequestJsonObject(errorLogger, logErrors)
|
||||
)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(JsonObjectBuilder.JsonObject[]::new);
|
||||
serviceJsonBuilder.appendField("id", serviceId);
|
||||
serviceJsonBuilder.appendField("customCharts", chartData);
|
||||
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
|
||||
baseJsonBuilder.appendField("serverUUID", serverUuid);
|
||||
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
|
||||
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Could not submit bStats metrics data", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
|
||||
if (logSentData) {
|
||||
infoLogger.accept("Sent bStats metrics data: " + data.toString());
|
||||
}
|
||||
String url = String.format(REPORT_URL, platform);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url)
|
||||
.openConnection();
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty(
|
||||
"Content-Length",
|
||||
String.valueOf(compressedData.length)
|
||||
);
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
|
||||
connection.setDoOutput(true);
|
||||
try (
|
||||
DataOutputStream outputStream = new DataOutputStream(
|
||||
connection.getOutputStream()
|
||||
)
|
||||
) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (
|
||||
BufferedReader bufferedReader = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream())
|
||||
)
|
||||
) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
if (logResponseStatusText) {
|
||||
infoLogger.accept(
|
||||
"Sent data to bStats and received response: " + builder
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks that the class was properly relocated. */
|
||||
private void checkRelocation() {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (
|
||||
System.getProperty("bstats.relocatecheck") == null ||
|
||||
!System.getProperty("bstats.relocatecheck").equals("false")
|
||||
) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this
|
||||
// little "trick" ... :D
|
||||
final String defaultPackage = new String(
|
||||
new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' }
|
||||
);
|
||||
final String examplePackage = new String(
|
||||
new byte[] {
|
||||
'y',
|
||||
'o',
|
||||
'u',
|
||||
'r',
|
||||
'.',
|
||||
'p',
|
||||
'a',
|
||||
'c',
|
||||
'k',
|
||||
'a',
|
||||
'g',
|
||||
'e',
|
||||
}
|
||||
);
|
||||
// We want to make sure no one just copy & pastes the example and uses the wrong
|
||||
// package names
|
||||
if (
|
||||
MetricsBase.class.getPackage().getName().startsWith(defaultPackage) ||
|
||||
MetricsBase.class.getPackage().getName().startsWith(examplePackage)
|
||||
) {
|
||||
throw new IllegalStateException(
|
||||
"bStats Metrics class has not been relocated correctly!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given string.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped string.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(
|
||||
String chartId,
|
||||
Callable<Map<String, Integer>> callable
|
||||
) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder()
|
||||
.appendField("values", valuesBuilder.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(
|
||||
String chartId,
|
||||
Callable<Map<String, Integer>> callable
|
||||
) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder()
|
||||
.appendField("values", valuesBuilder.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(
|
||||
String chartId,
|
||||
Callable<Map<String, Integer>> callable
|
||||
) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
valuesBuilder.appendField(
|
||||
entry.getKey(),
|
||||
new int[] { entry.getValue() }
|
||||
);
|
||||
}
|
||||
return new JsonObjectBuilder()
|
||||
.appendField("values", valuesBuilder.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(
|
||||
String chartId,
|
||||
Callable<Map<String, int[]>> callable
|
||||
) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder()
|
||||
.appendField("values", valuesBuilder.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(
|
||||
String chartId,
|
||||
Callable<Map<String, Map<String, Integer>>> callable
|
||||
) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map
|
||||
.get(entryValues.getKey())
|
||||
.entrySet()) {
|
||||
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder()
|
||||
.appendField("values", valuesBuilder.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CustomChart {
|
||||
|
||||
private final String chartId;
|
||||
|
||||
protected CustomChart(String chartId) {
|
||||
if (chartId == null) {
|
||||
throw new IllegalArgumentException("chartId must not be null");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
public JsonObjectBuilder.JsonObject getRequestJsonObject(
|
||||
BiConsumer<String, Throwable> errorLogger,
|
||||
boolean logErrors
|
||||
) {
|
||||
JsonObjectBuilder builder = new JsonObjectBuilder();
|
||||
builder.appendField("chartId", chartId);
|
||||
try {
|
||||
JsonObjectBuilder.JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
builder.appendField("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logErrors) {
|
||||
errorLogger.accept(
|
||||
"Failed to get data for custom chart with id " + chartId,
|
||||
t
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected abstract JsonObjectBuilder.JsonObject getChartData()
|
||||
throws Exception;
|
||||
}
|
||||
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An extremely simple JSON builder.
|
||||
*
|
||||
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
|
||||
* for its use-case.
|
||||
*/
|
||||
public static class JsonObjectBuilder {
|
||||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
|
||||
private boolean hasAtLeastOneField = false;
|
||||
|
||||
public JsonObjectBuilder() {
|
||||
builder.append("{");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a null field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendNull(String key) {
|
||||
appendFieldUnescaped(key, "null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("JSON value must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int value) {
|
||||
appendFieldUnescaped(key, String.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param object The object.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject object) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("JSON object must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, object.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The string array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays
|
||||
.stream(values)
|
||||
.map(value -> "\"" + escape(value) + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays
|
||||
.stream(values)
|
||||
.mapToObj(String::valueOf)
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues = Arrays
|
||||
.stream(values)
|
||||
.map(JsonObject::toString)
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a field to the object.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param escapedValue The escaped value of the field.
|
||||
*/
|
||||
private void appendFieldUnescaped(String key, String escapedValue) {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("JSON key must not be null");
|
||||
}
|
||||
if (hasAtLeastOneField) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder
|
||||
.append("\"")
|
||||
.append(escape(key))
|
||||
.append("\":")
|
||||
.append(escapedValue);
|
||||
hasAtLeastOneField = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the JSON string and invalidates this builder.
|
||||
*
|
||||
* @return The built JSON string.
|
||||
*/
|
||||
public JsonObject build() {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
JsonObject object = new JsonObject(builder.append("}").toString());
|
||||
builder = null;
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
|
||||
*
|
||||
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
|
||||
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
|
||||
*
|
||||
* @param value The value to escape.
|
||||
* @return The escaped value.
|
||||
*/
|
||||
private static String escape(String value) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '"') {
|
||||
builder.append("\\\"");
|
||||
} else if (c == '\\') {
|
||||
builder.append("\\\\");
|
||||
} else if (c <= '\u000F') {
|
||||
builder.append("\\u000").append(Integer.toHexString(c));
|
||||
} else if (c <= '\u001F') {
|
||||
builder.append("\\u00").append(Integer.toHexString(c));
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A super simple representation of a JSON object.
|
||||
*
|
||||
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
|
||||
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
|
||||
* JsonObject)}.
|
||||
*/
|
||||
public static class JsonObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
private JsonObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package me.codedred.playtimes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import me.codedred.playtimes.afk.AFKManager;
|
||||
import me.codedred.playtimes.afk.listeners.onChat;
|
||||
import me.codedred.playtimes.afk.listeners.onInteract;
|
||||
@@ -19,145 +23,102 @@ import me.codedred.playtimes.listeners.Quit;
|
||||
import me.codedred.playtimes.server.ServerManager;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class PlayTimes extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
checkForUpdate();
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
ServerManager.getInstance().register();
|
||||
StatManager.getInstance().registerStatistics();
|
||||
TimeManager.getInstance().registerTimings();
|
||||
ServerManager.getInstance().register();
|
||||
StatManager.getInstance().registerStatistics();
|
||||
TimeManager.getInstance().registerTimings();
|
||||
|
||||
loadDatabase();
|
||||
registerEvents();
|
||||
registerCommands();
|
||||
loadDatabase();
|
||||
registerEvents();
|
||||
registerCommands();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
Metrics metrics = new Metrics(this, 5289);
|
||||
AFKManager.getInstance().startAFKChecker();
|
||||
getLogger().info("Successfully loaded.");
|
||||
}
|
||||
|
||||
AFKManager.getInstance().startAFKChecker();
|
||||
getLogger().info("Successfully loaded.");
|
||||
}
|
||||
@Override
|
||||
public void onDisable() {
|
||||
AFKManager.getInstance().endAFKChecker();
|
||||
getLogger().info("PlayTimes shutting down");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
AFKManager.getInstance().endAFKChecker();
|
||||
getLogger().info("PlayTimes shutting down");
|
||||
}
|
||||
private void registerEvents() {
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
DataManager data = DataManager.getInstance();
|
||||
|
||||
private void registerEvents() {
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
DataManager data = DataManager.getInstance();
|
||||
pm.registerEvents(new Join(), this);
|
||||
pm.registerEvents(new Quit(), this);
|
||||
|
||||
pm.registerEvents(new Join(), this);
|
||||
pm.registerEvents(new Quit(), this);
|
||||
if (data.hasAfkEnabled()) {
|
||||
pm.registerEvents(new onJoinQuit(), this);
|
||||
|
||||
if (data.hasAfkEnabled()) {
|
||||
pm.registerEvents(new onJoinQuit(), this);
|
||||
FileConfiguration config = data.getConfig();
|
||||
boolean cancelAfkOnMove = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-move"
|
||||
);
|
||||
boolean cancelAfkOnChat = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-chat"
|
||||
);
|
||||
boolean cancelAfkOnInteract = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-interact"
|
||||
);
|
||||
|
||||
FileConfiguration config = data.getConfig();
|
||||
boolean cancelAfkOnMove = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-move"
|
||||
);
|
||||
boolean cancelAfkOnChat = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-chat"
|
||||
);
|
||||
boolean cancelAfkOnInteract = config.getBoolean(
|
||||
"afk-settings.cancel-afk.on-player-interact"
|
||||
);
|
||||
if (cancelAfkOnMove || cancelAfkOnChat || cancelAfkOnInteract) {
|
||||
if (cancelAfkOnMove) pm.registerEvents(new onMove(), this);
|
||||
if (cancelAfkOnChat) pm.registerEvents(new onChat(), this);
|
||||
if (cancelAfkOnInteract) pm.registerEvents(new onInteract(), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelAfkOnMove || cancelAfkOnChat || cancelAfkOnInteract) {
|
||||
if (cancelAfkOnMove) pm.registerEvents(new onMove(), this);
|
||||
if (cancelAfkOnChat) pm.registerEvents(new onChat(), this);
|
||||
if (cancelAfkOnInteract) pm.registerEvents(new onInteract(), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void registerCommands() {
|
||||
Objects.requireNonNull(getCommand("playtime")).setExecutor(new Time());
|
||||
Objects.requireNonNull(getCommand("uptime")).setExecutor(new Uptime());
|
||||
Objects
|
||||
.requireNonNull(getCommand("topplaytime"))
|
||||
.setExecutor(new TopTime());
|
||||
Objects
|
||||
.requireNonNull(this.getCommand("pt"))
|
||||
.setTabCompleter(new TimeTabCompleter());
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
Objects.requireNonNull(getCommand("playtime")).setExecutor(new Time());
|
||||
Objects.requireNonNull(getCommand("uptime")).setExecutor(new Uptime());
|
||||
Objects
|
||||
.requireNonNull(getCommand("topplaytime"))
|
||||
.setExecutor(new TopTime());
|
||||
Objects
|
||||
.requireNonNull(this.getCommand("pt"))
|
||||
.setTabCompleter(new TimeTabCompleter());
|
||||
}
|
||||
public void loadDatabase() {
|
||||
if (
|
||||
DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getBoolean("database-settings.enabled")
|
||||
) {
|
||||
getLogger().info("Connecting to Database...");
|
||||
DatabaseManager databaseManager = DatabaseManager.getInstance();
|
||||
|
||||
public void loadDatabase() {
|
||||
if (
|
||||
DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getBoolean("database-settings.enabled")
|
||||
) {
|
||||
getLogger().info("Connecting to Database...");
|
||||
DatabaseManager databaseManager = DatabaseManager.getInstance();
|
||||
try {
|
||||
if (databaseManager.getDataSource().getConnection() != null) {
|
||||
try {
|
||||
databaseManager.getDataSource().closeConnection();
|
||||
} catch (Exception e) {
|
||||
getLogger()
|
||||
.warning("Error while trying to close Database connection..");
|
||||
}
|
||||
databaseManager.load();
|
||||
|
||||
try {
|
||||
if (databaseManager.getDataSource().getConnection() != null) {
|
||||
try {
|
||||
databaseManager.getDataSource().closeConnection();
|
||||
} catch (Exception e) {
|
||||
getLogger()
|
||||
.warning("Error while trying to close Database connection..");
|
||||
}
|
||||
databaseManager.load();
|
||||
if (
|
||||
DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getBoolean("purge-database.enabled")
|
||||
) databaseManager.purgeOldPlaytimeData();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
getLogger().severe("Error loading the database: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getBoolean("purge-database.enabled")
|
||||
) databaseManager.purgeOldPlaytimeData();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
getLogger().severe("Error loading the database: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForUpdate() {
|
||||
Bukkit
|
||||
.getScheduler()
|
||||
.runTaskAsynchronously(
|
||||
this,
|
||||
() -> {
|
||||
UpdateChecker updater = new UpdateChecker(this, 58858);
|
||||
try {
|
||||
if (updater.hasUpdatesAvailable()) {
|
||||
getLogger()
|
||||
.warning(
|
||||
ChatUtil.format(
|
||||
"You are using an older version of PlayTimes!"
|
||||
)
|
||||
);
|
||||
getLogger()
|
||||
.info(ChatUtil.format("Download the newest version here:"));
|
||||
getLogger()
|
||||
.info(
|
||||
ChatUtil.format("https://www.spigotmc.org/resources/58858/")
|
||||
);
|
||||
} else {
|
||||
getLogger()
|
||||
.info(
|
||||
"[PlayTimes] Plugin is up to date! - " +
|
||||
getDescription().getVersion()
|
||||
);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
getLogger().warning("[PlayTimes] Could not check for updates!");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package me.codedred.playtimes;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class UpdateChecker {
|
||||
|
||||
private static final String UPDATE_URL =
|
||||
"https://api.spigotmc.org/legacy/update.php?resource=%d";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final int projectId;
|
||||
|
||||
public UpdateChecker(JavaPlugin plugin, int projectId) {
|
||||
this.plugin = Objects.requireNonNull(plugin, "Plugin cannot be null.");
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public boolean hasUpdatesAvailable() throws IOException {
|
||||
String latestVersion;
|
||||
|
||||
URL url = new URL(String.format(UPDATE_URL, projectId));
|
||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setUseCaches(true);
|
||||
|
||||
try (
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream())
|
||||
)
|
||||
) {
|
||||
latestVersion = reader.readLine();
|
||||
}
|
||||
|
||||
if (latestVersion == null || latestVersion.isEmpty()) {
|
||||
throw new IOException("Failed to retrieve latest version.");
|
||||
}
|
||||
|
||||
return !plugin.getDescription().getVersion().equals(latestVersion);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
package me.codedred.playtimes.afk.listeners;
|
||||
|
||||
import me.codedred.playtimes.afk.AFKManager;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
|
||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
import me.codedred.playtimes.afk.AFKManager;
|
||||
|
||||
public class onChat implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||
AFKManager.getInstance().updateActivity(event.getPlayer());
|
||||
}
|
||||
}
|
||||
@EventHandler
|
||||
public void onPlayerChat(AsyncChatEvent event) {
|
||||
AFKManager.getInstance().updateActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,18 +2,11 @@ package me.codedred.playtimes.commands;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import me.codedred.playtimes.PlayTimes;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.models.Message;
|
||||
import me.codedred.playtimes.server.ServerManager;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.time.TimeConstants;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@@ -23,289 +16,336 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import me.codedred.playtimes.PlayTimes;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.models.Message;
|
||||
import me.codedred.playtimes.server.ServerManager;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.time.TimeConstants;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
import me.codedred.playtimes.utils.OGUtils;
|
||||
|
||||
public class Time implements CommandExecutor {
|
||||
|
||||
private final DataManager data = DataManager.getInstance();
|
||||
private final DataManager data = DataManager.getInstance();
|
||||
|
||||
public boolean onCommand(
|
||||
CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
@NotNull String label,
|
||||
String[] args
|
||||
) {
|
||||
if (!sender.hasPermission("pt.use")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
public boolean onCommand(
|
||||
CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
@NotNull String label,
|
||||
String[] args
|
||||
) {
|
||||
if (! sender.hasPermission("pt.use")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
String arg = args.length > 0 ? args[0].toLowerCase() : "";
|
||||
String arg = args.length > 0 ? args[0].toLowerCase() : "";
|
||||
|
||||
switch (arg) {
|
||||
case "":
|
||||
handlePlayerCommand(sender);
|
||||
break;
|
||||
case "reload":
|
||||
handleReloadCommand(sender);
|
||||
break;
|
||||
case "reloaddatabase":
|
||||
handleReloadDatabaseCommand(sender);
|
||||
break;
|
||||
case "top":
|
||||
handleTopCommand(sender);
|
||||
break;
|
||||
case "block":
|
||||
handleBlockCommand(sender, args, true);
|
||||
break;
|
||||
case "unblock":
|
||||
handleBlockCommand(sender, args, false);
|
||||
break;
|
||||
case "version":
|
||||
handleVersionCommand(sender);
|
||||
break;
|
||||
case "help":
|
||||
handleHelpCommand(sender);
|
||||
break;
|
||||
default:
|
||||
handleOtherPlayerCommand(sender, args);
|
||||
break;
|
||||
}
|
||||
switch (arg) {
|
||||
case "":
|
||||
handlePlayerCommand(sender);
|
||||
break;
|
||||
case "reload":
|
||||
handleReloadCommand(sender);
|
||||
break;
|
||||
case "reloaddatabase":
|
||||
handleReloadDatabaseCommand(sender);
|
||||
break;
|
||||
case "top":
|
||||
handleTopCommand(sender);
|
||||
break;
|
||||
case "block":
|
||||
handleBlockCommand(sender, args, true);
|
||||
break;
|
||||
case "unblock":
|
||||
handleBlockCommand(sender, args, false);
|
||||
break;
|
||||
case "version":
|
||||
handleVersionCommand(sender);
|
||||
break;
|
||||
case "help":
|
||||
handleHelpCommand(sender);
|
||||
break;
|
||||
default:
|
||||
handleOtherPlayerCommand(sender, args);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleHelpCommand(CommandSender sender) {
|
||||
if (!sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Help ***"));
|
||||
sender.sendMessage(ChatUtil.format("&e/pt: &7Displays your play time"));
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt <player>: &7Displays the play time of <player>")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt reload: &7Reloads the PlayTimes plugin configurations"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt top: &7Shows the top players by play time")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt block <player>: &7Blocks a player from leaderboards"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt unblock <player>: &7Unblocks a player from leaderboards"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt version: &7Displays the version info")
|
||||
);
|
||||
}
|
||||
private void handleHelpCommand(CommandSender sender) {
|
||||
if (! sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Help ***"));
|
||||
sender.sendMessage(ChatUtil.format("&e/pt: &7Displays your play time"));
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt <player>: &7Displays the play time of <player>")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt reload: &7Reloads the PlayTimes plugin configurations"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt top: &7Shows the top players by play time")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt block <player>: &7Blocks a player from leaderboards"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&e/pt unblock <player>: &7Unblocks a player from leaderboards"
|
||||
)
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&e/pt version: &7Displays the version info")
|
||||
);
|
||||
}
|
||||
|
||||
private void handleVersionCommand(CommandSender sender) {
|
||||
if (!sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
boolean isOnline = ServerManager.getInstance().isOnline();
|
||||
String serverStatus = isOnline ? "Online" : "Offline";
|
||||
private void handleVersionCommand(CommandSender sender) {
|
||||
if (! sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
boolean isOnline = ServerManager.getInstance().isOnline();
|
||||
String serverStatus = isOnline ? "Online" : "Offline";
|
||||
|
||||
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Version Info ***"));
|
||||
sender.sendMessage(
|
||||
ChatColor.GOLD +
|
||||
"Server version: " +
|
||||
ChatColor.WHITE +
|
||||
Bukkit.getServer().getVersion() +
|
||||
ChatColor.GOLD +
|
||||
"\nPlayTimes version: " +
|
||||
ChatColor.WHITE +
|
||||
JavaPlugin.getPlugin(PlayTimes.class).getDescription().getVersion() +
|
||||
ChatColor.GOLD +
|
||||
"\nStat Manager: " +
|
||||
ChatColor.WHITE +
|
||||
StatManager.getInstance().name +
|
||||
ChatColor.GOLD +
|
||||
"\nServer Status: " +
|
||||
ChatColor.WHITE +
|
||||
serverStatus +
|
||||
ChatColor.GOLD +
|
||||
"\nDatabase connected: " +
|
||||
ChatColor.WHITE +
|
||||
DataManager.getInstance().hasDatabase() +
|
||||
ChatColor.GOLD +
|
||||
"\nAFK Status: " +
|
||||
ChatColor.WHITE +
|
||||
DataManager.getInstance().hasAfkEnabled() +
|
||||
ChatColor.GOLD +
|
||||
"\nUUID Lookup Type: " +
|
||||
ChatColor.WHITE +
|
||||
ServerManager.getInstance().lookupType()
|
||||
);
|
||||
}
|
||||
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Version Info ***"));
|
||||
if (sender instanceof Player) {
|
||||
OGUtils.playTimesOGMessage((Player) sender,
|
||||
"&6" +
|
||||
"Server version: " +
|
||||
"&f" +
|
||||
Bukkit.getServer().getVersion() +
|
||||
"&6" +
|
||||
"\nPlayTimes version: " +
|
||||
"&f" +
|
||||
"v1.0" +
|
||||
"&6" +
|
||||
"\nStat Manager: " +
|
||||
"&f" +
|
||||
StatManager.getInstance().name +
|
||||
"&6" +
|
||||
"\nServer Status: " +
|
||||
"&f" +
|
||||
serverStatus +
|
||||
"&6" +
|
||||
"\nDatabase connected: " +
|
||||
"&f" +
|
||||
DataManager.getInstance().hasDatabase() +
|
||||
"&6" +
|
||||
"\nAFK Status: " +
|
||||
"&f" +
|
||||
DataManager.getInstance().hasAfkEnabled() +
|
||||
"&6" +
|
||||
"\nUUID Lookup Type: " +
|
||||
"&f" +
|
||||
ServerManager.getInstance().lookupType()
|
||||
);
|
||||
}
|
||||
else {
|
||||
Logger logger = Bukkit.getServer().getLogger();
|
||||
logger.info(OGUtils.legacySerializerAnyCase(
|
||||
"&6" +
|
||||
"Server version: " +
|
||||
"&f" +
|
||||
Bukkit.getServer().getVersion() +
|
||||
"&6" +
|
||||
"\nPlayTimes version: " +
|
||||
"&f" +
|
||||
"v1.0" +
|
||||
"&6" +
|
||||
"\nStat Manager: " +
|
||||
"&f" +
|
||||
StatManager.getInstance().name +
|
||||
"&6" +
|
||||
"\nServer Status: " +
|
||||
"&f" +
|
||||
serverStatus +
|
||||
"&6" +
|
||||
"\nDatabase connected: " +
|
||||
"&f" +
|
||||
DataManager.getInstance().hasDatabase() +
|
||||
"&6" +
|
||||
"\nAFK Status: " +
|
||||
"&f" +
|
||||
DataManager.getInstance().hasAfkEnabled() +
|
||||
"&6" +
|
||||
"\nUUID Lookup Type: " +
|
||||
"&f" +
|
||||
ServerManager.getInstance().lookupType()
|
||||
).content());
|
||||
|
||||
private void handlePlayerCommand(CommandSender sender) {
|
||||
if (!(sender instanceof Player)) {
|
||||
StatManager stats = StatManager.getInstance();
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&cThe console has been up for " + stats.getUptime())
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Player player = (Player) sender;
|
||||
Message message = new Message(
|
||||
sender,
|
||||
player.getUniqueId(),
|
||||
player.getName()
|
||||
);
|
||||
message.sendMessageToTarget();
|
||||
}
|
||||
}
|
||||
.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReloadCommand(CommandSender sender) {
|
||||
if (!sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
data.reloadAll();
|
||||
TimeConstants.reload();
|
||||
TimeManager.getInstance().registerTimings();
|
||||
sender.sendMessage(ChatUtil.format("&aPlayTimes Configurations Reloaded!"));
|
||||
if (DataManager.getInstance().hasDatabase()) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&aTrying to reload the Database settings?")
|
||||
);
|
||||
sender.sendMessage(ChatUtil.format(" &e&oTry, /pt reloadDatabase"));
|
||||
}
|
||||
}
|
||||
private void handlePlayerCommand(CommandSender sender) {
|
||||
if (! (sender instanceof Player)) {
|
||||
StatManager stats = StatManager.getInstance();
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&cThe console has been up for " + stats.getUptime())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
private void handleReloadDatabaseCommand(CommandSender sender) {
|
||||
if (!sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
data.reloadDatabase();
|
||||
PlayTimes.getPlugin(PlayTimes.class).loadDatabase();
|
||||
sender.sendMessage(ChatUtil.format("&aDatabase Reloaded."));
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&oIf you are still encountering issues try restarting your server."
|
||||
)
|
||||
);
|
||||
}
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Player player = (Player) sender;
|
||||
Message message = new Message(
|
||||
sender,
|
||||
player.getUniqueId(),
|
||||
player.getName()
|
||||
);
|
||||
message.sendMessageToTarget();
|
||||
}
|
||||
}
|
||||
.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
|
||||
}
|
||||
|
||||
private void handleTopCommand(CommandSender sender) {
|
||||
Bukkit.dispatchCommand(sender, "toppt");
|
||||
}
|
||||
private void handleReloadCommand(CommandSender sender) {
|
||||
if (! sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
data.reloadAll();
|
||||
TimeConstants.reload();
|
||||
TimeManager.getInstance().registerTimings();
|
||||
sender.sendMessage(ChatUtil.format("&aPlayTimes Configurations Reloaded!"));
|
||||
if (DataManager.getInstance().hasDatabase()) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&aTrying to reload the Database settings?")
|
||||
);
|
||||
sender.sendMessage(ChatUtil.format(" &e&oTry, /pt reloadDatabase"));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBlockCommand(
|
||||
CommandSender sender,
|
||||
String[] args,
|
||||
boolean block
|
||||
) {
|
||||
String blockAction = block ? "block" : "unblock";
|
||||
if (!sender.hasPermission("pt.block")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix(
|
||||
"&c&lIncorrect Usage&c, try &7/pt " + blockAction + " <player>"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
String playerName = args[1];
|
||||
String blockedKey = "blocked." + playerName.toLowerCase();
|
||||
if (block == data.getData().contains(blockedKey)) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&cUser is already " + blockAction + "ed!")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix(
|
||||
"&c&oMaybe try, &7/pt " + (block ? "unblock" : "block") + " <player>"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
UUID uuid;
|
||||
if (Bukkit.getPlayer(playerName) == null) {
|
||||
try {
|
||||
uuid = ServerManager.getInstance().getUUID(playerName.toLowerCase());
|
||||
} catch (NullPointerException e) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uuid = Objects.requireNonNull(Bukkit.getPlayer(playerName)).getUniqueId();
|
||||
}
|
||||
if (uuid == null) {
|
||||
sender.sendMessage(ChatUtil.formatWithPrefix("&c&lUser not found."));
|
||||
return;
|
||||
}
|
||||
if (block) {
|
||||
data.getData().set(blockedKey, uuid.toString());
|
||||
if (data.getData().contains("leaderboard." + uuid)) {
|
||||
data.getData().set("leaderboard." + uuid, null);
|
||||
}
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&aUser &c&lBLOCKED &afrom leaderboards!")
|
||||
);
|
||||
} else {
|
||||
data.getData().set(blockedKey, null);
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&aUser &b&lUNBLOCKED &afrom leaderboards!")
|
||||
);
|
||||
}
|
||||
data.saveData();
|
||||
}
|
||||
private void handleReloadDatabaseCommand(CommandSender sender) {
|
||||
if (!sender.hasPermission("pt.reload")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
data.reloadDatabase();
|
||||
PlayTimes.getPlugin(PlayTimes.class).loadDatabase();
|
||||
sender.sendMessage(ChatUtil.format("&aDatabase Reloaded."));
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(
|
||||
"&oIf you are still encountering issues try restarting your server."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void handleOtherPlayerCommand(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("pt.others")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Pattern p = Pattern.compile("[^a-z0-9_]", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = p.matcher(args[0]);
|
||||
boolean b = m.find();
|
||||
private void handleTopCommand(CommandSender sender) {
|
||||
Bukkit.dispatchCommand(sender, "toppt");
|
||||
}
|
||||
|
||||
if (b) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
private void handleBlockCommand(
|
||||
CommandSender sender,
|
||||
String[] args,
|
||||
boolean block
|
||||
) {
|
||||
String blockAction = block ? "block" : "unblock";
|
||||
if (! sender.hasPermission("pt.block")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix(
|
||||
"&c&lIncorrect Usage&c, try &7/pt " + blockAction + " <player>"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
String playerName = args[1];
|
||||
String blockedKey = "blocked." + playerName.toLowerCase();
|
||||
if (block == data.getData().contains(blockedKey)) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&cUser is already " + blockAction + "ed!")
|
||||
);
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix(
|
||||
"&c&oMaybe try, &7/pt " + (block ? "unblock" : "block") + " <player>"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
UUID uuid;
|
||||
if (Bukkit.getPlayer(playerName) == null) {
|
||||
try {
|
||||
uuid = ServerManager.getInstance().getUUID(playerName.toLowerCase());
|
||||
} catch (NullPointerException e) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uuid = Objects.requireNonNull(Bukkit.getPlayer(playerName)).getUniqueId();
|
||||
}
|
||||
if (uuid == null) {
|
||||
sender.sendMessage(ChatUtil.formatWithPrefix("&c&lUser not found."));
|
||||
return;
|
||||
}
|
||||
if (block) {
|
||||
data.getData().set(blockedKey, uuid.toString());
|
||||
if (data.getData().contains("leaderboard." + uuid)) {
|
||||
data.getData().set("leaderboard." + uuid, null);
|
||||
}
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&aUser &c&lBLOCKED &afrom leaderboards!")
|
||||
);
|
||||
} else {
|
||||
data.getData().set(blockedKey, null);
|
||||
sender.sendMessage(
|
||||
ChatUtil.formatWithPrefix("&aUser &b&lUNBLOCKED &afrom leaderboards!")
|
||||
);
|
||||
}
|
||||
data.saveData();
|
||||
}
|
||||
|
||||
UUID target;
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
target = ServerManager.getInstance().getUUID(args[0]);
|
||||
if (target == null) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
target =
|
||||
Objects.requireNonNull(Bukkit.getPlayer(args[0])).getUniqueId();
|
||||
}
|
||||
private void handleOtherPlayerCommand(CommandSender sender, String[] args) {
|
||||
if (! sender.hasPermission("pt.others")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return;
|
||||
}
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Pattern p = Pattern.compile("[^a-z0-9_]", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = p.matcher(args[0]);
|
||||
boolean b = m.find();
|
||||
|
||||
OfflinePlayer offlinePlayer = Bukkit
|
||||
.getServer()
|
||||
.getOfflinePlayer(target);
|
||||
Message message = new Message(sender, target, offlinePlayer.getName());
|
||||
message.sendMessageToTarget();
|
||||
}
|
||||
}
|
||||
.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
|
||||
}
|
||||
if (b) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
UUID target;
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
target = ServerManager.getInstance().getUUID(args[0]);
|
||||
if (target == null) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
target =
|
||||
Objects.requireNonNull(Bukkit.getPlayer(args[0])).getUniqueId();
|
||||
}
|
||||
|
||||
OfflinePlayer offlinePlayer = Bukkit
|
||||
.getServer()
|
||||
.getOfflinePlayer(target);
|
||||
Message message = new Message(sender, target, offlinePlayer.getName());
|
||||
message.sendMessageToTarget();
|
||||
}
|
||||
}
|
||||
.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,7 @@ package me.codedred.playtimes.commands;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.models.Leaderboard;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.*;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@@ -15,102 +11,110 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.models.Leaderboard;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
import me.codedred.playtimes.utils.CoolDownUtil;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class TopTime implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(
|
||||
CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
@NotNull String label,
|
||||
String[] args
|
||||
) {
|
||||
if (!sender.hasPermission("pt.top")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCommand(
|
||||
CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
@NotNull String label,
|
||||
String[] args
|
||||
) {
|
||||
if (!sender.hasPermission("pt.top")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
DataManager data = DataManager.getInstance();
|
||||
DataManager data = DataManager.getInstance();
|
||||
|
||||
if (
|
||||
data.getConfig().getBoolean("top-playtime.enable-cooldown") &&
|
||||
!sender.hasPermission("pt.block-cooldown") &&
|
||||
sender instanceof Player
|
||||
) {
|
||||
Player player = (Player) sender;
|
||||
if (CoolDownUtil.contains(player.getUniqueId())) {
|
||||
String cooldownMessage = Objects
|
||||
.requireNonNull(data.getConfig().getString("messages.cooldown"))
|
||||
.replace(
|
||||
"%timeleft%",
|
||||
Integer.toString(CoolDownUtil.left(player.getUniqueId()))
|
||||
);
|
||||
sender.sendMessage(ChatUtil.formatWithPrefix(cooldownMessage));
|
||||
return true;
|
||||
}
|
||||
CoolDownUtil.add(
|
||||
player.getUniqueId(),
|
||||
System.currentTimeMillis() +
|
||||
(data.getConfig().getInt("top-playtime.cooldown-seconds") * 1000L)
|
||||
);
|
||||
}
|
||||
if (
|
||||
data.getConfig().getBoolean("top-playtime.enable-cooldown") &&
|
||||
!sender.hasPermission("pt.block-cooldown") &&
|
||||
sender instanceof Player
|
||||
) {
|
||||
Player player = (Player) sender;
|
||||
if (CoolDownUtil.contains(player.getUniqueId())) {
|
||||
String cooldownMessage = Objects
|
||||
.requireNonNull(data.getConfig().getString("messages.cooldown"))
|
||||
.replace(
|
||||
"%timeleft%",
|
||||
Integer.toString(CoolDownUtil.left(player.getUniqueId()))
|
||||
);
|
||||
sender.sendMessage(ChatUtil.formatWithPrefix(cooldownMessage));
|
||||
return true;
|
||||
}
|
||||
CoolDownUtil.add(
|
||||
player.getUniqueId(),
|
||||
System.currentTimeMillis() +
|
||||
(data.getConfig().getInt("top-playtime.cooldown-seconds") * 1000L)
|
||||
);
|
||||
}
|
||||
|
||||
Leaderboard board = new Leaderboard();
|
||||
Map<String, Integer> map = board.getTopTen();
|
||||
Leaderboard board = new Leaderboard();
|
||||
Map<String, Integer> map = board.getTopTen();
|
||||
|
||||
if (map.isEmpty()) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&cRejoin the server to fill the leaderboard!")
|
||||
);
|
||||
return true;
|
||||
}
|
||||
if (map.isEmpty()) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format("&cRejoin the server to fill the leaderboard!")
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
StatManager statManager = StatManager.getInstance();
|
||||
TimeManager timeManager = TimeManager.getInstance();
|
||||
String header = ChatUtil.format(
|
||||
data.getConfig().getString("top-playtime.header")
|
||||
);
|
||||
String footer = ChatUtil.format(
|
||||
data.getConfig().getString("top-playtime.footer")
|
||||
);
|
||||
String content = data.getConfig().getString("top-playtime.content");
|
||||
StatManager statManager = StatManager.getInstance();
|
||||
TimeManager timeManager = TimeManager.getInstance();
|
||||
TextComponent header = ChatUtil.format(
|
||||
data.getConfig().getString("top-playtime.header")
|
||||
);
|
||||
TextComponent footer = ChatUtil.format(
|
||||
data.getConfig().getString("top-playtime.footer")
|
||||
);
|
||||
String content = data.getConfig().getString("top-playtime.content");
|
||||
|
||||
sender.sendMessage(header);
|
||||
sender.sendMessage(header);
|
||||
|
||||
for (int i = 0; i < map.size(); i++) {
|
||||
UUID uuid = UUID.fromString(map.keySet().toArray()[i].toString());
|
||||
org.bukkit.OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
|
||||
for (int i = 0; i < map.size(); i++) {
|
||||
UUID uuid = UUID.fromString(map.keySet().toArray()[i].toString());
|
||||
org.bukkit.OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
|
||||
|
||||
String defaultPlayerName = "Unknown";
|
||||
String defaultJoinDate = "N/A";
|
||||
String defaultTime = "0h 0m 0s";
|
||||
String defaultPlayerName = "Unknown";
|
||||
String defaultJoinDate = "N/A";
|
||||
String defaultTime = "0h 0m 0s";
|
||||
|
||||
String offlinePlayerName = offlinePlayer.getName() != null
|
||||
? offlinePlayer.getName()
|
||||
: defaultPlayerName;
|
||||
String place = String.valueOf(i + 1);
|
||||
String time = timeManager.buildFormat(
|
||||
map.get(offlinePlayer.getUniqueId().toString()) / 20
|
||||
);
|
||||
String joinDate = statManager.getJoinDate(uuid) != null
|
||||
? statManager.getJoinDate(uuid)
|
||||
: defaultJoinDate;
|
||||
String offlinePlayerName = offlinePlayer.getName() != null
|
||||
? offlinePlayer.getName()
|
||||
: defaultPlayerName;
|
||||
String place = String.valueOf(i + 1);
|
||||
String time = timeManager.buildFormat(
|
||||
map.get(offlinePlayer.getUniqueId().toString()) / 20
|
||||
);
|
||||
String joinDate = statManager.getJoinDate(uuid) != null
|
||||
? statManager.getJoinDate(uuid)
|
||||
: defaultJoinDate;
|
||||
|
||||
if (time == null) {
|
||||
time = defaultTime;
|
||||
}
|
||||
if (time == null) {
|
||||
time = defaultTime;
|
||||
}
|
||||
|
||||
String formattedContent = content
|
||||
.replace("%player%", offlinePlayerName)
|
||||
.replace("%place%", place)
|
||||
.replace("%time%", time)
|
||||
.replace("%joindate%", joinDate);
|
||||
String formattedContent = content
|
||||
.replace("%player%", offlinePlayerName)
|
||||
.replace("%place%", place)
|
||||
.replace("%time%", time)
|
||||
.replace("%joindate%", joinDate);
|
||||
|
||||
sender.sendMessage(ChatUtil.format(formattedContent));
|
||||
sender.sendMessage(ChatUtil.format(formattedContent));
|
||||
|
||||
content = data.getConfig().getString("top-playtime.content");
|
||||
}
|
||||
content = data.getConfig().getString("top-playtime.content");
|
||||
}
|
||||
|
||||
sender.sendMessage(footer);
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage(footer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package me.codedred.playtimes.commands;
|
||||
|
||||
import java.util.List;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
import me.codedred.playtimes.utils.ServerUtils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@@ -12,63 +9,67 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
|
||||
public class Uptime implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
String cmdL,
|
||||
String[] args
|
||||
) {
|
||||
// command must be uptime,serveruptime,or serverupt
|
||||
if (
|
||||
!cmdL.equalsIgnoreCase("uptime") &&
|
||||
!cmdL.equalsIgnoreCase("serveruptime") &&
|
||||
!cmdL.equalsIgnoreCase("serverupt")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean onCommand(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Command cmd,
|
||||
String cmdL,
|
||||
String[] args
|
||||
) {
|
||||
// command must be uptime,serveruptime,or serverupt
|
||||
if (
|
||||
!cmdL.equalsIgnoreCase("uptime") &&
|
||||
!cmdL.equalsIgnoreCase("serveruptime") &&
|
||||
!cmdL.equalsIgnoreCase("serverupt")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for permission
|
||||
if (!sender.hasPermission("pt.uptime")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
// check for permission
|
||||
if (!sender.hasPermission("pt.uptime")) {
|
||||
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the uptime
|
||||
String uptime = StatManager.getInstance().getUptime();
|
||||
List<String> messages = DataManager
|
||||
.getInstance()
|
||||
.getConfig()
|
||||
.getStringList("uptime.message");
|
||||
// get the uptime
|
||||
String uptime = StatManager.getInstance().getUptime();
|
||||
List<String> messages = DataManager
|
||||
.getInstance()
|
||||
.getConfig()
|
||||
.getStringList("uptime.message");
|
||||
|
||||
// iterate through the messages and replace the placeholders
|
||||
for (String message : messages) {
|
||||
//1: replace them using placeholder api
|
||||
// TODO: use MMAPI
|
||||
/*
|
||||
// iterate through the messages and replace the placeholders
|
||||
for (String message : messages) {
|
||||
//1: replace them using placeholder api
|
||||
// TODO: use MMAPI
|
||||
/*
|
||||
if (ServerUtils.hasPAPI() && sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
message = PlaceholderAPI.setPlaceholders(player, message);
|
||||
}
|
||||
*/
|
||||
// 2. replace them using java string methods
|
||||
if (message.contains("{\"text\":") && sender instanceof Player) {
|
||||
String consoleCommand =
|
||||
"tellraw " +
|
||||
sender.getName() +
|
||||
" " +
|
||||
message.replace("%serveruptime%", uptime);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), consoleCommand);
|
||||
//3. if all else fails dont send name
|
||||
} else if(sender instanceof Player) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(message.replace("%serveruptime%", uptime))
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// 2. replace them using java string methods
|
||||
if (message.contains("{\"text\":") && sender instanceof Player) {
|
||||
String consoleCommand =
|
||||
"tellraw " +
|
||||
sender.getName() +
|
||||
" " +
|
||||
message.replace("%serveruptime%", uptime);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), consoleCommand);
|
||||
//3. if all else fails dont send name
|
||||
} else if(sender instanceof Player) {
|
||||
sender.sendMessage(
|
||||
ChatUtil.format(message.replace("%serveruptime%", uptime))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3,54 +3,53 @@ package me.codedred.playtimes.data.database.datasource.impl;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import me.codedred.playtimes.PlayTimes;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.data.database.datasource.DataSource;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
public class MySQL implements DataSource {
|
||||
|
||||
private final String connectionUrl;
|
||||
private final String user;
|
||||
private final String password;
|
||||
private final String connectionUrl;
|
||||
private final String user;
|
||||
private final String password;
|
||||
|
||||
public MySQL(PlayTimes plugin) {
|
||||
var config = DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getConfigurationSection("database-settings");
|
||||
String host = config.getString("host");
|
||||
String port = config.getString("port");
|
||||
this.user = config.getString("user");
|
||||
this.password = config.getString("password");
|
||||
String database = config.getString("database");
|
||||
boolean SSL = config.getBoolean("useSSL");
|
||||
public MySQL(PlayTimes plugin) {
|
||||
var config = DataManager
|
||||
.getInstance()
|
||||
.getDBConfig()
|
||||
.getConfigurationSection("database-settings");
|
||||
String host = config.getString("host");
|
||||
String port = config.getString("port");
|
||||
this.user = config.getString("user");
|
||||
this.password = config.getString("password");
|
||||
String database = config.getString("database");
|
||||
boolean SSL = config.getBoolean("useSSL");
|
||||
|
||||
this.connectionUrl =
|
||||
String.format(
|
||||
"jdbc:mysql://%s:%s/%s?autoReconnect=true&useSSL=" + SSL,
|
||||
host,
|
||||
port,
|
||||
database
|
||||
);
|
||||
this.connectionUrl =
|
||||
String.format(
|
||||
"jdbc:mysql://%s:%s/%s?autoReconnect=true&useSSL=" + SSL,
|
||||
host,
|
||||
port,
|
||||
database
|
||||
);
|
||||
|
||||
try {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
plugin.getLogger().info("Successfully connected to database.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin
|
||||
.getLogger()
|
||||
.severe("MySQL JDBC Driver not found: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
plugin.getLogger().info("Successfully connected to database.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin
|
||||
.getLogger()
|
||||
.severe("MySQL JDBC Driver not found: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return DriverManager.getConnection(connectionUrl, user, password);
|
||||
}
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return DriverManager.getConnection(connectionUrl, user, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() throws SQLException {
|
||||
// connection.close();
|
||||
}
|
||||
@Override
|
||||
public void closeConnection() throws SQLException {
|
||||
// connection.close();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
package me.codedred.playtimes.models;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import me.codedred.playtimes.afk.AFKManager;
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import me.codedred.playtimes.data.database.manager.DatabaseManager;
|
||||
@@ -10,197 +18,196 @@ import me.codedred.playtimes.statistics.StatManager;
|
||||
import me.codedred.playtimes.statistics.StatisticType;
|
||||
import me.codedred.playtimes.time.TimeManager;
|
||||
import me.codedred.playtimes.utils.ChatUtil;
|
||||
import me.codedred.playtimes.utils.ServerUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class Message {
|
||||
|
||||
private final CommandSender sender;
|
||||
private final UUID targetUUID;
|
||||
private final String targetName;
|
||||
private List<String> message;
|
||||
private final CommandSender sender;
|
||||
private final UUID targetUUID;
|
||||
private final String targetName;
|
||||
private List<String> message;
|
||||
|
||||
private final DataManager dataManager;
|
||||
private final StatManager statManager;
|
||||
private final TimeManager timeManager;
|
||||
private final DataManager dataManager;
|
||||
private final StatManager statManager;
|
||||
private final TimeManager timeManager;
|
||||
|
||||
/**
|
||||
* Constructor for Message.
|
||||
* Initializes the message for the target player.
|
||||
*
|
||||
* @param sender The command sender.
|
||||
* @param targetUUID The UUID of the offline player.
|
||||
* @param targetName The name of the offline player.
|
||||
*/
|
||||
public Message(CommandSender sender, UUID targetUUID, String targetName) {
|
||||
this.sender = sender;
|
||||
this.targetUUID = targetUUID;
|
||||
this.targetName = targetName;
|
||||
/**
|
||||
* Constructor for Message.
|
||||
* Initializes the message for the target player.
|
||||
*
|
||||
* @param sender The command sender.
|
||||
* @param targetUUID The UUID of the offline player.
|
||||
* @param targetName The name of the offline player.
|
||||
*/
|
||||
public Message(CommandSender sender, UUID targetUUID, String targetName) {
|
||||
this.sender = sender;
|
||||
this.targetUUID = targetUUID;
|
||||
this.targetName = targetName;
|
||||
|
||||
this.dataManager = DataManager.getInstance();
|
||||
this.statManager = StatManager.getInstance();
|
||||
this.timeManager = TimeManager.getInstance();
|
||||
this.dataManager = DataManager.getInstance();
|
||||
this.statManager = StatManager.getInstance();
|
||||
this.timeManager = TimeManager.getInstance();
|
||||
|
||||
this.message = buildMessage();
|
||||
}
|
||||
this.message = buildMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the message to be sent to the sender about the target player.
|
||||
* This involves fetching playtime statistics, formatting them,
|
||||
* and applying any necessary replacements and PlaceholderAPI placeholders.
|
||||
*
|
||||
* @return A list of formatted strings representing the message.
|
||||
*/
|
||||
private List<String> buildMessage() {
|
||||
List<String> builtMessage = dataManager
|
||||
.getConfig()
|
||||
.getStringList("playtime.message");
|
||||
long rawTime = statManager.getPlayerStat(
|
||||
targetUUID,
|
||||
StatisticType.PLAYTIME
|
||||
);
|
||||
long afkTime = AFKManager.getInstance().getAFKTime(targetUUID);
|
||||
/**
|
||||
* Builds the message to be sent to the sender about the target player.
|
||||
* This involves fetching playtime statistics, formatting them,
|
||||
* and applying any necessary replacements and PlaceholderAPI placeholders.
|
||||
*
|
||||
* @return A list of formatted strings representing the message.
|
||||
*/
|
||||
private List<String> buildMessage() {
|
||||
List<String> builtMessage = dataManager
|
||||
.getConfig()
|
||||
.getStringList("playtime.message");
|
||||
long rawTime = statManager.getPlayerStat(
|
||||
targetUUID,
|
||||
StatisticType.PLAYTIME
|
||||
);
|
||||
long afkTime = AFKManager.getInstance().getAFKTime(targetUUID);
|
||||
|
||||
if (dataManager.hasDatabase()) {
|
||||
DatabaseManager dbManager = DatabaseManager.getInstance();
|
||||
dbManager.updatePlaytime(targetUUID, rawTime / 20, afkTime);
|
||||
}
|
||||
if (dataManager.hasDatabase()) {
|
||||
DatabaseManager dbManager = DatabaseManager.getInstance();
|
||||
dbManager.updatePlaytime(targetUUID, rawTime / 20, afkTime);
|
||||
}
|
||||
|
||||
return processMessageWithReplacements(
|
||||
builtMessage,
|
||||
prepareReplacements(rawTime, afkTime)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Prepares a map of replacements to be used in the message.
|
||||
*
|
||||
* @param rawTime The playtime statistic to format and include in the replacements.
|
||||
* @param afkTime The afktime statistic to format and include in the replacements.
|
||||
* @return A map of placeholder keys and their replacement values.
|
||||
*/
|
||||
private Map<String, String> prepareReplacements(long rawTime, long afkTime) {
|
||||
Map<String, String> replacements = new HashMap<>();
|
||||
replacements.put("%time%", timeManager.buildFormat(rawTime / 20 - afkTime));
|
||||
replacements.put(
|
||||
"%playtime%",
|
||||
timeManager.buildFormat(rawTime / 20 - afkTime)
|
||||
);
|
||||
replacements.put("%rawtime%", timeManager.buildFormat(rawTime / 20));
|
||||
replacements.put("%afktime%", timeManager.buildFormat(afkTime));
|
||||
replacements.put("%player%", targetName);
|
||||
replacements.put(
|
||||
"%timesjoined%",
|
||||
Long.toString(
|
||||
statManager.getPlayerStat(targetUUID, StatisticType.TIMES_JOINED)
|
||||
)
|
||||
);
|
||||
replacements.put("%joindate%", statManager.getJoinDate(targetUUID));
|
||||
return processMessageWithReplacements(
|
||||
builtMessage,
|
||||
prepareReplacements(rawTime, afkTime)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Prepares a map of replacements to be used in the message.
|
||||
*
|
||||
* @param rawTime The playtime statistic to format and include in the replacements.
|
||||
* @param afkTime The afktime statistic to format and include in the replacements.
|
||||
* @return A map of placeholder keys and their replacement values.
|
||||
*/
|
||||
private Map<String, String> prepareReplacements(long rawTime, long afkTime) {
|
||||
Map<String, String> replacements = new HashMap<>();
|
||||
replacements.put("%time%", timeManager.buildFormat(rawTime / 20 - afkTime));
|
||||
replacements.put(
|
||||
"%playtime%",
|
||||
timeManager.buildFormat(rawTime / 20 - afkTime)
|
||||
);
|
||||
replacements.put("%rawtime%", timeManager.buildFormat(rawTime / 20));
|
||||
replacements.put("%afktime%", timeManager.buildFormat(afkTime));
|
||||
replacements.put("%player%", targetName);
|
||||
replacements.put(
|
||||
"%timesjoined%",
|
||||
Long.toString(
|
||||
statManager.getPlayerStat(targetUUID, StatisticType.TIMES_JOINED)
|
||||
)
|
||||
);
|
||||
replacements.put("%joindate%", statManager.getJoinDate(targetUUID));
|
||||
|
||||
if (dataManager.hasDatabase()) {
|
||||
DatabaseManager dbManager = DatabaseManager.getInstance();
|
||||
if (dataManager.hasDatabase()) {
|
||||
DatabaseManager dbManager = DatabaseManager.getInstance();
|
||||
|
||||
long globalPlaytime = dbManager.getTotalPlaytime(targetUUID);
|
||||
long globalRawtime = dbManager.getTotalRawtime(targetUUID);
|
||||
long globalAfktime = dbManager.getTotalAfktime(targetUUID);
|
||||
long globalPlaytime = dbManager.getTotalPlaytime(targetUUID);
|
||||
long globalRawtime = dbManager.getTotalRawtime(targetUUID);
|
||||
long globalAfktime = dbManager.getTotalAfktime(targetUUID);
|
||||
|
||||
replacements.put(
|
||||
"%global_playtime%",
|
||||
timeManager.buildFormat(globalPlaytime)
|
||||
);
|
||||
replacements.put(
|
||||
"%global_rawtime%",
|
||||
timeManager.buildFormat(globalRawtime)
|
||||
);
|
||||
replacements.put(
|
||||
"%global_afktime%",
|
||||
timeManager.buildFormat(globalAfktime)
|
||||
);
|
||||
}
|
||||
replacements.put(
|
||||
"%global_playtime%",
|
||||
timeManager.buildFormat(globalPlaytime)
|
||||
);
|
||||
replacements.put(
|
||||
"%global_rawtime%",
|
||||
timeManager.buildFormat(globalRawtime)
|
||||
);
|
||||
replacements.put(
|
||||
"%global_afktime%",
|
||||
timeManager.buildFormat(globalAfktime)
|
||||
);
|
||||
}
|
||||
|
||||
return replacements;
|
||||
}
|
||||
return replacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the message by applying the necessary replacements.
|
||||
*
|
||||
* @param message The original message.
|
||||
* @param replacements The map of placeholders and their replacements.
|
||||
* @return A list of processed messages.
|
||||
*/
|
||||
private List<String> processMessageWithReplacements(
|
||||
List<String> message,
|
||||
Map<String, String> replacements
|
||||
) {
|
||||
List<String> newMessage = new ArrayList<>();
|
||||
boolean hasDatabase = dataManager.hasDatabase();
|
||||
DatabaseManager dbManager = hasDatabase
|
||||
? DatabaseManager.getInstance()
|
||||
: null;
|
||||
Pattern pattern = Pattern.compile("%(rawtime|afktime|playtime)_(\\w+)%");
|
||||
/**
|
||||
* Processes the message by applying the necessary replacements.
|
||||
*
|
||||
* @param message The original message.
|
||||
* @param replacements The map of placeholders and their replacements.
|
||||
* @return A list of processed messages.
|
||||
*/
|
||||
private List<String> processMessageWithReplacements(
|
||||
List<String> message,
|
||||
Map<String, String> replacements
|
||||
) {
|
||||
List<String> newMessage = new ArrayList<>();
|
||||
boolean hasDatabase = dataManager.hasDatabase();
|
||||
DatabaseManager dbManager = hasDatabase
|
||||
? DatabaseManager.getInstance()
|
||||
: null;
|
||||
Pattern pattern = Pattern.compile("%(rawtime|afktime|playtime)_(\\w+)%");
|
||||
|
||||
for (String msg : message) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (hasDatabase && dbManager != null) {
|
||||
Matcher matcher = pattern.matcher(msg);
|
||||
while (matcher.find()) {
|
||||
String placeholderType = matcher.group(1);
|
||||
String serverId = matcher.group(2);
|
||||
Long timeValue = 0L;
|
||||
for (String msg : message) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (hasDatabase && dbManager != null) {
|
||||
Matcher matcher = pattern.matcher(msg);
|
||||
while (matcher.find()) {
|
||||
String placeholderType = matcher.group(1);
|
||||
String serverId = matcher.group(2);
|
||||
Long timeValue = 0L;
|
||||
|
||||
if (dbManager.hasTimeForServer(targetUUID, serverId)) {
|
||||
Map<String, Long> timeForServer = dbManager.getTimeForServer(
|
||||
targetUUID,
|
||||
serverId
|
||||
);
|
||||
timeValue =
|
||||
timeForServer.getOrDefault(
|
||||
placeholderType.equals("rawtime")
|
||||
? "playtime"
|
||||
: placeholderType,
|
||||
0L
|
||||
);
|
||||
if (placeholderType.equals("playtime")) {
|
||||
timeValue -= timeForServer.getOrDefault("afktime", 0L);
|
||||
}
|
||||
}
|
||||
if (dbManager.hasTimeForServer(targetUUID, serverId)) {
|
||||
Map<String, Long> timeForServer = dbManager.getTimeForServer(
|
||||
targetUUID,
|
||||
serverId
|
||||
);
|
||||
timeValue =
|
||||
timeForServer.getOrDefault(
|
||||
placeholderType.equals("rawtime")
|
||||
? "playtime"
|
||||
: placeholderType,
|
||||
0L
|
||||
);
|
||||
if (placeholderType.equals("playtime")) {
|
||||
timeValue -= timeForServer.getOrDefault("afktime", 0L);
|
||||
}
|
||||
}
|
||||
|
||||
matcher.appendReplacement(sb, timeManager.buildFormat(timeValue));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
msg = sb.toString();
|
||||
}
|
||||
matcher.appendReplacement(sb, timeManager.buildFormat(timeValue));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
msg = sb.toString();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : replacements.entrySet()) {
|
||||
msg =
|
||||
msg.replace(
|
||||
entry.getKey(),
|
||||
entry.getValue() != null ? entry.getValue() : entry.getKey()
|
||||
);
|
||||
}
|
||||
for (Map.Entry<String, String> entry : replacements.entrySet()) {
|
||||
msg =
|
||||
msg.replace(
|
||||
entry.getKey(),
|
||||
entry.getValue() != null ? entry.getValue() : entry.getKey()
|
||||
);
|
||||
}
|
||||
|
||||
newMessage.add(msg);
|
||||
}
|
||||
newMessage.add(msg);
|
||||
}
|
||||
|
||||
return newMessage;
|
||||
}
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the formatted message to the sender.
|
||||
* This method determines the appropriate method to send the message
|
||||
* (e.g., standard chat message or JSON formatted tellraw command).
|
||||
*/
|
||||
public void sendMessageToTarget() {
|
||||
for (String msg : message) {
|
||||
String formattedMsg = ChatUtil.format(msg);
|
||||
if (formattedMsg.contains("{\"text\":")) {
|
||||
Bukkit.dispatchCommand(
|
||||
Bukkit.getConsoleSender(),
|
||||
"tellraw " + sender.getName() + " " + formattedMsg
|
||||
);
|
||||
} else {
|
||||
sender.sendMessage(formattedMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the formatted message to the sender.
|
||||
* This method determines the appropriate method to send the message
|
||||
* (e.g., standard chat message or JSON formatted tellraw command).
|
||||
*/
|
||||
public void sendMessageToTarget() {
|
||||
for (String msg : message) {
|
||||
TextComponent formattedMsg = ChatUtil.format(msg);
|
||||
if (formattedMsg.content().contains("{\"text\":")) {
|
||||
Bukkit.dispatchCommand(
|
||||
Bukkit.getConsoleSender(),
|
||||
"tellraw " + sender.getName() + " " + formattedMsg
|
||||
);
|
||||
} else {
|
||||
sender.sendMessage(formattedMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +1,32 @@
|
||||
package me.codedred.playtimes.server;
|
||||
|
||||
import com.google.gson.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import me.codedred.playtimes.statistics.StatManager;
|
||||
|
||||
public class ServerOnline implements ServerStatus {
|
||||
|
||||
@Override
|
||||
public UUID getUUID(@NotNull String name) {
|
||||
UUID uuid = Bukkit.getServer().getPlayer(name).getUniqueId();
|
||||
if (!StatManager.getInstance().hasJoinedBefore(uuid)) {
|
||||
return null;
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
@Override
|
||||
public UUID getUUID(@NotNull String name) {
|
||||
UUID uuid = Bukkit.getServer().getPlayer(name).getUniqueId();
|
||||
if (!StatManager.getInstance().hasJoinedBefore(uuid)) {
|
||||
return null;
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) throws IOException {
|
||||
String new_name = Bukkit.getPlayer(uuid).getDisplayName();
|
||||
return new_name;
|
||||
}
|
||||
@Override
|
||||
public String getName(UUID uuid) throws IOException {
|
||||
String new_name = Bukkit.getPlayer(uuid).getName();
|
||||
return new_name;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,50 @@
|
||||
package me.codedred.playtimes.utils;
|
||||
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import me.codedred.playtimes.data.DataManager;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class ChatUtil {
|
||||
|
||||
private static final DataManager DATA_MANAGER = DataManager.getInstance();
|
||||
private static final boolean IS_NEWER_VERSION = ServerUtils.isNewerVersion();
|
||||
private static final DataManager DATA_MANAGER = DataManager.getInstance();
|
||||
|
||||
public enum ChatTypes {
|
||||
NO_PERMISSION,
|
||||
PLAYER_NOT_FOUND,
|
||||
PLAYER_NEVER_PLAYED,
|
||||
}
|
||||
public enum ChatTypes {
|
||||
NO_PERMISSION,
|
||||
PLAYER_NOT_FOUND,
|
||||
PLAYER_NEVER_PLAYED,
|
||||
}
|
||||
|
||||
public static void errno(CommandSender sender, ChatTypes type) {
|
||||
switch (type) {
|
||||
case NO_PERMISSION:
|
||||
sender.sendMessage(
|
||||
format(DATA_MANAGER.getConfig().getString("messages.noPermission"))
|
||||
);
|
||||
break;
|
||||
case PLAYER_NOT_FOUND:
|
||||
sender.sendMessage(
|
||||
formatWithPrefix(
|
||||
DATA_MANAGER.getConfig().getString("messages.player-not-found")
|
||||
)
|
||||
);
|
||||
break;
|
||||
case PLAYER_NEVER_PLAYED:
|
||||
sender.sendMessage(
|
||||
formatWithPrefix(
|
||||
DATA_MANAGER.getConfig().getString("messages.player-never-joined")
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static void errno(CommandSender sender, ChatTypes type) {
|
||||
switch (type) {
|
||||
case NO_PERMISSION:
|
||||
sender.sendMessage(
|
||||
format(DATA_MANAGER.getConfig().getString("messages.noPermission"))
|
||||
);
|
||||
break;
|
||||
case PLAYER_NOT_FOUND:
|
||||
sender.sendMessage(
|
||||
formatWithPrefix(
|
||||
DATA_MANAGER.getConfig().getString("messages.player-not-found")
|
||||
)
|
||||
);
|
||||
break;
|
||||
case PLAYER_NEVER_PLAYED:
|
||||
sender.sendMessage(
|
||||
formatWithPrefix(
|
||||
DATA_MANAGER.getConfig().getString("messages.player-never-joined")
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static String format(String msg) {
|
||||
msg = ChatColor.translateAlternateColorCodes('&', msg);
|
||||
if (IS_NEWER_VERSION) msg = HexUtil.hex(msg);
|
||||
return msg;
|
||||
}
|
||||
public static TextComponent format(String msg) {
|
||||
return OGUtils.legacySerializerAnyCase(msg);
|
||||
}
|
||||
|
||||
public static String formatWithPrefix(String msg) {
|
||||
msg =
|
||||
ChatColor.translateAlternateColorCodes(
|
||||
'&',
|
||||
DATA_MANAGER.getConfig().getString("prefix") + " " + msg
|
||||
);
|
||||
if (IS_NEWER_VERSION) msg = HexUtil.hex(msg);
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
public static TextComponent formatWithPrefix(String msg) {
|
||||
return OGUtils.legacySerializerAnyCase(DATA_MANAGER.getConfig().getString("prefix") + msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package me.codedred.playtimes.utils;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
public class OGUtils {
|
||||
|
||||
// Sends a formatted message to the player (including name replacement).
|
||||
public static void playTimesOGMessage(Player p, String message) {
|
||||
|
||||
p.sendMessage(legacySerializerAnyCase((message)));
|
||||
|
||||
}
|
||||
|
||||
public static TextComponent legacySerializerAnyCase(String subject) {
|
||||
|
||||
int count = 0;
|
||||
// Count the number of '&' characters to determine the size of the array
|
||||
for (char c : subject.toCharArray()) {
|
||||
|
||||
if (c == '&') {
|
||||
|
||||
count++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create an array to store the positions of '&' characters
|
||||
int[] positions = new int[count];
|
||||
int index = 0;
|
||||
// Find the positions of '&' characters and store in the array
|
||||
for (int i = 0; i < subject.length(); i++) {
|
||||
|
||||
if (subject.charAt(i) == '&') {
|
||||
|
||||
if (isUpperBukkitCode(subject.charAt(i + 1))) {
|
||||
|
||||
subject = replaceCharAtIndex(subject, (i + 1), Character.toLowerCase(subject.charAt(i + 1)));
|
||||
|
||||
}
|
||||
|
||||
positions[index++] = i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return LegacyComponentSerializer.legacyAmpersand().deserialize(subject);
|
||||
|
||||
}
|
||||
|
||||
private static boolean isUpperBukkitCode(char input) {
|
||||
|
||||
char[] bukkitColorCodes = {'A', 'B', 'C', 'D', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'R'};
|
||||
boolean match = false;
|
||||
|
||||
// Loop through each character in the array.
|
||||
for (char c : bukkitColorCodes) {
|
||||
// Check if the current character in the array is equal to the input character.
|
||||
if (c == input) {
|
||||
|
||||
match = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return match;
|
||||
|
||||
}
|
||||
|
||||
private static String replaceCharAtIndex(String original, int index, char newChar) {
|
||||
|
||||
// Check if the index is valid
|
||||
if (index >= 0 && index < original.length()) {
|
||||
|
||||
// Create a new string with the replaced character
|
||||
return original.substring(0, index) + newChar + original.substring(index + 1);
|
||||
|
||||
}
|
||||
|
||||
// If the index is invalid, return the original string
|
||||
return original;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user