Merge pull request #119 from Rsl1122/master

Forgot to sync, pulling update from master
This commit is contained in:
Risto Lahtela 2017-06-05 13:32:59 +03:00 committed by GitHub
commit b22a5ed298
30 changed files with 418 additions and 324 deletions

View File

@ -69,8 +69,8 @@ public enum Phrase {
ANALYSIS_FETCH_DATA(ANALYSIS + "Fetching Data.."),
ANALYSIS_FAIL_NO_PLAYERS(ANALYSIS + "Analysis failed, no known players."),
ANALYSIS_FAIL_NO_DATA(ANALYSIS + "Analysis failed, no data in the database."),
ANALYSIS_BEGIN_ANALYSIS(ANALYSIS + "Data Fetched, beginning Analysis of data.."),
ANALYSIS_COMPLETE(ANALYSIS + "Analysis Complete."),
ANALYSIS_BEGIN_ANALYSIS(ANALYSIS + "Data Fetched (REPLACE0 users, took REPLACE1ms), beginning Analysis of data.."),
ANALYSIS_COMPLETE(ANALYSIS + "Analysis Complete. (took REPLACE0ms) REPLACE1"),
DATA_CORRUPTION_WARN("Some data might be corrupted: " + REPLACE0),
//
ERROR_CONSOLE_PLAYER("This point of code should not be accessable on console. Inform author: " + REPLACE0 + " Console: REPLACE1"),
@ -109,6 +109,10 @@ public enum Phrase {
CMD_MANAGE_HELP_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Managment Help"),
CMD_MANAGE_STATUS_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Database status"),
CMD_MANAGE_STATUS_ACTIVE_DB(CMD_BALL + "" + COLOR_MAIN.color() + " Active Database: " + COLOR_SEC.color() + "REPLACE0"),
CMD_MANAGE_STATUS_QUEUE_SAVE(CMD_BALL + "" + COLOR_MAIN.color() + " Save Queue Size: " + COLOR_SEC.color() + "REPLACE0/"+Settings.PROCESS_SAVE_LIMIT.getNumber()),
CMD_MANAGE_STATUS_QUEUE_GET(CMD_BALL + "" + COLOR_MAIN.color() + " Get Queue Size: " + COLOR_SEC.color() + "REPLACE0/"+Settings.PROCESS_GET_LIMIT.getNumber()),
CMD_MANAGE_STATUS_QUEUE_CLEAR(CMD_BALL + "" + COLOR_MAIN.color() + " Clear Queue Size: " + COLOR_SEC.color() + "REPLACE0/"+Settings.PROCESS_CLEAR_LIMIT.getNumber()),
CMD_MANAGE_STATUS_QUEUE_PROCESS(CMD_BALL + "" + COLOR_MAIN.color() + " Process Queue Size: " + COLOR_SEC.color() + "REPLACE0/20000"),
CMD_CLICK_ME("Click Me"),
CMD_LINK(COLOR_SEC.color() + " " + BALL + COLOR_MAIN.color() + " Link: " + COLOR_TER.color()),
CMD_PASS_PLANLITE("UNUSED"),

View File

@ -63,6 +63,7 @@ public class Plan extends JavaPlugin {
private HashSet<Database> databases;
private WebSocketServer uiServer;
private HookHandler hookHandler;
private ServerVariableHolder variable;
private int bootAnalysisTaskID;
@ -81,7 +82,9 @@ public class Plan extends JavaPlugin {
getDataFolder().mkdirs();
initLocale();
variable = new ServerVariableHolder(this);
databases = new HashSet<>();
databases.add(new MySQLDB(this));
databases.add(new SQLiteDB(this));
@ -132,6 +135,7 @@ public class Plan extends JavaPlugin {
}
hookHandler = new HookHandler();
Log.debug("Verboose debug messages are enabled.");
Log.info(Phrase.ENABLED + "");
}
@ -369,6 +373,10 @@ public class Plan extends JavaPlugin {
Log.info("Using locale: " + usingLocale);
}
public ServerVariableHolder getVariable() {
return variable;
}
/**
* Used to get the current instance of Plan.
*

View File

@ -0,0 +1,20 @@
package main.java.com.djrapitops.plan;
/**
*
* @author Rsl1122
*/
public class ServerVariableHolder {
private int maxPlayers;
public ServerVariableHolder(Plan plugin) {
maxPlayers = plugin.getServer().getMaxPlayers();
}
public int getMaxPlayers() {
return maxPlayers;
}
}

View File

@ -5,7 +5,6 @@ import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.CommandType;
import main.java.com.djrapitops.plan.command.SubCommand;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@ -31,13 +30,17 @@ public class ManageStatusCommand extends SubCommand {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
ChatColor hColor = Phrase.COLOR_TER.color();
String[] messages = new String[]{
Phrase.CMD_MANAGE_STATUS_HEADER + "",
Phrase.CMD_MANAGE_STATUS_ACTIVE_DB.parse(plugin.getDB().getConfigName()),
Phrase.CMD_MANAGE_STATUS_QUEUE_PROCESS.parse("" + plugin.getHandler().getProcessTask().size()),
Phrase.CMD_MANAGE_STATUS_QUEUE_SAVE.parse("" + plugin.getHandler().getSaveTask().size()),
Phrase.CMD_MANAGE_STATUS_QUEUE_GET.parse("" + plugin.getHandler().getGetTask().size()),
Phrase.CMD_MANAGE_STATUS_QUEUE_CLEAR.parse("" + plugin.getHandler().getClearTask().size()),
Phrase.CMD_FOOTER + ""
};
sender.sendMessage(Phrase.CMD_MANAGE_STATUS_HEADER + "");
sender.sendMessage(Phrase.CMD_MANAGE_STATUS_ACTIVE_DB.parse(plugin.getDB().getConfigName()));
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
sender.sendMessage(messages);
return true;
}
}

View File

@ -32,6 +32,10 @@ public class SessionData {
this.sessionEnd = sessionEnd;
}
public SessionData(SessionData s) {
this.sessionStart = s.getSessionStart();
this.sessionEnd = s.getSessionEnd();
}
/**
* Ends the session with given end point.
*

View File

@ -42,22 +42,24 @@ public class AdvancedAchievementsAchievements extends PluginData {
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
if (MiscUtils.getTime()- lastRefresh > 60000) {
if (MiscUtils.getTime() - lastRefresh > 60000) {
totalAchievements = aaAPI.getPlayersTotalAchievements();
}
if (totalAchievements.containsKey(uuid)) {
return parseContainer(modifierPrefix,totalAchievements.get(uuid) + "");
Integer total = totalAchievements.get(uuid);
if (total != null) {
return parseContainer(modifierPrefix, total + "");
}
return parseContainer(modifierPrefix, 0+"");
return parseContainer(modifierPrefix, 0 + "");
}
@Override
public Serializable getValue(UUID uuid) {
if (MiscUtils.getTime()- lastRefresh > 60000) {
if (MiscUtils.getTime() - lastRefresh > 60000) {
totalAchievements = aaAPI.getPlayersTotalAchievements();
}
if (totalAchievements.containsKey(uuid)) {
return totalAchievements.get(uuid);
Integer total = totalAchievements.get(uuid);
if (total != null) {
return total;
}
return -1;
}

View File

@ -3,13 +3,10 @@ package main.java.com.djrapitops.plan.data.additional.advancedachievements;
import com.hm.achievement.api.AdvancedAchievementsAPI;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.ui.Html;

View File

@ -31,7 +31,6 @@ import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import static org.bukkit.Bukkit.getOfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
/**
* This Class contains the Cache.
@ -65,7 +64,6 @@ public class DataCacheHandler extends LocationCache {
// Variables
private int timesSaved;
private int maxPlayers;
/**
* Class Constructor.
@ -84,7 +82,6 @@ public class DataCacheHandler extends LocationCache {
startQueues();
timesSaved = 0;
maxPlayers = plugin.getServer().getMaxPlayers();
commandUse = new HashMap<>();
if (!getCommandUseFromDb()) {
@ -254,7 +251,7 @@ public class DataCacheHandler extends LocationCache {
saveTask.stop();
getTask.stop();
clearTask.stop();
List<HandlingInfo> toProcess = processTask.stop();
List<HandlingInfo> toProcess = processTask.stopAndReturnLeftovers();
Benchmark.start("ProcessOnlineHandlingInfo");
Log.debug("ToProcess size: " + toProcess.size() + " DataCache size: " + dataCache.keySet().size());
Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
@ -338,7 +335,7 @@ public class DataCacheHandler extends LocationCache {
*/
public void saveCommandUse() {
try {
db.saveCommandUse(commandUse);
db.saveCommandUse(new HashMap<>(commandUse));
} catch (SQLException | NullPointerException e) {
Log.toLog(this.getClass().getName(), e);
}
@ -348,15 +345,23 @@ public class DataCacheHandler extends LocationCache {
* Refreshes the calculations for all online players with ReloadInfo.
*/
public void saveHandlerDataToCache() {
Bukkit.getServer().getOnlinePlayers().parallelStream().forEach((p) -> {
saveHandlerDataToCache(p);
Bukkit.getServer().getOnlinePlayers().stream().forEach((p) -> {
saveHandlerDataToCache(p, false);
});
}
private void saveHandlerDataToCache(Player player) {
private void saveHandlerDataToCache(Player player, boolean pool) {
long time = MiscUtils.getTime();
UUID uuid = player.getUniqueId();
addToPool(new ReloadInfo(uuid, time, player.getAddress().getAddress(), player.isBanned(), player.getDisplayName(), player.getGameMode()));
ReloadInfo info = new ReloadInfo(uuid, time, player.getAddress().getAddress(), player.isBanned(), player.getDisplayName(), player.getGameMode());
if (!pool) {
UserData data = dataCache.get(uuid);
if (data != null) {
info.process(data);
return;
}
}
addToPool(info);
}
/**
@ -475,22 +480,13 @@ public class DataCacheHandler extends LocationCache {
newPlayer(player);
}
startSession(uuid);
saveHandlerDataToCache(player);
saveHandlerDataToCache(player, true);
}
this.cancel();
}
}).runTaskAsynchronously(plugin);
}
/**
* Used by Analysis for Player activity graphs.
*
* @return Maximum number of players defined in server.properties.
*/
public int getMaxPlayers() {
return maxPlayers;
}
/**
* Used to handle a command's execution.
*
@ -502,4 +498,20 @@ public class DataCacheHandler extends LocationCache {
}
commandUse.put(command, commandUse.get(command) + 1);
}
public DataCacheSaveQueue getSaveTask() {
return saveTask;
}
public DataCacheClearQueue getClearTask() {
return clearTask;
}
public DataCacheProcessQueue getProcessTask() {
return processTask;
}
public DataCacheGetQueue getGetTask() {
return getTask;
}
}

View File

@ -1,5 +1,6 @@
package main.java.com.djrapitops.plan.data.cache;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
@ -13,6 +14,7 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.ExportUtility;
/**
* This class stores UserData objects used for displaying the Html pages.
@ -53,6 +55,11 @@ public class InspectCacheHandler {
public void process(UserData data) {
cache.put(uuid, new UserData(data));
cacheTimes.put(uuid, MiscUtils.getTime());
try {
ExportUtility.writeInspectHtml(data, ExportUtility.getPlayersFolder(ExportUtility.getFolder()));
} catch (IOException ex) {
Log.toLog(this.getClass().getName(), ex);
}
}
};
handler.getUserDataForProcessing(cacher, uuid, false);
@ -81,7 +88,7 @@ public class InspectCacheHandler {
long time = MiscUtils.getTime();
for (UserData uData : userDataForUUIDS) {
UUID uuid = uData.getUuid();
cache.put(uuid, uData);
cache.put(uuid, new UserData(uData));
cacheTimes.put(uuid, time);
}
}

View File

@ -0,0 +1,43 @@
package main.java.com.djrapitops.plan.data.cache.queue;
import java.util.concurrent.BlockingQueue;
/**
* Abstract class representing a queue consumer.
*
* @author Rsl1122
* @param <T>
*/
public abstract class Consumer<T> implements Runnable {
boolean run;
final BlockingQueue<T> queue;
/**
* Constructor, defines queue.
*
* @param queue Queue to consume from.
*/
public Consumer(BlockingQueue<T> queue) {
this.queue = queue;
run = true;
}
@Override
public void run() {
try {
while (run) {
consume(queue.take());
}
} catch (InterruptedException ex) {
}
}
void stop() {
run = false;
}
abstract void clearVariables();
abstract void consume(T toConsume);
}

View File

@ -15,10 +15,7 @@ import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
* @author Rsl1122
* @since 3.0.0
*/
public class DataCacheClearQueue {
private BlockingQueue<UUID> q;
private ClearSetup s;
public class DataCacheClearQueue extends Queue<UUID>{
/**
* Class constructor, starts the new Thread for clearing.
@ -26,9 +23,9 @@ public class DataCacheClearQueue {
* @param handler current instance of DataCachehandler.
*/
public DataCacheClearQueue(DataCacheHandler handler) {
q = new ArrayBlockingQueue(Settings.PROCESS_CLEAR_LIMIT.getNumber());
s = new ClearSetup();
s.go(q, handler);
super(new ArrayBlockingQueue(Settings.PROCESS_CLEAR_LIMIT.getNumber()));
setup = new ClearSetup(queue, handler);
setup.go();
}
/**
@ -38,7 +35,7 @@ public class DataCacheClearQueue {
*/
public void scheduleForClear(UUID uuid) {
Log.debug(uuid + ": Scheduling for clear");
q.add(uuid);
queue.add(uuid);
}
/**
@ -52,46 +49,23 @@ public class DataCacheClearQueue {
}
Log.debug("Scheduling for clear: " + uuids);
try {
q.addAll(uuids);
queue.addAll(uuids);
} catch (IllegalStateException e) {
Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Clear Queue", Settings.PROCESS_CLEAR_LIMIT.getNumber() + ""));
}
}
/**
* Stops all activity and clears the queue.
*/
public void stop() {
if (s != null) {
s.stop();
}
s = null;
q.clear();
}
}
class ClearConsumer implements Runnable {
class ClearConsumer extends Consumer<UUID> implements Runnable {
private final BlockingQueue<UUID> queue;
private DataCacheHandler handler;
private boolean run;
ClearConsumer(BlockingQueue q, DataCacheHandler handler) {
queue = q;
super(q);
this.handler = handler;
run = true;
}
@Override
public void run() {
try {
while (run) {
consume(queue.take());
}
} catch (InterruptedException ex) {
}
}
void consume(UUID uuid) {
if (handler == null) {
return;
@ -108,24 +82,16 @@ class ClearConsumer implements Runnable {
}
}
void stop() {
run = false;
@Override
void clearVariables() {
if (handler != null) {
handler = null;
}
}
}
class ClearSetup {
private ClearConsumer one;
void go(BlockingQueue<UUID> q, DataCacheHandler handler) {
one = new ClearConsumer(q, handler);
new Thread(one).start();
}
void stop() {
one.stop();
class ClearSetup extends Setup<UUID> {
public ClearSetup(BlockingQueue<UUID> q, DataCacheHandler handler) {
super(new ClearConsumer(q, handler));
}
}

View File

@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
@ -21,10 +22,7 @@ import main.java.com.djrapitops.plan.database.Database;
* @author Rsl1122
* @since 3.0.0
*/
public class DataCacheGetQueue {
private BlockingQueue<HashMap<UUID, List<DBCallableProcessor>>> q;
private GetSetup s;
public class DataCacheGetQueue extends Queue<Map<UUID, List<DBCallableProcessor>>> {
/**
* Class constructor, starts the new Thread for fetching.
@ -32,9 +30,9 @@ public class DataCacheGetQueue {
* @param plugin current instance of Plan
*/
public DataCacheGetQueue(Plan plugin) {
q = new ArrayBlockingQueue(Settings.PROCESS_GET_LIMIT.getNumber());
s = new GetSetup();
s.go(q, plugin.getDB());
super(new ArrayBlockingQueue(Settings.PROCESS_GET_LIMIT.getNumber()));
setup = new GetSetup(queue, plugin.getDB());
setup.go();
}
/**
@ -47,52 +45,29 @@ public class DataCacheGetQueue {
public void scheduleForGet(UUID uuid, DBCallableProcessor... processors) {
Log.debug(uuid + ": Scheduling for get");
try {
HashMap<UUID, List<DBCallableProcessor>> map = new HashMap<>();
Map<UUID, List<DBCallableProcessor>> map = new HashMap<>();
if (map.get(uuid) == null) {
map.put(uuid, new ArrayList<>());
}
map.get(uuid).addAll(Arrays.asList(processors));
q.add(map);
queue.add(map);
} catch (IllegalStateException e) {
Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Get Queue", Settings.PROCESS_GET_LIMIT.getNumber() + ""));
}
}
/**
* Stops the activities and clears the queue.
*/
public void stop() {
if (s != null) {
s.stop();
}
s = null;
q.clear();
}
}
class GetConsumer implements Runnable {
class GetConsumer extends Consumer<Map<UUID, List<DBCallableProcessor>>> {
private final BlockingQueue<HashMap<UUID, List<DBCallableProcessor>>> queue;
private Database db;
private boolean run;
GetConsumer(BlockingQueue q, Database db) {
queue = q;
super(q);
this.db = db;
run = true;
}
@Override
public void run() {
try {
while (run) {
consume(queue.take());
}
} catch (InterruptedException ex) {
}
}
void consume(HashMap<UUID, List<DBCallableProcessor>> processors) {
void consume(Map<UUID, List<DBCallableProcessor>> processors) {
if (db == null) {
return;
}
@ -116,28 +91,17 @@ class GetConsumer implements Runnable {
}
}
void stop() {
run = false;
@Override
void clearVariables() {
if (db != null) {
db = null;
}
}
}
class GetSetup {
class GetSetup extends Setup<Map<UUID, List<DBCallableProcessor>>> {
private GetConsumer one;
private GetConsumer two;
void go(BlockingQueue<HashMap<UUID, List<DBCallableProcessor>>> q, Database db) {
one = new GetConsumer(q, db);
two = new GetConsumer(q, db);
new Thread(one).start();
new Thread(two).start();
}
void stop() {
one.stop();
two.stop();
GetSetup(BlockingQueue<Map<UUID, List<DBCallableProcessor>>> q, Database db) {
super(new GetConsumer(q, db), new GetConsumer(q, db));
}
}

View File

@ -20,10 +20,7 @@ import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo;
* @author Rsl1122
* @since 3.0.0
*/
public class DataCacheProcessQueue {
private BlockingQueue<HandlingInfo> queue;
private ProcessSetup setup;
public class DataCacheProcessQueue extends Queue<HandlingInfo> {
/**
* Class constructor, starts the new Thread for processing.
@ -31,9 +28,9 @@ public class DataCacheProcessQueue {
* @param handler current instance of DataCachehandler.
*/
public DataCacheProcessQueue(DataCacheHandler handler) {
queue = new ArrayBlockingQueue(20000);
setup = new ProcessSetup();
setup.go(queue, handler);
super(new ArrayBlockingQueue(20000));
setup = new ProcessSetup(queue, handler);
setup.go();
}
/**
@ -72,48 +69,18 @@ public class DataCacheProcessQueue {
public boolean containsUUID(UUID uuid) {
return new ArrayList<>(queue).stream().map(d -> d.getUuid()).collect(Collectors.toList()).contains(uuid);
}
/**
* Stops all activites and clears the queue.
*
* @return unprocessed HandlingInfo objects.
*/
public List<HandlingInfo> stop() {
try {
if (setup != null) {
setup.stop();
return new ArrayList<>(queue);
}
return new ArrayList<>();
} finally {
setup = null;
queue.clear();
}
}
}
class ProcessConsumer implements Runnable {
class ProcessConsumer extends Consumer<HandlingInfo> {
private final BlockingQueue<HandlingInfo> queue;
private DataCacheHandler handler;
private boolean run;
ProcessConsumer(BlockingQueue q, DataCacheHandler h) {
super(q);
handler = h;
queue = q;
run = true;
}
@Override
public void run() {
try {
while (run) {
consume(queue.take());
}
} catch (InterruptedException ex) {
}
}
void consume(HandlingInfo info) {
if (handler == null) {
return;
@ -130,28 +97,16 @@ class ProcessConsumer implements Runnable {
handler.getUserDataForProcessing(p, info.getUuid());
}
void stop() {
run = false;
@Override
void clearVariables() {
if (handler != null) {
handler = null;
}
}
}
class ProcessSetup {
private ProcessConsumer one;
private ProcessConsumer two;
void go(BlockingQueue<HandlingInfo> q, DataCacheHandler h) {
one = new ProcessConsumer(q, h);
two = new ProcessConsumer(q, h);
new Thread(one).start();
new Thread(two).start();
}
void stop() {
one.stop();
two.stop();
class ProcessSetup extends Setup<HandlingInfo> {
ProcessSetup(BlockingQueue<HandlingInfo> q, DataCacheHandler h) {
super(new ProcessConsumer(q, h), new ProcessConsumer(q, h));
}
}

View File

@ -20,10 +20,7 @@ import main.java.com.djrapitops.plan.database.Database;
* @author Rsl1122
* @since 3.0.0
*/
public class DataCacheSaveQueue {
private BlockingQueue<UserData> q;
private SaveSetup s;
public class DataCacheSaveQueue extends Queue<UserData>{
/**
* Class constructor, starts the new Thread for saving.
@ -33,9 +30,9 @@ public class DataCacheSaveQueue {
* UserData.clearAfterSave() is true
*/
public DataCacheSaveQueue(Plan plugin, DataCacheClearQueue clear) {
q = new ArrayBlockingQueue(Settings.PROCESS_SAVE_LIMIT.getNumber());
s = new SaveSetup();
s.go(q, clear, plugin.getDB());
super(new ArrayBlockingQueue(Settings.PROCESS_SAVE_LIMIT.getNumber()));
setup = new SaveSetup(queue, clear, plugin.getDB());
setup.go();
}
/**
@ -46,7 +43,7 @@ public class DataCacheSaveQueue {
public void scheduleForSave(UserData data) {
Log.debug(data.getUuid() + ": Scheduling for save");
try {
q.add(data);
queue.add(data);
} catch (IllegalStateException e) {
Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Save Queue", Settings.PROCESS_SAVE_LIMIT.getNumber() + ""));
}
@ -60,7 +57,7 @@ public class DataCacheSaveQueue {
public void scheduleForSave(Collection<UserData> data) {
Log.debug("Scheduling for save: " + data.stream().map(u -> u.getUuid()).collect(Collectors.toList()));
try {
q.addAll(data);
queue.addAll(data);
} catch (IllegalStateException e) {
Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Save Queue", Settings.PROCESS_SAVE_LIMIT.getNumber() + ""));
}
@ -74,7 +71,7 @@ public class DataCacheSaveQueue {
public void scheduleNewPlayer(UserData data) {
Log.debug(data.getUuid() + ": Scheduling new Player");
try {
q.add(data);
queue.add(data);
} catch (IllegalStateException e) {
Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Save Queue", Settings.PROCESS_SAVE_LIMIT.getNumber() + ""));
}
@ -87,45 +84,23 @@ public class DataCacheSaveQueue {
* @return true/false
*/
public boolean containsUUID(UUID uuid) {
return new ArrayList<>(q).stream().map(d -> d.getUuid()).collect(Collectors.toList()).contains(uuid);
}
/**
* Stops all activites and clears the queue.
*/
public void stop() {
if (s != null) {
s.stop();
}
s = null;
q.clear();
return new ArrayList<>(queue).stream().map(d -> d.getUuid()).collect(Collectors.toList()).contains(uuid);
}
}
class SaveConsumer implements Runnable {
class SaveConsumer extends Consumer<UserData> {
private final BlockingQueue<UserData> queue;
private Database db;
private DataCacheClearQueue clear;
private boolean run;
SaveConsumer(BlockingQueue q, DataCacheClearQueue clear, Database db) {
queue = q;
super(q);
this.db = db;
this.clear = clear;
run = true;
}
@Override
public void run() {
try {
while (run) {
consume(queue.take());
}
} catch (InterruptedException ex) {
}
}
void consume(UserData data) {
if (db == null) {
return;
@ -147,8 +122,8 @@ class SaveConsumer implements Runnable {
}
}
void stop() {
run = false;
@Override
void clearVariables() {
if (db != null) {
db = null;
}
@ -158,20 +133,8 @@ class SaveConsumer implements Runnable {
}
}
class SaveSetup {
private SaveConsumer one;
private SaveConsumer two;
void go(BlockingQueue<UserData> q, DataCacheClearQueue clear, Database db) {
one = new SaveConsumer(q, clear, db);
two = new SaveConsumer(q, clear, db);
new Thread(one).start();
new Thread(two).start();
}
void stop() {
one.stop();
two.stop();
class SaveSetup extends Setup<UserData>{
SaveSetup(BlockingQueue<UserData> q, DataCacheClearQueue clear, Database db) {
super(new SaveConsumer(q, clear, db), new SaveConsumer(q, clear, db));
}
}

View File

@ -0,0 +1,72 @@
package main.java.com.djrapitops.plan.data.cache.queue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
/**
* Abstract implementation of a Queue.
*
* @author Rsl1122
* @param <T> Object this queue consumes
*/
public abstract class Queue<T> {
final BlockingQueue<T> queue;
Setup<T> setup;
/**
* Consturctor, defines queue.
*
* @param queue BlockingQueue to use for this queue.
*/
public Queue(BlockingQueue<T> queue) {
this.queue = queue;
}
/**
* Add a object to the queue, default implementation.
*
* @param object Object to add.
*/
public void add(T object) {
queue.add(object);
}
/**
* Used to stop the queue processing & get the unprocessed objects.
*
* @return List of unprocessed objects.
*/
public List<T> stopAndReturnLeftovers() {
try {
if (setup != null) {
setup.stop();
return new ArrayList<>(queue);
}
return new ArrayList<>();
} finally {
stop();
}
}
/**
* Stops all activity and clears the queue.
*/
public void stop() {
if (setup != null) {
setup.stop();
}
setup = null;
queue.clear();
}
/**
* Get how many objects are in the queue.
*
* @return size of the queue.
*/
public int size() {
return queue.size();
}
}

View File

@ -0,0 +1,33 @@
package main.java.com.djrapitops.plan.data.cache.queue;
/**
* Abstract representation of a queue setup.
*
* @author Rsl1122
* @param <T> Object this queue consumes.
*/
public abstract class Setup<T> {
private Consumer<T>[] consumers;
/**
* Constructor, defines consumers.
*
* @param consumers Consumers for the new threads.
*/
public Setup(Consumer<T>... consumers) {
this.consumers = consumers;
}
void go() {
for (Consumer<T> consumer : consumers) {
new Thread(consumer).start();
}
}
void stop() {
for (Consumer<T> consumer : consumers) {
consumer.stop();
}
}
}

View File

@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.SessionData;
import main.java.com.djrapitops.plan.utilities.Benchmark;
@ -27,10 +28,9 @@ public class PlayerActivityGraphCreator {
*
* @param sessionData
* @param scale
* @param maxPlayers
* @return
*/
public static String[] generateDataArray(List<SessionData> sessionData, long scale, int maxPlayers) {
public static String[] generateDataArray(List<SessionData> sessionData, long scale) {
Benchmark.start("Generate Player Activity Graph " + sessionData.size() + " " + scale + " |");
long now = new Date().toInstant().getEpochSecond() * (long) 1000;
long nowMinusScale = now - scale;
@ -75,17 +75,12 @@ public class PlayerActivityGraphCreator {
for (int i = 0; i < playersOnline.size(); i++) {
long value = playersOnline.get(i);
if (value - average > 3 * standardDiviation) {
playersOnline.set(i, (long) maxPlayers + 10);
playersOnline.set(i, (long) Plan.getInstance().getVariable().getMaxPlayers() + 10);
}
}
}
}
Benchmark.stop("Player Activity Graph Amount Calculation");
playersOnline.add(0L);
playersOnline.add(0L);
playersOnline.add(0L);
playersOnline.add(0L);
playersOnline.add((long) maxPlayers);
Benchmark.stop("Generate Player Activity Graph " + sessionData.size() + " " + scale + " |");
return new String[]{playersOnline.toString(), labels.toString()};
}
@ -142,7 +137,7 @@ public class PlayerActivityGraphCreator {
public static List<List<Long>> filterAndTransformSessions(List<SessionData> sessionData, long nowMinusScale) {
List<Long[]> values = sessionData.parallelStream()
.filter(session -> (session != null))
.filter(session -> session.isValid())
.filter(session -> session.isValid() || session.getSessionEnd() == -1)
.filter((session) -> (session.getSessionStart() >= nowMinusScale || session.getSessionEnd() >= nowMinusScale))
.map(session -> new Long[]{session.getSessionStart(), session.getSessionEnd()})
.collect(Collectors.toList());
@ -150,7 +145,10 @@ public class PlayerActivityGraphCreator {
List<Long> sessionEnds = new ArrayList<>();
for (Long[] startAndEnd : values) {
sessionStarts.add(getSecond(startAndEnd[0]));
sessionEnds.add(getSecond(startAndEnd[1]));
Long end = startAndEnd[1];
if (end != -1) {
sessionEnds.add(getSecond(end));
}
}
List<List<Long>> r = new ArrayList<>();
r.add(sessionStarts);

View File

@ -41,10 +41,10 @@ public class PunchCardGraphCreator {
private static StringBuilder buildString(int[][] scaled) {
StringBuilder arrayBuilder = new StringBuilder();
arrayBuilder.append("[");
arrayBuilder.append("{").append("x:").append(-1).append(", y:").append(-1).append(", r:").append(1).append("}");
arrayBuilder.append(",");
arrayBuilder.append("{").append("x:").append(25).append(", y:").append(7).append(", r:").append(1).append("}");
arrayBuilder.append(",");
// arrayBuilder.append("{").append("x:").append(-1).append(", y:").append(-1).append(", r:").append(1).append("}");
// arrayBuilder.append(",");
// arrayBuilder.append("{").append("x:").append(25).append(", y:").append(7).append(", r:").append(1).append("}");
// arrayBuilder.append(",");
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 24; j++) {
int value = scaled[i][j];
@ -68,9 +68,6 @@ public class PunchCardGraphCreator {
int h = dAndH[1];
dataArray[d][h] = dataArray[d][h] + 1;
}
for (int i = 0; i < 7; i++) {
Log.debug(" " + Arrays.toString(dataArray[i]));
}
if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) {
int avg = findAverage(dataArray);
double standardDiviation = getStandardDiviation(dataArray, avg);
@ -84,9 +81,6 @@ public class PunchCardGraphCreator {
}
}
}
for (int i = 0; i < 7; i++) {
Log.debug(" " + Arrays.toString(dataArray[i]));
}
}
}
return dataArray;
@ -167,10 +161,7 @@ public class PunchCardGraphCreator {
scaled[i][j] = value;
}
}
Log.debug("Biggest value: " + big);
for (int i = 0; i < 7; i++) {
Log.debug(" " + Arrays.toString(scaled[i]));
}
Log.debug("Punchcard Biggest value: " + big);
return scaled;
}
}

View File

@ -39,9 +39,9 @@ public class SessionLengthDistributionGraphCreator {
*/
public static String[] generateDataArray(Collection<Long> lengths) {
Map<Long, Integer> values = getValues(lengths);
Map<Long, Integer> scaled = scale(values);
StringBuilder arrayBuilder = buildString(scaled);
StringBuilder labelBuilder = buildLabels(scaled);
// Map<Long, Integer> scaled = scale(values);
StringBuilder arrayBuilder = buildString(values);
StringBuilder labelBuilder = buildLabels(values);
return new String[]{arrayBuilder.toString(), labelBuilder.toString()};
}

View File

@ -130,6 +130,7 @@ public class PlaceholderUtils {
replaceMap.put("#" + defaultCols[i], "#" + colors[i]);
}
}
replaceMap.put("%graphmaxplayers%", plugin.getVariable().getMaxPlayers()+"");
replaceMap.put("%refreshlong%", data.getRefreshDate()+"");
replaceMap.put("%servername%", Settings.SERVER_NAME.toString());
Benchmark.stop("Replace Placeholders Anaysis");
@ -205,7 +206,8 @@ public class PlaceholderUtils {
Plan plugin = Plan.getInstance();
replaceMap.put("%version%", plugin.getDescription().getVersion());
replaceMap.put("%planlite%", "");
String[] playersDataArray = PlayerActivityGraphCreator.generateDataArray(data.getSessions(), (long) 604800 * 1000, 2);
String[] playersDataArray = PlayerActivityGraphCreator.generateDataArray(data.getSessions(), (long) 604800 * 1000);
replaceMap.put("%graphmaxplayers%", 2+"");
replaceMap.put("%dataweek%", playersDataArray[0]);
replaceMap.put("%labelsweek%", playersDataArray[1]);
replaceMap.put("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL + "");

View File

@ -10,7 +10,6 @@ import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.Gender;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.DemographicsData;
import main.java.com.djrapitops.plan.data.KillData;
@ -21,6 +20,7 @@ import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler;
import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
import main.java.com.djrapitops.plan.data.cache.InspectCacheHandler;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.ui.Html;
@ -100,7 +100,7 @@ public class Analysis {
Log.info(Phrase.ANALYSIS_FAIL_NO_DATA + "");
return false;
}
Benchmark.stop("Analysis Fetch Phase");
;
return analyzeData(rawData, analysisCache);
}
@ -116,11 +116,21 @@ public class Analysis {
List<UUID> uuids = rawData.stream().map(d -> d.getUuid()).collect(Collectors.toList());
Benchmark.stop("Analysis UUID transform");
Benchmark.start("Analysis Create Empty dataset");
Map<String, Integer> commandUse = plugin.getHandler().getCommandUse();
DataCacheHandler handler = plugin.getHandler();
Map<UUID, SessionData> activeSessions = handler.getActiveSessions();
long now = MiscUtils.getTime();
rawData.stream().forEach((data) -> {
SessionData session = activeSessions.get(data.getUuid());
List<SessionData> sessions = data.getSessions();
if (session != null && !sessions.contains(session)) {
sessions.add(session);
}
});
Map<String, Integer> commandUse = handler.getCommandUse();
AnalysisData analysisData = new AnalysisData();
Benchmark.stop("Analysis Create Empty dataset");
log(Phrase.ANALYSIS_BEGIN_ANALYSIS + "");
log(Phrase.ANALYSIS_BEGIN_ANALYSIS.parse(rawData.size() + "", Benchmark.stop("Analysis Fetch Phase") + ""));
String playersTable = SortablePlayersTableCreator.createSortablePlayersTable(rawData);
analysisData.setSortablePlayersTable(playersTable);
@ -151,14 +161,13 @@ public class Analysis {
analysisData.setAdditionalDataReplaceMap(analyzeAdditionalPluginData(uuids));
analysisCache.cache(analysisData);
Benchmark.stop("Analysis");
long time = Benchmark.stop("Analysis");
if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) {
Log.info(Phrase.ANALYSIS_COMPLETE + "");
}
// LocationAnalysis.performAnalysis(analysisData, plugin.getDB());
if (Settings.ANALYSIS_EXPORT.isTrue()) {
ExportUtility.export(plugin, analysisData, rawData);
Log.info(Phrase.ANALYSIS_COMPLETE.parse(time + "", HtmlUtils.getServerAnalysisUrl()));
}
// LocationAnalysis.performAnalysis(analysisData, plugin.getDB());
ExportUtility.export(plugin, analysisData, rawData);
return true;
}
@ -292,7 +301,6 @@ public class Analysis {
long scaleDay = 86400 * 1000;
long scaleWeek = 604800 * 1000;
long scaleMonth = (long) 2592000 * (long) 1000;
int maxPlayers = plugin.getHandler().getMaxPlayers();
data.setNewPlayersDay(AnalysisUtils.getNewPlayers(registered, scaleDay, now));
data.setNewPlayersWeek(AnalysisUtils.getNewPlayers(registered, scaleWeek, now));
@ -304,22 +312,22 @@ public class Analysis {
data.setAvgUniqJoinsWeek(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, scaleWeek));
data.setAvgUniqJoinsMonth(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, scaleMonth));
Benchmark.stop("Analysis Unique/day");
Benchmark.start("Analysis Unique");
data.setUniqueJoinsDay(AnalysisUtils.getUniqueJoins(sortedSData, scaleDay));
data.setUniqueJoinsWeek(AnalysisUtils.getUniqueJoins(sortedSData, scaleWeek));
data.setUniqueJoinsMonth(AnalysisUtils.getUniqueJoins(sortedSData, scaleMonth));
Benchmark.stop("Analysis Unique");
List<SessionData> sessions = sData.stream()
.filter(session -> (session != null))
.filter(session -> session.isValid())
.filter((session) -> (session.getSessionStart() >= now - scaleMonth || session.getSessionEnd() >= now - scaleMonth))
.collect(Collectors.toList());
String[] dayArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleDay, maxPlayers);
String[] weekArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleWeek, maxPlayers);
String[] monthArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleMonth, maxPlayers);
String[] dayArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleDay);
String[] weekArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleWeek);
String[] monthArray = PlayerActivityGraphCreator.generateDataArray(sessions, scaleMonth);
data.setPlayersDataArray(new String[]{dayArray[0], dayArray[1], weekArray[0], weekArray[1], monthArray[0], monthArray[1]});
}

View File

@ -11,15 +11,11 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.ui.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer;
import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.PlaceholderUtils;
@ -31,7 +27,7 @@ import main.java.com.djrapitops.plan.utilities.PlaceholderUtils;
*/
public class ExportUtility {
private static File getFolder() throws IOException {
public static File getFolder() throws IOException {
String path = Settings.ANALYSIS_EXPORT_PATH.toString();
if (path.contains(":")) {
File folder = new File(path);
@ -50,12 +46,14 @@ public class ExportUtility {
}
public static void export(Plan plugin, AnalysisData analysisData, List<UserData> rawData) {
if (!Settings.ANALYSIS_EXPORT.isTrue()) {
return;
}
Benchmark.start("Exporting Html pages");
try {
File folder = getFolder();
writeAnalysisHtml(analysisData, folder);
File playersFolder = new File(folder, "player");
playersFolder.mkdirs();
File playersFolder = getPlayersFolder(folder);
for (UserData userData : rawData) {
writeInspectHtml(userData, playersFolder);
}
@ -66,7 +64,16 @@ public class ExportUtility {
}
}
private static void writeInspectHtml(UserData userData, File playersFolder) throws FileNotFoundException, IOException {
public static File getPlayersFolder(File folder) {
File playersFolder = new File(folder, "player");
playersFolder.mkdirs();
return playersFolder;
}
public static void writeInspectHtml(UserData userData, File playersFolder) throws FileNotFoundException, IOException {
if (!Settings.ANALYSIS_EXPORT.isTrue()) {
return;
}
String inspectHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getHtmlStringFromResource("player.html"),
PlaceholderUtils.getInspectReplaceRules(userData));
File playerFolder = new File(playersFolder, userData.getName());
@ -78,7 +85,10 @@ public class ExportUtility {
Files.write(inspectHtmlFile.toPath(), Arrays.asList(inspectHtml));
}
private static void writeAnalysisHtml(AnalysisData analysisData, File folder) throws FileNotFoundException, IOException {
public static void writeAnalysisHtml(AnalysisData analysisData, File folder) throws FileNotFoundException, IOException {
if (!Settings.ANALYSIS_EXPORT.isTrue()) {
return;
}
String analysisHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getHtmlStringFromResource("analysis.html"),
PlaceholderUtils.getAnalysisReplaceRules(analysisData))
.replace(HtmlUtils.getInspectUrl(""), "./player/");

View File

@ -630,6 +630,7 @@ header p {
</div>
</div>
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
<p>If the graph contains more sessions than login times, likely cause is use of /reload (Restarts sessions).</p>
</div>
</div>
<!--<div class="columns">
@ -1028,6 +1029,12 @@ function countUpTimer() {
data: dataday,
options: {
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMax: %graphmaxplayers%
}
}],
xAxes: [{
display: false
}]
@ -1039,6 +1046,12 @@ function countUpTimer() {
data: dataday,
options: {
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMax: %graphmaxplayers%
}
}],
xAxes: [{
display: false
}]
@ -1050,6 +1063,12 @@ function countUpTimer() {
data: dataweek,
options: {
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMax: %graphmaxplayers%
}
}],
xAxes: [{
display: false
}]
@ -1061,6 +1080,12 @@ function countUpTimer() {
data: datamonth,
options: {
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMax: %graphmaxplayers%
}
}],
xAxes: [{
display: false
}]
@ -1130,14 +1155,18 @@ function countUpTimer() {
ticks: {
callback: function(value, index, values) {
return hour(value);
}
},
suggestedMax: 25,
suggestedMin: -1
}
}],
yAxes: [{
ticks: {
callback: function(value, index, values) {
return day(value);
}
},
suggestedMax: 7,
suggestedMin: -1
}
}]
}
@ -1178,7 +1207,7 @@ function countUpTimer() {
tooltips: {
callbacks: {
label: function(tooltipItems, data) {
return tooltipItems.xLabel+'utes: '+tooltipItems.yLabel+'%';
return tooltipItems.xLabel+'utes: '+tooltipItems.yLabel+' sessions';
}
}
},
@ -1186,7 +1215,7 @@ function countUpTimer() {
yAxes: [{
ticks: {
callback: function(value, index, values) {
return value+'%';
return value+'';
}
}
}]

View File

@ -14,9 +14,9 @@ Settings:
DestinationFolder: 'Analysis Results'
Cache:
Processing:
GetLimit: 2000
SaveLimit: 1000
ClearLimit: 1000
GetLimit: 5000
SaveLimit: 2500
ClearLimit: 2500
AnalysisCache:
RefreshAnalysisCacheOnEnable: true
RefreshEveryXMinutes: -1

View File

@ -539,7 +539,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
</div>
<p>If the graph contains more sessions than login times, likely cause is use of /reload (Restarts sessions).</p>
</div>
</div>
</div>
<div class="tab" style="display: block;">
@ -730,6 +731,12 @@ function countUpTimer() {
data: dataweek,
options: {
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMax: %graphmaxplayers%
}
}],
xAxes: [{
display: false
}]
@ -795,14 +802,18 @@ function countUpTimer() {
ticks: {
callback: function(value, index, values) {
return hour(value);
}
},
suggestedMax: 25,
suggestedMin: -1
}
}],
yAxes: [{
ticks: {
callback: function(value, index, values) {
return day(value);
}
},
suggestedMax: 7,
suggestedMin: -1
}
}]
}
@ -841,7 +852,7 @@ function countUpTimer() {
tooltips: {
callbacks: {
label: function(tooltipItems, data) {
return tooltipItems.xLabel+'utes: '+tooltipItems.yLabel+'%';
return tooltipItems.xLabel+'utes: '+tooltipItems.yLabel+' sessions';
}
}
},
@ -849,7 +860,7 @@ function countUpTimer() {
yAxes: [{
ticks: {
callback: function(value, index, values) {
return value+'%';
return value+'';
}
}
}]

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.Plan
version: 3.4.0
version: 3.4.1
softdepend:
- OnTime

View File

@ -303,14 +303,6 @@ public class DataCacheHandlerTest {
public void testHandleReload() {
}
/**
*
*/
@Test
public void testGetMaxPlayers() {
assertEquals(20, handler.getMaxPlayers());
}
/**
*
*/

View File

@ -104,7 +104,7 @@ public class DataCacheProcessQueueTest {
}
});
Thread.sleep(1000);
assertTrue(q.stop().isEmpty());
assertTrue(q.stopAndReturnLeftovers().isEmpty());
}
@ -129,7 +129,7 @@ public class DataCacheProcessQueueTest {
l.add(h);
q.addToPool(l);
Thread.sleep(1000);
assertTrue(q.stop().isEmpty());
assertTrue(q.stopAndReturnLeftovers().isEmpty());
}
/**

View File

@ -45,7 +45,7 @@ public class PlayerActivityGraphCreatorTest {
public void testGenerateDataArray() {
List<SessionData> sessionData = createRandomSessionDataList();
long scale = 2592000L * 1000L;
String result = PlayerActivityGraphCreator.generateDataArray(sessionData, scale, 20)[1];
String result = PlayerActivityGraphCreator.generateDataArray(sessionData, scale)[1];
assertTrue("0", 0 < result.length());
}

View File

@ -5,7 +5,7 @@ The plugin uses two .html files: `analysis.html` and `player.html`
If the `/plugins/Plan/` folder contains either of the files, they will be used instead of the ones found inside the .jar.
This means you can copy the html files from the jar to the folder and edit them.
Page version: **3.2.0**
Page version: **3.4.0**
## Placeholders
The plugin uses placeholders to place the values into the html. Here I will go through each placeholder.