mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-21 05:50:18 +08:00
Merge pull request #216 from Fuzzlemann/master
PR for 3.6.1 (Fuzzlemann) (1)
This commit is contained in:
commit
6ddd7a212c
@ -1,13 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: com.djrapitops:PlanPluginBridge:3.5.0">
|
||||
<library name="Maven: com.djrapitops:PlanPluginBridge:3.6.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.5.0/PlanPluginBridge-3.5.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.6.0/PlanPluginBridge-3.6.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.5.0/PlanPluginBridge-3.5.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.6.0/PlanPluginBridge-3.6.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.5.0/PlanPluginBridge-3.5.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/PlanPluginBridge/3.6.0/PlanPluginBridge-3.6.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.djrapitops</groupId>
|
||||
<artifactId>Plan</artifactId>
|
||||
<version>3.5.5</version>
|
||||
<version>3.6.0</version>
|
||||
<build>
|
||||
<sourceDirectory>${basedir}/src</sourceDirectory>
|
||||
<defaultGoal>clean package install</defaultGoal>
|
||||
@ -12,6 +12,8 @@
|
||||
<targetPath>.</targetPath>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>*.keystore</include>
|
||||
<include>*.js</include>
|
||||
<include>*.yml</include>
|
||||
<include>*.html</include>
|
||||
</includes>
|
||||
@ -178,6 +180,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<sonar.language>java</sonar.language>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
|
@ -25,6 +25,7 @@ public class PluginConfigSectionHandler {
|
||||
if (!section.contains(pluginName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigurationSection pluginSection = section.getConfigurationSection(pluginName);
|
||||
return pluginSection.contains(dataSource.getPlaceholder(""));
|
||||
}
|
||||
@ -38,8 +39,10 @@ public class PluginConfigSectionHandler {
|
||||
ConfigurationSection section = getPluginsSection();
|
||||
String pluginName = dataSource.getSourcePlugin();
|
||||
String source = dataSource.placeholder;
|
||||
|
||||
section.addDefault(pluginName + ".Enabled", true);
|
||||
section.addDefault(pluginName + ".Data." + source, true);
|
||||
|
||||
FileConfiguration config = plan.getConfig();
|
||||
config.set("Customization.Plugins", section);
|
||||
plan.saveConfig();
|
||||
@ -47,9 +50,11 @@ public class PluginConfigSectionHandler {
|
||||
|
||||
public boolean isEnabled(PluginData dataSource) {
|
||||
ConfigurationSection section = getPluginsSection();
|
||||
|
||||
String pluginName = dataSource.getSourcePlugin();
|
||||
if (!section.getBoolean(pluginName + ".Enabled")) {
|
||||
return false;
|
||||
|
||||
}
|
||||
String source = dataSource.placeholder;
|
||||
return section.getBoolean(pluginName + ".Data." + source);
|
||||
|
@ -16,7 +16,7 @@ import java.util.Map;
|
||||
* <p>
|
||||
* It caches all IPs with their matching country.
|
||||
* <p>
|
||||
* This cache uses the Google Guava {@link Cache} and has a capacity of 10.000 entries.
|
||||
* This cache uses the Google Guava {@link Cache}.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
* @since 3.5.5
|
||||
@ -31,7 +31,6 @@ public class GeolocationCacheHandler {
|
||||
}
|
||||
|
||||
private static final Cache<String, String> geolocationCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(10000)
|
||||
.build();
|
||||
|
||||
/**
|
||||
|
@ -44,17 +44,14 @@ public class InspectCacheHandler {
|
||||
* @param uuid UUID of the player.
|
||||
*/
|
||||
public void cache(UUID uuid) {
|
||||
DBCallableProcessor cacher = new DBCallableProcessor() {
|
||||
@Override
|
||||
public void process(UserData data) {
|
||||
cache.put(uuid, new UserData(data));
|
||||
cacheTimes.put(uuid, MiscUtils.getTime());
|
||||
PageCacheHandler.cachePage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(Plan.getInstance().getUiServer().getDataReqHandler(), uuid));
|
||||
try {
|
||||
ExportUtility.writeInspectHtml(data, ExportUtility.getPlayersFolder(ExportUtility.getFolder()));
|
||||
} catch (IOException ex) {
|
||||
Log.toLog(this.getClass().getName(), ex);
|
||||
}
|
||||
DBCallableProcessor cacher = data -> {
|
||||
cache.put(uuid, new UserData(data));
|
||||
cacheTimes.put(uuid, MiscUtils.getTime());
|
||||
PageCacheHandler.cachePage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(Plan.getInstance().getUiServer().getDataReqHandler(), uuid));
|
||||
try {
|
||||
ExportUtility.writeInspectHtml(data, ExportUtility.getPlayersFolder(ExportUtility.getFolder()));
|
||||
} catch (IOException ex) {
|
||||
Log.toLog(this.getClass().getName(), ex);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@ package main.java.com.djrapitops.plan.data.handling.importing;
|
||||
|
||||
import com.djrapitops.plugin.utilities.player.Fetch;
|
||||
import com.djrapitops.plugin.utilities.player.IOfflinePlayer;
|
||||
import com.djrapitops.plugin.utilities.status.ProcessStatus;
|
||||
import main.java.com.djrapitops.plan.Log;
|
||||
import main.java.com.djrapitops.plan.Plan;
|
||||
import main.java.com.djrapitops.plan.data.UserData;
|
||||
@ -14,8 +15,10 @@ import main.java.com.djrapitops.plan.utilities.NewPlayerCreator;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Abstract class used for importing data from other plugins.
|
||||
@ -58,11 +61,16 @@ public abstract class Importer {
|
||||
public boolean importData(Collection<UUID> uuids, String... args) {
|
||||
Plan plan = Plan.getInstance();
|
||||
plan.getAnalysisCache().disableAnalysisTemporarily();
|
||||
|
||||
try {
|
||||
String processName = "Import, " + getClass().getSimpleName();
|
||||
plan.processStatus().startExecution(processName);
|
||||
|
||||
ProcessStatus<Plan> processStatus = plan.processStatus();
|
||||
DataCacheHandler handler = plan.getHandler();
|
||||
Database db = plan.getDB();
|
||||
|
||||
processStatus.startExecution(processName);
|
||||
|
||||
Set<UUID> saved;
|
||||
try {
|
||||
saved = db.getSavedUUIDs();
|
||||
@ -70,30 +78,58 @@ public abstract class Importer {
|
||||
Log.toLog(this.getClass().getName(), ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
List<UUID> unSaved = new ArrayList<>(uuids);
|
||||
unSaved.removeAll(saved);
|
||||
String createUserObjects = "Creating new UserData objects for: " + unSaved.size();
|
||||
plan.processStatus().setStatus(processName, createUserObjects);
|
||||
|
||||
int amount = unSaved.size();
|
||||
|
||||
String createUserObjects = "Creating " + amount + " new UserData objects";
|
||||
processStatus.setStatus(processName, createUserObjects);
|
||||
|
||||
Map<UUID, IOfflinePlayer> offlinePlayers = Fetch.getIOfflinePlayers().stream().collect(Collectors.toMap(IOfflinePlayer::getUuid, Function.identity()));
|
||||
|
||||
Benchmark.start(createUserObjects);
|
||||
List<IOfflinePlayer> offlineP = unSaved.stream().map(offlinePlayers::get).collect(Collectors.toList());
|
||||
|
||||
List<UserData> newUsers = new ArrayList<>();
|
||||
for (IOfflinePlayer p : offlineP) {
|
||||
UserData newPlayer = NewPlayerCreator.createNewOfflinePlayer(p);
|
||||
newPlayer.setLastPlayed(newPlayer.getRegistered());
|
||||
newUsers.add(newPlayer);
|
||||
plan.processStatus().setStatus(processName, "Creating new UserData objects: " + newUsers.size() + "/" + unSaved.size());
|
||||
}
|
||||
List<IOfflinePlayer> offlineP = unSaved
|
||||
.stream()
|
||||
.map(offlinePlayers::get)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
AtomicInteger currentUser = new AtomicInteger(0);
|
||||
AtomicInteger currentPercent = new AtomicInteger(0);
|
||||
|
||||
int fivePercent = amount / 20;
|
||||
|
||||
//Using Set because of better Collection#contains() performance
|
||||
Set<Integer> milestones = IntStream.rangeClosed(1, 20)
|
||||
.mapToObj(i -> i * fivePercent)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
offlineP.parallelStream()
|
||||
.map(NewPlayerCreator::createNewOfflinePlayer)
|
||||
.forEach(newPlayer -> {
|
||||
newPlayer.setLastPlayed(newPlayer.getRegistered());
|
||||
newUsers.add(newPlayer);
|
||||
if (milestones.contains(currentUser.incrementAndGet())) {
|
||||
processStatus.setStatus(processName, "Creating new UserData objects: " + currentPercent.addAndGet(5) + "%");
|
||||
}
|
||||
});
|
||||
|
||||
Benchmark.stop(createUserObjects);
|
||||
plan.processStatus().setStatus(processName, "Save new UserData objects (" + unSaved.size() + ")");
|
||||
processStatus.setStatus(processName, "Save new UserData objects (" + amount + ")");
|
||||
|
||||
try {
|
||||
plan.getDB().saveMultipleUserData(newUsers);
|
||||
} catch (SQLException ex) {
|
||||
Log.toLog(this.getClass().getName(), ex);
|
||||
}
|
||||
|
||||
for (UUID uuid : uuids) {
|
||||
handler.addToPool(importData(uuid, args));
|
||||
}
|
||||
|
||||
plan.processStatus().finishExecution(processName);
|
||||
} finally {
|
||||
plan.getAnalysisCache().enableAnalysis();
|
||||
|
@ -60,10 +60,10 @@ public class PlanDeathEventListener implements Listener {
|
||||
Material itemInHand;
|
||||
try {
|
||||
itemInHand = killer.getInventory().getItemInMainHand().getType();
|
||||
} catch (Exception e) {
|
||||
} catch (NoSuchMethodError e) {
|
||||
try {
|
||||
itemInHand = killer.getInventory().getItemInHand().getType(); // Support for non dual wielding versions.
|
||||
} catch (Exception e2) {
|
||||
} catch (Error e2) {
|
||||
itemInHand = Material.AIR;
|
||||
}
|
||||
}
|
||||
|
@ -117,26 +117,6 @@ public abstract class TimeKeeper {
|
||||
return times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TimeKeeper that = (TimeKeeper) o;
|
||||
|
||||
if (lastStateChange != that.lastStateChange) return false;
|
||||
if (times != null ? !times.equals(that.times) : that.times != null) return false;
|
||||
return state != null ? state.equals(that.state) : that.state == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = times != null ? times.hashCode() : 0;
|
||||
result = 31 * result + (state != null ? state.hashCode() : 0);
|
||||
result = 31 * result + (int) (lastStateChange ^ (lastStateChange >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
@ -153,10 +133,32 @@ public abstract class TimeKeeper {
|
||||
return lastStateChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TimeKeeper that = (TimeKeeper) o;
|
||||
|
||||
return lastStateChange == that.lastStateChange &&
|
||||
times != null ? times.equals(that.times) : that.times == null
|
||||
&& state != null ? state.equals(that.state) : that.state == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = times != null ? times.hashCode() : 0;
|
||||
result = 31 * result + (state != null ? state.hashCode() : 0);
|
||||
result = 31 * result + (int) (lastStateChange ^ (lastStateChange >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "times:" + times +
|
||||
",state:" + state +
|
||||
",lastStateChange:" + lastStateChange;
|
||||
return "TimeKeeper{" +
|
||||
"times=" + times +
|
||||
", state='" + state + '\'' +
|
||||
", lastStateChange=" + lastStateChange +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -72,6 +72,7 @@ public class DBUtils {
|
||||
if (wrappedBatches.size() <= j) {
|
||||
wrappedBatches.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
wrappedBatches.get(j).add(new Container<>(object, entry.getKey()));
|
||||
i++;
|
||||
if (i % BATCH_SIZE == 0) {
|
||||
@ -81,4 +82,25 @@ public class DBUtils {
|
||||
}
|
||||
return wrappedBatches;
|
||||
}
|
||||
|
||||
public static <T> List<List<Container<T>>> splitIntoBatchesWithID(Map<Integer, T> objects) {
|
||||
List<List<Container<T>>> wrappedBatches = new ArrayList<>();
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
for (Entry<Integer, T> entry : objects.entrySet()) {
|
||||
T object = entry.getValue();
|
||||
if (wrappedBatches.size() <= j) {
|
||||
wrappedBatches.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
wrappedBatches.get(j).add(new Container<>(object, entry.getKey()));
|
||||
i++;
|
||||
if (i % BATCH_SIZE == 0) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return wrappedBatches;
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ public class MySQLDB extends SQLDB {
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
|
||||
String url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getString("mysql.port") + "/" + config.getString("mysql.database");
|
||||
String url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getString("mysql.port") + "/"
|
||||
+ config.getString("mysql.database")
|
||||
+ "?rewriteBatchedStatements=true";
|
||||
|
||||
return DriverManager.getConnection(url, config.getString("mysql.user"), config.getString("mysql.password"));
|
||||
} catch (ClassNotFoundException | SQLException e) {
|
||||
|
@ -424,19 +424,24 @@ public abstract class SQLDB extends Database {
|
||||
*/
|
||||
@Override
|
||||
public void saveMultipleUserData(Collection<UserData> data) throws SQLException {
|
||||
Benchmark.start("Database: Save multiple Userdata");
|
||||
checkConnection();
|
||||
if (data.isEmpty()) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Benchmark.start("Database: Save multiple Userdata");
|
||||
data.removeIf(Objects::isNull);
|
||||
|
||||
checkConnection();
|
||||
setStatus("Save userdata (multiple) for " + data.size());
|
||||
usersTable.saveUserDataInformationBatch(data);
|
||||
|
||||
// Transform to map
|
||||
Map<UUID, UserData> userDatas = data.stream().collect(Collectors.toMap(UserData::getUuid, Function.identity()));
|
||||
Map<UUID, UserData> userDatas = data.stream()
|
||||
.collect(Collectors.toMap(UserData::getUuid, Function.identity()));
|
||||
|
||||
// Get UserIDs
|
||||
Map<UUID, Integer> userIds = usersTable.getAllUserIds();
|
||||
// Empty dataset
|
||||
// Create empty data sets
|
||||
Map<Integer, Set<String>> nicknames = new HashMap<>();
|
||||
Map<Integer, String> lastNicks = new HashMap<>();
|
||||
Map<Integer, Set<InetAddress>> ips = new HashMap<>();
|
||||
@ -445,14 +450,16 @@ public abstract class SQLDB extends Database {
|
||||
Map<Integer, List<SessionData>> sessions = new HashMap<>();
|
||||
Map<Integer, Map<String, Long>> gmTimes = new HashMap<>();
|
||||
Map<Integer, Map<String, Long>> worldTimes = new HashMap<>();
|
||||
// Put to dataset
|
||||
|
||||
// Put in data set
|
||||
List<String> worldNames = data.stream()
|
||||
.map(UserData::getWorldTimes)
|
||||
.map(WorldTimes::getTimes)
|
||||
.map(Map::keySet)
|
||||
.flatMap(keySet -> keySet.stream())
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Map.Entry<UUID, UserData> entrySet : userDatas.entrySet()) {
|
||||
UUID uuid = entrySet.getKey();
|
||||
UserData uData = entrySet.getValue();
|
||||
@ -472,6 +479,7 @@ public abstract class SQLDB extends Database {
|
||||
gmTimes.put(id, new HashMap<>(uData.getGmTimes().getTimes()));
|
||||
worldTimes.put(id, new HashMap<>(uData.getWorldTimes().getTimes()));
|
||||
}
|
||||
|
||||
// Save
|
||||
nicknamesTable.saveNickLists(nicknames, lastNicks);
|
||||
ipsTable.saveIPList(ips);
|
||||
|
@ -83,6 +83,7 @@ public class CommandUseTable extends Table {
|
||||
if (data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Benchmark.start("Database: Save Commanduse");
|
||||
Map<String, Integer> newData = new HashMap<>(data);
|
||||
Map<String, Integer> saved = getCommandUse();
|
||||
|
@ -2,6 +2,9 @@ package main.java.com.djrapitops.plan.database.tables;
|
||||
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
import main.java.com.djrapitops.plan.Log;
|
||||
import main.java.com.djrapitops.plan.data.time.GMTimes;
|
||||
import main.java.com.djrapitops.plan.database.Container;
|
||||
import main.java.com.djrapitops.plan.database.DBUtils;
|
||||
import main.java.com.djrapitops.plan.database.databases.SQLDB;
|
||||
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
||||
|
||||
@ -93,12 +96,14 @@ public class GMTimesTable extends Table {
|
||||
statement.setInt(1, userId);
|
||||
set = statement.executeQuery();
|
||||
HashMap<String, Long> times = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
times.put("SURVIVAL", set.getLong(columnSurvivalTime));
|
||||
times.put("CREATIVE", set.getLong(columnCreativeTime));
|
||||
times.put("ADVENTURE", set.getLong(columnAdventureTime));
|
||||
times.put("SPECTATOR", set.getLong(columnSpectatorTime));
|
||||
}
|
||||
|
||||
return times;
|
||||
} finally {
|
||||
close(set);
|
||||
@ -113,18 +118,21 @@ public class GMTimesTable extends Table {
|
||||
try {
|
||||
statement = prepareStatement("SELECT * FROM " + tableName);
|
||||
set = statement.executeQuery();
|
||||
|
||||
while (set.next()) {
|
||||
Map<String, Long> gmTimes = new HashMap<>();
|
||||
int id = set.getInt(columnUserID);
|
||||
if (!userIds.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gmTimes.put("SURVIVAL", set.getLong(columnSurvivalTime));
|
||||
gmTimes.put("CREATIVE", set.getLong(columnCreativeTime));
|
||||
gmTimes.put("ADVENTURE", set.getLong(columnAdventureTime));
|
||||
gmTimes.put("SPECTATOR", set.getLong(columnSpectatorTime));
|
||||
times.put(id, gmTimes);
|
||||
}
|
||||
|
||||
return times;
|
||||
} finally {
|
||||
close(set);
|
||||
@ -141,8 +149,10 @@ public class GMTimesTable extends Table {
|
||||
if (Verify.isEmpty(gamemodeTimes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement statement = null;
|
||||
String[] gms = getGMKeyArray();
|
||||
|
||||
int update;
|
||||
try {
|
||||
statement = prepareStatement(
|
||||
@ -153,22 +163,17 @@ public class GMTimesTable extends Table {
|
||||
+ columnSpectatorTime + "=? "
|
||||
+ " WHERE (" + columnUserID + "=?)");
|
||||
statement.setInt(5, userId);
|
||||
|
||||
for (int i = 0; i < gms.length; i++) {
|
||||
try {
|
||||
Long time = gamemodeTimes.get(gms[i]);
|
||||
if (time != null) {
|
||||
statement.setLong(i + 1, time);
|
||||
} else {
|
||||
statement.setLong(i + 1, 0);
|
||||
}
|
||||
} catch (NoSuchFieldError e) {
|
||||
statement.setLong(i + 1, 0);
|
||||
}
|
||||
Long time = gamemodeTimes.get(gms[i]);
|
||||
statement.setLong(i + 1, time != null ? time : 0);
|
||||
}
|
||||
|
||||
update = statement.executeUpdate();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
|
||||
if (update == 0) {
|
||||
addNewGMTimesRow(userId, gamemodeTimes);
|
||||
}
|
||||
@ -195,11 +200,52 @@ public class GMTimesTable extends Table {
|
||||
if (Verify.isEmpty(gamemodeTimes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Benchmark.start("Database: Save GMTimes");
|
||||
PreparedStatement statement = null;
|
||||
String[] gms = getGMKeyArray();
|
||||
|
||||
Set<Integer> savedIDs = getSavedIDs();
|
||||
|
||||
Map<Integer, GMTimes> gmTimes = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Integer, Map<String, Long>> entrySet : gamemodeTimes.entrySet()) {
|
||||
int userID = entrySet.getKey();
|
||||
|
||||
if (!savedIDs.contains(userID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Long> gmTimesMap = entrySet.getValue();
|
||||
gmTimes.put(userID, new GMTimes(gmTimesMap));
|
||||
}
|
||||
|
||||
List<List<Container<GMTimes>>> batches = DBUtils.splitIntoBatchesWithID(gmTimes);
|
||||
|
||||
batches.parallelStream().forEach(batch -> {
|
||||
try {
|
||||
saveGMTimesBatch(batch);
|
||||
} catch (SQLException e) {
|
||||
Log.toLog("GMTimesTable.saveGMTimes", e);
|
||||
}
|
||||
});
|
||||
|
||||
gamemodeTimes.keySet().removeAll(savedIDs);
|
||||
|
||||
addNewGMTimesRows(gamemodeTimes);
|
||||
Benchmark.stop("Database: Save GMTimes");
|
||||
}
|
||||
|
||||
private void saveGMTimesBatch(List<Container<GMTimes>> batch) throws SQLException {
|
||||
if (batch.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int batchSize = batch.size();
|
||||
Log.debug("Preparing insertion of GM Times... Batch Size: " + batchSize);
|
||||
|
||||
String[] gms = getGMKeyArray();
|
||||
Set<Integer> savedIDs = getSavedIDs();
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = prepareStatement(
|
||||
"UPDATE " + tableName + " SET "
|
||||
@ -208,48 +254,72 @@ public class GMTimesTable extends Table {
|
||||
+ columnAdventureTime + "=?, "
|
||||
+ columnSpectatorTime + "=? "
|
||||
+ " WHERE (" + columnUserID + "=?)");
|
||||
boolean commitRequired = false;
|
||||
for (Map.Entry<Integer, Map<String, Long>> entrySet : gamemodeTimes.entrySet()) {
|
||||
Integer id = entrySet.getKey();
|
||||
|
||||
for (Container<GMTimes> data : batch) {
|
||||
int id = data.getId();
|
||||
|
||||
if (!savedIDs.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statement.setInt(5, id);
|
||||
|
||||
for (int i = 0; i < gms.length; i++) {
|
||||
try {
|
||||
Map<String, Long> times = entrySet.getValue();
|
||||
Long time = times.get(gms[i]);
|
||||
Map<String, Long> times = data.getObject().getTimes();
|
||||
Long time = times.get(gms[i]);
|
||||
|
||||
statement.setLong(i + 1, time != null ? time : 0);
|
||||
} catch (NoSuchFieldError e) {
|
||||
statement.setLong(i + 1, 0);
|
||||
}
|
||||
statement.setLong(i + 1, time != null ? time : 0);
|
||||
}
|
||||
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
}
|
||||
|
||||
if (commitRequired) {
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
gamemodeTimes.keySet().removeAll(savedIDs);
|
||||
Log.debug("Executing GM Times batch: " + batchSize);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
|
||||
addNewGMTimesRows(gamemodeTimes);
|
||||
Benchmark.stop("Database: Save GMTimes");
|
||||
}
|
||||
|
||||
private void addNewGMTimesRows(Map<Integer, Map<String, Long>> gamemodeTimes) throws SQLException {
|
||||
if (Verify.isEmpty(gamemodeTimes)) {
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement = null;
|
||||
|
||||
Benchmark.start("Database: Add GMTimes Rows");
|
||||
|
||||
Map<Integer, GMTimes> gmTimes = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Integer, Map<String, Long>> entrySet : gamemodeTimes.entrySet()) {
|
||||
int userID = entrySet.getKey();
|
||||
Map<String, Long> gmTimesMap = entrySet.getValue();
|
||||
gmTimes.put(userID, new GMTimes(gmTimesMap));
|
||||
}
|
||||
|
||||
List<List<Container<GMTimes>>> batches = DBUtils.splitIntoBatchesWithID(gmTimes);
|
||||
|
||||
batches.parallelStream().forEach(batch -> {
|
||||
try {
|
||||
addNewGMTimesBatch(batch);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
Benchmark.stop("Database: Add GMTimes Rows");
|
||||
}
|
||||
|
||||
private void addNewGMTimesBatch(List<Container<GMTimes>> batch) throws SQLException {
|
||||
if (batch.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int batchSize = batch.size();
|
||||
Log.debug("Preparing insertion of GM Times... Batch Size: " + batchSize);
|
||||
|
||||
String[] gms = getGMKeyArray();
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = prepareStatement(
|
||||
"INSERT INTO " + tableName + " ("
|
||||
@ -259,28 +329,22 @@ public class GMTimesTable extends Table {
|
||||
+ columnAdventureTime + ", "
|
||||
+ columnSpectatorTime
|
||||
+ ") VALUES (?, ?, ?, ?, ?)");
|
||||
boolean commitRequired = false;
|
||||
for (Map.Entry<Integer, Map<String, Long>> entry : gamemodeTimes.entrySet()) {
|
||||
Integer id = entry.getKey();
|
||||
|
||||
statement.setInt(1, id);
|
||||
for (Container<GMTimes> data : batch) {
|
||||
statement.setInt(1, data.getId());
|
||||
|
||||
for (int i = 0; i < gms.length; i++) {
|
||||
try {
|
||||
Map<String, Long> times = entry.getValue();
|
||||
Long time = times.get(gms[i]);
|
||||
Map<String, Long> times = data.getObject().getTimes();
|
||||
Long time = times.get(gms[i]);
|
||||
|
||||
statement.setLong(i + 2, time != null ? time : 0);
|
||||
} catch (NoSuchFieldError e) {
|
||||
statement.setLong(i + 2, 0);
|
||||
}
|
||||
statement.setLong(i + 2, time != null ? time : 0);
|
||||
}
|
||||
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
}
|
||||
|
||||
if (commitRequired) {
|
||||
statement.executeBatch();
|
||||
}
|
||||
Log.debug("Executing GM Times batch: " + batchSize);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
@ -290,6 +354,7 @@ public class GMTimesTable extends Table {
|
||||
if (Verify.isEmpty(gamemodeTimes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement statement = null;
|
||||
String[] gms = getGMKeyArray();
|
||||
try {
|
||||
@ -302,14 +367,10 @@ public class GMTimesTable extends Table {
|
||||
+ ") VALUES (?, ?, ?, ?, ?)");
|
||||
|
||||
statement.setInt(1, userId);
|
||||
for (int i = 0; i < gms.length; i++) {
|
||||
try {
|
||||
Long time = gamemodeTimes.get(gms[i]);
|
||||
|
||||
statement.setLong(i + 2, time != null ? time : 0);
|
||||
} catch (NoSuchFieldError e) {
|
||||
statement.setLong(i + 2, 0);
|
||||
}
|
||||
for (int i = 0; i < gms.length; i++) {
|
||||
Long time = gamemodeTimes.get(gms[i]);
|
||||
statement.setLong(i + 2, time != null ? time : 0);
|
||||
}
|
||||
|
||||
statement.execute();
|
||||
|
@ -90,6 +90,7 @@ public class IPsTable extends Table {
|
||||
Log.error("Host not found at getIPAddresses: " + ipAddressName); //Shouldn't ever happen
|
||||
}
|
||||
}
|
||||
|
||||
return ips;
|
||||
} finally {
|
||||
close(set);
|
||||
|
@ -107,36 +107,38 @@ public class SessionsTable extends Table {
|
||||
if (sessions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Benchmark.start("Database: Save Sessions");
|
||||
sessions.removeAll(getSessionData(userId));
|
||||
|
||||
if (sessions.isEmpty()) {
|
||||
Benchmark.stop("Database: Save Sessions");
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
|
||||
PreparedStatement statement = null;
|
||||
|
||||
try {
|
||||
statement = prepareStatement("INSERT INTO " + tableName + " ("
|
||||
+ columnUserID + ", "
|
||||
+ columnSessionStart + ", "
|
||||
+ columnSessionEnd
|
||||
+ ") VALUES (?, ?, ?)");
|
||||
|
||||
boolean commitRequired = false;
|
||||
for (SessionData session : sessions) {
|
||||
long end = session.getSessionEnd();
|
||||
long start = session.getSessionStart();
|
||||
if (end < start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statement.setInt(1, userId);
|
||||
statement.setLong(2, start);
|
||||
statement.setLong(3, end);
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
}
|
||||
if (commitRequired) {
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
Benchmark.stop("Database: Save Sessions");
|
||||
@ -152,25 +154,31 @@ public class SessionsTable extends Table {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Benchmark.start("Database: Get Sessions multiple");
|
||||
PreparedStatement statement = null;
|
||||
ResultSet set = null;
|
||||
|
||||
try {
|
||||
Map<Integer, List<SessionData>> sessions = new HashMap<>();
|
||||
statement = prepareStatement("SELECT * FROM " + tableName);
|
||||
set = statement.executeQuery();
|
||||
|
||||
for (Integer id : ids) {
|
||||
sessions.put(id, new ArrayList<>());
|
||||
}
|
||||
|
||||
while (set.next()) {
|
||||
Integer id = set.getInt(columnUserID);
|
||||
if (!ids.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
sessions.get(id).add(new SessionData(set.getLong(columnSessionStart), set.getLong(columnSessionEnd)));
|
||||
|
||||
long sessionStart = set.getLong(columnSessionStart);
|
||||
long sessionEnd = set.getLong(columnSessionEnd);
|
||||
|
||||
sessions.get(id).add(new SessionData(sessionStart, sessionEnd));
|
||||
}
|
||||
set.close();
|
||||
statement.close();
|
||||
|
||||
return sessions;
|
||||
} finally {
|
||||
@ -195,8 +203,8 @@ public class SessionsTable extends Table {
|
||||
for (Map.Entry<Integer, List<SessionData>> entrySet : sessions.entrySet()) {
|
||||
Integer id = entrySet.getKey();
|
||||
List<SessionData> sessionList = entrySet.getValue();
|
||||
|
||||
List<SessionData> s = saved.get(id);
|
||||
|
||||
if (s != null) {
|
||||
sessionList.removeAll(s);
|
||||
}
|
||||
@ -207,11 +215,17 @@ public class SessionsTable extends Table {
|
||||
|
||||
saved.put(id, sessionList);
|
||||
}
|
||||
|
||||
List<List<Container<SessionData>>> batches = splitIntoBatches(sessions);
|
||||
|
||||
for (List<Container<SessionData>> batch : batches) {
|
||||
saveSessionBatch(batch);
|
||||
}
|
||||
batches.parallelStream().forEach(batch -> {
|
||||
try {
|
||||
saveSessionBatch(batch);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
Benchmark.stop("Database: Save Sessions multiple");
|
||||
}
|
||||
|
||||
@ -219,6 +233,10 @@ public class SessionsTable extends Table {
|
||||
if (batch.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int batchSize = batch.size();
|
||||
Log.debug("Preparing insertion of sessions... Batch Size: " + batchSize);
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = prepareStatement("INSERT INTO " + tableName + " ("
|
||||
@ -227,25 +245,21 @@ public class SessionsTable extends Table {
|
||||
+ columnSessionEnd
|
||||
+ ") VALUES (?, ?, ?)");
|
||||
|
||||
boolean commitRequired = false;
|
||||
int i = 0;
|
||||
for (Container<SessionData> data : batch) {
|
||||
SessionData session = data.getObject();
|
||||
int id = data.getId();
|
||||
if (!session.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statement.setInt(1, id);
|
||||
statement.setLong(2, session.getSessionStart());
|
||||
statement.setLong(3, session.getSessionEnd());
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
i++;
|
||||
}
|
||||
if (commitRequired) {
|
||||
Log.debug("Executing session batch: " + i);
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
Log.debug("Executing session batch: " + batchSize);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
|
@ -119,12 +119,24 @@ public class TPSTable extends Table {
|
||||
*/
|
||||
public void saveTPSData(List<TPS> data) throws SQLException {
|
||||
List<List<TPS>> batches = DBUtils.splitIntoBatches(data);
|
||||
for (List<TPS> batch : batches) {
|
||||
saveTPSBatch(batch);
|
||||
}
|
||||
batches.parallelStream()
|
||||
.forEach(batch -> {
|
||||
try {
|
||||
saveTPSBatch(batch);
|
||||
} catch (SQLException e) {
|
||||
Log.toLog("UsersTable.saveUserDataInformationBatch", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void saveTPSBatch(List<TPS> batch) throws SQLException {
|
||||
if (batch.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int batchSize = batch.size();
|
||||
Log.debug("Preparing insertion of TPS... Batch Size: " + batchSize);
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = prepareStatement("INSERT INTO " + tableName + " ("
|
||||
@ -137,8 +149,6 @@ public class TPSTable extends Table {
|
||||
+ columnChunksLoaded
|
||||
+ ") VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
boolean commitRequired = false;
|
||||
int i = 0;
|
||||
for (TPS tps : batch) {
|
||||
statement.setLong(1, tps.getDate());
|
||||
statement.setDouble(2, tps.getTps());
|
||||
@ -148,13 +158,10 @@ public class TPSTable extends Table {
|
||||
statement.setDouble(6, tps.getEntityCount());
|
||||
statement.setDouble(7, tps.getChunksLoaded());
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
i++;
|
||||
}
|
||||
if (commitRequired) {
|
||||
Log.debug("Executing tps batch: " + i);
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
Log.debug("Executing tps batch: " + batchSize);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
|
@ -680,10 +680,18 @@ public class UsersTable extends Table {
|
||||
try {
|
||||
List<UserData> newUserdata = updateExistingUserData(data);
|
||||
Benchmark.start("Database: Insert new UserInfo multiple");
|
||||
|
||||
List<List<UserData>> batches = DBUtils.splitIntoBatches(newUserdata);
|
||||
for (List<UserData> batch : batches) {
|
||||
insertNewUserData(batch);
|
||||
}
|
||||
|
||||
batches.parallelStream()
|
||||
.forEach(batch -> {
|
||||
try {
|
||||
insertNewUserData(batch);
|
||||
} catch (SQLException e) {
|
||||
Log.toLog("UsersTable.saveUserDataInformationBatch", e);
|
||||
}
|
||||
});
|
||||
|
||||
Benchmark.stop("Database: Insert new UserInfo multiple");
|
||||
} finally {
|
||||
Benchmark.stop("Database: Save UserInfo multiple");
|
||||
@ -691,18 +699,27 @@ public class UsersTable extends Table {
|
||||
}
|
||||
|
||||
private void insertNewUserData(Collection<UserData> data) throws SQLException {
|
||||
if (data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int batchSize = data.size();
|
||||
Log.debug("Preparing insertion of new users... Batch Size: " + batchSize);
|
||||
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = prepareStatement(getInsertStatement());
|
||||
boolean commitRequired = false;
|
||||
int i = 0;
|
||||
|
||||
for (UserData uData : data) {
|
||||
UUID uuid = uData.getUuid();
|
||||
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setString(2, uData.getGeolocation());
|
||||
|
||||
GMTimes gmTimes = uData.getGmTimes();
|
||||
statement.setString(3, gmTimes.getState());
|
||||
statement.setLong(4, gmTimes.getLastStateChange());
|
||||
|
||||
statement.setLong(5, uData.getPlayTime());
|
||||
statement.setInt(6, uData.getLoginTimes());
|
||||
statement.setLong(7, uData.getLastPlayed());
|
||||
@ -713,17 +730,16 @@ public class UsersTable extends Table {
|
||||
statement.setBoolean(12, uData.isBanned());
|
||||
statement.setString(13, uData.getName());
|
||||
statement.setLong(14, uData.getRegistered());
|
||||
|
||||
WorldTimes worldTimes = uData.getWorldTimes();
|
||||
statement.setString(15, worldTimes.getState());
|
||||
statement.setLong(16, worldTimes.getLastStateChange());
|
||||
|
||||
statement.addBatch();
|
||||
commitRequired = true;
|
||||
i++;
|
||||
}
|
||||
if (commitRequired) {
|
||||
Log.debug("Executing session batch: " + i);
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
Log.debug("Executing users batch: " + batchSize);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
close(statement);
|
||||
}
|
||||
|
@ -15,13 +15,16 @@ public class WorldPieCreator {
|
||||
for (Map.Entry<String, Long> world : worldTimes.entrySet()) {
|
||||
arrayBuilder.append("{name:'").append(world.getKey())
|
||||
.append("',y:").append(world.getValue());
|
||||
|
||||
if (i == 1) {
|
||||
arrayBuilder.append(", sliced: true, selected: true");
|
||||
}
|
||||
|
||||
arrayBuilder.append("}");
|
||||
if (i < size - 1) {
|
||||
arrayBuilder.append(",");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
arrayBuilder.append("]");
|
||||
return arrayBuilder.toString();
|
||||
|
@ -6,7 +6,9 @@ import main.java.com.djrapitops.plan.data.KillData;
|
||||
import main.java.com.djrapitops.plan.ui.html.Html;
|
||||
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.comparators.KillDataComparator;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -32,6 +34,10 @@ public class KillsTableCreator {
|
||||
html.append(Html.TABLELINE_3.parse(Html.KILLDATA_NONE.parse(), "", ""));
|
||||
} else {
|
||||
int i = 0;
|
||||
|
||||
killData.sort(new KillDataComparator());
|
||||
Collections.reverse(killData);
|
||||
|
||||
for (KillData kill : killData) {
|
||||
if (i >= 20) {
|
||||
break;
|
||||
|
@ -162,18 +162,19 @@ public class AnalysisUtils {
|
||||
* @return
|
||||
*/
|
||||
public static String getBooleanPercentage(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
|
||||
if (analysisType == AnalysisType.BOOLEAN_PERCENTAGE) {
|
||||
try {
|
||||
List<Boolean> tempList = getCorrectValues(uuids, source)
|
||||
.map(value -> (boolean) value)
|
||||
.collect(Collectors.toList());
|
||||
long count = tempList.stream().filter(value -> value).count();
|
||||
return source.parseContainer(analysisType.getModifier(), (((double) count / tempList.size()) * 100) + "%");
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchFieldError e) {
|
||||
return logPluginDataCausedError(source, e);
|
||||
}
|
||||
if (analysisType != AnalysisType.BOOLEAN_PERCENTAGE) {
|
||||
return source.parseContainer("Err ", "Wrong Analysistype specified: " + analysisType.name());
|
||||
}
|
||||
|
||||
try {
|
||||
List<Boolean> tempList = getCorrectValues(uuids, source)
|
||||
.map(value -> (boolean) value)
|
||||
.collect(Collectors.toList());
|
||||
long count = tempList.stream().filter(value -> value).count();
|
||||
return source.parseContainer(analysisType.getModifier(), (((double) count / tempList.size()) * 100) + "%");
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchFieldError e) {
|
||||
return logPluginDataCausedError(source, e);
|
||||
}
|
||||
return source.parseContainer("Err ", "Wrong Analysistype specified: " + analysisType.name());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,18 +184,19 @@ public class AnalysisUtils {
|
||||
* @return
|
||||
*/
|
||||
public static String getBooleanTotal(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
|
||||
if (analysisType == AnalysisType.BOOLEAN_TOTAL) {
|
||||
try {
|
||||
List<Boolean> tempList = getCorrectValues(uuids, source)
|
||||
.map(value -> (boolean) value)
|
||||
.collect(Collectors.toList());
|
||||
long count = tempList.stream().filter(value -> value).count();
|
||||
return source.parseContainer(analysisType.getModifier(), count + " / " + tempList.size());
|
||||
} catch (Exception e) {
|
||||
return logPluginDataCausedError(source, e);
|
||||
}
|
||||
if (analysisType != AnalysisType.BOOLEAN_TOTAL) {
|
||||
return source.parseContainer("Err ", "Wrong Analysistype specified: " + analysisType.name());
|
||||
}
|
||||
|
||||
try {
|
||||
List<Boolean> tempList = getCorrectValues(uuids, source)
|
||||
.map(value -> (boolean) value)
|
||||
.collect(Collectors.toList());
|
||||
long count = tempList.stream().filter(value -> value).count();
|
||||
return source.parseContainer(analysisType.getModifier(), count + " / " + tempList.size());
|
||||
} catch (Exception e) {
|
||||
return logPluginDataCausedError(source, e);
|
||||
}
|
||||
return source.parseContainer("Err ", "Wrong Analysistype specified: " + analysisType.name());
|
||||
}
|
||||
|
||||
private static String logPluginDataCausedError(PluginData source, Throwable e) {
|
||||
@ -214,6 +216,7 @@ public class AnalysisUtils {
|
||||
public static int getUniqueJoins(Map<UUID, List<SessionData>> sessions, long scale) {
|
||||
long now = MiscUtils.getTime();
|
||||
long nowMinusScale = now - scale;
|
||||
|
||||
Set<UUID> uniqueJoins = new HashSet<>();
|
||||
sessions.forEach((uuid, s) ->
|
||||
s.stream()
|
||||
@ -221,6 +224,7 @@ public class AnalysisUtils {
|
||||
.map(session -> uuid)
|
||||
.forEach(uniqueJoins::add)
|
||||
);
|
||||
|
||||
return uniqueJoins.size();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package main.java.com.djrapitops.plan.utilities.comparators;
|
||||
|
||||
import main.java.com.djrapitops.plan.data.KillData;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
public class KillDataComparator implements Comparator<KillData> {
|
||||
|
||||
@Override
|
||||
public int compare(KillData o1, KillData o2) {
|
||||
return Long.compare(o1.getDate(), o2.getDate());
|
||||
}
|
||||
|
||||
}
|
@ -1,107 +1 @@
|
||||
Player Analytics (Plan) Licence v.1.0.1
|
||||
|
||||
Copyright (C) Risto Lahtela / Rsl1122
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
0. Definitions
|
||||
|
||||
With 'software' this licence refers to the following:
|
||||
Player Analytics (Plan) Bukkit plugin
|
||||
Player Analytics Lite (PlanLite) Bukkit plugin
|
||||
(https://github.com/Rsl1122/Plan-PlayerAnalytics)
|
||||
Player Demographics (Plade) Bukkit plugin
|
||||
(https://github.com/Rsl1122/Plan-Player-Demographics)
|
||||
& the source code of these that is publicly available.
|
||||
|
||||
'visual aspect of software'
|
||||
The messages sent with Bukkit API to Player/Console
|
||||
Html pages & the included styles
|
||||
Images & Videos found on the plugin page
|
||||
|
||||
Additional 'resources'
|
||||
Provided .yml .html .txt and image files inside the software.
|
||||
|
||||
'code modifyer'
|
||||
A person modifying the code/resources of the software.
|
||||
|
||||
'user'
|
||||
A person running the software
|
||||
|
||||
|
||||
1. Use & Distribution
|
||||
|
||||
This licence grants the end user the rights to run the software & modify it to a certain extent. (detailed in section 3. Modification)
|
||||
All versions downloaded from Spigot (https://www.spigotmc.org/resources/authors/rsl1122.122894/) & .jar packages compiled
|
||||
from the source code can be used as a dependency in another project, commercial or not.
|
||||
|
||||
You may not sell the software or modified versions of this software.
|
||||
|
||||
Modified software can only be distributed if ALL of the following conditions apply:
|
||||
a. the original author and the original work are clearly mentioned & linked in the distribution method or when using the software
|
||||
b. Modified software does not contain harmful code to the user.
|
||||
c. Modified software is free & the modified source code is publicly available.
|
||||
d. Modified software is published under this licence
|
||||
e. The end user is provided a copy of this licence
|
||||
|
||||
When distributing a modified copy of the software you grant the right for the original author to post a takedown notice, upon which
|
||||
the modified source code and modified software must be removed from distribution.
|
||||
|
||||
2. Commercial use
|
||||
|
||||
When using parts of the software with 'Minecraft Server software', the use must comply with EULA provided by Mojang (https://help.mojang.com/customer/en/portal/articles/1590522-minecraft-commercial-use)
|
||||
If a project requires end user to obtain a copy of the software, a link must be provided to obtain the software from the author / Spigot.
|
||||
|
||||
|
||||
3. Modification
|
||||
|
||||
The code & resources can be modified & run if the following conditions apply:
|
||||
a. The modified version is used only by the modifyer (Person modifying the resources/software) & not distributed/sold.
|
||||
The modifyer may transfer his right to use the software to another person in following cases:
|
||||
a1: Modifyer was paid to modify part of the software for customization of visual appearance of the software or fix Exceptions & Errors caused
|
||||
by updates to Minecraft Server software.
|
||||
|
||||
|
||||
4. Usage of part of code in another software
|
||||
|
||||
This part (4) of the licence does not include the usage of the API of the plugin,
|
||||
or adding the compiled code as provided dependency. Such use is allowed.
|
||||
|
||||
Usage of a part of code in another software is allowed if following conditions apply:
|
||||
a. The software falls under this licence
|
||||
b. This licence is accepted by the person using the code inside their software
|
||||
c. The use is not a clear copyright infringement
|
||||
OR
|
||||
a. It can be proven that it is possible to come to the same solution independently in a resonable time frame of one hour
|
||||
with no prior access to the software.
|
||||
|
||||
|
||||
5. Revised Versions of this Licence
|
||||
|
||||
The author may publish revised and/or new versions of
|
||||
this License from time to time. Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
6. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
7. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
Moved to https://github.com/Rsl1122/Plan-PlayerAnalytics/edit/master/Plan/src/main/resources/license.yml
|
||||
|
124
Plan/src/main/resources/license.yml
Normal file
124
Plan/src/main/resources/license.yml
Normal file
@ -0,0 +1,124 @@
|
||||
Player Analytics (Plan) License v.2.0.0
|
||||
|
||||
Copyright (C) Risto Lahtela / Rsl1122
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
0. Definitions
|
||||
|
||||
With 'Software' this license refers to the following:
|
||||
Player Analytics (Plan) Bukkit plugin
|
||||
(https://github.com/Rsl1122/Plan-PlayerAnalytics),
|
||||
Modified versions the software
|
||||
& the source code that is publicly available on Plan’s GitHub repository.
|
||||
This does not include the Markdown (.md) files available in the repository.
|
||||
|
||||
‘Java Runtime Environment’
|
||||
A Runtime Environment which allows Java Bytecode to run, mostly Oracle JRE.
|
||||
But this also includes other Runtime Environments like OpenJDK / JRE (http://openjdk.java.net)
|
||||
|
||||
‘Java Virtual Machine’
|
||||
The virtual machine included in the Java Runtime Environment.
|
||||
|
||||
‘GitHub’
|
||||
(https://www.github.com)
|
||||
|
||||
‘Minecraft’
|
||||
A game by Mojang AB (https://www.mojang.com).
|
||||
(https://www.minecraft.net)
|
||||
|
||||
‘Minecraft Server software’
|
||||
The software to operate a server for Minecraft, mostly Bukkit or its forks.
|
||||
Original Minecraft Server independent software like Glowstone (https://www.glowstone.net) are falling under this definition as well.
|
||||
|
||||
‘Plan’s Spigot plugin page’
|
||||
(https://www.spigotmc.org/resources/plan-player-analytics.32536)
|
||||
|
||||
‘Minecraft EULA’
|
||||
(https://help.mojang.com/customer/en/portal/articles/1590522-minecraft-commercial-use)
|
||||
|
||||
‘Plan’s GitHub repository’
|
||||
(https://www.github.com/Rsl1122/Plan-PlayerAnalytics)
|
||||
|
||||
‘Fork’
|
||||
Refers to a copy made of Plan’s GitHub repository which is using the Fork System of GitHub.
|
||||
|
||||
'End User'
|
||||
A person running the software on a Java Virtual Machine environment.
|
||||
|
||||
‘Original Source Code’
|
||||
Refers to the source code that is available on Plan’s GitHub repository.
|
||||
|
||||
‘Original Author’
|
||||
Rsl1122 / Risto Lahtela
|
||||
|
||||
1. Use & Distribution
|
||||
|
||||
|
||||
This license grants the end user the rights to run the software & make modifications to its HTML components, Java Keystore, locale files
|
||||
& configuration files in the scope that the plugin allows without decompiling the .class files inside the jar.
|
||||
|
||||
Distribution and modification of source code is allowed under the circumstances that such code is publicly available, the original
|
||||
author is mentioned & the original author is made aware of the modified code. A fork counts as a notification about modified code.
|
||||
A removal of the Fork display is not allowed under any circumstances except if the original author grants a written permission for
|
||||
this exact action.
|
||||
|
||||
All versions downloaded from the Plan’s Spigot plugin page & .jar packages compiled
|
||||
from the original source code can be used as a dependency and only as a dependency in another project, commercial or not.
|
||||
|
||||
|
||||
You may not distribute or sell modified, or unmodified versions of compiled source code without a direct written permission of
|
||||
the original author.
|
||||
Such permissions are granted separately for Distribution & Selling.
|
||||
|
||||
When distributing a modified, or unmodified copy of the software you grant the right for the original author to post a takedown
|
||||
notice, upon which the modified software must be removed from distribution.
|
||||
If the conditions of the license are breached, the software breaking the license must be removed from distribution.
|
||||
|
||||
2. Commercial use
|
||||
|
||||
When using parts of the software with Minecraft Server software, the use must comply with EULA provided by Mojang.
|
||||
If a project requires the end user to obtain a copy of the software, a link must be provided to obtain the software from the author
|
||||
or Spigot.
|
||||
|
||||
3. Modification
|
||||
|
||||
|
||||
Modification on the code is allowed, as long as the section 1 of this license is not violated.
|
||||
|
||||
4. Usage of part of the code in another program
|
||||
|
||||
This part of the license is about copying code directly from the source code or decompiled .class files.
|
||||
|
||||
Usage of a part of code in another non-commercial program is allowed if following conditions apply:
|
||||
a. The program falls under this license
|
||||
b. This license is accepted by the person using the code inside their program
|
||||
c. The use does not break the conditions of this license
|
||||
d. The use is not a clear copyright infringement
|
||||
OR
|
||||
a. It can be proven that it is possible to come to the same solution independently in a reasonable time frame of one hour with
|
||||
no prior access to the software.
|
||||
OR
|
||||
a. The original author grants written permission for the use.
|
||||
|
||||
5. Revised versions of this License
|
||||
|
||||
The author may publish revised and/or new versions of this License from time to time. Such new versions will be similar in spirit
|
||||
to the old version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
6. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
|
||||
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU.
|
||||
SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
7. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
|
||||
DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE
|
||||
(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE
|
||||
OF THE SOFTWARE TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
@ -235,13 +235,10 @@ public class DatabaseTest {
|
||||
db.saveUserData(data);
|
||||
data.addNickname("TestUpdateForSave");
|
||||
db.saveUserData(data);
|
||||
DBCallableProcessor process = new DBCallableProcessor() {
|
||||
@Override
|
||||
public void process(UserData d) {
|
||||
System.out.println("\nOriginal: " + data);
|
||||
System.out.println("Database: " + d);
|
||||
assertTrue("Not Equals", data.equals(d));
|
||||
}
|
||||
DBCallableProcessor process = d -> {
|
||||
System.out.println("\nOriginal: " + data);
|
||||
System.out.println("Database: " + d);
|
||||
assertTrue("Not Equals", data.equals(d));
|
||||
};
|
||||
db.giveUserDataToProcessors(data.getUuid(), process);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import main.java.com.djrapitops.plan.data.handling.info.InfoType;
|
||||
import main.java.com.djrapitops.plan.database.tables.GMTimesTable;
|
||||
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
|
||||
import main.java.com.djrapitops.plan.utilities.analysis.Point;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -34,8 +35,7 @@ public class RandomData {
|
||||
* Random enough.
|
||||
*/
|
||||
public static String randomString(int size) {
|
||||
String randomString = UUID.randomUUID().toString().replaceAll("-", "").substring(0, size);
|
||||
return randomString;
|
||||
return RandomStringUtils.random(size);
|
||||
}
|
||||
|
||||
public static List<WebUser> randomWebUsers() throws PassEncryptUtil.CannotPerformOperationException {
|
||||
@ -75,7 +75,7 @@ public class RandomData {
|
||||
public static List<HandlingInfo> randomHandlingInfo() {
|
||||
List<HandlingInfo> test = new ArrayList<>();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
test.add(new HandlingInfo(UUID.randomUUID(), InfoType.OTHER, r.nextLong()) {
|
||||
test.add(new HandlingInfo(UUID.randomUUID(), randomEnum(InfoType.class), r.nextLong()) {
|
||||
@Override
|
||||
public boolean process(UserData uData) {
|
||||
return false;
|
||||
@ -85,5 +85,8 @@ public class RandomData {
|
||||
return test;
|
||||
}
|
||||
|
||||
|
||||
public static <T extends Enum> T randomEnum(Class<T> clazz) {
|
||||
int x = r.nextInt(clazz.getEnumConstants().length);
|
||||
return clazz.getEnumConstants()[x];
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ Originally the plugin only displayed data of other plugins, but now it gathers i
|
||||
### Links
|
||||
- [Spigot, Resource page](https://www.spigotmc.org/resources/plan-player-analytics.32536/)
|
||||
- [Issues & Suggestions](https://github.com/Rsl1122/Plan-PlayerAnalytics/issues)
|
||||
- [Licence](https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/licence.yml)
|
||||
- [License](https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml)
|
||||
|
||||
## Documentation
|
||||
- [Javadocs](https://rsl1122.github.io/Plan-PlayerAnalytics/) (OutDated)
|
||||
|
@ -62,7 +62,7 @@ Requirements:
|
||||
- A cloudflare account
|
||||
- A domain with full access
|
||||
|
||||
If you wish to bypass the security warning (not seeing that the connection isn’t private), you can use ![Cloudflare](https://www.cloudflare.com)
|
||||
If you wish to bypass the security warning (not seeing that the connection isn’t private), you can use [Cloudflare](https://www.cloudflare.com)
|
||||
|
||||
- Connect your domain to Cloudflare
|
||||
- Add a DNS record of the type “A” which points to your Server IP
|
||||
@ -70,7 +70,7 @@ If you wish to bypass the security warning (not seeing that the connection isn
|
||||
|
||||
Notes:
|
||||
If you only want to use HTTPS on the Analytics site, you can use the “Page Rules”
|
||||
![Page Rules Tutorial](https://support.cloudflare.com/hc/en-us/articles/218411427-Page-Rules-Tutorial)
|
||||
[Page Rules Tutorial](https://support.cloudflare.com/hc/en-us/articles/218411427-Page-Rules-Tutorial)
|
||||
|
||||
It is recommend to activate “Automatic HTTPS Rewrites” under “Crypto” to be able to use http://LINK.TLD as well.
|
||||
This removes the need to write “https://” at the beginning of the address.
|
||||
|
Loading…
Reference in New Issue
Block a user