mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-26 02:57:52 +01:00
Removed project files
This commit is contained in:
parent
219d819d2d
commit
5590717c39
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 106 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 82 KiB |
@ -1,41 +0,0 @@
|
||||
plugins {
|
||||
id "com.jfrog.bintray" version "1.8.4"
|
||||
}
|
||||
|
||||
ext.apiVersion = '0.0.6'
|
||||
|
||||
bintray {
|
||||
user = System.getenv('BINTRAY_USER')
|
||||
key = System.getenv('BINTRAY_KEY')
|
||||
pkg {
|
||||
repo = 'Plan-repository'
|
||||
name = 'Plan-API'
|
||||
licenses = ['LGPL-v3.0']
|
||||
vcsUrl = 'https://github.com/plan-player-analytics/Plan'
|
||||
issueTrackerUrl = 'https://github.com/plan-player-analytics/Plan/issues'
|
||||
version {
|
||||
name = "$apiVersion"
|
||||
desc = "Plan APIv5 version $apiVersion"
|
||||
}
|
||||
publications = ['BintrayPublication']
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
BintrayPublication(MavenPublication) {
|
||||
groupId = 'com.djrapitops'
|
||||
artifactId = 'Plan-api'
|
||||
version = "$apiVersion"
|
||||
|
||||
artifact jar
|
||||
}
|
||||
mavenJava(MavenPublication) {
|
||||
groupId = 'com.djrapitops'
|
||||
artifactId = 'Plan-api'
|
||||
version = "$apiVersion"
|
||||
|
||||
artifact jar
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.capability;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* List of different capabilities current version provides.
|
||||
* <p>
|
||||
* The enum is package private to restrict direct access. This is to avoid NoClassDefFoundError in case
|
||||
* a wanted Capability is not provided in an earlier version.
|
||||
* <p>
|
||||
* Use {@link CapabilityService#hasCapability(String)} with name of a Capability to figure out if an API is available.
|
||||
* Example usage: {@code CapabilityService.getInstance().hasCapability("DATA_EXTENSION_VALUES")}.
|
||||
* <p>
|
||||
* If a capability is not available, attempting to use the capability might lead to exceptions.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
enum Capability {
|
||||
|
||||
/**
|
||||
* ExtensionService, DataExtension API base package, PluginInfo, Conditional, Tab, TabInfo, TabOrder and BooleanProvider, DoubleProvider, PercentageProvider, NumberProvider, StringProvider annotations.
|
||||
*/
|
||||
DATA_EXTENSION_VALUES,
|
||||
/**
|
||||
* DataExtension API table package, TableProvider, Table and Table.Factory
|
||||
*/
|
||||
DATA_EXTENSION_TABLES,
|
||||
/**
|
||||
* DataExtension API addition, allows throwing {@link com.djrapitops.plan.extension.NotReadyException} inside a Provider method when your API is not ready for a method call.
|
||||
*/
|
||||
DATA_EXTENSION_NOT_READY_EXCEPTION,
|
||||
/**
|
||||
* DataExtension API addition, parameter {@code showInPlayerTable} for BooleanProvider, DoubleProvider, PercentageProvider, NumberProvider, StringProvider annotations.
|
||||
* <p>
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
*/
|
||||
DATA_EXTENSION_SHOW_IN_PLAYER_TABLE,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
QUERY_API;
|
||||
|
||||
static Optional<Capability> getByName(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.capability;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Service for figuring out provided API capabilities.
|
||||
* <p>
|
||||
* {@link CapabilityService#registerEnableListener(Consumer)} to be notified of Plan reloads
|
||||
* {@link CapabilityService#hasCapability(String)} to check if a capability is available.
|
||||
* <p>
|
||||
* See {@link Capability} for list of capabilities provided by the current version.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface CapabilityService {
|
||||
|
||||
/**
|
||||
* Obtain instance of CapabilityService.
|
||||
*
|
||||
* @return CapabilityService implementation.
|
||||
* @throws NoClassDefFoundError If Plan is not installed and this class can not be found or if older Plan version is installed.
|
||||
* @throws IllegalStateException If Plan is installed, but not enabled.
|
||||
*/
|
||||
static CapabilityService getInstance() {
|
||||
return Optional.ofNullable(CapabilityServiceHolder.service)
|
||||
.orElseThrow(() -> new IllegalStateException("CapabilityService has not been initialised yet."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a method to be called when Plan reloads.
|
||||
*
|
||||
* @param isEnabledListener The boolean given to the method tells if Plan has enabled successfully.
|
||||
*/
|
||||
void registerEnableListener(Consumer<Boolean> isEnabledListener);
|
||||
|
||||
/**
|
||||
* Check if the API on the current version provides a capability.
|
||||
*
|
||||
* @param capabilityName Name of a capability
|
||||
* @return true if the capability is available.
|
||||
* @see Capability for different capabilityNames.
|
||||
*/
|
||||
default boolean hasCapability(String capabilityName) {
|
||||
return Capability.getByName(capabilityName).isPresent();
|
||||
}
|
||||
|
||||
class CapabilityServiceHolder {
|
||||
static CapabilityService service;
|
||||
|
||||
private CapabilityServiceHolder() {
|
||||
/* Static variable holder */
|
||||
}
|
||||
|
||||
static void set(CapabilityService service) {
|
||||
CapabilityServiceHolder.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Enum representing different events when Plan calls methods of {@link DataExtension} automatically.
|
||||
* <p>
|
||||
* You can also call the update methods via {@link Caller} manually.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum CallEvents {
|
||||
|
||||
/**
|
||||
* This event represents a manual call via {@link Caller}.
|
||||
* Definition inside {@link DataExtension#callExtensionMethodsOn()} is NOT REQUIRED for using Caller methods.
|
||||
*/
|
||||
MANUAL,
|
||||
/**
|
||||
* This event represents call to player methods on a Player Join event.
|
||||
* <p>
|
||||
* The call is made from a listener at the last event priority (Bukkit/Bungee: MONITOR, Sponge: POST).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
PLAYER_JOIN,
|
||||
/**
|
||||
* This event represents a call to player methods on a Player Leave event.
|
||||
* <p>
|
||||
* The call is made from a listener at the first event priority (Bukkit/Bungee: LOWEST, Sponge: PRE).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
PLAYER_LEAVE,
|
||||
/**
|
||||
* This event represents a call to server methods when the {@link DataExtension} is registered.
|
||||
* <p>
|
||||
* Server methods include any {@link Group} parameter methods.
|
||||
* <p>
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
SERVER_EXTENSION_REGISTER,
|
||||
/**
|
||||
* This event represents a call to server methods via a periodical task.
|
||||
* <p>
|
||||
* Server methods include any {@link Group} parameter methods.
|
||||
* <p>
|
||||
* Periodic task with a runs user configured period (Plan config).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
SERVER_PERIODICAL
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Interface for manually calling update methods on a registered {@link DataExtension}.
|
||||
* <p>
|
||||
* You can obtain an instance by registering an extension via {@link ExtensionService#register(DataExtension)}.
|
||||
* <p>
|
||||
* Plan calls the methods in DataExtension based on {@link CallEvents} defined by {@link }
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Caller {
|
||||
|
||||
/**
|
||||
* Calls all player methods of the associated {@link DataExtension}.
|
||||
* <p>
|
||||
* Player methods have {@code UUID} or {@code String} as a method parameter and a Provider annotation.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param playerName Name of the player.
|
||||
* @throws IllegalArgumentException If playerUUID or playerName is null.
|
||||
*/
|
||||
void updatePlayerData(UUID playerUUID, String playerName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Calls all server methods of the associated {@link DataExtension}.
|
||||
* <p>
|
||||
* Server methods have no parameters or {@link Group} method parameter and a Provider annotation.
|
||||
*/
|
||||
void updateServerData();
|
||||
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Interface to implement data extensions with.
|
||||
* <p>
|
||||
* The class implementing this interface should be annotated with {@link com.djrapitops.plan.extension.annotation.PluginInfo}.
|
||||
* If the extension is given to Plan API without the annotation it will be rejected.
|
||||
* <hr>
|
||||
* <p>
|
||||
* Public methods in the class should be annotated with appropriate Provider annotations.
|
||||
* Provider annotations:
|
||||
* {@link com.djrapitops.plan.extension.annotation.BooleanProvider} for {@code boolean} values and conditions for {@link com.djrapitops.plan.extension.annotation.Conditional}.
|
||||
* {@link com.djrapitops.plan.extension.annotation.NumberProvider} for {@code long} values. (Use this for integers by casting to long) Has option for formatting.
|
||||
* {@link com.djrapitops.plan.extension.annotation.DoubleProvider} for {@code double} values.
|
||||
* {@link com.djrapitops.plan.extension.annotation.PercentageProvider} for {@code double} values that represent a percentage.
|
||||
* {@link com.djrapitops.plan.extension.annotation.StringProvider} for {@link String} values.
|
||||
* <hr>
|
||||
* <p>
|
||||
* Methods can have one of the following as method parameters:
|
||||
* {@code UUID playerUUID} - UUID of the player the data is about
|
||||
* {@code String playerName} - Name of the player the data is about
|
||||
* {@link Group group} - Provided group the data is about (In case a group needs additional information)
|
||||
* nothing - The data is interpreted to be about the server.
|
||||
* <hr>
|
||||
* <p>
|
||||
* The name of the method will be used as an identifier in the database, so that a single provider does not duplicate entries.
|
||||
* Only first 50 characters of the method name are stored.
|
||||
* If you need to change a method name add a class annotation with the old method name: {@link com.djrapitops.plan.extension.annotation.InvalidateMethod}
|
||||
* <p>
|
||||
* Some additional annotations are available for controlling appearance of the results:
|
||||
* {@link com.djrapitops.plan.extension.annotation.Conditional} A {@code boolean} returned by {@link com.djrapitops.plan.extension.annotation.BooleanProvider} has to be {@code true} for this method to be called.
|
||||
* {@link com.djrapitops.plan.extension.annotation.Tab} The value of this provider should be placed on a tab with a specific name
|
||||
* {@link com.djrapitops.plan.extension.annotation.TabInfo} Optional Structure information about a tab
|
||||
* {@link com.djrapitops.plan.extension.annotation.TabOrder} Optional information about preferred tab
|
||||
* <hr>
|
||||
* <p>
|
||||
* Method calls are asynchronous. You can control when the calls are made via {@link DataExtension#callExtensionMethodsOn()} and {@link Caller}.
|
||||
* <p>
|
||||
* You can check against implementation violations by using {@link com.djrapitops.plan.extension.extractor.ExtensionExtractor#validateAnnotations()} in your Unit Tests.
|
||||
* <p>
|
||||
* Implementation violations:
|
||||
* - No {@link com.djrapitops.plan.extension.annotation.PluginInfo} class annotation
|
||||
* - Class contains no public methods with Provider annotations
|
||||
* - Class contains private method with Provider annotation
|
||||
* - Non-primitive return type when primitive is required (eg. Boolean instead of boolean)
|
||||
* - Method doesn't have correct parameters (see above)
|
||||
* - {@link com.djrapitops.plan.extension.annotation.BooleanProvider} is annotated with a {@link com.djrapitops.plan.extension.annotation.Conditional} that requires same condition the provider provides.
|
||||
* - {@link com.djrapitops.plan.extension.annotation.Conditional} without a {@link com.djrapitops.plan.extension.annotation.BooleanProvider} that provides value for the condition
|
||||
* - Annotation variable is over 50 characters (Or 150 if description)
|
||||
* - Method name is over 50 characters (Used as an identifier for storage)
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.extension.annotation.PluginInfo Required Annotation
|
||||
* @see CallEvents for method call event types.
|
||||
*/
|
||||
public interface DataExtension {
|
||||
|
||||
/**
|
||||
* Determines when DataExtension methods are called automatically by Plan.
|
||||
* <p>
|
||||
* Override this method to determine more suitable call times for your plugin.
|
||||
* You can also use {@link Caller} to update manually.
|
||||
* <p>
|
||||
* If an empty array is supplied the DataExtension methods are not called by Plan automatically.
|
||||
*
|
||||
* @return Event types that will trigger method calls to the DataExtension.
|
||||
* @see CallEvents for details when the methods are called.
|
||||
*/
|
||||
default CallEvents[] callExtensionMethodsOn() {
|
||||
return new CallEvents[]{
|
||||
CallEvents.PLAYER_JOIN,
|
||||
CallEvents.PLAYER_LEAVE,
|
||||
CallEvents.SERVER_EXTENSION_REGISTER
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Enum representing big elements of a plugin.
|
||||
* <p>
|
||||
* Used for determining in which order elements are placed on a {@link com.djrapitops.plan.extension.annotation.Tab} by
|
||||
* using {@link com.djrapitops.plan.extension.annotation.TabInfo}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum ElementOrder {
|
||||
/**
|
||||
* Represents text - value pair box.
|
||||
*/
|
||||
VALUES,
|
||||
/**
|
||||
* Represents graphs.
|
||||
*/
|
||||
GRAPH,
|
||||
/**
|
||||
* Represents tables.
|
||||
*/
|
||||
TABLE;
|
||||
|
||||
public static String serialize(ElementOrder[] order) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int length = order.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
builder.append(order[i].name());
|
||||
if (i < length - 1) {
|
||||
builder.append(',');
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static ElementOrder[] deserialize(String serializedOrder) {
|
||||
if (serializedOrder == null || serializedOrder.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] split = serializedOrder.split(",");
|
||||
|
||||
List<ElementOrder> order = new ArrayList<>();
|
||||
for (String elementName : split) {
|
||||
try {
|
||||
ElementOrder element = valueOf(elementName);
|
||||
order.add(element);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
/* Has been deleted */
|
||||
}
|
||||
}
|
||||
|
||||
return order.toArray(new ElementOrder[0]);
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import com.djrapitops.plan.extension.extractor.ExtensionExtractor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface for registering {@link DataExtension}s.
|
||||
* <p>
|
||||
* Obtaining instance:
|
||||
* - Obtain instance with {@link ExtensionService#getInstance()}.
|
||||
* - Make sure to catch a possible NoClassDefFoundError in case Plan is not installed
|
||||
* - Catch IllegalStateException in case ExtensionService is not enabled
|
||||
* <p>
|
||||
* Registering {@link DataExtension}:
|
||||
* - Register your {@link DataExtension} with {@link ExtensionService#register(DataExtension)}
|
||||
* - Catch a possible IllegalArgumentException in case the DataExtension implementation is invalid.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface ExtensionService {
|
||||
|
||||
/**
|
||||
* Obtain instance of ExtensionService.
|
||||
*
|
||||
* @return ExtensionService implementation.
|
||||
* @throws NoClassDefFoundError If Plan is not installed and this class can not be found or if older Plan version is installed.
|
||||
* @throws IllegalStateException If Plan is installed, but not enabled.
|
||||
*/
|
||||
static ExtensionService getInstance() {
|
||||
return Optional.ofNullable(ExtensionServiceHolder.service)
|
||||
.orElseThrow(() -> new IllegalStateException("ExtensionService has not been initialised yet."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register your {@link DataExtension} implementation.
|
||||
* <p>
|
||||
* You can use {@link ExtensionExtractor#validateAnnotations()} in your Unit Tests to prevent IllegalArgumentExceptions here at runtime.
|
||||
*
|
||||
* @param extension Your DataExtension implementation, see {@link DataExtension} for requirements.
|
||||
* @return Optional {@link Caller} that can be used to call for data update in Plan database manually - If the Optional is not present the user has disabled the extension in Plan config.
|
||||
* @throws IllegalArgumentException If an implementation violation is found.
|
||||
*/
|
||||
Optional<Caller> register(DataExtension extension);
|
||||
|
||||
/**
|
||||
* Unregister your {@link DataExtension} implementation.
|
||||
* <p>
|
||||
* This method should be used if calling methods on the DataExtension suddenly becomes unavailable, due to
|
||||
* plugin disable for example.
|
||||
*
|
||||
* @param extension Your DataExtension implementation that was registered before.
|
||||
*/
|
||||
void unregister(DataExtension extension);
|
||||
|
||||
class ExtensionServiceHolder {
|
||||
static ExtensionService service;
|
||||
|
||||
private ExtensionServiceHolder() {
|
||||
/* Static variable holder */
|
||||
}
|
||||
|
||||
static void set(ExtensionService service) {
|
||||
ExtensionServiceHolder.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum for determining additional formatter for a value given by a {@link com.djrapitops.plan.extension.annotation.NumberProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum FormatType {
|
||||
|
||||
/**
|
||||
* Formats a long value (Epoch ms) to a readable timestamp, year is important.
|
||||
*/
|
||||
DATE_YEAR,
|
||||
/**
|
||||
* Formats a long value (Epoch ms) to a readable timestamp, second is important.
|
||||
*/
|
||||
DATE_SECOND,
|
||||
/**
|
||||
* Formats a long value (ms) to a readable format.
|
||||
*/
|
||||
TIME_MILLISECONDS,
|
||||
/**
|
||||
* Applies no formatting to the value.
|
||||
*/
|
||||
NONE;
|
||||
|
||||
public static Optional<FormatType> getByName(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Method parameter for providing values about a group with provider annotations.
|
||||
* <p>
|
||||
* Usage Example: {@code @StringProvider String provideStringAboutGroup(Group group)}
|
||||
* <p>
|
||||
* Group names of users are provided with {@code @GroupProvider String[] provideGroups(UUID playerUUID)}
|
||||
* {@code Group} parameter methods are not called without knowledge of a group name.
|
||||
* <p>
|
||||
* This method parameter is used since it is not possible to differentiate String playerName and String groupName.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Group {
|
||||
|
||||
String getGroupName();
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Exception to throw inside DataExtension if a method is not ready to be called (Data is not available etc).
|
||||
* <p>
|
||||
* This Exception will not cause Plan to "yell" about the exception.
|
||||
* <p>
|
||||
* Requires Capability#DATA_EXTENSION_NOT_READY_EXCEPTION.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class NotReadyException extends IllegalStateException {
|
||||
|
||||
/**
|
||||
* Construct the exception.
|
||||
* <p>
|
||||
* The Exception is not logged (Fails silently) so no message is available.
|
||||
*/
|
||||
public NotReadyException() {
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a boolean value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @BooleanProvider boolean method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The provided boolean can be used as a condition for calls to other Provider
|
||||
* methods by defining the name of the condition and using {@link Conditional}
|
||||
* on the other method with a Provider annotation.
|
||||
* <p>
|
||||
* For example:
|
||||
* {@code @BooleanProvider(condition="example") boolean condition(UUID playerUUID);}
|
||||
* {@code @Conditional("example") @NumberProvider long someValue(UUID playerUUID);}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface BooleanProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Banned", "Has Island"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Boat", description: "Whether or not the player is on a boat."
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of the {@link Conditional} condition limited to 50 characters.
|
||||
*
|
||||
* @return Case sensitive string of max 50 characters.
|
||||
*/
|
||||
String conditionName() default "";
|
||||
|
||||
/**
|
||||
* Should the result of this method be hidden from the user.
|
||||
*
|
||||
* @return true if the value should not be displayed on the page.
|
||||
*/
|
||||
boolean hidden() default false;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
/**
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
* <p>
|
||||
* If {@link BooleanProvider#hidden()} is {@code true} then this value will not be shown in the table regardless of the value of this parameter.
|
||||
*
|
||||
* @return false by default.
|
||||
*/
|
||||
boolean showInPlayerTable() default false;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method Annotation to determine that a method can not be called unless a condition is fulfilled.
|
||||
* <p>
|
||||
* Condition information is provided with {@link com.djrapitops.plan.extension.annotation.BooleanProvider}.
|
||||
* If {@link com.djrapitops.plan.extension.annotation.BooleanProvider} for the condition is not specified the
|
||||
* method tagged with this annotation will not be called, (Condition is assumed false).
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Conditional {
|
||||
|
||||
/**
|
||||
* Name of the condition limited to 50 characters.
|
||||
*
|
||||
* @return Case sensitive string of max 50 characters.
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* Reverse the condition.
|
||||
* <p>
|
||||
* Example:
|
||||
* - Method with {@code Conditional("expires", negated = true)} will only be called when the condition "expires" is false.
|
||||
*
|
||||
* @return {@code false} by default.
|
||||
*/
|
||||
boolean negated() default false;
|
||||
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a double value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @DoubleProvider double method(UUID playerUUID)}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DoubleProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Distance from spawn", "Balance"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Balance", description: "Economy balance of the player"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
/**
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
*
|
||||
* @return false by default.
|
||||
*/
|
||||
boolean showInPlayerTable() default false;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation used to invalidate old method values.
|
||||
* <p>
|
||||
* The name of the methods are used as an identifier in the database, so that a single provider does not duplicate entries.
|
||||
* Only first 50 characters of the method name are stored.
|
||||
* If you need to change a method name add this class annotation with the old method name.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(InvalidateMethod.Multiple.class)
|
||||
public @interface InvalidateMethod {
|
||||
|
||||
/**
|
||||
* Name of the old method, values of which should be removed from the database.
|
||||
*
|
||||
* @return Name of the old method, case sensitive. Only first 50 characters are used.
|
||||
*/
|
||||
String value();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface Multiple {
|
||||
|
||||
InvalidateMethod[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a long (64bit number) value about a Player.
|
||||
* <p>
|
||||
* If you want to return int values, use this provider with a long as
|
||||
* return type of the method.
|
||||
* <p>
|
||||
* Usage: {@code @NumberProvider long method(UUID playerUUID)}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface NumberProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Owned Chickens", "Claimed Blocks"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Fished", description: "How long the player has fished for"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Apply special formatting to the value before presentation.
|
||||
*
|
||||
* @return {@link FormatType} that best represents the long value.
|
||||
* @see FormatType for available formatters.
|
||||
*/
|
||||
FormatType format() default FormatType.NONE;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
/**
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
*
|
||||
* @return false by default.
|
||||
*/
|
||||
boolean showInPlayerTable() default false;
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a double (Percentage) about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @PercentageProvider double method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The returned value should be between (or one of) 0.0 (0%) and 1.0 (100%).
|
||||
* Other values will be ignored.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface PercentageProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Health", "Power"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Power", description: "Faction power, affects ability of faction to perform actions. Regenerates"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
/**
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
*
|
||||
* @return false by default.
|
||||
*/
|
||||
boolean showInPlayerTable() default false;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Class Annotation for informing Plan about a plugin.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see TabOrder to determine preferred tab ordering if you use {@link Tab}s.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface PluginInfo {
|
||||
|
||||
/**
|
||||
* Name of the plugin, limited to 50 characters.
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "cube";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color color() default Color.NONE;
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a String value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @StringProvider String method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The returned value is limited to 100 characters, remainder will be clipped.
|
||||
* <p>
|
||||
* If the value is a player name, provide value for playerName=true.
|
||||
* This will allow linking between pages.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface StringProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Town Name", "Pet Name"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Power", description: "Faction power, affects ability of faction to perform actions. Regenerates"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Determine if this value represents a Player name, for example a mayor of a town.
|
||||
*
|
||||
* @return {@code true} if the name can be used as a link to another player's page.
|
||||
*/
|
||||
boolean playerName() default false;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
/**
|
||||
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
|
||||
*
|
||||
* @return false by default.
|
||||
*/
|
||||
boolean showInPlayerTable() default false;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method Annotation for determining Tab the given element should appear on.
|
||||
* <p>
|
||||
* If not specified Plan places the item on the default tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see TabInfo if you want to determine an icon or element order for a Tab.
|
||||
* @see TabOrder to determine preferred tab ordering if you use Tabs.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Tab {
|
||||
|
||||
/**
|
||||
* Name of the tab to place this item on.
|
||||
*
|
||||
* @return Tab name, limited to 50 characters.
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Class Annotation that allows determining an Icon and {@link ElementOrder} of a tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(TabInfo.Multiple.class)
|
||||
public @interface TabInfo {
|
||||
|
||||
/**
|
||||
* Name of the tab this information is about.
|
||||
*
|
||||
* @return Tab name, limited to 50 characters.
|
||||
*/
|
||||
String tab();
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "circle";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Order preference for the large elements of a tab.
|
||||
* <p>
|
||||
* If an ordering is not present they will be added to the end in the default order.
|
||||
* If a duplicate ordering exists only the first will be used for determining the order.
|
||||
*
|
||||
* @return ElementOrders in the order that they want to be displayed in.
|
||||
*/
|
||||
ElementOrder[] elementOrder();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface Multiple {
|
||||
TabInfo[] value();
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Class Annotation for informing Plan about plugin's tab order preference.
|
||||
* <p>
|
||||
* If tab order is not defined alphabetical order is used.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface TabOrder {
|
||||
|
||||
/**
|
||||
* Order preference of different {@link Tab}s.
|
||||
* <p>
|
||||
* If a tab is defined that is not present it is ignored.
|
||||
* If a tab is not defined but is present alphabetical order is used.
|
||||
*
|
||||
* @return Names of the defined tabs (case sensitive).
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a Table.
|
||||
* <p>
|
||||
* Usage: {@code @TableProvider Table method(UUID playerUUID)}
|
||||
* <p>
|
||||
* Tables about players can have up to 4 columns.
|
||||
* Tables about server can have up to 5 columns.
|
||||
* <p>
|
||||
* It is recommended to place each table on their own tab with a {@link Tab} annotation on the same method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface TableProvider {
|
||||
|
||||
/**
|
||||
* Determine the color of the table header.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color tableColor() default Color.NONE;
|
||||
|
||||
}
|
@ -1,373 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.Group;
|
||||
import com.djrapitops.plan.extension.annotation.*;
|
||||
import com.djrapitops.plan.extension.table.Table;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Implementation detail, for extracting methods from {@link com.djrapitops.plan.extension.DataExtension}.
|
||||
* <p>
|
||||
* This class can be used for testing validity of annotation implementations
|
||||
* in your unit tests to avoid runtime errors. {@link ExtensionExtractor#validateAnnotations()}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public final class ExtensionExtractor {
|
||||
|
||||
private final DataExtension extension;
|
||||
private final String extensionName;
|
||||
|
||||
private final List<String> warnings = new ArrayList<>();
|
||||
|
||||
private PluginInfo pluginInfo;
|
||||
private TabOrder tabOrder;
|
||||
private List<TabInfo> tabInformation;
|
||||
private List<InvalidateMethod> invalidMethods;
|
||||
private MethodAnnotations methodAnnotations;
|
||||
|
||||
private static final String WAS_OVER_50_CHARACTERS = "' was over 50 characters.";
|
||||
|
||||
public ExtensionExtractor(DataExtension extension) {
|
||||
this.extension = extension;
|
||||
extensionName = extension.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method in an unit test to validate your DataExtension.
|
||||
*
|
||||
* @throws IllegalArgumentException If an implementation error is found.
|
||||
*/
|
||||
public void validateAnnotations() {
|
||||
extractAnnotationInformation();
|
||||
|
||||
if (!warnings.isEmpty()) {
|
||||
throw new IllegalArgumentException("Warnings: " + warnings.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Annotation> Optional<T> getClassAnnotation(Class<T> ofClass) {
|
||||
return Optional.ofNullable(extension.getClass().getAnnotation(ofClass));
|
||||
}
|
||||
|
||||
private Method[] getMethods() {
|
||||
return extension.getClass().getMethods();
|
||||
}
|
||||
|
||||
public void extractAnnotationInformation() {
|
||||
extractPluginInfo();
|
||||
extractInvalidMethods();
|
||||
|
||||
extractMethodAnnotations();
|
||||
validateMethodAnnotations();
|
||||
|
||||
validateConditionals();
|
||||
|
||||
extractTabInfo();
|
||||
}
|
||||
|
||||
private void extractMethodAnnotations() {
|
||||
methodAnnotations = new MethodAnnotations();
|
||||
|
||||
for (Method method : getMethods()) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (!Modifier.isPublic(modifiers)
|
||||
|| Modifier.isStatic(modifiers)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodAnnotations.get(method, BooleanProvider.class).ifPresent(annotation -> methodAnnotations.put(method, BooleanProvider.class, annotation));
|
||||
MethodAnnotations.get(method, NumberProvider.class).ifPresent(annotation -> methodAnnotations.put(method, NumberProvider.class, annotation));
|
||||
MethodAnnotations.get(method, DoubleProvider.class).ifPresent(annotation -> methodAnnotations.put(method, DoubleProvider.class, annotation));
|
||||
MethodAnnotations.get(method, PercentageProvider.class).ifPresent(annotation -> methodAnnotations.put(method, PercentageProvider.class, annotation));
|
||||
MethodAnnotations.get(method, StringProvider.class).ifPresent(annotation -> methodAnnotations.put(method, StringProvider.class, annotation));
|
||||
|
||||
MethodAnnotations.get(method, Conditional.class).ifPresent(annotation -> methodAnnotations.put(method, Conditional.class, annotation));
|
||||
MethodAnnotations.get(method, Tab.class).ifPresent(annotation -> methodAnnotations.put(method, Tab.class, annotation));
|
||||
|
||||
MethodAnnotations.get(method, TableProvider.class).ifPresent(annotation -> methodAnnotations.put(method, TableProvider.class, annotation));
|
||||
}
|
||||
|
||||
if (methodAnnotations.isEmpty()) {
|
||||
throw new IllegalArgumentException(extensionName + " class had no methods annotated with a Provider annotation");
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void validateReturnType(Method method, Class<T> expectedType) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!expectedType.isAssignableFrom(returnType)) {
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has invalid return type. was: " + returnType.getName() + ", expected: " + expectedType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodAnnotationPropertyLength(String property, String name, int maxLength, Method method) {
|
||||
if (property.length() > maxLength) {
|
||||
warnings.add(extensionName + "." + method.getName() + " '" + name + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodArguments(Method method, boolean parameterIsRequired, Class... parameterOptions) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
// Possible parameters for the methods:
|
||||
// UUID playerUUID, String playerName, Group group, none
|
||||
|
||||
int parameters = parameterTypes.length;
|
||||
|
||||
if (parameterIsRequired && parameters == 0) {
|
||||
// Does not have parameters, but one is required
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " requires one of " + Arrays.toString(parameterOptions) + " as a parameter.");
|
||||
} else if (parameters == 0) {
|
||||
// Has no parameters & it is acceptable.
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameters > 1) {
|
||||
// Has too many parameters
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has too many parameters, only one of " + Arrays.toString(parameterOptions) + " is required as a parameter.");
|
||||
}
|
||||
|
||||
Class<?> methodParameter = parameterTypes[0];
|
||||
|
||||
boolean validParameter = false;
|
||||
for (Class option : parameterOptions) {
|
||||
if (option.equals(methodParameter)) {
|
||||
validParameter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validParameter) {
|
||||
// Has invalid parameter
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has invalid parameter: '" + methodParameter.getName() + "' one of " + Arrays.toString(parameterOptions) + " is required as a parameter.");
|
||||
}
|
||||
// Has valid parameter & it is acceptable.
|
||||
}
|
||||
|
||||
private void validateMethodAnnotations() {
|
||||
validateBooleanProviderAnnotations();
|
||||
validateNumberProviderAnnotations();
|
||||
validateDoubleProviderAnnotations();
|
||||
validatePercentageProviderAnnotations();
|
||||
validateStringProviderAnnotations();
|
||||
validateTableProviderAnnotations();
|
||||
}
|
||||
|
||||
private void validateBooleanProviderAnnotations() {
|
||||
for (Map.Entry<Method, BooleanProvider> booleanProvider : methodAnnotations.getMethodAnnotations(BooleanProvider.class).entrySet()) {
|
||||
Method method = booleanProvider.getKey();
|
||||
BooleanProvider annotation = booleanProvider.getValue();
|
||||
|
||||
validateReturnType(method, boolean.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.conditionName(), "conditionName", 50, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
|
||||
String condition = MethodAnnotations.get(method, Conditional.class).map(Conditional::value).orElse(null);
|
||||
if (annotation.conditionName().equals(condition)) {
|
||||
warnings.add(extensionName + "." + method.getName() + " can not be conditional of itself. required condition: " + condition + ", provided condition: " + annotation.conditionName());
|
||||
}
|
||||
|
||||
if (annotation.conditionName().isEmpty() && annotation.hidden()) {
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " can not be 'hidden' without a 'conditionName'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNumberProviderAnnotations() {
|
||||
for (Map.Entry<Method, NumberProvider> numberProvider : methodAnnotations.getMethodAnnotations(NumberProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
NumberProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, long.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDoubleProviderAnnotations() {
|
||||
for (Map.Entry<Method, DoubleProvider> numberProvider : methodAnnotations.getMethodAnnotations(DoubleProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
DoubleProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, double.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePercentageProviderAnnotations() {
|
||||
for (Map.Entry<Method, PercentageProvider> numberProvider : methodAnnotations.getMethodAnnotations(PercentageProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
PercentageProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, double.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateStringProviderAnnotations() {
|
||||
for (Map.Entry<Method, StringProvider> numberProvider : methodAnnotations.getMethodAnnotations(StringProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
StringProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, String.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTableProviderAnnotations() {
|
||||
for (Method method : methodAnnotations.getMethodAnnotations(TableProvider.class).keySet()) {
|
||||
validateReturnType(method, Table.class);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateConditionals() {
|
||||
Collection<Conditional> conditionals = methodAnnotations.getAnnotations(Conditional.class);
|
||||
Collection<BooleanProvider> conditionProviders = methodAnnotations.getAnnotations(BooleanProvider.class);
|
||||
|
||||
Set<String> providedConditions = conditionProviders.stream().map(BooleanProvider::conditionName).collect(Collectors.toSet());
|
||||
|
||||
for (Conditional condition : conditionals) {
|
||||
String conditionName = condition.value();
|
||||
|
||||
if (conditionName.length() > 50) {
|
||||
warnings.add(extensionName + ": '" + conditionName + "' conditionName was over 50 characters.");
|
||||
}
|
||||
|
||||
if (!providedConditions.contains(conditionName)) {
|
||||
warnings.add(extensionName + ": '" + conditionName + "' Condition was not provided by any BooleanProvider.");
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that all methods annotated with Conditional have a Provider annotation
|
||||
Collection<Method> conditionalMethods = methodAnnotations.getMethodAnnotations(Conditional.class).keySet();
|
||||
for (Method conditionalMethod : conditionalMethods) {
|
||||
if (!MethodAnnotations.hasAnyOf(conditionalMethod,
|
||||
BooleanProvider.class, DoubleProvider.class, NumberProvider.class,
|
||||
PercentageProvider.class, StringProvider.class
|
||||
)) {
|
||||
throw new IllegalArgumentException(extensionName + "." + conditionalMethod.getName() + " did not have any associated Provider for Conditional.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractPluginInfo() {
|
||||
pluginInfo = getClassAnnotation(PluginInfo.class).orElseThrow(() -> new IllegalArgumentException("Given class had no PluginInfo annotation"));
|
||||
|
||||
if (pluginInfo.name().length() > 50) {
|
||||
warnings.add(extensionName + " PluginInfo 'name' was over 50 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTabInfo() {
|
||||
tabInformation = new ArrayList<>();
|
||||
getClassAnnotation(TabInfo.Multiple.class).ifPresent(tabs -> {
|
||||
for (TabInfo tabInfo : tabs.value()) {
|
||||
String tabName = tabInfo.tab();
|
||||
|
||||
// Length restriction check
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + " tabName '" + tabName + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
|
||||
tabInformation.add(tabInfo);
|
||||
}
|
||||
});
|
||||
|
||||
tabOrder = getClassAnnotation(TabOrder.class).orElse(null);
|
||||
|
||||
Map<Method, Tab> tabs = this.methodAnnotations.getMethodAnnotations(Tab.class);
|
||||
Set<String> tabNames = tabs.values().stream().map(Tab::value).collect(Collectors.toSet());
|
||||
|
||||
// Check for unused TabInfo annotations
|
||||
for (TabInfo tabInfo : tabInformation) {
|
||||
String tabName = tabInfo.tab();
|
||||
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + " TabInfo " + tabName + " name was over 50 characters.");
|
||||
}
|
||||
|
||||
if (!tabNames.contains(tabName)) {
|
||||
warnings.add(extensionName + " has TabInfo for " + tabName + ", but it is not used.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check Tab name lengths
|
||||
for (Map.Entry<Method, Tab> tab : tabs.entrySet()) {
|
||||
String tabName = tab.getValue().value();
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + "." + tab.getKey().getName() + " Tab '" + tabName + "' name was over 50 characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractInvalidMethods() {
|
||||
invalidMethods = new ArrayList<>();
|
||||
getClassAnnotation(InvalidateMethod.Multiple.class).ifPresent(tabs -> {
|
||||
for (InvalidateMethod tabInfo : tabs.value()) {
|
||||
String methodName = tabInfo.value();
|
||||
|
||||
// Length restriction check
|
||||
if (methodName.length() > 50) {
|
||||
warnings.add(extensionName + " invalidated method '" + methodName + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
|
||||
invalidMethods.add(tabInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
public PluginInfo getPluginInfo() {
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
public Optional<TabOrder> getTabOrder() {
|
||||
return Optional.ofNullable(tabOrder);
|
||||
}
|
||||
|
||||
public List<TabInfo> getTabInformation() {
|
||||
return tabInformation != null ? tabInformation : Collections.emptyList();
|
||||
}
|
||||
|
||||
public MethodAnnotations getMethodAnnotations() {
|
||||
return methodAnnotations;
|
||||
}
|
||||
|
||||
public List<InvalidateMethod> getInvalidateMethodAnnotations() {
|
||||
return invalidMethods != null ? invalidMethods : Collections.emptyList();
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Implementation detail, utility class for handling method annotations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class MethodAnnotations {
|
||||
|
||||
private final Map<Class, Map<Method, Annotation>> byAnnotationType;
|
||||
|
||||
public MethodAnnotations() {
|
||||
byAnnotationType = new HashMap<>();
|
||||
}
|
||||
|
||||
public static boolean hasAnyOf(Method method, Class... annotationClasses) {
|
||||
for (Annotation annotation : method.getAnnotations()) {
|
||||
for (Class annotationClass : annotationClasses) {
|
||||
if (annotationClass.isAssignableFrom(annotation.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> Optional<T> get(Method from, Class<T> ofClass) {
|
||||
return Optional.ofNullable(from.getAnnotation(ofClass));
|
||||
}
|
||||
|
||||
public <T extends Annotation> void put(Method method, Class<T> annotationClass, T annotation) {
|
||||
Map<Method, Annotation> methods = byAnnotationType.getOrDefault(annotationClass, new HashMap<>());
|
||||
methods.put(method, annotation);
|
||||
byAnnotationType.put(annotationClass, methods);
|
||||
}
|
||||
|
||||
public <T extends Annotation> Map<Method, T> getMethodAnnotations(Class<T> ofType) {
|
||||
return (Map<Method, T>) byAnnotationType.getOrDefault(ofType, new HashMap<>());
|
||||
}
|
||||
|
||||
public <T extends Annotation> Collection<T> getAnnotations(Class<T> ofType) {
|
||||
return getMethodAnnotations(ofType).values();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return byAnnotationType.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodAnnotations{" + byAnnotationType + '}';
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum to determine what color to use for some element.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum Color {
|
||||
|
||||
RED,
|
||||
PINK,
|
||||
PURPLE,
|
||||
DEEP_PURPLE,
|
||||
INDIGO,
|
||||
BLUE,
|
||||
LIGHT_BLUE,
|
||||
CYAN,
|
||||
TEAL,
|
||||
GREEN,
|
||||
LIGHT_GREEN,
|
||||
LIME,
|
||||
YELLOW,
|
||||
AMBER,
|
||||
ORANGE,
|
||||
DEEP_ORANGE,
|
||||
BROWN,
|
||||
GREY,
|
||||
BLUE_GREY,
|
||||
BLACK,
|
||||
NONE;
|
||||
|
||||
public static Optional<Color> getByName(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum to determine font-awesome icon family.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum Family {
|
||||
SOLID,
|
||||
REGULAR,
|
||||
BRAND;
|
||||
|
||||
public static Optional<Family> getByName(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
/**
|
||||
* Object that represents an icon on the website.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons (select 'free')) for icons and their {@link Family}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Icon {
|
||||
|
||||
private Family type;
|
||||
private String name;
|
||||
private Color color;
|
||||
|
||||
private Icon() {
|
||||
type = Family.SOLID;
|
||||
color = Color.NONE;
|
||||
}
|
||||
|
||||
public Icon(Family type, String name, Color color) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static Builder called(String name) {
|
||||
return new Builder().called(name);
|
||||
}
|
||||
|
||||
public static Builder of(Family type) {
|
||||
return new Builder().of(type);
|
||||
}
|
||||
|
||||
public static Builder of(Color color) {
|
||||
return new Builder().of(color);
|
||||
}
|
||||
|
||||
public Family getFamily() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Icon setColor(Color color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Icon{" + type.name() + ", '" + name + '\'' + ", " + color.name() + '}';
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Icon icon;
|
||||
|
||||
Builder() {
|
||||
this.icon = new Icon();
|
||||
}
|
||||
|
||||
public Builder called(String name) {
|
||||
icon.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder of(Color color) {
|
||||
icon.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder of(Family type) {
|
||||
icon.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Icon build() {
|
||||
if (icon.name == null) {
|
||||
throw new IllegalStateException("'name' was not defined yet!");
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.table;
|
||||
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Object for giving Plan table data.
|
||||
* <p>
|
||||
* Usage: {@code Table.builder().columnOne("columnName", new Icon(...)).addRow("Your", "Row", "Data").build()}
|
||||
* <p>
|
||||
* Tables about players can have up to 4 columns.
|
||||
* Tables about server can have up to 5 columns.
|
||||
* <p>
|
||||
* Icon colors are ignored.
|
||||
* <p>
|
||||
* If a row has more values than the column limit, they are ignored.
|
||||
* If a row has less values than table columns, a '-' is displayed to distinguish a missing value.
|
||||
* <p>
|
||||
* If a table has no columns or rows, it is ignored.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.extension.annotation.TableProvider for associated annotation.
|
||||
*/
|
||||
public final class Table {
|
||||
|
||||
private final String[] columns;
|
||||
private final Icon[] icons;
|
||||
|
||||
private final List<Object[]> rows;
|
||||
|
||||
private Table() {
|
||||
/* Tables are constructed with the factory. */
|
||||
|
||||
columns = new String[5];
|
||||
icons = new Icon[5];
|
||||
rows = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Table Factory.
|
||||
*
|
||||
* @return a new Table Factory.
|
||||
*/
|
||||
public static Table.Factory builder() {
|
||||
return new Table.Factory();
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public int getMaxColumnSize() {
|
||||
int columnCount = 0;
|
||||
for (String column : columns) {
|
||||
if (column == null) {
|
||||
break; // Prevent having one null column between two columns
|
||||
}
|
||||
columnCount++;
|
||||
}
|
||||
return columnCount;
|
||||
}
|
||||
|
||||
public Icon[] getIcons() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
public List<Object[]> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating new {@link Table} objects.
|
||||
*/
|
||||
public static final class Factory {
|
||||
|
||||
private final Table building;
|
||||
|
||||
// These variable are related to implementation, and is used when the table is being fetched from the database.
|
||||
Color color; // Table color is defined with TableProvider annotation.
|
||||
String tableName; // tableName is defined by method name annotated by TableProvider.
|
||||
String tabName; // Tab name is defined with Tab annotation
|
||||
int tabPriority; // Tab priority is defined with TabOrder annotation
|
||||
ElementOrder[] tabOrder; // Tab element order is defined with TabInfo annotation
|
||||
Icon tabIcon; // Tab icon is defined with TabInfo annotation
|
||||
|
||||
private Factory() {
|
||||
building = new Table();
|
||||
}
|
||||
|
||||
private Factory column(int indx, String columnName, Icon icon) {
|
||||
building.columns[indx] = columnName;
|
||||
building.icons[indx] = icon != null ? Icon.called(icon.getName()).of(icon.getFamily()).build() : Icon.called("question").build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set first column name and icon.
|
||||
*
|
||||
* @param columnName Name of the column.
|
||||
* @param icon Icon of the column, color is ignored.
|
||||
* @return Factory.
|
||||
*/
|
||||
public Factory columnOne(String columnName, Icon icon) {
|
||||
return column(0, columnName, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set second column name and icon.
|
||||
*
|
||||
* @param columnName Name of the column.
|
||||
* @param icon Icon of the column, color is ignored.
|
||||
* @return Factory.
|
||||
*/
|
||||
public Factory columnTwo(String columnName, Icon icon) {
|
||||
return column(1, columnName, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set third column name and icon.
|
||||
*
|
||||
* @param columnName Name of the column.
|
||||
* @param icon Icon of the column, color is ignored.
|
||||
* @return Factory.
|
||||
*/
|
||||
public Factory columnThree(String columnName, Icon icon) {
|
||||
return column(2, columnName, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fourth column name and icon.
|
||||
*
|
||||
* @param columnName Name of the column.
|
||||
* @param icon Icon of the column, color is ignored.
|
||||
* @return Factory.
|
||||
*/
|
||||
public Factory columnFour(String columnName, Icon icon) {
|
||||
return column(3, columnName, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set fifth column name and icon.
|
||||
*
|
||||
* @param columnName Name of the column.
|
||||
* @param icon Icon of the column, color is ignored.
|
||||
* @return Factory.
|
||||
*/
|
||||
public Factory columnFive(String columnName, Icon icon) {
|
||||
return column(4, columnName, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a row of values to the table.
|
||||
*
|
||||
* @param values One value per column you have defined, {@code Object#toString()} will be called on the objects.
|
||||
* @return Factory.
|
||||
* @throws IllegalArgumentException If given varargs for 'values' is null.
|
||||
*/
|
||||
public Factory addRow(Object... values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("'values' for Table#addRow can not be null!");
|
||||
}
|
||||
|
||||
if (values.length == 0 || areAllValuesNull(values)) {
|
||||
return this; // Ignore row when all values are null or no values are present.
|
||||
}
|
||||
|
||||
building.rows.add(Arrays.copyOf(values, 5));
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean areAllValuesNull(Object[] values) {
|
||||
boolean allNull = true;
|
||||
for (Object value : values) {
|
||||
if (value != null) {
|
||||
allNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return allNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish building the table.
|
||||
*
|
||||
* @return Finished Table object.
|
||||
*/
|
||||
public Table build() {
|
||||
return building;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.query;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Class that allows performing most commonly wanted queries.
|
||||
* <p>
|
||||
* This exists so that SQL does not necessarily need to be written.
|
||||
* Obtain an instance from {@link QueryService}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface CommonQueries {
|
||||
|
||||
/**
|
||||
* Fetch playtime of a player on a server.
|
||||
* <p>
|
||||
* Returns 0 for any non existing players or servers.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @param after Data after this Epoch ms should be fetched
|
||||
* @param before Data before this Epoch ms should be fetched
|
||||
* @return Milliseconds the player has played with the defined parameters.
|
||||
*/
|
||||
long fetchPlaytime(UUID playerUUID, UUID serverUUID, long after, long before);
|
||||
|
||||
/**
|
||||
* Fetch last seen Epoch ms for a player on a server.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @return Epoch ms the player was last seen, 0 if player has not played on server.
|
||||
*/
|
||||
long fetchLastSeen(UUID playerUUID, UUID serverUUID);
|
||||
|
||||
Set<UUID> fetchServerUUIDs();
|
||||
|
||||
Optional<UUID> fetchUUIDOf(String playerName);
|
||||
|
||||
Optional<String> fetchNameOf(UUID playerUUID);
|
||||
|
||||
boolean doesDBHaveTable(String table);
|
||||
|
||||
boolean doesDBHaveTableColumn(String table, String column);
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.query;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Service for Query API.
|
||||
* <p>
|
||||
* Requires Capability QUERY_API
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface QueryService {
|
||||
|
||||
/**
|
||||
* Obtain instance of QueryService.
|
||||
*
|
||||
* @return QueryService implementation.
|
||||
* @throws NoClassDefFoundError If Plan is not installed and this class can not be found or if older Plan version is installed.
|
||||
* @throws IllegalStateException If Plan is installed, but not enabled.
|
||||
*/
|
||||
static QueryService getInstance() {
|
||||
return Optional.ofNullable(QueryService.QueryServiceHolder.service)
|
||||
.orElseThrow(() -> new IllegalStateException("QueryService has not been initialised yet."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get what kind of database is in use.
|
||||
*
|
||||
* @return H2, SQLITE or MYSQL
|
||||
* @throws IllegalStateException If database has not been initialized (Plugin failed to enable)
|
||||
*/
|
||||
String getDBType();
|
||||
|
||||
/**
|
||||
* Perform a query against Plan database.
|
||||
* <p>
|
||||
* Blocks thread until query is complete.
|
||||
*
|
||||
* @param sql SQL String to execute, can contain parameterized queries ({@code ?}).
|
||||
* @param performQuery set your parameters to the PreparedStatement and execute the query, return results.
|
||||
* @param <T> Type of results.
|
||||
* @return The object returned by {@code results}.
|
||||
* @throws IllegalStateException If something goes wrong with the query. SQLException might be as cause.
|
||||
*/
|
||||
<T> T query(
|
||||
String sql,
|
||||
ThrowingFunction<PreparedStatement, T> performQuery
|
||||
) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Execute SQL against Plan database.
|
||||
* <p>
|
||||
* Does not block thread, SQL is executed in a single transaction to the database.
|
||||
* <p>
|
||||
* Differs from {@link QueryService#query(String, ThrowingFunction)} in that no results are returned.
|
||||
*
|
||||
* @param sql SQL String to execute, can contain parameterized queries ({@code ?}).
|
||||
* @param performStatement set your parameters to the PreparedStatement and execute the statement.
|
||||
* @return A Future that tells when the transaction has completed. Blocks thread if Future#get is called.
|
||||
* @throws IllegalStateException If something goes wrong with the query. SQLException might be as cause.
|
||||
*/
|
||||
Future<?> execute(
|
||||
String sql,
|
||||
ThrowingConsumer<PreparedStatement> performStatement
|
||||
) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Used for getting notified about removal of player data.
|
||||
* <p>
|
||||
* SQL for removing this player's data should be executed when this occurs.
|
||||
* <p>
|
||||
* Example usage:
|
||||
* {@code subscribeToPlayerRemoveEvent(playerUUID -> { do stuff })}
|
||||
*
|
||||
* @param eventListener Functional interface that is called on the event.
|
||||
*/
|
||||
void subscribeToPlayerRemoveEvent(Consumer<UUID> eventListener);
|
||||
|
||||
/**
|
||||
* Used for getting notified about removal of ALL data.
|
||||
* <p>
|
||||
* SQL for removing all extra tables (and data) should be performed
|
||||
* <p>
|
||||
* Example usage:
|
||||
* {@code subscribeDataClearEvent(() -> { do stuff })}
|
||||
*
|
||||
* @param eventListener Functional interface that is called on the event.
|
||||
*/
|
||||
void subscribeDataClearEvent(VoidFunction eventListener);
|
||||
|
||||
/**
|
||||
* Get the UUID of this server.
|
||||
*
|
||||
* @return Optinal of the server UUID, empty if server did not start properly.
|
||||
*/
|
||||
Optional<UUID> getServerUUID();
|
||||
|
||||
/**
|
||||
* Perform some commonly wanted queries.
|
||||
*
|
||||
* @return {@link CommonQueries} implementation.
|
||||
* @throws IllegalStateException If database has not been initialized (Plugin failed to enable)
|
||||
*/
|
||||
CommonQueries getCommonQueries();
|
||||
|
||||
/**
|
||||
* See https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface ThrowingConsumer<T> {
|
||||
void accept(T t) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface ThrowingFunction<T, R> {
|
||||
R apply(T t) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface VoidFunction {
|
||||
void apply();
|
||||
}
|
||||
|
||||
class QueryServiceHolder {
|
||||
static QueryService service;
|
||||
|
||||
private QueryServiceHolder() {
|
||||
/* Static variable holder */
|
||||
}
|
||||
|
||||
static void set(QueryService service) {
|
||||
QueryService.QueryServiceHolder.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.annotation.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Tests for different validations of ExtensionExtractor.
|
||||
* <p>
|
||||
* This Test class contains only INVALID implementations of the DataExtension API.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@RunWith(JUnitPlatform.class)
|
||||
class ExtensionExtractorTest {
|
||||
|
||||
@Test
|
||||
void pluginInfoIsRequired() {
|
||||
class Extension implements DataExtension {}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Given class had no PluginInfo annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void providerMethodsAreRequired() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension class had no methods annotated with a Provider annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicProviderMethodsAreRequired() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
private boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension class had no methods annotated with a Provider annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pluginInfoNameOver50Chars() {
|
||||
@PluginInfo(name = "five five five five five five five five five five -")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Required Provider")
|
||||
public boolean method() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension PluginInfo 'name' was over 50 characters.]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderMustReturnBoolean() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
public String method(UUID playerUUID) {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.String, expected: boolean", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderMustReturnPrimitiveBoolean() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
public Boolean method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Boolean, expected: boolean", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void numberProviderMustReturnPrimitiveLong() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@NumberProvider(text = "Achievements")
|
||||
public Long method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Long, expected: long", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleProviderMustReturnPrimitiveDouble() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@DoubleProvider(text = "Money")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: double", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void percentageProviderMustReturnPrimitiveDouble() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@PercentageProvider(text = "Achievements awarded")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: double", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void stringProviderMustReturnString() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@StringProvider(text = "Town")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: java.lang.String", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableProviderMustReturnTable() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@TableProvider
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: com.djrapitops.plan.extension.table.Table", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderCanNotSupplyItsOwnConditional() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "hasJoined")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension.method can not be conditional of itself. required condition: hasJoined, provided condition: hasJoined]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void conditionalMethodRequiresProvider() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method did not have any associated Provider for Conditional.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void conditionalNeedsToBeProvided() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension: 'hasJoined' Condition was not provided by any BooleanProvider.]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNeedsValidParameters() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(Integer invalid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid parameter: 'java.lang.Integer' one of [class java.util.UUID, class java.lang.String, interface com.djrapitops.plan.extension.Group] is required as a parameter.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodHasTooManyParameters() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(String playerName, UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has too many parameters, only one of [class java.util.UUID, class java.lang.String, interface com.djrapitops.plan.extension.Group] is required as a parameter.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
// Aggregate Javadocs
|
||||
buildscript {
|
||||
repositories { jcenter() }
|
||||
dependencies {
|
||||
classpath 'com.netflix.nebula:gradle-aggregate-javadocs-plugin:2.2.+'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
id "jacoco"
|
||||
id "checkstyle"
|
||||
id "org.sonarqube" version "2.7"
|
||||
id "net.ltgt.apt" version "0.21"
|
||||
id "net.ltgt.apt-idea" version "0.21"
|
||||
id "com.github.johnrengelman.shadow" version "5.1.0"
|
||||
}
|
||||
|
||||
apply plugin: 'nebula-aggregate-javadocs'
|
||||
|
||||
allprojects {
|
||||
wrapper.gradleVersion = "5.0"
|
||||
|
||||
group "com.djrapitops"
|
||||
version "4.9.1"
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "failed"
|
||||
exceptionFormat "full"
|
||||
}
|
||||
}
|
||||
|
||||
// Fix for UTF-8 files showing with wrong encoding when compiled on Windows machines.
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
// Build plugins
|
||||
apply plugin: "java"
|
||||
apply plugin: "maven-publish"
|
||||
apply plugin: "net.ltgt.apt" // Annotation processing plugin
|
||||
apply plugin: "net.ltgt.apt-idea" // Annotation processing IntelliJ IDEA configuration plugin
|
||||
apply plugin: "com.github.johnrengelman.shadow"
|
||||
|
||||
// Report plugins
|
||||
apply plugin: "checkstyle"
|
||||
apply plugin: "jacoco"
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
ext.daggerVersion = "2.24"
|
||||
ext.daggerCompilerVersion = "2.24"
|
||||
|
||||
ext.abstractPluginFrameworkVersion = "3.4.1"
|
||||
ext.planPluginBridgeVersion = "4.9.0-R0.3"
|
||||
|
||||
ext.bukkitVersion = "1.12.2-R0.1-SNAPSHOT"
|
||||
ext.spigotVersion = "1.12.2-R0.1-SNAPSHOT"
|
||||
ext.paperVersion = "1.12.2-R0.1-SNAPSHOT"
|
||||
ext.spongeVersion = "7.1.0"
|
||||
ext.bungeeVersion = "1.12-SNAPSHOT"
|
||||
ext.velocityVersion = "1.0-SNAPSHOT"
|
||||
ext.redisBungeeVersion = "0.3.8-SNAPSHOT"
|
||||
|
||||
ext.httpClientVersion = "4.5.9"
|
||||
ext.commonsTextVersion = "1.7"
|
||||
ext.htmlCompressorVersion = "1.5.2"
|
||||
ext.caffeineVersion = "2.7.0"
|
||||
ext.h2Version = "1.4.199"
|
||||
ext.mysqlVersion = "8.0.17"
|
||||
ext.hikariVersion = "3.3.1"
|
||||
ext.slf4jVersion = "1.7.26"
|
||||
ext.geoIpVersion = "2.12.0"
|
||||
ext.guavaVersion = "28.0-jre"
|
||||
ext.bstatsVersion = "1.4"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { // Spigot Repository
|
||||
url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
|
||||
}
|
||||
maven { // Paper Repository
|
||||
url = "https://papermc.io/repo/repository/maven-public/"
|
||||
}
|
||||
maven { // Sponge Repository
|
||||
url = "https://repo.spongepowered.org/maven"
|
||||
}
|
||||
maven { // BungeeCord Repository
|
||||
url = "https://oss.sonatype.org/content/repositories/snapshots"
|
||||
}
|
||||
maven { // RedisBungee Repository
|
||||
url = "http://repo.md-5.net/content/repositories/snapshots/"
|
||||
}
|
||||
maven { // Velocity Repository
|
||||
url = "https://repo.velocitypowered.com/snapshots/"
|
||||
}
|
||||
maven { // bStats Repository
|
||||
url = "https://repo.codemc.org/repository/maven-public"
|
||||
}
|
||||
maven { // PlanPluginBridge Repository
|
||||
url = "https://dl.bintray.com/rsl1122/Plan-repository"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Dependency Injection used across the project
|
||||
compile "com.google.dagger:dagger:$daggerVersion"
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerCompilerVersion"
|
||||
testAnnotationProcessor "com.google.dagger:dagger-compiler:$daggerCompilerVersion"
|
||||
|
||||
// Test Tooling Dependencies
|
||||
testCompile "org.junit.jupiter:junit-jupiter-engine:5.5.1" // JUnit 5
|
||||
testCompile "org.junit.platform:junit-platform-runner:1.5.1" // JUnit 4 runner for JUnit 5 tests
|
||||
testCompile "org.junit.vintage:junit-vintage-engine:5.5.1" // JUnit 4 compatibility for JUnit 5
|
||||
testCompile "org.junit.jupiter:junit-jupiter-params:5.5.1" // JUnit 5, parameterized tests
|
||||
testCompile "org.mockito:mockito-core:3.0.0" // Mockito Core
|
||||
testCompile "org.mockito:mockito-junit-jupiter:3.0.0" // Mockito JUnit 5 Extension
|
||||
testCompile "org.seleniumhq.selenium:selenium-java:3.141.59" // Selenium (Browser tests)
|
||||
testCompile "com.jayway.awaitility:awaitility:1.7.0" // Awaitility (Concurrent wait conditions)
|
||||
|
||||
// Testing dependencies required by Plan
|
||||
testCompile "org.xerial:sqlite-jdbc:3.28.0" // SQLite
|
||||
testCompile "mysql:mysql-connector-java:$mysqlVersion" // MySQL
|
||||
}
|
||||
|
||||
configurations {
|
||||
testArtifacts.extendsFrom testRuntime
|
||||
}
|
||||
// Test classes available to other modules
|
||||
task testJar(type: Jar) {
|
||||
classifier "test"
|
||||
from sourceSets.test.output
|
||||
}
|
||||
artifacts {
|
||||
testArtifacts testJar
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
configFile rootProject.file('config/checkstyle/checkstyle.xml')
|
||||
}
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectName", "Player Analytics"
|
||||
property "sonar.projectKey", "com.djrapitops:Plan"
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
dependencies {
|
||||
compile project(path: ":common", configuration: 'shadow')
|
||||
|
||||
compile "com.djrapitops:AbstractPluginFramework-bukkit:$abstractPluginFrameworkVersion"
|
||||
compile "org.bstats:bstats-bukkit:$bstatsVersion"
|
||||
|
||||
// compileOnly "org.spigotmc:spigot-api:$spigotVersion"
|
||||
// compileOnly "org.bukkit:bukkit:$bukkitVersion"
|
||||
compileOnly "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
|
||||
// testCompile "org.spigotmc:spigot-api:$spigotVersion"
|
||||
// testCompile "org.bukkit:bukkit:$bukkitVersion"
|
||||
testCompile "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
|
||||
testCompile project(path: ":common", configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
configurations = [project.configurations.compile]
|
||||
|
||||
relocate 'org.bstats', 'com.djrapitops.plan.utilities.metrics'
|
||||
relocate 'org.slf4j', 'plan.org.slf4j'
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plugin.api.Check;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
|
||||
public class BStatsBukkit {
|
||||
|
||||
private final Plan plugin;
|
||||
private Metrics metrics;
|
||||
|
||||
public BStatsBukkit(Plan plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void registerMetrics() {
|
||||
if (metrics == null) {
|
||||
metrics = new Metrics(plugin);
|
||||
}
|
||||
registerConfigSettingGraphs();
|
||||
}
|
||||
|
||||
private void registerConfigSettingGraphs() {
|
||||
String serverType = plugin.getServer().getName();
|
||||
if ("CraftBukkit".equals(serverType) && Check.isSpigotAvailable()) {
|
||||
serverType = "Spigot";
|
||||
}
|
||||
String databaseType = plugin.getSystem().getDatabaseSystem().getDatabase().getType().getName();
|
||||
|
||||
addStringSettingPie("server_type", serverType);
|
||||
addStringSettingPie("database_type", databaseType);
|
||||
}
|
||||
|
||||
protected void addStringSettingPie(String id, String setting) {
|
||||
metrics.addCustomChart(new Metrics.SimplePie(id, () -> setting));
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.utilities.java.Reflection;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* ServerShutdownSave implementation for Bukkit based servers.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitServerShutdownSave extends ServerShutdownSave {
|
||||
|
||||
@Inject
|
||||
public BukkitServerShutdownSave(
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(locale, dbSystem, logger, errorHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkServerShuttingDownStatus() {
|
||||
try {
|
||||
return performCheck();
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchFieldError e) {
|
||||
logger.debug("Server shutdown check failed, using JVM ShutdownHook instead. Error: " + e.toString());
|
||||
return false; // ShutdownHook handles save in case this fails upon plugin disable.
|
||||
}
|
||||
}
|
||||
|
||||
private boolean performCheck() {
|
||||
// Special thanks to Fuzzlemann for figuring out the methods required for this check.
|
||||
// https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/769#issuecomment-433898242
|
||||
Class<?> minecraftServerClass = Reflection.getMinecraftClass("MinecraftServer");
|
||||
Object minecraftServer = Reflection.getField(minecraftServerClass, "SERVER", minecraftServerClass).get(null);
|
||||
|
||||
return Reflection.getField(minecraftServerClass, "isStopped", boolean.class).get(minecraftServer);
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.command.PlanCommand;
|
||||
import com.djrapitops.plan.command.commands.RegisterCommandFilter;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plan.system.settings.theme.PlanColorScheme;
|
||||
import com.djrapitops.plugin.BukkitPlugin;
|
||||
import com.djrapitops.plugin.benchmarking.Benchmark;
|
||||
import com.djrapitops.plugin.command.ColorScheme;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Main class for Bukkit that manages the plugin.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Plan extends BukkitPlugin implements PlanPlugin {
|
||||
|
||||
private PlanSystem system;
|
||||
private Locale locale;
|
||||
private ServerShutdownSave serverShutdownSave;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
PlanBukkitComponent component = DaggerPlanBukkitComponent.builder().plan(this).build();
|
||||
try {
|
||||
timings.start("Enable");
|
||||
system = component.system();
|
||||
serverShutdownSave = component.serverShutdownSave();
|
||||
locale = system.getLocaleSystem().getLocale();
|
||||
system.enable();
|
||||
|
||||
registerMetrics();
|
||||
|
||||
logger.debug("Verbose debug messages are enabled.");
|
||||
String benchTime = " (" + timings.end("Enable").map(Benchmark::toDurationString).orElse("-") + ")";
|
||||
logger.info(locale.getString(PluginLang.ENABLED) + benchTime);
|
||||
} catch (AbstractMethodError e) {
|
||||
logger.error("Plugin ran into AbstractMethodError - Server restart is required. Likely cause is updating the jar without a restart.");
|
||||
} catch (EnableException e) {
|
||||
logger.error("----------------------------------------");
|
||||
logger.error("Error: " + e.getMessage());
|
||||
logger.error("----------------------------------------");
|
||||
logger.error("Plugin Failed to Initialize Correctly. If this issue is caused by config settings you can use /plan reload");
|
||||
onDisable();
|
||||
} catch (Exception e) {
|
||||
Logger.getGlobal().log(Level.SEVERE, this.getClass().getSimpleName() + "-v" + getVersion(), e);
|
||||
logger.error("Plugin Failed to Initialize Correctly. If this issue is caused by config settings you can use /plan reload");
|
||||
logger.error("This error should be reported at https://github.com/Rsl1122/Plan-PlayerAnalytics/issues");
|
||||
onDisable();
|
||||
}
|
||||
PlanCommand command = component.planCommand();
|
||||
command.registerCommands();
|
||||
registerCommand("plan", command);
|
||||
new RegisterCommandFilter().registerFilter();
|
||||
if (system != null) {
|
||||
system.getProcessing().submitNonCritical(() -> system.getListenerSystem().callEnableEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMetrics() {
|
||||
Plan plugin = this;
|
||||
// Spigot 1.14 requires Sync events to be fired from a server thread.
|
||||
// Registering a service fires a sync event, and bStats registers a service,
|
||||
// so this has to be run on the server thread.
|
||||
runnableFactory.create("Register Metrics task", new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new BStatsBukkit(plugin).registerMetrics();
|
||||
}
|
||||
}).runTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorScheme getColorScheme() {
|
||||
return PlanColorScheme.create(system.getConfigSystem().getConfig(), logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the plugin.
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (serverShutdownSave != null) {
|
||||
serverShutdownSave.performSave();
|
||||
}
|
||||
if (system != null) {
|
||||
system.disable();
|
||||
}
|
||||
|
||||
logger.info(locale != null ? locale.getString(PluginLang.DISABLED) : PluginLang.DISABLED.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Nothing to be done, systems are disabled
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReloading() {
|
||||
return reloading;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated due to use of APF Config
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void reloadConfig() {
|
||||
throw new IllegalStateException("This method should be used on this plugin. Use onReload() instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated due to use of APF Config
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public FileConfiguration getConfig() {
|
||||
throw new IllegalStateException("This method should be used on this plugin. Use getMainConfig() instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated due to use of APF Config
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void saveConfig() {
|
||||
throw new IllegalStateException("This method should be used on this plugin. Use getMainConfig().save() instead");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated due to use of APF Config
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void saveDefaultConfig() {
|
||||
throw new IllegalStateException("This method should be used on this plugin.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanSystem getSystem() {
|
||||
return system;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.command.PlanCommand;
|
||||
import com.djrapitops.plan.modules.APFModule;
|
||||
import com.djrapitops.plan.modules.FilesModule;
|
||||
import com.djrapitops.plan.modules.ServerSuperClassBindingModule;
|
||||
import com.djrapitops.plan.modules.SystemObjectProvidingModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitPlanModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitServerPropertiesModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitSuperClassBindingModule;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.pluginbridge.plan.PluginBridgeModule;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Dagger Component that constructs the plugin systems running on Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
BukkitPlanModule.class,
|
||||
SystemObjectProvidingModule.class,
|
||||
APFModule.class,
|
||||
FilesModule.class,
|
||||
BukkitServerPropertiesModule.class,
|
||||
ServerSuperClassBindingModule.class,
|
||||
BukkitSuperClassBindingModule.class,
|
||||
PluginBridgeModule.Bukkit.class
|
||||
})
|
||||
public interface PlanBukkitComponent {
|
||||
|
||||
PlanCommand planCommand();
|
||||
|
||||
PlanSystem system();
|
||||
|
||||
ServerShutdownSave serverShutdownSave();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder plan(Plan plan);
|
||||
|
||||
PlanBukkitComponent build();
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.api.events;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* Event that is called when Plan is enabled.
|
||||
* <p>
|
||||
* This includes, but might not be limited to:
|
||||
* - First time the plugin enables successfully
|
||||
* - Plan is reloaded
|
||||
* - Bukkit-BungeeCord setup updates settings
|
||||
* - Plan is enabled after it was disabled
|
||||
* <p>
|
||||
* {@code event.isPlanSystemEnabled()} can be called to determine if the enable was successful.
|
||||
* It is not guaranteed that this event is called when the plugin fails to enable properly.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanBukkitEnableEvent extends Event {
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
public PlanBukkitEnableEvent(boolean enabled) {
|
||||
super(true);
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public boolean isPlanSystemEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return PlanBukkitEnableEvent.getHandlerList();
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.filter.AbstractFilter;
|
||||
import org.apache.logging.log4j.message.Message;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Filters out WebUser registration command logs.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RegisterCommandFilter extends AbstractFilter {
|
||||
|
||||
private final Set<String> censoredCommands = ImmutableSet.of("/plan web register", "/plan webuser register", "/plan register");
|
||||
|
||||
public void registerFilter() {
|
||||
Logger logger = (Logger) LogManager.getRootLogger();
|
||||
logger.addFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(LogEvent event) {
|
||||
if (event == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
|
||||
return validateMessage(event.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
|
||||
return validateMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
|
||||
return validateMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
|
||||
if (msg == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
|
||||
return validateMessage(msg.toString());
|
||||
}
|
||||
|
||||
private Result validateMessage(Message message) {
|
||||
if (message == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
|
||||
return validateMessage(message.getFormattedMessage());
|
||||
}
|
||||
|
||||
private Result validateMessage(String message) {
|
||||
if (message == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
|
||||
return commandShouldBeCensored(message)
|
||||
? Result.DENY
|
||||
: Result.NEUTRAL;
|
||||
}
|
||||
|
||||
private boolean commandShouldBeCensored(String message) {
|
||||
return message != null
|
||||
&& (message.toLowerCase().contains("issued server command:")
|
||||
&& shouldBeCensored(message));
|
||||
}
|
||||
|
||||
private boolean shouldBeCensored(String message) {
|
||||
return message != null && censoredCommands.stream().anyMatch(message::contains);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.command.PlanCommand;
|
||||
import com.djrapitops.plugin.command.CommandNode;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Dagger module for binding Plan instance.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public interface BukkitPlanModule {
|
||||
|
||||
@Binds
|
||||
PlanPlugin bindPlanPlugin(Plan plugin);
|
||||
|
||||
@Binds
|
||||
@Named("mainCommand")
|
||||
CommandNode bindMainCommand(PlanCommand command);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.system.info.server.properties.BukkitServerProperties;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Dagger module for Bukkit ServerProperties.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public class BukkitServerPropertiesModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ServerProperties provideServerProperties(Plan plugin) {
|
||||
return new BukkitServerProperties(plugin.getServer());
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.BukkitServerShutdownSave;
|
||||
import com.djrapitops.plan.ServerShutdownSave;
|
||||
import com.djrapitops.plan.system.database.BukkitDBSystem;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.importing.BukkitImportSystem;
|
||||
import com.djrapitops.plan.system.importing.ImportSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.ServerServerInfo;
|
||||
import com.djrapitops.plan.system.listeners.BukkitListenerSystem;
|
||||
import com.djrapitops.plan.system.listeners.ListenerSystem;
|
||||
import com.djrapitops.plan.system.settings.BukkitConfigSystem;
|
||||
import com.djrapitops.plan.system.settings.ConfigSystem;
|
||||
import com.djrapitops.plan.system.tasks.BukkitTaskSystem;
|
||||
import com.djrapitops.plan.system.tasks.TaskSystem;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
|
||||
/**
|
||||
* Module for binding Bukkit specific classes to the interface implementations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public interface BukkitSuperClassBindingModule {
|
||||
|
||||
@Binds
|
||||
ServerInfo bindBukkitServerInfo(ServerServerInfo serverServerInfo);
|
||||
|
||||
@Binds
|
||||
DBSystem bindBukkitDatabaseSystem(BukkitDBSystem dbSystem);
|
||||
|
||||
@Binds
|
||||
ConfigSystem bindBukkitConfigSystem(BukkitConfigSystem bukkitConfigSystem);
|
||||
|
||||
@Binds
|
||||
TaskSystem bindBukkitTaskSystem(BukkitTaskSystem bukkitTaskSystem);
|
||||
|
||||
@Binds
|
||||
ListenerSystem bindBukkitListenerSystem(BukkitListenerSystem bukkitListenerSystem);
|
||||
|
||||
@Binds
|
||||
ImportSystem bindImportSystem(BukkitImportSystem bukkitImportSystem);
|
||||
|
||||
@Binds
|
||||
ServerShutdownSave bindBukkitServerShutdownSave(BukkitServerShutdownSave bukkitServerShutdownSave);
|
||||
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.database;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.db.H2DB;
|
||||
import com.djrapitops.plan.db.MySQLDB;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Bukkit Database system that initializes SQLite and MySQL database objects.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitDBSystem extends DBSystem {
|
||||
|
||||
private final PlanConfig config;
|
||||
|
||||
@Inject
|
||||
public BukkitDBSystem(
|
||||
Locale locale,
|
||||
MySQLDB mySQLDB,
|
||||
SQLiteDB.Factory sqLiteDB,
|
||||
H2DB.Factory h2DB,
|
||||
PlanConfig config,
|
||||
PluginLogger logger,
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(locale, sqLiteDB, h2DB, logger, timings, errorHandler);
|
||||
this.config = config;
|
||||
|
||||
databases.add(mySQLDB);
|
||||
databases.add(h2DB.usingDefaultFile());
|
||||
databases.add(sqLiteDB.usingDefaultFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() throws EnableException {
|
||||
String dbType = config.get(DatabaseSettings.TYPE).toLowerCase().trim();
|
||||
db = getActiveDatabaseByName(dbType);
|
||||
super.enable();
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.importing;
|
||||
|
||||
import com.djrapitops.plan.system.importing.importers.OfflinePlayerImporter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* ImportSystem implementation for Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitImportSystem extends ImportSystem {
|
||||
|
||||
private final OfflinePlayerImporter offlinePlayerImporter;
|
||||
|
||||
@Inject
|
||||
public BukkitImportSystem(
|
||||
OfflinePlayerImporter offlinePlayerImporter
|
||||
) {
|
||||
this.offlinePlayerImporter = offlinePlayerImporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerImporters() {
|
||||
registerImporter(offlinePlayerImporter);
|
||||
}
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.importing.data;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.system.DebugChannels;
|
||||
import com.djrapitops.plugin.api.utility.UUIDFetcher;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* UserImportRefiner attempts to find any crucial information that is missing.
|
||||
*
|
||||
* - Finds UUIDs if only name is present.
|
||||
* - Finds Names if only UUID is present.
|
||||
* - Removes any importers that do not have any identifiers.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
public class BukkitUserImportRefiner {
|
||||
|
||||
private final Plan plugin;
|
||||
private final Timings timings;
|
||||
private final boolean onlineMode;
|
||||
|
||||
private final List<UserImportData> importers = new ArrayList<>();
|
||||
|
||||
private final Map<UserImportData, String> missingUUIDs = new HashMap<>();
|
||||
private final Map<UserImportData, String> missingNames = new HashMap<>();
|
||||
|
||||
private final Map<UserImportData, String> foundUUIDs = new HashMap<>();
|
||||
private final Map<UserImportData, String> foundNames = new HashMap<>();
|
||||
|
||||
public BukkitUserImportRefiner(Plan plugin, List<UserImportData> importers) {
|
||||
this.plugin = plugin;
|
||||
this.timings = plugin.getTimings();
|
||||
this.importers.addAll(importers);
|
||||
|
||||
onlineMode = plugin.getServer().getOnlineMode();
|
||||
}
|
||||
|
||||
public List<UserImportData> refineData() {
|
||||
String benchmarkName = "Refining UserImportData";
|
||||
|
||||
timings.start(benchmarkName);
|
||||
processMissingIdentifiers();
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
|
||||
return importers;
|
||||
}
|
||||
|
||||
private void processMissingIdentifiers() {
|
||||
String benchmarkName = "Processing missing identifiers";
|
||||
|
||||
timings.start(benchmarkName);
|
||||
|
||||
List<UserImportData> invalidData = new ArrayList<>();
|
||||
|
||||
importers.parallelStream().forEach(importer -> {
|
||||
String name = importer.getName();
|
||||
UUID uuid = importer.getUuid();
|
||||
|
||||
boolean nameNull = name == null;
|
||||
boolean uuidNull = uuid == null;
|
||||
|
||||
if (nameNull && uuidNull) {
|
||||
invalidData.add(importer);
|
||||
} else if (nameNull) {
|
||||
missingNames.put(importer, uuid.toString());
|
||||
} else if (uuidNull) {
|
||||
missingUUIDs.put(importer, name);
|
||||
}
|
||||
});
|
||||
|
||||
importers.removeAll(invalidData);
|
||||
|
||||
processMissingUUIDs();
|
||||
processMissingNames();
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
}
|
||||
|
||||
private void processMissingUUIDs() {
|
||||
String benchmarkName = "Processing missing UUIDs";
|
||||
|
||||
timings.start(benchmarkName);
|
||||
|
||||
if (onlineMode) {
|
||||
addMissingUUIDsOverFetcher();
|
||||
addMissingUUIDsOverOfflinePlayer();
|
||||
} else {
|
||||
addMissingUUIDsOverOfflinePlayer();
|
||||
addMissingUUIDsOverFetcher();
|
||||
}
|
||||
|
||||
foundUUIDs.entrySet().parallelStream()
|
||||
.forEach(entry -> {
|
||||
UserImportData userImportData = entry.getKey();
|
||||
UUID uuid = UUID.fromString(entry.getValue());
|
||||
|
||||
userImportData.setUuid(uuid);
|
||||
});
|
||||
|
||||
importers.removeAll(missingUUIDs.keySet());
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
}
|
||||
|
||||
private void addMissingUUIDsOverFetcher() {
|
||||
UUIDFetcher uuidFetcher = new UUIDFetcher(new ArrayList<>(missingUUIDs.values()));
|
||||
|
||||
Map<String, String> result;
|
||||
|
||||
try {
|
||||
result = uuidFetcher.call().entrySet().parallelStream()
|
||||
.collect(Collectors.toMap(entry -> entry.getValue().toString(), Map.Entry::getKey));
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
|
||||
addFoundUUIDs(result);
|
||||
}
|
||||
|
||||
private void addMissingUUIDsOverOfflinePlayer() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
for (String name : missingUUIDs.values()) {
|
||||
String uuid = getUuidByOfflinePlayer(name);
|
||||
|
||||
if (uuid == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(name, uuid);
|
||||
}
|
||||
|
||||
addFoundUUIDs(result);
|
||||
}
|
||||
|
||||
private void addFoundUUIDs(Map<String, String> foundUUIDs) {
|
||||
List<UserImportData> found = new ArrayList<>();
|
||||
|
||||
missingUUIDs.entrySet().parallelStream().forEach(entry -> {
|
||||
UserImportData importer = entry.getKey();
|
||||
String name = entry.getValue();
|
||||
|
||||
String uuid = foundUUIDs.get(name);
|
||||
|
||||
this.foundUUIDs.put(importer, uuid);
|
||||
found.add(importer);
|
||||
});
|
||||
|
||||
missingUUIDs.keySet().removeAll(found);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getUuidByOfflinePlayer(String name) {
|
||||
OfflinePlayer player = plugin.getServer().getOfflinePlayer(name);
|
||||
|
||||
if (!player.hasPlayedBefore()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return player.getUniqueId().toString();
|
||||
}
|
||||
|
||||
private void processMissingNames() {
|
||||
String benchmarkNames = "Processing missing names";
|
||||
|
||||
timings.start(benchmarkNames);
|
||||
|
||||
findMissingNames();
|
||||
|
||||
foundNames.entrySet().parallelStream().forEach(entry -> entry.getKey().setName(entry.getValue()));
|
||||
|
||||
importers.removeAll(missingNames.keySet());
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkNames);
|
||||
}
|
||||
|
||||
private void findMissingNames() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
missingNames.values().parallelStream().forEach(uuid -> {
|
||||
String name = getNameByOfflinePlayer(uuid);
|
||||
|
||||
result.put(uuid, name);
|
||||
});
|
||||
|
||||
addFoundNames(result);
|
||||
}
|
||||
|
||||
private void addFoundNames(Map<String, String> foundNames) {
|
||||
List<UserImportData> found = new ArrayList<>();
|
||||
|
||||
missingNames.entrySet().parallelStream().forEach(entry -> {
|
||||
UserImportData importer = entry.getKey();
|
||||
String uuid = entry.getValue();
|
||||
|
||||
String name = foundNames.get(uuid);
|
||||
|
||||
this.foundNames.put(importer, name);
|
||||
found.add(importer);
|
||||
});
|
||||
|
||||
missingNames.keySet().removeAll(found);
|
||||
}
|
||||
|
||||
private String getNameByOfflinePlayer(String uuid) {
|
||||
OfflinePlayer player = plugin.getServer().getOfflinePlayer(UUID.fromString(uuid));
|
||||
|
||||
if (!player.hasPlayedBefore()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return player.getName();
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.importing.importers;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.container.BaseUser;
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.container.UserInfo;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.LargeStoreQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.importing.data.BukkitUserImportRefiner;
|
||||
import com.djrapitops.plan.system.importing.data.ServerImportData;
|
||||
import com.djrapitops.plan.system.importing.data.UserImportData;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Generic importer for user data into Plan on the Bukkit platform.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
public abstract class BukkitImporter implements Importer {
|
||||
|
||||
protected final Supplier<UUID> serverUUID;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final DBSystem dbSystem;
|
||||
private final String name;
|
||||
private final Plan plugin;
|
||||
|
||||
protected BukkitImporter(
|
||||
Plan plugin,
|
||||
GeolocationCache geolocationCache,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
String name
|
||||
) {
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverUUID = serverInfo::getServerUUID;
|
||||
|
||||
this.name = name;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<String> getNames() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public abstract ServerImportData getServerImportData();
|
||||
|
||||
public abstract List<UserImportData> getUserImportData();
|
||||
|
||||
@Override
|
||||
public final void processImport() {
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
|
||||
try {
|
||||
service.submit(this::processServerData);
|
||||
service.submit(this::processUserData);
|
||||
} finally {
|
||||
shutdownService(service);
|
||||
}
|
||||
}
|
||||
|
||||
private void processServerData() {
|
||||
ServerImportData serverImportData = getServerImportData();
|
||||
|
||||
if (serverImportData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new Transaction() {
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(LargeStoreQueries.storeAllTPSData(Collections.singletonMap(serverUUID.get(), serverImportData.getTpsData())));
|
||||
execute(LargeStoreQueries.storeAllCommandUsageData(Collections.singletonMap(serverUUID.get(), serverImportData.getCommandUsages())));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void processUserData() {
|
||||
List<UserImportData> userImportData = getUserImportData();
|
||||
|
||||
if (Verify.isEmpty(userImportData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BukkitUserImportRefiner userImportRefiner = new BukkitUserImportRefiner(plugin, userImportData);
|
||||
userImportData = userImportRefiner.refineData();
|
||||
|
||||
Database db = dbSystem.getDatabase();
|
||||
|
||||
Set<UUID> existingUUIDs = db.query(UserIdentifierQueries.fetchAllPlayerUUIDs());
|
||||
Set<UUID> existingUserInfoTableUUIDs = db.query(UserIdentifierQueries.fetchPlayerUUIDsOfServer(serverUUID.get()));
|
||||
|
||||
Map<UUID, BaseUser> users = new HashMap<>();
|
||||
List<UserInfo> userInfo = new ArrayList<>();
|
||||
Map<UUID, List<Nickname>> nickNames = new HashMap<>();
|
||||
List<Session> sessions = new ArrayList<>();
|
||||
Map<UUID, List<GeoInfo>> geoInfo = new HashMap<>();
|
||||
|
||||
userImportData.parallelStream().forEach(data -> {
|
||||
UUID uuid = data.getUuid();
|
||||
|
||||
if (!existingUUIDs.contains(uuid)) {
|
||||
users.put(uuid, toBaseUser(data));
|
||||
}
|
||||
|
||||
if (!existingUserInfoTableUUIDs.contains(uuid)) {
|
||||
userInfo.add(toUserInfo(data));
|
||||
}
|
||||
|
||||
nickNames.put(uuid, data.getNicknames());
|
||||
geoInfo.put(uuid, convertGeoInfo(data));
|
||||
sessions.add(toSession(data));
|
||||
});
|
||||
|
||||
db.executeTransaction(new Transaction() {
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(LargeStoreQueries.storeAllCommonUserInformation(users.values()));
|
||||
execute(LargeStoreQueries.storeAllSessionsWithKillAndWorldData(sessions));
|
||||
Map<UUID, List<UserInfo>> userInformation = Collections.singletonMap(serverUUID.get(), userInfo);
|
||||
execute(LargeStoreQueries.storePerServerUserInformation(userInformation));
|
||||
execute(LargeStoreQueries.storeAllNicknameData(Collections.singletonMap(serverUUID.get(), nickNames)));
|
||||
execute(LargeStoreQueries.storeAllGeoInformation(geoInfo));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void shutdownService(ExecutorService service) {
|
||||
service.shutdown();
|
||||
try {
|
||||
if (!service.awaitTermination(20, TimeUnit.MINUTES)) {
|
||||
service.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
service.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private BaseUser toBaseUser(UserImportData userImportData) {
|
||||
UUID playerUUID = userImportData.getUuid();
|
||||
String playerName = userImportData.getName();
|
||||
long registered = userImportData.getRegistered();
|
||||
int timesKicked = userImportData.getTimesKicked();
|
||||
return new BaseUser(playerUUID, playerName, registered, timesKicked);
|
||||
}
|
||||
|
||||
private UserInfo toUserInfo(UserImportData userImportData) {
|
||||
UUID uuid = userImportData.getUuid();
|
||||
long registered = userImportData.getRegistered();
|
||||
boolean op = userImportData.isOp();
|
||||
boolean banned = userImportData.isBanned();
|
||||
|
||||
return new UserInfo(uuid, serverUUID.get(), registered, op, banned);
|
||||
}
|
||||
|
||||
private Session toSession(UserImportData userImportData) {
|
||||
int mobKills = userImportData.getMobKills();
|
||||
int deaths = userImportData.getDeaths();
|
||||
|
||||
Session session = new Session(0, userImportData.getUuid(), serverUUID.get(), 0L, 0L, mobKills, deaths, 0);
|
||||
|
||||
session.setPlayerKills(userImportData.getKills());
|
||||
session.setWorldTimes(new WorldTimes(userImportData.getWorldTimes()));
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
private List<GeoInfo> convertGeoInfo(UserImportData userImportData) {
|
||||
long date = System.currentTimeMillis();
|
||||
|
||||
return userImportData.getIps().parallelStream()
|
||||
.map(ip -> {
|
||||
String geoLoc = geolocationCache.getCountry(ip);
|
||||
return new GeoInfo(ip, geoLoc, date);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.importing.importers;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.importing.data.ServerImportData;
|
||||
import com.djrapitops.plan.system.importing.data.UserImportData;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
@Singleton
|
||||
public class OfflinePlayerImporter extends BukkitImporter {
|
||||
|
||||
@Inject
|
||||
public OfflinePlayerImporter(
|
||||
Plan plugin,
|
||||
GeolocationCache geolocationCache,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo
|
||||
) {
|
||||
super(plugin, geolocationCache, dbSystem, serverInfo, "offline");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerImportData getServerImportData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserImportData> getUserImportData() {
|
||||
List<UserImportData> dataList = new ArrayList<>();
|
||||
|
||||
Set<OfflinePlayer> operators = Bukkit.getOperators();
|
||||
Set<OfflinePlayer> banned = Bukkit.getBannedPlayers();
|
||||
|
||||
Arrays.stream(Bukkit.getOfflinePlayers()).parallel().forEach(player -> {
|
||||
UserImportData.UserImportDataBuilder builder = UserImportData.builder(serverUUID.get());
|
||||
builder.name(player.getName())
|
||||
.uuid(player.getUniqueId())
|
||||
.registered(player.getFirstPlayed());
|
||||
|
||||
if (operators.contains(player)) {
|
||||
builder.op();
|
||||
}
|
||||
|
||||
if (banned.contains(player)) {
|
||||
builder.banned();
|
||||
}
|
||||
|
||||
dataList.add(builder.build());
|
||||
});
|
||||
|
||||
return dataList;
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.info.server.properties;
|
||||
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* ServerProperties for Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class BukkitServerProperties extends ServerProperties {
|
||||
|
||||
public BukkitServerProperties(Server server) {
|
||||
super(
|
||||
server.getName(),
|
||||
server.getPort(),
|
||||
server.getVersion(),
|
||||
server.getBukkitVersion(),
|
||||
server::getIp,
|
||||
server.getMaxPlayers(),
|
||||
() -> server.getOnlinePlayers().size()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.api.events.PlanBukkitEnableEvent;
|
||||
import com.djrapitops.plan.capability.CapabilityServiceImplementation;
|
||||
import com.djrapitops.plan.system.listeners.bukkit.*;
|
||||
import com.djrapitops.plan.system.status.Status;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class BukkitListenerSystem extends ListenerSystem {
|
||||
|
||||
private final Plan plugin;
|
||||
|
||||
private final Status status;
|
||||
private final PlayerOnlineListener playerOnlineListener;
|
||||
private final ChatListener chatListener;
|
||||
private final GameModeChangeListener gamemodeChangeListener;
|
||||
private final WorldChangeListener worldChangeListener;
|
||||
private final CommandListener commandListener;
|
||||
private final DeathEventListener deathEventListener;
|
||||
private final AFKListener afkListener;
|
||||
|
||||
@Inject
|
||||
public BukkitListenerSystem(Plan plugin,
|
||||
Status status,
|
||||
PlayerOnlineListener playerOnlineListener,
|
||||
ChatListener chatListener,
|
||||
GameModeChangeListener gamemodeChangeListener,
|
||||
WorldChangeListener worldChangeListener,
|
||||
CommandListener commandListener,
|
||||
DeathEventListener deathEventListener,
|
||||
AFKListener afkListener
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.status = status;
|
||||
|
||||
this.playerOnlineListener = playerOnlineListener;
|
||||
this.chatListener = chatListener;
|
||||
this.gamemodeChangeListener = gamemodeChangeListener;
|
||||
this.worldChangeListener = worldChangeListener;
|
||||
this.commandListener = commandListener;
|
||||
this.deathEventListener = deathEventListener;
|
||||
this.afkListener = afkListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerListeners() {
|
||||
plugin.registerListener(
|
||||
playerOnlineListener,
|
||||
chatListener,
|
||||
gamemodeChangeListener,
|
||||
worldChangeListener,
|
||||
commandListener,
|
||||
deathEventListener,
|
||||
afkListener
|
||||
);
|
||||
status.setCountKicks(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListeners() {
|
||||
HandlerList.unregisterAll(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEnableEvent(PlanPlugin plugin) {
|
||||
boolean isEnabled = plugin.isSystemEnabled();
|
||||
PlanBukkitEnableEvent event = new PlanBukkitEnableEvent(isEnabled);
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
CapabilityServiceImplementation.notifyAboutEnable(isEnabled);
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.system.afk.AFKTracker;
|
||||
import com.djrapitops.plan.system.settings.Permissions;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Listener that keeps track of actions that are not considered being AFK.
|
||||
* <p>
|
||||
* Additional Listener calls in PlayerOnlineListener to avoid having HIGHEST priority listeners.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see PlayerOnlineListener
|
||||
*/
|
||||
public class AFKListener implements Listener {
|
||||
|
||||
// Static so that /reload does not cause afk tracking to fail.
|
||||
static AFKTracker AFK_TRACKER;
|
||||
|
||||
private final Map<UUID, Boolean> ignorePermissionInfo;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public AFKListener(PlanConfig config, ErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
this.ignorePermissionInfo = new HashMap<>();
|
||||
|
||||
AFKListener.assignAFKTracker(config);
|
||||
}
|
||||
|
||||
private static void assignAFKTracker(PlanConfig config) {
|
||||
if (AFK_TRACKER == null) {
|
||||
AFK_TRACKER = new AFKTracker(config);
|
||||
}
|
||||
}
|
||||
|
||||
private void event(PlayerEvent event) {
|
||||
try {
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
Boolean ignored = ignorePermissionInfo.get(uuid);
|
||||
if (ignored == null) {
|
||||
ignored = player.hasPermission(Permissions.IGNORE_AFK.getPermission());
|
||||
}
|
||||
if (ignored) {
|
||||
AFK_TRACKER.hasIgnorePermission(uuid);
|
||||
ignorePermissionInfo.put(uuid, true);
|
||||
} else {
|
||||
ignorePermissionInfo.put(uuid, false);
|
||||
}
|
||||
|
||||
AFK_TRACKER.performedAction(uuid, time);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
event(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||
event(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent event) {
|
||||
event(event);
|
||||
boolean isAfkCommand = event.getMessage().substring(1).toLowerCase().startsWith("afk");
|
||||
if (isAfkCommand) {
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
AFK_TRACKER.usedAfkCommand(uuid, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.access.transactions.events.NicknameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.NicknameCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Event Listener for AsyncPlayerChatEvents.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ChatListener implements Listener {
|
||||
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final NicknameCache nicknameCache;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public ChatListener(
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
NicknameCache nicknameCache,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.nicknameCache = nicknameCache;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
actOnChatEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnChatEvent(AsyncPlayerChatEvent event) {
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
String displayName = player.getDisplayName();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new NicknameStoreTransaction(
|
||||
uuid, new Nickname(displayName, time, serverInfo.getServerUUID()),
|
||||
(playerUUID, name) -> name.equals(nicknameCache.getDisplayName(playerUUID))
|
||||
));
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.db.access.transactions.events.CommandStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.Permissions;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Event Listener for PlayerCommandPreprocessEvents.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class CommandListener implements Listener {
|
||||
|
||||
private final Plan plugin;
|
||||
private final PlanConfig config;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public CommandListener(
|
||||
Plan plugin,
|
||||
PlanConfig config,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent event) {
|
||||
boolean hasIgnorePermission = event.getPlayer().hasPermission(Permissions.IGNORE_COMMAND_USE.getPermission());
|
||||
if (event.isCancelled() || hasIgnorePermission) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
actOnCommandEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnCommandEvent(PlayerCommandPreprocessEvent event) {
|
||||
String commandName = event.getMessage().substring(1).split(" ")[0].toLowerCase();
|
||||
|
||||
boolean logUnknownCommands = config.isTrue(DataGatheringSettings.LOG_UNKNOWN_COMMANDS);
|
||||
boolean combineCommandAliases = config.isTrue(DataGatheringSettings.COMBINE_COMMAND_ALIASES);
|
||||
|
||||
if (!logUnknownCommands || combineCommandAliases) {
|
||||
Command command = getBukkitCommand(commandName);
|
||||
if (command == null) {
|
||||
if (!logUnknownCommands) {
|
||||
return;
|
||||
}
|
||||
} else if (combineCommandAliases) {
|
||||
commandName = command.getName();
|
||||
}
|
||||
}
|
||||
dbSystem.getDatabase().executeTransaction(new CommandStoreTransaction(serverInfo.getServerUUID(), commandName));
|
||||
}
|
||||
|
||||
private Command getBukkitCommand(String commandName) {
|
||||
Command command = plugin.getServer().getPluginCommand(commandName);
|
||||
if (command == null) {
|
||||
try {
|
||||
command = plugin.getServer().getCommandMap().getCommand(commandName);
|
||||
} catch (NoSuchMethodError ignored) {
|
||||
/* Ignored, Bukkit 1.8 has no such method. This method is from Paper */
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.player.MobKillProcessor;
|
||||
import com.djrapitops.plan.system.processing.processors.player.PlayerKillProcessor;
|
||||
import com.djrapitops.plan.utilities.formatting.EntityNameFormatter;
|
||||
import com.djrapitops.plan.utilities.formatting.ItemNameFormatter;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Event Listener for EntityDeathEvents.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DeathEventListener implements Listener {
|
||||
|
||||
private final Processing processing;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public DeathEventListener(
|
||||
Processing processing,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.processing = processing;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onDeath(EntityDeathEvent event) {
|
||||
long time = System.currentTimeMillis();
|
||||
LivingEntity dead = event.getEntity();
|
||||
|
||||
if (dead instanceof Player) {
|
||||
// Process Death
|
||||
SessionCache.getCachedSession(dead.getUniqueId()).ifPresent(Session::died);
|
||||
}
|
||||
|
||||
try {
|
||||
EntityDamageEvent entityDamageEvent = dead.getLastDamageCause();
|
||||
if (!(entityDamageEvent instanceof EntityDamageByEntityEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) entityDamageEvent;
|
||||
Entity killerEntity = entityDamageByEntityEvent.getDamager();
|
||||
|
||||
UUID uuid = dead instanceof Player ? dead.getUniqueId() : null;
|
||||
handleKill(time, uuid, killerEntity);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleKill(long time, UUID victimUUID, Entity killerEntity) {
|
||||
Runnable processor = null;
|
||||
if (killerEntity instanceof Player) {
|
||||
processor = handlePlayerKill(time, victimUUID, (Player) killerEntity);
|
||||
} else if (killerEntity instanceof Tameable) {
|
||||
processor = handlePetKill(time, victimUUID, (Tameable) killerEntity);
|
||||
} else if (killerEntity instanceof Projectile) {
|
||||
processor = handleProjectileKill(time, victimUUID, (Projectile) killerEntity);
|
||||
}
|
||||
if (processor != null) {
|
||||
processing.submit(processor);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable handlePlayerKill(long time, UUID victimUUID, Player killer) {
|
||||
Material itemInHand;
|
||||
try {
|
||||
itemInHand = killer.getInventory().getItemInMainHand().getType();
|
||||
} catch (NoSuchMethodError e) {
|
||||
try {
|
||||
itemInHand = killer.getInventory().getItemInHand().getType(); // Support for non dual wielding versions.
|
||||
} catch (Exception | NoSuchMethodError | NoSuchFieldError e2) {
|
||||
itemInHand = Material.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
String weaponName = new ItemNameFormatter().apply(itemInHand.name());
|
||||
|
||||
return victimUUID != null
|
||||
? new PlayerKillProcessor(killer.getUniqueId(), time, victimUUID, weaponName)
|
||||
: new MobKillProcessor(killer.getUniqueId());
|
||||
}
|
||||
|
||||
private Runnable handlePetKill(long time, UUID victimUUID, Tameable tameable) {
|
||||
if (!tameable.isTamed()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AnimalTamer owner = tameable.getOwner();
|
||||
if (!(owner instanceof Player)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String name;
|
||||
try {
|
||||
name = tameable.getType().name();
|
||||
} catch (NoSuchMethodError oldVersionNoTypesError) {
|
||||
// getType introduced in 1.9
|
||||
name = tameable.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
return victimUUID != null
|
||||
? new PlayerKillProcessor(owner.getUniqueId(), time, victimUUID, new EntityNameFormatter().apply(name))
|
||||
: new MobKillProcessor(owner.getUniqueId());
|
||||
}
|
||||
|
||||
private Runnable handleProjectileKill(long time, UUID victimUUID, Projectile projectile) {
|
||||
ProjectileSource source = projectile.getShooter();
|
||||
if (!(source instanceof Player)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Player player = (Player) source;
|
||||
String projectileName = new EntityNameFormatter().apply(projectile.getType().name());
|
||||
|
||||
return victimUUID != null
|
||||
? new PlayerKillProcessor(player.getUniqueId(), time, victimUUID, projectileName)
|
||||
: new MobKillProcessor(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.WorldAliasSettings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerGameModeChangeEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Event Listener for PlayerGameModeChangeEvents.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class GameModeChangeListener implements Listener {
|
||||
|
||||
private final WorldAliasSettings worldAliasSettings;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public GameModeChangeListener(
|
||||
WorldAliasSettings worldAliasSettings,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.worldAliasSettings = worldAliasSettings;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onGameModeChange(PlayerGameModeChangeEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
actOnEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnEvent(PlayerGameModeChangeEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
long time = System.currentTimeMillis();
|
||||
String gameMode = event.getNewGameMode().name();
|
||||
String worldName = player.getWorld().getName();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName));
|
||||
worldAliasSettings.addWorld(worldName);
|
||||
|
||||
Optional<Session> cachedSession = SessionCache.getCachedSession(uuid);
|
||||
cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time));
|
||||
}
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.*;
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.NicknameCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.system.status.Status;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.net.InetAddress;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Event Listener for PlayerJoin, PlayerQuit and PlayerKickEvents.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerOnlineListener implements Listener {
|
||||
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ExtensionServiceImplementation extensionService;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final NicknameCache nicknameCache;
|
||||
private final SessionCache sessionCache;
|
||||
private final ErrorHandler errorHandler;
|
||||
private final Status status;
|
||||
|
||||
@Inject
|
||||
public PlayerOnlineListener(
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ExtensionServiceImplementation extensionService,
|
||||
GeolocationCache geolocationCache,
|
||||
NicknameCache nicknameCache,
|
||||
SessionCache sessionCache,
|
||||
Status status,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.extensionService = extensionService;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.nicknameCache = nicknameCache;
|
||||
this.sessionCache = sessionCache;
|
||||
this.status = status;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
try {
|
||||
PlayerLoginEvent.Result result = event.getResult();
|
||||
UUID playerUUID = event.getPlayer().getUniqueId();
|
||||
boolean operator = event.getPlayer().isOp();
|
||||
boolean banned = result == PlayerLoginEvent.Result.KICK_BANNED;
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, () -> banned));
|
||||
dbSystem.getDatabase().executeTransaction(new OperatorStatusTransaction(playerUUID, operator));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PlayerKickEvent Listener.
|
||||
* <p>
|
||||
* Adds processing information to the ProcessingQueue.
|
||||
* After KickEvent, the QuitEvent is automatically called.
|
||||
*
|
||||
* @param event Fired event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerKick(PlayerKickEvent event) {
|
||||
try {
|
||||
if (!status.areKicksCounted() || event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
if (AFKListener.AFK_TRACKER.isAfk(uuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new KickStoreTransaction(uuid));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
try {
|
||||
actOnJoinEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnJoinEvent(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
UUID serverUUID = serverInfo.getServerUUID();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
AFKListener.AFK_TRACKER.performedAction(playerUUID, time);
|
||||
|
||||
String world = player.getWorld().getName();
|
||||
String gm = player.getGameMode().name();
|
||||
|
||||
Database database = dbSystem.getDatabase();
|
||||
database.executeTransaction(new WorldNameStoreTransaction(serverUUID, world));
|
||||
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
|
||||
String playerName = player.getName();
|
||||
String displayName = player.getDisplayName();
|
||||
|
||||
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
|
||||
if (gatheringGeolocations) {
|
||||
database.executeTransaction(
|
||||
new GeoInfoStoreTransaction(playerUUID, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
|
||||
database.executeTransaction(new PlayerServerRegisterTransaction(playerUUID, player::getFirstPlayed, playerName, serverUUID));
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverUUID, time, world, gm))
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
playerUUID, new Nickname(displayName, time, serverUUID),
|
||||
(uuid, name) -> name.equals(nicknameCache.getDisplayName(uuid))
|
||||
));
|
||||
|
||||
processing.submitNonCritical(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_JOIN));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void beforePlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String playerName = player.getName();
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_LEAVE));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
try {
|
||||
actOnQuitEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnQuitEvent(PlayerQuitEvent event) {
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
AFKListener.AFK_TRACKER.loggedOut(playerUUID, time);
|
||||
|
||||
nicknameCache.removeDisplayName(playerUUID);
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, player::isBanned));
|
||||
|
||||
sessionCache.endSession(playerUUID, time)
|
||||
.ifPresent(endedSession -> dbSystem.getDatabase().executeTransaction(new SessionEndTransaction(endedSession)));
|
||||
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.WorldAliasSettings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WorldChangeListener implements Listener {
|
||||
|
||||
private final WorldAliasSettings worldAliasSettings;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public WorldChangeListener(
|
||||
WorldAliasSettings worldAliasSettings,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.worldAliasSettings = worldAliasSettings;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onWorldChange(PlayerChangedWorldEvent event) {
|
||||
try {
|
||||
actOnEvent(event);
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void actOnEvent(PlayerChangedWorldEvent event) {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
String worldName = player.getWorld().getName();
|
||||
String gameMode = player.getGameMode().name();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName));
|
||||
worldAliasSettings.addWorld(worldName);
|
||||
|
||||
Optional<Session> cachedSession = SessionCache.getCachedSession(uuid);
|
||||
cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time));
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.ShutdownHook;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bukkit.BukkitTPSCountTimer;
|
||||
import com.djrapitops.plan.system.tasks.bukkit.PaperTPSCountTimer;
|
||||
import com.djrapitops.plan.system.tasks.bukkit.PingCountTimerBukkit;
|
||||
import com.djrapitops.plan.system.tasks.server.BootAnalysisTask;
|
||||
import com.djrapitops.plan.system.tasks.server.ConfigStoreTask;
|
||||
import com.djrapitops.plan.system.tasks.server.PeriodicAnalysisTask;
|
||||
import com.djrapitops.plugin.api.Check;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* TaskSystem responsible for registering tasks for Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
|
||||
private final Plan plugin;
|
||||
private final ShutdownHook shutdownHook;
|
||||
private final PingCountTimerBukkit pingCountTimer;
|
||||
private final ConfigStoreTask configStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
|
||||
@Inject
|
||||
public BukkitTaskSystem(
|
||||
Plan plugin,
|
||||
PlanConfig config,
|
||||
ShutdownHook shutdownHook,
|
||||
RunnableFactory runnableFactory,
|
||||
PaperTPSCountTimer paperTPSCountTimer,
|
||||
BukkitTPSCountTimer bukkitTPSCountTimer,
|
||||
BootAnalysisTask bootAnalysisTask,
|
||||
PeriodicAnalysisTask periodicAnalysisTask,
|
||||
PingCountTimerBukkit pingCountTimer,
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
ConfigStoreTask configStoreTask,
|
||||
DBCleanTask dbCleanTask,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask
|
||||
) {
|
||||
super(
|
||||
runnableFactory,
|
||||
Check.isPaperAvailable() ? paperTPSCountTimer : bukkitTPSCountTimer,
|
||||
config,
|
||||
bootAnalysisTask,
|
||||
periodicAnalysisTask,
|
||||
logsFolderCleanTask,
|
||||
playersPageRefreshTask);
|
||||
this.plugin = plugin;
|
||||
this.shutdownHook = shutdownHook;
|
||||
this.pingCountTimer = pingCountTimer;
|
||||
this.configStoreTask = configStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
super.enable();
|
||||
try {
|
||||
Long pingDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (pingDelay < TimeUnit.HOURS.toMillis(1L) && config.get(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(pingCountTimer);
|
||||
long startDelay = TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS);
|
||||
registerTask(pingCountTimer).runTaskTimer(startDelay, 40L);
|
||||
}
|
||||
} catch (ExceptionInInitializerError | NoClassDefFoundError ignore) {
|
||||
// Running CraftBukkit
|
||||
}
|
||||
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask(configStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
shutdownHook.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
super.disable();
|
||||
Optional.ofNullable(Bukkit.getScheduler()).ifPresent(scheduler -> scheduler.cancelTasks(plugin));
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.tasks.TPSCountTimer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.World;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Singleton
|
||||
public class BukkitTPSCountTimer extends TPSCountTimer {
|
||||
|
||||
protected final Plan plugin;
|
||||
private ServerProperties serverProperties;
|
||||
private long lastCheckNano;
|
||||
|
||||
@Inject
|
||||
public BukkitTPSCountTimer(
|
||||
Plan plugin,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
ServerProperties serverProperties,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(dbSystem, serverInfo, logger, errorHandler);
|
||||
this.plugin = plugin;
|
||||
this.serverProperties = serverProperties;
|
||||
lastCheckNano = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNewTPSEntry(long nanoTime, long now) {
|
||||
long diff = nanoTime - lastCheckNano;
|
||||
|
||||
lastCheckNano = nanoTime;
|
||||
|
||||
if (diff > nanoTime) { // First run's diff = nanoTime + 1, no calc possible.
|
||||
logger.debug("First run of TPSCountTimer Task.");
|
||||
return;
|
||||
}
|
||||
|
||||
history.add(calculateTPS(diff, now));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the TPS
|
||||
*
|
||||
* @param diff The time difference between the last run and the new run
|
||||
* @param now The time right now
|
||||
* @return the TPS
|
||||
*/
|
||||
private TPS calculateTPS(long diff, long now) {
|
||||
double averageCPUUsage = getCPUUsage();
|
||||
long usedMemory = getUsedMemory();
|
||||
long freeDiskSpace = getFreeDiskSpace();
|
||||
|
||||
int playersOnline = serverProperties.getOnlinePlayers();
|
||||
latestPlayersOnline = playersOnline;
|
||||
int loadedChunks = getLoadedChunks();
|
||||
int entityCount = getEntityCount();
|
||||
|
||||
return getTPS(diff, now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline, freeDiskSpace);
|
||||
}
|
||||
|
||||
protected TPS getTPS(long diff, long now,
|
||||
double cpuUsage, long usedMemory,
|
||||
int entityCount, int chunksLoaded,
|
||||
int playersOnline, long freeDiskSpace) {
|
||||
long difference = diff;
|
||||
if (difference < TimeUnit.SECONDS.toNanos(1L)) { // No tick count above 20
|
||||
difference = TimeUnit.SECONDS.toNanos(1L);
|
||||
}
|
||||
|
||||
long twentySeconds = TimeUnit.SECONDS.toNanos(20L);
|
||||
while (difference > twentySeconds) {
|
||||
// Add 0 TPS since more than 20 ticks has passed.
|
||||
history.add(TPSBuilder.get()
|
||||
.date(now)
|
||||
.tps(0)
|
||||
.playersOnline(playersOnline)
|
||||
.usedCPU(cpuUsage)
|
||||
.usedMemory(usedMemory)
|
||||
.entities(entityCount)
|
||||
.chunksLoaded(chunksLoaded)
|
||||
.freeDiskSpace(freeDiskSpace)
|
||||
.toTPS());
|
||||
difference -= twentySeconds;
|
||||
}
|
||||
|
||||
double tpsN = twentySeconds * 1.0 / difference;
|
||||
|
||||
return TPSBuilder.get()
|
||||
.date(now)
|
||||
.tps(tpsN)
|
||||
.playersOnline(playersOnline)
|
||||
.usedCPU(cpuUsage)
|
||||
.usedMemory(usedMemory)
|
||||
.entities(entityCount)
|
||||
.chunksLoaded(chunksLoaded)
|
||||
.freeDiskSpace(freeDiskSpace)
|
||||
.toTPS();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of loaded chunks
|
||||
*
|
||||
* @return amount of loaded chunks
|
||||
*/
|
||||
private int getLoadedChunks() {
|
||||
int sum = 0;
|
||||
for (World world : plugin.getServer().getWorlds()) {
|
||||
sum += world.getLoadedChunks().length;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of entities on the server for Bukkit / Spigot
|
||||
*
|
||||
* @return amount of entities
|
||||
*/
|
||||
protected int getEntityCount() {
|
||||
int sum = 0;
|
||||
for (World world : plugin.getServer().getWorlds()) {
|
||||
sum += world.getEntities().size();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.World;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class PaperTPSCountTimer extends BukkitTPSCountTimer {
|
||||
|
||||
@Inject
|
||||
public PaperTPSCountTimer(
|
||||
Plan plugin,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(plugin, dbSystem, serverInfo, serverInfo.getServerProperties(), logger, errorHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TPS getTPS(long diff, long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline, long freeDiskSpace) {
|
||||
double tps;
|
||||
try {
|
||||
tps = plugin.getServer().getTPS()[0];
|
||||
} catch (NoSuchMethodError e) {
|
||||
// This method is from Paper
|
||||
return super.getTPS(diff, now, cpuUsage, usedMemory, entityCount, chunksLoaded, playersOnline, freeDiskSpace);
|
||||
}
|
||||
|
||||
if (tps > 20) {
|
||||
tps = 20;
|
||||
}
|
||||
|
||||
return TPSBuilder.get()
|
||||
.date(now)
|
||||
.tps(tps)
|
||||
.playersOnline(playersOnline)
|
||||
.usedCPU(cpuUsage)
|
||||
.usedMemory(usedMemory)
|
||||
.entities(entityCount)
|
||||
.chunksLoaded(chunksLoaded)
|
||||
.freeDiskSpace(freeDiskSpace)
|
||||
.toTPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEntityCount() {
|
||||
try {
|
||||
return plugin.getServer().getWorlds().stream().mapToInt(World::getEntityCount).sum();
|
||||
} catch (BootstrapMethodError | NoSuchMethodError e) {
|
||||
return super.getEntityCount();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016-2018
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.DateObj;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PingStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.utilities.java.Reflection;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Task that handles player ping calculation on Bukkit based servers.
|
||||
* <p>
|
||||
* Modified PingManager from LagMonitor plugin.
|
||||
* https://github.com/games647/LagMonitor/blob/master/src/main/java/com/github/games647/lagmonitor/task/PingManager.java
|
||||
*
|
||||
* @author games647
|
||||
*/
|
||||
@Singleton
|
||||
public class PingCountTimerBukkit extends AbsRunnable implements Listener {
|
||||
|
||||
//the server is pinging the client every 40 Ticks (2 sec) - so check it then
|
||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/PlayerConnection.java#L178
|
||||
|
||||
private static final boolean PING_METHOD_AVAILABLE;
|
||||
|
||||
private static final MethodHandle PING_FIELD;
|
||||
private static final MethodHandle GET_HANDLE_METHOD;
|
||||
|
||||
static {
|
||||
PING_METHOD_AVAILABLE = isPingMethodAvailable();
|
||||
|
||||
MethodHandle localHandle = null;
|
||||
MethodHandle localPing = null;
|
||||
if (!PING_METHOD_AVAILABLE) {
|
||||
try {
|
||||
Class<?> craftPlayerClass = Reflection.getCraftBukkitClass("entity.CraftPlayer");
|
||||
Class<?> entityPlayer = Reflection.getMinecraftClass("EntityPlayer");
|
||||
|
||||
Lookup lookup = MethodHandles.publicLookup();
|
||||
|
||||
Method getHandleMethod = craftPlayerClass.getDeclaredMethod("getHandle");
|
||||
localHandle = lookup.unreflect(getHandleMethod);
|
||||
|
||||
localPing = lookup.findGetter(entityPlayer, "ping", Integer.TYPE);
|
||||
} catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException reflectiveEx) {
|
||||
Logger.getGlobal().log(
|
||||
Level.WARNING,
|
||||
"Plan: Reflective exception in static initializer of PingCountTimer",
|
||||
reflectiveEx
|
||||
);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Logger.getGlobal().log(
|
||||
Level.WARNING,
|
||||
"Plan: No Ping method handle found - Ping will not be recorded."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GET_HANDLE_METHOD = localHandle;
|
||||
PING_FIELD = localPing;
|
||||
}
|
||||
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public PingCountTimerBukkit(
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.runnableFactory = runnableFactory;
|
||||
playerHistory = new HashMap<>();
|
||||
}
|
||||
|
||||
private static boolean isPingMethodAvailable() {
|
||||
try {
|
||||
//Only available in Paper
|
||||
Class.forName("org.bukkit.entity.Player$Spigot").getDeclaredMethod("getPing");
|
||||
return true;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException noSuchMethodEx) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long time = System.currentTimeMillis();
|
||||
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<UUID, List<DateObj<Integer>>> entry = iterator.next();
|
||||
UUID uuid = entry.getKey();
|
||||
List<DateObj<Integer>> history = entry.getValue();
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
int ping = getPing(player);
|
||||
if (ping < -1 || ping > TimeUnit.SECONDS.toMillis(8L)) {
|
||||
// Don't accept bad values
|
||||
continue;
|
||||
}
|
||||
history.add(new DateObj<>(time, ping));
|
||||
if (history.size() >= 30) {
|
||||
dbSystem.getDatabase().executeTransaction(
|
||||
new PingStoreTransaction(uuid, serverInfo.getServerUUID(), new ArrayList<>(history))
|
||||
);
|
||||
history.clear();
|
||||
}
|
||||
} else {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPlayer(Player player) {
|
||||
playerHistory.put(player.getUniqueId(), new ArrayList<>());
|
||||
}
|
||||
|
||||
public void removePlayer(Player player) {
|
||||
playerHistory.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
private int getPing(Player player) {
|
||||
if (PING_METHOD_AVAILABLE) {
|
||||
// This method is from Paper
|
||||
return player.spigot().getPing();
|
||||
}
|
||||
|
||||
return getReflectionPing(player);
|
||||
}
|
||||
|
||||
private int getReflectionPing(Player player) {
|
||||
try {
|
||||
Object entityPlayer = GET_HANDLE_METHOD.invoke(player);
|
||||
return (int) PING_FIELD.invoke(entityPlayer);
|
||||
} catch (Exception ex) {
|
||||
return -1;
|
||||
} catch (Throwable throwable) {
|
||||
throw (Error) throwable;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
|
||||
Player player = joinEvent.getPlayer();
|
||||
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
|
||||
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
|
||||
return;
|
||||
}
|
||||
runnableFactory.create("Add Player to Ping list", new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.isOnline()) {
|
||||
addPlayer(player);
|
||||
}
|
||||
}
|
||||
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent quitEvent) {
|
||||
removePlayer(quitEvent.getPlayer());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
playerHistory.clear();
|
||||
}
|
||||
}
|
@ -1,432 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016-2018
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.djrapitops.plan.utilities.java;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* An utility class that simplifies reflection in Bukkit plugins.
|
||||
* <p>
|
||||
* Modified Reflection utility from LagMonitor plugin.
|
||||
* https://github.com/games647/LagMonitor/blob/master/src/main/java/com/github/games647/lagmonitor/traffic/Reflection.java
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class Reflection {
|
||||
|
||||
// Deduce the net.minecraft.server.v* package
|
||||
private static final String OBC_PREFIX = getOBCPrefix();
|
||||
private static final String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||
private static final String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", "");
|
||||
// Variable replacement
|
||||
private static final Pattern MATCH_VARIABLE = Pattern.compile("\\{([^\\}]+)\\}");
|
||||
|
||||
private Reflection() {
|
||||
// Seal class
|
||||
}
|
||||
|
||||
private static String getOBCPrefix() {
|
||||
Server server = Bukkit.getServer();
|
||||
return server != null ? server.getClass().getPackage().getName() : Server.class.getPackage().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor for a specific field type and name.
|
||||
*
|
||||
* @param target - the target type.
|
||||
* @param name - the name of the field, or NULL to ignore.
|
||||
* @param fieldType - a compatible field type.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType) {
|
||||
return getField(target, name, fieldType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor for a specific field type and name.
|
||||
*
|
||||
* @param className - lookup name of the class, see {@link #getClass(String)}.
|
||||
* @param name - the name of the field, or NULL to ignore.
|
||||
* @param fieldType - a compatible field type.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static <T> FieldAccessor<T> getField(String className, String name, Class<T> fieldType) {
|
||||
return getField(getClass(className), name, fieldType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor for a specific field type and name.
|
||||
*
|
||||
* @param target - the target type.
|
||||
* @param fieldType - a compatible field type.
|
||||
* @param index - the number of compatible fields to skip.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
|
||||
return getField(target, null, fieldType, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor for a specific field type and name.
|
||||
*
|
||||
* @param className - lookup name of the class, see {@link #getClass(String)}.
|
||||
* @param fieldType - a compatible field type.
|
||||
* @param index - the number of compatible fields to skip.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static <T> FieldAccessor<T> getField(String className, Class<T> fieldType, int index) {
|
||||
return getField(getClass(className), fieldType, index);
|
||||
}
|
||||
|
||||
// Common method
|
||||
private static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType, int index) {
|
||||
for (final Field field : target.getDeclaredFields()) {
|
||||
if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) {
|
||||
field.setAccessible(true);
|
||||
|
||||
// A function for retrieving a specific field value
|
||||
return new FieldAccessor<T>() {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T get(Object target) {
|
||||
try {
|
||||
return (T) field.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Cannot access reflection.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object target, Object value) {
|
||||
try {
|
||||
field.set(target, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Cannot access reflection.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(Object target) {
|
||||
// target instanceof DeclaringClass
|
||||
return field.getDeclaringClass().isAssignableFrom(target.getClass());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Search in parent classes
|
||||
if (target.getSuperclass() != null) {
|
||||
return getField(target.getSuperclass(), name, fieldType, index);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined method of the given name and parameter count.
|
||||
*
|
||||
* @param className - lookup name of the class, see {@link #getClass(String)}.
|
||||
* @param methodName - the method name, or NULL to skip.
|
||||
* @param params - the expected parameters.
|
||||
* @return An object that invokes this specific method.
|
||||
* @throws IllegalStateException If we cannot find this method.
|
||||
*/
|
||||
public static MethodInvoker getMethod(String className, String methodName, Class<?>... params) {
|
||||
return getTypedMethod(getClass(className), methodName, null, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined method of the given name and parameter count.
|
||||
*
|
||||
* @param clazz - a class to start with.
|
||||
* @param methodName - the method name, or NULL to skip.
|
||||
* @param params - the expected parameters.
|
||||
* @return An object that invokes this specific method.
|
||||
* @throws IllegalStateException If we cannot find this method.
|
||||
*/
|
||||
public static MethodInvoker getMethod(Class<?> clazz, String methodName, Class<?>... params) {
|
||||
return getTypedMethod(clazz, methodName, null, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined method of the given name and parameter count.
|
||||
*
|
||||
* @param clazz - a class to start with.
|
||||
* @param methodName - the method name, or NULL to skip.
|
||||
* @param returnType - the expected return type, or NULL to ignore.
|
||||
* @param params - the expected parameters.
|
||||
* @return An object that invokes this specific method.
|
||||
* @throws IllegalStateException If we cannot find this method.
|
||||
*/
|
||||
public static MethodInvoker getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if ((methodName == null || method.getName().equals(methodName)) && (returnType == null) || method.getReturnType().equals(returnType) && Arrays.equals(method.getParameterTypes(), params)) {
|
||||
method.setAccessible(true);
|
||||
|
||||
return (target, arguments) -> {
|
||||
try {
|
||||
return method.invoke(target, arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot invoke method " + method, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Search in every superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return getMethod(clazz.getSuperclass(), methodName, params);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined constructor of the given name and parameter count.
|
||||
*
|
||||
* @param className - lookup name of the class, see {@link #getClass(String)}.
|
||||
* @param params - the expected parameters.
|
||||
* @return An object that invokes this constructor.
|
||||
* @throws IllegalStateException If we cannot find this method.
|
||||
*/
|
||||
public static ConstructorInvoker getConstructor(String className, Class<?>... params) {
|
||||
return getConstructor(getClass(className), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first publicly and privately defined constructor of the given name and parameter count.
|
||||
*
|
||||
* @param clazz - a class to start with.
|
||||
* @param params - the expected parameters.
|
||||
* @return An object that invokes this constructor.
|
||||
* @throws IllegalStateException If we cannot find this method.
|
||||
*/
|
||||
public static ConstructorInvoker getConstructor(Class<?> clazz, Class<?>... params) {
|
||||
for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) {
|
||||
if (Arrays.equals(constructor.getParameterTypes(), params)) {
|
||||
constructor.setAccessible(true);
|
||||
|
||||
return arguments -> {
|
||||
try {
|
||||
return constructor.newInstance(arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot invoke constructor " + constructor, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class from its full name, without knowing its type on compile time.
|
||||
* <p>
|
||||
* This is useful when looking up fields by a NMS or OBC type.
|
||||
* <p>
|
||||
*
|
||||
* @param lookupName - the class name with variables.
|
||||
* @return The class.
|
||||
* @see Object#getClass()
|
||||
*/
|
||||
public static Class<Object> getUntypedClass(String lookupName) {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
Class<Object> clazz = (Class) getClass(lookupName);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class from its full name.
|
||||
* <p>
|
||||
* Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table:
|
||||
* </p>
|
||||
* <table border="1" summary="Variables and description">
|
||||
* <tr>
|
||||
* <th>Variable</th>
|
||||
* <th>Content</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{nms}</td>
|
||||
* <td>Actual package name of net.minecraft.server.VERSION</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{obc}</td>
|
||||
* <td>Actual package name of org.bukkit.craftbukkit.VERSION</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{version}</td>
|
||||
* <td>The current Minecraft package VERSION, if any.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param lookupName - the class name with variables.
|
||||
* @return The looked up class.
|
||||
* @throws IllegalArgumentException If a variable or class could not be found.
|
||||
*/
|
||||
public static Class<?> getClass(String lookupName) {
|
||||
return getCanonicalClass(expandVariables(lookupName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class in the net.minecraft.server.VERSION.* package.
|
||||
*
|
||||
* @param name - the name of the class, excluding the package.
|
||||
* @throws IllegalArgumentException If the class doesn't exist.
|
||||
*/
|
||||
public static Class<?> getMinecraftClass(String name) {
|
||||
return getCanonicalClass(NMS_PREFIX + '.' + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package.
|
||||
*
|
||||
* @param name - the name of the class, excluding the package.
|
||||
* @throws IllegalArgumentException If the class doesn't exist.
|
||||
*/
|
||||
public static Class<?> getCraftBukkitClass(String name) {
|
||||
return getCanonicalClass(OBC_PREFIX + '.' + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class by its canonical name.
|
||||
*
|
||||
* @param canonicalName - the canonical name.
|
||||
* @return The class.
|
||||
*/
|
||||
private static Class<?> getCanonicalClass(String canonicalName) {
|
||||
try {
|
||||
return Class.forName(canonicalName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException("Cannot find " + canonicalName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand variables such as "{nms}" and "{obc}" to their corresponding packages.
|
||||
*
|
||||
* @param name - the full name of the class.
|
||||
* @return The expanded string.
|
||||
*/
|
||||
private static String expandVariables(String name) {
|
||||
StringBuffer output = new StringBuffer();
|
||||
Matcher matcher = MATCH_VARIABLE.matcher(name);
|
||||
|
||||
while (matcher.find()) {
|
||||
String variable = matcher.group(1);
|
||||
String replacement;
|
||||
|
||||
// Expand all detected variables
|
||||
if ("nms".equalsIgnoreCase(variable)) {
|
||||
replacement = NMS_PREFIX;
|
||||
} else if ("obc".equalsIgnoreCase(variable)) {
|
||||
replacement = OBC_PREFIX;
|
||||
} else if ("version".equalsIgnoreCase(variable)) {
|
||||
replacement = VERSION;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown variable: " + variable);
|
||||
}
|
||||
|
||||
// Assume the expanded variables are all packages, and append a dot
|
||||
if (!replacement.isEmpty() && matcher.end() < name.length() && name.charAt(matcher.end()) != '.') {
|
||||
replacement += ".";
|
||||
}
|
||||
matcher.appendReplacement(output, Matcher.quoteReplacement(replacement));
|
||||
}
|
||||
|
||||
matcher.appendTail(output);
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for invoking a specific constructor.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConstructorInvoker {
|
||||
|
||||
/**
|
||||
* Invoke a constructor for a specific class.
|
||||
*
|
||||
* @param arguments - the arguments to pass to the constructor.
|
||||
* @return The constructed object.
|
||||
*/
|
||||
Object invoke(Object... arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for invoking a specific method.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MethodInvoker {
|
||||
|
||||
/**
|
||||
* Invoke a method on a specific target object.
|
||||
*
|
||||
* @param target - the target object, or NULL for a static method.
|
||||
* @param arguments - the arguments to pass to the method.
|
||||
* @return The return value, or NULL if is void.
|
||||
*/
|
||||
Object invoke(Object target, Object... arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for retrieving the field content.
|
||||
*
|
||||
* @param <T> - field type.
|
||||
*/
|
||||
public interface FieldAccessor<T> {
|
||||
|
||||
/**
|
||||
* Retrieve the content of a field.
|
||||
*
|
||||
* @param target - the target object, or NULL for a static field.
|
||||
* @return The value of the field.
|
||||
*/
|
||||
T get(Object target);
|
||||
|
||||
/**
|
||||
* Set the content of a field.
|
||||
*
|
||||
* @param target - the target object, or NULL for a static field.
|
||||
* @param value - the new value of the field.
|
||||
*/
|
||||
void set(Object target, Object value);
|
||||
|
||||
/**
|
||||
* Determine if the given object has this field.
|
||||
*
|
||||
* @param target - the object to test.
|
||||
* @return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
boolean hasField(Object target);
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plan.system.settings.ConfigSettingKeyTest;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
|
||||
import com.djrapitops.plan.system.settings.paths.key.Setting;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import rules.BukkitComponentMocker;
|
||||
import rules.ComponentMocker;
|
||||
import utilities.OptionalAssert;
|
||||
import utilities.RandomData;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for Bukkit PlanSystem.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class BukkitSystemTest {
|
||||
|
||||
@ClassRule
|
||||
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public ComponentMocker component = new BukkitComponentMocker(temporaryFolder);
|
||||
|
||||
private final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
|
||||
private PlanSystem system;
|
||||
|
||||
@Before
|
||||
public void prepareSystem() {
|
||||
system = component.getPlanSystem();
|
||||
system.getConfigSystem().getConfig()
|
||||
.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bukkitSystemEnables() throws EnableException {
|
||||
try {
|
||||
system.enable();
|
||||
assertTrue(system.isEnabled());
|
||||
} finally {
|
||||
system.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctWebAddressInDatabaseAfterEnable() throws EnableException {
|
||||
try {
|
||||
system.enable();
|
||||
Database database = system.getDatabaseSystem().getDatabase();
|
||||
String expectedAddress = system.getWebServerSystem().getWebServer().getAccessAddress();
|
||||
Optional<String> found = database.query(ServerQueries.fetchServerMatchingIdentifier(system.getServerInfo().getServerUUID()))
|
||||
.map(Server::getWebAddress);
|
||||
|
||||
OptionalAssert.equals(expectedAddress, found);
|
||||
} finally {
|
||||
system.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bukkitSystemHasDefaultConfigValuesAfterEnable() throws EnableException, IllegalAccessException {
|
||||
try {
|
||||
system.enable();
|
||||
PlanConfig config = system.getConfigSystem().getConfig();
|
||||
|
||||
Collection<Setting> serverSettings = ConfigSettingKeyTest.getServerSettings();
|
||||
ConfigSettingKeyTest.assertValidDefaultValuesForAllSettings(config, serverSettings);
|
||||
} finally {
|
||||
system.disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners;
|
||||
|
||||
import com.djrapitops.plan.system.listeners.bukkit.AFKListener;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plugin.logging.console.TestPluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ConsoleErrorLogger;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import utilities.TestConstants;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Test for {@link AFKListener}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class AFKListenerTest {
|
||||
|
||||
private AFKListener underTest;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
PlanConfig config = Mockito.mock(PlanConfig.class);
|
||||
when(config.get(TimeSettings.AFK_THRESHOLD)).thenReturn(TimeUnit.MINUTES.toMillis(3));
|
||||
underTest = new AFKListener(config, new ConsoleErrorLogger(new TestPluginLogger()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afkPermissionIsNotCalledMoreThanOnce() {
|
||||
Player player = mockPlayer();
|
||||
PlayerMoveEvent event = mockMoveEvent(player);
|
||||
|
||||
underTest.onMove(event);
|
||||
underTest.onMove(event);
|
||||
|
||||
verify(player, times(1)).hasPermission(anyString());
|
||||
}
|
||||
|
||||
private PlayerMoveEvent mockMoveEvent(Player player) {
|
||||
PlayerMoveEvent event = Mockito.mock(PlayerMoveEvent.class);
|
||||
when(event.getPlayer()).thenReturn(player);
|
||||
return event;
|
||||
}
|
||||
|
||||
private Player mockPlayer() {
|
||||
Player player = Mockito.mock(Player.class);
|
||||
when(player.getUniqueId()).thenReturn(TestConstants.PLAYER_ONE_UUID);
|
||||
when(player.hasPermission(anyString())).thenReturn(true);
|
||||
return player;
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package rules;
|
||||
|
||||
import com.djrapitops.plan.DaggerPlanBukkitComponent;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanBukkitComponent;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import utilities.mocks.PlanBukkitMocker;
|
||||
|
||||
public class BukkitComponentMocker extends ExternalResource implements ComponentMocker {
|
||||
|
||||
private final TemporaryFolder testFolder;
|
||||
|
||||
private Plan planMock;
|
||||
private PlanBukkitComponent component;
|
||||
|
||||
public BukkitComponentMocker(TemporaryFolder testFolder) {
|
||||
this.testFolder = testFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
PlanBukkitMocker mocker = PlanBukkitMocker.setUp()
|
||||
.withDataFolder(testFolder.newFolder())
|
||||
.withPluginDescription()
|
||||
.withResourceFetchingFromJar()
|
||||
.withServer();
|
||||
planMock = mocker.getPlanMock();
|
||||
component = DaggerPlanBukkitComponent.builder().plan(planMock).build();
|
||||
}
|
||||
|
||||
public PlanPlugin getPlanMock() {
|
||||
return planMock;
|
||||
}
|
||||
|
||||
public PlanSystem getPlanSystem() {
|
||||
return component.system();
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package utilities.mocks;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import com.djrapitops.plugin.command.ColorScheme;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.console.TestPluginLogger;
|
||||
import com.djrapitops.plugin.logging.debug.CombineDebugLogger;
|
||||
import com.djrapitops.plugin.logging.debug.DebugLogger;
|
||||
import com.djrapitops.plugin.logging.debug.MemoryDebugLogger;
|
||||
import com.djrapitops.plugin.logging.error.ConsoleErrorLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.plugin.InvalidDescriptionException;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.mockito.Mockito;
|
||||
import utilities.TestConstants;
|
||||
import utilities.mocks.objects.TestLogger;
|
||||
import utilities.mocks.objects.TestRunnableFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
||||
/**
|
||||
* Mocking Utility for Bukkit version of Plan.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanBukkitMocker extends Mocker {
|
||||
|
||||
private Plan planMock;
|
||||
|
||||
private PlanBukkitMocker() {
|
||||
}
|
||||
|
||||
public static PlanBukkitMocker setUp() {
|
||||
return new PlanBukkitMocker().mockPlugin();
|
||||
}
|
||||
|
||||
private PlanBukkitMocker mockPlugin() {
|
||||
planMock = Mockito.mock(Plan.class);
|
||||
super.planMock = planMock;
|
||||
|
||||
doReturn(new ColorScheme("§1", "§2", "§3")).when(planMock).getColorScheme();
|
||||
doReturn("1.0.0").when(planMock).getVersion();
|
||||
|
||||
TestLogger testLogger = new TestLogger();
|
||||
RunnableFactory runnableFactory = new TestRunnableFactory();
|
||||
PluginLogger testPluginLogger = new TestPluginLogger();
|
||||
DebugLogger debugLogger = new CombineDebugLogger(new MemoryDebugLogger());
|
||||
ErrorHandler consoleErrorLogger = new ConsoleErrorLogger(testPluginLogger);
|
||||
Timings timings = new Timings(debugLogger);
|
||||
|
||||
Mockito.doReturn(testLogger).when(planMock).getLogger();
|
||||
doReturn(runnableFactory).when(planMock).getRunnableFactory();
|
||||
doReturn(testPluginLogger).when(planMock).getPluginLogger();
|
||||
doReturn(debugLogger).when(planMock).getDebugLogger();
|
||||
doReturn(consoleErrorLogger).when(planMock).getErrorHandler();
|
||||
doReturn(timings).when(planMock).getTimings();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBukkitMocker withDataFolder(File tempFolder) {
|
||||
doReturn(tempFolder).when(planMock).getDataFolder();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PlanBukkitMocker withLogging() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBukkitMocker withPluginDescription() {
|
||||
try {
|
||||
File pluginYml = getFile("/plugin.yml");
|
||||
PluginDescriptionFile description = new PluginDescriptionFile(new FileInputStream(pluginYml));
|
||||
doReturn(description).when(planMock).getDescription();
|
||||
} catch (FileNotFoundException | InvalidDescriptionException e) {
|
||||
System.out.println("Error while setting plugin description");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBukkitMocker withResourceFetchingFromJar() throws IOException {
|
||||
withPluginFiles();
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBukkitMocker withServer() {
|
||||
Server serverMock = Mockito.mock(Server.class);
|
||||
doReturn("").when(serverMock).getIp();
|
||||
doReturn("Bukkit").when(serverMock).getName();
|
||||
doReturn("Bukkit").when(serverMock).getServerName();
|
||||
doReturn(25565).when(serverMock).getPort();
|
||||
doReturn("1.12.2").when(serverMock).getVersion();
|
||||
doReturn("32423").when(serverMock).getBukkitVersion();
|
||||
Mockito.doReturn(TestConstants.BUKKIT_MAX_PLAYERS).when(serverMock).getMaxPlayers();
|
||||
ConsoleCommandSender sender = Mockito.mock(ConsoleCommandSender.class);
|
||||
doReturn(sender).when(serverMock).getConsoleSender();
|
||||
|
||||
BukkitScheduler bukkitScheduler = Mockito.mock(BukkitScheduler.class);
|
||||
doReturn(bukkitScheduler).when(serverMock).getScheduler();
|
||||
|
||||
doReturn(serverMock).when(planMock).getServer();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Plan getPlanMock() {
|
||||
return planMock;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
mock-maker-inline
|
@ -1,20 +0,0 @@
|
||||
dependencies {
|
||||
compile project(path: ":common", configuration: 'shadow')
|
||||
|
||||
compile "com.djrapitops:AbstractPluginFramework-bungeecord:$abstractPluginFrameworkVersion"
|
||||
compile "org.bstats:bstats-bungeecord:$bstatsVersion"
|
||||
|
||||
compileOnly "net.md-5:bungeecord-api:$bungeeVersion"
|
||||
compileOnly "com.imaginarycode.minecraft:RedisBungee:$redisBungeeVersion"
|
||||
testCompile "net.md-5:bungeecord-api:$bungeeVersion"
|
||||
testCompile "com.imaginarycode.minecraft:RedisBungee:$redisBungeeVersion"
|
||||
|
||||
testCompile project(path: ":common", configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
configurations = [project.configurations.compile]
|
||||
|
||||
relocate 'org.bstats', 'com.djrapitops.plan.utilities.metrics'
|
||||
relocate 'org.slf4j', 'plan.org.slf4j'
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class BStatsBungee {
|
||||
|
||||
private final PlanBungee plugin;
|
||||
private final Database database;
|
||||
private final ConnectionSystem connectionSystem;
|
||||
|
||||
private Metrics metrics;
|
||||
|
||||
public BStatsBungee(PlanBungee plugin, Database database, ConnectionSystem connectionSystem) {
|
||||
this.plugin = plugin;
|
||||
this.database = database;
|
||||
this.connectionSystem = connectionSystem;
|
||||
}
|
||||
|
||||
public void registerMetrics() {
|
||||
if (metrics == null) {
|
||||
metrics = new Metrics(plugin);
|
||||
}
|
||||
registerConfigSettingGraphs();
|
||||
}
|
||||
|
||||
private void registerConfigSettingGraphs() {
|
||||
String serverType = plugin.getProxy().getName();
|
||||
String databaseType = database.getType().getName();
|
||||
|
||||
addStringSettingPie("server_type", serverType);
|
||||
addStringSettingPie("database_type", databaseType);
|
||||
addStringSettingPie("network_servers", connectionSystem.getDataServers().size());
|
||||
}
|
||||
|
||||
protected void addStringSettingPie(String id, Serializable setting) {
|
||||
metrics.addCustomChart(new Metrics.SimplePie(id, setting::toString));
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.command.PlanProxyCommand;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plan.system.settings.theme.PlanColorScheme;
|
||||
import com.djrapitops.plugin.BungeePlugin;
|
||||
import com.djrapitops.plugin.command.ColorScheme;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Bungee Main class.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanBungee extends BungeePlugin implements PlanPlugin {
|
||||
|
||||
private PlanSystem system;
|
||||
private Locale locale;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
PlanBungeeComponent component = DaggerPlanBungeeComponent.builder().plan(this).build();
|
||||
try {
|
||||
system = component.system();
|
||||
locale = system.getLocaleSystem().getLocale();
|
||||
system.enable();
|
||||
|
||||
new BStatsBungee(
|
||||
this,
|
||||
system.getDatabaseSystem().getDatabase(),
|
||||
system.getInfoSystem().getConnectionSystem()
|
||||
).registerMetrics();
|
||||
|
||||
logger.info(locale.getString(PluginLang.ENABLED));
|
||||
} catch (AbstractMethodError e) {
|
||||
logger.error("Plugin ran into AbstractMethodError - Server restart is required. Likely cause is updating the jar without a restart.");
|
||||
} catch (EnableException e) {
|
||||
logger.error("----------------------------------------");
|
||||
logger.error("Error: " + e.getMessage());
|
||||
logger.error("----------------------------------------");
|
||||
logger.error("Plugin Failed to Initialize Correctly. If this issue is caused by config settings you can use /planbungee reload");
|
||||
onDisable();
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.CRITICAL, this.getClass(), e);
|
||||
logger.error("Plugin Failed to Initialize Correctly. If this issue is caused by config settings you can use /planbungee reload");
|
||||
logger.error("This error should be reported at https://github.com/Rsl1122/Plan-PlayerAnalytics/issues");
|
||||
onDisable();
|
||||
}
|
||||
PlanProxyCommand command = component.planCommand();
|
||||
command.registerCommands();
|
||||
registerCommand("planbungee", command);
|
||||
if (system != null) {
|
||||
system.getProcessing().submitNonCritical(() -> system.getListenerSystem().callEnableEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (system != null) system.disable();
|
||||
|
||||
logger.info(locale.getString(PluginLang.DISABLED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return super.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Nothing to be done, systems are disabled
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResource(String resource) {
|
||||
return getResourceAsStream(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorScheme getColorScheme() {
|
||||
return PlanColorScheme.create(system.getConfigSystem().getConfig(), logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanSystem getSystem() {
|
||||
return system;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReloading() {
|
||||
return reloading;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.command.PlanProxyCommand;
|
||||
import com.djrapitops.plan.modules.APFModule;
|
||||
import com.djrapitops.plan.modules.FilesModule;
|
||||
import com.djrapitops.plan.modules.ProxySuperClassBindingModule;
|
||||
import com.djrapitops.plan.modules.SystemObjectProvidingModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeCommandModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeePlanModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeServerPropertiesModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeSuperClassBindingModule;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.pluginbridge.plan.PluginBridgeModule;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Dagger Component that constructs the plugin systems running on Bungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
BungeePlanModule.class,
|
||||
BungeeCommandModule.class,
|
||||
SystemObjectProvidingModule.class,
|
||||
APFModule.class,
|
||||
FilesModule.class,
|
||||
ProxySuperClassBindingModule.class,
|
||||
BungeeSuperClassBindingModule.class,
|
||||
BungeeServerPropertiesModule.class,
|
||||
PluginBridgeModule.Bungee.class
|
||||
})
|
||||
public interface PlanBungeeComponent {
|
||||
|
||||
PlanProxyCommand planCommand();
|
||||
|
||||
PlanSystem system();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder plan(PlanBungee plan);
|
||||
|
||||
PlanBungeeComponent build();
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.api.events;
|
||||
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* Event that is called when Plan is enabled.
|
||||
* <p>
|
||||
* This includes, but might not be limited to:
|
||||
* - First time the plugin enables successfully
|
||||
* - Plan is reloaded
|
||||
* - Plan is enabled after it was disabled
|
||||
* <p>
|
||||
* {@code event.isPlanSystemEnabled()} can be called to determine if the enable was successful.
|
||||
* It is not guaranteed that this event is called when the plugin fails to enable properly.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanBungeeEnableEvent extends Event {
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
public PlanBungeeEnableEvent(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isPlanSystemEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bungee;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
@Module
|
||||
public class BungeeCommandModule {
|
||||
|
||||
@Provides
|
||||
@Named("mainCommandName")
|
||||
String provideMainCommandName() {
|
||||
return "planbungee";
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bungee;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.command.PlanProxyCommand;
|
||||
import com.djrapitops.plugin.command.CommandNode;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Dagger module for binding PlanBungee instance.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public interface BungeePlanModule {
|
||||
|
||||
@Binds
|
||||
PlanPlugin bindPlanPlugin(PlanBungee plugin);
|
||||
|
||||
@Binds
|
||||
@Named("mainCommand")
|
||||
CommandNode bindMainCommand(PlanProxyCommand command);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bungee;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.system.info.server.properties.BungeeServerProperties;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Dagger module for Bungee ServerProperties.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public class BungeeServerPropertiesModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ServerProperties provideServerProperties(PlanBungee plugin, PlanConfig config) {
|
||||
return new BungeeServerProperties(plugin.getProxy(), config);
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bungee;
|
||||
|
||||
import com.djrapitops.plan.system.info.server.BungeeServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.listeners.BungeeListenerSystem;
|
||||
import com.djrapitops.plan.system.listeners.ListenerSystem;
|
||||
import com.djrapitops.plan.system.tasks.BungeeTaskSystem;
|
||||
import com.djrapitops.plan.system.tasks.TaskSystem;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
|
||||
/**
|
||||
* Module for binding Bungee specific classes to the interface implementations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Module
|
||||
public interface BungeeSuperClassBindingModule {
|
||||
|
||||
@Binds
|
||||
ServerInfo bindBungeeServerInfo(BungeeServerInfo bungeeServerInfo);
|
||||
|
||||
@Binds
|
||||
TaskSystem bindBungeeTaskSystem(BungeeTaskSystem bungeeTaskSystem);
|
||||
|
||||
@Binds
|
||||
ListenerSystem bindBungeeListenerSystem(BungeeListenerSystem bungeeListenerSystem);
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.info.server;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.StoreServerInformationTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.webserver.WebServer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import dagger.Lazy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Manages Server information on the Bungee instance.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BungeeServerInfo extends ServerInfo {
|
||||
|
||||
private final DBSystem dbSystem;
|
||||
private final Lazy<WebServer> webServer;
|
||||
private final PluginLogger logger;
|
||||
|
||||
@Inject
|
||||
public BungeeServerInfo(
|
||||
ServerProperties serverProperties,
|
||||
DBSystem dbSystem,
|
||||
Lazy<WebServer> webServer,
|
||||
PluginLogger logger
|
||||
) {
|
||||
super(serverProperties);
|
||||
this.dbSystem = dbSystem;
|
||||
this.webServer = webServer;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadServerInfo() throws EnableException {
|
||||
checkIfDefaultIP();
|
||||
|
||||
try {
|
||||
Database database = dbSystem.getDatabase();
|
||||
Optional<Server> proxyInfo = database.query(ServerQueries.fetchProxyServerInformation());
|
||||
if (proxyInfo.isPresent()) {
|
||||
server = proxyInfo.get();
|
||||
updateServerInfo(database);
|
||||
} else {
|
||||
server = registerBungeeInfo(database);
|
||||
}
|
||||
} catch (DBOpException | ExecutionException e) {
|
||||
throw new EnableException("Failed to read Server information from Database.");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateServerInfo(Database db) {
|
||||
String accessAddress = webServer.get().getAccessAddress();
|
||||
if (!accessAddress.equals(server.getWebAddress())) {
|
||||
server.setWebAddress(accessAddress);
|
||||
db.executeTransaction(new StoreServerInformationTransaction(server));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIfDefaultIP() throws EnableException {
|
||||
String ip = serverProperties.getIp();
|
||||
if ("0.0.0.0".equals(ip)) {
|
||||
logger.error("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server.");
|
||||
logger.info("Player Analytics partially enabled (Use /planbungee to reload config)");
|
||||
throw new EnableException("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server.");
|
||||
}
|
||||
}
|
||||
|
||||
private Server registerBungeeInfo(Database db) throws EnableException, ExecutionException, InterruptedException {
|
||||
UUID serverUUID = generateNewUUID();
|
||||
String accessAddress = webServer.get().getAccessAddress();
|
||||
|
||||
Server proxy = new Server(-1, serverUUID, "BungeeCord", accessAddress, serverProperties.getMaxPlayers());
|
||||
db.executeTransaction(new StoreServerInformationTransaction(proxy))
|
||||
.get();
|
||||
|
||||
Optional<Server> proxyInfo = db.query(ServerQueries.fetchProxyServerInformation());
|
||||
if (proxyInfo.isPresent()) {
|
||||
return proxyInfo.get();
|
||||
}
|
||||
throw new EnableException("BungeeCord registration failed (DB)");
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.info.server.properties;
|
||||
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.ProxySettings;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
/**
|
||||
* ServerProperties for Bungee.
|
||||
* <p>
|
||||
* Supports RedisBungee for Players online getting.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class BungeeServerProperties extends ServerProperties {
|
||||
|
||||
public BungeeServerProperties(ProxyServer server, PlanConfig config) {
|
||||
super(
|
||||
"BungeeCord",
|
||||
-1,
|
||||
server.getVersion(),
|
||||
server.getVersion(),
|
||||
() -> config.get(ProxySettings.IP),
|
||||
server.getConfig().getPlayerLimit(),
|
||||
RedisCheck.isClassAvailable() ? new RedisPlayersOnlineSupplier() : server::getOnlineCount
|
||||
);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.info.server.properties;
|
||||
|
||||
import com.djrapitops.plugin.api.Check;
|
||||
|
||||
/**
|
||||
* Utility class for checking if RedisBungee API is available.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RedisCheck {
|
||||
|
||||
private RedisCheck() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
public static boolean isClassAvailable() {
|
||||
return Check.isAvailable("com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI");
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.info.server.properties;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
/**
|
||||
* Players online supplier when using RedisBungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RedisPlayersOnlineSupplier implements IntSupplier {
|
||||
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
return RedisBungee.getApi().getPlayerCount();
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.api.events.PlanBungeeEnableEvent;
|
||||
import com.djrapitops.plan.capability.CapabilityServiceImplementation;
|
||||
import com.djrapitops.plan.system.listeners.bungee.PlayerOnlineListener;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class BungeeListenerSystem extends ListenerSystem {
|
||||
|
||||
private final PlanBungee plugin;
|
||||
private PlayerOnlineListener playerOnlineListener;
|
||||
|
||||
@Inject
|
||||
public BungeeListenerSystem(PlanBungee plugin, PlayerOnlineListener playerOnlineListener) {
|
||||
this.plugin = plugin;
|
||||
this.playerOnlineListener = playerOnlineListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerListeners() {
|
||||
plugin.registerListener(playerOnlineListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListeners() {
|
||||
plugin.getProxy().getPluginManager().unregisterListeners(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEnableEvent(PlanPlugin plugin) {
|
||||
boolean isEnabled = plugin.isSystemEnabled();
|
||||
PlanBungeeEnableEvent event = new PlanBungeeEnableEvent(isEnabled);
|
||||
((PlanBungee) plugin).getProxy().getPluginManager().callEvent(event);
|
||||
CapabilityServiceImplementation.notifyAboutEnable(isEnabled);
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.system.webserver.cache.PageId;
|
||||
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.net.InetAddress;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Player Join listener for Bungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerOnlineListener implements Listener {
|
||||
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final DBSystem dbSystem;
|
||||
private final ExtensionServiceImplementation extensionService;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final SessionCache sessionCache;
|
||||
private final ServerInfo serverInfo;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public PlayerOnlineListener(
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ExtensionServiceImplementation extensionService,
|
||||
GeolocationCache geolocationCache,
|
||||
SessionCache sessionCache,
|
||||
ServerInfo serverInfo,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.dbSystem = dbSystem;
|
||||
this.extensionService = extensionService;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.sessionCache = sessionCache;
|
||||
this.serverInfo = serverInfo;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String playerName = player.getName();
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverInfo.getServerUUID(), time, null, null));
|
||||
Database database = dbSystem.getDatabase();
|
||||
|
||||
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
|
||||
if (gatheringGeolocations) {
|
||||
database.executeTransaction(
|
||||
new GeoInfoStoreTransaction(playerUUID, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
|
||||
database.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> time, playerName));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_JOIN));
|
||||
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void beforeLogout(PlayerDisconnectEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String playerName = player.getName();
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_LEAVE));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onLogout(PlayerDisconnectEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
sessionCache.endSession(playerUUID, System.currentTimeMillis());
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
// Replaces the current session in the cache.
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverInfo.getServerUUID(), time, null, null));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bungee.BungeeTPSCountTimer;
|
||||
import com.djrapitops.plan.system.tasks.bungee.PingCountTimerBungee;
|
||||
import com.djrapitops.plan.system.tasks.proxy.NetworkConfigStoreTask;
|
||||
import com.djrapitops.plan.system.tasks.proxy.NetworkPageRefreshTask;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* TaskSystem responsible for registering tasks for Bungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BungeeTaskSystem extends TaskSystem {
|
||||
|
||||
private final PlanBungee plugin;
|
||||
private final PlanConfig config;
|
||||
private final NetworkPageRefreshTask networkPageRefreshTask;
|
||||
private final PingCountTimerBungee pingCountTimer;
|
||||
private final LogsFolderCleanTask logsFolderCleanTask;
|
||||
private final PlayersPageRefreshTask playersPageRefreshTask;
|
||||
private final NetworkConfigStoreTask networkConfigStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
|
||||
@Inject
|
||||
public BungeeTaskSystem(
|
||||
PlanBungee plugin,
|
||||
PlanConfig config,
|
||||
RunnableFactory runnableFactory,
|
||||
BungeeTPSCountTimer bungeeTPSCountTimer,
|
||||
NetworkPageRefreshTask networkPageRefreshTask,
|
||||
PingCountTimerBungee pingCountTimer,
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
NetworkConfigStoreTask networkConfigStoreTask,
|
||||
DBCleanTask dbCleanTask,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask
|
||||
) {
|
||||
super(runnableFactory, bungeeTPSCountTimer);
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
|
||||
this.networkPageRefreshTask = networkPageRefreshTask;
|
||||
this.pingCountTimer = pingCountTimer;
|
||||
this.logsFolderCleanTask = logsFolderCleanTask;
|
||||
this.playersPageRefreshTask = playersPageRefreshTask;
|
||||
this.networkConfigStoreTask = networkConfigStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
registerTasks();
|
||||
}
|
||||
|
||||
private void registerTasks() {
|
||||
registerTask(tpsCountTimer).runTaskTimerAsynchronously(1000, TimeAmount.toTicks(1L, TimeUnit.SECONDS));
|
||||
registerTask(networkPageRefreshTask).runTaskTimerAsynchronously(1500, TimeAmount.toTicks(5L, TimeUnit.MINUTES));
|
||||
registerTask(logsFolderCleanTask).runTaskLaterAsynchronously(TimeAmount.toTicks(30L, TimeUnit.SECONDS));
|
||||
|
||||
Long pingDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (pingDelay < TimeUnit.HOURS.toMillis(1L) && config.get(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(pingCountTimer);
|
||||
long startDelay = TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS);
|
||||
registerTask(pingCountTimer).runTaskTimer(startDelay, 40L);
|
||||
}
|
||||
|
||||
registerTask(playersPageRefreshTask)
|
||||
.runTaskTimerAsynchronously(TimeAmount.toTicks(5L, TimeUnit.MINUTES), TimeAmount.toTicks(5L, TimeUnit.MINUTES));
|
||||
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask(networkConfigStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.tasks.TPSCountTimer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class BungeeTPSCountTimer extends TPSCountTimer {
|
||||
|
||||
private final ServerProperties serverProperties;
|
||||
|
||||
@Inject
|
||||
public BungeeTPSCountTimer(
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
ServerProperties serverProperties,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(dbSystem, serverInfo, logger, errorHandler);
|
||||
this.serverProperties = serverProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNewTPSEntry(long nanoTime, long now) {
|
||||
int onlineCount = serverProperties.getOnlinePlayers();
|
||||
TPS tps = TPSBuilder.get()
|
||||
.date(now)
|
||||
.playersOnline(onlineCount)
|
||||
.usedCPU(getCPUUsage())
|
||||
.usedMemory(getUsedMemory())
|
||||
.entities(-1)
|
||||
.chunksLoaded(-1)
|
||||
.freeDiskSpace(getFreeDiskSpace())
|
||||
.toTPS();
|
||||
|
||||
history.add(tps);
|
||||
latestPlayersOnline = onlineCount;
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016-2018
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.djrapitops.plan.system.tasks.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.DateObj;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PingStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.event.ServerDisconnectEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Task that handles player ping calculation on Bungee based servers.
|
||||
*
|
||||
* @author BrainStone
|
||||
*/
|
||||
@Singleton
|
||||
public class PingCountTimerBungee extends AbsRunnable implements Listener {
|
||||
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public PingCountTimerBungee(
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.runnableFactory = runnableFactory;
|
||||
playerHistory = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long time = System.currentTimeMillis();
|
||||
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<UUID, List<DateObj<Integer>>> entry = iterator.next();
|
||||
UUID uuid = entry.getKey();
|
||||
List<DateObj<Integer>> history = entry.getValue();
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid);
|
||||
if (player != null) {
|
||||
int ping = getPing(player);
|
||||
if (ping < -1 || ping > TimeUnit.SECONDS.toMillis(8L)) {
|
||||
// Don't accept bad values
|
||||
continue;
|
||||
}
|
||||
history.add(new DateObj<>(time, ping));
|
||||
if (history.size() >= 30) {
|
||||
dbSystem.getDatabase().executeTransaction(
|
||||
new PingStoreTransaction(uuid, serverInfo.getServerUUID(), new ArrayList<>(history))
|
||||
);
|
||||
history.clear();
|
||||
}
|
||||
} else {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPlayer(ProxiedPlayer player) {
|
||||
playerHistory.put(player.getUniqueId(), new ArrayList<>());
|
||||
}
|
||||
|
||||
public void removePlayer(ProxiedPlayer player) {
|
||||
playerHistory.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
private int getPing(ProxiedPlayer player) {
|
||||
return player.getPing();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(ServerConnectedEvent joinEvent) {
|
||||
ProxiedPlayer player = joinEvent.getPlayer();
|
||||
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
|
||||
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
|
||||
return;
|
||||
}
|
||||
runnableFactory.create("Add Player to Ping list", new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.isConnected()) {
|
||||
addPlayer(player);
|
||||
}
|
||||
}
|
||||
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(ServerDisconnectEvent quitEvent) {
|
||||
removePlayer(quitEvent.getPlayer());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
playerHistory.clear();
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
|
||||
import com.djrapitops.plan.system.settings.paths.ProxySettings;
|
||||
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import rules.BungeeComponentMocker;
|
||||
import rules.ComponentMocker;
|
||||
import utilities.CIProperties;
|
||||
import utilities.RandomData;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
/**
|
||||
* Test for Bungee PlanSystem.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class BungeeSystemTest {
|
||||
|
||||
@ClassRule
|
||||
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
|
||||
|
||||
@Rule
|
||||
public ComponentMocker component = new BungeeComponentMocker(temporaryFolder);
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void bungeeEnables() throws Exception {
|
||||
PlanSystem bungeeSystem = component.getPlanSystem();
|
||||
try {
|
||||
PlanConfig config = bungeeSystem.getConfigSystem().getConfig();
|
||||
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
|
||||
config.set(ProxySettings.IP, "8.8.8.8");
|
||||
|
||||
DBSystem dbSystem = bungeeSystem.getDatabaseSystem();
|
||||
SQLiteDB db = dbSystem.getSqLiteFactory().usingDefaultFile();
|
||||
db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
|
||||
dbSystem.setActiveDatabase(db);
|
||||
|
||||
bungeeSystem.enable();
|
||||
assertTrue(bungeeSystem.isEnabled());
|
||||
} finally {
|
||||
bungeeSystem.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bungeeDoesNotEnableWithDefaultIP() throws Exception {
|
||||
thrown.expect(EnableException.class);
|
||||
thrown.expectMessage("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server.");
|
||||
|
||||
PlanSystem bungeeSystem = component.getPlanSystem();
|
||||
try {
|
||||
PlanConfig config = bungeeSystem.getConfigSystem().getConfig();
|
||||
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
|
||||
config.set(ProxySettings.IP, "0.0.0.0");
|
||||
|
||||
DBSystem dbSystem = bungeeSystem.getDatabaseSystem();
|
||||
SQLiteDB db = dbSystem.getSqLiteFactory().usingDefaultFile();
|
||||
db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
|
||||
dbSystem.setActiveDatabase(db);
|
||||
|
||||
bungeeSystem.enable(); // Throws EnableException
|
||||
} finally {
|
||||
bungeeSystem.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableNoMySQL() throws EnableException {
|
||||
thrown.expect(EnableException.class);
|
||||
|
||||
PlanSystem bungeeSystem = component.getPlanSystem();
|
||||
try {
|
||||
PlanConfig config = bungeeSystem.getConfigSystem().getConfig();
|
||||
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
|
||||
config.set(ProxySettings.IP, "8.8.8.8");
|
||||
|
||||
bungeeSystem.enable(); // Throws EnableException
|
||||
} finally {
|
||||
bungeeSystem.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableWithMySQL() throws EnableException {
|
||||
boolean isCI = Boolean.parseBoolean(System.getenv(CIProperties.IS_CI_SERVICE));
|
||||
assumeTrue(isCI);
|
||||
|
||||
PlanSystem bungeeSystem = component.getPlanSystem();
|
||||
try {
|
||||
PlanConfig config = bungeeSystem.getConfigSystem().getConfig();
|
||||
config.set(DatabaseSettings.MYSQL_DATABASE, "Plan");
|
||||
config.set(DatabaseSettings.MYSQL_USER, "travis");
|
||||
config.set(DatabaseSettings.MYSQL_PASS, "");
|
||||
config.set(DatabaseSettings.MYSQL_HOST, "127.0.0.1");
|
||||
config.set(DatabaseSettings.TYPE, "MySQL");
|
||||
|
||||
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
|
||||
config.set(ProxySettings.IP, "8.8.8.8");
|
||||
|
||||
bungeeSystem.enable();
|
||||
assertTrue(bungeeSystem.isEnabled());
|
||||
} finally {
|
||||
bungeeSystem.disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package rules;
|
||||
|
||||
import com.djrapitops.plan.DaggerPlanBungeeComponent;
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.PlanBungeeComponent;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import utilities.mocks.PlanBungeeMocker;
|
||||
|
||||
public class BungeeComponentMocker extends ExternalResource implements ComponentMocker {
|
||||
|
||||
private final TemporaryFolder testFolder;
|
||||
|
||||
private PlanBungee planMock;
|
||||
private PlanBungeeComponent component;
|
||||
|
||||
public BungeeComponentMocker(TemporaryFolder testFolder) {
|
||||
this.testFolder = testFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
PlanBungeeMocker mocker = PlanBungeeMocker.setUp()
|
||||
.withDataFolder(testFolder.newFolder())
|
||||
.withPluginDescription()
|
||||
.withResourceFetchingFromJar()
|
||||
.withProxy();
|
||||
planMock = mocker.getPlanMock();
|
||||
component = DaggerPlanBungeeComponent.builder().plan(planMock).build();
|
||||
}
|
||||
|
||||
public PlanPlugin getPlanMock() {
|
||||
return planMock;
|
||||
}
|
||||
|
||||
public PlanSystem getPlanSystem() {
|
||||
return component.system();
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package utilities.mocks;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import com.djrapitops.plugin.command.ColorScheme;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.console.TestPluginLogger;
|
||||
import com.djrapitops.plugin.logging.debug.CombineDebugLogger;
|
||||
import com.djrapitops.plugin.logging.debug.DebugLogger;
|
||||
import com.djrapitops.plugin.logging.debug.MemoryDebugLogger;
|
||||
import com.djrapitops.plugin.logging.error.ConsoleErrorLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyConfig;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.PluginDescription;
|
||||
import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import org.mockito.Mockito;
|
||||
import utilities.TestConstants;
|
||||
import utilities.mocks.objects.TestLogger;
|
||||
import utilities.mocks.objects.TestRunnableFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Mocking Utility for Bungee version of Plan (PlanBungee).
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanBungeeMocker extends Mocker {
|
||||
|
||||
private PlanBungee planMock;
|
||||
|
||||
private PlanBungeeMocker() {
|
||||
}
|
||||
|
||||
public static PlanBungeeMocker setUp() {
|
||||
return new PlanBungeeMocker().mockPlugin();
|
||||
}
|
||||
|
||||
private PlanBungeeMocker mockPlugin() {
|
||||
planMock = Mockito.mock(PlanBungee.class);
|
||||
super.planMock = planMock;
|
||||
|
||||
doReturn(new ColorScheme("§1", "§2", "§3")).when(planMock).getColorScheme();
|
||||
doReturn("1.0.0").when(planMock).getVersion();
|
||||
|
||||
TestLogger testLogger = new TestLogger();
|
||||
RunnableFactory runnableFactory = new TestRunnableFactory();
|
||||
PluginLogger testPluginLogger = new TestPluginLogger();
|
||||
DebugLogger debugLogger = new CombineDebugLogger(new MemoryDebugLogger());
|
||||
ErrorHandler consoleErrorLogger = new ConsoleErrorLogger(testPluginLogger);
|
||||
Timings timings = new Timings(debugLogger);
|
||||
|
||||
doReturn(testLogger).when(planMock).getLogger();
|
||||
doReturn(runnableFactory).when(planMock).getRunnableFactory();
|
||||
doReturn(testPluginLogger).when(planMock).getPluginLogger();
|
||||
doReturn(debugLogger).when(planMock).getDebugLogger();
|
||||
doReturn(consoleErrorLogger).when(planMock).getErrorHandler();
|
||||
doReturn(timings).when(planMock).getTimings();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBungeeMocker withDataFolder(File tempFolder) {
|
||||
when(planMock.getDataFolder()).thenReturn(tempFolder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBungeeMocker withResourceFetchingFromJar() throws Exception {
|
||||
withPluginFiles();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PlanBungeeMocker withLogging() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public PlanBungeeMocker withProxy() {
|
||||
ProxyServer proxyMock = Mockito.mock(ProxyServer.class);
|
||||
doReturn("1.12.2").when(proxyMock).getVersion();
|
||||
|
||||
CommandSender console = Mockito.mock(CommandSender.class);
|
||||
doReturn(console).when(proxyMock).getConsole();
|
||||
|
||||
ProxyConfig proxyConfig = Mockito.mock(ProxyConfig.class);
|
||||
doReturn(TestConstants.BUNGEE_MAX_PLAYERS).when(proxyConfig).getPlayerLimit();
|
||||
doReturn(proxyConfig).when(proxyMock).getConfig();
|
||||
|
||||
PluginManager pm = Mockito.mock(PluginManager.class);
|
||||
doReturn(pm).when(proxyMock).getPluginManager();
|
||||
|
||||
doReturn(proxyMock).when(planMock).getProxy();
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBungeeMocker withPluginDescription() {
|
||||
File pluginYml = getFile("/bungee.yml");
|
||||
HashSet<String> empty = new HashSet<>();
|
||||
PluginDescription pluginDescription = new PluginDescription("Plan", "", "9.9.9", "Rsl1122", empty, empty, pluginYml, "");
|
||||
when(planMock.getDescription()).thenReturn(pluginDescription);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlanBungee getPlanMock() {
|
||||
return planMock;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
mock-maker-inline
|
@ -1,97 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
<module name='Checker'>
|
||||
|
||||
<property name="localeCountry" value="EN"/>
|
||||
<property name="localeLanguage" value="en"/>
|
||||
|
||||
<module name='TreeWalker'>
|
||||
|
||||
<property name='tabWidth' value='4'/>
|
||||
|
||||
<!-- Block Checks -->
|
||||
|
||||
<module name='EmptyBlock'/>
|
||||
<module name='LeftCurly'/>
|
||||
<module name='NeedBraces'/>
|
||||
<module name='RightCurly'/>
|
||||
<module name='AvoidNestedBlocks'/>
|
||||
<module name="NestedIfDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="NestedForDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="NestedTryDepth"/>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<module name='Indentation'/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
|
||||
<!--- Naming Conventions -->
|
||||
|
||||
<module name='ClassTypeParameterName'/>
|
||||
<module name='ConstantName'/>
|
||||
<module name='LocalFinalVariableName'/>
|
||||
<module name='LocalVariableName'/>
|
||||
<module name='MemberName'/>
|
||||
<module name='MethodName'/>
|
||||
<module name='MethodTypeParameterName'/>
|
||||
|
||||
<module name='PackageName'>
|
||||
<property name='format' value='^[a-z]+(\.[a-z][a-z0-9]*)*$'/>
|
||||
</module>
|
||||
|
||||
<module name='ParameterName'/>
|
||||
<module name='StaticVariableName'/>
|
||||
<module name='TypeName'/>
|
||||
|
||||
<!-- Whitespace -->
|
||||
|
||||
<module name='GenericWhitespace'/>
|
||||
<module name='EmptyForInitializerPad'/>
|
||||
<module name='EmptyForIteratorPad'/>
|
||||
<module name='MethodParamPad'/>
|
||||
|
||||
<module name='NoWhitespaceAfter'>
|
||||
<property name='tokens' value='BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS'/>
|
||||
</module>
|
||||
|
||||
<module name='NoWhitespaceBefore'>
|
||||
<property name='tokens' value='SEMI, DOT, POST_DEC, POST_INC'/>
|
||||
<property name='allowLineBreaks' value='true'/>
|
||||
</module>
|
||||
|
||||
<module name='ParenPad'/>
|
||||
<module name='TypecastParenPad'/>
|
||||
<module name='WhitespaceAfter'/>
|
||||
|
||||
<module name='WhitespaceAround'>
|
||||
<property name='allowEmptyConstructors' value='true'/>
|
||||
<property name='allowEmptyMethods' value='true'/>
|
||||
</module>
|
||||
|
||||
<!-- Javadoc -->
|
||||
<module name="JavadocMethod">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="allowMissingParamTags" value="false"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
<property name="allowMissingThrowsTags" value="false"/>
|
||||
<property name="allowMissingReturnTag" value="false"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="checkEmptyJavadoc" value="true"/>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
<!-- File Length -->
|
||||
|
||||
<module name='FileLength'>
|
||||
<property name='max' value='2000'/>
|
||||
</module>
|
||||
|
||||
</module>
|
@ -1,56 +0,0 @@
|
||||
dependencies {
|
||||
compile "com.djrapitops:AbstractPluginFramework-api:$abstractPluginFrameworkVersion"
|
||||
compile project(":api")
|
||||
compile project(path: ":extensions", configuration: 'shadow')
|
||||
compile "com.djrapitops:PlanPluginBridge:$planPluginBridgeVersion"
|
||||
compile "org.apache.httpcomponents:httpclient:$httpClientVersion"
|
||||
compile "org.apache.commons:commons-text:$commonsTextVersion"
|
||||
compile "com.googlecode.htmlcompressor:htmlcompressor:$htmlCompressorVersion"
|
||||
compile "com.github.ben-manes.caffeine:caffeine:$caffeineVersion"
|
||||
compile "com.h2database:h2:$h2Version"
|
||||
compile "mysql:mysql-connector-java:$mysqlVersion"
|
||||
compile "com.zaxxer:HikariCP:$hikariVersion"
|
||||
compile "org.slf4j:slf4j-nop:$slf4jVersion"
|
||||
compile "org.slf4j:slf4j-api:$slf4jVersion"
|
||||
compile "com.maxmind.geoip2:geoip2:$geoIpVersion"
|
||||
compileOnly "com.google.guava:guava:$guavaVersion"
|
||||
|
||||
testCompile project(":api")
|
||||
testCompile "com.google.code.gson:gson:2.8.5"
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
configurations = [project.configurations.compile]
|
||||
|
||||
// Exclude these files
|
||||
exclude "**/*.svg"
|
||||
exclude "**/*.ttf"
|
||||
exclude "**/*.woff"
|
||||
exclude "**/*.eot"
|
||||
exclude "**/*.woff2"
|
||||
exclude "**/*.psd"
|
||||
|
||||
exclude "**/module-info.class"
|
||||
exclude 'META-INF/versions/' // Causes Sponge to crash
|
||||
|
||||
relocate('org.apache', 'plan.org.apache') {
|
||||
exclude 'org/apache/logging/**'
|
||||
}
|
||||
relocate 'com.maxmind', 'plan.com.maxmind'
|
||||
relocate 'com.fasterxml', 'plan.com.fasterxml'
|
||||
relocate 'com.zaxxer', 'plan.com.zaxxer'
|
||||
relocate 'com.github.benmanes', 'plan.com.github.benmanes'
|
||||
relocate 'com.googlecode', 'plan.com.googlecode'
|
||||
relocate 'org.h2', 'plan.org.h2'
|
||||
relocate 'org.bstats', 'plan.org.bstats'
|
||||
relocate 'org.slf4j', 'plan.org.slf4j'
|
||||
|
||||
// Exclude test dependencies
|
||||
exclude "org/junit/**/*"
|
||||
exclude "org/opentest4j/**/*"
|
||||
exclude "org/checkerframework/**/*"
|
||||
exclude "org/apiguardian/**/*"
|
||||
exclude "org/mockito/**/*"
|
||||
exclude "org/selenium/**/*"
|
||||
exclude "org/jayway/**/*"
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plugin.IPlugin;
|
||||
import com.djrapitops.plugin.command.ColorScheme;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Abstraction interface for both Plan and PlanBungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface PlanPlugin extends IPlugin {
|
||||
|
||||
@Override
|
||||
File getDataFolder();
|
||||
|
||||
InputStream getResource(String resource);
|
||||
|
||||
ColorScheme getColorScheme();
|
||||
|
||||
@Override
|
||||
boolean isReloading();
|
||||
|
||||
PlanSystem getSystem();
|
||||
|
||||
default boolean isSystemEnabled() {
|
||||
return getSystem().isEnabled();
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.ServerShutdownTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Class in charge of performing save operations when the server shuts down.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class ServerShutdownSave {
|
||||
|
||||
protected final PluginLogger logger;
|
||||
private final DBSystem dbSystem;
|
||||
private final Locale locale;
|
||||
private final ErrorHandler errorHandler;
|
||||
private boolean shuttingDown = false;
|
||||
|
||||
public ServerShutdownSave(
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.locale = locale;
|
||||
this.dbSystem = dbSystem;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
protected abstract boolean checkServerShuttingDownStatus();
|
||||
|
||||
public void serverIsKnownToBeShuttingDown() {
|
||||
shuttingDown = true;
|
||||
}
|
||||
|
||||
public void performSave() {
|
||||
if (!checkServerShuttingDownStatus() && !shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<UUID, Session> activeSessions = SessionCache.getActiveSessions();
|
||||
if (activeSessions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This check ensures that logging is not attempted on JVM shutdown.
|
||||
// Underlying Logger might not be available leading to an exception.
|
||||
if (!shuttingDown) {
|
||||
logger.info(locale.getString(PluginLang.DISABLED_UNSAVED_SESSIONS));
|
||||
}
|
||||
attemptSave(activeSessions);
|
||||
|
||||
SessionCache.clear();
|
||||
}
|
||||
|
||||
private void attemptSave(Map<UUID, Session> activeSessions) {
|
||||
try {
|
||||
prepareSessionsForStorage(activeSessions, System.currentTimeMillis());
|
||||
saveActiveSessions(activeSessions);
|
||||
} catch (DBInitException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} catch (IllegalStateException ignored) {
|
||||
/* Database is not initialized */
|
||||
} finally {
|
||||
closeDatabase(dbSystem.getDatabase());
|
||||
}
|
||||
}
|
||||
|
||||
private void saveActiveSessions(Map<UUID, Session> activeSessions) {
|
||||
Database database = dbSystem.getDatabase();
|
||||
if (database.getState() == Database.State.CLOSED) {
|
||||
// Ensure that database is not closed when performing the transaction.
|
||||
database.init();
|
||||
}
|
||||
|
||||
saveSessions(activeSessions, database);
|
||||
}
|
||||
|
||||
private void prepareSessionsForStorage(Map<UUID, Session> activeSessions, long now) {
|
||||
for (Session session : activeSessions.values()) {
|
||||
Optional<Long> end = session.getValue(SessionKeys.END);
|
||||
if (!end.isPresent()) {
|
||||
session.endSession(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSessions(Map<UUID, Session> activeSessions, Database database) {
|
||||
try {
|
||||
database.executeTransaction(new ServerShutdownTransaction(activeSessions.values()))
|
||||
.get(); // Ensure that the transaction is executed before shutdown.
|
||||
} catch (ExecutionException | DBOpException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDatabase(Database database) {
|
||||
database.close();
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Thread that is run when JVM shuts down.
|
||||
* <p>
|
||||
* Saves active sessions to the Database (PlayerQuitEvent is not called)
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ShutdownHook extends Thread {
|
||||
|
||||
private static ShutdownHook activated;
|
||||
|
||||
private final ServerShutdownSave serverShutdownSave;
|
||||
|
||||
@Inject
|
||||
public ShutdownHook(ServerShutdownSave serverShutdownSave) {
|
||||
this.serverShutdownSave = serverShutdownSave;
|
||||
}
|
||||
|
||||
private static boolean isActivated() {
|
||||
return activated != null;
|
||||
}
|
||||
|
||||
private static void activate(ShutdownHook hook) {
|
||||
activated = hook;
|
||||
Runtime.getRuntime().addShutdownHook(hook);
|
||||
}
|
||||
|
||||
private static void deactivate() {
|
||||
Runtime.getRuntime().removeShutdownHook(activated);
|
||||
activated = null;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
if (isActivated()) {
|
||||
deactivate();
|
||||
}
|
||||
activate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
serverShutdownSave.serverIsKnownToBeShuttingDown();
|
||||
serverShutdownSave.performSave();
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.api;
|
||||
|
||||
import com.djrapitops.plan.api.data.PlayerContainer;
|
||||
import com.djrapitops.plan.api.data.ServerContainer;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.plugin.HookHandler;
|
||||
import com.djrapitops.plan.data.plugin.PluginData;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.system.database.databases.sql.operation.SQLFetchOps;
|
||||
import com.djrapitops.plan.utilities.uuid.UUIDUtility;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* PlanAPI extension for all implementations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class CommonAPI implements PlanAPI {
|
||||
|
||||
private final DBSystem dbSystem;
|
||||
private final UUIDUtility uuidUtility;
|
||||
private final HookHandler hookHandler;
|
||||
private final PluginLogger logger;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public CommonAPI(
|
||||
DBSystem dbSystem,
|
||||
UUIDUtility uuidUtility,
|
||||
HookHandler hookHandler,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.dbSystem = dbSystem;
|
||||
this.uuidUtility = uuidUtility;
|
||||
this.hookHandler = hookHandler;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
PlanAPIHolder.set(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPluginDataSource(PluginData pluginData) {
|
||||
hookHandler.addPluginDataSource(pluginData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerInspectPageLink(UUID uuid) {
|
||||
return getPlayerInspectPageLink(getPlayerName(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerInspectPageLink(String playerName) {
|
||||
return "../player/" + playerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID playerNameToUUID(String playerName) {
|
||||
return uuidUtility.getUUIDOf(playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, String> getKnownPlayerNames() {
|
||||
try {
|
||||
return queryDB(UserIdentifierQueries.fetchAllPlayerNames());
|
||||
} catch (DBOpException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerContainer fetchPlayerContainer(UUID uuid) {
|
||||
return new PlayerContainer(queryDB(ContainerFetchQueries.fetchPlayerContainer(uuid)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerContainer fetchServerContainer(UUID serverUUID) {
|
||||
return new ServerContainer(queryDB(ContainerFetchQueries.fetchServerContainer(serverUUID)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UUID> fetchServerUUIDs() {
|
||||
return queryDB(ServerQueries.fetchPlanServerInformation()).keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerName(UUID playerUUID) {
|
||||
return queryDB(UserIdentifierQueries.fetchPlayerNameOf(playerUUID)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOperations fetchFromPlanDB() {
|
||||
logger.warn("PlanAPI#fetchFromPlanDB has been deprecated and will be removed in the future. Stack trace to follow");
|
||||
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
|
||||
logger.warn(element.toString());
|
||||
}
|
||||
return new SQLFetchOps(dbSystem.getDatabase());
|
||||
}
|
||||
|
||||
private <T> T queryDB(Query<T> query) {
|
||||
return dbSystem.getDatabase().query(query);
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.api;
|
||||
|
||||
import com.djrapitops.plan.api.data.PlayerContainer;
|
||||
import com.djrapitops.plan.api.data.ServerContainer;
|
||||
import com.djrapitops.plan.data.plugin.PluginData;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Interface for PlanAPI methods.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface PlanAPI {
|
||||
|
||||
static PlanAPI getInstance() {
|
||||
return Optional.ofNullable(PlanAPIHolder.API)
|
||||
.orElseThrow(() -> new IllegalStateException("PlanAPI has not been initialised yet."));
|
||||
}
|
||||
|
||||
class PlanAPIHolder {
|
||||
static PlanAPI API;
|
||||
|
||||
static void set(PlanAPI api) {
|
||||
PlanAPIHolder.API = api;
|
||||
}
|
||||
|
||||
private PlanAPIHolder() {
|
||||
/* Static variable holder */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated PluginData API has been deprecated - see https://github.com/plan-player-analytics/Plan/wiki/APIv5---DataExtension-API for new API.
|
||||
*/
|
||||
@Deprecated
|
||||
void addPluginDataSource(PluginData pluginData);
|
||||
|
||||
String getPlayerInspectPageLink(UUID uuid);
|
||||
|
||||
String getPlayerInspectPageLink(String playerName);
|
||||
|
||||
String getPlayerName(UUID uuid);
|
||||
|
||||
UUID playerNameToUUID(String playerName);
|
||||
|
||||
Map<UUID, String> getKnownPlayerNames();
|
||||
|
||||
/**
|
||||
* Fetch things from the database.
|
||||
*
|
||||
* @return FetchOperations object.
|
||||
* @deprecated FetchOperations interface is going to removed since it is too rigid.
|
||||
*/
|
||||
@Deprecated
|
||||
FetchOperations fetchFromPlanDB();
|
||||
|
||||
/**
|
||||
* Fetch PlayerContainer from the database.
|
||||
* <p>
|
||||
* Blocking operation.
|
||||
*
|
||||
* @param uuid UUID of the player.
|
||||
* @return a {@link PlayerContainer}.
|
||||
*/
|
||||
PlayerContainer fetchPlayerContainer(UUID uuid);
|
||||
|
||||
/**
|
||||
* Fetch a ServerContainer from the database.
|
||||
* <p>
|
||||
* Blocking operation.
|
||||
*
|
||||
* @param serverUUID UUID of the server.
|
||||
* @return a {@link ServerContainer}.
|
||||
*/
|
||||
ServerContainer fetchServerContainer(UUID serverUUID);
|
||||
|
||||
/**
|
||||
* Fetch server UUIDs.
|
||||
*
|
||||
* @return All Plan server UUIDs.
|
||||
*/
|
||||
Collection<UUID> fetchServerUUIDs();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user