[Merge] Version 4.9.0 (#1120)

This commit is contained in:
Risto Lahtela 2019-08-02 10:38:04 +03:00 committed by GitHub
commit 152fe9a803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 704 additions and 1369 deletions

View File

@ -2,7 +2,7 @@ plugins {
id "com.jfrog.bintray" version "1.8.4"
}
ext.apiVersion = '0.0.5'
ext.apiVersion = '0.0.6'
bintray {
user = System.getenv('BINTRAY_USER')

View File

@ -50,7 +50,11 @@ enum Capability {
* <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;
DATA_EXTENSION_SHOW_IN_PLAYER_TABLE,
/**
*
*/
QUERY_API;
static Optional<Capability> getByName(String name) {
if (name == null) {

View File

@ -0,0 +1,64 @@
/*
* 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);
}

View File

@ -0,0 +1,163 @@
/*
* 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:
* 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:
* 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;
}
}
}

View File

@ -12,7 +12,7 @@ allprojects {
wrapper.gradleVersion = "5.0"
group "com.djrapitops"
version "4.8.8"
version "4.9.0"
test {
useJUnitPlatform()
@ -43,11 +43,11 @@ subprojects {
sourceCompatibility = 1.8
targetCompatibility = 1.8
ext.daggerVersion = "2.23.2"
ext.daggerCompilerVersion = "2.23.2"
ext.daggerVersion = "2.24"
ext.daggerCompilerVersion = "2.24"
ext.abstractPluginFrameworkVersion = "3.4.1"
ext.planPluginBridgeVersion = "4.8.8-R0.2"
ext.planPluginBridgeVersion = "4.9.0-R0.3"
ext.bukkitVersion = "1.12.2-R0.1-SNAPSHOT"
ext.spigotVersion = "1.12.2-R0.1-SNAPSHOT"

View File

@ -30,6 +30,7 @@ shadowJar {
exclude "**/*.woff2"
exclude "**/*.psd"
exclude "**/module-info.class"
exclude 'META-INF/versions/' // Causes Sponge to crash
relocate('org.apache', 'plan.org.apache') {

View File

@ -16,11 +16,13 @@
*/
package com.djrapitops.plan.command.commands.manage;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.api.exceptions.database.DBInitException;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.db.DBType;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.commands.RemoveEverythingTransaction;
import com.djrapitops.plan.query.QueryServiceImplementation;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
@ -49,23 +51,29 @@ import java.util.concurrent.ExecutionException;
@Singleton
public class ManageClearCommand extends CommandNode {
private final PlanPlugin plugin;
private final Locale locale;
private final Processing processing;
private final DBSystem dbSystem;
private final QueryServiceImplementation queryService;
private final ErrorHandler errorHandler;
@Inject
public ManageClearCommand(
PlanPlugin plugin,
Locale locale,
Processing processing,
DBSystem dbSystem,
QueryServiceImplementation queryService,
ErrorHandler errorHandler
) {
super("clear", Permissions.MANAGE.getPermission(), CommandType.PLAYER_OR_ARGS);
this.plugin = plugin;
this.locale = locale;
this.processing = processing;
this.dbSystem = dbSystem;
this.queryService = queryService;
this.errorHandler = errorHandler;
setArguments("<DB>", "[-a]");
@ -104,7 +112,9 @@ public class ManageClearCommand extends CommandNode {
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
database.executeTransaction(new RemoveEverythingTransaction())
.get(); // Wait for completion
queryService.dataCleared();
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
reloadPlugin(sender);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (DBOpException | ExecutionException e) {
@ -113,4 +123,14 @@ public class ManageClearCommand extends CommandNode {
}
});
}
private void reloadPlugin(Sender sender) {
try {
plugin.reloadPlugin(true);
} catch (Exception e) {
errorHandler.log(L.CRITICAL, this.getClass(), e);
sender.sendMessage(locale.getString(CommandLang.RELOAD_FAILED));
}
sender.sendMessage(locale.getString(CommandLang.RELOAD_COMPLETE));
}
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
import com.djrapitops.plan.db.access.transactions.commands.RemovePlayerTransaction;
import com.djrapitops.plan.query.QueryServiceImplementation;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
@ -55,6 +56,7 @@ public class ManageRemoveCommand extends CommandNode {
private final Locale locale;
private final Processing processing;
private final DBSystem dbSystem;
private final QueryServiceImplementation queryService;
private final UUIDUtility uuidUtility;
private final ErrorHandler errorHandler;
@ -63,6 +65,7 @@ public class ManageRemoveCommand extends CommandNode {
Locale locale,
Processing processing,
DBSystem dbSystem,
QueryServiceImplementation queryService,
UUIDUtility uuidUtility,
ErrorHandler errorHandler
) {
@ -71,6 +74,7 @@ public class ManageRemoveCommand extends CommandNode {
this.locale = locale;
this.processing = processing;
this.dbSystem = dbSystem;
this.queryService = queryService;
this.uuidUtility = uuidUtility;
this.errorHandler = errorHandler;
@ -120,6 +124,7 @@ public class ManageRemoveCommand extends CommandNode {
}
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
queryService.playerRemoved(playerUUID);
db.executeTransaction(new RemovePlayerTransaction(playerUUID))
.get(); // Wait for completion
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.data.time;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* Class that tracks the time spent in each World based on GMTimes.
@ -171,8 +172,8 @@ public class WorldTimes {
return b.toString();
}
public String getCurrentWorld() {
return currentWorld;
public Optional<String> getCurrentWorld() {
return Optional.ofNullable(currentWorld);
}
public void add(WorldTimes toAdd) {

View File

@ -0,0 +1,50 @@
/*
* 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.db.access;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.query.QueryService;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class QueryAPIExecutable implements Executable {
private final String sql;
private final QueryService.ThrowingConsumer<PreparedStatement> statement;
public QueryAPIExecutable(
String sql,
QueryService.ThrowingConsumer<PreparedStatement> statement
) {
this.sql = sql;
this.statement = statement;
}
@Override
public boolean execute(Connection connection) {
try {
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
statement.accept(preparedStatement);
return true;
}
} catch (SQLException e) {
throw DBOpException.forCause(sql, e);
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.db.access;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.db.SQLDB;
import com.djrapitops.plan.query.QueryService;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class QueryAPIQuery<T> implements Query<T> {
private final QueryService.ThrowingFunction<PreparedStatement, T> performQuery;
private String sql;
public QueryAPIQuery(
String sql,
QueryService.ThrowingFunction<PreparedStatement, T> performQuery
) {
this.sql = sql;
this.performQuery = performQuery;
}
@Override
public T executeQuery(SQLDB db) {
Connection connection = null;
try {
connection = db.getConnection();
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
return performQuery.apply(preparedStatement);
}
} catch (SQLException e) {
throw DBOpException.forCause(sql, e);
} finally {
db.returnToPool(connection);
}
}
}

View File

@ -26,6 +26,7 @@ import com.djrapitops.plan.db.access.transactions.init.RemoveOldSampledDataTrans
import com.djrapitops.plan.db.sql.tables.SessionsTable;
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalPlayerResultsTransaction;
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalServerResultsTransaction;
import com.djrapitops.plan.query.QueryServiceImplementation;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.locale.Locale;
@ -58,6 +59,7 @@ public class DBCleanTask extends AbsRunnable {
private final Locale locale;
private final DBSystem dbSystem;
private final PlanConfig config;
private final QueryServiceImplementation queryService;
private final ServerInfo serverInfo;
private final PluginLogger logger;
private final ErrorHandler errorHandler;
@ -67,6 +69,7 @@ public class DBCleanTask extends AbsRunnable {
PlanConfig config,
Locale locale,
DBSystem dbSystem,
QueryServiceImplementation queryService,
ServerInfo serverInfo,
PluginLogger logger,
ErrorHandler errorHandler
@ -75,6 +78,7 @@ public class DBCleanTask extends AbsRunnable {
this.dbSystem = dbSystem;
this.config = config;
this.queryService = queryService;
this.serverInfo = serverInfo;
this.logger = logger;
this.errorHandler = errorHandler;
@ -110,8 +114,9 @@ public class DBCleanTask extends AbsRunnable {
long keepActiveAfter = now - config.get(TimeSettings.DELETE_INACTIVE_PLAYERS_AFTER);
List<UUID> inactivePlayers = database.query(fetchInactivePlayerUUIDs(keepActiveAfter));
for (UUID uuid : inactivePlayers) {
database.executeTransaction(new RemovePlayerTransaction(uuid));
for (UUID playerUUID : inactivePlayers) {
queryService.playerRemoved(playerUUID);
database.executeTransaction(new RemovePlayerTransaction(playerUUID));
}
return inactivePlayers.size();
}

View File

@ -27,6 +27,7 @@ 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.settings.config.PlanConfig;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.logging.L;
import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.logging.error.ErrorHandler;
@ -80,8 +81,10 @@ public class ExtensionServiceImplementation implements ExtensionService {
ExtensionService.ExtensionServiceHolder.set(this);
}
public void enable() {
public void register() {
extensionRegister.registerBuiltInExtensions();
if (Check.isBukkitAvailable()) extensionRegister.registerBukkitExtensions();
if (Check.isBungeeAvailable()) extensionRegister.registerBungeeExtensions();
}
@Override
@ -156,7 +159,7 @@ public class ExtensionServiceImplementation implements ExtensionService {
// Try again
updatePlayerValues(gatherer, playerUUID, playerName, event);
} catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError unexpectedError) {
logger.warn(gatherer.getPluginName() + " ran into unexpected error (please report this)" + unexpectedError +
logger.warn("Encountered unexpected error with " + gatherer.getPluginName() + " Extension (please report this): " + unexpectedError +
" (but failed safely) when updating value for '" + playerName +
"', stack trace to follow:");
errorHandler.log(L.WARN, gatherer.getClass(), unexpectedError);
@ -166,8 +169,8 @@ public class ExtensionServiceImplementation implements ExtensionService {
private void logFailure(String playerName, DataExtensionMethodCallException methodCallFailed) {
Throwable cause = methodCallFailed.getCause();
String causeName = cause.getClass().getSimpleName();
logger.warn(methodCallFailed.getPluginName() + " ran into " + causeName +
" (but failed safely) when updating value for '" + playerName +
logger.warn("Encountered " + causeName + " with " + methodCallFailed.getPluginName() + " Extension (please report this)" +
" (failed safely) when updating value for '" + playerName +
"', the method was disabled temporarily (won't be called until next Plan reload)" +
", stack trace to follow:");
errorHandler.log(L.WARN, getClass(), cause);
@ -195,8 +198,8 @@ public class ExtensionServiceImplementation implements ExtensionService {
// Try again
updateServerValues(gatherer, event);
} catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError unexpectedError) {
logger.warn(gatherer.getPluginName() + " ran into unexpected error (please report this)" + unexpectedError +
" (but failed safely) when updating value for server, stack trace to follow:");
logger.warn("Encountered unexpected error with " + gatherer.getPluginName() + " Extension (please report this): " + unexpectedError +
" (failed safely) when updating value for server, stack trace to follow:");
errorHandler.log(L.WARN, gatherer.getClass(), unexpectedError);
}
}

View File

@ -79,21 +79,21 @@ public class DataProviders {
return byReturnType;
}
public void removeProviderWithMethod(MethodWrapper method) {
MethodType methodType = method.getMethodType();
public void removeProviderWithMethod(MethodWrapper toRemove) {
MethodType methodType = toRemove.getMethodType();
Map<Class, List<DataProvider>> byResultType = byMethodType.getOrDefault(methodType, Collections.emptyMap());
if (byResultType.isEmpty()) {
return;
}
Class resultType = method.getResultType();
Class resultType = toRemove.getResultType();
List<DataProvider> providers = byResultType.getOrDefault(resultType, Collections.emptyList());
if (providers.isEmpty()) {
return;
}
byResultType.put(resultType, providers.stream()
.filter(provider -> provider.getMethod().equals(method))
.filter(provider -> !provider.getMethod().equals(toRemove))
.collect(Collectors.toList())
);
byMethodType.put(methodType, byResultType);

View File

@ -0,0 +1,105 @@
/*
* 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 com.djrapitops.plan.data.store.containers.PlayerContainer;
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
import com.djrapitops.plan.db.DBType;
import com.djrapitops.plan.db.Database;
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.db.access.queries.schema.H2SchemaQueries;
import com.djrapitops.plan.db.access.queries.schema.MySQLSchemaQueries;
import com.djrapitops.plan.db.access.queries.schema.SQLiteSchemaQueries;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
public class CommonQueriesImplementation implements CommonQueries {
private final Database db;
CommonQueriesImplementation(Database db) {
this.db = db;
}
@Override
public long fetchPlaytime(UUID playerUUID, UUID serverUUID, long after, long before) {
// TODO Replace with single query later
PlayerContainer player = db.query(ContainerFetchQueries.fetchPlayerContainer(playerUUID));
return SessionsMutator.forContainer(player)
.filterSessionsBetween(after, before)
.filterPlayedOnServer(serverUUID)
.toPlaytime();
}
@Override
public long fetchLastSeen(UUID playerUUID, UUID serverUUID) {
// TODO Replace with single query later
PlayerContainer player = db.query(ContainerFetchQueries.fetchPlayerContainer(playerUUID));
return SessionsMutator.forContainer(player)
.filterPlayedOnServer(serverUUID)
.toLastSeen();
}
@Override
public Set<UUID> fetchServerUUIDs() {
return db.query(ServerQueries.fetchServerNames()).keySet();
}
@Override
public Optional<UUID> fetchUUIDOf(String playerName) {
return db.query(UserIdentifierQueries.fetchPlayerUUIDOf(playerName));
}
@Override
public Optional<String> fetchNameOf(UUID playerUUID) {
return db.query(UserIdentifierQueries.fetchPlayerNameOf(playerUUID));
}
@Override
public boolean doesDBHaveTable(String table) {
DBType dbType = db.getType();
switch (dbType) {
case H2:
return db.query(H2SchemaQueries.doesTableExist(table));
case SQLITE:
return db.query(SQLiteSchemaQueries.doesTableExist(table));
case MYSQL:
return db.query(MySQLSchemaQueries.doesTableExist(table));
default:
throw new IllegalStateException("Unsupported Database Type: " + dbType.getName());
}
}
@Override
public boolean doesDBHaveTableColumn(String table, String column) {
DBType dbType = db.getType();
switch (dbType) {
case H2:
return db.query(H2SchemaQueries.doesColumnExist(table, column));
case MYSQL:
return db.query(MySQLSchemaQueries.doesColumnExist(table, column));
case SQLITE:
return db.query(SQLiteSchemaQueries.doesColumnExist(table, column));
default:
throw new IllegalStateException("Unsupported Database Type: " + dbType.getName());
}
}
}

View File

@ -0,0 +1,115 @@
/*
* 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 com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.QueryAPIExecutable;
import com.djrapitops.plan.db.access.QueryAPIQuery;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.info.server.ServerInfo;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.sql.PreparedStatement;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.function.Consumer;
@Singleton
public class QueryServiceImplementation implements QueryService {
private DBSystem dbSystem;
private ServerInfo serverInfo;
private Set<Consumer<UUID>> playerRemoveSubscribers;
private Set<VoidFunction> clearSubscribers;
@Inject
public QueryServiceImplementation(
DBSystem dbSystem,
ServerInfo serverInfo
) {
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
playerRemoveSubscribers = new HashSet<>();
clearSubscribers = new HashSet<>();
}
public void register() {
QueryService.QueryServiceHolder.set(this);
}
@Override
public String getDBType() {
Database database = dbSystem.getDatabase();
if (database == null) throw new IllegalStateException("Database has not been initialized.");
return database.getType().name();
}
@Override
public <T> T query(String sql, ThrowingFunction<PreparedStatement, T> performQuery) {
return dbSystem.getDatabase().query(new QueryAPIQuery<>(sql, performQuery));
}
@Override
public Future<?> execute(String sql, ThrowingConsumer<PreparedStatement> performStatement) {
return dbSystem.getDatabase().executeTransaction(
new Transaction() {
@Override
protected void performOperations() {
execute(new QueryAPIExecutable(sql, performStatement));
}
}
);
}
@Override
public void subscribeToPlayerRemoveEvent(Consumer<UUID> eventListener) {
playerRemoveSubscribers.add(eventListener);
}
@Override
public void subscribeDataClearEvent(VoidFunction eventListener) {
clearSubscribers.add(eventListener);
}
public void playerRemoved(UUID playerUUID) {
playerRemoveSubscribers.forEach(subscriber -> subscriber.accept(playerUUID));
}
public void dataCleared() {
clearSubscribers.forEach(VoidFunction::apply);
}
@Override
public Optional<UUID> getServerUUID() {
return Optional.ofNullable(serverInfo.getServer()).map(Server::getUuid);
}
@Override
public CommonQueries getCommonQueries() {
Database database = dbSystem.getDatabase();
if (database == null) throw new IllegalStateException("Database has not been initialized.");
return new CommonQueriesImplementation(database);
}
}

View File

@ -22,6 +22,7 @@ import com.djrapitops.plan.capability.CapabilityServiceImplementation;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.plan.extension.ExtensionService;
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
import com.djrapitops.plan.query.QueryServiceImplementation;
import com.djrapitops.plan.system.cache.CacheSystem;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.export.ExportSystem;
@ -73,6 +74,7 @@ public class PlanSystem implements SubSystem {
private final HtmlUtilities htmlUtilities;
private final HookHandler hookHandler;
private final ExtensionServiceImplementation extensionService;
private final QueryServiceImplementation queryService;
private final PlanAPI planAPI;
private final ErrorHandler errorHandler;
@ -95,6 +97,7 @@ public class PlanSystem implements SubSystem {
HtmlUtilities htmlUtilities,
HookHandler hookHandler,
ExtensionServiceImplementation extensionService,
QueryServiceImplementation queryService,
PlanAPI planAPI,
ErrorHandler errorHandler
) {
@ -115,6 +118,7 @@ public class PlanSystem implements SubSystem {
this.htmlUtilities = htmlUtilities;
this.hookHandler = hookHandler;
this.extensionService = extensionService;
this.queryService = queryService;
this.planAPI = planAPI;
this.errorHandler = errorHandler;
}
@ -140,7 +144,8 @@ public class PlanSystem implements SubSystem {
taskSystem,
hookHandler
);
extensionService.enable();
queryService.register();
extensionService.register();
enabled = true;
}

View File

@ -63,6 +63,9 @@ public class ConfigNode {
}
public Optional<ConfigNode> getNode(String path) {
if (path == null) {
return Optional.empty();
}
String[] parts = splitPathInTwo(path);
String key = parts[0];
String leftover = parts[1];
@ -88,7 +91,7 @@ public class ConfigNode {
public ConfigNode addNode(String path) {
ConfigNode newParent = this;
if (!path.isEmpty()) {
if (path != null && !path.isEmpty()) {
String[] parts = splitPathInTwo(path);
String key = parts[0];
String leftover = parts[1];
@ -105,7 +108,7 @@ public class ConfigNode {
// Otherwise continue recursively.
return leftover.isEmpty() ? child : child.addNode(leftover);
}
throw new IllegalArgumentException("Can not add a node with empty path");
throw new IllegalArgumentException("Can not add a node with path '" + path + "'");
}
/**

View File

@ -157,8 +157,9 @@ public class WorldAliasSettings {
}
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes());
if (!session.supports(SessionKeys.END)) {
String currentWorld = worldTimes.getCurrentWorld();
return "Current: " + (aliases.contains(currentWorld) ? aliases.getString(currentWorld) : currentWorld);
return worldTimes.getCurrentWorld()
.map(currentWorld -> "Current: " + (aliases.contains(currentWorld) ? aliases.getString(currentWorld) : currentWorld))
.orElse("Current: Unavailable");
}
Map<String, Long> playtimePerAlias = getPlaytimePerAlias(worldTimes);

View File

@ -135,12 +135,19 @@ public enum Html {
StringBuilder result = new StringBuilder(string.length());
String[] split = string.split("§");
// Skip first part if it does not start with §
boolean skipFirst = !string.startsWith("§");
int placedSpans = 0;
for (String part : split) {
if (part.isEmpty()) {
continue;
}
if (skipFirst) {
result.append(part);
skipFirst = false;
continue;
}
char colorChar = part.charAt(0);
if (colorChar == 'r') {

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: com.djrapitops.plan.PlanBungee
version: 4.8.8
version: 4.9.0
softdepend:
- AdvancedBan
- LiteBans

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: com.djrapitops.plan.Plan
version: 4.8.8
version: 4.9.0
softdepend:
- ASkyBlock
- AdvancedAchievements

View File

@ -67,6 +67,7 @@ import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionSer
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalPlayerResultsTransaction;
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalServerResultsTransaction;
import com.djrapitops.plan.extension.table.Table;
import com.djrapitops.plan.query.QueryServiceImplementation;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.Server;
@ -629,6 +630,7 @@ public abstract class CommonDBTest {
system.getConfigSystem().getConfig(),
new Locale(),
system.getDatabaseSystem(),
new QueryServiceImplementation(system.getDatabaseSystem(), system.getServerInfo()),
system.getServerInfo(),
new TestPluginLogger(),
new ConsoleErrorLogger(new TestPluginLogger())

View File

@ -53,4 +53,12 @@ class HtmlTest {
String result = Html.swapColorCodesToSpan(testString);
assertEquals(expected, result);
}
@Test
void swapColorCodesDoesNotReplaceNonColors() {
String testString = "1test§2yes";
String expected = "1test" + Html.COLOR_2.parse() + "yes</span>";
String result = Html.swapColorCodesToSpan(testString);
assertEquals(expected, result);
}
}

View File

@ -1,22 +1,26 @@
dependencies {
compile project(path: ":api")
compile "com.djrapitops:Extension-AdvancedAchievements:1.1-R0.3"
compile "com.djrapitops:Extension-AdvancedBan:2.1.5-R0.6"
compile "com.djrapitops:Extension-ASkyBlock:3.0.9.4-R0.4"
compile "com.djrapitops:Extension-BanManager:5.15.0-R0.5"
compile "com.djrapitops:Extension-CoreProtect:2.16.0-R0.3"
compile "com.djrapitops:Extension-DiscordSRV:1.16.6-R0.4"
compile "com.djrapitops:Extension-EssentialsX:2.15.0-R0.3"
compile "com.djrapitops:Extension-GriefPrevention:16.11.6-R0.2"
compile "com.djrapitops:Extension-GriefPrevention-Sponge:4.0.1-R0.2"
compile "com.djrapitops:Extension-GriefPreventionPlus:13.3-R0.2"
compile "com.djrapitops:Extension-McMMO:2.1.44-R0.2"
compile 'com.djrapitops:Extension-AAC:4.0.5-R0.3'
compile 'com.djrapitops:Extension-AdvancedAchievements:1.1-R0.3'
compile 'com.djrapitops:Extension-AdvancedBan:2.1.5-R0.6'
compile 'com.djrapitops:Extension-ASkyBlock:3.0.9.4-R0.4'
compile 'com.djrapitops:Extension-BanManager:5.15.0-R0.5'
compile 'com.djrapitops:Extension-CoreProtect:2.16.0-R0.3'
compile 'com.djrapitops:Extension-DiscordSRV:1.16.6-R0.4'
compile 'com.djrapitops:Extension-EssentialsX:2.15.0-R0.3'
compile 'com.djrapitops:Extension-GriefPrevention:16.11.6-R0.2'
compile 'com.djrapitops:Extension-GriefPrevention-Sponge:4.0.1-R0.2'
compile 'com.djrapitops:Extension-GriefPreventionPlus:13.3-R0.2'
compile 'com.djrapitops:Extension-McMMO:2.1.44-R0.2'
compile 'com.djrapitops:Extension-MinigamesLib:1.14.17-R0.2'
compile 'com.djrapitops:Extension-Nucleus:1.9.2-R0.2'
compile "com.djrapitops:Extension-RedProtect:7.5.6-R0.2"
compile "com.djrapitops:Extension-Sponge-Economy:7.1.0-R0.3"
compile "com.djrapitops:Extension-SuperbVote:0.5.4-R0.1"
compile "com.djrapitops:Extension-Vault:1.7-R0.2"
compile 'com.djrapitops:Extension-nuVotifier:2.3.4-R0.1'
compile 'com.djrapitops:Extension-ProtocolSupport:4.29-R0.1'
compile 'com.djrapitops:Extension-RedProtect:7.5.6-R0.2'
compile 'com.djrapitops:Extension-Sponge-Economy:7.1.0-R0.3'
compile 'com.djrapitops:Extension-SuperbVote:0.5.4-R0.1'
compile 'com.djrapitops:Extension-Vault:1.7-R0.2'
compile 'com.djrapitops:Extension-ViaVersion:2.1.3-R0.3'
}
shadowJar {

View File

@ -22,6 +22,7 @@ import com.djrapitops.plan.extension.ExtensionService;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.function.Consumer;
/**
* In charge of registering built in {@link com.djrapitops.plan.extension.DataExtension} implementations.
@ -41,23 +42,43 @@ public class ExtensionRegister {
// registerBuiltInExtensions method will not be called unless Plan has enabled properly
ExtensionService extensionService = ExtensionService.getInstance();
new AdvancedAchievementsExtensionFactory().createExtension().ifPresent(extensionService::register);
new AdvancedBanExtensionFactory().createExtension().ifPresent(extensionService::register);
new ASkyBlockExtensionFactory().createExtension().ifPresent(extensionService::register);
new BanManagerExtensionFactory().createExtension().ifPresent(extensionService::register);
new CoreProtectExtensionFactory().createExtension().ifPresent(extensionService::register);
new DiscordSRVExtensionFactory().createExtension().ifPresent(extensionService::register);
Consumer<DataExtension> register = extensionService::register;
new AACExtensionFactory().createExtension().ifPresent(register);
new AdvancedAchievementsExtensionFactory().createExtension().ifPresent(register);
new AdvancedBanExtensionFactory().createExtension().ifPresent(register);
new ASkyBlockExtensionFactory().createExtension().ifPresent(register);
new BanManagerExtensionFactory().createExtension().ifPresent(register);
new CoreProtectExtensionFactory().createExtension().ifPresent(register);
new DiscordSRVExtensionFactory().createExtension().ifPresent(register);
registerEssentialsExtension(extensionService);
new GriefPreventionExtensionFactory().createExtension().ifPresent(extensionService::register);
new GriefPreventionSpongeExtensionFactory().createExtension().ifPresent(extensionService::register);
new GriefPreventionPlusExtensionFactory().createExtension().ifPresent(extensionService::register);
new McMMOExtensionFactory().createExtension().ifPresent(extensionService::register);
new GriefPreventionExtensionFactory().createExtension().ifPresent(register);
new GriefPreventionSpongeExtensionFactory().createExtension().ifPresent(register);
new GriefPreventionPlusExtensionFactory().createExtension().ifPresent(register);
new McMMOExtensionFactory().createExtension().ifPresent(register);
registerMinigameLibExtensions(extensionService);
new NucleusExtensionFactory().createExtension().ifPresent(extensionService::register);
new RedProtectExtensionFactory().createExtension().ifPresent(extensionService::register);
new SpongeEconomyExtensionFactory().createExtension().ifPresent(extensionService::register);
new SuperbVoteExtensionFactory().createExtension().ifPresent(extensionService::register);
new VaultExtensionFactory().createExtension().ifPresent(extensionService::register);
new NucleusExtensionFactory().createExtension().ifPresent(register);
new NuVotifierExtensionFactory().createExtension().ifPresent(register);
new ProtocolSupportExtensionFactory().createExtension().ifPresent(register);
new RedProtectExtensionFactory().createExtension().ifPresent(register);
new SpongeEconomyExtensionFactory().createExtension().ifPresent(register);
new SuperbVoteExtensionFactory().createExtension().ifPresent(register);
new VaultExtensionFactory().createExtension().ifPresent(register);
}
public void registerBukkitExtensions() {
// No need to catch exceptions here,
// registerBuiltInExtensions method will not be called unless Plan has enabled properly
ExtensionService extensionService = ExtensionService.getInstance();
new ViaVersionBukkitExtensionFactory().createExtension().ifPresent(extensionService::register);
}
public void registerBungeeExtensions() {
// No need to catch exceptions here,
// registerBuiltInExtensions method will not be called unless Plan has enabled properly
ExtensionService extensionService = ExtensionService.getInstance();
new ViaVersionBungeeExtensionFactory().createExtension().ifPresent(extensionService::register);
}
private void registerEssentialsExtension(ExtensionService extensionService) {

View File

@ -42,7 +42,7 @@ import java.io.InputStream;
@Plugin(
id = "plan",
name = "Plan",
version = "4.8.8",
version = "4.9.0",
description = "Player Analytics Plugin by Rsl1122",
authors = {"Rsl1122"},
dependencies = {

View File

@ -46,7 +46,7 @@ import java.nio.file.Path;
@Plugin(
id = "plan",
name = "Plan",
version = "4.8.8",
version = "4.9.0",
description = "Player Analytics Plugin by Rsl1122",
authors = {"Rsl1122"}
)

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>PlanPluginBridge</artifactId>
<version>4.8.8-R0.2</version>
<version>4.9.0-R0.3</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>
@ -61,10 +61,6 @@
<id>jitpack.io (GriefPrevention)</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>viaversion-repo</id>
<url>https://repo.viaversion.com</url>
</repository>
<repository>
<id>placeholderapi</id>
<url>http://repo.extendedclip.com/content/repositories/placeholderapi/</url>
@ -116,7 +112,7 @@
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>2.23.2</version>
<version>2.24</version>
</dependency>
<!-- Plugins from repositories -->
@ -127,12 +123,6 @@
<version>2.10.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
<dependency> <!-- Maven Central -->
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
@ -141,13 +131,6 @@
</dependency>
<!-- Plugins requiring local install -->
<dependency>
<groupId>me.konsolas</groupId>
<artifactId>AAC</artifactId>
<version>4.0.0-b1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>factions</artifactId>
@ -172,12 +155,6 @@
<version>0.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.ProtocolSupport</groupId>
<artifactId>ProtocolSupport</artifactId>
<version>4.28</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.volmit</groupId>
<artifactId>react</artifactId>

View File

@ -18,15 +18,12 @@ package com.djrapitops.pluginbridge.plan;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plugin.logging.error.ErrorHandler;
import com.djrapitops.pluginbridge.plan.aac.AdvancedAntiCheatHook;
import com.djrapitops.pluginbridge.plan.buycraft.BuyCraftHook;
import com.djrapitops.pluginbridge.plan.factions.FactionsHook;
import com.djrapitops.pluginbridge.plan.jobs.JobsHook;
import com.djrapitops.pluginbridge.plan.litebans.LiteBansBukkitHook;
import com.djrapitops.pluginbridge.plan.luckperms.LuckPermsHook;
import com.djrapitops.pluginbridge.plan.protocolsupport.ProtocolSupportHook;
import com.djrapitops.pluginbridge.plan.towny.TownyHook;
import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionBukkitHook;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -39,55 +36,42 @@ import javax.inject.Singleton;
@Singleton
public class BukkitBridge extends AbstractBridge {
private final AdvancedAntiCheatHook advancedAntiCheatHook;
private final BuyCraftHook buyCraftHook;
private final FactionsHook factionsHook;
private final JobsHook jobsHook;
private final LiteBansBukkitHook liteBansHook;
private final LuckPermsHook luckPermsHook;
private final ProtocolSupportHook protocolSupportHook;
private final TownyHook townyHook;
private final ViaVersionBukkitHook viaVersionHook;
@Inject
public BukkitBridge(
PlanConfig config,
ErrorHandler errorHandler,
AdvancedAntiCheatHook advancedAntiCheatHook,
BuyCraftHook buyCraftHook,
FactionsHook factionsHook,
JobsHook jobsHook,
LiteBansBukkitHook liteBansHook,
LuckPermsHook luckPermsHook,
ProtocolSupportHook protocolSupportHook,
TownyHook townyHook,
ViaVersionBukkitHook viaVersionHook
TownyHook townyHook
) {
super(config, errorHandler);
this.advancedAntiCheatHook = advancedAntiCheatHook;
this.buyCraftHook = buyCraftHook;
this.factionsHook = factionsHook;
this.jobsHook = jobsHook;
this.liteBansHook = liteBansHook;
this.luckPermsHook = luckPermsHook;
this.protocolSupportHook = protocolSupportHook;
this.townyHook = townyHook;
this.viaVersionHook = viaVersionHook;
}
@Override
Hook[] getHooks() {
return new Hook[]{
advancedAntiCheatHook,
buyCraftHook,
factionsHook,
jobsHook,
liteBansHook,
luckPermsHook,
protocolSupportHook,
townyHook,
viaVersionHook
};
}
}

View File

@ -21,7 +21,6 @@ import com.djrapitops.plugin.logging.error.ErrorHandler;
import com.djrapitops.pluginbridge.plan.buycraft.BuyCraftHook;
import com.djrapitops.pluginbridge.plan.litebans.LiteBansBungeeHook;
import com.djrapitops.pluginbridge.plan.luckperms.LuckPermsHook;
import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionBungeeHook;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -37,23 +36,19 @@ public class BungeeBridge extends AbstractBridge {
private final BuyCraftHook buyCraftHook;
private final LiteBansBungeeHook liteBansHook;
private final LuckPermsHook luckPermsHook;
private final ViaVersionBungeeHook viaVersionHook;
@Inject
public BungeeBridge(
PlanConfig config,
ErrorHandler errorHandler,
BuyCraftHook buyCraftHook,
LiteBansBungeeHook liteBansHook,
LuckPermsHook luckPermsHook,
ViaVersionBungeeHook viaVersionHook
LuckPermsHook luckPermsHook
) {
super(config, errorHandler);
this.buyCraftHook = buyCraftHook;
this.liteBansHook = liteBansHook;
this.luckPermsHook = luckPermsHook;
this.viaVersionHook = viaVersionHook;
}
@Override
@ -62,7 +57,6 @@ public class BungeeBridge extends AbstractBridge {
buyCraftHook,
liteBansHook,
luckPermsHook,
viaVersionHook
};
}
}

View File

@ -1,91 +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.pluginbridge.plan.aac;
import com.djrapitops.plan.data.element.AnalysisContainer;
import com.djrapitops.plan.data.element.InspectContainer;
import com.djrapitops.plan.data.element.TableContainer;
import com.djrapitops.plan.data.plugin.ContainerSize;
import com.djrapitops.plan.data.plugin.PluginData;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.utilities.formatting.Formatter;
import com.djrapitops.plan.utilities.html.icon.Color;
import com.djrapitops.plan.utilities.html.icon.Family;
import com.djrapitops.plan.utilities.html.icon.Icon;
import com.djrapitops.plugin.utilities.Format;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* PluginData for AAC plugin.
*
* @author Rsl1122
*/
class AdvancedAntiCheatData extends PluginData {
private final Database database;
private final Formatter<Long> timestampFormatter;
AdvancedAntiCheatData(Database database, Formatter<Long> timestampFormatter) {
super(ContainerSize.THIRD, "AdvancedAntiCheat");
this.timestampFormatter = timestampFormatter;
super.setPluginIcon(Icon.called("heart").of(Color.RED).build());
this.database = database;
}
@Override
public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) {
List<HackObject> hackObjects = database.query(HackerTable.getHackObjects(uuid));
inspectContainer.addValue(
getWithIcon("Times Kicked for Possible Hacking", Icon.called("exclamation-triangle").of(Color.RED)),
hackObjects.size()
);
TableContainer hackTable = new TableContainer(
getWithIcon("Kicked", Icon.called("calendar").of(Family.REGULAR)),
getWithIcon("Hack", Icon.called("exclamation-triangle")),
getWithIcon("Violation Level", Icon.called("gavel"))
);
hackTable.setColor("red");
for (HackObject hackObject : hackObjects) {
String date = timestampFormatter.apply(hackObject.getDate());
String hack = new Format(hackObject.getHackType()).capitalize().toString();
hackTable.addRow(date, hack, hackObject.getViolationLevel());
}
inspectContainer.addTable("hackTable", hackTable);
return inspectContainer;
}
@Override
public AnalysisContainer getServerData(Collection<UUID> collection, AnalysisContainer analysisContainer) {
Map<UUID, List<HackObject>> hackObjects = database.query(HackerTable.getHackObjects());
Map<UUID, Integer> violations = hackObjects.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().size()));
analysisContainer.addPlayerTableValues(getWithIcon("Kicked for Hacking", Icon.called("exclamation-triangle")), violations);
return analysisContainer;
}
}

View File

@ -1,72 +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.pluginbridge.plan.aac;
import com.djrapitops.plan.Plan;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.utilities.formatting.Formatters;
import com.djrapitops.pluginbridge.plan.Hook;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Hook for AAC plugin.
*
* @author Rsl1122
*/
@Singleton
public class AdvancedAntiCheatHook extends Hook {
private final Plan plugin;
private final DBSystem dbSystem;
private final Formatters formatters;
@Inject
public AdvancedAntiCheatHook(
Plan plugin,
DBSystem dbSystem,
Formatters formatters
) {
super("me.konsolas.aac.AAC");
this.plugin = plugin;
this.dbSystem = dbSystem;
this.formatters = formatters;
}
@Override
public void hook(HookHandler hookHandler) throws NoClassDefFoundError {
if (!enabled) {
return;
}
Database database = dbSystem.getDatabase();
database.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(HackerTable.createTableSQL(database.getType()));
}
});
database.executeTransaction(new HackerTableMissingDateColumnPatch());
plugin.registerListener(new PlayerHackKickListener(database));
hookHandler.addPluginDataSource(new AdvancedAntiCheatData(database, formatters.yearLong()));
}
}

View File

@ -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.pluginbridge.plan.aac;
import java.util.UUID;
/**
* Data object for AAC data.
*
* @author Rsl1122
*/
public class HackObject {
private final UUID uuid;
private final long date;
private final String hackType;
private final int violationLevel;
public HackObject(UUID uuid, long date, String hackType, int violationLevel) {
this.uuid = uuid;
this.date = date;
this.hackType = hackType;
this.violationLevel = violationLevel;
}
public UUID getUuid() {
return uuid;
}
public long getDate() {
return date;
}
public String getHackType() {
return hackType;
}
public int getViolationLevel() {
return violationLevel;
}
}

View File

@ -1,102 +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.pluginbridge.plan.aac;
import com.djrapitops.plan.db.DBType;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryAllStatement;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
import com.djrapitops.plan.db.sql.parsing.Select;
import com.djrapitops.plan.db.sql.parsing.Sql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
/**
* Table information about 'plan_aac_hack_table'.
*
* @author Rsl1122
*/
public class HackerTable {
public static final String TABLE_NAME = "plan_aac_hack_table";
public static final String COL_ID = "id";
public static final String COL_UUID = "uuid";
public static final String COL_DATE = "date";
public static final String COL_HACK_TYPE = "hack_type";
public static final String COL_VIOLATION_LEVEL = "violation_level";
private HackerTable() {
/* Static information class */
}
public static String createTableSQL(DBType dbType) {
return CreateTableParser.create(TABLE_NAME, dbType)
.column(COL_ID, Sql.INT).primaryKey()
.column(COL_UUID, Sql.varchar(36)).notNull()
.column(COL_DATE, Sql.LONG).notNull()
.column(COL_HACK_TYPE, Sql.varchar(100)).notNull()
.column(COL_VIOLATION_LEVEL, Sql.INT).notNull()
.build();
}
public static Query<List<HackObject>> getHackObjects(UUID uuid) {
String sql = "SELECT * FROM " + TABLE_NAME + " WHERE " + COL_UUID + "=?";
return new QueryStatement<List<HackObject>>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
@Override
public List<HackObject> processResults(ResultSet set) throws SQLException {
List<HackObject> hackObjects = new ArrayList<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString(COL_UUID));
long date = set.getLong(COL_DATE);
String hackType = set.getString(COL_HACK_TYPE);
int violationLevel = set.getInt(COL_VIOLATION_LEVEL);
hackObjects.add(new HackObject(uuid, date, hackType, violationLevel));
}
return hackObjects;
}
};
}
public static Query<Map<UUID, List<HackObject>>> getHackObjects() {
return new QueryAllStatement<Map<UUID, List<HackObject>>>(Select.all(TABLE_NAME).toString(), 5000) {
@Override
public Map<UUID, List<HackObject>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<HackObject>> hackObjects = new HashMap<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString(COL_UUID));
long date = set.getLong(COL_DATE);
String hackType = set.getString(COL_HACK_TYPE);
int violationLevel = set.getInt(COL_VIOLATION_LEVEL);
List<HackObject> list = hackObjects.getOrDefault(uuid, new ArrayList<>());
list.add(new HackObject(uuid, date, hackType, violationLevel));
hackObjects.put(uuid, list);
}
return hackObjects;
}
};
}
}

View File

@ -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.pluginbridge.plan.aac;
import com.djrapitops.plan.db.patches.Patch;
/**
* Patch to fix a bug
* https://github.com/plan-player-analytics/Plan/issues/1027
* introduced in commit 530c4a2
* https://github.com/plan-player-analytics/Plan/commit/530c4a2ea6fd56fd9a7aa3382f7571f31971dc1a#commitcomment-33415938
*
* @author Rsl1122
*/
public class HackerTableMissingDateColumnPatch extends Patch {
@Override
public boolean hasBeenApplied() {
return hasColumn(HackerTable.TABLE_NAME, HackerTable.COL_DATE);
}
@Override
protected void applyPatch() {
addColumn(HackerTable.TABLE_NAME, HackerTable.COL_DATE + " bigint NOT NULL DEFAULT 0");
}
}

View File

@ -1,61 +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.pluginbridge.plan.aac;
import com.djrapitops.plan.db.Database;
import me.konsolas.aac.api.AACAPIProvider;
import me.konsolas.aac.api.HackType;
import me.konsolas.aac.api.PlayerViolationCommandEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.util.UUID;
/**
* Class responsible for listening kick events made by AAC.
*
* @author Rsl1122
*/
public class PlayerHackKickListener implements Listener {
private final Database database;
PlayerHackKickListener(Database database) {
this.database = database;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onKick(PlayerViolationCommandEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
HackType hackType = event.getHackType();
String hackTypeName = hackType.getName();
long time = System.currentTimeMillis();
int violations = new AACAPIProvider().getAPI().getViolationLevel(player, hackType);
HackObject hackObject = new HackObject(uuid, time, hackTypeName, violations);
database.executeTransaction(new StoreHackViolationKickTransaction(hackObject));
}
}

View File

@ -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.pluginbridge.plan.aac;
import com.djrapitops.plan.db.access.ExecStatement;
import com.djrapitops.plan.db.access.Executable;
import com.djrapitops.plan.db.access.transactions.Transaction;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import static com.djrapitops.pluginbridge.plan.aac.HackerTable.*;
/**
* Transaction to store kick information when AAC kicks a player for hacking.
*
* @author Rsl1122
*/
public class StoreHackViolationKickTransaction extends Transaction {
private final HackObject info;
public StoreHackViolationKickTransaction(HackObject info) {
this.info = info;
}
@Override
protected void performOperations() {
execute(storeViolationKick());
}
private Executable storeViolationKick() {
String sql = "INSERT INTO " + TABLE_NAME + " ("
+ COL_UUID + ", "
+ COL_DATE + ", "
+ COL_HACK_TYPE + ", "
+ COL_VIOLATION_LEVEL
+ ") VALUES (?, ?, ?, ?)";
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, info.getUuid().toString());
statement.setLong(2, info.getDate());
statement.setString(3, info.getHackType());
statement.setInt(4, info.getViolationLevel());
}
};
}
}

View File

@ -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.pluginbridge.plan.protocolsupport;
import com.djrapitops.plan.db.Database;
import com.djrapitops.pluginbridge.plan.viaversion.StoreUsedProtocolTransaction;
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 protocolsupport.api.ProtocolSupportAPI;
import protocolsupport.api.ProtocolVersion;
import java.util.UUID;
/**
* Class responsible for listening join events for Version protocol.
*
* @author Rsl1122
*/
public class PlayerVersionListener implements Listener {
private final Database database;
public PlayerVersionListener(Database database) {
this.database = database;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
ProtocolVersion protocolVersion = ProtocolSupportAPI.getProtocolVersion(player);
int playerVersion = protocolVersion.getId();
database.executeTransaction(new StoreUsedProtocolTransaction(uuid, playerVersion));
}
}

View File

@ -1,123 +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.pluginbridge.plan.protocolsupport;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.data.element.AnalysisContainer;
import com.djrapitops.plan.data.element.InspectContainer;
import com.djrapitops.plan.data.element.TableContainer;
import com.djrapitops.plan.data.plugin.ContainerSize;
import com.djrapitops.plan.data.plugin.PluginData;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.utilities.html.icon.Color;
import com.djrapitops.plan.utilities.html.icon.Icon;
import com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable;
import protocolsupport.api.ProtocolVersion;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* PluginData for ProtocolSupport plugin.
*
* @author Rsl1122
*/
class ProtocolSupportData extends PluginData {
private final Database database;
ProtocolSupportData(Database database) {
super(ContainerSize.THIRD, "ProtocolSupport");
setPluginIcon(Icon.called("gamepad").of(Color.CYAN).build());
this.database = database;
}
@Override
public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) {
try {
int protocolVersion = database.query(ProtocolTable.getProtocolVersion(uuid));
inspectContainer.addValue(getWithIcon("Last Join Version", Icon.called("signal").of(Color.CYAN)),
getProtocolVersionString(protocolVersion));
} catch (DBOpException ex) {
inspectContainer.addValue("Error", ex.toString());
}
return inspectContainer;
}
private String getProtocolVersionString(int number) {
if (number == -1) {
return "Not Yet Known";
}
ProtocolVersion[] versions = ProtocolVersion.getAllSupported();
for (ProtocolVersion version : versions) {
if (version.getId() == number) {
String name = version.getName();
if (name == null) {
break; // Unknown name for the version
}
return name;
}
}
return "Unknown (" + number + ')';
}
@Override
public AnalysisContainer getServerData(Collection<UUID> collection, AnalysisContainer analysisContainer) {
Map<UUID, Integer> versions;
try {
versions = database.query(ProtocolTable.getProtocolVersions());
} catch (DBOpException ex) {
analysisContainer.addValue("Error", ex.toString());
return analysisContainer;
}
Map<UUID, String> userVersions = versions.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> getProtocolVersionString(entry.getValue())));
analysisContainer.addPlayerTableValues(getWithIcon("Last Version", Icon.called("signal")), userVersions);
String versionS = getWithIcon("Version", Icon.called("signal"));
String membersS = getWithIcon("Users", Icon.called("users"));
TableContainer versionTable = new TableContainer(versionS, membersS);
versionTable.setColor("cyan");
Map<String, Integer> usersPerVersion = getUsersPerVersion(userVersions);
for (Map.Entry<String, Integer> entry : usersPerVersion.entrySet()) {
versionTable.addRow(entry.getKey(), entry.getValue());
}
analysisContainer.addTable("versionTable", versionTable);
return analysisContainer;
}
private Map<String, Integer> getUsersPerVersion(Map<UUID, String> userVersions) {
Map<String, Integer> usersPerVersion = new HashMap<>();
for (String version : userVersions.values()) {
if (!usersPerVersion.containsKey(version)) {
usersPerVersion.put(version, 0);
}
usersPerVersion.replace(version, usersPerVersion.get(version) + 1);
}
return usersPerVersion;
}
}

View File

@ -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.pluginbridge.plan.protocolsupport;
import com.djrapitops.plan.Plan;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.pluginbridge.plan.Hook;
import com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Hook for ProtocolSupport plugin.
*
* @author Rsl1122
*/
@Singleton
public class ProtocolSupportHook extends Hook {
private final Plan plugin;
private final DBSystem dbSystem;
@Inject
public ProtocolSupportHook(
Plan plugin,
DBSystem dbSystem
) {
super("protocolsupport.ProtocolSupport");
this.plugin = plugin;
this.dbSystem = dbSystem;
}
@Override
public void hook(HookHandler handler) throws NoClassDefFoundError {
if (!enabled) {
return;
}
Database database = dbSystem.getDatabase();
database.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(ProtocolTable.createTableSQL(database.getType()));
}
});
plugin.registerListener(new PlayerVersionListener(database));
handler.addPluginDataSource(new ProtocolSupportData(database));
}
}

View File

@ -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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.db.Database;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import us.myles.ViaVersion.api.ViaAPI;
import java.util.UUID;
/**
* Class responsible for listening join events for Version protocol.
*
* @author Rsl1122
*/
public class BukkitPlayerVersionListener implements Listener {
private final ViaAPI viaAPI;
private final Database database;
BukkitPlayerVersionListener(
ViaAPI viaAPI,
Database database
) {
this.viaAPI = viaAPI;
this.database = database;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent event) {
UUID uuid = event.getPlayer().getUniqueId();
int playerVersion = viaAPI.getPlayerVersion(uuid);
database.executeTransaction(new StoreUsedProtocolTransaction(uuid, playerVersion));
}
}

View File

@ -1,53 +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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.db.Database;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import us.myles.ViaVersion.api.ViaAPI;
import java.util.UUID;
/**
* Class responsible for listening join events for Version protocol.
*
* @author Rsl1122
*/
public class BungeePlayerVersionListener implements Listener {
private final ViaAPI viaAPI;
private final Database database;
BungeePlayerVersionListener(
ViaAPI viaAPI,
Database database
) {
this.viaAPI = viaAPI;
this.database = database;
}
@EventHandler
public void onJoin(PostLoginEvent event) {
UUID uuid = event.getPlayer().getUniqueId();
int playerVersion = viaAPI.getPlayerVersion(uuid);
database.executeTransaction(new StoreUsedProtocolTransaction(uuid, playerVersion));
}
}

View File

@ -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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.db.DBType;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryAllStatement;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
import com.djrapitops.plan.db.sql.parsing.Select;
import com.djrapitops.plan.db.sql.parsing.Sql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Class responsible for version protocol information in Plan database.
*
* @author Rsl1122
*/
public class ProtocolTable {
public static final String TABLE_NAME = "plan_version_protocol";
public static final String COL_ID = "id";
public static final String COL_UUID = "uuid";
public static final String COL_PROTOCOL_VERSION = "protocol_version";
private ProtocolTable() {
/* Static information class */
}
public static String createTableSQL(DBType dbType) {
return CreateTableParser.create(TABLE_NAME, dbType)
.column(COL_ID, Sql.INT).primaryKey()
.column(COL_UUID, Sql.varchar(36)).notNull().unique()
.column(COL_PROTOCOL_VERSION, Sql.INT).notNull()
.build();
}
public static Query<Integer> getProtocolVersion(UUID uuid) {
String sql = "SELECT " + COL_PROTOCOL_VERSION + " FROM " + TABLE_NAME + " WHERE " + COL_UUID + "=?";
return new QueryStatement<Integer>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
@Override
public Integer processResults(ResultSet set) throws SQLException {
if (set.next()) {
return set.getInt(COL_PROTOCOL_VERSION);
} else {
return -1;
}
}
};
}
public static Query<Map<UUID, Integer>> getProtocolVersions() {
return new QueryAllStatement<Map<UUID, Integer>>(Select.all(TABLE_NAME).toString(), 5000) {
@Override
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
Map<UUID, Integer> versions = new HashMap<>();
while (set.next()) {
String uuidS = set.getString(COL_UUID);
UUID uuid = UUID.fromString(uuidS);
versions.put(uuid, set.getInt(COL_PROTOCOL_VERSION));
}
return versions;
}
};
}
}

View File

@ -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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.db.access.ExecStatement;
import com.djrapitops.plan.db.access.Executable;
import com.djrapitops.plan.db.access.transactions.Transaction;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.UUID;
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
import static com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable.*;
/**
* Transaction to store used version protocol.
*
* @author Rsl1122
*/
public class StoreUsedProtocolTransaction extends Transaction {
private final UUID playerUUID;
private final int protocolVersion;
public StoreUsedProtocolTransaction(UUID playerUUID, int protocolVersion) {
this.playerUUID = playerUUID;
this.protocolVersion = protocolVersion;
}
@Override
protected void performOperations() {
execute(storeProtocol());
}
private Executable storeProtocol() {
return connection -> {
if (!updateProtocol().execute(connection)) {
return insertProtocol().execute(connection);
}
return false;
};
}
private Executable updateProtocol() {
String sql = "UPDATE " + TABLE_NAME + " SET "
+ COL_PROTOCOL_VERSION + "=?"
+ WHERE + COL_UUID + "=?";
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setInt(1, protocolVersion);
statement.setString(2, playerUUID.toString());
}
};
}
private Executable insertProtocol() {
String sql = "INSERT INTO " + TABLE_NAME + " ("
+ COL_UUID + ", "
+ COL_PROTOCOL_VERSION
+ ") VALUES (?, ?)";
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, playerUUID.toString());
statement.setInt(2, protocolVersion);
}
};
}
}

View File

@ -1,69 +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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.Plan;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.pluginbridge.plan.Hook;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* A Class responsible for hooking to ViaVersion and registering data sources.
*
* @author Rsl1122
*/
@Singleton
public class ViaVersionBukkitHook extends Hook {
private final Plan plugin;
private final DBSystem dbSystem;
@Inject
public ViaVersionBukkitHook(
Plan plugin,
DBSystem dbSystem
) {
super("us.myles.ViaVersion.ViaVersionPlugin");
this.plugin = plugin;
this.dbSystem = dbSystem;
}
public void hook(HookHandler handler) throws NoClassDefFoundError {
if (!enabled) {
return;
}
ViaAPI api = Via.getAPI();
Database database = dbSystem.getDatabase();
database.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(ProtocolTable.createTableSQL(database.getType()));
}
});
plugin.registerListener(new BukkitPlayerVersionListener(api, database));
handler.addPluginDataSource(new ViaVersionData(database));
}
}

View File

@ -1,69 +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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.PlanBungee;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.pluginbridge.plan.Hook;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* A Class responsible for hooking to ViaVersion and registering data sources.
*
* @author Rsl1122
*/
@Singleton
public class ViaVersionBungeeHook extends Hook {
private final PlanBungee plugin;
private final DBSystem dbSystem;
@Inject
public ViaVersionBungeeHook(
PlanBungee plugin,
DBSystem dbSystem
) {
super("us.myles.ViaVersion.BungeePlugin");
this.plugin = plugin;
this.dbSystem = dbSystem;
}
public void hook(HookHandler handler) throws NoClassDefFoundError {
if (!enabled) {
return;
}
ViaAPI api = Via.getAPI();
Database database = dbSystem.getDatabase();
database.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(ProtocolTable.createTableSQL(database.getType()));
}
});
plugin.registerListener(new BungeePlayerVersionListener(api, database));
handler.addPluginDataSource(new ViaVersionData(database));
}
}

View File

@ -1,109 +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.pluginbridge.plan.viaversion;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.data.element.AnalysisContainer;
import com.djrapitops.plan.data.element.InspectContainer;
import com.djrapitops.plan.data.element.TableContainer;
import com.djrapitops.plan.data.plugin.ContainerSize;
import com.djrapitops.plan.data.plugin.PluginData;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.utilities.html.icon.Color;
import com.djrapitops.plan.utilities.html.icon.Icon;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* PluginData for ViaVersion plugin.
*
* @author Rsl1122
*/
class ViaVersionData extends PluginData {
private final Database database;
ViaVersionData(Database database) {
super(ContainerSize.THIRD, "ViaVersion");
setPluginIcon(Icon.called("gamepad").of(Color.LIGHT_GREEN).build());
this.database = database;
}
@Override
public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) {
try {
int version = database.query(ProtocolTable.getProtocolVersion(uuid));
inspectContainer.addValue(getWithIcon("Last Join Version", Icon.called("signal").of(Color.LIGHT_GREEN)),
getProtocolVersionString(version));
} catch (DBOpException ex) {
inspectContainer.addValue("Error", ex.toString());
}
return inspectContainer;
}
private String getProtocolVersionString(int version) {
return version != -1 ? ProtocolVersion.getProtocol(version).getName() : "Not Yet Known";
}
@Override
public AnalysisContainer getServerData(Collection<UUID> collection, AnalysisContainer analysisContainer) {
Map<UUID, Integer> versions;
try {
versions = database.query(ProtocolTable.getProtocolVersions());
} catch (DBOpException ex) {
analysisContainer.addValue("Error", ex.toString());
return analysisContainer;
}
Map<UUID, String> userVersions = versions.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> getProtocolVersionString(entry.getValue())));
analysisContainer.addPlayerTableValues(getWithIcon("Last Version", Icon.called("signal")), userVersions);
String versionS = getWithIcon("Version", Icon.called("signal"));
String membersS = getWithIcon("Users", Icon.called("users"));
TableContainer versionTable = new TableContainer(versionS, membersS);
versionTable.setColor("light-green");
Map<String, Integer> usersPerVersion = getUsersPerVersion(userVersions);
for (Map.Entry<String, Integer> entry : usersPerVersion.entrySet()) {
versionTable.addRow(entry.getKey(), entry.getValue());
}
analysisContainer.addTable("versionTable", versionTable);
return analysisContainer;
}
private Map<String, Integer> getUsersPerVersion(Map<UUID, String> userVersions) {
Map<String, Integer> usersPerVersion = new HashMap<>();
for (String version : userVersions.values()) {
if (!usersPerVersion.containsKey(version)) {
usersPerVersion.put(version, 0);
}
usersPerVersion.replace(version, usersPerVersion.get(version) + 1);
}
return usersPerVersion;
}
}