diff --git a/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_0.xml b/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml similarity index 67% rename from .idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_0.xml rename to .idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml index e90b3b519..826d210d1 100644 --- a/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_0.xml +++ b/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/Plan/.idea/libraries/Maven__com_destroystokyo_paper_paper_1_12_R0_1_SNAPSHOT.xml b/Plan/.idea/libraries/Maven__com_destroystokyo_paper_paper_1_12_R0_1_SNAPSHOT.xml new file mode 100644 index 000000000..ec40ac224 --- /dev/null +++ b/Plan/.idea/libraries/Maven__com_destroystokyo_paper_paper_1_12_R0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plan/.idea/libraries/Maven__com_djrapitops_PlanPluginBridge_3_6_0.xml b/Plan/.idea/libraries/Maven__com_djrapitops_PlanPluginBridge_3_6_0.xml new file mode 100644 index 000000000..f28c9c6a8 --- /dev/null +++ b/Plan/.idea/libraries/Maven__com_djrapitops_PlanPluginBridge_3_6_0.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plan/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml b/Plan/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml new file mode 100644 index 000000000..826d210d1 --- /dev/null +++ b/Plan/.idea/libraries/Maven__com_djrapitops_abstract_plugin_framework_2_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plan/.idea/sonarIssues.xml b/Plan/.idea/sonarIssues.xml new file mode 100644 index 000000000..405f4b5a3 --- /dev/null +++ b/Plan/.idea/sonarIssues.xml @@ -0,0 +1,349 @@ + + + + + + \ No newline at end of file diff --git a/Plan/.idea/uiDesigner.xml b/Plan/.idea/uiDesigner.xml new file mode 100644 index 000000000..e96534fb2 --- /dev/null +++ b/Plan/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plan/Class Diagram.xml b/Plan/Class Diagram.xml index eb7010ed1..1b97043a4 100644 --- a/Plan/Class Diagram.xml +++ b/Plan/Class Diagram.xml @@ -1,3 +1,7 @@ - - 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 + \ No newline at end of file diff --git a/Plan/checkstyle.xml b/Plan/checkstyle.xml index 249ae3d57..e04acdf0d 100644 --- a/Plan/checkstyle.xml +++ b/Plan/checkstyle.xml @@ -1,5 +1,6 @@ - + @@ -8,15 +9,15 @@ - - + + - - - - - + + + + + @@ -26,50 +27,50 @@ - + - - - - - - - + + + + + + + - + - - - + + + - - - - + + + + - + - - + + - - - + + + - - + + @@ -81,7 +82,7 @@ - + @@ -91,7 +92,7 @@ - + \ No newline at end of file diff --git a/Plan/dependency-reduced-pom.xml b/Plan/dependency-reduced-pom.xml index 5712fbced..8da93e303 100644 --- a/Plan/dependency-reduced-pom.xml +++ b/Plan/dependency-reduced-pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.djrapitops Plan - 3.5.4 + 3.5.5 ${basedir}/src clean package install @@ -100,15 +100,19 @@ - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + plan-repo + http://repo.fuzzlemann.de/artifactory/libs-release/ + + + plan-snapshot-repo + http://repo.fuzzlemann.de/artifactory/libs-snapshot/ - org.spigotmc - spigot - 1.12-R0.1-SNAPSHOT + com.destroystokyo.paper + paper + 1.12-R0.1-20170725.202533-1 provided diff --git a/Plan/localization/locale_EN.txt b/Plan/localization/locale_EN.txt index 780d4f491..9c759ad4e 100644 --- a/Plan/localization/locale_EN.txt +++ b/Plan/localization/locale_EN.txt @@ -1,6 +1,6 @@ ENABLED <> Player Analytics Enabled. DISABLED <> Player Analytics Disabled. -RELOAD_COMPLETE <> §a[Plan] Reload complete. +RELOAD_COMPLETE <> ďż˝a[Plan] Reload complete. CACHE_SAVE <> Saving cached data.. CACHE_ADD <> Added REPLACE0 to Cache. CACHE_REMOVE <> Cleared REPLACE0 from Cache. @@ -13,19 +13,19 @@ DB_CONNECTION_FAIL <> REPLACE0-Database Connection failed: REPLACE1 DB_ESTABLISHED <> REPLACE0-database connection established. DB_TYPE_DOES_NOT_EXIST <> That database type doesn't exist. DB_FAILURE_DISABLE <> Database initialization has failed, disabling Plan. -NOTIFY_EMPTY_IP <> §e[Plan] IP in server.properties is empty & AlternativeServerIP is not used, incorrect links will be given! -VERSION_NEW_AVAILABLE <> New Version (REPLACE0) is availible at https://www.spigotmc.org/resources/plan-player-analytics.32536/ +NOTIFY_EMPTY_IP <> ďż˝e[Plan] IP in server.properties is empty & AlternativeServerIP is not used, incorrect links will be given! +VERSION_NEW_AVAILABLE <> New Version (REPLACE0) is available at https://www.spigotmc.org/resources/plan-player-analytics.32536/ VERSION_LATEST <> You're running the latest version VERSION_CHECK_ERROR <> Failed to compare versions. VERSION_FAIL <> Failed to get newest version number. -USERNAME_NOT_VALID <> §c[Plan] This Player doesn't exist. -USERNAME_NOT_SEEN <> §c[Plan] This Player has not played on this server. -USERNAME_NOT_KNOWN <> §c[Plan] Player not found from the database. -GRABBING_DATA_MESSAGE <> »§2 Fetching data to cache.. +USERNAME_NOT_VALID <> ďż˝c[Plan] This Player doesn't exist. +USERNAME_NOT_SEEN <> ďż˝c[Plan] This Player has not played on this server. +USERNAME_NOT_KNOWN <> ďż˝c[Plan] Player not found from the database. +GRABBING_DATA_MESSAGE <> ��2 Fetching data to cache.. DEM_UNKNOWN <> Not Known NOT_IN_TOWN <> Not in a town NOT_IN_FAC <> Not in a faction -COMMAND_TIMEOUT <> §c[Plan] REPLACE0 Command timed out! Error most likely on console. +COMMAND_TIMEOUT <> ďż˝c[Plan] REPLACE0 Command timed out! Error most likely on console. ANALYSIS_START <> Analysis | Beginning analysis of user data.. ANALYSIS_BOOT_NOTIFY <> Analysis | Boot analysis in 30 seconds.. ANALYSIS_BOOT <> Analysis | Starting Boot Analysis.. @@ -36,44 +36,44 @@ 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. DATA_CORRUPTION_WARN <> Some data might be corrupted: REPLACE0 -ERROR_NO_DATA_VIEW <> §eWebserver disabled but Alternative IP/PlanLite not used, no way to view data! -ERROR_WEBSERVER_OFF_ANALYSIS <> §e[Plan] This command can be only used if the webserver is running on this server. -ERROR_WEBSERVER_OFF_INSPECT <> §e[Plan] This command can be only used if webserver/planlite is enabled on this server. -MANAGE_ERROR_INCORRECT_PLUGIN <> §c[Plan] Plugin not supported: -MANAGE_PROCESS_START <> »§7 Processing data.. -MANAGE_ERROR_PLUGIN_NOT_ENABLED <> §c[Plan] Plugin is not enabled: -MANAGE_ERROR_INCORRECT_DB <> §c[Plan] Incorrect database! (sqlite/mysql accepted): -MANAGE_ERROR_SAME_DB <> §c[Plan] Can't move to the same database! -MANAGE_DATABASE_FAILURE <> §c[Plan] One of the databases was not initialized properly. -MANAGE_DB_CONFIG_REMINDER <> §e[Plan] Remember to swap to the new database and reload plugin -MANAGE_ERROR_NO_PLAYERS <> §c[Plan] Database has no player data! -MANAGE_ERROR_BACKUP_FILE_NOT_FOUND <> §c[Plan] Backup file doesn't exist! -MANAGE_MOVE_SUCCESS <> §a[Plan] All data moved successfully! -MANAGE_COPY_SUCCESS <> §a[Plan] All data copied successfully! -MANAGE_PROCESS_FAIL <> §c[Plan] Something went wrong while processing the data! -MANAGE_CLEAR_SUCCESS <> §a[Plan] All data cleared successfully! -MANAGE_REMOVE_SUCCESS <> §f» §2Data of §fREPLACE0§2 was removed from Database §fREPLACE1§2. -MANAGE_IMPORTING <> §f» §2 Importing Data.. -MANAGE_SUCCESS <> §f» §2 Success! -CMD_ANALYZE_HEADER <> §f»§2 Player Analytics - Analysis results -CMD_INSPECT_HEADER <> §f»§2 Player Analytics - Inspect results: -CMD_INFO_HEADER <> §f»§2 Player Analytics - Info -CMD_INFO_VERSION <> §7 •§2§2 Version: §7REPLACE0 -CMD_SEARCH_HEADER <> §f»§2 Player Analytics - Search results for: -CMD_HELP_HEADER <> §f»§2 Player Analytics - Help -CMD_MANAGE_HELP_HEADER <> §f»§2 Player Analytics - Managment Help -CMD_MANAGE_STATUS_HEADER <> §f»§2 Player Analytics - Database status -CMD_MANAGE_STATUS_ACTIVE_DB <> §7 •§2§2 Active Database: §7REPLACE0 +ERROR_NO_DATA_VIEW <> ďż˝eWebserver disabled but Alternative IP/PlanLite not used, no way to view data! +ERROR_WEBSERVER_OFF_ANALYSIS <> ďż˝e[Plan] This command can be only used if the webserver is running on this server. +ERROR_WEBSERVER_OFF_INSPECT <> ďż˝e[Plan] This command can be only used if webserver/planlite is enabled on this server. +MANAGE_ERROR_INCORRECT_PLUGIN <> ďż˝c[Plan] Plugin not supported: +MANAGE_PROCESS_START <> ��7 Processing data.. +MANAGE_ERROR_PLUGIN_NOT_ENABLED <> ďż˝c[Plan] Plugin is not enabled: +MANAGE_ERROR_INCORRECT_DB <> ďż˝c[Plan] Incorrect database! (sqlite/mysql accepted): +MANAGE_ERROR_SAME_DB <> ďż˝c[Plan] Can't move to the same database! +MANAGE_DATABASE_FAILURE <> ďż˝c[Plan] One of the databases was not initialized properly. +MANAGE_DB_CONFIG_REMINDER <> ďż˝e[Plan] Remember to swap to the new database and reload plugin +MANAGE_ERROR_NO_PLAYERS <> ďż˝c[Plan] Database has no player data! +MANAGE_ERROR_BACKUP_FILE_NOT_FOUND <> ďż˝c[Plan] Backup file doesn't exist! +MANAGE_MOVE_SUCCESS <> ďż˝a[Plan] All data moved successfully! +MANAGE_COPY_SUCCESS <> ďż˝a[Plan] All data copied successfully! +MANAGE_PROCESS_FAIL <> ďż˝c[Plan] Something went wrong while processing the data! +MANAGE_CLEAR_SUCCESS <> ďż˝a[Plan] All data cleared successfully! +MANAGE_REMOVE_SUCCESS <> ďż˝fďż˝ ďż˝2Data of ďż˝fREPLACE0ďż˝2 was removed from Database ďż˝fREPLACE1ďż˝2. +MANAGE_IMPORTING <> ďż˝fďż˝ ďż˝2 Importing Data.. +MANAGE_SUCCESS <> ďż˝fďż˝ ďż˝2 Success! +CMD_ANALYZE_HEADER <> ďż˝f��2 Player Analytics - Analysis results +CMD_INSPECT_HEADER <> ďż˝f��2 Player Analytics - Inspect results: +CMD_INFO_HEADER <> ďż˝f��2 Player Analytics - Info +CMD_INFO_VERSION <> ďż˝7 ��2ďż˝2 Version: ďż˝7REPLACE0 +CMD_SEARCH_HEADER <> ďż˝f��2 Player Analytics - Search results for: +CMD_HELP_HEADER <> ďż˝f��2 Player Analytics - Help +CMD_MANAGE_HELP_HEADER <> ďż˝f��2 Player Analytics - Managment Help +CMD_MANAGE_STATUS_HEADER <> ďż˝f��2 Player Analytics - Database status +CMD_MANAGE_STATUS_ACTIVE_DB <> ďż˝7 ��2ďż˝2 Active Database: ďż˝7REPLACE0 CMD_CLICK_ME <> Click Me -CMD_LINK <> §7 •§2 Link: §f -CMD_RESULTS_AVAILABLE <> §7 Results will be available for §fREPLACE0§7 minutes. -CMD_NO_RESULTS <> §7 •§2 No results for §7REPLACE0§2. -CMD_MATCH <> §7 Matching player: §f +CMD_LINK <> ďż˝7 ��2 Link: ďż˝f +CMD_RESULTS_AVAILABLE <> ďż˝7 Results will be available for ďż˝fREPLACE0ďż˝7 minutes. +CMD_NO_RESULTS <> ďż˝7 ��2 No results for ďż˝7REPLACE0ďż˝2. +CMD_MATCH <> ďż˝7 Matching player: ďż˝f CMD_USG_ANALYZE <> View the Server Analysis CMD_USG_HELP <> Show command list. CMD_USG_INFO <> View Version of Plan CMD_USG_INSPECT <> Inspect Player's Data -CMD_USG_MANAGE <> Database managment command +CMD_USG_MANAGE <> Database management command CMD_USG_MANAGE_BACKUP <> Backup a database to .db file CMD_USG_MANAGE_RESTORE <> Restore a database from a backup file CMD_USG_MANAGE_MOVE <> Copy data from one database to another & overwrite values @@ -82,7 +82,7 @@ CMD_USG_MANAGE_IMPORT <> Import Data from supported plugins to Active Database. CMD_USG_MANAGE_CLEAR <> Clear data from one database CMD_USG_MANAGE_REMOVE <> Remove players's data from the Active Database. CMD_USG_MANAGE_STATUS <> Check the status of the Active Database. -CMD_USG_MANAGE_HELP <> Show managment help. +CMD_USG_MANAGE_HELP <> Show management help. CMD_USG_MANAGE_HOTSWAP <> Hotswap to another database & restart the plugin CMD_USG_RELOAD <> Reload plugin config & save cached data CMD_USG_SEARCH <> Search for player @@ -101,11 +101,11 @@ WARN_REWRITE <> Data in REPLACE0-database will be rewritten! WARN_OVERWRITE <> Data in REPLACE0-database will be overwritten! WARN_OVERWRITE_SOME <> Some data in REPLACE0-database will be overwritten! WARN_REMOVE <> Data in REPLACE0-database will be removed! -COMMAND_SENDER_NOT_PLAYER <> §c[Plan] This command can be only used as a player. -COMMAND_REQUIRES_ARGUMENTS <> §c[Plan] Command requires arguments. REPLACE0 -COMMAND_ADD_CONFIRMATION_ARGUMENT <> §c[Plan] Add -a to confirm execution! REPLACE0 -COMMAND_REQUIRES_ARGUMENTS_ONE <> §c[Plan] Command requires one argument. -COMMAND_NO_PERMISSION <> §c[Plan] You do not have the required permmission. +COMMAND_SENDER_NOT_PLAYER <> ďż˝c[Plan] This command can be only used as a player. +COMMAND_REQUIRES_ARGUMENTS <> ďż˝c[Plan] Command requires arguments. REPLACE0 +COMMAND_ADD_CONFIRMATION_ARGUMENT <> ďż˝c[Plan] Add -a to confirm execution! REPLACE0 +COMMAND_REQUIRES_ARGUMENTS_ONE <> ďż˝c[Plan] Command requires one argument. +COMMAND_NO_PERMISSION <> ďż˝c[Plan] You do not have the required permission. <<<<<>>>>> WARN_INACCURATE <>
Data might be inaccurate, player has just registered.
BANNED <> | Banned diff --git a/Plan/nbactions.xml b/Plan/nbactions.xml index aaaee2e0c..a224df77b 100644 --- a/Plan/nbactions.xml +++ b/Plan/nbactions.xml @@ -46,7 +46,9 @@ org.codehaus.mojo:exec-maven-plugin:1.2.1:exec - -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.djrapitops.nmplayer.NMPlayer + -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath + com.djrapitops.nmplayer.NMPlayer + java true diff --git a/Plan/pom.xml b/Plan/pom.xml index a2eae970d..272959b04 100644 --- a/Plan/pom.xml +++ b/Plan/pom.xml @@ -1,10 +1,10 @@ - 4.0.0 com.djrapitops Plan - 3.5.5 + 3.6.0 jar @@ -28,14 +28,14 @@ com.djrapitops abstract-plugin-framework - 2.0.0 + 2.0.1 compile com.djrapitops PlanPluginBridge - 3.5.0 + 3.6.0 compile @@ -105,6 +105,8 @@ . ${basedir}/src/main/resources + *.keystore + *.js *.yml *.html @@ -198,5 +200,6 @@ UTF-8 1.8 1.8 + java \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/Log.java b/Plan/src/main/java/com/djrapitops/plan/Log.java index 4689dadf4..e64feca63 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Log.java +++ b/Plan/src/main/java/com/djrapitops/plan/Log.java @@ -4,7 +4,7 @@ import java.util.Collection; /** * This class manages the messages going to the Console Logger. - * + *

* Methods of Abstract Plugin Framework log utility are used. * * @author Rsl1122 @@ -12,6 +12,13 @@ import java.util.Collection; */ public class Log { + /** + * Constructor used to hide the public constructor + */ + private Log() { + throw new IllegalStateException("Utility Class"); + } + /** * Logs the message to the console as INFO. * @@ -52,7 +59,7 @@ public class Log { * Logs trace of caught Exception to Errors.txt and notifies on console. * * @param source Class name the exception was caught in. - * @param e Throwable, eg NullPointerException + * @param e Throwable, eg NullPointerException */ public static void toLog(String source, Throwable e) { Plan.getInstance().getPluginLogger().toLog(source, e); @@ -62,7 +69,7 @@ public class Log { * Logs multiple caught Errors to Errors.txt. * * @param source Class name the exception was caught in. - * @param e Collection of Throwables, eg NullPointerException + * @param e Collection of Throwables, eg NullPointerException */ public static void toLog(String source, Collection e) { Plan.getInstance().getPluginLogger().toLog(source, e); @@ -71,7 +78,7 @@ public class Log { /** * Logs a message to the a given file with a timestamp. * - * @param message Message to log to Errors.txt [timestamp] Message + * @param message Message to log to Errors.txt [timestamp] Message * @param filename Name of the file to write to. */ public static void toLog(String message, String filename) { diff --git a/Plan/src/main/java/com/djrapitops/plan/Permissions.java b/Plan/src/main/java/com/djrapitops/plan/Permissions.java index 922c5140c..448d88572 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Permissions.java +++ b/Plan/src/main/java/com/djrapitops/plan/Permissions.java @@ -44,7 +44,7 @@ public enum Permissions { /** * Returns the permission node in plugin.yml. - * + *

* Same as getPermission. * * @return permission node eg. plan.inspect diff --git a/Plan/src/main/java/com/djrapitops/plan/Phrase.java b/Plan/src/main/java/com/djrapitops/plan/Phrase.java index 8c3b24d93..1770c228b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Phrase.java +++ b/Plan/src/main/java/com/djrapitops/plan/Phrase.java @@ -1,12 +1,13 @@ package main.java.com.djrapitops.plan; +import org.bukkit.ChatColor; + import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Scanner; -import org.bukkit.ChatColor; /** * Phrase contains every message that is used in placeholders or commands. The @@ -21,7 +22,7 @@ public enum Phrase { PREFIX("[Plan] "), ENABLED("Player Analytics Enabled."), DISABLED("Player Analytics Disabled."), - RELOAD_COMPLETE(ChatColor.GREEN + "" + PREFIX + "Reload complete."), + RELOAD_COMPLETE(ChatColor.GREEN.toString() + PREFIX + "Reload complete."), CACHE_SAVE("Saving cached data.."), CACHE_ADD("Added REPLACE0 to Cache."), CACHE_REMOVE("Cleared REPLACE0 from Cache."), @@ -34,7 +35,7 @@ public enum Phrase { DB_ESTABLISHED(REPLACE0 + "-database connection established."), DB_TYPE_DOES_NOT_EXIST("That database type doesn't exist."), DB_FAILURE_DISABLE("Database initialization has failed, disabling Plan."), - NOTIFY_EMPTY_IP(ChatColor.YELLOW + "" + PREFIX + "IP in server.properties is empty & AlternativeServerIP is not used, incorrect links will be given!"), + NOTIFY_EMPTY_IP(ChatColor.YELLOW.toString() + PREFIX + "IP in server.properties is empty & AlternativeServerIP is not used, incorrect links will be given!"), NOTIFY_DISABLED_CHATLISTENER(ChatColor.YELLOW + "Chat listener disabled, nickname info inaccurate."), NOTIFY_DISABLED_GMLISTENER(ChatColor.YELLOW + "Gamemode change listener disabled, Gm times info inaccurate."), NOTIFY_DISABLED_COMMANDLISTENER(ChatColor.YELLOW + "Command usage listener disabled."), @@ -44,14 +45,14 @@ public enum Phrase { CACHE_GETTASK_DISABLED("Attempted to schedule data grab after task was shut down."), CACHE_CLEARTASK_DISABLED("Attempted to schedule data for clear after task was shut down."), // - VERSION_NEW_AVAILABLE("New Version (" + REPLACE0 + ") is availible at https://www.spigotmc.org/resources/plan-player-analytics.32536/"), + VERSION_NEW_AVAILABLE("New Version (" + REPLACE0 + ") is available at https://www.spigotmc.org/resources/plan-player-analytics.32536/"), VERSION_LATEST("You're running the latest version"), VERSION_CHECK_ERROR("Failed to compare versions."), VERSION_FAIL("Failed to get newest version number."), // - USERNAME_NOT_VALID(ChatColor.RED + "" + PREFIX + "This Player doesn't exist."), - USERNAME_NOT_SEEN(ChatColor.RED + "" + PREFIX + "This Player has not played on this server."), - USERNAME_NOT_KNOWN(ChatColor.RED + "" + PREFIX + "Player not found from the database."), + USERNAME_NOT_VALID(ChatColor.RED.toString() + PREFIX + "This Player doesn't exist."), + USERNAME_NOT_SEEN(ChatColor.RED.toString() + PREFIX + "This Player has not played on this server."), + USERNAME_NOT_KNOWN(ChatColor.RED.toString() + PREFIX + "Player not found from the database."), // COLOR_MAIN(ChatColor.getByChar(Settings.COLOR_MAIN.toString().charAt(1))), COLOR_SEC(ChatColor.getByChar(Settings.COLOR_SEC.toString().charAt(1))), @@ -59,14 +60,14 @@ public enum Phrase { // ARROWS_RIGHT("»"), BALL("•"), - GRABBING_DATA_MESSAGE(COLOR_TER + "" + ARROWS_RIGHT + COLOR_MAIN.color() + " Fetching data to cache.."), + GRABBING_DATA_MESSAGE(COLOR_TER.toString() + ARROWS_RIGHT + COLOR_MAIN.color() + " Fetching data to cache.."), // DEM_UNKNOWN("Not Known"), NOT_IN_TOWN("Not in a town"), NOT_IN_FAC("Not in a faction"), // ANALYSIS("Analysis | "), - COMMAND_TIMEOUT(ChatColor.RED + "" + PREFIX + "REPLACE0 Command timed out! Check '/plan status' & console."), + COMMAND_TIMEOUT(ChatColor.RED.toString() + PREFIX + "REPLACE0 Command timed out! Check '/plan status' & console."), ANALYSIS_START(ANALYSIS + "Beginning analysis of user data.."), ANALYSIS_BOOT_NOTIFY(ANALYSIS + "Boot analysis in 30 seconds.."), ANALYSIS_BOOT(ANALYSIS + "Starting Boot Analysis.."), @@ -82,45 +83,45 @@ public enum Phrase { ERROR_CONSOLE_PLAYER("This point of code should not be accessable on console. Inform author: " + REPLACE0 + " Console: REPLACE1"), ERROR_NO_DATA_VIEW(ChatColor.YELLOW + "Webserver disabled but Alternative IP/PlanLite not used, no way to view data!"), ERROR_WEBSERVER_OFF_ANALYSIS(ChatColor.YELLOW + "" + PREFIX + "This command can be only used if the webserver is running on this server."), - ERROR_WEBSERVER_OFF_INSPECT(ChatColor.YELLOW + "" + PREFIX + "This command can be only used if webserver/planlite is enabled on this server."), + ERROR_WEBSERVER_OFF_INSPECT(ChatColor.YELLOW + "" + PREFIX + "This command can be only used if webserver is enabled on this server."), ERROR_LOGGED("Caught " + REPLACE0 + ". It has been logged to the Errors.txt"), ERROR_SESSIONDATA_INITIALIZATION("Player's session was initialized in a wrong way! (" + REPLACE0 + ")"), ERROR_ANALYSIS_FETCH_FAIL("Failed to fetch data for Analysis, Exception occurred."), ERROR_ANALYSIS_DISABLED_TEMPORARILY(ChatColor.YELLOW + "Analysis has been temporarily disabled due to expensive task, use /plan status for info."), // - CMD_FOOTER(COLOR_TER.color() + "" + ARROWS_RIGHT), - MANAGE_ERROR_INCORRECT_PLUGIN(ChatColor.RED + "" + PREFIX + "Plugin not supported: "), - MANAGE_PROCESS_START(ARROWS_RIGHT + "" + COLOR_SEC.color() + " Processing data.."), - MANAGE_ERROR_PLUGIN_NOT_ENABLED(ChatColor.RED + "" + PREFIX + "Plugin is not enabled: "), - MANAGE_ERROR_INCORRECT_DB(ChatColor.RED + "" + PREFIX + "Incorrect database! (sqlite/mysql accepted): "), - MANAGE_ERROR_SAME_DB(ChatColor.RED + "" + PREFIX + "Can't move to the same database!"), - MANAGE_DATABASE_FAILURE(ChatColor.RED + "" + PREFIX + "One of the databases was not initialized properly."), - MANAGE_DB_CONFIG_REMINDER(ChatColor.YELLOW + "" + PREFIX + "Remember to swap to the new database and reload plugin"), - MANAGE_ERROR_NO_PLAYERS(ChatColor.RED + "" + PREFIX + "Database has no player data!"), - MANAGE_ERROR_BACKUP_FILE_NOT_FOUND(ChatColor.RED + "" + PREFIX + "Backup file doesn't exist!"), - MANAGE_MOVE_SUCCESS(ChatColor.GREEN + "" + PREFIX + "All data moved successfully!"), - MANAGE_COPY_SUCCESS(ChatColor.GREEN + "" + PREFIX + "All data copied successfully!"), - MANAGE_PROCESS_FAIL(ChatColor.RED + "" + PREFIX + "Something went wrong while processing the data!"), - MANAGE_CLEAR_SUCCESS(ChatColor.GREEN + "" + PREFIX + "All data cleared successfully!"), + CMD_FOOTER(COLOR_TER.color().toString() + ARROWS_RIGHT), + MANAGE_ERROR_INCORRECT_PLUGIN(ChatColor.RED.toString() + PREFIX + "Plugin not supported: "), + MANAGE_PROCESS_START(ARROWS_RIGHT.toString() + COLOR_SEC.color() + " Processing data.."), + MANAGE_ERROR_PLUGIN_NOT_ENABLED(ChatColor.RED.toString() + PREFIX + "Plugin is not enabled: "), + MANAGE_ERROR_INCORRECT_DB(ChatColor.RED.toString() + PREFIX + "Incorrect database! (sqlite/mysql accepted): "), + MANAGE_ERROR_SAME_DB(ChatColor.RED.toString() + PREFIX + "Can't move to the same database!"), + MANAGE_DATABASE_FAILURE(ChatColor.RED.toString() + PREFIX + "One of the databases was not initialized properly."), + MANAGE_DB_CONFIG_REMINDER(ChatColor.YELLOW.toString() + PREFIX + "Remember to swap to the new database and reload plugin"), + MANAGE_ERROR_NO_PLAYERS(ChatColor.RED.toString() + PREFIX + "Database has no player data!"), + MANAGE_ERROR_BACKUP_FILE_NOT_FOUND(ChatColor.RED.toString() + PREFIX + "Backup file doesn't exist!"), + MANAGE_MOVE_SUCCESS(ChatColor.GREEN.toString() + PREFIX + "All data moved successfully!"), + MANAGE_COPY_SUCCESS(ChatColor.GREEN.toString() + PREFIX + "All data copied successfully!"), + MANAGE_PROCESS_FAIL(ChatColor.RED.toString() + PREFIX + "Something went wrong while processing the data!"), + MANAGE_CLEAR_SUCCESS(ChatColor.GREEN.toString() + PREFIX + "All data cleared successfully!"), MANAGE_REMOVE_SUCCESS(CMD_FOOTER + " " + COLOR_MAIN.color() + "Data of " + COLOR_TER.color() + "REPLACE0" + COLOR_MAIN.color() + " was removed from Database " + COLOR_TER.color() + "REPLACE1" + COLOR_MAIN.color() + "."), MANAGE_IMPORTING(CMD_FOOTER + " " + COLOR_MAIN.color() + " Importing Data.."), MANAGE_SUCCESS(CMD_FOOTER + " " + COLOR_MAIN.color() + " Success!"), // CMD_BALL(COLOR_SEC.color() + " " + Phrase.BALL.toString() + COLOR_MAIN.color()), - CMD_ANALYZE_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Analysis results"), - CMD_INSPECT_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Inspect results: "), - CMD_INFO_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Info"), - CMD_INFO_VERSION(CMD_BALL + "" + COLOR_MAIN.color() + " Version: " + COLOR_SEC.color() + REPLACE0), - CMD_SEARCH_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Search results for: "), - CMD_SEARCH_SEARCHING(CMD_FOOTER + "" + COLOR_MAIN.color() + " Searching.."), - CMD_HELP_HEADER(CMD_FOOTER + "" + COLOR_MAIN.color() + " Player Analytics - Help"), - 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_ANALYZE_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Analysis results"), + CMD_INSPECT_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Inspect results: "), + CMD_INFO_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Info"), + CMD_INFO_VERSION(CMD_BALL.toString() + COLOR_MAIN.color() + " Version: " + COLOR_SEC.color() + REPLACE0), + CMD_SEARCH_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Search results for: "), + CMD_SEARCH_SEARCHING(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Searching.."), + CMD_HELP_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Help"), + CMD_MANAGE_HELP_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Managment Help"), + CMD_MANAGE_STATUS_HEADER(CMD_FOOTER.toString() + COLOR_MAIN.color() + " Player Analytics - Database status"), + CMD_MANAGE_STATUS_ACTIVE_DB(CMD_BALL.toString() + COLOR_MAIN.color() + " Active Database: " + COLOR_SEC.color() + "REPLACE0"), + CMD_MANAGE_STATUS_QUEUE_SAVE(CMD_BALL.toString() + COLOR_MAIN.color() + " Save Queue Size: " + COLOR_SEC.color() + "REPLACE0/" + Settings.PROCESS_SAVE_LIMIT.getNumber()), + CMD_MANAGE_STATUS_QUEUE_GET(CMD_BALL.toString() + COLOR_MAIN.color() + " Get Queue Size: " + COLOR_SEC.color() + "REPLACE0/" + Settings.PROCESS_GET_LIMIT.getNumber()), + CMD_MANAGE_STATUS_QUEUE_CLEAR(CMD_BALL.toString() + COLOR_MAIN.color() + " Clear Queue Size: " + COLOR_SEC.color() + "REPLACE0/" + Settings.PROCESS_CLEAR_LIMIT.getNumber()), + CMD_MANAGE_STATUS_QUEUE_PROCESS(CMD_BALL.toString() + 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"), @@ -134,7 +135,7 @@ public enum Phrase { CMD_USG_INFO("View Version of Plan"), CMD_USG_INSPECT("Inspect Player's Data"), CMD_USG_QINSPECT("QuickInspect Player's Data"), - CMD_USG_MANAGE("Database managment command"), + CMD_USG_MANAGE("Database management command"), CMD_USG_MANAGE_BACKUP("Backup a database to .db file"), CMD_USG_MANAGE_RESTORE("Restore a database from a backup file"), CMD_USG_MANAGE_MOVE("Copy data from one database to another & overwrite values"), @@ -144,7 +145,7 @@ public enum Phrase { CMD_USG_MANAGE_CLEAN("Clear incorrect data from the database"), CMD_USG_MANAGE_REMOVE("Remove players's data from the Active Database."), CMD_USG_MANAGE_STATUS("Check the status of the Active Database."), - CMD_USG_MANAGE_HELP("Show managment help."), + CMD_USG_MANAGE_HELP("Show management help."), CMD_USG_MANAGE_HOTSWAP("Hotswap to another database & restart the plugin"), CMD_USG_RELOAD("Reload plugin config & save cached data"), CMD_USG_SEARCH("Search for player"), @@ -167,11 +168,11 @@ public enum Phrase { WARN_OVERWRITE_SOME("Some data in REPLACE0-database will be overwritten!"), WARN_REMOVE("Data in REPLACE0-database will be removed!"), // - COMMAND_SENDER_NOT_PLAYER(ChatColor.RED + "" + PREFIX + "This command can be only used as a player."), - COMMAND_REQUIRES_ARGUMENTS(ChatColor.RED + "" + PREFIX + "Command requires arguments. REPLACE0"), - COMMAND_ADD_CONFIRMATION_ARGUMENT(ChatColor.RED + "" + PREFIX + "Add -a to confirm execution! REPLACE0"), - COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED + "" + PREFIX + "Command requires one argument."), - COMMAND_NO_PERMISSION(ChatColor.RED + "" + PREFIX + "You do not have the required permmission."), + COMMAND_SENDER_NOT_PLAYER(ChatColor.RED.toString() + PREFIX + "This command can be only used as a player."), + COMMAND_REQUIRES_ARGUMENTS(ChatColor.RED.toString() + PREFIX + "Command requires arguments. REPLACE0"), + COMMAND_ADD_CONFIRMATION_ARGUMENT(ChatColor.RED.toString() + PREFIX + "Add -a to confirm execution! REPLACE0"), + COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED.toString() + PREFIX + "Command requires one argument."), + COMMAND_NO_PERMISSION(ChatColor.RED.toString() + PREFIX + "You do not have the required permission."), ERROR_TOO_SMALL_QUEUE("Queue size is too small! (REPLACE0), change the setting to a higher number! (Currently REPLACE1)"); private String text; @@ -187,6 +188,32 @@ public enum Phrase { this.text = ""; } + static void loadLocale(File localeFile) { + try (Scanner localeScanner = new Scanner(localeFile, "UTF-8")) { + List localeRows = new ArrayList<>(); + while (localeScanner.hasNextLine()) { + String line = localeScanner.nextLine(); + if (!line.isEmpty()) { + if ("<<<<<>>>>>".equals(line)) { + break; + } + localeRows.add(line); + } + } + + for (String localeRow : localeRows) { + try { + String[] split = localeRow.split(" <> "); + Phrase.valueOf(split[0]).setText(split[1]); + } catch (IllegalArgumentException e) { + Log.error("There is a miswritten line in locale on line " + localeRows.indexOf(localeRow)); + } + } + } catch (IOException e) { + Log.error("Error at Locale Scanning: " + e.getCause()); + } + } + @Override public String toString() { return text; @@ -241,30 +268,4 @@ public enum Phrase { public void setColor(char colorCode) { this.color = ChatColor.getByChar(colorCode); } - - static void loadLocale(File localeFile) { - try { - Scanner localeScanner = new Scanner(localeFile, "UTF-8"); - List localeRows = new ArrayList<>(); - while (localeScanner.hasNextLine()) { - String line = localeScanner.nextLine(); - if (!line.isEmpty()) { - if ("<<<<<>>>>>".equals(line)) { - break; - } - localeRows.add(line); - } - } - for (String localeRow : localeRows) { - try { - String[] split = localeRow.split(" <> "); - Phrase.valueOf(split[0]).setText(split[1]); - } catch (IllegalArgumentException e) { - Log.error("There is a miswritten line in locale on line " + localeRows.indexOf(localeRow)); - } - } - } catch (IOException e) { - - } - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/Plan.java b/Plan/src/main/java/com/djrapitops/plan/Plan.java index de4c0d3f5..62a9aa8bf 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Plan.java +++ b/Plan/src/main/java/com/djrapitops/plan/Plan.java @@ -32,27 +32,30 @@ import main.java.com.djrapitops.plan.data.additional.HookHandler; 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.data.cache.PageCacheHandler; import main.java.com.djrapitops.plan.data.listeners.*; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.database.databases.MySQLDB; import main.java.com.djrapitops.plan.database.databases.SQLiteDB; import main.java.com.djrapitops.plan.ui.html.Html; -import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer; +import main.java.com.djrapitops.plan.ui.webserver.WebServer; import main.java.com.djrapitops.plan.utilities.Benchmark; import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.metrics.BStats; -import org.bukkit.Bukkit; +import org.apache.logging.log4j.LogManager; import java.io.*; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; /** * Main class for Bukkit that manages the plugin. - * + *

* Everything can be accessed through this class. Use Plan.getInstance() to get * the initialised instance of Plan. * @@ -71,14 +74,38 @@ public class Plan extends BukkitPlugin { private Database db; private HashSet databases; - private WebSocketServer uiServer; + private WebServer uiServer; private ServerVariableHolder serverVariableHolder; private int bootAnalysisTaskID = -1; /** - * OnEnable method. + * Used to get the PlanAPI. @see API * + * @return API of the current instance of Plan. + * @throws IllegalStateException If onEnable method has not been called on + * Plan and the instance is null. + */ + public static API getPlanAPI() throws IllegalStateException { + Plan instance = getInstance(); + if (instance == null) { + throw new IllegalStateException("Plugin not enabled properly, Singleton instance is null."); + } + return instance.api; + } + + /** + * Used to get the plugin-instance singleton. + * + * @return this object. + */ + public static Plan getInstance() { + return (Plan) getPluginInstance(Plan.class); + } + + /** + * OnEnable method. + *

* - Enables the plugin's subsystems. */ @Override @@ -103,13 +130,13 @@ public class Plan extends BukkitPlugin { Benchmark.start("Enable: Copy default config"); getConfig().options().copyDefaults(true); - getConfig().options().header(Phrase.CONFIG_HEADER + ""); + getConfig().options().header(Phrase.CONFIG_HEADER.toString()); saveConfig(); Benchmark.stop("Enable: Copy default config"); Benchmark.start("Enable: Init Database"); - Log.info(Phrase.DB_INIT + ""); - if (Check.isTrue_Error(initDatabase(), Phrase.DB_FAILURE_DISABLE.toString())) { + Log.info(Phrase.DB_INIT.toString()); + if (Check.ErrorIfFalse(initDatabase(), Phrase.DB_FAILURE_DISABLE.toString())) { Log.info(Phrase.DB_ESTABLISHED.parse(db.getConfigName())); } else { disablePlugin(); @@ -154,15 +181,19 @@ public class Plan extends BukkitPlugin { boolean hasDataViewCapability = usingAlternativeIP || usingAlternativeUI || webserverIsEnabled; if (webserverIsEnabled) { - uiServer = new WebSocketServer(this); + uiServer = new WebServer(this); uiServer.initServer(); - // Prevent passwords showing up on console. - Bukkit.getLogger().setFilter(new RegisterCommandFilter()); + + if (!uiServer.isEnabled()) { + Log.error("WebServer was not successfully initialized."); + } + + setupFilter(); } else if (!hasDataViewCapability) { - Log.infoColor(Phrase.ERROR_NO_DATA_VIEW + ""); + Log.infoColor(Phrase.ERROR_NO_DATA_VIEW.toString()); } if (!usingAlternativeIP && serverVariableHolder.getIp().isEmpty()) { - Log.infoColor(Phrase.NOTIFY_EMPTY_IP + ""); + Log.infoColor(Phrase.NOTIFY_EMPTY_IP.toString()); } Benchmark.stop("Enable: WebServer Initialization"); @@ -176,64 +207,73 @@ public class Plan extends BukkitPlugin { bStats.registerMetrics(); Log.debug("Verbose debug messages are enabled."); - Log.info(Phrase.ENABLED + ""); + Log.info(Phrase.ENABLED.toString()); processStatus().finishExecution("Enable"); } /** * Disables the plugin. - * + *

* Stops the webserver, cancels all tasks and saves cache to the database. */ @Override public void onDisable() { + //Clears the page cache + PageCacheHandler.clearCache(); + // Stop the UI Server if (uiServer != null) { uiServer.stop(); } + getServer().getScheduler().cancelTasks(this); + if (Verify.notNull(handler, db)) { Benchmark.start("Disable: DataCache Save"); // Saves the DataCache to the database without Bukkit's Schedulers. - Log.info(Phrase.CACHE_SAVE + ""); - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + Log.info(Phrase.CACHE_SAVE.toString()); + + ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.execute(() -> { handler.saveCacheOnDisable(); taskStatus().cancelAllKnownTasks(); Benchmark.stop("Disable: DataCache Save"); }); - scheduler.shutdown(); // Schedules the save to shutdown after it has ran the execute method. + scheduler.shutdown(); // Schedules the save to shutdown after it has ran the execute method. } - Log.info(Phrase.DISABLED + ""); + + Log.info(Phrase.DISABLED.toString()); } private void registerListeners() { Benchmark.start("Enable: Register Listeners"); registerListener(new PlanPlayerListener(this)); - boolean chatListenerIsEnabled = Check.isTrue(Settings.GATHERCHAT.isTrue(), Phrase.NOTIFY_DISABLED_CHATLISTENER + ""); - boolean gamemodeChangeListenerIsEnabled = Check.isTrue(Settings.GATHERGMTIMES.isTrue(), Phrase.NOTIFY_DISABLED_GMLISTENER + ""); - boolean commandListenerIsEnabled = Check.isTrue(Settings.GATHERCOMMANDS.isTrue(), Phrase.NOTIFY_DISABLED_COMMANDLISTENER + ""); - boolean deathListenerIsEnabled = Check.isTrue(Settings.GATHERKILLS.isTrue(), Phrase.NOTIFY_DISABLED_DEATHLISTENER + ""); + boolean chatListenerIsEnabled = Check.isTrue(Settings.GATHERCHAT.isTrue(), Phrase.NOTIFY_DISABLED_CHATLISTENER.toString()); + boolean commandListenerIsEnabled = Check.isTrue(Settings.GATHERCOMMANDS.isTrue(), Phrase.NOTIFY_DISABLED_COMMANDLISTENER.toString()); + boolean deathListenerIsEnabled = Check.isTrue(Settings.GATHERKILLS.isTrue(), Phrase.NOTIFY_DISABLED_DEATHLISTENER.toString()); if (chatListenerIsEnabled) { registerListener(new PlanChatListener(this)); } - if (gamemodeChangeListenerIsEnabled) { - registerListener(new PlanGamemodeChangeListener(this)); - } + + registerListener(new PlanGamemodeChangeListener(this)); + registerListener(new PlanWorldChangeListener(this)); + if (commandListenerIsEnabled) { registerListener(new PlanCommandPreprocessListener(this)); } + if (deathListenerIsEnabled) { registerListener(new PlanDeathEventListener(this)); } + Benchmark.stop("Enable: Register Listeners"); } /** * Initializes the database according to settings in the config. - * + *

* If database connection can not be established plugin is disabled. * * @return true if init was successful, false if not. @@ -243,7 +283,7 @@ public class Plan extends BukkitPlugin { databases.add(new MySQLDB(this)); databases.add(new SQLiteDB(this)); - String dbType = (Settings.DB_TYPE + "").toLowerCase().trim(); + String dbType = Settings.DB_TYPE.toString().toLowerCase().trim(); for (Database database : databases) { String databaseType = database.getConfigName().toLowerCase().trim(); @@ -253,11 +293,13 @@ public class Plan extends BukkitPlugin { break; } } + if (!Verify.notNull(db)) { Log.info(Phrase.DB_TYPE_DOES_NOT_EXIST.toString() + " " + dbType); return false; } - return Check.isTrue_Error(db.init(), Phrase.DB_FAILURE_DISABLE.toString()); + + return Check.ErrorIfFalse(db.init(), Phrase.DB_FAILURE_DISABLE.toString()); } private void startAnalysisRefreshTask(int everyXMinutes) throws IllegalStateException { @@ -269,9 +311,7 @@ public class Plan extends BukkitPlugin { @Override public void run() { Log.debug("Running PeriodicalAnalysisTask"); - if (!analysisCache.isCached()) { - analysisCache.updateCache(); - } else if (MiscUtils.getTime() - analysisCache.getData().getRefreshDate() > TimeAmount.MINUTE.ms()) { + if (!analysisCache.isCached() || MiscUtils.getTime() - analysisCache.getData().getRefreshDate() > TimeAmount.MINUTE.ms()) { analysisCache.updateCache(); } } @@ -300,10 +340,14 @@ public class Plan extends BukkitPlugin { */ public void writeNewLocaleFile() { File genLocale = new File(getDataFolder(), "locale_EN.txt"); - try { - genLocale.createNewFile(); - FileWriter fw = new FileWriter(genLocale, true); - PrintWriter pw = new PrintWriter(fw); + try ( + FileWriter fw = new FileWriter(genLocale, true); + PrintWriter pw = new PrintWriter(fw) + ) { + if (genLocale.createNewFile()) { + Log.debug(genLocale.getAbsoluteFile() + " created"); + } + for (Phrase p : Phrase.values()) { pw.println(p.name() + " <> " + p.parse()); pw.flush(); @@ -319,41 +363,83 @@ public class Plan extends BukkitPlugin { } private void initLocale() { + String defaultLocale = "Default: EN"; + String locale = Settings.LOCALE.toString().toUpperCase(); Benchmark.start("Enable: Initializing locale"); File localeFile = new File(getDataFolder(), "locale.txt"); - boolean skipLoc = false; - String usingLocale = ""; + + String usingLocale; + if (localeFile.exists()) { Phrase.loadLocale(localeFile); Html.loadLocale(localeFile); - skipLoc = true; - usingLocale = "locale.txt"; + + stopInitLocale(defaultLocale); + return; } - if (!locale.equals("DEFAULT")) { - try { - if (!skipLoc) { - URL localeURL = new URL("https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan/localization/locale_" + locale + ".txt"); - InputStream inputStream = localeURL.openStream(); - OutputStream outputStream = new FileOutputStream(localeFile); - int read; - byte[] bytes = new byte[1024]; - while ((read = inputStream.read(bytes)) != -1) { - outputStream.write(bytes, 0, read); - } - Phrase.loadLocale(localeFile); - Html.loadLocale(localeFile); - usingLocale = locale; - localeFile.delete(); - } - } catch (FileNotFoundException ex) { - Log.error("Attempted using locale that doesn't exist."); - usingLocale = "Default: EN"; - } catch (IOException e) { + + if (locale.equals("DEFAULT")) { + stopInitLocale(defaultLocale); + return; + } + + String urlString = "https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan/localization/locale_" + locale + ".txt"; + + URL localeURL; + try { + localeURL = new URL(urlString); + } catch (MalformedURLException e) { + Log.error("Error at parsing \"" + urlString + "\" to an URL"); //Shouldn't ever happen + + stopInitLocale(defaultLocale); + return; + } + + try (InputStream inputStream = localeURL.openStream(); + OutputStream outputStream = new FileOutputStream(localeFile)) { + + int read; + byte[] bytes = new byte[1024]; + while ((read = inputStream.read(bytes)) != -1) { + outputStream.write(bytes, 0, read); } - } else { - usingLocale = "Default: EN"; + + Phrase.loadLocale(localeFile); + Html.loadLocale(localeFile); + usingLocale = locale; + + if (localeFile.delete()) { + Log.debug(localeFile.getAbsoluteFile() + " (Locale File) deleted"); + } + + stopInitLocale(usingLocale); + } catch (FileNotFoundException ex) { + Log.error("Attempted using locale that doesn't exist."); + + stopInitLocale(defaultLocale); + } catch (IOException e) { + Log.error("Error at loading locale from GitHub, using default locale."); + + stopInitLocale(defaultLocale); } + } + + /** + * Setups the command console output filter + */ + private void setupFilter() { + org.apache.logging.log4j.core.Logger logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); + logger.addFilter(new RegisterCommandFilter()); + } + + /** + * Stops initializing the locale + * + * @param usingLocale The locale that's used + * @implNote Removes clutter in the method + */ + private void stopInitLocale(String usingLocale) { Benchmark.stop("Enable: Initializing locale"); Log.info("Using locale: " + usingLocale); } @@ -399,7 +485,7 @@ public class Plan extends BukkitPlugin { * * @return the Webserver */ - public WebSocketServer getUiServer() { + public WebServer getUiServer() { return uiServer; } @@ -414,12 +500,12 @@ public class Plan extends BukkitPlugin { /** * Used to get all possible database objects. - * + *

* #init() might need to be called in order for the object to function. * * @return Set containing the SqLite and MySQL objects. */ - public HashSet getDatabases() { + public Set getDatabases() { return databases; } @@ -446,35 +532,11 @@ public class Plan extends BukkitPlugin { /** * Old method for getting the API. * - * @deprecated Use Plan.getPlanAPI() (static method) instead. * @return the Plan API. + * @deprecated Use Plan.getPlanAPI() (static method) instead. */ @Deprecated public API getAPI() { return api; } - - /** - * Used to get the PlanAPI. @see API - * - * @return API of the current instance of Plan. - * @throws IllegalStateException If onEnable method has not been called on - * Plan and the instance is null. - */ - public static API getPlanAPI() throws IllegalStateException { - Plan instance = getInstance(); - if (instance == null) { - throw new IllegalStateException("Plugin not enabled properly, Singleton instance is null."); - } - return instance.api; - } - - /** - * Used to get the plugin-instance singleton. - * - * @return this object. - */ - public static Plan getInstance() { - return (Plan) getPluginInstance(Plan.class); - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java b/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java index 785e2ce87..04d3c69cb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java +++ b/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java @@ -11,7 +11,6 @@ import org.bukkit.Server; */ public class ServerVariableHolder { - private final int maxPlayers; private final String ip; private final boolean usingPaper; @@ -21,18 +20,11 @@ public class ServerVariableHolder { * @param server instance the plugin is running on. */ public ServerVariableHolder(Server server) { - maxPlayers = server.getMaxPlayers(); ip = server.getIp(); - usingPaper = server.getName().equals("Paper"); - } - /** - * Maximum amount of players defined in server.properties. - * - * @return number. - */ - public int getMaxPlayers() { - return maxPlayers; + String serverName = server.getName(); + usingPaper = serverName.equals("Paper") + || serverName.equals("TacoSpigot"); //Fork of Paper } /** diff --git a/Plan/src/main/java/com/djrapitops/plan/Settings.java b/Plan/src/main/java/com/djrapitops/plan/Settings.java index 519bb62e1..6f0ec63ff 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Settings.java +++ b/Plan/src/main/java/com/djrapitops/plan/Settings.java @@ -15,18 +15,15 @@ public enum Settings { ANALYSIS_REFRESH_ON_ENABLE("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable"), ANALYSIS_LOG_TO_CONSOLE("Settings.Analysis.LogProgressOnConsole"), ANALYSIS_LOG_FINISHED("Settings.Analysis.NotifyWhenFinished"), - ANALYSIS_REMOVE_OUTLIERS("Settings.Analysis.RemoveOutliersFromVisualization"), ANALYSIS_EXPORT("Settings.Analysis.Export.Enabled"), SHOW_ALTERNATIVE_IP("Settings.WebServer.ShowAlternativeServerIP"), USE_ALTERNATIVE_UI("Settings.UseTextUI"), GATHERCHAT("Settings.Data.ChatListener"), GATHERKILLS("Settings.Data.GatherKillData"), - GATHERGMTIMES("Settings.Data.GamemodeChangeListener"), GATHERCOMMANDS("Settings.Data.GatherCommandUsage"), DO_NOT_LOG_UNKNOWN_COMMANDS("Customization.Data.DoNotLogUnknownCommands"), COMBINE_COMMAND_ALIASES_TO_MAIN_COMMAND("Customization.Data.CombineCommandAliasesToMainCommand"), SECURITY_IP_UUID("Settings.WebServer.Security.DisplayIPsAndUUIDs"), - GRAPH_PLAYERS_USEMAXPLAYERS_SCALE("Customization.Graphs.PlayersOnlineGraph.UseMaxPlayersAsScale"), PLAYERLIST_SHOW_IMAGES("Customization.SmallHeadImagesOnAnalysisPlayerlist"), // Integer ANALYSIS_MINUTES_FOR_ACTIVE("Settings.Analysis.MinutesPlayedUntilConsidiredActive"), @@ -49,7 +46,11 @@ public enum Settings { LOCALE("Settings.Locale"), WEBSERVER_IP("Settings.WebServer.InternalIP"), ANALYSIS_EXPORT_PATH("Settings.Analysis.Export.DestinationFolder"), - LINK_PROTOCOL("Settings.WebServer.LinkProtocol"), + WEBSERVER_CERTIFICATE_PATH("Settings.WebServer.Security.Certificate.KeyStorePath"), + WEBSERVER_CERTIFICATE_KEYPASS("Settings.WebServer.Security.Certificate.KeyPass"), + WEBSERVER_CERTIFICATE_STOREPASS("Settings.WebServer.Security.Certificate.StorePass"), + WEBSERVER_CERTIFICATE_ALIAS("Settings.WebServer.Security.Certificate.Alias"), + LINK_PROTOCOL("Settings.WebServer.ExternalWebServerLinkProtocol"), // SERVER_NAME("Customization.ServerName"), // @@ -72,7 +73,6 @@ public enum Settings { HCOLOR_TER("Customization.Colors.HTML.UI.Tertiary"), HCOLOR_TER_DARK("Customization.Colors.HTML.UI.TertiaryDark"), HCOLOR_ACT_ONL("Customization.Colors.HTML.ActivityGraph.OnlinePlayers"), - HCOLOR_ACT_ONL_FILL("Customization.Colors.HTML.ActivityGraph.OnlinePlayersFill"), HCOLOR_ACTP_ACT("Customization.Colors.HTML.ActivityPie.Active"), HCOLOR_ACTP_BAN("Customization.Colors.HTML.ActivityPie.Banned"), HCOLOR_ACTP_INA("Customization.Colors.HTML.ActivityPie.Inactive"), diff --git a/Plan/src/main/java/com/djrapitops/plan/api/API.java b/Plan/src/main/java/com/djrapitops/plan/api/API.java index a580e4e34..195e9948f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/API.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/API.java @@ -12,7 +12,7 @@ import main.java.com.djrapitops.plan.data.additional.PluginData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; import main.java.com.djrapitops.plan.ui.html.DataRequestHandler; -import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer; +import main.java.com.djrapitops.plan.ui.webserver.WebServer; import main.java.com.djrapitops.plan.utilities.HtmlUtils; import java.sql.SQLException; @@ -25,20 +25,20 @@ import java.util.stream.Collectors; /** * This class contains the API methods. - * + *

* Methods can be called from Asynchronous task and are thread safe unless * otherwise stated. - * + *

* Use Plan.getPlanAPI() to get the API. - * + *

* More information about API methods can be found on GitHub. * * @author Rsl1122 - * @since 2.0.0 * @see PluginData * @see AnalysisType * @see DBCallableProcessor * @see HandlingInfo + * @since 2.0.0 */ public class API { @@ -65,12 +65,12 @@ public class API { /** * Add a source of plugin data to the Plugins tab on Analysis and/or Inspect * page. - * + *

* Refer to documentation on GitHub or Javadoc of PluginData to set-up a * data source that extends PluginData correctly. * * @param dataSource an object that extends PluginData-object, thus allowing - * Analysis and Inspect to manage the data of a plugin correctly. + * Analysis and Inspect to manage the data of a plugin correctly. * @see PluginData */ public void addPluginDataSource(PluginData dataSource) { @@ -81,15 +81,15 @@ public class API { /** * Used to get the link to InspectPage of a player. - * + *

* This method is useful if you have a table and want to link to the inspect * page. + *

+ * Html.LINK.parse("Link", "PlayerName") can be used to get a link + * {@code PlayerName} * - * Html.LINK.parse("Link", "Playername") can be used to get a link - * {@code Playername} - * - * @param name Playername of the player - * @return ip:port/security/player/Playername + * @param name Name of the player + * @return ip:port/security/player/PlayerName */ public String getPlayerInspectPageLink(String name) { return HtmlUtils.getInspectUrlWithProtocol(name); @@ -98,12 +98,12 @@ public class API { /** * Schedule a UserData object to be fetched from the database or cache if * the player is online. - * + *

* The data will not be cached if it is not already cached. * - * @param uuid UUID of the player. + * @param uuid UUID of the player. * @param processor Object implementing DBCallableProcessor, which - * process (UserData data) method will be called. + * process (UserData data) method will be called. */ public void scheduleForGet(UUID uuid, DBCallableProcessor processor) { plugin.getHandler().getUserDataForProcessing(processor, uuid, false); @@ -111,7 +111,7 @@ public class API { /** * Schedule a HandlingInfo object to be processed. - * + *

* UserData associated with the UUID of the HandlingInfo object will be * cached. * @@ -123,11 +123,11 @@ public class API { /** * Used to cache a UserData object. - * + *

* If data is already cached it will be overridden. * * @param data UserData object. Will be placed to the data.getUuid() key in - * the cache. + * the cache. */ public void placeDataToCache(UserData data) { plugin.getHandler().cache(data); @@ -135,7 +135,7 @@ public class API { /** * Used to save the cached data to the database. - * + *

* Should be only called from an Asynchronous thread. */ public void saveCachedData() { @@ -154,7 +154,7 @@ public class API { /** * Cache the UserData to InspectCache. - * + *

* Uses cache if data is cached or database if not. Call from an Asynchronous * thread. * @@ -166,14 +166,14 @@ public class API { /** * Used to get the full Html of the Inspect page as a string. - * + *

* Check if the data is cached to InspectCache before calling this. * * @param uuid UUID of the player. * @return player.html with all placeholders replaced. */ public String getPlayerHtmlAsString(UUID uuid) { - WebSocketServer server = plugin.getUiServer(); + WebServer server = plugin.getUiServer(); if (Verify.notNull(server)) { return server.getDataReqHandler().getInspectHtml(uuid); } @@ -193,7 +193,7 @@ public class API { /** * Run's the analysis with the current data in the cache and fetches rest * from the database. - * + *

* Starts a new Asynchronous task to run the analysis. */ public void updateAnalysisCache() { @@ -202,13 +202,13 @@ public class API { /** * Used to get the full HTML of the Analysis page as a string. - * + *

* Check if the data is cached to AnalysisCache before calling this. * * @return analysis.html with all placeholders replaced. */ public String getAnalysisHtmlAsString() { - WebSocketServer server = plugin.getUiServer(); + WebServer server = plugin.getUiServer(); if (Verify.notNull(server)) { return server.getDataReqHandler().getAnalysisHtml(); } @@ -218,7 +218,7 @@ public class API { /** * Used to get the AnalysisData object. - * + *

* Check if the data is cached to AnalysisCache before calling this. * * @return AnalysisData object. @@ -229,13 +229,13 @@ public class API { } /** - * Used to get the playerName of a player who has played on the server. + * Used to get the PlayerName of a player who has played on the server. * * @param uuid UUID of the player. - * @return Playername, eg "Rsl1122" + * @return PlayerName, eg "Rsl1122" * @throws IllegalArgumentException If uuid is null. - * @throws IllegalStateException If the player has not played on the server - * before. + * @throws IllegalStateException If the player has not played on the server + * before. */ public String getPlayerName(UUID uuid) throws IllegalStateException, IllegalArgumentException { Verify.nullCheck(uuid); @@ -253,13 +253,13 @@ public class API { * @return UUID of the Player * @throws Exception if player's name is not registered at Mojang */ - public UUID playerNameToUUID(String playerName) throws Exception { + public UUID PlayerNameToUUID(String playerName) throws Exception { return UUIDFetcher.getUUIDOf(playerName); } /** * Get the saved UUIDs in the database. - * + *

* Should be called from async thread. * * @return Collection of UUIDs that can be found in the database. @@ -272,9 +272,9 @@ public class API { /** * Get the saved UserData in the database for a collection of UUIDs. - * + *

* Will not contain data for UUIDs not found in the database. - * + *

* Should be called from async thread. * * @param uuids Collection of UUIDs that can be found in the database. @@ -288,7 +288,7 @@ public class API { /** * Get the cached UserData objects in the InspectCache. - * + *

* This can be used with PluginData objects safely to get the data for all * users in Plan database, because all data is InspectCached before analysis * begins. @@ -302,7 +302,7 @@ public class API { /** * Get the cached UserData objects in the InspectCache in a Map form. - * + *

* This can be used with PluginData objects safely to get the data for all * users in Plan database, because all data is InspectCached before analysis * begins. diff --git a/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java b/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java index aea74ca74..346ef4219 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java @@ -14,6 +14,13 @@ import java.util.UUID; */ public class ConditionUtils { + /** + * Constructor used to hide the public constructor + */ + private ConditionUtils() { + throw new IllegalStateException("Utility class"); + } + /** * Check if the plugin can display the data. * diff --git a/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java index bf8c17817..9a840ab58 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java @@ -3,15 +3,16 @@ package main.java.com.djrapitops.plan.command; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; import com.djrapitops.plugin.command.defaultcmds.StatusCommand; +import com.djrapitops.plugin.settings.ColorScheme; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.command.commands.*; /** * TreeCommand for the /plan command, and all subcommands. - * + *

* Uses the Abstract Plugin Framework for easier command management. - * + * * @author Rsl1122 * @since 1.0.0 */ @@ -19,7 +20,7 @@ public class PlanCommand extends TreeCommand { /** * CommandExecutor class Constructor. - * + *

* Initializes Subcommands * * @param plugin Current instance of Plan @@ -27,6 +28,24 @@ public class PlanCommand extends TreeCommand { public PlanCommand(Plan plugin) { super(plugin, "plan", CommandType.CONSOLE, "", "", "plan"); super.setDefaultCommand("inspect"); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "/plan - Main Command", + tCol + " Used to access all SubCommands & help", + sCol + " /plan - List subcommands", + sCol + " /plan ? - in depth help" + }; + + setInDepthHelp(help); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java index 2cb49b8aa..93db0e186 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java @@ -5,21 +5,16 @@ import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; -import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.Permissions; -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.*; import main.java.com.djrapitops.plan.command.ConditionUtils; import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler; import main.java.com.djrapitops.plan.ui.text.TextUI; import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.HtmlUtils; import main.java.com.djrapitops.plan.utilities.MiscUtils; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.command.CommandException; /** * This subcommand is used to run the analysis and access the /server link. @@ -38,9 +33,27 @@ public class AnalyzeCommand extends SubCommand { * @param plugin Current instance of Plan */ public AnalyzeCommand(Plan plugin) { - super("analyze, analyse, analysis", CommandType.CONSOLE, Permissions.ANALYZE.getPermission(), Phrase.CMD_USG_ANALYZE.parse()); + super("analyze, analyse, analysis, a", CommandType.CONSOLE, Permissions.ANALYZE.getPermission(), Phrase.CMD_USG_ANALYZE.parse()); this.plugin = plugin; analysisCache = plugin.getAnalysisCache(); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Analysis Command", + tCol + " Used to Refresh analysis cache & Access the result page", + sCol + " /plan status can be used to check status of analysis while it is running.", + sCol + " Aliases: analyze, analyse, analysis, a" + }; + + setInDepthHelp(help); } @Override @@ -48,30 +61,32 @@ public class AnalyzeCommand extends SubCommand { if (!Check.isTrue(ConditionUtils.pluginHasViewCapability(), Phrase.ERROR_WEBSERVER_OFF_ANALYSIS.toString(), sender)) { return true; } - if (!Check.isTrue(analysisCache.isAnalysisEnabled(), Phrase.ERROR_ANALYSIS_DISABLED_TEMPORARILY.toString(), sender)) { - if (!analysisCache.isCached()) { - return true; - } + + if (!Check.isTrue(analysisCache.isAnalysisEnabled(), Phrase.ERROR_ANALYSIS_DISABLED_TEMPORARILY.toString(), sender) + && !analysisCache.isCached()) { + return true; } sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + ""); - plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") { - @Override - public void run() { - try { - if (CommandUtils.isPlayer(sender)) { - boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName()); - if (!senderHasWebUser) { - sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); + if (plugin.getUiServer().isAuthRequired()) { + plugin.getRunnableFactory().createNew(new AbsRunnable("WebUser exist check task") { + @Override + public void run() { + try { + if (CommandUtils.isPlayer(sender)) { + boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName()); + if (!senderHasWebUser) { + sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); + } } + } catch (Exception e) { + Log.toLog(this.getClass().getName() + getName(), e); + } finally { + this.cancel(); } - } catch (Exception e) { - Log.toLog(this.getClass().getName() + getName(), e); - } finally { - this.cancel(); } - } - }).runTaskAsynchronously(); + }).runTaskAsynchronously(); + } updateCache(); runMessageSenderTask(sender); return true; @@ -110,7 +125,7 @@ public class AnalyzeCommand extends SubCommand { /** * Used to send the message after /plan analysis. - * + *

* Final because * * @param sender Command sender. @@ -129,17 +144,9 @@ public class AnalyzeCommand extends SubCommand { sender.sendMessage(message + url); } else { sender.sendMessage(message); - sendLink(sender, url); + sender.sendLink(" ", Phrase.CMD_CLICK_ME.toString(), url); } } - sender.sendMessage(Phrase.CMD_FOOTER + ""); - } - - @Deprecated // TODO Will be rewritten to the RslPlugin abstractions in the future. - private void sendLink(ISender sender, String url) throws CommandException { - plugin.getServer().dispatchCommand( - Bukkit.getConsoleSender(), - "tellraw " + sender.getName() + " [\"\",{\"text\":\"" + Phrase.CMD_CLICK_ME + "\",\"underlined\":true," - + "\"clickEvent\":{\"action\":\"open_url\",\"value\":\"" + url + "\"}}]"); + sender.sendMessage(Phrase.CMD_FOOTER.toString()); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java index c4d4d84de..9a59230f7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java @@ -34,11 +34,11 @@ public class InfoCommand extends SubCommand { public boolean onCommand(ISender sender, String commandLabel, String[] args) { ChatColor tColor = Phrase.COLOR_SEC.color(); String[] messages = { - Phrase.CMD_INFO_HEADER.toString(), - Phrase.CMD_INFO_VERSION.parse(plugin.getDescription().getVersion()), - Phrase.CMD_BALL.toString() + tColor + " " + Version.checkVersion(plugin), - Phrase.CMD_MANAGE_STATUS_ACTIVE_DB.parse(plugin.getDB().getConfigName()), - Phrase.CMD_FOOTER.toString() + Phrase.CMD_INFO_HEADER.toString(), + Phrase.CMD_INFO_VERSION.parse(plugin.getDescription().getVersion()), + Phrase.CMD_BALL.toString() + tColor + " " + Version.checkVersion(plugin), + Phrase.CMD_MANAGE_STATUS_ACTIVE_DB.parse(plugin.getDB().getConfigName()), + Phrase.CMD_FOOTER.toString() }; sender.sendMessage(messages); return true; diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java index d6d8383bc..9a16ff96a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java @@ -5,6 +5,7 @@ import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.*; @@ -15,9 +16,7 @@ import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.HtmlUtils; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.command.CommandException; import java.sql.SQLException; import java.util.UUID; @@ -43,6 +42,24 @@ public class InspectCommand extends SubCommand { this.plugin = plugin; inspectCache = plugin.getInspectCache(); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Inspect command", + tCol + " Used to get a link to User's inspect page.", + sCol + " Own inspect page can be accessed with /plan inspect", + sCol + " Alias: /plan " + }; + + super.setInDepthHelp(help); } @Override @@ -72,8 +89,8 @@ public class InspectCommand extends SubCommand { if (!Check.isTrue(plugin.getDB().wasSeenBefore(uuid), Phrase.USERNAME_NOT_KNOWN.toString(), sender)) { return; } - sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE + ""); - if (CommandUtils.isPlayer(sender)) { + sender.sendMessage(Phrase.GRABBING_DATA_MESSAGE.toString()); + if (CommandUtils.isPlayer(sender) && plugin.getUiServer().isAuthRequired()) { boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName()); if (!senderHasWebUser) { sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); @@ -123,24 +140,16 @@ public class InspectCommand extends SubCommand { } else { // Link String url = HtmlUtils.getInspectUrlWithProtocol(playerName); - String message = Phrase.CMD_LINK + ""; + String message = Phrase.CMD_LINK.toString(); boolean console = !CommandUtils.isPlayer(sender); if (console) { sender.sendMessage(message + url); } else { sender.sendMessage(message); - sendLink(sender, url); + sender.sendLink(" ", Phrase.CMD_CLICK_ME.toString(), url); } } - sender.sendMessage(Phrase.CMD_FOOTER + ""); + sender.sendMessage(Phrase.CMD_FOOTER.toString()); } - - @Deprecated // TODO Will be rewritten to the RslPlugin abstractions in the future. - private void sendLink(ISender sender, String url) throws CommandException { - plugin.getServer().dispatchCommand( - Bukkit.getConsoleSender(), - "tellraw " + sender.getName() + " [\"\",{\"text\":\"" + Phrase.CMD_CLICK_ME + "\",\"underlined\":true," - + "\"clickEvent\":{\"action\":\"open_url\",\"value\":\"" + url + "\"}}]"); - } -} +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java index 45de5380c..7c805e4b2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java @@ -4,36 +4,50 @@ import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.command.ConditionUtils; import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.HtmlUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandException; /** * Command used to display link to the player list webpage. - * + *

* Subcommand is not registered if Webserver is not enabled. - * + * * @author Rsl1122 * @since 3.5.2 */ public class ListCommand extends SubCommand { - private final Plan plugin; - /** * Class Constructor. * * @param plugin Current instance of Plan */ public ListCommand(Plan plugin) { - super("list", CommandType.CONSOLE, Permissions.INSPECT_OTHER.getPermission(), "List to all cached players", ""); + super("list, pl", CommandType.CONSOLE, Permissions.INSPECT_OTHER.getPermission(), "List to all cached players", ""); - this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "List command", + tCol + " Used to get a link to players page.", + sCol + " Players page contains links to all cached inspect pages.", + sCol + " Alias: /plan pl" + }; + + setInDepthHelp(help); } @Override @@ -50,22 +64,14 @@ public class ListCommand extends SubCommand { // Link String url = HtmlUtils.getServerAnalysisUrlWithProtocol().replace("server", "players"); - String message = Phrase.CMD_LINK + ""; + String message = Phrase.CMD_LINK.toString(); boolean console = !CommandUtils.isPlayer(sender); if (console) { sender.sendMessage(message + url); } else { sender.sendMessage(message); - sendLink(sender, url); + sender.sendLink(" ", Phrase.CMD_CLICK_ME.toString(), url); } - sender.sendMessage(Phrase.CMD_FOOTER + ""); - } - - @Deprecated // TODO Will be rewritten to the RslPlugin abstractions in the future. - private void sendLink(ISender sender, String url) throws CommandException { - plugin.getServer().dispatchCommand( - Bukkit.getConsoleSender(), - "tellraw " + sender.getName() + " [\"\",{\"text\":\"" + Phrase.CMD_CLICK_ME + "\",\"underlined\":true," - + "\"clickEvent\":{\"action\":\"open_url\",\"value\":\"" + url + "\"}}]"); + sender.sendMessage(Phrase.CMD_FOOTER.toString()); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java index e3eb1df36..e476ac497 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java @@ -2,6 +2,7 @@ package main.java.com.djrapitops.plan.command.commands; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; +import com.djrapitops.plugin.settings.ColorScheme; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Plan; @@ -9,7 +10,7 @@ import main.java.com.djrapitops.plan.command.commands.manage.*; /** * This command is used to manage the database of the plugin. - * + *

* No arguments will run ManageHelpCommand. Contains subcommands. * * @author Rsl1122 @@ -24,6 +25,25 @@ public class ManageCommand extends TreeCommand { */ public ManageCommand(Plan plugin) { super(plugin, "manage,m", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE + "", "plan m"); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Manage command", + tCol + " Used to Manage Database of the plugin.", + sCol + " Alias: /plan m", + sCol + " /plan m - List subcommands", + sCol + " /plan m ? - in depth help" + }; + + setInDepthHelp(help); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickAnalyzeCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickAnalyzeCommand.java index 5dc463a20..150543275 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickAnalyzeCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickAnalyzeCommand.java @@ -4,6 +4,7 @@ import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Permissions; @@ -33,21 +34,39 @@ public class QuickAnalyzeCommand extends SubCommand { * @param plugin Current instance of Plan */ public QuickAnalyzeCommand(Plan plugin) { - super("qanalyze, qanalyse, qanalysis", CommandType.CONSOLE, Permissions.QUICK_ANALYZE.getPermission(), Phrase.CMD_USG_QANALYZE.parse()); + super("qanalyze, qanalyse, qanalysis, qa", CommandType.CONSOLE, Permissions.QUICK_ANALYZE.getPermission(), Phrase.CMD_USG_QANALYZE.parse()); this.plugin = plugin; analysisCache = plugin.getAnalysisCache(); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Quick Analysis command", + tCol + " Used to get in game info about analysis.", + sCol + " Has less info than full Analysis web page.", + sCol + " Aliases: qanalyze, ganalyse, qanalysis, qa" + }; + + setInDepthHelp(help); } @Override public boolean onCommand(ISender sender, String commandLabel, String[] args) { - if (!Check.isTrue(ConditionUtils.pluginHasViewCapability(), Phrase.ERROR_WEBSERVER_OFF_ANALYSIS + "", sender)) { + if (!Check.isTrue(ConditionUtils.pluginHasViewCapability(), Phrase.ERROR_WEBSERVER_OFF_ANALYSIS.toString(), sender)) { return true; } - if (!Check.isTrue(analysisCache.isAnalysisEnabled(), Phrase.ERROR_ANALYSIS_DISABLED_TEMPORARILY + "", sender)) { - if (!analysisCache.isCached()) { - return true; - } + if (!Check.isTrue(analysisCache.isAnalysisEnabled(), Phrase.ERROR_ANALYSIS_DISABLED_TEMPORARILY.toString(), sender) + && !analysisCache.isCached()) { + return true; } + updateCache(); runMessageSenderTask(sender); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickInspectCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickInspectCommand.java index 6cbb363e6..10b35dc39 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickInspectCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/QuickInspectCommand.java @@ -4,9 +4,9 @@ import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.Verify; -import java.util.UUID; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Phrase; @@ -18,6 +18,8 @@ import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility; +import java.util.UUID; + /** * This command is used to cache UserData to InspectCache and to view some of * the data in game. @@ -36,10 +38,28 @@ public class QuickInspectCommand extends SubCommand { * @param plugin Current instance of Plan */ public QuickInspectCommand(Plan plugin) { - super("qinspect", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.QUICK_INSPECT.getPermission(), Phrase.CMD_USG_QINSPECT + "", Phrase.ARG_PLAYER + ""); + super("qinspect, qi", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.QUICK_INSPECT.getPermission(), Phrase.CMD_USG_QINSPECT + "", Phrase.ARG_PLAYER + ""); this.plugin = plugin; inspectCache = plugin.getInspectCache(); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Quick Inspect command", + tCol + " Used to get some inspect info in game.", + sCol + " Has less info than full Inspect web page.", + sCol + " Alias: /plan qi" + }; + + setInDepthHelp(help); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java index 1d007417f..55021ed41 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java @@ -4,6 +4,7 @@ import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Permissions; @@ -17,11 +18,11 @@ import org.bukkit.ChatColor; /** * Command for registering web users. - * + *

* Registers a new webuser to the database. - * + *

* No permission required for self registration. (Constructor string is empty) - * + *

* plan.webmanage required for registering other users. * * @author Rsl1122 @@ -34,6 +35,24 @@ public class RegisterCommand extends SubCommand { public RegisterCommand(Plan plugin) { super("register", CommandType.CONSOLE_WITH_ARGUMENTS, "", "Register a user for the webserver", " [name] [access lvl]"); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Web Register command", + tCol + " Used to register a new user for the webserver.", + sCol + " Registering a user for another player requires " + Permissions.MANAGE_WEB.getPerm() + " permission.", + sCol + " Passwords are hashed with PBKDF2 (64,000 iterations of SHA1) using a cryptographically-random salt." + }; + + setInDepthHelp(help); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommandFilter.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommandFilter.java index e099cff5c..377c321bf 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommandFilter.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommandFilter.java @@ -1,23 +1,73 @@ package main.java.com.djrapitops.plan.command.commands; -import java.util.logging.Filter; -import java.util.logging.LogRecord; +import com.google.common.collect.ImmutableSet; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.filter.AbstractFilter; +import org.apache.logging.log4j.message.Message; + +import java.util.Set; /** * Filters out WebUser registration command logs. - * + * * @author Rsl1122 * @since 3.5.2 */ -public class RegisterCommandFilter implements Filter { +public class RegisterCommandFilter extends AbstractFilter { + + private final Set censoredCommands = ImmutableSet.of("/plan web register", "/plan webuser register", "/plan register"); @Override - public boolean isLoggable(LogRecord record) { - String message = record.getMessage(); - boolean block = message.contains("command: /plan register") - || message.contains("command: /plan web register") - || message.contains("command: /plan webuser register"); - return !block; + public Result filter(LogEvent event) { + if (event == null) { + return Result.NEUTRAL; + } + + return validateMessage(event.getMessage()); + } + + @Override + public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { + return validateMessage(msg); + } + + @Override + public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) { + return validateMessage(msg); + } + + @Override + public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { + if (msg == null) { + return Result.NEUTRAL; + } + + return validateMessage(msg.toString()); + } + + private Result validateMessage(Message message) { + if (message == null) { + return Result.NEUTRAL; + } + + return validateMessage(message.getFormattedMessage()); + } + + private Result validateMessage(String message) { + return isSensibleCommand(message) + ? Result.DENY + : Result.NEUTRAL; + } + + private boolean isSensibleCommand(String message) { + message = message.toLowerCase(); + return message.contains("issued server command:") && isSensible(message); + } + + private boolean isSensible(String message) { + return censoredCommands.stream().anyMatch(message::contains); } - } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java index d05af963f..b5f9561d1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java @@ -23,7 +23,7 @@ public class ReloadCommand extends SubCommand { * @param plugin Current instance of Plan */ public ReloadCommand(Plan plugin) { - super("reload", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_RELOAD + ""); + super("reload", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_RELOAD.toString()); this.plugin = plugin; } @@ -33,7 +33,7 @@ public class ReloadCommand extends SubCommand { plugin.onDisable(); plugin.reloadConfig(); plugin.onEnable(); - sender.sendMessage(Phrase.RELOAD_COMPLETE + ""); + sender.sendMessage(Phrase.RELOAD_COMPLETE.toString()); return true; } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java index 6f4c42949..9b10e0b76 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java @@ -3,16 +3,18 @@ package main.java.com.djrapitops.plan.command.commands; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.FormattingUtils; -import java.util.Arrays; -import java.util.List; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.utilities.Check; import main.java.com.djrapitops.plan.utilities.MiscUtils; +import java.util.Arrays; +import java.util.List; + /** * This subcommand is used to search for a user, and to view all matches' data. * @@ -29,8 +31,25 @@ public class SearchCommand extends SubCommand { * @param plugin Current instance of Plan */ public SearchCommand(Plan plugin) { - super("search", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.SEARCH.getPermission(), Phrase.CMD_USG_SEARCH + "", Phrase.ARG_SEARCH + ""); + super("search", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.SEARCH.getPermission(), Phrase.CMD_USG_SEARCH.toString(), Phrase.ARG_SEARCH.toString()); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Search command", + tCol + " Used to get a list of Player names that match the given argument.", + sCol + " Example: /plan search 123 - Finds all users with 123 in their name." + }; + + setInDepthHelp(help); } @Override @@ -38,7 +57,7 @@ public class SearchCommand extends SubCommand { if (!Check.isTrue(args.length >= 1, Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString(), sender)) { return true; } - sender.sendMessage(Phrase.CMD_SEARCH_SEARCHING + ""); + sender.sendMessage(Phrase.CMD_SEARCH_SEARCHING.toString()); runSearchTask(args, sender); return true; @@ -55,9 +74,10 @@ public class SearchCommand extends SubCommand { if (names.isEmpty()) { sender.sendMessage(Phrase.CMD_NO_RESULTS.parse(Arrays.toString(args))); } else { - sender.sendMessage(Phrase.CMD_MATCH + "" + FormattingUtils.collectionToStringNoBrackets(names)); + sender.sendMessage(Phrase.CMD_MATCH.toString() + FormattingUtils.collectionToStringNoBrackets(names)); } - sender.sendMessage(Phrase.CMD_FOOTER + ""); + + sender.sendMessage(Phrase.CMD_FOOTER.toString()); } finally { this.cancel(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java index b2f485de3..7aa69b078 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java @@ -2,6 +2,7 @@ package main.java.com.djrapitops.plan.command.commands; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; +import com.djrapitops.plugin.settings.ColorScheme; import main.java.com.djrapitops.plan.Permissions; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.command.commands.webuser.WebCheckCommand; @@ -20,6 +21,27 @@ public class WebUserCommand extends TreeCommand { public WebUserCommand(Plan plugin, RegisterCommand register) { super(plugin, "webuser, web", CommandType.CONSOLE, Permissions.MANAGE_WEB.getPerm(), "Manage Webusers", "plan web"); commands.add(register); + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Web User Manage command", + tCol + " Used to manage web users of the plugin", + sCol + " Users have a permission level:", + tCol + " 0 - Access to all pages", + tCol + " 1 - Access to /players & all inspect pages", + tCol + " 2 - Access to own inspect page", + sCol + " Alias: /plan web" + }; + + setInDepthHelp(help); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageCleanCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageCleanCommand.java index 4da62da1a..d529912f8 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageCleanCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageCleanCommand.java @@ -39,6 +39,7 @@ public class ManageCleanCommand extends SubCommand { if (!Check.isTrue(args.length != 0, Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString(), sender)) { return true; } + String dbName = args[0].toLowerCase(); boolean isCorrectDB = "sqlite".equals(dbName) || "mysql".equals(dbName); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java index 4bbe0ae39..6aba02654 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.command.commands.manage; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.Log; @@ -32,11 +33,29 @@ public class ManageClearCommand extends SubCommand { super("clear", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_CLEAR + "", " [-a]"); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Manage Clear command", + tCol + " Used to delete ALL data in the active database.", + sCol + " Plugin should be reloaded after successful clear.", + sCol + " Alias: /plan pl" + }; + + setInDepthHelp(help); } @Override public boolean onCommand(ISender sender, String commandLabel, String[] args) { - if (!Check.isTrue(args.length >= 1, Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE + "", sender)) { + if (!Check.isTrue(args.length >= 1, Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString(), sender)) { return true; } @@ -54,7 +73,7 @@ public class ManageClearCommand extends SubCommand { final Database database = ManageUtils.getDB(plugin, dbName); // If DB is null return - if (!Check.isTrue(Verify.notNull(database), Phrase.MANAGE_DATABASE_FAILURE + "", sender)) { + if (!Check.isTrue(Verify.notNull(database), Phrase.MANAGE_DATABASE_FAILURE.toString(), sender)) { Log.error(dbName + " was null!"); return true; } @@ -71,6 +90,7 @@ public class ManageClearCommand extends SubCommand { sender.sendMessage(Phrase.MANAGE_PROCESS_START.parse()); if (database.removeAllData()) { + plugin.getHandler().getDataCache().clear(); sender.sendMessage(Phrase.MANAGE_CLEAR_SUCCESS.toString()); } else { sender.sendMessage(Phrase.MANAGE_PROCESS_FAIL.toString()); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java index b9bf70b64..a08f59a83 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.command.commands.manage; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Permissions; @@ -32,6 +33,23 @@ public class ManageHotswapCommand extends SubCommand { super("hotswap", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_HOTSWAP.toString(), ""); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Manage Hotswap command", + tCol + " Used to change database in use on the fly.", + sCol + " Does not change database if connection fails" + }; + + setInDepthHelp(help); } @Override @@ -46,7 +64,7 @@ public class ManageHotswapCommand extends SubCommand { return true; } - if (Check.isTrue(dbName.equals(plugin.getDB().getConfigName()), Phrase.MANAGE_ERROR_SAME_DB + "", sender)) { + if (Check.isTrue(dbName.equals(plugin.getDB().getConfigName()), Phrase.MANAGE_ERROR_SAME_DB.toString(), sender)) { return true; } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java index 671f422a3..e13d5baf7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.command.commands.manage; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.FormattingUtils; import com.djrapitops.plugin.utilities.player.Fetch; @@ -21,7 +22,7 @@ import java.util.stream.Collectors; /** * This manage subcommand is used to import data from 3rd party plugins. - * + *

* Supported plugins (v3.0.0) : OnTime * * @author Rsl1122 @@ -39,6 +40,24 @@ public class ManageImportCommand extends SubCommand { public ManageImportCommand(Plan plugin) { super("import", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_IMPORT.toString(), Phrase.ARG_IMPORT.toString()); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String sCol = colorScheme.getSecondaryColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Manage Import command", + tCol + " Used to import data from other sources", + sCol + " Analysis will be disabled during import.", + sCol + " If a lot of users are not in the database, saving may take a long time." + }; + + setInDepthHelp(help); } @Override @@ -58,6 +77,7 @@ public class ManageImportCommand extends SubCommand { if (!Check.isTrue(importPlugins.keySet().contains(importFromPlugin), Phrase.MANAGE_ERROR_INCORRECT_PLUGIN + importFromPlugin, sender)) { return true; } + if (!Check.isTrue(ImportUtils.isPluginEnabled(importFromPlugin), Phrase.MANAGE_ERROR_PLUGIN_NOT_ENABLED + importFromPlugin, sender)) { return true; } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java index a91c2a744..a0c10ff11 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java @@ -18,7 +18,7 @@ import java.util.UUID; /** * This manage subcommand is used to move all data from one database to another. - * + *

* Destination database will be cleared. * * @author Rsl1122 @@ -58,9 +58,11 @@ public class ManageMoveCommand extends SubCommand { if (!Check.isTrue(isCorrectDB, Phrase.MANAGE_ERROR_INCORRECT_DB + toDB, sender)) { return true; } + if (!Check.isTrue(!Verify.equalsIgnoreCase(fromDB, toDB), Phrase.MANAGE_ERROR_SAME_DB.toString(), sender)) { return true; } + if (!Check.isTrue(Verify.contains("-a", args), Phrase.COMMAND_ADD_CONFIRMATION_ARGUMENT.parse(Phrase.WARN_REMOVE.parse(args[1])), sender)) { return true; } @@ -92,9 +94,11 @@ public class ManageMoveCommand extends SubCommand { if (Check.isTrue(Verify.isEmpty(uuids), Phrase.MANAGE_ERROR_NO_PLAYERS + " (" + fromDatabase.getName() + ")", sender)) { return; } + sender.sendMessage(Phrase.MANAGE_PROCESS_START.parse()); + if (ManageUtils.clearAndCopy(toDatabase, fromDatabase, uuids)) { - sender.sendMessage(Phrase.MANAGE_MOVE_SUCCESS + ""); + sender.sendMessage(Phrase.MANAGE_MOVE_SUCCESS.toString()); boolean movedToCurrentDatabase = Verify.equalsIgnoreCase(toDatabase.getConfigName(), plugin.getDB().getConfigName()); Check.isTrue(!movedToCurrentDatabase, Phrase.MANAGE_DB_CONFIG_REMINDER.toString(), sender); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java index a66b6cc52..30e6afc1c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.command.commands.manage; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; +import com.djrapitops.plugin.settings.ColorScheme; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.Log; @@ -35,6 +36,21 @@ public class ManageRemoveCommand extends SubCommand { super("remove", CommandType.CONSOLE_WITH_ARGUMENTS, Permissions.MANAGE.getPermission(), Phrase.CMD_USG_MANAGE_REMOVE.toString(), Phrase.ARG_PLAYER + " [-a]"); this.plugin = plugin; + setHelp(plugin); + } + + private void setHelp(Plan plugin) { + ColorScheme colorScheme = plugin.getColorScheme(); + + String mCol = colorScheme.getMainColor(); + String tCol = colorScheme.getTertiaryColor(); + + String[] help = new String[]{ + mCol + "Manage Remove command", + tCol + " Used to Remove user's data from the active database." + }; + + setInDepthHelp(help); } @Override @@ -56,13 +72,16 @@ public class ManageRemoveCommand extends SubCommand { try { UUID uuid = UUIDUtility.getUUIDOf(playerName); String message = Phrase.USERNAME_NOT_VALID.toString(); + if (!Check.isTrue(Verify.notNull(uuid), message, sender)) { return; } + message = Phrase.USERNAME_NOT_KNOWN.toString(); if (!Check.isTrue(plugin.getDB().wasSeenBefore(uuid), message, sender)) { return; } + message = Phrase.COMMAND_ADD_CONFIRMATION_ARGUMENT.parse(Phrase.WARN_REMOVE.parse(plugin.getDB().getConfigName())); if (!Check.isTrue(Verify.contains("-a", args), message, sender)) { return; diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java index 3ef71609f..f0a96c11b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java @@ -44,12 +44,14 @@ public class ManageRestoreCommand extends SubCommand { if (!Check.isTrue(args.length >= 2, Phrase.COMMAND_REQUIRES_ARGUMENTS.parse(Phrase.USE_RESTORE.toString()), sender)) { return true; } + String db = args[1].toLowerCase(); boolean isCorrectDB = "sqlite".equals(db) || "mysql".equals(db); if (!Check.isTrue(isCorrectDB, Phrase.MANAGE_ERROR_INCORRECT_DB + db, sender)) { return true; } + if (!Check.isTrue(Verify.contains("-a", args), Phrase.COMMAND_ADD_CONFIRMATION_ARGUMENT.parse(Phrase.WARN_REWRITE.parse(args[1])), sender)) { return true; } @@ -71,7 +73,7 @@ public class ManageRestoreCommand extends SubCommand { public void run() { try { String backupDBName = args[0]; - boolean containsDBFileExtension = backupDBName.contains(".db"); + boolean containsDBFileExtension = backupDBName.endsWith(".db"); File backupDBFile = new File(plugin.getDataFolder(), backupDBName + (containsDBFileExtension ? "" : ".db")); if (!Check.isTrue(Verify.exists(backupDBFile), Phrase.MANAGE_ERROR_BACKUP_FILE_NOT_FOUND + " " + args[0], sender)) { @@ -79,22 +81,27 @@ public class ManageRestoreCommand extends SubCommand { } if (containsDBFileExtension) { - backupDBName = backupDBName.replace(".db", ""); + backupDBName = backupDBName.substring(0, backupDBName.length() - 3); } + SQLiteDB backupDB = new SQLiteDB(plugin, backupDBName); if (!backupDB.init()) { sender.sendMessage(Phrase.MANAGE_DATABASE_FAILURE.toString()); return; } + sender.sendMessage(Phrase.MANAGE_PROCESS_START.parse()); + final Collection uuids = ManageUtils.getUUIDS(backupDB); if (!Check.isTrue(!Verify.isEmpty(uuids), Phrase.MANAGE_ERROR_NO_PLAYERS + " (" + backupDBName + ")", sender)) { return; } + if (ManageUtils.clearAndCopy(database, backupDB, uuids)) { if (database.getConfigName().equals(plugin.getDB().getConfigName())) { plugin.getHandler().getCommandUseFromDb(); } + sender.sendMessage(Phrase.MANAGE_COPY_SUCCESS.toString()); } else { sender.sendMessage(Phrase.MANAGE_PROCESS_FAIL.toString()); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageStatusCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageStatusCommand.java index 149e52d07..588205953 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageStatusCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageStatusCommand.java @@ -30,13 +30,13 @@ public class ManageStatusCommand extends SubCommand { @Override public boolean onCommand(ISender sender, String commandLabel, String[] args) { String[] messages = new String[]{ - Phrase.CMD_MANAGE_STATUS_HEADER.toString(), - 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.toString() + Phrase.CMD_MANAGE_STATUS_HEADER.toString(), + Phrase.CMD_MANAGE_STATUS_ACTIVE_DB.parse(plugin.getDB().getConfigName()), + Phrase.CMD_MANAGE_STATUS_QUEUE_PROCESS.parse(String.valueOf(plugin.getHandler().getProcessTask().size())), + Phrase.CMD_MANAGE_STATUS_QUEUE_SAVE.parse(String.valueOf(plugin.getHandler().getSaveTask().size())), + Phrase.CMD_MANAGE_STATUS_QUEUE_GET.parse(String.valueOf(plugin.getHandler().getGetTask().size())), + Phrase.CMD_MANAGE_STATUS_QUEUE_CLEAR.parse(String.valueOf(plugin.getHandler().getClearTask().size())), + Phrase.CMD_FOOTER.toString() }; sender.sendMessage(messages); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java index 810070e63..56bccddf2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java @@ -29,12 +29,12 @@ public class WebLevelCommand extends SubCommand { String sCol = cs.getSecondaryColor(); String cmdBall = Phrase.CMD_BALL.parse(); String[] messages = new String[]{ - Phrase.CMD_FOOTER.parse(), - cmdBall + sCol + "0: Access all pages", - cmdBall + sCol + "1: Access '/players' and all inspect pages", - cmdBall + sCol + "2: Access inspect page with the same username as the webuser", - cmdBall + sCol + "3+: No permissions", - Phrase.CMD_FOOTER.parse() + Phrase.CMD_FOOTER.parse(), + cmdBall + sCol + "0: Access all pages", + cmdBall + sCol + "1: Access '/players' and all inspect pages", + cmdBall + sCol + "2: Access inspect page with the same username as the webuser", + cmdBall + sCol + "3+: No permissions", + Phrase.CMD_FOOTER.parse() }; sender.sendMessage(messages); return true; diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java index 1a2a98d60..c34f18b19 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java @@ -37,7 +37,6 @@ public class WebListUsersCommand extends SubCommand { try { ColorScheme cs = plugin.getColorScheme(); String mCol = cs.getMainColor(); - String sCol = cs.getSecondaryColor(); List users = plugin.getDB().getSecurityTable().getUsers(); users.sort(new WebUserComparator()); sender.sendMessage(Phrase.CMD_FOOTER.parse() + mCol + " WebUsers (" + users.size() + ")"); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java b/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java index 83f58ea2f..b740fabaa 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java @@ -13,27 +13,19 @@ import java.util.Map; /** * Big container object for Data. - * + *

* Contains parts that can be analysed. Each part has their own purpose. - * + *

* Parts contain variables that can be added to. These variables are then * analysed using the analysis method. - * + *

* After being analysed the ReplaceMap can be retrieved for replacing * placeholders on the analysis.html file. * * @author Rsl1122 * @since 3.5.2 */ -public class AnalysisData extends RawData { - - private long refreshDate; - - private String planVersion; - private String pluginsTabLayout; - private Map additionalDataReplaceMap; - - private String playersTable; +public class AnalysisData extends RawData { private final ActivityPart activityPart; private final CommandUsagePart commandUsagePart; @@ -44,6 +36,12 @@ public class AnalysisData extends RawData { private final PlayerCountPart playerCountPart; private final PlaytimePart playtimePart; private final TPSPart tpsPart; + private final WorldPart worldPart; + private long refreshDate; + private String planVersion; + private String pluginsTabLayout; + private Map additionalDataReplaceMap; + private String playersTable; public AnalysisData(Map commandUsage, List tpsData) { commandUsagePart = new CommandUsagePart(commandUsage); @@ -55,6 +53,7 @@ public class AnalysisData extends RawData { gamemodePart = new GamemodePart(); tpsPart = new TPSPart(tpsData); activityPart = new ActivityPart(joinInfoPart, tpsPart); + worldPart = new WorldPart(); } public ActivityPart getActivityPart() { @@ -93,12 +92,14 @@ public class AnalysisData extends RawData { return tpsPart; } + public WorldPart getWorldPart() { + return worldPart; + } + public List getAllParts() { - return Arrays.asList(new RawData[]{ - activityPart, commandUsagePart, gamemodePart, - geolocationPart, joinInfoPart, killPart, - playerCountPart, playtimePart, tpsPart - }); + return Arrays.asList(activityPart, commandUsagePart, gamemodePart, + geolocationPart, joinInfoPart, killPart, + playerCountPart, playtimePart, tpsPart, worldPart); } public String getPlanVersion() { @@ -125,10 +126,6 @@ public class AnalysisData extends RawData { this.additionalDataReplaceMap = additionalDataReplaceMap; } - public void setRefreshDate(long refreshDate) { - this.refreshDate = refreshDate; - } - public void setPlayersTable(String playersTable) { this.playersTable = playersTable; } @@ -143,7 +140,7 @@ public class AnalysisData extends RawData { addValue("version", planVersion); final List parts = getAllParts(); - parts.forEach((part) -> { + parts.forEach(part -> { try { Benchmark.start("Analysis Phase: " + part.getClass().getSimpleName()); part.analyseData(); @@ -166,4 +163,8 @@ public class AnalysisData extends RawData { public long getRefreshDate() { return refreshDate; } + + public void setRefreshDate(long refreshDate) { + this.refreshDate = refreshDate; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/KillData.java b/Plan/src/main/java/com/djrapitops/plan/data/KillData.java index cf3f340e0..72f6a2844 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/KillData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/KillData.java @@ -19,10 +19,10 @@ public class KillData { /** * Creates a KillData object with given parameters. * - * @param victim UUID of the victim. + * @param victim UUID of the victim. * @param victimID ID of the victim, get from the database. - * @param weapon Weapon used. - * @param date Epoch millisecond at which the kill occurred. + * @param weapon Weapon used. + * @param date Epoch millisecond at which the kill occurred. */ public KillData(UUID victim, int victimID, String weapon, long date) { this.victim = victim; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/SessionData.java b/Plan/src/main/java/com/djrapitops/plan/data/SessionData.java index 549222a06..253a10100 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/SessionData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/SessionData.java @@ -1,7 +1,7 @@ package main.java.com.djrapitops.plan.data; /** - * This class is used for storing start and end of a playsession inside UserData + * This class is used for storing start and end of a play session inside UserData * object. * * @author Rsl1122 @@ -25,7 +25,7 @@ public class SessionData { * Creates a new session with given start and end. * * @param sessionStart Epoch millisecond the session was started. - * @param sessionEnd Epoch millisecond the session ended. + * @param sessionEnd Epoch millisecond the session ended. */ public SessionData(long sessionStart, long sessionEnd) { this.sessionStart = sessionStart; @@ -44,7 +44,7 @@ public class SessionData { /** * Ends the session with given end point. - * + *

* (Changes the end to the parameter.). * * @param endOfSession Epoch millisecond the session ended. diff --git a/Plan/src/main/java/com/djrapitops/plan/data/TPS.java b/Plan/src/main/java/com/djrapitops/plan/data/TPS.java index 798bcd821..7c8bf34cd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/TPS.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/TPS.java @@ -6,7 +6,7 @@ package main.java.com.djrapitops.plan.data; /** - * Class containing single datapoint of TPS/players online. + * Class containing single datapoint of TPS / Players online / CPU Usage / Used Memory / Entity Count / Chunks loaded. * * @author Rsl1122 * @since 3.5.0 @@ -17,20 +17,29 @@ public class TPS { private final double tps; private final int players; private final double cpuUsage; + private final long usedMemory; + private final int entityCount; + private final int chunksLoaded; /** * Constructor. * - * @param date time of the average calculation. - * @param tps average tps for the last minute. - * @param players average players for the last minute. - * @param cpuUsage average CPU usage for the last minute. + * @param date time of the TPS calculation. + * @param tps average tps for the last minute. + * @param players players for the minute. + * @param cpuUsage CPU usage for the minute + * @param usedMemory used memory at the time of fetching + * @param entityCount amount of entities at the time of fetching + * @param chunksLoaded amount of chunks loaded at the time of fetching */ - public TPS(long date, double tps, int players, double cpuUsage) { + public TPS(long date, double tps, int players, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded) { this.date = date; this.tps = tps; this.players = players; this.cpuUsage = cpuUsage; + this.usedMemory = usedMemory; + this.entityCount = entityCount; + this.chunksLoaded = chunksLoaded; } /** @@ -52,7 +61,7 @@ public class TPS { } /** - * Get the average players for the minute. + * Get the player for the time, when the data was fetched. * * @return Players online. */ @@ -61,14 +70,41 @@ public class TPS { } /** - * Get the average CPU Usage for the minute. + * Get the average CPU Usage for the minute * - * @return 0-20 double + * @return 0-100 double */ public double getCPUUsage() { return cpuUsage; } + /** + * Get the used memory for the time, when the data was fetched. + * + * @return Used Memory in Megabyte + */ + public long getUsedMemory() { + return usedMemory; + } + + /** + * Get the amount of entities for the time, when the data was fetched + * + * @return Amount of entities + */ + public int getEntityCount() { + return entityCount; + } + + /** + * Get the amount of chunks loaded for the time, when the data was fetched + * + * @return Amount of chunks loaded + */ + public int getChunksLoaded() { + return chunksLoaded; + } + @Override public int hashCode() { int hash = 3; @@ -83,17 +119,20 @@ public class TPS { if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + final TPS other = (TPS) obj; - return this.date == other.date - && Double.doubleToLongBits(this.tps) == Double.doubleToLongBits(other.tps) + return date == other.date + && Double.compare(this.tps, other.tps) == 0 && this.players == other.players - && this.cpuUsage == other.cpuUsage; + && Double.compare(cpuUsage, other.cpuUsage) == 0; } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/data/UserData.java b/Plan/src/main/java/com/djrapitops/plan/data/UserData.java index 72fc3536b..24fe2c229 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/UserData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/UserData.java @@ -4,6 +4,8 @@ import com.djrapitops.plugin.utilities.Verify; import com.djrapitops.plugin.utilities.player.IOfflinePlayer; import com.djrapitops.plugin.utilities.player.IPlayer; import main.java.com.djrapitops.plan.Log; +import main.java.com.djrapitops.plan.data.time.GMTimes; +import main.java.com.djrapitops.plan.data.time.WorldTimes; import java.net.InetAddress; import java.util.*; @@ -20,85 +22,85 @@ public class UserData { private boolean clearAfterSave; private UUID uuid; - private Set ips; + private String name; private Set nicknames; private String lastNick; - private long registered; - private long lastPlayed; - private long playTime; + private String geolocation; + private Set ips; + private int loginTimes; private int timesKicked; - private long lastGmSwapTime; - private String lastGamemode; - private Map gmTimes; + private boolean isOp; private boolean isBanned; - private String geolocation; + private boolean isOnline; private int mobKills; private List playerKills; private int deaths; - private String name; - private boolean isOnline; + private long registered; + private long lastPlayed; + private long playTime; + + private GMTimes gmTimes; + private WorldTimes worldTimes; - private SessionData currentSession; private final List sessions; /** * Creates a new UserData object with given values and default values. - * + *

* Some variables are left uninitialized: isBanned, lastPlayed, playTime, - * loginTimes, timesKicked, lastGmSwapTime, mobKills, deaths and - * currentSession. - * + * loginTimes, timesKicked, lastGmSwapTime, mobKills, deaths, lastWorldSwapTime, lastWorld + *

* These variables need to be set with setters. - * + *

* All Collections are left empty: locations, nicknames, ips, sessions, * playerKills. Because nicknames is empty, lastNick is an empty string. - * - * gmTimes HashMap will contain 4 '0L' values: SURVIVAL, CREATIVE, + *

+ * gmTimes Map will contain 4 '0L' values: SURVIVAL, CREATIVE, * ADVENTURE, SPECTATOR + * worldTimes Map is left empty. * - * @param uuid UUID of the player - * @param reg Epoch millisecond the player registered. - * @param op Is the player op? (true/false) - * @param lastGM last GameMode the player was seen in. - * @param name Name of the player. + * @param uuid UUID of the player + * @param reg Epoch millisecond the player registered. + * @param op Is the player op? (true/false) + * @param name Name of the player. * @param online Is the player online? */ - public UserData(UUID uuid, long reg, boolean op, String lastGM, String name, boolean online) { + public UserData(UUID uuid, long reg, boolean op, String gm, String name, boolean online) { accessing = 0; + + this.gmTimes = new GMTimes(gm); + this.worldTimes = new WorldTimes(); + this.uuid = uuid; - registered = reg; - isOp = op; + this.name = name; + lastNick = ""; nicknames = new HashSet<>(); ips = new HashSet<>(); - gmTimes = new HashMap<>(); - String[] gms = new String[]{"SURVIVAL", "CREATIVE", "ADVENTURE", "SPECTATOR"}; - for (String gm : gms) { - gmTimes.put(gm, 0L); - } - lastGamemode = lastGM; geolocation = "Not Known"; - this.name = name; + + isOp = op; isOnline = online; + registered = reg; + sessions = new ArrayList<>(); - lastNick = ""; playerKills = new ArrayList<>(); } /** * Creates a new UserData object with the variables inside a Player object. - * + *

* Some variables are left uninitialized: lastPlayed, playTime, loginTimes, * timesKicked, lastGmSwapTime, mobKills, deaths and currentSession. - * + *

* These variables need to be set with setters. - * + *

* All Collections are left empty: locations, nicknames, ips, sessions, * playerKills. Because nicknames is empty, lastNick is an empty string. - * + *

* gmTimes HashMap will contain 4 '0L' values: SURVIVAL, CREATIVE, * ADVENTURE, SPECTATOR * @@ -118,19 +120,19 @@ public class UserData { /** * Creates a new UserData object with the variables inside a OfflinePlayer * object. - * + *

* Some variables are left uninitialized: location, lastPlayed, playTime, * loginTimes, timesKicked, lastGmSwapTime, mobKills, deaths and * currentSession. - * + *

* These variables need to be set with setters. - * + *

* All Collections are left empty: locations, nicknames, ips, sessions, * playerKills. Because nicknames is empty, lastNick is an empty string. - * + *

* gmTimes HashMap will contain 4 '0L' values: SURVIVAL, CREATIVE, * ADVENTURE, SPECTATOR - * + *

* lastGM will be set as SURVIVAL * * @param player IOfflinePlayer object. @@ -164,10 +166,8 @@ public class UserData { this.playTime = data.getPlayTime(); this.loginTimes = data.getLoginTimes(); this.timesKicked = data.getTimesKicked(); - this.lastGmSwapTime = data.getLastGmSwapTime(); - this.lastGamemode = data.getLastGamemode(); - this.gmTimes = new HashMap<>(); - gmTimes.putAll(data.getGmTimes()); + this.gmTimes = data.getGmTimes(); + this.worldTimes = data.getWorldTimes(); this.isOp = data.isOp(); this.isBanned = data.isBanned(); this.geolocation = data.getGeolocation(); @@ -183,12 +183,22 @@ public class UserData { @Override public String toString() { try { - return "{" + "accessing:" + accessing + "|uuid:" + uuid + "|ips:" + ips + "|nicknames:" + nicknames + "|lastNick:" + lastNick + "|registered:" + registered + "|lastPlayed:" + lastPlayed + "|playTime:" + playTime + "|loginTimes:" + loginTimes + "|timesKicked:" + timesKicked + "|lastGmSwapTime:" + lastGmSwapTime + "|lastGamemode:" + lastGamemode + "|gmTimes:" + gmTimes + "|isOp:" + isOp + "|isBanned:" + isBanned + "|geolocation:" + geolocation + "|mobKills:" + mobKills + "|playerKills:" + playerKills + "|deaths:" + deaths + "|name:" + name + "|isOnline:" + isOnline + "|currentSession:" + currentSession + "|sessions:" + sessions + '}'; - } catch (Throwable e) { + return "{" + "accessing:" + accessing + "|uuid:" + uuid + "|ips:" + ips + "|nicknames:" + nicknames + "|lastNick:" + lastNick + "|registered:" + registered + "|lastPlayed:" + lastPlayed + "|playTime:" + playTime + "|loginTimes:" + loginTimes + "|timesKicked:" + timesKicked + "|gm:" + gmTimes + "|world:" + worldTimes + "|isOp:" + isOp + "|isBanned:" + isBanned + "|geolocation:" + geolocation + "|mobKills:" + mobKills + "|playerKills:" + playerKills + "|deaths:" + deaths + "|name:" + name + "|isOnline:" + isOnline + "|sessions:" + sessions + '}'; + } catch (Exception e) { return "UserData: Error on toString:" + e; } } + @Deprecated + public String getLastGamemode() { + return gmTimes.getState(); + } + + @Deprecated + public long getLastGmSwapTime() { + return gmTimes.getLastStateChange(); + } + /** * Adds an to the ips Set if it is not null or the set doesn't contain it. * @@ -215,9 +225,9 @@ public class UserData { /** * Adds a nickname to the nicknames Set. - * + *

* null or empty values filtered. - * + *

* lastNick will be set as the given parameter, if accepted. * * @param nick Displayname of the player. @@ -237,7 +247,7 @@ public class UserData { /** * Adds nicknames to the nicknames Set. - * + *

* null or empty values filtered. * * @param addNicks Collection of nicknames. @@ -246,40 +256,9 @@ public class UserData { nicknames.addAll(addNicks.stream().filter(nick -> !Verify.isEmpty(nick)).collect(Collectors.toList())); } - /** - * Set a specific GameMode's millisecond value. - * - * @param gm Name of Gamemode. - * @param time Milliseconds spent in the gamemode. - */ - public void setGMTime(String gm, long time) { - if (!Verify.notNull(gmTimes)) { - gmTimes = new HashMap<>(); - } - if (Verify.notNull(gm)) { - gmTimes.put(gm, time); - } - } - - /** - * Set every GameMode's millisecond value. - * - * @param survivalTime ms spent in SURVIVAL - * @param creativeTime ms spent in CREATIVE - * @param adventureTime ms spent in ADVENTURE - * @param spectatorTime ms spent in SPECTATOR - */ - public void setAllGMTimes(long survivalTime, long creativeTime, long adventureTime, long spectatorTime) { - gmTimes.clear(); - gmTimes.put("SURVIVAL", survivalTime); - gmTimes.put("CREATIVE", creativeTime); - gmTimes.put("ADVENTURE", adventureTime); - gmTimes.put("SPECTATOR", spectatorTime); - } - /** * Adds a new SessionData to the sessions list. - * + *

* null and invalid sessions filtered. * * @param session SessionData object @@ -292,7 +271,7 @@ public class UserData { /** * Adds SessionData objects to the sessions list. - * + *

* null and invalid sessions filtered. * * @param sessions Collection of SessionData objects. @@ -305,28 +284,6 @@ public class UserData { this.sessions.addAll(filteredSessions); } - /** - * Sets the current session. - * - * Currently unused. - * - * @param session SessionData object, no restrictions. - */ - public void setCurrentSession(SessionData session) { - currentSession = session; - } - - /** - * Gets the current session. - * - * Currently unused. - * - * @return SessionData object with a recent start. - */ - public SessionData getCurrentSession() { - return currentSession; - } - /** * Changes the value of isBanned. * @@ -369,6 +326,15 @@ public class UserData { return uuid; } + /** + * Set the UUID. + * + * @param uuid UUID + */ + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + /** * Get the InetAddress Set. * @@ -378,6 +344,17 @@ public class UserData { return ips; } + /** + * Set the ips set. + * + * @param ips ips of the user. + */ + public void setIps(Set ips) { + if (Verify.notNull(ips)) { + this.ips = ips; + } + } + /** * Get the nickname String Set. * @@ -387,6 +364,17 @@ public class UserData { return nicknames; } + /** + * Set the nicknames set. + * + * @param nicknames nicknames of the user. + */ + public void setNicknames(Set nicknames) { + if (Verify.notNull(nicknames)) { + this.nicknames = nicknames; + } + } + /** * Get the Epoch millisecond the player registered. * @@ -397,8 +385,17 @@ public class UserData { } /** - * Get the Epoch millisecond the player was last seen. + * Set the time the user was registered. * + * @param registered Epoch millisecond of register time. + */ + public void setRegistered(long registered) { + this.registered = registered; + } + + /** + * Get the Epoch millisecond the player was last seen. + *

* NOT INITIALIZED BY CONSTRUCTORS. Value is updated periodically by cache * if the player is online. * @@ -409,8 +406,20 @@ public class UserData { } /** - * Get the playtime in milliseconds. + * Set the time the user was last seen. + *

+ * Affects playtime calculation, playtime should be updated before updating + * this value. * + * @param lastPlayed Epoch millisecond of last seen moment. + */ + public void setLastPlayed(long lastPlayed) { + this.lastPlayed = lastPlayed; + } + + /** + * Get the playtime in milliseconds. + *

* NOT INITIALIZED BY CONSTRUCTORS. Value is updated periodically by cache * if the player is online. * @@ -421,8 +430,17 @@ public class UserData { } /** - * Get how many times the player has logged in. + * Set the time the user has been playing. * + * @param playTime Time in ms. + */ + public void setPlayTime(long playTime) { + this.playTime = playTime; + } + + /** + * Get how many times the player has logged in. + *

* NOT INITIALIZED BY CONSTRUCTORS. * * @return 0 to Integer.MAX @@ -432,8 +450,19 @@ public class UserData { } /** - * Get how many times the player has been kicked. + * Set how many times the user has logged in. + *

+ * No check for input. * + * @param loginTimes 0 to Int.MAX + */ + public void setLoginTimes(int loginTimes) { + this.loginTimes = loginTimes; + } + + /** + * Get how many times the player has been kicked. + *

* NOT INITIALIZED BY CONSTRUCTORS. * * @return 0 to Integer.MAX @@ -443,36 +472,42 @@ public class UserData { } /** - * Get the GMTimes Map. + * Set how many times the user has been kicked. + *

+ * No check for input. * - * @return a GameMode map with 4 keys: SURVIVAL, CREATIVE, ADVENTURE, - * SPECTATOR. + * @param timesKicked 0 to Int.MAX */ - public Map getGmTimes() { - if (gmTimes == null) { - gmTimes = new HashMap<>(); - } + public void setTimesKicked(int timesKicked) { + this.timesKicked = timesKicked; + } + + /** + * Get the GMTimes object. + * + * @return TimeKeeper object with possible keys of SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR + */ + public GMTimes getGmTimes() { return gmTimes; } /** - * Get the last time a Gamemode time was updated. + * Set the GM Times object containing playtime in each gamemode. * - * @return Epoch millisecond of last GM Time update. + * @param gmTimes GM Times object */ - public long getLastGmSwapTime() { - return lastGmSwapTime; + public void setGmTimes(GMTimes gmTimes) { + if (Verify.notNull(gmTimes)) { + this.gmTimes = gmTimes; + } } - /** - * Get the last Gamemode that the user was seen in. - * - * When player changes to SURVIVAL this is set to SURVIVAL. - * - * @return Gamemode. - */ - public String getLastGamemode() { - return lastGamemode; + public void setGmTimes(Map times) { + if (Verify.notNull(times)) { + for (Map.Entry entry : times.entrySet()) { + gmTimes.setTime(entry.getKey(), entry.getValue()); + } + } } /** @@ -493,6 +528,15 @@ public class UserData { return isBanned; } + /** + * Set the banned value. + * + * @param isBanned true/false + */ + public void setBanned(boolean isBanned) { + this.isBanned = isBanned; + } + /** * Get the username of the player. * @@ -502,132 +546,6 @@ public class UserData { return name; } - /** - * Set the UUID. - * - * @param uuid UUID - */ - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - - /** - * Set the ips set. - * - * @param ips ips of the user. - */ - public void setIps(Set ips) { - if (Verify.notNull(ips)) { - this.ips = ips; - } - } - - /** - * Set the nicknames set. - * - * @param nicknames nicknames of the user. - */ - public void setNicknames(Set nicknames) { - if (Verify.notNull(nicknames)) { - this.nicknames = nicknames; - } - } - - /** - * Set the time the user was registered. - * - * @param registered Epoch millisecond of register time. - */ - public void setRegistered(long registered) { - this.registered = registered; - } - - /** - * Set the time the user was last seen. - * - * Affects playtime calculation, playtime should be updated before updating - * this value. - * - * @param lastPlayed Epoch millisecond of last seen moment. - */ - public void setLastPlayed(long lastPlayed) { - this.lastPlayed = lastPlayed; - } - - /** - * Set the time the user has been playing. - * - * @param playTime Time in ms. - */ - public void setPlayTime(long playTime) { - this.playTime = playTime; - } - - /** - * Set how many times the user has logged in. - * - * No check for input. - * - * @param loginTimes 0 to Int.MAX - */ - public void setLoginTimes(int loginTimes) { - this.loginTimes = loginTimes; - } - - /** - * Set how many times the user has been kicked. - * - * No check for input. - * - * @param timesKicked 0 to Int.MAX - */ - public void setTimesKicked(int timesKicked) { - this.timesKicked = timesKicked; - } - - /** - * Set the GM Times map containing playtime in each gamemode. - * - * @param gmTimes Map containing SURVIVAL, CREATIVE, ADVENTURE and SPECTATOR - * (After 1.8) keys. - */ - public void setGmTimes(Map gmTimes) { - if (Verify.notNull(gmTimes)) { - this.gmTimes = gmTimes; - } - } - - /** - * Set the last time a Gamemode time was updated. - * - * @param lastGmSwapTime Epoch millisecond a gm time was updated. - */ - public void setLastGmSwapTime(long lastGmSwapTime) { - this.lastGmSwapTime = lastGmSwapTime; - } - - /** - * Set the last gamemode the user was seen in. - * - * @param lastGamemode gamemode. - */ - public void setLastGamemode(String lastGamemode) { - this.lastGamemode = lastGamemode; - } - - /** - * Set whether or not player is op. - * - * @param isOp operator? - */ - public void setIsOp(boolean isOp) { - this.isOp = isOp; - } - - public void setGeolocation(String geolocation) { - this.geolocation = geolocation; - } - /** * Set the username of the user. * @@ -637,6 +555,15 @@ public class UserData { this.name = name; } + /** + * Set whether or not player is op. + * + * @param isOp operator? + */ + public void setIsOp(boolean isOp) { + this.isOp = isOp; + } + /** * Is the player online? * @@ -646,6 +573,15 @@ public class UserData { return isOnline; } + /** + * Set the online value. + * + * @param isOnline true/false + */ + public void setOnline(boolean isOnline) { + this.isOnline = isOnline; + } + /** * Get how many mob kills the player has. * @@ -722,7 +658,7 @@ public class UserData { /** * Get the last nickname the user has set. - * + *

* Set when using addNickname(String) * * @return last nickname used. @@ -733,7 +669,7 @@ public class UserData { /** * Set the last nickname the user has set. - * + *

* Also set when using addNickname(String) * * @param lastNick last nickname used. @@ -742,39 +678,13 @@ public class UserData { this.lastNick = lastNick; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final UserData other = (UserData) obj; -// if (this.lastPlayed != other.lastPlayed) { -// return false; -// } + public WorldTimes getWorldTimes() { + return worldTimes; + } - return this.registered == other.registered - && this.playTime == other.playTime - && this.loginTimes == other.loginTimes - && this.timesKicked == other.timesKicked - && this.lastGmSwapTime == other.lastGmSwapTime - && this.mobKills == other.mobKills - && this.deaths == other.deaths - && Objects.equals(this.lastNick, other.lastNick) - && Objects.equals(this.name, other.name) - && Objects.equals(this.uuid, other.uuid) - && Objects.equals(this.ips, other.ips) - && Objects.equals(this.nicknames, other.nicknames) - && Objects.equals(this.lastGamemode, other.lastGamemode) - && Objects.equals(this.gmTimes, other.gmTimes) - && Objects.equals(this.playerKills, other.playerKills) - && Objects.equals(this.sessions, other.sessions); + public void setWorldTimes(WorldTimes worldTimes) { + this.worldTimes = worldTimes; } /** @@ -797,25 +707,69 @@ public class UserData { this.clearAfterSave = clearAfterSave; } - /** - * Set the banned value. - * - * @param isBanned true/false - */ - public void setBanned(boolean isBanned) { - this.isBanned = isBanned; - } - - /** - * Set the online value. - * - * @param isOnline true/false - */ - public void setOnline(boolean isOnline) { - this.isOnline = isOnline; - } - public String getGeolocation() { return geolocation; } -} + + public void setGeolocation(String geolocation) { + this.geolocation = geolocation; + } + + @Override + public int hashCode() { + int result = sessions.hashCode(); + result = 31 * result + accessing; + result = 31 * result + (clearAfterSave ? 1 : 0); + result = 31 * result + uuid.hashCode(); + result = 31 * result + ips.hashCode(); + result = 31 * result + nicknames.hashCode(); + result = 31 * result + lastNick.hashCode(); + result = 31 * result + (int) (registered ^ (registered >>> 32)); + result = 31 * result + (int) (lastPlayed ^ (lastPlayed >>> 32)); + result = 31 * result + (int) (playTime ^ (playTime >>> 32)); + result = 31 * result + loginTimes; + result = 31 * result + timesKicked; + result = 31 * result + gmTimes.hashCode(); + result = 31 * result + worldTimes.hashCode(); + result = 31 * result + (isOp ? 1 : 0); + result = 31 * result + (isBanned ? 1 : 0); + result = 31 * result + geolocation.hashCode(); + result = 31 * result + mobKills; + result = 31 * result + playerKills.hashCode(); + result = 31 * result + deaths; + result = 31 * result + name.hashCode(); + result = 31 * result + (isOnline ? 1 : 0); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + + final UserData other = (UserData) obj; + + return this.registered == other.registered + && this.playTime == other.playTime + && this.loginTimes == other.loginTimes + && this.timesKicked == other.timesKicked + && this.mobKills == other.mobKills + && this.deaths == other.deaths + && Objects.equals(this.lastNick, other.lastNick) + && Objects.equals(this.name, other.name) + && Objects.equals(this.uuid, other.uuid) + && Objects.equals(this.ips, other.ips) + && Objects.equals(this.nicknames, other.nicknames) + && Objects.equals(this.gmTimes, other.gmTimes) + && Objects.equals(this.worldTimes, other.worldTimes) + && Objects.equals(this.playerKills, other.playerKills) + && Objects.equals(this.sessions, other.sessions); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java b/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java index 49f7ec4b6..e7696202e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java @@ -3,10 +3,10 @@ package main.java.com.djrapitops.plan.data.additional; /** * This class contains Enum values for different types of Analysis that can be * performed on values of PluginData. - * + *

* The enum determines what should be done to the return value of * PluginData.getValue() method when the analysis is run. - * + *

* Refer to the documentation on GitHub for additional information. * * @author Rsl1122 @@ -17,56 +17,56 @@ public enum AnalysisType { /** * Used when the getValue() method returns an integer and average should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ INT_AVG("avgInt_", "Average "), /** * Used when the getValue() method returns a long and average should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ LONG_AVG("avgLong_", "Average "), /** * Used when the getValue() method returns double and average should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ DOUBLE_AVG("avgDouble_", "Average "), /** * Used when the getValue() method returns an integer and total should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ INT_TOTAL("totalInt_", "Total "), /** * Used when the getValue() method returns a long and total should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ LONG_TOTAL("totalLong_", "Total "), /** * Used when the getValue() method returns a double and total should be * calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ DOUBLE_TOTAL("totalDouble_", "Total "), /** * Used when the getValue() method returns an amount of milliseconds as long * and average should be calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ LONG_TIME_MS_AVG("avgTimeMs_", "Average "), /** * Used when the getValue() method returns an amount of milliseconds as long * and total should be calculated. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ LONG_TIME_MS_TOTAL("totalTimeMs_"), @@ -74,11 +74,11 @@ public enum AnalysisType { * Used when the getValue() method returns an Epoch Millisecond as long and * average of differences between the millisecond and current millisecond * should be calculated. - * + *

* For example if a player has dropped a Foo on epoch ms 1494486504000 and * that was 5s (5000ms) ago. Now you want to calculate the average * time-since for all players. Then you use this one. - * + *

* -1 values will be disregarded from the calculation (size will not grow). */ LONG_EPOCH_MS_MINUS_NOW_AVG("avgEpochMsMinusNow_", "Average "), @@ -89,13 +89,13 @@ public enum AnalysisType { /** * Used to calculate number of true values for the returned boolean values * of getValue(). - * + *

* Will be presented as "n / total". */ BOOLEAN_TOTAL("totalBool_"), /** * Used to add html tags to the plugins tab. - * + *

* Can be used to add Tables, Images (for example maps) and other html * elements. */ @@ -121,7 +121,7 @@ public enum AnalysisType { /** * Used to get the modifier for the Prefix of the value. - * + *

* For example: "Average Votes" when INT_AVG is used and Prefix is set as * "Votes". * diff --git a/Plan/src/main/java/com/djrapitops/plan/data/additional/HookHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/additional/HookHandler.java index 859f1a8b7..45eaf5d43 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/additional/HookHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/additional/HookHandler.java @@ -30,7 +30,7 @@ public class HookHandler { configHandler = new PluginConfigSectionHandler(plugin); try { Bridge.hook(this); - } catch (Throwable e) { + } catch (Exception e) { Log.toLog(this.getClass().getName(), e); Log.error("Plan Plugin Bridge not included in the plugin jar."); } @@ -38,10 +38,10 @@ public class HookHandler { /** * Adds a new PluginData source to the list. - * + *

* The plugin data will appear on Analysis and/or Inspect pages depending on * how the extending object is set up. - * + *

* Refer to documentation on GitHub for more information. * * @param dataSource an object extending the PluginData class. diff --git a/Plan/src/main/java/com/djrapitops/plan/data/additional/PluginData.java b/Plan/src/main/java/com/djrapitops/plan/data/additional/PluginData.java index bd7b06efa..a06c57935 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/additional/PluginData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/additional/PluginData.java @@ -8,7 +8,7 @@ import java.util.*; /** * This is an abstract class that can be used to add data from a plugin to the * "Plugins"-tab of Analysis and Inspect pages. - * + *

* API-section of documentation has examples on the usage of this class and how * to register objects extending this class. * @@ -17,71 +17,65 @@ import java.util.*; */ public abstract class PluginData { + /** + * A list containing the AnalysisType enums that determine what should be + * done with the data on the analysis page. + */ + protected final List analysisTypes; /** * Placeholder string, for example "stepsTaken". This will be used when * building the structure of the Plugins tab. - * + *

* The complete placeholder also includes the plugin name and if analysis is * run, a modifier. - * + *

* Second parameter of any super constructor. */ protected String placeholder; - /** * Name of the plugin the data is coming from. - * + *

* All sources of data with the same sourcePlugin will be placed in the same * "box" in the "Plugins" tab. - * + *

* A box has a max height of 600px, and higher than that will add a * scrollbar. - * + *

* First parameter of any super constructor. */ protected String sourcePlugin; - /** * Determines if the datapoint should only be used for the analysis page. - * + *

* If set to false, the datapoint will be added to the inspect page as well. */ protected boolean analysisOnly; - /** * Font Awesome icon name. - * + *

* http://fontawesome.io/icons/ */ protected String icon; - /** * Prefix shown before the data, for example "Steps taken: ". */ protected String prefix; - /** * Suffix shown after the data, for example " steps". */ protected String suffix; - /** - * A list containing the AnalysisType enums that determine what should be - * done with the data on the analysis page. - */ - protected final List analysisTypes; - /** * Main constructor. - * + *

* Defaults analysisOnly to true. - * + *

* Defaults icon, prefix and suffix to "". * - * @param sourcePlugin Name of the plugin the data is coming from - * @param placeholder Placeholder string, for example "stepsTaken" + * @param sourcePlugin Name of the plugin the data is coming from + * @param placeholder Placeholder string, for example "stepsTaken" * @param analysisTypes A list containing the AnalysisType enums that - * determine what should be done with the data on the analysis page + * determine what should be done with the data on the analysis page */ public PluginData(String sourcePlugin, String placeholder, List analysisTypes) { this.placeholder = placeholder; @@ -96,10 +90,10 @@ public abstract class PluginData { /** * Constructor for accepting single, multiple and arrays of AnalysisType. * - * @param sourcePlugin Name of the plugin the data is coming from - * @param placeholder Placeholder string, for example "stepsTaken" + * @param sourcePlugin Name of the plugin the data is coming from + * @param placeholder Placeholder string, for example "stepsTaken" * @param analysisTypes AnalysisType enums that determine what should be - * done with the data on the analysis page + * done with the data on the analysis page */ public PluginData(String sourcePlugin, String placeholder, AnalysisType... analysisTypes) { this(sourcePlugin, placeholder, Arrays.asList(analysisTypes)); @@ -107,11 +101,11 @@ public abstract class PluginData { /** * Constructor for Inspect-page only data point. - * + *

* analysisOnly will be set to false. * * @param sourcePlugin Name of the plugin the data is coming from - * @param placeholder Placeholder string, for example "stepsTaken" + * @param placeholder Placeholder string, for example "stepsTaken" */ public PluginData(String sourcePlugin, String placeholder) { this(sourcePlugin, placeholder, new ArrayList<>()); @@ -120,7 +114,7 @@ public abstract class PluginData { /** * Returns the list of AnalysisTypes. - * + *

* Used by Analysis * * @return a list. @@ -132,15 +126,15 @@ public abstract class PluginData { /** * This method should be used with the return values of * getHtmlReplaceValue(String, UUID). - * + *

* It will add the div, icon, modifier, prefix and suffix to the value. * Modifier is for example, if calculating AnalysisType.INT_AVG "Average ", * it is a text that helps user understand that a calculation has been made. * * @param modifier For example "Average " - Determined by value of - * AnalysisType's modifier-variable. + * AnalysisType's modifier-variable. * @param contents The data, number/string/html that should be placed on the - * page. + * page. * @return a proper format for the html. * @see AnalysisType */ @@ -150,12 +144,12 @@ public abstract class PluginData { /** * Used to get the full placeholder. - * + *

* Used to avoid conflicts with existing placeholders and placeholders of * other plugins. * * @param modifier Modifier determined by AnalysisType's - * placeholderModifier-variable. + * placeholderModifier-variable. * @return for example "%StepCounter_stepsTaken_total%" * @see AnalysisType */ @@ -174,20 +168,20 @@ public abstract class PluginData { /** * Used to get the string for the html page. - * + *

* parseContainer(modifierPrefix, value); should be used for all return * values so that div, icon, prefix and suffix are added. - * + *

* This method is used when AnalysisType.HTML is set, or while getting the * value for the inspect page. - * + *

* When using AnalysisType.HTML a random UUID is given, so it should be * disregarded. modifierPrefix is empty in that case. * * @param modifierPrefix Modifier determined by AnalysisType's - * modifier-variable. - * @param uuid UUID of the player or random UUID if AnalysisType.HTML is - * used. + * modifier-variable. + * @param uuid UUID of the player or random UUID if AnalysisType.HTML is + * used. * @return html for the page. */ public abstract String getHtmlReplaceValue(String modifierPrefix, UUID uuid); @@ -196,10 +190,10 @@ public abstract class PluginData { * Used to get the value for analysis. The return value is determined by * AnalysisType you have specified. If the AnalysisType's name has a BOOLEAN * in it, Analysis will expect boolean values etc. - * + *

* If the Type and return value mismatch, exception is thrown and the result * on the analysis page will say that error occurred as the value. - * + *

* If a player has no value a -1 should be returned in the case of a Number. * -1 is excluded from the Average calculation's size and total. * @@ -209,24 +203,6 @@ public abstract class PluginData { */ public abstract Serializable getValue(UUID uuid); - /** - * Used to set the prefix. - * - * @param prefix for example "Steps Taken: " or a Html start tag. - */ - public final void setPrefix(String prefix) { - this.prefix = prefix; - } - - /** - * Used to set the suffix. - * - * @param suffix for example " steps" or a html end tag. - */ - public final void setSuffix(String suffix) { - this.suffix = suffix; - } - /** * Used to set the Font Awesome icon. * @@ -238,7 +214,7 @@ public abstract class PluginData { /** * Used to set the analysisOnly parameter. - * + *

* true: only used for Analysis page false: used for both if AnalysisTypes * specified, if no AnalysisTypes are specified only used for Inspect page. * @@ -266,6 +242,15 @@ public abstract class PluginData { return prefix; } + /** + * Used to set the prefix. + * + * @param prefix for example "Steps Taken: " or a Html start tag. + */ + public final void setPrefix(String prefix) { + this.prefix = prefix; + } + /** * Used to get the suffix. * @@ -275,6 +260,15 @@ public abstract class PluginData { return suffix; } + /** + * Used to set the suffix. + * + * @param suffix for example " steps" or a html end tag. + */ + public final void setSuffix(String suffix) { + this.suffix = suffix; + } + /** * If a PluginData object has same placeholder, sourcePlugin and * analysisTypes, it is considered equal. diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/ActivityPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/ActivityPart.java index 9b420a480..d00876cce 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/ActivityPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/ActivityPart.java @@ -2,13 +2,6 @@ package main.java.com.djrapitops.plan.data.analysis; import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.utilities.Verify; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.TPS; @@ -19,17 +12,21 @@ import main.java.com.djrapitops.plan.ui.html.graphs.PunchCardGraphCreator; import main.java.com.djrapitops.plan.ui.html.graphs.SessionLengthDistributionGraphCreator; import main.java.com.djrapitops.plan.utilities.FormatUtils; import main.java.com.djrapitops.plan.utilities.HtmlUtils; +import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils; import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; +import java.util.*; +import java.util.stream.Collectors; + /** * Part responsible for all Player Activity related analysis. - * + *

* Online Graphs, Player-base pie-chart, Recent Players and Session * visualisation. - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: recentlogins, sessionaverage, * datapunchcard, datasessiondistribution, labelssessiondistribution, * datascatterday, datascatterweek, datascattermonth, playersonlinecolor, @@ -40,18 +37,16 @@ import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; * @author Rsl1122 * @since 3.5.2 */ -public class ActivityPart extends RawData { +public class ActivityPart extends RawData { private final JoinInfoPart joins; private final TPSPart tpsPart; - - private List recentPlayers; - private List recentPlayersUUIDs; - private final Set bans; private final Set active; private final Set inactive; private final Set joinedOnce; + private List recentPlayers; + private List recentPlayersUUIDs; public ActivityPart(JoinInfoPart joins, TPSPart tps) { this.joins = joins; @@ -75,38 +70,29 @@ public class ActivityPart extends RawData { final List sessions = joins.getAllSessions(); - long averageLength = MathUtils.averageLong(AnalysisUtils.transformSessionDataToLengths(sessions)); + List lengths = AnalysisUtils.transformSessionDataToLengths(sessions); + long averageLength = MathUtils.averageLong(lengths); addValue("sessionaverage", FormatUtils.formatTimeAmount(averageLength)); - String punchCardArray = PunchCardGraphCreator.generateDataArray(sessions); - addValue("datapunchcard", punchCardArray); - - String[] sessionDistribution = SessionLengthDistributionGraphCreator.generateDataArraySessions(sessions); - addValue("datasessiondistribution", sessionDistribution[0]); - addValue("labelssessiondistribution", sessionDistribution[1]); + List sessionsMonth = sessions.stream() + .filter(s -> s.getSessionStart() > MiscUtils.getTime() - TimeAmount.MONTH.ms()) + .collect(Collectors.toList()); + addValue("punchcardseries", PunchCardGraphCreator.createDataSeries(sessionsMonth)); + addValue("sessionlengthseries", SessionLengthDistributionGraphCreator.createDataSeries(lengths)); } private void playerActivityGraphs() { List tpsData = tpsPart.getTpsData(); - - String dayScatter = PlayerActivityGraphCreator.buildScatterDataString(tpsData, TimeAmount.DAY.ms()); - String weekScatter = PlayerActivityGraphCreator.buildScatterDataString(tpsData, TimeAmount.WEEK.ms()); - String monthScatter = PlayerActivityGraphCreator.buildScatterDataString(tpsData, TimeAmount.MONTH.ms()); - - addValue("datascatterday", dayScatter); - addValue("datascatterweek", weekScatter); - addValue("datascattermonth", monthScatter); - - addValue("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL + ""); - addValue("%playersgraphfill%", Settings.HCOLOR_ACT_ONL_FILL + ""); + addValue("playersonlineseries", PlayerActivityGraphCreator.buildSeriesDataString(tpsData)); + addValue("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL.toString()); } private void activityPiechart() { int[] counts = new int[]{active.size(), inactive.size(), joinedOnce.size(), bans.size()}; - final String colAct = Settings.HCOLOR_ACTP_ACT + ""; - final String colIna = Settings.HCOLOR_ACTP_INA + ""; - final String colJoi = Settings.HCOLOR_ACTP_JON + ""; - final String colBan = Settings.HCOLOR_ACTP_BAN + ""; + final String colAct = Settings.HCOLOR_ACTP_ACT.toString(); + final String colIna = Settings.HCOLOR_ACTP_INA.toString(); + final String colJoi = Settings.HCOLOR_ACTP_JON.toString(); + final String colBan = Settings.HCOLOR_ACTP_BAN.toString(); addValue("%activecol%", colAct); addValue("%inactivecol%", colIna); @@ -149,14 +135,6 @@ public class ActivityPart extends RawData { joinedOnce.add(uuid); } - public void setRecentPlayers(List recentPlayers) { - this.recentPlayers = recentPlayers; - } - - public void setRecentPlayersUUIDs(List recentPlayersUUIDs) { - this.recentPlayersUUIDs = recentPlayersUUIDs; - } - public Map getPlayersOnline() { return tpsPart.getTpsData().stream().collect(Collectors.toMap(TPS::getDate, TPS::getPlayers)); } @@ -165,10 +143,18 @@ public class ActivityPart extends RawData { return recentPlayers; } + public void setRecentPlayers(List recentPlayers) { + this.recentPlayers = recentPlayers; + } + public List getRecentPlayersUUIDs() { return recentPlayersUUIDs; } + public void setRecentPlayersUUIDs(List recentPlayersUUIDs) { + this.recentPlayersUUIDs = recentPlayersUUIDs; + } + public Set getBans() { return bans; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/CommandUsagePart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/CommandUsagePart.java index 6ccb1dc01..8375abd77 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/CommandUsagePart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/CommandUsagePart.java @@ -5,23 +5,24 @@ */ package main.java.com.djrapitops.plan.data.analysis; -import java.util.Map; import main.java.com.djrapitops.plan.ui.html.tables.CommandUseTableCreator; import main.java.com.djrapitops.plan.utilities.HtmlUtils; +import java.util.Map; + /** * Part responsible for all CommandUsage related analysis. - * + *

* Command Usage Table. - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: uniquecommands, totalcommands, commanduse * * @author Rsl1122 * @since 3.5.2 */ -public class CommandUsagePart extends RawData { +public class CommandUsagePart extends RawData { private final Map commandUsage; @@ -31,8 +32,8 @@ public class CommandUsagePart extends RawData { @Override public void analyse() { - addValue("uniquecommands", getUniqueCommands() + ""); - addValue("totalcommands", getCommandTotal() + ""); + addValue("uniquecommands", String.valueOf(getUniqueCommands())); + addValue("totalcommands", String.valueOf(getCommandTotal())); String commandUsageTable = CommandUseTableCreator.createSortedCommandUseTable(commandUsage); addValue("commanduse", HtmlUtils.removeXSS(commandUsageTable)); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/GamemodePart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/GamemodePart.java index 7632fab84..8b6d15f0b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/GamemodePart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/GamemodePart.java @@ -9,18 +9,18 @@ import java.util.Arrays; /** * Part responsible for all Gamemode usage related analysis. - * + *

* Gamemode Piechart, Percentages and Totals. - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: gmtotal, gm0col-gm3col, gmcolors, gmlabels, * gm0-gm3, gmdata, gm0total-gm3total * * @author Rsl1122 * @since 3.5.2 */ -public class GamemodePart extends RawData { +public class GamemodePart extends RawData { private long survivalTime; private long creativeTime; @@ -45,18 +45,18 @@ public class GamemodePart extends RawData { addValue("gmtotal", FormatUtils.formatTimeAmount(totalTime)); double[] percentages = new double[]{ - (survivalTime * 100.0) / totalTime, - (creativeTime * 100.0) / totalTime, - (adventureTime * 100.0) / totalTime, - (spectatorTime * 100.0) / totalTime + (survivalTime * 100.0) / totalTime, + (creativeTime * 100.0) / totalTime, + (adventureTime * 100.0) / totalTime, + (spectatorTime * 100.0) / totalTime }; long[] times = new long[]{ - survivalTime, creativeTime, adventureTime, spectatorTime + survivalTime, creativeTime, adventureTime, spectatorTime }; - String col0 = Settings.HCOLOR_GMP_0 + ""; - String col1 = Settings.HCOLOR_GMP_1 + ""; - String col2 = Settings.HCOLOR_GMP_2 + ""; - String col3 = Settings.HCOLOR_GMP_3 + ""; + String col0 = Settings.HCOLOR_GMP_0.toString(); + String col1 = Settings.HCOLOR_GMP_1.toString(); + String col2 = Settings.HCOLOR_GMP_2.toString(); + String col3 = Settings.HCOLOR_GMP_3.toString(); addValue("%gm0col%", col0); addValue("%gm1col%", col1); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/GeolocationPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/GeolocationPart.java index 957bdf047..66fce4c83 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/GeolocationPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/GeolocationPart.java @@ -1,79 +1,51 @@ package main.java.com.djrapitops.plan.data.analysis; +import main.java.com.djrapitops.plan.ui.html.graphs.WorldMapCreator; + import java.util.HashMap; import java.util.Map; /** * Part responsible for all Geolocation related analysis. - * - * Player location World Chloropleth map. - * + *

+ * Player location World Choropleth map. + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: geomapz, geomapcountries, geomapcodes * * @author Rsl1122 * @since 3.5.2 */ -public class GeolocationPart extends RawData { +public class GeolocationPart extends RawData { - private final Map geolocations; private final Map geoCodes; + private final Map geoCodeCounts; public GeolocationPart() { - geolocations = new HashMap<>(); geoCodes = new HashMap<>(); + geoCodeCounts = new HashMap<>(); + String[] countries = new String[]{"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas, The", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burma", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic of the", "Congo, Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Curacao", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Islas Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia, The", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea-Bissau", "Guinea", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia, Federated States of", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Namibia", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Nigeria", "Niger", "Niue", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia", "Saint Martin", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands", "West Bank", "Yemen", "Zambia", "Zimbabwe"}; String[] codes = new String[]{"AFG", "ALB", "DZA", "ASM", "AND", "AGO", "AIA", "ATG", "ARG", "ARM", "ABW", "AUS", "AUT", "AZE", "BHM", "BHR", "BGD", "BRB", "BLR", "BEL", "BLZ", "BEN", "BMU", "BTN", "BOL", "BIH", "BWA", "BRA", "VGB", "BRN", "BGR", "BFA", "MMR", "BDI", "CPV", "KHM", "CMR", "CAN", "CYM", "CAF", "TCD", "CHL", "CHN", "COL", "COM", "COD", "COG", "COK", "CRI", "CIV", "HRV", "CUB", "CUW", "CYP", "CZE", "DNK", "DJI", "DMA", "DOM", "ECU", "EGY", "SLV", "GNQ", "ERI", "EST", "ETH", "FLK", "FRO", "FJI", "FIN", "FRA", "PYF", "GAB", "GMB", "GEO", "DEU", "GHA", "GIB", "GRC", "GRL", "GRD", "GUM", "GTM", "GGY", "GNB", "GIN", "GUY", "HTI", "HND", "HKG", "HUN", "ISL", "IND", "IDN", "IRN", "IRQ", "IRL", "IMN", "ISR", "ITA", "JAM", "JPN", "JEY", "JOR", "KAZ", "KEN", "KIR", "KOR", "PRK", "KSV", "KWT", "KGZ", "LAO", "LVA", "LBN", "LSO", "LBR", "LBY", "LIE", "LTU", "LUX", "MAC", "MKD", "MDG", "MWI", "MYS", "MDV", "MLI", "MLT", "MHL", "MRT", "MUS", "MEX", "FSM", "MDA", "MCO", "MNG", "MNE", "MAR", "MOZ", "NAM", "NPL", "NLD", "NCL", "NZL", "NIC", "NGA", "NER", "NIU", "MNP", "NOR", "OMN", "PAK", "PLW", "PAN", "PNG", "PRY", "PER", "PHL", "POL", "PRT", "PRI", "QAT", "ROU", "RUS", "RWA", "KNA", "LCA", "MAF", "SPM", "VCT", "WSM", "SMR", "STP", "SAU", "SEN", "SRB", "SYC", "SLE", "SGP", "SXM", "SVK", "SVN", "SLB", "SOM", "ZAF", "SSD", "ESP", "LKA", "SDN", "SUR", "SWZ", "SWE", "CHE", "SYR", "TWN", "TJK", "TZA", "THA", "TLS", "TGO", "TON", "TTO", "TUN", "TUR", "TKM", "TUV", "UGA", "UKR", "ARE", "GBR", "USA", "URY", "UZB", "VUT", "VEN", "VNM", "VGB", "WBG", "YEM", "ZMB", "ZWE"}; for (int i = 0; i < countries.length; i++) { String country = countries[i]; - geolocations.put(country, 0); - geoCodes.put(country, codes[i]); + String countryCode = codes[i]; + + geoCodes.put(country, countryCode); + geoCodeCounts.put(countryCode, 0); } } @Override public void analyse() { - cloroplethMapValues(); + addValue("geomapseries", WorldMapCreator.createDataSeries(geoCodeCounts)); } - private void cloroplethMapValues() { - StringBuilder locations = new StringBuilder(); - StringBuilder z = new StringBuilder(); - StringBuilder text = new StringBuilder(); - locations.append("["); - z.append("["); - text.append("["); - int i = 0; - int size = geolocations.size(); - for (String c : geolocations.keySet()) { - locations.append("\"").append(c).append("\""); - z.append("\"").append(geolocations.get(c)).append("\""); - text.append("\""); - String code = geoCodes.get(c); - if (code != null) { - text.append(code); - } else { - text.append("UNK"); - } - text.append("\""); - - if (i < size - 1) { - locations.append(","); - z.append(","); - text.append(","); - } + public void addGeolocation(String country) { + String countryCode = geoCodes.get(country); + if (countryCode != null) { + geoCodeCounts.computeIfPresent(countryCode, (computedCountry, amount) -> amount + 1); } - locations.append("]"); - z.append("]"); - text.append("]"); - addValue("geomapz", z.toString()); - addValue("geomapcountries", locations.toString()); - addValue("geomapcodes", text.toString()); } - - public void addGeoloc(String country) { - geolocations.computeIfPresent(country, (computedCountry, amount) -> amount + 1); - } - } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/JoinInfoPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/JoinInfoPart.java index 263065eed..44edffd00 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/JoinInfoPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/JoinInfoPart.java @@ -11,19 +11,20 @@ import java.util.stream.Collectors; /** * Part responsible for all Player login related analysis. - * + *

* Unique per Day, Unique, New Players, Logins - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: totallogins, uniquejoinsday, * uniquejoinsweek, uniquejoinsmonth, avguniquejoins, avguniquejoinsday, - * avguniquejoinsweek, avguniquejoinsmonth, npday, npweek, npmonth + * avguniquejoinsweek, avguniquejoinsmonth, npday, npweek, npmonth, + * npdataday, npdataweek, npdatamonth, newperday, newperdayday, newperdayweek, newperdaymonth * * @author Rsl1122 * @since 3.5.2 */ -public class JoinInfoPart extends RawData { +public class JoinInfoPart extends RawData { private final Map> sessions; private final List registered; @@ -67,13 +68,24 @@ public class JoinInfoPart extends RawData { } private void newPlayers() { - int newDay = AnalysisUtils.getNewPlayers(registered, TimeAmount.DAY.ms(), MiscUtils.getTime()); - int newWeek = AnalysisUtils.getNewPlayers(registered, TimeAmount.WEEK.ms(), MiscUtils.getTime()); - int newMonth = AnalysisUtils.getNewPlayers(registered, TimeAmount.MONTH.ms(), MiscUtils.getTime()); + long now = MiscUtils.getTime(); + long newDay = AnalysisUtils.getNewPlayers(registered, TimeAmount.DAY.ms(), now); + long newWeek = AnalysisUtils.getNewPlayers(registered, TimeAmount.WEEK.ms(), now); + long newMonth = AnalysisUtils.getNewPlayers(registered, TimeAmount.MONTH.ms(), now); addValue("npday", newDay); addValue("npweek", newWeek); addValue("npmonth", newMonth); + + long newPerDay = AnalysisUtils.getNewUsersPerDay(registered, -1); + long newPerDayDay = AnalysisUtils.getNewUsersPerDay(registered, TimeAmount.DAY.ms()); + long newPerDayWeek = AnalysisUtils.getNewUsersPerDay(registered, TimeAmount.WEEK.ms()); + long newPerDayMonth = AnalysisUtils.getNewUsersPerDay(registered, TimeAmount.MONTH.ms()); + + addValue("newperday", newPerDay); + addValue("newperdayday", newPerDayDay); + addValue("newperdayweek", newPerDayWeek); + addValue("newperdaymonth", newPerDayMonth); } public void addToLoginTimes() { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/KillPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/KillPart.java index d5c42b8bc..68e93e54d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/KillPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/KillPart.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.data.analysis; import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.data.KillData; import main.java.com.djrapitops.plan.utilities.MiscUtils; +import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import java.util.HashMap; import java.util.List; @@ -11,19 +12,19 @@ import java.util.UUID; /** * Part responsible for all Death related analysis. - * + *

* Totals - * + *

* Placeholder values can be retrieved using the get method. - * - * Contains following place-holders: deaths, mobkills, playerkilss + *

+ * Contains following place-holders: deaths, mobkills, playerkills, avgdeaths, avgmobkills, avgplayerkills * * @author Rsl1122 * @since 3.5.2 */ -public class KillPart extends RawData { +public class KillPart extends RawData { - private final PlayerCountPart playerCount; // TODO Averages + private final PlayerCountPart playerCount; private final Map> playerKills; private long mobKills; private long deaths; @@ -39,7 +40,12 @@ public class KillPart extends RawData { public void analyse() { addValue("deaths", deaths); addValue("mobkills", mobKills); - addValue("playerkills", getAllPlayerKills().size()); + int playerKillAmount = getAllPlayerKills().size(); + addValue("playerkills", playerKillAmount); + int playerCount = this.playerCount.getPlayerCount(); + addValue("avgdeaths", MathUtils.averageLong(deaths, playerCount)); + addValue("avgmobkills", MathUtils.averageLong(mobKills, playerCount)); + addValue("avgplayerkills", MathUtils.averageLong(playerKillAmount, playerCount)); } public void addKills(UUID uuid, List kills) throws IllegalArgumentException { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlayerCountPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlayerCountPart.java index df4342828..fd29df0d4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlayerCountPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlayerCountPart.java @@ -1,6 +1,7 @@ package main.java.com.djrapitops.plan.data.analysis; import com.djrapitops.plugin.utilities.Verify; + import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -8,17 +9,17 @@ import java.util.UUID; /** * Part responsible for counting players. - * + *

* Total player count, op count - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: activitytotal, ops * * @author Rsl1122 * @since 3.5.2 */ -public class PlayerCountPart extends RawData { +public class PlayerCountPart extends RawData { private final Set uuids; private final Set ops; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlaytimePart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlaytimePart.java index f74a9f041..7070e8776 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlaytimePart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/PlaytimePart.java @@ -5,18 +5,18 @@ import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; /** * Part responsible for all Playtime related analysis. - * + *

* Placeholder values can be retrieved using the get method. - * + *

* Contains following place-holders: totalplaytime, avgplaytime * * @author Rsl1122 * @since 3.5.2 */ -public class PlaytimePart extends RawData { +public class PlaytimePart extends RawData { - private long totalPlaytime; private final PlayerCountPart playerCount; + private long totalPlaytime; public PlaytimePart(PlayerCountPart part) { playerCount = part; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/RawData.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/RawData.java index e5842df43..5cdcdfdc3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/RawData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/RawData.java @@ -1,6 +1,7 @@ package main.java.com.djrapitops.plan.data.analysis; import com.djrapitops.plugin.utilities.Verify; + import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -9,10 +10,9 @@ import java.util.Map; * Extending objects should represent, add together and analyse data. * * @author Rsl1122 - * @param The extending class, return value for get method. * @since 3.5.2 */ -public abstract class RawData { +public abstract class RawData { private final Map replaceMap; @@ -40,7 +40,7 @@ public abstract class RawData { /** * Analyses the data added together. - * + *

* Places place-holders to the replace map. */ public void analyseData() { @@ -50,7 +50,7 @@ public abstract class RawData { /** * Subclasses should analyse the data added together. - * + *

* Place-holders should be added to the replace map. */ protected abstract void analyse(); @@ -69,7 +69,7 @@ public abstract class RawData { * Adds a placeholder to the replaceMap. * * @param placeholder placeholder, with or without % signs. - * @param value Any value the placeholder should be replaced with. + * @param value Any value the placeholder should be replaced with. */ public void addValue(String placeholder, Serializable value) { placeholder = addPlaceholderSigns(placeholder); @@ -78,10 +78,10 @@ public abstract class RawData { private String addPlaceholderSigns(String placeholder) { if (placeholder.charAt(0) != '%') { - placeholder = '%' + placeholder; + placeholder = "%" + placeholder; } if (placeholder.charAt(placeholder.length() - 1) != '%') { - placeholder += '%'; + placeholder += "%"; } return placeholder; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/TPSPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/TPSPart.java index 3bdd61928..268a694e6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/analysis/TPSPart.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/TPSPart.java @@ -3,7 +3,9 @@ package main.java.com.djrapitops.plan.data.analysis; import com.djrapitops.plugin.api.TimeAmount; import main.java.com.djrapitops.plan.data.TPS; import main.java.com.djrapitops.plan.ui.html.graphs.CPUGraphCreator; +import main.java.com.djrapitops.plan.ui.html.graphs.RamGraphCreator; import main.java.com.djrapitops.plan.ui.html.graphs.TPSGraphCreator; +import main.java.com.djrapitops.plan.ui.html.graphs.WorldLoadGraphCreator; import main.java.com.djrapitops.plan.utilities.FormatUtils; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; @@ -12,18 +14,19 @@ import java.util.List; /** * Part responsible for all TPS related analysis. - * + *

* Ticks Per Second Graphs - * + *

* Placeholder values can be retrieved using the get method. - * - * Contains following place-holders: tpsscatterday, tpsscatterweek, cpuscatterday, cpuscatterweek, averagetps, - * averagetpsday + *

+ * Contains following place-holders: tpsscatterday, tpsscatterweek, cpuscatterday, cpuscatterweek, averagetps(-week), + * averagetpsday, averagecpuday, averagecpuweek, averagememoryday, averagememoryweek, averageentitiesday, averageentitiesweek, + * averagechunksday, averagechunkweek, ramscatterday, ramscatterweek * * @author Rsl1122 * @since 3.5.2 */ -public class TPSPart extends RawData { +public class TPSPart extends RawData { private final List tpsData; @@ -37,22 +40,43 @@ public class TPSPart extends RawData { List week = TPSGraphCreator.filterTPS(tpsData, now - TimeAmount.WEEK.ms()); List day = TPSGraphCreator.filterTPS(tpsData, now - TimeAmount.DAY.ms()); - String tpsScatterDay = TPSGraphCreator.buildScatterDataStringTPS(day, TimeAmount.DAY.ms()); - String tpsScatterWeek = TPSGraphCreator.buildScatterDataStringTPS(week, TimeAmount.WEEK.ms()); - String cpuScatterDay = CPUGraphCreator.buildScatterDataString(day, TimeAmount.DAY.ms()); - String cpuScatterWeek = CPUGraphCreator.buildScatterDataString(week, TimeAmount.WEEK.ms()); - addValue("tpsscatterday", tpsScatterDay); - addValue("tpsscatterweek", tpsScatterWeek); + addValue("tpsseries", TPSGraphCreator.buildSeriesDataString(tpsData)); + addValue("cpuseries", CPUGraphCreator.buildSeriesDataString(tpsData)); + addValue("ramseries", RamGraphCreator.buildSeriesDataString(tpsData)); + addValue("entityseries", WorldLoadGraphCreator.buildSeriesDataStringEntities(tpsData)); + addValue("chunkseries", WorldLoadGraphCreator.buildSeriesDataStringChunks(tpsData)); - addValue("cpuscatterday", cpuScatterDay); - addValue("cpuscatterweek", cpuScatterWeek); + double averageTPSWeek = MathUtils.averageDouble(week.stream().map(TPS::getTps)); + double averageTPSDay = MathUtils.averageDouble(day.stream().map(TPS::getTps)); - double averageTPSweek = MathUtils.averageDouble(week.stream().map(TPS::getTps)); - double averageTPSday = MathUtils.averageDouble(day.stream().map(TPS::getTps)); + double averageCPUWeek = MathUtils.averageDouble(week.stream().map(TPS::getCPUUsage).filter(i -> i != 0)); + double averageCPUDay = MathUtils.averageDouble(day.stream().map(TPS::getCPUUsage).filter(i -> i != 0)); - addValue("averagetps", FormatUtils.cutDecimals(averageTPSweek)); - addValue("averagetpsday", FormatUtils.cutDecimals(averageTPSday)); + long averageUsedMemoryWeek = MathUtils.averageLong(week.stream().map(TPS::getUsedMemory).filter(i -> i != 0)); + long averageUsedMemoryDay = MathUtils.averageLong(day.stream().map(TPS::getUsedMemory).filter(i -> i != 0)); + + double averageEntityCountWeek = MathUtils.averageInt(week.stream().map(TPS::getEntityCount).filter(i -> i != 0)); + double averageEntityCountDay = MathUtils.averageInt(day.stream().map(TPS::getEntityCount).filter(i -> i != 0)); + + double averageChunksLoadedWeek = MathUtils.averageInt(week.stream().map(TPS::getChunksLoaded).filter(i -> i != 0)); + double averageChunksLoadedDay = MathUtils.averageInt(day.stream().map(TPS::getChunksLoaded).filter(i -> i != 0)); + + addValue("averagetps", FormatUtils.cutDecimals(averageTPSWeek)); //Staying for backwards compatibility + addValue("averagetpsweek", FormatUtils.cutDecimals(averageTPSWeek)); + addValue("averagetpsday", FormatUtils.cutDecimals(averageTPSDay)); + + addValue("averagecpuweek", averageCPUWeek >= 0 ? FormatUtils.cutDecimals(averageCPUWeek) + "%" : "Unavailable"); + addValue("averagecpuday", averageCPUDay >= 0 ? FormatUtils.cutDecimals(averageCPUDay) + "%" : "Unavailable"); + + addValue("averagememoryweek", FormatUtils.cutDecimals(averageUsedMemoryWeek)); + addValue("averagememoryday", FormatUtils.cutDecimals(averageUsedMemoryDay)); + + addValue("averageentitiesweek", FormatUtils.cutDecimals(averageEntityCountWeek)); + addValue("averageentitiesday", FormatUtils.cutDecimals(averageEntityCountDay)); + + addValue("averagechunksweek", FormatUtils.cutDecimals(averageChunksLoadedWeek)); + addValue("averagechunksday", FormatUtils.cutDecimals(averageChunksLoadedDay)); } public List getTpsData() { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/analysis/WorldPart.java b/Plan/src/main/java/com/djrapitops/plan/data/analysis/WorldPart.java new file mode 100644 index 000000000..1b0653c6c --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/analysis/WorldPart.java @@ -0,0 +1,41 @@ +package main.java.com.djrapitops.plan.data.analysis; + +import main.java.com.djrapitops.plan.data.time.WorldTimes; +import main.java.com.djrapitops.plan.ui.html.graphs.WorldPieCreator; +import main.java.com.djrapitops.plan.utilities.FormatUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Part responsible for all World Playtime related analysis. + *

+ * World times Pie + *

+ * Placeholder values can be retrieved using the get method. + *

+ * Contains following place-holders: worldtotal, worldseries + * + * @author Rsl1122 + * @since 3.6.0 + */ +public class WorldPart extends RawData { + + private final Map worldTimes; + + public WorldPart() { + worldTimes = new HashMap<>(); + } + + @Override + protected void analyse() { + WorldTimes t = new WorldTimes(worldTimes); + addValue("worldtotal", FormatUtils.formatTimeAmount(t.getTotal())); + addValue("worldseries", WorldPieCreator.createSeriesData(worldTimes)); + } + + public void addToWorld(String worldName, long playTime) { + Long value = worldTimes.getOrDefault(worldName, 0L); + worldTimes.put(worldName, value + playTime); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/AnalysisCacheHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/AnalysisCacheHandler.java index c56517ea2..f63db6aa1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/AnalysisCacheHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/AnalysisCacheHandler.java @@ -13,13 +13,13 @@ import main.java.com.djrapitops.plan.utilities.analysis.Analysis; */ public class AnalysisCacheHandler { - private AnalysisData cache; private final Analysis analysis; + private AnalysisData cache; private boolean analysisEnabled; /** * Class Constructor. - * + *

* Initializes Analysis * * @param plugin Current instance of Plan @@ -64,7 +64,6 @@ public class AnalysisCacheHandler { } /** - * * @return */ public boolean isAnalysisBeingRun() { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/DBCallableProcessor.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/DBCallableProcessor.java index fbe691b00..a12c62d72 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/DBCallableProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/DBCallableProcessor.java @@ -3,23 +3,23 @@ package main.java.com.djrapitops.plan.data.cache; import main.java.com.djrapitops.plan.data.UserData; /** - * This abstract class can be extended with anything as the process method and + * This interface can be extended with anything as the process method and * given to the Database. - * + *

* The process method will be called with the UserData object fetched from the * database. * * @author Rsl1122 * @since 2.6.0 */ -public abstract class DBCallableProcessor { +public interface DBCallableProcessor { /** * Method used to do multiple things to UserData objects such as Caching, * changing properties etc. * * @param data UserData object given to the DBCallableProcessor by the - * method it was given as parameter to. + * method it was given as parameter to. */ - public abstract void process(UserData data); + void process(UserData data); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/DataCacheHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/DataCacheHandler.java index 8bfc74128..4c30f2d3c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/DataCacheHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/DataCacheHandler.java @@ -21,19 +21,20 @@ import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.NewPlayerCreator; import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import main.java.com.djrapitops.plan.utilities.comparators.HandlingInfoTimeComparator; +import org.bukkit.entity.Player; import java.sql.SQLException; import java.util.*; /** * This Class contains the Cache. - * + *

* This class is the main processing class that initialises Save, Clear, Process * and Get queue and Starts the asynchronous save task. - * + *

* It is used to store command use, locations, active sessions and UserData * objects in memory. - * + *

* Its methods can be used to access all the data it stores and to clear them. * * @author Rsl1122 @@ -42,14 +43,16 @@ import java.util.*; public class DataCacheHandler extends SessionCache { // Cache - private final HashMap dataCache; - private Map commandUse; - private List> unsavedTPSHistory; + private final Map dataCache; // Plan private final Plan plugin; private final Database db; + //Cache + private Map commandUse; + private List> unsavedTPSHistory; + // Queues private DataCacheSaveQueue saveTask; private DataCacheClearQueue clearTask; @@ -61,7 +64,7 @@ public class DataCacheHandler extends SessionCache { /** * Class Constructor. - * + *

* Gets the Database from the plugin. Starts the queues. Registers * Asynchronous Periodic Save Task * @@ -115,8 +118,8 @@ public class DataCacheHandler extends SessionCache { * Used to start the Asynchronous Save Task. * * @throws IllegalArgumentException BukkitRunnable was given wrong - * parameters. - * @throws IllegalStateException BukkitScheduler is in a wrong state. + * parameters. + * @throws IllegalStateException BukkitScheduler is in a wrong state. */ public void startAsyncPeriodicSaveTask() throws IllegalArgumentException, IllegalStateException { int minutes = Settings.SAVE_CACHE_MIN.getNumber(); @@ -160,26 +163,21 @@ public class DataCacheHandler extends SessionCache { /** * Uses Database or Cache to retrieve the UserData of a matching player. - * + *

* Caches the data to the Cache if cache-parameter is true. * * @param processor DBCallableProcessor Object used to process the data - * after it was retrieved - * @param uuid Player's UUID - * @param cache Whether or not the UserData will be Cached in this instance - * of DataCacheHandler after it has been fetched (if not already fetched) + * after it was retrieved + * @param uuid Player's UUID + * @param cache Whether or not the UserData will be Cached in this instance + * of DataCacheHandler after it has been fetched (if not already fetched) */ public void getUserDataForProcessing(DBCallableProcessor processor, UUID uuid, boolean cache) { Log.debug(uuid + ": HANDLER getForProcess," + " Cache:" + cache); UserData uData = dataCache.get(uuid); if (uData == null) { if (cache) { - DBCallableProcessor cacher = new DBCallableProcessor() { - @Override - public void process(UserData data) { - cache(data); - } - }; + DBCallableProcessor cacher = this::cache; getTask.scheduleForGet(uuid, cacher, processor); } else { getTask.scheduleForGet(uuid, processor); @@ -191,7 +189,7 @@ public class DataCacheHandler extends SessionCache { /** * Used to Cache a UserData object to the Cache. - * + *

* If a object already exists it will be replaced. * * @param data UserData object with the UUID inside used as key. @@ -204,12 +202,12 @@ public class DataCacheHandler extends SessionCache { /** * Uses Database or Cache to retrieve the UserData of a matching player. - * + *

* Always Caches the data after retrieval (unless already cached) * * @param processor DBCallableProcessor Object used to process the data - * after it was retrieved - * @param uuid Player's UUID + * after it was retrieved + * @param uuid Player's UUID */ public void getUserDataForProcessing(DBCallableProcessor processor, UUID uuid) { getUserDataForProcessing(processor, uuid, true); @@ -217,9 +215,7 @@ public class DataCacheHandler extends SessionCache { /** * Saves all UserData in the cache to Database. - * - * ATTENTION: TODO - Doesn't save the Locations in the locationCache. - * + *

* Should only be called from Async thread */ public void saveCachedUserData() { @@ -234,7 +230,7 @@ public class DataCacheHandler extends SessionCache { /** * Used to add event HandlingInfo to the processTask's pool. - * + *

* Given HandlingInfo object's process method will be called. * * @param i Object that extends HandlingInfo. @@ -249,9 +245,9 @@ public class DataCacheHandler extends SessionCache { /** * Saves all data in the cache to Database and closes the database down. - * + *

* Stops all tasks. - * + *

* If processTask has unprocessed information, it will be processed. */ public void saveCacheOnDisable() { @@ -268,7 +264,8 @@ public class DataCacheHandler extends SessionCache { for (IPlayer p : onlinePlayers) { UUID uuid = p.getUuid(); endSession(uuid); - toProcess.add(new LogoutInfo(uuid, time, p.isBanned(), p.getGamemode(), getSession(uuid))); + String worldName = ((Player) p.getWrappedPlayerClass()).getWorld().getName(); + toProcess.add(new LogoutInfo(uuid, time, p.isBanned(), p.getGamemode().name(), getSession(uuid), worldName)); } Log.debug("ToProcess size_AFTER: " + toProcess.size() + " DataCache size: " + dataCache.keySet().size()); toProcess.sort(new HandlingInfoTimeComparator()); @@ -301,12 +298,7 @@ public class DataCacheHandler extends SessionCache { for (HandlingInfo i : toProcess) { UserData uData = dataCache.get(i.getUuid()); if (uData == null) { - DBCallableProcessor p = new DBCallableProcessor() { - @Override - public void process(UserData data) { - i.process(data); - } - }; + DBCallableProcessor p = i::process; getUserDataForProcessing(p, i.getUuid()); } else { i.process(uData); @@ -321,20 +313,17 @@ public class DataCacheHandler extends SessionCache { */ public void saveCachedData(UUID uuid) { Log.debug(uuid + ": SaveCachedData"); - DBCallableProcessor saveProcessor = new DBCallableProcessor() { - @Override - public void process(UserData data) { - data.access(); - data.setClearAfterSave(true); - saveTask.scheduleForSave(data); - } + DBCallableProcessor saveProcessor = data -> { + data.access(); + data.setClearAfterSave(true); + saveTask.scheduleForSave(data); }; getUserDataForProcessing(saveProcessor, uuid); } /** * Saves the cached CommandUse. - * + *

* Should be only called from an Asynchronous Thread. */ public void saveCommandUse() { @@ -366,11 +355,14 @@ public class DataCacheHandler extends SessionCache { for (List history : copy) { final long lastDate = history.get(history.size() - 1).getDate(); - final double averageTPS = MathUtils.averageDouble(history.stream().map(TPS::getTps)); + final double averageTPS = MathUtils.round(MathUtils.averageDouble(history.stream().map(TPS::getTps))); final int averagePlayersOnline = (int) MathUtils.averageInt(history.stream().map(TPS::getPlayers)); - final double averageCPUUsage = MathUtils.averageDouble(history.stream().map(TPS::getCPUUsage)); + final double averageCPUUsage = MathUtils.round(MathUtils.averageDouble(history.stream().map(TPS::getCPUUsage))); + final long averageUsedMemory = MathUtils.averageLong(history.stream().map(TPS::getUsedMemory)); + final int averageEntityCount = (int) MathUtils.averageInt(history.stream().map(TPS::getEntityCount)); + final int averageChunksLoaded = (int) MathUtils.averageInt(history.stream().map(TPS::getChunksLoaded)); - averages.add(new TPS(lastDate, averageTPS, averagePlayersOnline, averageCPUUsage)); + averages.add(new TPS(lastDate, averageTPS, averagePlayersOnline, averageCPUUsage, averageUsedMemory, averageEntityCount, averageChunksLoaded)); } unsavedTPSHistory.removeAll(copy); return averages; @@ -381,13 +373,14 @@ public class DataCacheHandler extends SessionCache { */ public void saveHandlerDataToCache() { final List onlinePlayers = plugin.fetch().getOnlinePlayers(); - onlinePlayers.forEach((p) -> saveHandlerDataToCache(p, false)); + onlinePlayers.forEach(p -> saveHandlerDataToCache(p, false)); } - private void saveHandlerDataToCache(IPlayer player, boolean pool) { + private void saveHandlerDataToCache(IPlayer p, boolean pool) { long time = MiscUtils.getTime(); - UUID uuid = player.getUuid(); - ReloadInfo info = new ReloadInfo(uuid, time, player.getAddress().getAddress(), player.isBanned(), player.getDisplayName(), player.getGamemode()); + UUID uuid = p.getUuid(); + String worldName = ((Player) p.getWrappedPlayerClass()).getWorld().getName(); + ReloadInfo info = new ReloadInfo(uuid, time, p.getAddress().getAddress(), p.isBanned(), p.getDisplayName(), p.getGamemode().name(), worldName); if (!pool) { UserData data = dataCache.get(uuid); if (data != null) { @@ -474,9 +467,9 @@ public class DataCacheHandler extends SessionCache { /** * Used to get the contents of the cache. * - * @return The HashMap containing all Cached UserData + * @return The Map containing all Cached UserData */ - public HashMap getDataCache() { + public Map getDataCache() { return dataCache; } @@ -491,7 +484,7 @@ public class DataCacheHandler extends SessionCache { /** * If /reload is run this treats every online player as a new login. - * + *

* Calls all the methods that are ran when PlayerJoinEvent is fired */ public void handleReload() { @@ -525,7 +518,6 @@ public class DataCacheHandler extends SessionCache { } /** - * * @return */ public DataCacheSaveQueue getSaveTask() { @@ -533,7 +525,6 @@ public class DataCacheHandler extends SessionCache { } /** - * * @return */ public DataCacheClearQueue getClearTask() { @@ -541,7 +532,6 @@ public class DataCacheHandler extends SessionCache { } /** - * * @return */ public DataCacheProcessQueue getProcessTask() { @@ -549,7 +539,6 @@ public class DataCacheHandler extends SessionCache { } /** - * * @return */ public DataCacheGetQueue getGetTask() { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/GeolocationCacheHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/GeolocationCacheHandler.java index 1f9b5a453..5dcde6df6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/GeolocationCacheHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/GeolocationCacheHandler.java @@ -7,6 +7,7 @@ import main.java.com.djrapitops.plan.utilities.Benchmark; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.Map; @@ -21,6 +22,14 @@ import java.util.Map; * @since 3.5.5 */ public class GeolocationCacheHandler { + + /** + * Constructor used to hide the public constructor + */ + private GeolocationCacheHandler() { + throw new IllegalStateException("Utility class"); + } + private static final Cache geolocationCache = CacheBuilder.newBuilder() .maximumSize(10000) .build(); @@ -71,12 +80,20 @@ public class GeolocationCacheHandler { */ private static String getUncachedCountry(String ipAddress) { Benchmark.start("getUncachedCountry"); + + URL url; + + String urlString = "http://freegeoip.net/csv/" + ipAddress; try { - URL url = new URL("http://freegeoip.net/csv/" + ipAddress); - BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); + url = new URL(urlString); + } catch (MalformedURLException e) { + Log.error("The URL \"" + urlString + "\" couldn't be converted to URL: " + e.getCause()); //Shouldn't ever happen + return "Not Known"; + } + + try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) { String resultLine = in.readLine(); - Log.debug(resultLine); - in.close(); + Log.debug("Result for country request for " + ipAddress + ": " + resultLine); String[] results = resultLine.split(","); String result = results[2]; @@ -87,7 +104,5 @@ public class GeolocationCacheHandler { } finally { Benchmark.stop("getUncachedCountry"); } - } - } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/InspectCacheHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/InspectCacheHandler.java index e1c454255..a8fb5162b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/InspectCacheHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/InspectCacheHandler.java @@ -4,6 +4,7 @@ import main.java.com.djrapitops.plan.Log; 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.ui.webserver.response.InspectPageResponse; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.ExportUtility; @@ -36,7 +37,7 @@ public class InspectCacheHandler { /** * Caches the UserData object to InspectCache. - * + *

* If the Userdata is cached in DataCache it will be used. Otherwise the Get * Queue will handle the DBCallableProcessor. * @@ -48,6 +49,7 @@ public class InspectCacheHandler { 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) { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/PageCacheHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/PageCacheHandler.java new file mode 100644 index 000000000..5a1aff43a --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/PageCacheHandler.java @@ -0,0 +1,76 @@ +package main.java.com.djrapitops.plan.data.cache; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import main.java.com.djrapitops.plan.ui.webserver.response.Response; + +/** + * This class contains the page cache. + *

+ * It caches all Responses with their matching identifiers. + * This reduces CPU cycles and the time to wait for loading the pages. + * This is especially useful in situations where multiple clients are accessing the server. + *

+ * This cache uses the Google Guava {@link Cache}. + * + * @author Fuzzlemann + * @since 3.6.0 + */ +public class PageCacheHandler { + + /** + * Constructor used to hide the public constructor + */ + private PageCacheHandler() { + throw new IllegalStateException("Utility class"); + } + + private static final Cache pageCache = CacheBuilder.newBuilder() + .build(); + + /** + * Loads the page from the page cache. + *

+ * If the {@link Response} isn't cached, {@link PageLoader#createResponse()} in the {@code loader} + * is called to create the Response. + *

+ * If the Response is created, it's automatically cached. + * + * @param identifier The identifier of the page + * @param loader The {@link PageLoader} (How should it load the page if it's not cached) + * @return The Response that was cached or created by the {@link PageLoader loader} + */ + public static Response loadPage(String identifier, PageLoader loader) { + Response response = pageCache.getIfPresent(identifier); + + if (response != null) { + return response; + } + + response = loader.createResponse(); + + pageCache.put(identifier, response); + + return response; + } + + /** + * Puts the page into the page cache. + *

+ * If the cache already inherits that {@code identifier}, it's renewed. + * + * @param identifier The identifier of the page + * @param loader The {@link PageLoader} (How it should load the page) + */ + public static void cachePage(String identifier, PageLoader loader) { + Response response = loader.createResponse(); + pageCache.put(identifier, response); + } + + /** + * Clears the cache from all its contents. + */ + public static void clearCache() { + pageCache.asMap().clear(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/PageLoader.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/PageLoader.java new file mode 100644 index 000000000..947019430 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/PageLoader.java @@ -0,0 +1,15 @@ +package main.java.com.djrapitops.plan.data.cache; + +import main.java.com.djrapitops.plan.ui.webserver.response.Response; + +/** + * This interface is used for providing the method to load the page. + * + * @author Fuzzlemann + * @since 3.6.0 + */ +public interface PageLoader { + + Response createResponse(); + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/SessionCache.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/SessionCache.java index cc0c2b6f6..ea9c43ee7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/SessionCache.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/SessionCache.java @@ -1,13 +1,14 @@ package main.java.com.djrapitops.plan.data.cache; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.utilities.MiscUtils; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * This class is used to store active sessions of players in memory. * @@ -54,7 +55,7 @@ public class SessionCache { /** * Used to get the SessionData of the player in the sessionCache. * - * @param uuid UUId of the player. + * @param uuid UUID of the player. * @return SessionData or null if not cached. */ public SessionData getSession(UUID uuid) { @@ -78,7 +79,7 @@ public class SessionCache { /** * Used to get the Map of active sessions. - * + *

* Used for testing. * * @return key:value UUID:SessionData diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Consumer.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Consumer.java index cd9ee74ac..7c99348e0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Consumer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Consumer.java @@ -1,24 +1,26 @@ package main.java.com.djrapitops.plan.data.cache.queue; import com.djrapitops.plugin.task.AbsRunnable; +import main.java.com.djrapitops.plan.Log; + import java.util.concurrent.BlockingQueue; /** * Abstract class representing a queue consumer. * - * @author Rsl1122 * @param + * @author Rsl1122 */ public abstract class Consumer extends AbsRunnable { - boolean run; final BlockingQueue queue; + boolean run; /** * Constructor, defines queue. * * @param queue Queue to consume from. - * @param name Name of the queue. + * @param name Name of the queue. */ public Consumer(BlockingQueue queue, String name) { super(name); @@ -33,6 +35,8 @@ public abstract class Consumer extends AbsRunnable { consume(queue.take()); } } catch (InterruptedException ex) { + Log.error("Consumer interrupted: " + ex.getCause()); + Thread.currentThread().interrupt(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueue.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueue.java index e3bf5cae7..f7151d29d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueue.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueue.java @@ -34,9 +34,9 @@ public class DataCacheGetQueue extends Queue /** * Schedules UserData objects to be get for the given processors. * - * @param uuid UUID of the player whose UserData object is fetched. + * @param uuid UUID of the player whose UserData object is fetched. * @param processors Processors which process-method will be called after - * fetch is complete, with the UserData object. + * fetch is complete, with the UserData object. */ public void scheduleForGet(UUID uuid, DBCallableProcessor... processors) { Log.debug(uuid + ": Scheduling for get"); @@ -45,12 +45,12 @@ public class DataCacheGetQueue extends Queue map.put(uuid, Arrays.asList(processors)); queue.add(map); } catch (IllegalStateException e) { - Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Get Queue", Settings.PROCESS_GET_LIMIT.getNumber() + "")); + Log.error(Phrase.ERROR_TOO_SMALL_QUEUE.parse("Get Queue", String.valueOf(Settings.PROCESS_GET_LIMIT.getNumber()))); } } public boolean containsUUIDtoBeCached(UUID uuid) { - return uuid != null && new ArrayList<>(queue).stream().anyMatch((map) -> (map.get(uuid) != null && map.get(uuid).size() >= 2)); + return uuid != null && new ArrayList<>(queue).stream().anyMatch(map -> (map.get(uuid) != null && map.get(uuid).size() >= 2)); } } @@ -68,12 +68,17 @@ class GetConsumer extends Consumer>> { if (db == null) { return; } + try { - for (UUID uuid : processors.keySet()) { + for (Map.Entry> entrySet : processors.entrySet()) { + UUID uuid = entrySet.getKey(); + if (uuid == null) { continue; } - List processorsList = processors.get(uuid); + + List processorsList = entrySet.getValue(); + if (processorsList != null) { Log.debug(uuid + ": Get, For:" + processorsList.size()); try { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueue.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueue.java index e5ae27522..ce7fffce3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueue.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueue.java @@ -1,12 +1,10 @@ package main.java.com.djrapitops.plan.data.cache.queue; import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; import main.java.com.djrapitops.plan.data.cache.DataCacheHandler; import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; -import java.util.ArrayList; import java.util.Collection; import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; @@ -27,7 +25,7 @@ public class DataCacheProcessQueue extends Queue { * @param handler current instance of DataCacheHandler. */ public DataCacheProcessQueue(DataCacheHandler handler) { - super(new ArrayBlockingQueue(20000)); + super(new ArrayBlockingQueue<>(20000)); setup = new ProcessSetup(queue, handler); setup.go(); } @@ -66,7 +64,7 @@ public class DataCacheProcessQueue extends Queue { * @return true/false */ public boolean containsUUID(UUID uuid) { - return uuid != null && new ArrayList<>(queue).stream().anyMatch(info -> info.getUuid().equals(uuid)); + return uuid != null && queue.stream().anyMatch(info -> info.getUuid().equals(uuid)); } } @@ -74,7 +72,7 @@ class ProcessConsumer extends Consumer { private DataCacheHandler handler; - ProcessConsumer(BlockingQueue q, DataCacheHandler h) { + ProcessConsumer(BlockingQueue q, DataCacheHandler h) { super(q, "ProcessQueueConsumer"); handler = h; } @@ -84,19 +82,19 @@ class ProcessConsumer extends Consumer { if (handler == null) { return; } + if (handler.getGetTask().containsUUIDtoBeCached(info.getUuid())) { // Wait for get queue. queue.add(info); return; } + Log.debug(info.getUuid() + ": Processing type: " + info.getType().name()); - DBCallableProcessor p = new DBCallableProcessor() { - @Override - public void process(UserData data) { - if (!info.process(data)) { - Log.error("Attempted to process data for wrong uuid: W:" + data.getUuid() + " | R:" + info.getUuid() + " Type:" + info.getType().name()); - } + DBCallableProcessor p = data -> { + if (!info.process(data)) { + Log.error("Attempted to process data for wrong uuid: W:" + data.getUuid() + " | R:" + info.getUuid() + " Type:" + info.getType().name()); } }; + handler.getUserDataForProcessing(p, info.getUuid()); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueue.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueue.java index fd5f804ff..77a6ef9e7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueue.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueue.java @@ -9,7 +9,6 @@ import main.java.com.djrapitops.plan.data.cache.DataCacheHandler; import main.java.com.djrapitops.plan.database.Database; import java.sql.SQLException; -import java.util.ArrayList; import java.util.Collection; import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; @@ -27,11 +26,11 @@ public class DataCacheSaveQueue extends Queue { /** * Class constructor, starts the new Thread for saving. * - * @param plugin current instance of Plan + * @param plugin current instance of Plan * @param handler DataCacheHandler */ public DataCacheSaveQueue(Plan plugin, DataCacheHandler handler) { - super(new ArrayBlockingQueue(Settings.PROCESS_SAVE_LIMIT.getNumber())); + super(new ArrayBlockingQueue<>(Settings.PROCESS_SAVE_LIMIT.getNumber())); setup = new SaveSetup(queue, handler, plugin.getDB()); setup.go(); } @@ -85,7 +84,7 @@ public class DataCacheSaveQueue extends Queue { * @return true/false */ public boolean containsUUID(UUID uuid) { - return uuid != null && new ArrayList<>(queue).stream().anyMatch(d -> d.getUuid().equals(uuid)); + return uuid != null && queue.stream().anyMatch(d -> d.getUuid().equals(uuid)); } } @@ -94,7 +93,7 @@ class SaveConsumer extends Consumer { private Database db; private DataCacheHandler handler; - SaveConsumer(BlockingQueue q, DataCacheHandler handler, Database db) { + SaveConsumer(BlockingQueue q, DataCacheHandler handler, Database db) { super(q, "SaveQueueConsumer"); this.db = db; this.handler = handler; @@ -106,23 +105,23 @@ class SaveConsumer extends Consumer { if (db == null) { return; } + UUID uuid = data.getUuid(); if (handler.getProcessTask().containsUUID(uuid)) { // Wait for process queue. queue.add(data); return; } + Log.debug(uuid + ": Saving: " + uuid); try { db.saveUserData(data); data.stopAccessing(); Log.debug(uuid + ": Saved!"); - if (data.shouldClearAfterSave()) { - if (handler != null) { - handler.getClearTask().scheduleForClear(uuid); - } + if (data.shouldClearAfterSave() + && handler != null) { + handler.getClearTask().scheduleForClear(uuid); } } catch (SQLException ex) { -// queue.add(data); Log.toLog(this.getClass().getName(), ex); } } @@ -132,6 +131,7 @@ class SaveConsumer extends Consumer { if (db != null) { db = null; } + if (handler != null) { handler = null; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Queue.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Queue.java index 31ee765f5..e75022b56 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Queue.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Queue.java @@ -7,8 +7,8 @@ import java.util.concurrent.BlockingQueue; /** * Abstract implementation of a Queue. * - * @author Rsl1122 * @param Object this queue consumes + * @author Rsl1122 */ public abstract class Queue { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Setup.java b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Setup.java index cdc561088..813e5bb1f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Setup.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/cache/queue/Setup.java @@ -5,8 +5,8 @@ import main.java.com.djrapitops.plan.Plan; /** * Abstract representation of a queue setup. * - * @author Rsl1122 * @param Object this queue consumes. + * @author Rsl1122 */ public abstract class Setup { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/ChatHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/ChatHandling.java index 3f30fbac2..c46a34446 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/ChatHandling.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/ChatHandling.java @@ -11,15 +11,21 @@ import main.java.com.djrapitops.plan.data.UserData; */ public class ChatHandling { + /** + * Constructor used to hide the public constructor + */ + private ChatHandling() { + throw new IllegalStateException("Utility class"); + } + /** * Processes the information of the Event and changes UserData object * accordingly. * - * @param data UserData of the player. + * @param data UserData of the player. * @param nickname Nickname of the player during the event. - * @param msg Message sent by the player. */ - public static void processChatInfo(UserData data, String nickname, String msg) { + public static void processChatInfo(UserData data, String nickname) { data.addNickname(nickname); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/GamemodeHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/GamemodeHandling.java deleted file mode 100644 index b4f0edb76..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/GamemodeHandling.java +++ /dev/null @@ -1,46 +0,0 @@ -package main.java.com.djrapitops.plan.data.handling; - -import com.djrapitops.plugin.utilities.player.Gamemode; -import main.java.com.djrapitops.plan.data.UserData; - -import java.util.Map; - -/** - * Class containing static methods for processing information contained in a - * GamemodeChangeEvent. - * - * @author Rsl1122 - * @since 3.0.0 - */ -public class GamemodeHandling { - - /** - * Processes the information of the Event and changes UserData object - * accordingly. - * - * @param data UserData of the player. - * @param time Epoch ms the event occurred. - * @param newGM The Gamemode the player changed to. - */ - public static void processGamemodeInfo(UserData data, long time, Gamemode newGM) { - if (newGM == null) { - return; - } - final String newGamemode = newGM.name(); - String lastGamemode = data.getLastGamemode(); - - if (lastGamemode == null) { - data.setLastGamemode(newGamemode); - } - lastGamemode = data.getLastGamemode(); - Map times = data.getGmTimes(); - long currentGMTime = times.getOrDefault(lastGamemode, 0L); - data.setPlayTime(data.getPlayTime() + (time - data.getLastPlayed())); - data.setLastPlayed(time); - long lastSwap = data.getLastGmSwapTime(); - long playtime = data.getPlayTime(); - data.setGMTime(lastGamemode, currentGMTime + (playtime - lastSwap)); - data.setLastGmSwapTime(playtime); - data.setLastGamemode(newGamemode); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/KillHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/KillHandling.java index aef91d044..75042f01f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/KillHandling.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/KillHandling.java @@ -1,7 +1,5 @@ package main.java.com.djrapitops.plan.data.handling; -import java.sql.SQLException; -import java.util.UUID; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.KillData; @@ -9,6 +7,9 @@ import main.java.com.djrapitops.plan.data.UserData; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import java.sql.SQLException; +import java.util.UUID; + /** * Class containing static methods for processing information contained in a * DeathEvent when the killer is a player. @@ -18,13 +19,20 @@ import org.bukkit.entity.Player; */ public class KillHandling { + /** + * Utility Class, hides constructor. + */ + private KillHandling() { + throw new IllegalStateException("Utility Class."); + } + /** * Processes the information of the Event and changes UserData object * accordingly. * - * @param data UserData of the player. - * @param time Epoch ms the event occurred. - * @param dead Mob or a Player the player killed. + * @param data UserData of the player. + * @param time Epoch ms the event occurred. + * @param dead Mob or a Player the player killed. * @param weaponName The name of the Weapon used. */ public static void processKillInfo(UserData data, long time, LivingEntity dead, String weaponName) { @@ -34,7 +42,7 @@ public class KillHandling { int victimID; try { UUID victimUUID = deadPlayer.getUniqueId(); - victimID = plugin.getDB().getUsersTable().getUserId(victimUUID + ""); + victimID = plugin.getDB().getUsersTable().getUserId(victimUUID); if (victimID == -1) { return; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/LoginHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/LoginHandling.java index 2b40e3b73..8a800ad36 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/LoginHandling.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/LoginHandling.java @@ -14,15 +14,22 @@ import java.net.InetAddress; */ public class LoginHandling { + /** + * Utility Class, hides constructor. + */ + private LoginHandling() { + throw new IllegalStateException("Utility Class."); + } + /** * Processes the information of the Event and changes UserData object * accordingly. * - * @param data UserData of the player. - * @param time Epoch ms the event occurred. - * @param ip IP of the player - * @param banned Is the player banned - * @param nickname Nickname of the player + * @param data UserData of the player. + * @param time Epoch ms the event occurred. + * @param ip IP of the player + * @param banned Is the player banned + * @param nickname Nickname of the player * @param loginTimes amount the loginTimes should be incremented with. */ public static void processLoginInfo(UserData data, long time, InetAddress ip, boolean banned, String nickname, int loginTimes) { @@ -36,10 +43,10 @@ public class LoginHandling { /** * Updates the geolocation of the player. - * + *

* Uses free service of freegeoip.net. 15000 requests can be sent per hour. * - * @param ip InetAddress used for location. + * @param ip InetAddress used for location. * @param data UserData of the player. * @see GeolocationCacheHandler */ diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/LogoutHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/LogoutHandling.java index 5c2c37259..ea1ec1038 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/LogoutHandling.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/LogoutHandling.java @@ -15,8 +15,8 @@ public class LogoutHandling { * Processes the information of the Event and changes UserData object * accordingly. * - * @param data UserData of the player. - * @param time Epoch ms the event occurred. + * @param data UserData of the player. + * @param time Epoch ms the event occurred. * @param banned Is the player banned? */ public static void processLogoutInfo(UserData data, long time, boolean banned) { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/PlaytimeHandling.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/PlaytimeHandling.java new file mode 100644 index 000000000..3a7e301d2 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/PlaytimeHandling.java @@ -0,0 +1,25 @@ +package main.java.com.djrapitops.plan.data.handling; + +import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.time.GMTimes; +import main.java.com.djrapitops.plan.data.time.WorldTimes; + +public class PlaytimeHandling { + + public static void processPlaytimeDependentInfo(UserData data, long time, String gamemode, String worldName) { + long diff = time - data.getLastPlayed(); + long playTime = data.getPlayTime() + diff; + data.setPlayTime(playTime); + data.setLastPlayed(time); + + GMTimes gmTimes = data.getGmTimes(); + if (gamemode != null) { + gmTimes.changeState(gamemode, playTime); + } else { + gmTimes.changeState(gmTimes.getState(), playTime); + } + + WorldTimes worldTimes = data.getWorldTimes(); + worldTimes.changeState(worldName, playTime); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/ImportUtils.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/ImportUtils.java index 3e82c5c9b..546d315a6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/ImportUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/ImportUtils.java @@ -1,9 +1,11 @@ package main.java.com.djrapitops.plan.data.handling.importing; import com.djrapitops.pluginbridge.plan.importing.OnTimeImporter; +import main.java.com.djrapitops.plan.Log; + import java.util.HashMap; import java.util.Map; -import main.java.com.djrapitops.plan.Log; + import static org.bukkit.Bukkit.getPluginManager; /** @@ -34,7 +36,7 @@ public class ImportUtils { try { importers.put("ontime", new OnTimeImporter()); importers.put("offline", new OfflinePlayerImporter()); - } catch (Throwable e) { + } catch (Exception e) { Log.toLog("ImportUtils.getImporters", e); Log.error("Plan Plugin Bridge not included in the plugin jar."); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/Importer.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/Importer.java index 8fd167b8d..86a124843 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/Importer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/Importer.java @@ -2,15 +2,6 @@ package main.java.com.djrapitops.plan.data.handling.importing; import com.djrapitops.plugin.utilities.player.Fetch; import com.djrapitops.plugin.utilities.player.IOfflinePlayer; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.function.Function; -import java.util.stream.Collectors; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.UserData; @@ -21,6 +12,11 @@ import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.utilities.Benchmark; import main.java.com.djrapitops.plan.utilities.NewPlayerCreator; +import java.sql.SQLException; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + /** * Abstract class used for importing data from other plugins. * @@ -52,11 +48,11 @@ public abstract class Importer { /** * Method used for the import. - * + *

* Creates UserData for players that have not been saved to the database. * * @param uuids UUIDs to be imported - * @param args arguments for the import + * @param args arguments for the import * @return success */ public boolean importData(Collection uuids, String... args) { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/OfflinePlayerImporter.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/OfflinePlayerImporter.java index a8b079e43..0f903d190 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/OfflinePlayerImporter.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/importing/OfflinePlayerImporter.java @@ -1,8 +1,9 @@ package main.java.com.djrapitops.plan.data.handling.importing; -import java.util.UUID; import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; +import java.util.UUID; + /** * Imports all players who have not joined since Plan was installed. * diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ChatInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ChatInfo.java index 97fda4881..9225bf5fc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ChatInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ChatInfo.java @@ -14,19 +14,16 @@ import java.util.UUID; public class ChatInfo extends HandlingInfo { private final String nickname; - private final String message; /** * Constructor. * - * @param uuid UUID of the player. + * @param uuid UUID of the player. * @param nickname Nickname of the player. - * @param message Message the player sent. */ - public ChatInfo(UUID uuid, String nickname, String message) { + public ChatInfo(UUID uuid, String nickname) { super(uuid, InfoType.CHAT, 0L); this.nickname = nickname; - this.message = message; } @Override @@ -34,7 +31,7 @@ public class ChatInfo extends HandlingInfo { if (!uData.getUuid().equals(uuid)) { return false; } - ChatHandling.processChatInfo(uData, nickname, message); + ChatHandling.processChatInfo(uData, nickname); return true; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/DeathInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/DeathInfo.java index 30ee3704f..9c077c132 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/DeathInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/DeathInfo.java @@ -1,8 +1,9 @@ package main.java.com.djrapitops.plan.data.handling.info; -import java.util.UUID; import main.java.com.djrapitops.plan.data.UserData; +import java.util.UUID; + /** * HandlingInfo Class for DeathEvent information. * diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfo.java deleted file mode 100644 index 9d5a782d8..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfo.java +++ /dev/null @@ -1,41 +0,0 @@ -package main.java.com.djrapitops.plan.data.handling.info; - -import com.djrapitops.plugin.utilities.player.Gamemode; -import java.util.UUID; -import main.java.com.djrapitops.plan.data.UserData; -import main.java.com.djrapitops.plan.data.handling.GamemodeHandling; - -/** - * HandlingInfo Class for GamemodeChangeEvent information. - * - * @author Rsl1122 - * @since 3.0.0 - */ -public class GamemodeInfo extends HandlingInfo { - - private final Gamemode currentGamemode; - - /** - * Constructor. - * - * @param uuid UUID of the player. - * @param time Epoch ms of the event. - * @param gm Gamemode the player changed to. - */ - public GamemodeInfo(UUID uuid, long time, Gamemode gm) { - super(uuid, InfoType.GM, time); - currentGamemode = gm; - } - - @Override - public boolean process(UserData uData) { - if (currentGamemode == null) { - return false; - } - if (!uData.getUuid().equals(uuid)) { - return false; - } - GamemodeHandling.processGamemodeInfo(uData, time, currentGamemode); - return true; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/HandlingInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/HandlingInfo.java index 1e3f25b02..7b5e6f93e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/HandlingInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/HandlingInfo.java @@ -22,7 +22,7 @@ public abstract class HandlingInfo { * * @param uuid UUID of the player * @param type InfoType enum of the event. Only used for debugging different - * types. + * types. * @param time Epoch ms of the event. */ public HandlingInfo(UUID uuid, InfoType type, long time) { @@ -60,7 +60,7 @@ public abstract class HandlingInfo { /** * Process the info and modify the UserData object accordingly. - * + *

* If the UUIDs don't match no change should occur. * * @param uData UserData object to modify. diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/InfoType.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/InfoType.java index 793e54406..531eb9f46 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/InfoType.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/InfoType.java @@ -2,9 +2,9 @@ package main.java.com.djrapitops.plan.data.handling.info; /** * Enum class for the types of HandlingInfo to be processed. - * + *

* Type is only used for debugging. - * + *

* OTHER should be used when * * @author Rsl1122 @@ -49,5 +49,6 @@ public enum InfoType { * * @since 3.1.1 */ + WORLD, OTHER } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KickInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KickInfo.java index ff5ab977f..59fcb4350 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KickInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KickInfo.java @@ -1,8 +1,9 @@ package main.java.com.djrapitops.plan.data.handling.info; -import java.util.UUID; import main.java.com.djrapitops.plan.data.UserData; +import java.util.UUID; + /** * HandlingInfo Class for KickEvent information. * diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KillInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KillInfo.java index 4a17348a3..1ccf83b1c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KillInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/KillInfo.java @@ -21,9 +21,9 @@ public class KillInfo extends HandlingInfo { /** * Constructor. * - * @param uuid UUID of the killer. - * @param time Epoch ms the event occurred. - * @param dead Dead entity (Mob or Player) + * @param uuid UUID of the killer. + * @param time Epoch ms the event occurred. + * @param dead Dead entity (Mob or Player) * @param weaponName Weapon used. */ public KillInfo(UUID uuid, long time, LivingEntity dead, String weaponName) { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LoginInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LoginInfo.java index dd12297af..954b2cc6f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LoginInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LoginInfo.java @@ -1,6 +1,5 @@ package main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.LoginHandling; @@ -18,41 +17,48 @@ public class LoginInfo extends HandlingInfo { private final InetAddress ip; private final boolean banned; private final String nickname; - private final GamemodeInfo gmInfo; + private final PlaytimeDependentInfo playtimeDependentInfo; private final int loginTimes; /** * Constructor. * - * @param uuid UUID of the player. - * @param time Epoch ms of the event. - * @param ip IP of the player - * @param banned Is the player banned? - * @param nickname Nickname of the player - * @param gm current gamemode of the player + * @param uuid UUID of the player. + * @param time Epoch ms of the event. + * @param ip IP of the player + * @param banned Is the player banned? + * @param nickname Nickname of the player + * @param gm current gamemode of the player * @param loginTimes number the loginTimes should be incremented with. */ - public LoginInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, Gamemode gm, int loginTimes) { + public LoginInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, String gm, int loginTimes, String worldName) { super(uuid, InfoType.LOGIN, time); this.ip = ip; this.banned = banned; this.nickname = nickname; - this.gmInfo = new GamemodeInfo(uuid, time, gm); + this.playtimeDependentInfo = new PlaytimeDependentInfo(uuid, InfoType.OTHER, time, gm, worldName); this.loginTimes = loginTimes; } /** * Constructor for not incrementing the loginTimes. + *

+ * This constructor is used only by ReloadInfo * - * @param uuid UUID of the player. - * @param time Epoch ms of the event. - * @param ip IP of the player - * @param banned Is the player banned? + * @param uuid UUID of the player. + * @param time Epoch ms of the event. + * @param ip IP of the player + * @param banned Is the player banned? * @param nickname Nickname of the player - * @param gm current gamemode of the player + * @param gm current gamemode of the player */ - public LoginInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, Gamemode gm) { - this(uuid, time, ip, banned, nickname, gm, 0); + public LoginInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, String gm, String worldName) { + super(uuid, InfoType.RELOAD, time); + this.ip = ip; + this.banned = banned; + this.nickname = nickname; + this.playtimeDependentInfo = new PlaytimeDependentInfo(uuid, InfoType.OTHER, time, gm, worldName); + this.loginTimes = 0; } @Override @@ -61,7 +67,7 @@ public class LoginInfo extends HandlingInfo { return false; } LoginHandling.processLoginInfo(uData, time, ip, banned, nickname, loginTimes); - gmInfo.process(uData); + playtimeDependentInfo.process(uData); return true; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LogoutInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LogoutInfo.java index 87ed6b107..c591190b3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LogoutInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/LogoutInfo.java @@ -1,6 +1,5 @@ package main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.LogoutHandling; @@ -17,23 +16,23 @@ public class LogoutInfo extends HandlingInfo { private final boolean banned; private final SessionData sData; - private final GamemodeInfo gmInfo; + private final PlaytimeDependentInfo playtimeDependentInfo; /** * Constructor. * - * @param uuid UUID of the player. - * @param time Epoch ms of the event. + * @param uuid UUID of the player. + * @param time Epoch ms of the event. * @param banned Is the player banned - * @param gm current gamemode of the player - * @param sData session that has been ended at the moment of the logout - * event. + * @param gm current gamemode of the player + * @param sData session that has been ended at the moment of the logout + * event. */ - public LogoutInfo(UUID uuid, long time, boolean banned, Gamemode gm, SessionData sData) { + public LogoutInfo(UUID uuid, long time, boolean banned, String gm, SessionData sData, String worldName) { super(uuid, InfoType.LOGOUT, time); this.banned = banned; this.sData = sData; - this.gmInfo = new GamemodeInfo(uuid, time, gm); + this.playtimeDependentInfo = new PlaytimeDependentInfo(uuid, InfoType.OTHER, time, gm, worldName); } @Override @@ -43,7 +42,7 @@ public class LogoutInfo extends HandlingInfo { } uData.addSession(sData); LogoutHandling.processLogoutInfo(uData, time, banned); - gmInfo.process(uData); + playtimeDependentInfo.process(uData); return true; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/PlaytimeDependentInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/PlaytimeDependentInfo.java new file mode 100644 index 000000000..757c4e88f --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/PlaytimeDependentInfo.java @@ -0,0 +1,27 @@ +package main.java.com.djrapitops.plan.data.handling.info; + +import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.handling.PlaytimeHandling; + +import java.util.UUID; + +public class PlaytimeDependentInfo extends HandlingInfo { + + private final String gamemode; + private final String worldName; + + public PlaytimeDependentInfo(UUID uuid, InfoType type, long time, String gm, String worldName) { + super(uuid, type, time); + this.worldName = worldName; + this.gamemode = gm; + } + + @Override + public boolean process(UserData uData) { + if (!uuid.equals(uData.getUuid())) { + return false; + } + PlaytimeHandling.processPlaytimeDependentInfo(uData, time, gamemode, worldName); + return true; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ReloadInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ReloadInfo.java index 5d4d7043e..3b289fd08 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ReloadInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/handling/info/ReloadInfo.java @@ -1,9 +1,5 @@ package main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; -import main.java.com.djrapitops.plan.data.UserData; -import main.java.com.djrapitops.plan.data.handling.LoginHandling; - import java.net.InetAddress; import java.util.UUID; @@ -13,43 +9,19 @@ import java.util.UUID; * @author Rsl1122 * @since 3.0.0 */ -public class ReloadInfo extends HandlingInfo { - - private final InetAddress ip; - private final boolean banned; - private final String nickname; - private final GamemodeInfo gmInfo; +public class ReloadInfo extends LoginInfo { /** * Constructor. * - * @param uuid UUID of the player. - * @param time Epoch ms of the event. - * @param ip IP of the player - * @param banned Is the player banned? + * @param uuid UUID of the player. + * @param time Epoch ms of the event. + * @param ip IP of the player + * @param banned Is the player banned? * @param nickname Nickname of the player - * @param gm current gamemode of the player + * @param gm current gamemode of the player */ - public ReloadInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, Gamemode gm) { - super(uuid, InfoType.RELOAD, time); - this.ip = ip; - this.banned = banned; - this.nickname = nickname; - gmInfo = new GamemodeInfo(uuid, time, gm); + public ReloadInfo(UUID uuid, long time, InetAddress ip, boolean banned, String nickname, String gm, String worldName) { + super(uuid, time, ip, banned, nickname, gm, worldName); } - - @Override - public boolean process(UserData uData) { - if (!uData.getUuid().equals(uuid)) { - return false; - } - uData.setPlayTime(uData.getPlayTime() + (time - uData.getLastPlayed())); - uData.setLastPlayed(time); - uData.updateBanned(banned); - uData.addIpAddress(ip); - uData.addNickname(nickname); - LoginHandling.updateGeolocation(ip, uData); - return gmInfo.process(uData); - } - } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanChatListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanChatListener.java index fec2e8c90..2b1567df1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanChatListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanChatListener.java @@ -37,7 +37,8 @@ public class PlanChatListener implements Listener { if (event.isCancelled()) { return; } + Player p = event.getPlayer(); - handler.addToPool(new ChatInfo(p.getUniqueId(), p.getDisplayName(), event.getMessage())); + handler.addToPool(new ChatInfo(p.getUniqueId(), p.getDisplayName())); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanCommandPreprocessListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanCommandPreprocessListener.java index 143997743..4e74dee7a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanCommandPreprocessListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanCommandPreprocessListener.java @@ -49,14 +49,14 @@ public class PlanCommandPreprocessListener implements Listener { boolean combineCommandAliasesToMainCommand = Settings.COMBINE_COMMAND_ALIASES_TO_MAIN_COMMAND.isTrue(); if (doNotLogUnknownCommands || combineCommandAliasesToMainCommand) { - Command command = plugin.getServer().getPluginCommand(commandName); + Command command = plugin.getServer().getPluginCommand(commandName.substring(1, commandName.length())); if (command == null) { if (doNotLogUnknownCommands) { Log.debug("Ignored command, command is unknown"); return; } } else if (combineCommandAliasesToMainCommand) { - commandName = command.getName(); + commandName = "/" + command.getName(); } } @@ -66,6 +66,7 @@ public class PlanCommandPreprocessListener implements Listener { Log.debug("Ignored command, player had ignore permission."); return; } + handler.handleCommand(commandName); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanDeathEventListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanDeathEventListener.java index 06cd75d31..9c25f8fd9 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanDeathEventListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanDeathEventListener.java @@ -6,11 +6,12 @@ import main.java.com.djrapitops.plan.data.handling.info.DeathInfo; import main.java.com.djrapitops.plan.data.handling.info.KillInfo; import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.Material; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; /** @@ -41,23 +42,51 @@ public class PlanDeathEventListener implements Listener { public void onDeath(EntityDeathEvent event) { long time = MiscUtils.getTime(); LivingEntity dead = event.getEntity(); - Player killer = dead.getKiller(); - boolean killerIsPlayer = killer != null; - if (killerIsPlayer) { - Material itemInHand; - try { - itemInHand = killer.getInventory().getItemInMainHand().getType(); - } catch (Throwable e) { - try { - itemInHand = killer.getInventory().getItemInHand().getType(); // Support for non dual wielding versions. - } catch (Throwable e2) { - itemInHand = Material.AIR; - } - } - handler.addToPool(new KillInfo(killer.getUniqueId(), time, dead, itemInHand.name())); - } + if (dead instanceof Player) { handler.addToPool(new DeathInfo(dead.getUniqueId())); } + + EntityDamageEvent entityDamageEvent = dead.getLastDamageCause(); + if (!(entityDamageEvent instanceof EntityDamageByEntityEvent)) { + return; + } + + EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) entityDamageEvent; + Entity killerEntity = entityDamageByEntityEvent.getDamager(); + + if (killerEntity instanceof Player) { + Player killer = (Player) killerEntity; + Material itemInHand; + try { + itemInHand = killer.getInventory().getItemInMainHand().getType(); + } catch (Exception e) { + try { + itemInHand = killer.getInventory().getItemInHand().getType(); // Support for non dual wielding versions. + } catch (Exception e2) { + itemInHand = Material.AIR; + } + } + + handler.addToPool(new KillInfo(killer.getUniqueId(), time, dead, itemInHand.name())); + return; + } + + if (killerEntity instanceof Wolf) { + Wolf wolf = (Wolf) killerEntity; + + if (!wolf.isTamed()) { + return; + } + + AnimalTamer owner = wolf.getOwner(); + + if (!(owner instanceof Player)) { + return; + } + + handler.addToPool(new KillInfo(owner.getUniqueId(), time, dead, "Wolf")); + } } } + diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanGamemodeChangeListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanGamemodeChangeListener.java index 8b4bc9ffd..4a21103e5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanGamemodeChangeListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanGamemodeChangeListener.java @@ -1,9 +1,9 @@ package main.java.com.djrapitops.plan.data.listeners; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.cache.DataCacheHandler; -import main.java.com.djrapitops.plan.data.handling.info.GamemodeInfo; +import main.java.com.djrapitops.plan.data.handling.info.InfoType; +import main.java.com.djrapitops.plan.data.handling.info.PlaytimeDependentInfo; import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -11,6 +11,8 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerGameModeChangeEvent; +import java.util.UUID; + /** * Event Listener for PlayerGameModeChangeEvents. * @@ -41,6 +43,8 @@ public class PlanGamemodeChangeListener implements Listener { return; } Player p = event.getPlayer(); - handler.addToPool(new GamemodeInfo(p.getUniqueId(), MiscUtils.getTime(), Gamemode.wrap(event.getNewGameMode()))); + UUID uuid = p.getUniqueId(); + long time = MiscUtils.getTime(); + handler.addToPool(new PlaytimeDependentInfo(uuid, InfoType.GM, time, event.getNewGameMode().name(), p.getWorld().getName())); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanPlayerListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanPlayerListener.java index 315b42bf1..e57d54790 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanPlayerListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanPlayerListener.java @@ -1,8 +1,9 @@ package main.java.com.djrapitops.plan.data.listeners; import com.djrapitops.plugin.task.AbsRunnable; +import com.djrapitops.plugin.utilities.player.Fetch; import com.djrapitops.plugin.utilities.player.Gamemode; -import com.djrapitops.plugin.utilities.player.bukkit.BukkitPlayer; +import com.djrapitops.plugin.utilities.player.IPlayer; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.UserData; @@ -20,12 +21,14 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; +import java.net.InetAddress; import java.util.UUID; /** * Event Listener for PlayerJoin, PlayerQuit and PlayerKickEvents. * * @author Rsl1122 + * @since 2.0.0 */ public class PlanPlayerListener implements Listener { @@ -34,9 +37,8 @@ public class PlanPlayerListener implements Listener { /** * Class Constructor. - * - * Copies the references to multiple handlers from Current instance of - * handler. + *

+ * Copies the references to multiple handlers from Current instance of handler. * * @param plugin Current instance of Plan */ @@ -47,42 +49,57 @@ public class PlanPlayerListener implements Listener { /** * PlayerJoinEvent Listener. - * - * If player is a new player, creates a new data in the database for the - * player. Retrieves the UserData, updates and then saves it to the Cache. + *

+ * If player is a new player, creates new data for the player. + *

+ * Adds a LoginInfo to the processingQueue if the user is not new. * * @param event The Fired event. */ @EventHandler(priority = EventPriority.MONITOR) public void onPlayerLogin(PlayerJoinEvent event) { Player player = event.getPlayer(); + + IPlayer iPlayer = Fetch.wrapBukkit(player); + plugin.getNotificationCenter().checkNotifications(iPlayer); + UUID uuid = player.getUniqueId(); handler.startSession(uuid); Log.debug(uuid + ": PlayerJoinEvent"); + plugin.getRunnableFactory().createNew(new AbsRunnable("NewPlayerCheckTask") { @Override public void run() { - LoginInfo loginInfo = new LoginInfo(uuid, MiscUtils.getTime(), player.getAddress().getAddress(), player.isBanned(), player.getDisplayName(), Gamemode.wrap(player.getGameMode()), 1); + long time = MiscUtils.getTime(); + InetAddress ip = player.getAddress().getAddress(); + boolean banned = player.isBanned(); + String displayName = player.getDisplayName(); + String gm = player.getGameMode().name(); + String worldName = player.getWorld().getName(); + + LoginInfo loginInfo = new LoginInfo(uuid, time, ip, banned, displayName, gm, 1, worldName); boolean isNewPlayer = !plugin.getDB().wasSeenBefore(uuid); + if (isNewPlayer) { - UserData newUserData = NewPlayerCreator.createNewPlayer(BukkitPlayer.wrap(player)); + UserData newUserData = NewPlayerCreator.createNewPlayer(iPlayer); loginInfo.process(newUserData); handler.newPlayer(newUserData); } else { handler.addToPool(loginInfo); } + Log.debug(uuid + ": PlayerJoinEvent_AsyncTask_END, New:" + isNewPlayer); this.cancel(); } }).runTaskAsynchronously(); + Log.debug(uuid + ": PlayerJoinEvent_END"); } /** * PlayerQuitEvent Listener. - * - * Retrieves the current UserData for the Player, updates it, saves the data - * to Database and clears it from cache. + *

+ * Adds a LogoutInfo to the processing Queue. * * @param event Fired event */ @@ -92,15 +109,20 @@ public class PlanPlayerListener implements Listener { UUID uuid = player.getUniqueId(); handler.endSession(uuid); Log.debug(uuid + ": PlayerQuitEvent"); - handler.addToPool(new LogoutInfo(uuid, MiscUtils.getTime(), player.isBanned(), Gamemode.wrap(player.getGameMode()), handler.getSession(uuid))); + long time = MiscUtils.getTime(); + boolean banned = player.isBanned(); + Gamemode gm = Gamemode.wrap(player.getGameMode()); + String worldName = player.getWorld().getName(); + + handler.addToPool(new LogoutInfo(uuid, time, banned, gm.name(), handler.getSession(uuid), worldName)); handler.saveCachedData(uuid); Log.debug(uuid + ": PlayerQuitEvent_END"); } /** * PlayerKickEvent Listener. - * - * Updates current playerdata and saves it to the Database. + *

+ * Adds a KickInfo & LogoutInfo to the processing Queue. * * @param event Fired event */ @@ -113,7 +135,12 @@ public class PlanPlayerListener implements Listener { UUID uuid = player.getUniqueId(); handler.endSession(uuid); Log.debug(uuid + ": PlayerKickEvent"); - handler.addToPool(new LogoutInfo(uuid, MiscUtils.getTime(), player.isBanned(), Gamemode.wrap(player.getGameMode()), handler.getSession(uuid))); + long time = MiscUtils.getTime(); + boolean banned = player.isBanned(); + Gamemode gm = Gamemode.wrap(player.getGameMode()); + String worldName = player.getWorld().getName(); + + handler.addToPool(new LogoutInfo(uuid, time, banned, gm.name(), handler.getSession(uuid), worldName)); handler.addToPool(new KickInfo(uuid)); handler.saveCachedData(uuid); Log.debug(uuid + ": PlayerKickEvent_END"); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanWorldChangeListener.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanWorldChangeListener.java new file mode 100644 index 000000000..543d0a086 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/PlanWorldChangeListener.java @@ -0,0 +1,35 @@ +package main.java.com.djrapitops.plan.data.listeners; + +import main.java.com.djrapitops.plan.Plan; +import main.java.com.djrapitops.plan.data.cache.DataCacheHandler; +import main.java.com.djrapitops.plan.data.handling.info.InfoType; +import main.java.com.djrapitops.plan.data.handling.info.PlaytimeDependentInfo; +import main.java.com.djrapitops.plan.utilities.MiscUtils; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; + +import java.util.UUID; + +public class PlanWorldChangeListener implements Listener { + private final DataCacheHandler handler; + + public PlanWorldChangeListener(Plan plugin) { + this.handler = plugin.getHandler(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onWorldChange(PlayerChangedWorldEvent event) { + Player p = event.getPlayer(); + String previousWorld = event.getFrom().getName(); + String worldName = p.getWorld().getName(); + if (previousWorld.equals(worldName)) { + return; + } + UUID uuid = p.getUniqueId(); + long time = MiscUtils.getTime(); + handler.addToPool(new PlaytimeDependentInfo(uuid, InfoType.WORLD, time, p.getGameMode().name(), p.getWorld().getName())); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/listeners/TPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/data/listeners/TPSCountTimer.java index 2fa7b4b5a..90758193b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/listeners/TPSCountTimer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/listeners/TPSCountTimer.java @@ -8,6 +8,7 @@ import main.java.com.djrapitops.plan.data.TPS; import main.java.com.djrapitops.plan.data.cache.DataCacheHandler; import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; +import org.bukkit.World; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; @@ -21,10 +22,10 @@ import java.util.List; */ public class TPSCountTimer extends AbsRunnable { - private long lastCheckNano; private final Plan plugin; private final DataCacheHandler handler; private final List history; + private long lastCheckNano; public TPSCountTimer(Plan plugin) { super("TPSCountTimer"); @@ -60,36 +61,73 @@ public class TPSCountTimer extends AbsRunnable { * Calculates the TPS * * @param diff The time difference between the last run and the new run - * @param now The time right now + * @param now The time right now * @return the TPS */ private TPS calculateTPS(long diff, long now) { OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); int availableProcessors = operatingSystemMXBean.getAvailableProcessors(); double averageCPUUsage = MathUtils.round(operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0); - if (averageCPUUsage < 0) { // If Unavailable, getSystemLoadAverage() returns -1 + + if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 averageCPUUsage = -1; } + Runtime runtime = Runtime.getRuntime(); + + long totalMemory = runtime.totalMemory(); + long usedMemory = (totalMemory - runtime.freeMemory()) / 1000000; + int playersOnline = plugin.getServer().getOnlinePlayers().size(); + int loadedChunks = getLoadedChunks(); + int entityCount; if (plugin.getVariable().isUsingPaper()) { - return getTPSPaper(now, averageCPUUsage, playersOnline); + entityCount = getEntityCountPaper(); + + return getTPSPaper(now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); } else { + entityCount = getEntityCount(); + diff -= TimeAmount.MILLISECOND.ns() * 40L; // 40ms removed because the run appears to take 40-50ms, screwing the tps. - return getTPS(diff, now, averageCPUUsage, playersOnline); + return getTPS(diff, now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); } } + /** + * Gets the TPS for Spigot / Bukkit + * + * @param diff The difference between the last run and this run + * @param now The time right now + * @param cpuUsage The usage of the CPU + * @param playersOnline The amount of players that are online + * @return the TPS + */ + private TPS getTPS(long diff, long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { + if (diff < TimeAmount.SECOND.ns()) { // No tick count above 20 + diff = TimeAmount.SECOND.ns(); + } + + long twentySeconds = 20L * TimeAmount.SECOND.ns(); + while (diff > twentySeconds) { + history.add(new TPS(now, 0, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded)); + diff -= twentySeconds; + } + + double tpsN = twentySeconds * 1.0 / diff; + + return new TPS(now, tpsN, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); + } + /** * Gets the TPS for Paper * - * @param now The time right now - * @param cpuUsage The usage of the CPU + * @param now The time right now + * @param cpuUsage The usage of the CPU * @param playersOnline The amount of players that are online * @return the TPS */ - private TPS getTPSPaper(long now, double cpuUsage, int playersOnline) { + private TPS getTPSPaper(long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { double tps = plugin.getServer().getTPS()[0]; if (tps > 20) { @@ -98,31 +136,33 @@ public class TPSCountTimer extends AbsRunnable { tps = MathUtils.round(tps); - return new TPS(now, tps, playersOnline, cpuUsage); + return new TPS(now, tps, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); } /** - * Gets the TPS for a Spigot / Bukkit + * Gets the amount of loaded chunks * - * @param diff The difference between the last run and this run - * @param now The time right now - * @param cpuUsage The usage of the CPU - * @param playersOnline The amount of players that are online - * @return the TPS + * @return amount of loaded chunks */ - private TPS getTPS(long diff, long now, double cpuUsage, int playersOnline) { - if (diff < TimeAmount.SECOND.ns()) { // No tick count above 20 - diff = TimeAmount.SECOND.ns(); - } + private int getLoadedChunks() { + return plugin.getServer().getWorlds().stream().mapToInt(world -> world.getLoadedChunks().length).sum(); + } - long twentySeconds = 20L * TimeAmount.SECOND.ns(); - while (diff > twentySeconds) { - history.add(new TPS(now, 0, playersOnline, cpuUsage)); - diff -= twentySeconds; - } + /** + * Gets the amount of entities on the server for Bukkit / Spigot + * + * @return amount of entities + */ + private int getEntityCount() { + return plugin.getServer().getWorlds().stream().mapToInt(world -> world.getEntities().size()).sum(); + } - double tpsN = twentySeconds / diff; - - return new TPS(now, tpsN, playersOnline, cpuUsage); + /** + * Gets the amount of entities on the server for Paper + * + * @return amount of entities + */ + private int getEntityCountPaper() { + return plugin.getServer().getWorlds().stream().mapToInt(World::getEntityCount).sum(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/time/GMTimes.java b/Plan/src/main/java/com/djrapitops/plan/data/time/GMTimes.java new file mode 100644 index 000000000..f5e5cf38e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/time/GMTimes.java @@ -0,0 +1,73 @@ +package main.java.com.djrapitops.plan.data.time; + +import com.djrapitops.plugin.utilities.Verify; +import main.java.com.djrapitops.plan.database.tables.GMTimesTable; + +import java.util.Map; + +/** + * TimeKeeper class that tracks the time spent in each GameMode based on Playtime. + * + * @author Rsl1122 + * @since 3.6.0 + */ +public class GMTimes extends TimeKeeper { + + public GMTimes(Map times, String lastState, long lastStateChange) { + super(times, lastState, lastStateChange); + } + + public GMTimes(String lastState, long lastStateChange) { + super(lastState, lastStateChange); + } + + public GMTimes(String lastState) { + super(lastState); + } + + public GMTimes(Map times) { + super(times); + } + + public GMTimes() { + super(); + } + + /** + * Sets times for all 4 gamemodes. + *

+ * Give 1 - 4 parameters. + * times starts from Survival, ends in Spectator. + *

+ * Given too few parameters (Under 4, rest are set as 0L) + * Extra parameters are ignored (Over 4) + * + * @param times 1-4 time parameters. + * @throws IllegalArgumentException If any parameter is null. + */ + public void setAllGMTimes(long... times) throws IllegalArgumentException { + Verify.nullCheck(times); + String[] gms = GMTimesTable.getGMKeyArray(); + int size = times.length; + for (int i = 0; i < 4; i++) { + if (i >= size) { + setTime(gms[i], 0L); + } else { + setTime(gms[i], times[i]); + } + } + } + + public void resetTimes(long playtime) { + resetState("SURVIVAL", playtime); + resetState("CREATIVE"); + resetState("ADVENTURE"); + resetState("SPECTATOR"); + } + + @Override + public String getState() { + String state = super.getState(); + return state != null ? state : "SURVIVAL"; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java b/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java new file mode 100644 index 000000000..b17c28c41 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java @@ -0,0 +1,162 @@ +package main.java.com.djrapitops.plan.data.time; + +import com.djrapitops.plugin.utilities.Verify; + +import java.util.HashMap; +import java.util.Map; + +/** + * Abstract class for keeping track of time spent in each state. + */ +public abstract class TimeKeeper { + /** + * Keeps time of states. + */ + protected Map times; + /** + * Last State seen in + */ + protected String state; + /** + * Relates to Playtime Milliseconds. + */ + protected long lastStateChange; + + public TimeKeeper(Map times, String lastState, long lastStateChange) { + this.times = times; + this.state = lastState; + this.lastStateChange = lastStateChange; + } + + public TimeKeeper(String lastState, long lastStateChange) { + this(new HashMap<>(), lastState, lastStateChange); + } + + public TimeKeeper(String lastState) { + this(new HashMap<>(), lastState, 0L); + } + + public TimeKeeper(Map times) { + this(times, null, 0); + } + + public TimeKeeper() { + this(new HashMap<>()); + } + + public void setTime(String state, long time) throws IllegalArgumentException { + times.put(Verify.nullCheck(state), time); + } + + public void renameState(String state, String renameTo) { + Verify.nullCheck(state, renameTo); + Long time = times.get(state); + if (time != null) { + times.put(renameTo, time); + times.remove(state); + if (state.equals(this.state)) { + this.state = renameTo; + } + } + } + + /** + * Adds time to the last state while updating the status of other parameters. + * + * @param newState New State seen in. + * @param playTime Current Playtime. + * @throws IllegalArgumentException If new state is null. + * @throws IllegalStateException If lastStateChange time is higher than playtime. + */ + public void changeState(String newState, long playTime) throws IllegalArgumentException, IllegalStateException { + Verify.nullCheck(newState); + if (playTime < lastStateChange) { + throw new IllegalStateException("Given Playtime is lower than last status change time: " + playTime + " / " + lastStateChange); + } + if (state == null) { + state = newState; + } + Long currentTime = times.get(state); + if (currentTime == null) { + currentTime = 0L; + } + long diff = playTime - lastStateChange; + times.put(state, currentTime + diff); + state = newState; + lastStateChange = playTime; + } + + protected void resetState(String state) { + times.remove(Verify.nullCheck(state)); + } + + protected void resetState(String state, long time) { + if (time > 0) { + times.put(Verify.nullCheck(state), time); + lastStateChange = time; + this.state = state; + } else { + resetState(state); + } + } + + public long getTime(String state) { + Long time = times.get(state); + return time != null ? time : 0L; + } + + public long getTotal() { + return times.values().stream().mapToLong(i -> i).sum(); + } + + public void setTimes(Map times) { + this.times = times; + } + + public Map getTimes() { + 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; + } + + public void setLastStateChange(long lastStateChange) { + this.lastStateChange = lastStateChange; + } + + public String getState() { + return state; + } + + public long getLastStateChange() { + return lastStateChange; + } + + @Override + public String toString() { + return "times:" + times + + ",state:" + state + + ",lastStateChange:" + lastStateChange; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/time/WorldTimes.java b/Plan/src/main/java/com/djrapitops/plan/data/time/WorldTimes.java new file mode 100644 index 000000000..7ee4e79b4 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/time/WorldTimes.java @@ -0,0 +1,43 @@ +package main.java.com.djrapitops.plan.data.time; + +import java.util.Map; + +/** + * TimeKeeper class that tracks the time spent in each World based on Playtime. + * + * @author Rsl1122 + * @since 3.6.0 + */ +public class WorldTimes extends TimeKeeper { + + public WorldTimes(Map times, String lastState, long lastStateChange) { + super(times, lastState, lastStateChange); + } + + public WorldTimes(String lastState, long lastStateChange) { + super(lastState, lastStateChange); + } + + public WorldTimes(String lastState) { + super(lastState); + } + + public WorldTimes(Map times, long lastStateChange) { + super(times, null, lastStateChange); + } + + public WorldTimes(Map times) { + super(times); + } + + public WorldTimes() { + super(); + } + + @Override + public String getState() { + String state = super.getState(); + return state != null ? state : "Unknown"; + } + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/Container.java b/Plan/src/main/java/com/djrapitops/plan/database/Container.java index 5fa72c0bc..ed9cd2002 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/Container.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/Container.java @@ -3,9 +3,9 @@ package main.java.com.djrapitops.plan.database; /** * Class to contain objects in the batches. * + * @param Object stored. * @author Rsl1122 * @since 3.4.3 - * @param Object stored. */ public class Container { @@ -16,7 +16,7 @@ public class Container { * Constructor for the object. * * @param object Object to place inside the container. - * @param id UserID related to the object. + * @param id UserID related to the object. */ public Container(T object, int id) { this.object = object; diff --git a/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java b/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java index c641b9136..8548c3136 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java @@ -19,15 +19,22 @@ import java.util.Map.Entry; */ public class DBUtils { + /** + * Constructor used to hide the public constructor + */ + private DBUtils() { + throw new IllegalStateException("Utility class"); + } + private static final int BATCH_SIZE = 2048; /** * Splits a collection of objects into lists with the size defined by * BATCH_SIZE. * - * @param Object type + * @param Object type * @param objects Collection of the objects. // * @return Lists with max - * size of BATCH_SIZE. + * size of BATCH_SIZE. * @return */ public static List> splitIntoBatches(Collection objects) { @@ -50,7 +57,6 @@ public class DBUtils { } /** - * * @param * @param objects * @return diff --git a/Plan/src/main/java/com/djrapitops/plan/database/Database.java b/Plan/src/main/java/com/djrapitops/plan/database/Database.java index 3b8ec5654..4c187e7e5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/Database.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/Database.java @@ -10,7 +10,7 @@ import java.util.*; /** * Abstract class representing a Database. - * + *

* All methods should be only called from an asynchronous thread, unless stated * otherwise. * @@ -78,8 +78,27 @@ public abstract class Database { */ protected VersionTable versionTable; + /** + * Table representing plan_security in the database. + * + * @since 3.5.2 + */ protected SecurityTable securityTable; + /** + * Table representing plan_worlds in the database. + * + * @since 3.6.0 + */ + protected WorldTable worldTable; + + /** + * Table representing plan_world_times in the database. + * + * @since 3.6.0 + */ + protected WorldTimesTable worldTimesTable; + /** * Super constructor. * @@ -91,7 +110,7 @@ public abstract class Database { /** * Initiates the database. - * + *

* Default method returns false. * * @return Was the initiation successful? @@ -103,12 +122,12 @@ public abstract class Database { /** * Used to give Database processors to call with UserData after they have * been fetched from the database. - * + *

* This method is a shortcut method for multiple parameters. * - * @param uuid UUID of the player. + * @param uuid UUID of the player. * @param processors Processors to call with the UserData after the fetch is - * complete. + * complete. * @throws SQLException If a database error occurs. */ public void giveUserDataToProcessors(UUID uuid, DBCallableProcessor... processors) throws SQLException { @@ -119,16 +138,16 @@ public abstract class Database { * Used to give Database processors to call with UserData after they have * been fetched from the database. * - * @param uuid UUID of the player. + * @param uuid UUID of the player. * @param processors Processors to call with the UserData after the fetch is - * complete. + * complete. * @throws SQLException If a database error occurs. */ public abstract void giveUserDataToProcessors(UUID uuid, Collection processors) throws SQLException; /** * Used to get all UserData for multiple UUIDs. - * + *

* Should only be called from async thread. * * @param uuids UUIDs to fetch data for. @@ -168,7 +187,7 @@ public abstract class Database { /** * Used to get the name of the database type. - * + *

* Thread safe. * * @return SQLite/MySQL @@ -177,7 +196,7 @@ public abstract class Database { /** * Used to get the config name of the database type. - * + *

* Thread safe. * * @return sqlite/mysql @@ -199,7 +218,7 @@ public abstract class Database { * Used to set the database schema version. * * @param version Integer starting from 0, incremented by one when schema is - * updated. + * updated. * @throws SQLException If a database error occurs. */ public abstract void setVersion(int version) throws SQLException; @@ -222,7 +241,7 @@ public abstract class Database { /** * Used to clear all data from the database. - * + *

* Uses DELETE * FROM table. * * @return Success of removal. @@ -233,7 +252,7 @@ public abstract class Database { * Used to save CommandUse map. * * @param data String command (key), Integer times used - * @throws SQLException If a database error occurs. + * @throws SQLException If a database error occurs. * @throws NullPointerException If the database has not initialized tables. */ public void saveCommandUse(Map data) throws SQLException, NullPointerException { @@ -343,7 +362,30 @@ public abstract class Database { return tpsTable; } + /** + * Used to get the security table. + * + * @return Table representing plan_security + */ public SecurityTable getSecurityTable() { return securityTable; } + + /** + * Used to get the worlds table. + * + * @return Table representing plan_worlds + */ + public WorldTable getWorldTable() { + return worldTable; + } + + /** + * Used to get the world times table. + * + * @return Table representing plan_world_times + */ + public WorldTimesTable getWorldTimesTable() { + return worldTimesTable; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java b/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java index 1140c5b69..21632a8f6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java @@ -1,15 +1,15 @@ package main.java.com.djrapitops.plan.database.databases; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Plan; import org.bukkit.configuration.file.FileConfiguration; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + /** - * * @author Rsl1122 */ public class MySQLDB extends SQLDB { @@ -45,7 +45,6 @@ public class MySQLDB extends SQLDB { } /** - * * @return */ @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java index 81ac4591f..c6a824273 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java @@ -7,6 +7,7 @@ import main.java.com.djrapitops.plan.data.KillData; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; +import main.java.com.djrapitops.plan.data.time.WorldTimes; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.database.tables.*; import main.java.com.djrapitops.plan.utilities.Benchmark; @@ -15,13 +16,16 @@ import main.java.com.djrapitops.plan.utilities.FormatUtils; import java.net.InetAddress; import java.sql.Connection; import java.sql.SQLException; +import java.sql.Statement; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; /** + * Class containing main logic for different data related save & load functionality. * * @author Rsl1122 + * @since 2.0.0 */ public abstract class SQLDB extends Database { @@ -30,7 +34,6 @@ public abstract class SQLDB extends Database { private Connection connection; /** - * * @param plugin * @param supportsModification */ @@ -50,6 +53,8 @@ public abstract class SQLDB extends Database { versionTable = new VersionTable(this, usingMySQL); tpsTable = new TPSTable(this, usingMySQL); securityTable = new SecurityTable(this, usingMySQL); + worldTable = new WorldTable(this, usingMySQL); + worldTimesTable = new WorldTimesTable(this, usingMySQL); startConnectionPingTask(); } @@ -63,19 +68,28 @@ public abstract class SQLDB extends Database { plugin.getRunnableFactory().createNew(new AbsRunnable("DBConnectionPingTask " + getName()) { @Override public void run() { + Statement statement = null; try { if (connection != null && !connection.isClosed()) { - connection.createStatement().execute("/* ping */ SELECT 1"); + statement = connection.createStatement(); + statement.execute("/* ping */ SELECT 1"); } } catch (SQLException e) { connection = getNewConnection(); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + Log.error("Error at closing statement"); + } + } } } }).runTaskTimerAsynchronously(60 * 20, 60 * 20); } /** - * * @return */ @Override @@ -99,7 +113,6 @@ public abstract class SQLDB extends Database { } /** - * * @return @throws SQLException */ public boolean checkConnection() throws SQLException { @@ -114,30 +127,37 @@ public abstract class SQLDB extends Database { try { getVersion(); newDatabase = false; - } catch (Exception e) { + } catch (Exception ignored) { + } if (!versionTable.createTable()) { Log.error("Failed to create table: " + versionTable.getTableName()); return false; } + if (newDatabase) { Log.info("New Database created."); - setVersion(6); + setVersion(8); } + Benchmark.start("Database: Create tables"); + for (Table table : getAllTables()) { if (!table.createTable()) { Log.error("Failed to create table: " + table.getTableName()); return false; } } + if (!securityTable.createTable()) { Log.error("Failed to create table: " + securityTable.getTableName()); return false; } + Benchmark.stop("Database: Create tables"); - if (!newDatabase && getVersion() < 6) { - setVersion(6); + + if (!newDatabase && getVersion() < 8) { + setVersion(8); } } return true; @@ -178,29 +198,33 @@ public abstract class SQLDB extends Database { } /** - * * @return */ public Table[] getAllTables() { - return new Table[]{usersTable, gmTimesTable, ipsTable, nicknamesTable, sessionsTable, killsTable, commandUseTable, tpsTable}; + return new Table[]{ + usersTable, gmTimesTable, ipsTable, + nicknamesTable, sessionsTable, killsTable, + commandUseTable, tpsTable, worldTable, + worldTimesTable}; } /** - * * @return */ public Table[] getAllTablesInRemoveOrder() { - return new Table[]{locationsTable, gmTimesTable, ipsTable, nicknamesTable, sessionsTable, killsTable, usersTable, commandUseTable, tpsTable}; + return new Table[]{ + locationsTable, gmTimesTable, ipsTable, + nicknamesTable, sessionsTable, killsTable, + worldTimesTable, worldTable, usersTable, + commandUseTable, tpsTable}; } /** - * * @return */ public abstract Connection getNewConnection(); /** - * * @throws SQLException */ @Override @@ -212,7 +236,6 @@ public abstract class SQLDB extends Database { } /** - * * @return @throws SQLException */ @Override @@ -221,7 +244,6 @@ public abstract class SQLDB extends Database { } /** - * * @param version * @throws SQLException */ @@ -231,7 +253,6 @@ public abstract class SQLDB extends Database { } /** - * * @param uuid * @return */ @@ -252,7 +273,6 @@ public abstract class SQLDB extends Database { } /** - * * @param uuid * @return * @throws SQLException @@ -273,7 +293,15 @@ public abstract class SQLDB extends Database { return false; } int userId = usersTable.getUserId(uuid); - return userId != -1 && locationsTable.removeUserLocations(userId) && ipsTable.removeUserIps(userId) && nicknamesTable.removeUserNicknames(userId) && gmTimesTable.removeUserGMTimes(userId) && sessionsTable.removeUserSessions(userId) && killsTable.removeUserKillsAndVictims(userId) && usersTable.removeUser(uuid); + return userId != -1 + && locationsTable.removeUserLocations(userId) + && ipsTable.removeUserIps(userId) + && nicknamesTable.removeUserNicknames(userId) + && gmTimesTable.removeUserGMTimes(userId) + && sessionsTable.removeUserSessions(userId) + && killsTable.removeUserKillsAndVictims(userId) + && worldTimesTable.removeUserWorldTimes(userId) + && usersTable.removeUser(uuid); } finally { Benchmark.stop("Database: Remove Account"); setAvailable(); @@ -281,7 +309,6 @@ public abstract class SQLDB extends Database { } /** - * * @param uuid * @param processors * @throws SQLException @@ -307,25 +334,31 @@ public abstract class SQLDB extends Database { List nicknames = nicknamesTable.getNicknames(userId); data.addNicknames(nicknames); - if (nicknames.size() > 0) { + if (!nicknames.isEmpty()) { data.setLastNick(nicknames.get(nicknames.size() - 1)); } List ips = ipsTable.getIPAddresses(userId); data.addIpAddresses(ips); - Map times = gmTimesTable.getGMTimes(userId); - data.setGmTimes(times); + Map gmTimes = gmTimesTable.getGMTimes(userId); + data.getGmTimes().setTimes(gmTimes); + Map worldTimes = worldTimesTable.getWorldTimes(userId); + WorldTimes worldT = data.getWorldTimes(); + worldT.setTimes(worldTimes); + if (worldT.getLastStateChange() == 0) { + worldT.setLastStateChange(data.getPlayTime()); + } + List sessions = sessionsTable.getSessionData(userId); data.addSessions(sessions); data.setPlayerKills(killsTable.getPlayerKills(userId)); - processors.forEach((processor) -> processor.process(data)); + processors.forEach(processor -> processor.process(data)); Benchmark.stop("Database: Give userdata to processors"); setAvailable(); } /** - * * @param uuidsCol * @return * @throws SQLException @@ -339,7 +372,7 @@ public abstract class SQLDB extends Database { Benchmark.start("Database: Get UserData for " + uuidsCol.size()); Map userIds = usersTable.getAllUserIds(); Set remove = uuidsCol.stream() - .filter((uuid) -> (!userIds.containsKey(uuid))) + .filter(uuid -> !userIds.containsKey(uuid)) .collect(Collectors.toSet()); List uuids = new ArrayList<>(uuidsCol); Log.debug("Data not found for: " + remove.size()); @@ -358,23 +391,34 @@ public abstract class SQLDB extends Database { Map> playerKills = killsTable.getPlayerKills(ids, idUuidRel); Map> sessionData = sessionsTable.getSessionData(ids); Map> gmTimes = gmTimesTable.getGMTimes(ids); + Map> worldTimes = worldTimesTable.getWorldTimes(ids); Log.debug("Sizes: UUID:" + uuids.size() + " DATA:" + data.size() + " ID:" + userIds.size() + " N:" + nicknames.size() + " I:" + ipList.size() + " K:" + playerKills.size() + " S:" + sessionData.size()); + for (UserData uData : data) { UUID uuid = uData.getUuid(); Integer id = userIds.get(uuid); uData.addIpAddresses(ipList.get(id)); - uData.addNicknames(nicknames.get(id)); + List userNicks = nicknames.get(id); + uData.addNicknames(userNicks); + if (!userNicks.isEmpty()) { + uData.setLastNick(userNicks.get(userNicks.size() - 1)); + } uData.addSessions(sessionData.get(id)); uData.setPlayerKills(playerKills.get(id)); - uData.setGmTimes(gmTimes.get(id)); + uData.getGmTimes().setTimes(gmTimes.get(id)); + WorldTimes worldT = uData.getWorldTimes(); + worldT.setTimes(worldTimes.get(id)); + if (worldT.getLastStateChange() == 0) { + worldT.setLastStateChange(uData.getPlayTime()); + } } + Benchmark.stop("Database: Get UserData for " + uuidsCol.size()); setAvailable(); return data; } /** - * * @param data * @throws SQLException */ @@ -387,6 +431,7 @@ public abstract class SQLDB extends Database { } setStatus("Save userdata (multiple) for " + data.size()); usersTable.saveUserDataInformationBatch(data); + // Transform to map Map userDatas = data.stream().collect(Collectors.toMap(UserData::getUuid, Function.identity())); // Get UserIDs @@ -399,21 +444,33 @@ public abstract class SQLDB extends Database { Map uuids = userIds.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); Map> sessions = new HashMap<>(); Map> gmTimes = new HashMap<>(); + Map> worldTimes = new HashMap<>(); // Put to dataset - for (UUID uuid : userDatas.keySet()) { + List worldNames = data.stream() + .map(UserData::getWorldTimes) + .map(WorldTimes::getTimes) + .map(Map::keySet) + .flatMap(keySet -> keySet.stream()) + .distinct() + .collect(Collectors.toList()); + for (Map.Entry entrySet : userDatas.entrySet()) { + UUID uuid = entrySet.getKey(); + UserData uData = entrySet.getValue(); Integer id = userIds.get(uuid); - UserData uData = userDatas.get(uuid); + if (id == -1) { Log.debug("User not seen before, saving last: " + uuid); continue; } + uData.access(); nicknames.put(id, new HashSet<>(uData.getNicknames())); lastNicks.put(id, uData.getLastNick()); ips.put(id, new HashSet<>(uData.getIps())); kills.put(id, new ArrayList<>(uData.getPlayerKills())); sessions.put(id, new ArrayList<>(uData.getSessions())); - gmTimes.put(id, uData.getGmTimes()); + gmTimes.put(id, new HashMap<>(uData.getGmTimes().getTimes())); + worldTimes.put(id, new HashMap<>(uData.getWorldTimes().getTimes())); } // Save nicknamesTable.saveNickLists(nicknames, lastNicks); @@ -421,6 +478,8 @@ public abstract class SQLDB extends Database { killsTable.savePlayerKills(kills, uuids); sessionsTable.saveSessionData(sessions); gmTimesTable.saveGMTimes(gmTimes); + worldTable.saveWorlds(worldNames); + worldTimesTable.saveWorldTimes(worldTimes); userDatas.values().stream() .filter(Objects::nonNull) .filter(UserData::isAccessed) @@ -430,7 +489,6 @@ public abstract class SQLDB extends Database { } /** - * * @param data * @throws SQLException */ @@ -453,7 +511,9 @@ public abstract class SQLDB extends Database { nicknamesTable.saveNickList(userId, new HashSet<>(data.getNicknames()), data.getLastNick()); ipsTable.saveIPList(userId, new HashSet<>(data.getIps())); killsTable.savePlayerKills(userId, new ArrayList<>(data.getPlayerKills())); - gmTimesTable.saveGMTimes(userId, data.getGmTimes()); + gmTimesTable.saveGMTimes(userId, data.getGmTimes().getTimes()); + worldTable.saveWorlds(new HashSet<>(data.getWorldTimes().getTimes().keySet())); + worldTimesTable.saveWorldTimes(userId, data.getWorldTimes().getTimes()); data.stopAccessing(); setAvailable(); } @@ -468,7 +528,6 @@ public abstract class SQLDB extends Database { checkConnection(); tpsTable.clean(); locationsTable.removeAllData(); -// sessionsTable.clean(); Log.info("Clean complete."); } catch (SQLException e) { Log.toLog(this.getClass().getName(), e); @@ -476,7 +535,6 @@ public abstract class SQLDB extends Database { } /** - * * @return */ @Override @@ -492,7 +550,6 @@ public abstract class SQLDB extends Database { } /** - * * @return */ public boolean supportsModification() { @@ -500,7 +557,6 @@ public abstract class SQLDB extends Database { } /** - * * @return */ public Connection getConnection() { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java index d1d7aab05..6b07d0bec 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java @@ -1,13 +1,13 @@ package main.java.com.djrapitops.plan.database.databases; +import main.java.com.djrapitops.plan.Plan; + import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import main.java.com.djrapitops.plan.Plan; /** - * * @author Rsl1122 */ public class SQLiteDB extends SQLDB { @@ -24,7 +24,6 @@ public class SQLiteDB extends SQLDB { } /** - * * @param plugin * @param dbName */ @@ -44,7 +43,6 @@ public class SQLiteDB extends SQLDB { } /** - * * @param dbName * @return */ @@ -59,7 +57,6 @@ public class SQLiteDB extends SQLDB { } /** - * * @return */ @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java index 0fa042663..a9261f919 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java @@ -1,16 +1,16 @@ package main.java.com.djrapitops.plan.database.tables; +import main.java.com.djrapitops.plan.Log; +import main.java.com.djrapitops.plan.database.databases.SQLDB; +import main.java.com.djrapitops.plan.utilities.Benchmark; + import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; -import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.database.databases.SQLDB; -import main.java.com.djrapitops.plan.utilities.Benchmark; /** - * * @author Rsl1122 */ public class CommandUseTable extends Table { @@ -19,7 +19,6 @@ public class CommandUseTable extends Table { private final String columnTimesUsed; /** - * * @param db * @param usingMySQL */ @@ -30,7 +29,6 @@ public class CommandUseTable extends Table { } /** - * * @return */ @Override @@ -49,7 +47,6 @@ public class CommandUseTable extends Table { } /** - * * @return @throws SQLException */ public Map getCommandUse() throws SQLException { @@ -78,7 +75,6 @@ public class CommandUseTable extends Table { } /** - * * @param data * @throws SQLException * @throws NullPointerException @@ -91,17 +87,22 @@ public class CommandUseTable extends Table { Map newData = new HashMap<>(data); Map saved = getCommandUse(); newData.keySet().removeAll(saved.keySet()); + insertCommands(newData); + Map updateData = new HashMap<>(data); updateData.keySet().removeAll(newData.keySet()); - for (String cmd : saved.keySet()) { + + for (Map.Entry savedEntry : saved.entrySet()) { + String cmd = savedEntry.getKey(); + // IMPORTANT - not using saved as value Integer toSave = updateData.get(cmd); - if (toSave != null) { - if (toSave <= saved.get(cmd)) { - updateData.remove(cmd); - } + + if (toSave != null && toSave <= savedEntry.getValue()) { + updateData.remove(cmd); } } + updateCommands(updateData); Benchmark.stop("Database: Save Commanduse"); } @@ -112,16 +113,20 @@ public class CommandUseTable extends Table { String updateStatement = "UPDATE " + tableName + " SET " + columnTimesUsed + "=? WHERE (" + columnCommand + "=?)"; statement = prepareStatement(updateStatement); boolean commitRequired = false; - for (String key : data.keySet()) { - Integer amount = data.get(key); + for (Map.Entry entrySet : data.entrySet()) { + String key = entrySet.getKey(); + Integer amount = entrySet.getValue(); + if (key.length() > 20) { continue; } + statement.setInt(1, amount); statement.setString(2, key); statement.addBatch(); commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } @@ -139,16 +144,20 @@ public class CommandUseTable extends Table { + ") VALUES (?, ?)"; statement = prepareStatement(insertStatement); boolean commitRequired = false; - for (String key : data.keySet()) { - Integer amount = data.get(key); + for (Map.Entry entrySet : data.entrySet()) { + String key = entrySet.getKey(); + Integer amount = entrySet.getValue(); + if (key.length() > 20) { continue; } + statement.setString(1, key); statement.setInt(2, amount); statement.addBatch(); commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/GMTimesTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/GMTimesTable.java index 7fe617ea8..c75481364 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/GMTimesTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/GMTimesTable.java @@ -1,5 +1,6 @@ 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.database.databases.SQLDB; import main.java.com.djrapitops.plan.utilities.Benchmark; @@ -10,7 +11,6 @@ import java.sql.SQLException; import java.util.*; /** - * * @author Rsl1122 */ public class GMTimesTable extends Table { @@ -22,7 +22,6 @@ public class GMTimesTable extends Table { private final String columnSpectatorTime; /** - * * @param db * @param usingMySQL */ @@ -40,7 +39,6 @@ public class GMTimesTable extends Table { } /** - * * @return */ @Override @@ -64,7 +62,6 @@ public class GMTimesTable extends Table { } /** - * * @param userId * @return */ @@ -84,7 +81,6 @@ public class GMTimesTable extends Table { } /** - * * @param userId * @return * @throws SQLException @@ -137,13 +133,12 @@ public class GMTimesTable extends Table { } /** - * * @param userId * @param gamemodeTimes * @throws SQLException */ public void saveGMTimes(int userId, Map gamemodeTimes) throws SQLException { - if (gamemodeTimes == null || gamemodeTimes.isEmpty()) { + if (Verify.isEmpty(gamemodeTimes)) { return; } PreparedStatement statement = null; @@ -152,11 +147,11 @@ public class GMTimesTable extends Table { try { statement = prepareStatement( "UPDATE " + tableName + " SET " - + columnSurvivalTime + "=?, " - + columnCreativeTime + "=?, " - + columnAdventureTime + "=?, " - + columnSpectatorTime + "=? " - + " WHERE (" + columnUserID + "=?)"); + + columnSurvivalTime + "=?, " + + columnCreativeTime + "=?, " + + columnAdventureTime + "=?, " + + columnSpectatorTime + "=? " + + " WHERE (" + columnUserID + "=?)"); statement.setInt(5, userId); for (int i = 0; i < gms.length; i++) { try { @@ -197,7 +192,7 @@ public class GMTimesTable extends Table { } public void saveGMTimes(Map> gamemodeTimes) throws SQLException { - if (gamemodeTimes == null || gamemodeTimes.isEmpty()) { + if (Verify.isEmpty(gamemodeTimes)) { return; } Benchmark.start("Database: Save GMTimes"); @@ -208,26 +203,26 @@ public class GMTimesTable extends Table { try { statement = prepareStatement( "UPDATE " + tableName + " SET " - + columnSurvivalTime + "=?, " - + columnCreativeTime + "=?, " - + columnAdventureTime + "=?, " - + columnSpectatorTime + "=? " - + " WHERE (" + columnUserID + "=?)"); + + columnSurvivalTime + "=?, " + + columnCreativeTime + "=?, " + + columnAdventureTime + "=?, " + + columnSpectatorTime + "=? " + + " WHERE (" + columnUserID + "=?)"); boolean commitRequired = false; - for (Integer id : gamemodeTimes.keySet()) { + for (Map.Entry> entrySet : gamemodeTimes.entrySet()) { + Integer id = entrySet.getKey(); + if (!savedIDs.contains(id)) { continue; } + statement.setInt(5, id); for (int i = 0; i < gms.length; i++) { try { - Map times = gamemodeTimes.get(id); + Map times = entrySet.getValue(); Long time = times.get(gms[i]); - if (time != null) { - statement.setLong(i + 1, time); - } else { - statement.setLong(i + 1, 0); - } + + statement.setLong(i + 1, time != null ? time : 0); } catch (NoSuchFieldError e) { statement.setLong(i + 1, 0); } @@ -235,45 +230,46 @@ public class GMTimesTable extends Table { statement.addBatch(); commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } + gamemodeTimes.keySet().removeAll(savedIDs); } finally { close(statement); } + addNewGMTimesRows(gamemodeTimes); Benchmark.stop("Database: Save GMTimes"); } private void addNewGMTimesRows(Map> gamemodeTimes) throws SQLException { - if (gamemodeTimes == null || gamemodeTimes.isEmpty()) { + if (Verify.isEmpty(gamemodeTimes)) { return; } PreparedStatement statement = null; String[] gms = getGMKeyArray(); - try { statement = prepareStatement( "INSERT INTO " + tableName + " (" - + columnUserID + ", " - + columnSurvivalTime + ", " - + columnCreativeTime + ", " - + columnAdventureTime + ", " - + columnSpectatorTime - + ") VALUES (?, ?, ?, ?, ?)"); + + columnUserID + ", " + + columnSurvivalTime + ", " + + columnCreativeTime + ", " + + columnAdventureTime + ", " + + columnSpectatorTime + + ") VALUES (?, ?, ?, ?, ?)"); boolean commitRequired = false; - for (Integer id : gamemodeTimes.keySet()) { + for (Map.Entry> entry : gamemodeTimes.entrySet()) { + Integer id = entry.getKey(); + statement.setInt(1, id); for (int i = 0; i < gms.length; i++) { try { - Map times = gamemodeTimes.get(id); + Map times = entry.getValue(); Long time = times.get(gms[i]); - if (time != null) { - statement.setLong(i + 2, time); - } else { - statement.setLong(i + 2, 0); - } + + statement.setLong(i + 2, time != null ? time : 0); } catch (NoSuchFieldError e) { statement.setLong(i + 2, 0); } @@ -281,6 +277,7 @@ public class GMTimesTable extends Table { statement.addBatch(); commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } @@ -290,9 +287,11 @@ public class GMTimesTable extends Table { } private void addNewGMTimesRow(int userId, Map gamemodeTimes) throws SQLException { + if (Verify.isEmpty(gamemodeTimes)) { + return; + } PreparedStatement statement = null; String[] gms = getGMKeyArray(); - try { statement = prepareStatement("INSERT INTO " + tableName + " (" + columnUserID + ", " @@ -306,15 +305,13 @@ public class GMTimesTable extends Table { for (int i = 0; i < gms.length; i++) { try { Long time = gamemodeTimes.get(gms[i]); - if (time != null) { - statement.setLong(i + 2, time); - } else { - statement.setLong(i + 2, 0); - } + + statement.setLong(i + 2, time != null ? time : 0); } catch (NoSuchFieldError e) { statement.setLong(i + 2, 0); } } + statement.execute(); } finally { close(statement); diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java index 516aa8f2e..e07fd29d4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java @@ -1,23 +1,17 @@ package main.java.com.djrapitops.plan.database.tables; +import main.java.com.djrapitops.plan.Log; +import main.java.com.djrapitops.plan.database.databases.SQLDB; +import main.java.com.djrapitops.plan.utilities.Benchmark; + import java.net.InetAddress; import java.net.UnknownHostException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.database.databases.SQLDB; -import main.java.com.djrapitops.plan.utilities.Benchmark; +import java.util.*; /** - * * @author Rsl1122 */ public class IPsTable extends Table { @@ -26,7 +20,6 @@ public class IPsTable extends Table { private final String columnIP; /** - * * @param db * @param usingMySQL */ @@ -37,7 +30,6 @@ public class IPsTable extends Table { } /** - * * @return */ @Override @@ -58,7 +50,6 @@ public class IPsTable extends Table { } /** - * * @param userId * @return */ @@ -78,7 +69,6 @@ public class IPsTable extends Table { } /** - * * @param userId * @return * @throws SQLException @@ -93,9 +83,11 @@ public class IPsTable extends Table { set = statement.executeQuery(); List ips = new ArrayList<>(); while (set.next()) { + String ipAddressName = set.getString(columnIP); try { - ips.add(InetAddress.getByName(set.getString(columnIP))); + ips.add(InetAddress.getByName(ipAddressName)); } catch (UnknownHostException e) { + Log.error("Host not found at getIPAddresses: " + ipAddressName); //Shouldn't ever happen } } return ips; @@ -107,7 +99,6 @@ public class IPsTable extends Table { } /** - * * @param userId * @param ips * @throws SQLException @@ -116,11 +107,14 @@ public class IPsTable extends Table { if (ips == null) { return; } + Benchmark.start("Database: Save Ips"); ips.removeAll(getIPAddresses(userId)); + if (ips.isEmpty()) { return; } + PreparedStatement statement = null; try { statement = prepareStatement("INSERT INTO " + tableName + " (" @@ -129,14 +123,18 @@ public class IPsTable extends Table { + ") VALUES (?, ?)"); boolean commitRequired = false; for (InetAddress ip : ips) { + if (ip == null) { continue; } + statement.setInt(1, userId); statement.setString(2, ip.getHostAddress()); statement.addBatch(); + commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } @@ -147,7 +145,6 @@ public class IPsTable extends Table { } /** - * * @param ids * @return * @throws SQLException @@ -156,26 +153,36 @@ public class IPsTable extends Table { if (ids == null || ids.isEmpty()) { return new HashMap<>(); } + Benchmark.start("Database: Get Ips Multiple"); PreparedStatement statement = null; ResultSet set = null; + try { statement = prepareStatement("SELECT * FROM " + tableName); set = statement.executeQuery(); Map> ips = new HashMap<>(); + for (Integer id : ids) { ips.put(id, new HashSet<>()); } + while (set.next()) { Integer id = set.getInt(columnUserID); + if (!ids.contains(id)) { continue; } + + String ipAddressName = set.getString(columnIP); + try { - ips.get(id).add(InetAddress.getByName(set.getString(columnIP))); + ips.get(id).add(InetAddress.getByName(ipAddressName)); } catch (UnknownHostException e) { + Log.error("Host not found at getIPAddresses: " + ipAddressName); //Shouldn't ever happen } } + return ips; } finally { close(set); @@ -185,7 +192,6 @@ public class IPsTable extends Table { } /** - * * @param ips * @throws SQLException */ @@ -203,19 +209,25 @@ public class IPsTable extends Table { + ") VALUES (?, ?)"); boolean commitRequired = false; int i = 0; - for (Integer id : ips.keySet()) { - Set ipAddresses = ips.get(id); + for (Map.Entry> entrySet : ips.entrySet()) { + Integer id = entrySet.getKey(); + Set ipAddresses = entrySet.getValue(); + Set s = saved.get(id); + if (s != null) { ipAddresses.removeAll(s); } + if (ipAddresses.isEmpty()) { continue; } + for (InetAddress ip : ipAddresses) { if (ip == null) { continue; } + statement.setInt(1, id); statement.setString(2, ip.getHostAddress()); statement.addBatch(); @@ -223,13 +235,14 @@ public class IPsTable extends Table { i++; } } + if (commitRequired) { Log.debug("Executing ips batch: " + i); statement.executeBatch(); } - Benchmark.stop("Database: Save Ips Multiple"); } finally { close(statement); + Benchmark.stop("Database: Save Ips Multiple"); } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java index 3ee5a6c17..f8dd0b5f8 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java @@ -1,22 +1,17 @@ package main.java.com.djrapitops.plan.database.tables; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.data.KillData; import main.java.com.djrapitops.plan.database.databases.SQLDB; import main.java.com.djrapitops.plan.utilities.Benchmark; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author Rsl1122 */ public class KillsTable extends Table { @@ -27,7 +22,6 @@ public class KillsTable extends Table { private final String columnDate; /** - * * @param db * @param usingMySQL */ @@ -40,7 +34,6 @@ public class KillsTable extends Table { } /** - * * @return */ @Override @@ -64,7 +57,6 @@ public class KillsTable extends Table { } /** - * * @param userId * @return */ @@ -85,7 +77,6 @@ public class KillsTable extends Table { } /** - * * @param userId * @return * @throws SQLException @@ -102,7 +93,7 @@ public class KillsTable extends Table { List killData = new ArrayList<>(); while (set.next()) { int victimID = set.getInt(columnVictimUserID); - UUID victimUUID = usersTable.getUserUUID(victimID + ""); + UUID victimUUID = usersTable.getUserUUID(String.valueOf(victimID)); killData.add(new KillData(victimUUID, victimID, set.getString(columnWeapon), set.getLong(columnDate))); } return killData; @@ -114,7 +105,6 @@ public class KillsTable extends Table { } /** - * * @param userId * @param kills * @throws SQLException @@ -141,20 +131,24 @@ public class KillsTable extends Table { if (kill == null) { continue; } + statement.setInt(1, userId); int victimUserID = kill.getVictimUserID(); + if (victimUserID == -1) { victimUserID = db.getUsersTable().getUserId(kill.getVictim()); if (victimUserID == -1) { continue; } } + statement.setInt(2, victimUserID); statement.setString(3, kill.getWeapon()); statement.setLong(4, kill.getDate()); statement.addBatch(); commitRequired = true; } + if (commitRequired) { statement.executeBatch(); } @@ -165,7 +159,6 @@ public class KillsTable extends Table { } /** - * * @param ids * @param uuids * @return @@ -203,7 +196,6 @@ public class KillsTable extends Table { } /** - * * @param kills * @param uuids * @throws SQLException @@ -212,6 +204,7 @@ public class KillsTable extends Table { if (kills == null || kills.isEmpty()) { return; } + Benchmark.start("Database: Save Kills multiple"); Map> saved = getPlayerKills(kills.keySet(), uuids); @@ -225,16 +218,22 @@ public class KillsTable extends Table { + ") VALUES (?, ?, ?, ?)"); boolean commitRequired = false; int i = 0; - for (Integer id : kills.keySet()) { - List playerKills = kills.get(id); + + for (Map.Entry> entrySet : kills.entrySet()) { + Integer id = entrySet.getKey(); + List playerKills = entrySet.getValue(); + List s = saved.get(id); + if (s != null) { playerKills.removeAll(s); } + for (KillData kill : playerKills) { if (kill == null) { continue; } + statement.setInt(1, id); int victimUserID = kill.getVictimUserID(); if (victimUserID == -1) { @@ -242,11 +241,14 @@ public class KillsTable extends Table { .stream().filter(e -> e.getValue().equals(kill.getVictim())) .map(Map.Entry::getKey) .collect(Collectors.toList()); + if (matchingIds.isEmpty()) { continue; } + victimUserID = matchingIds.get(0); } + statement.setInt(2, victimUserID); statement.setString(3, kill.getWeapon()); statement.setLong(4, kill.getDate()); @@ -254,14 +256,15 @@ public class KillsTable extends Table { commitRequired = true; i++; } + if (commitRequired) { Log.debug("Executing kills batch: " + i); statement.executeBatch(); } } - Benchmark.stop("Database: Save Kills multiple"); } finally { close(statement); + Benchmark.stop("Database: Save Kills multiple"); } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/LocationsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/LocationsTable.java index e8872085c..d40f67454 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/LocationsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/LocationsTable.java @@ -1,12 +1,12 @@ package main.java.com.djrapitops.plan.database.tables; -import java.sql.PreparedStatement; -import java.sql.SQLException; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.database.databases.SQLDB; +import java.sql.PreparedStatement; +import java.sql.SQLException; + /** - * * @author Rsl1122 */ @Deprecated @@ -18,20 +18,10 @@ public class LocationsTable extends Table { private final String columnCoordinatesZ; private final String columnWorld; - @Override - @Deprecated - public boolean removeAllData() { - try { - execute("DELETE FROM " + tableName); - } catch (Exception e) { - } - return true; - } - /** - * * @param db * @param usingMySQL + * @deprecated Deprecated because it isn't used anymore */ @Deprecated public LocationsTable(SQLDB db, boolean usingMySQL) { @@ -43,8 +33,17 @@ public class LocationsTable extends Table { columnWorld = "world_name"; } + @Override + @Deprecated + public boolean removeAllData() { + try { + execute("DELETE FROM " + tableName); + } catch (Exception ignored) { + } + return true; + } + /** - * * @return */ @Override @@ -70,7 +69,6 @@ public class LocationsTable extends Table { } /** - * * @param userId * @return */ diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java index 78bcc3230..ec85698b8 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java @@ -1,20 +1,15 @@ package main.java.com.djrapitops.plan.database.tables; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.database.databases.SQLDB; import main.java.com.djrapitops.plan.utilities.Benchmark; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + /** - * * @author Rsl1122 */ public class NicknamesTable extends Table { @@ -24,7 +19,6 @@ public class NicknamesTable extends Table { private final String columnCurrent; /** - * * @param db * @param usingMySQL */ @@ -36,7 +30,6 @@ public class NicknamesTable extends Table { } /** - * * @return */ @Override @@ -61,21 +54,10 @@ public class NicknamesTable extends Table { } private void alterTablesV3() { - String query; - if (usingMySQL) { - query = "ALTER TABLE " + tableName + " ADD " + columnCurrent + " boolean NOT NULL DEFAULT 0"; - - } else { - query = "ALTER TABLE " + tableName + " ADD COLUMN " + columnCurrent + " boolean NOT NULL DEFAULT 0"; - } - try { - execute(query); - } catch (Exception e) { - } + addColumns(columnCurrent + " boolean NOT NULL DEFAULT 0"); } /** - * * @param userId * @return */ @@ -95,7 +77,6 @@ public class NicknamesTable extends Table { } /** - * * @param userId * @return * @throws SQLException @@ -133,7 +114,6 @@ public class NicknamesTable extends Table { } /** - * * @param userId * @param names * @param lastNick @@ -177,7 +157,6 @@ public class NicknamesTable extends Table { } /** - * * @param ids * @return * @throws SQLException @@ -212,11 +191,17 @@ public class NicknamesTable extends Table { lastNicks.put(id, nickname); } } - for (Integer id : lastNicks.keySet()) { - String lastNick = lastNicks.get(id); + + for (Map.Entry entry : lastNicks.entrySet()) { + Integer id = entry.getKey(); + String lastNick = entry.getValue(); + List list = nicks.get(id); - list.remove(lastNick); - list.add(lastNick); + + // Moves the last known nickname to the end of the List. + // This is due to the way nicknames are added to UserData, + // Nicknames are stored as a Set and last Nickname is a separate String. + list.set(list.size() - 1, lastNick); } return nicks; @@ -228,7 +213,6 @@ public class NicknamesTable extends Table { } /** - * * @param nicknames * @param lastNicks * @throws SQLException @@ -237,7 +221,9 @@ public class NicknamesTable extends Table { if (nicknames == null || nicknames.isEmpty()) { return; } + Benchmark.start("Database: Save Nicknames Multiple"); + Map> saved = getNicknames(nicknames.keySet()); PreparedStatement statement = null; try { @@ -247,16 +233,22 @@ public class NicknamesTable extends Table { + columnCurrent + ", " + columnNick + ") VALUES (?, ?, ?)"); - for (Integer id : nicknames.keySet()) { - Set newNicks = nicknames.get(id); + + for (Map.Entry> entrySet : nicknames.entrySet()) { + Integer id = entrySet.getKey(); + Set newNicks = entrySet.getValue(); + String lastNick = lastNicks.get(id); List s = saved.get(id); + if (s != null) { newNicks.removeAll(s); } + if (newNicks.isEmpty()) { continue; } + for (String name : newNicks) { statement.setInt(1, id); statement.setInt(2, (name.equals(lastNick)) ? 1 : 0); @@ -265,6 +257,7 @@ public class NicknamesTable extends Table { commitRequired = true; } } + if (commitRequired) { statement.executeBatch(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java index a42e725bb..537e758fc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java @@ -16,7 +16,6 @@ import java.util.ArrayList; import java.util.List; /** - * * @author Rsl1122 */ public class SecurityTable extends Table { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java index b969d2a67..b96052423 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java @@ -5,8 +5,6 @@ import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.database.Container; import main.java.com.djrapitops.plan.database.databases.SQLDB; import main.java.com.djrapitops.plan.utilities.Benchmark; -import main.java.com.djrapitops.plan.utilities.ManageUtils; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -14,7 +12,6 @@ import java.sql.SQLException; import java.util.*; /** - * * @author Rsl1122 */ public class SessionsTable extends Table { @@ -24,7 +21,6 @@ public class SessionsTable extends Table { private final String columnSessionEnd; /** - * * @param db * @param usingMySQL */ @@ -36,7 +32,6 @@ public class SessionsTable extends Table { } /** - * * @return */ @Override @@ -58,7 +53,6 @@ public class SessionsTable extends Table { } /** - * * @param userId * @return * @throws SQLException @@ -86,7 +80,6 @@ public class SessionsTable extends Table { } /** - * * @param userId * @return */ @@ -106,7 +99,6 @@ public class SessionsTable extends Table { } /** - * * @param userId * @param sessions * @throws SQLException @@ -152,7 +144,6 @@ public class SessionsTable extends Table { } /** - * * @param ids * @return * @throws SQLException @@ -190,7 +181,6 @@ public class SessionsTable extends Table { } /** - * * @param sessions * @throws SQLException */ @@ -198,20 +188,27 @@ public class SessionsTable extends Table { if (sessions == null || sessions.isEmpty()) { return; } + Benchmark.start("Database: Save Sessions multiple"); + Map> saved = getSessionData(sessions.keySet()); - for (Integer id : sessions.keySet()) { - List sessionList = sessions.get(id); + for (Map.Entry> entrySet : sessions.entrySet()) { + Integer id = entrySet.getKey(); + List sessionList = entrySet.getValue(); + List s = saved.get(id); if (s != null) { sessionList.removeAll(s); } + if (sessionList.isEmpty()) { continue; } + saved.put(id, sessionList); } List>> batches = splitIntoBatches(sessions); + for (List> batch : batches) { saveSessionBatch(batch); } @@ -255,48 +252,9 @@ public class SessionsTable extends Table { } /** - * * @throws SQLException */ public void clean() throws SQLException { - Map loginTimes = db.getUsersTable().getLoginTimes(); - Map> allSessions = getSessionData(loginTimes.keySet()); - Benchmark.start("Database: Combine Sessions"); - int before = MathUtils.sumInt(allSessions.values().stream().map(List::size)); - Log.debug("Sessions before: " + before); - Map beforeM = new HashMap<>(); - Map afterM = new HashMap<>(); - for (Integer id : allSessions.keySet()) { - List sessions = allSessions.get(id); - beforeM.put(id, sessions.size()); - if (sessions.isEmpty()) { - afterM.put(id, 0); - continue; - } - Integer times = loginTimes.get(id); - if (sessions.size() == times) { - afterM.put(id, times); - continue; - } - List combined = ManageUtils.combineSessions(sessions, times); - afterM.put(id, combined.size()); - allSessions.put(id, combined); - } - int after = MathUtils.sumInt(allSessions.values().stream().map(List::size)); - Log.debug("Sessions after: " + after); - if (before - after > 50) { - Benchmark.start("Database: Save combined sessions"); - for (Integer id : new HashSet<>(allSessions.keySet())) { - if (afterM.get(id) < beforeM.get(id)) { - removeUserSessions(id); - } else { - allSessions.remove(id); - } - } - saveSessionData(allSessions); - Benchmark.stop("Database: Save combined sessions"); - } - Benchmark.stop("Database: Combine Sessions"); - Log.info("Combined " + (before - after) + " sessions."); + // TODO Clean sessions before Configurable time span } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java index 1c0092462..55921e575 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java @@ -26,6 +26,9 @@ public class TPSTable extends Table { private final String columnTPS; private final String columnPlayers; private final String columnCPUUsage; + private final String columnRAMUsage; + private final String columnEntities; + private final String columnChunksLoaded; /** * @param db @@ -37,6 +40,9 @@ public class TPSTable extends Table { columnTPS = "tps"; columnPlayers = "players_online"; columnCPUUsage = "cpu_usage"; + columnRAMUsage = "ram_usage"; + columnEntities = "entities"; + columnChunksLoaded = "chunks_loaded"; } @Override @@ -46,13 +52,19 @@ public class TPSTable extends Table { + columnDate + " bigint NOT NULL, " + columnTPS + " double NOT NULL, " + columnPlayers + " integer NOT NULL, " - + columnCPUUsage + " double NOT NULL" + + columnCPUUsage + " double NOT NULL, " + + columnRAMUsage + " bigint NOT NULL, " + + columnEntities + " integer NOT NULL, " + + columnChunksLoaded + " integer NOT NULL" + ")" ); int version = getVersion(); if (version < 6) { alterTablesV6(); } + if (version < 7) { + alterTablesV7(); + } return true; } catch (SQLException ex) { Log.toLog(this.getClass().getName(), ex); @@ -61,15 +73,15 @@ public class TPSTable extends Table { } private void alterTablesV6() { - try { - if (usingMySQL) { - execute("ALTER TABLE " + tableName + " ADD " + columnCPUUsage + " double NOT NULL DEFAULT 0"); - } else { - execute("ALTER TABLE " + tableName + " ADD COLUMN " + columnCPUUsage + " double NOT NULL DEFAULT 0"); - } - } catch (SQLException e) { + addColumns(columnCPUUsage + " double NOT NULL DEFAULT 0"); + } - } + private void alterTablesV7() { + addColumns( + columnRAMUsage + " bigint NOT NULL DEFAULT 0", + columnEntities + " integer NOT NULL DEFAULT 0", + columnChunksLoaded + " integer NOT NULL DEFAULT 0" + ); } /** @@ -88,7 +100,10 @@ public class TPSTable extends Table { double tps = set.getDouble(columnTPS); int players = set.getInt(columnPlayers); double cpuUsage = set.getDouble(columnCPUUsage); - data.add(new TPS(date, tps, players, cpuUsage)); + long ramUsage = set.getLong(columnRAMUsage); + int entities = set.getInt(columnEntities); + int chunksLoaded = set.getInt(columnChunksLoaded); + data.add(new TPS(date, tps, players, cpuUsage, ramUsage, entities, chunksLoaded)); } return data; } finally { @@ -116,8 +131,11 @@ public class TPSTable extends Table { + columnDate + ", " + columnTPS + ", " + columnPlayers + ", " - + columnCPUUsage - + ") VALUES (?, ?, ?, ?)"); + + columnCPUUsage + ", " + + columnRAMUsage + ", " + + columnEntities + ", " + + columnChunksLoaded + + ") VALUES (?, ?, ?, ?, ?, ?, ?)"); boolean commitRequired = false; int i = 0; @@ -126,6 +144,9 @@ public class TPSTable extends Table { statement.setDouble(2, tps.getTps()); statement.setInt(3, tps.getPlayers()); statement.setDouble(4, tps.getCPUUsage()); + statement.setLong(5, tps.getUsedMemory()); + statement.setDouble(6, tps.getEntityCount()); + statement.setDouble(7, tps.getChunksLoaded()); statement.addBatch(); commitRequired = true; i++; diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java index a49047f84..9b36d93a2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java @@ -1,5 +1,6 @@ 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.database.Container; import main.java.com.djrapitops.plan.database.DBUtils; @@ -9,11 +10,11 @@ import main.java.com.djrapitops.plan.utilities.MiscUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Statement; import java.util.List; import java.util.Map; /** - * * @author Rsl1122 */ public abstract class Table { @@ -34,7 +35,6 @@ public abstract class Table { protected final boolean usingMySQL; /** - * * @param name * @param db * @param usingMySQL @@ -46,13 +46,11 @@ public abstract class Table { } /** - * * @return */ public abstract boolean createTable(); /** - * * @return @throws SQLException */ protected Connection getConnection() throws SQLException { @@ -64,7 +62,6 @@ public abstract class Table { } /** - * * @return @throws SQLException */ public int getVersion() throws SQLException { @@ -72,28 +69,49 @@ public abstract class Table { } /** - * - * @param sql + * @param statementString * @return * @throws SQLException */ - protected boolean execute(String sql) throws SQLException { + protected boolean execute(String statementString) throws SQLException { Connection connection = getConnection(); - return connection.createStatement().execute(sql); + Statement statement = null; + try { + statement = connection.createStatement(); + return statement.execute(statementString); + } finally { + if (statement != null) { + statement.close(); + } + } } /** + * Used to execute queries while possible SQLExceptions are suppressed. * + * @param statements SQL statements to execute + */ + protected void executeUnsafe(String... statements) { + Verify.nullCheck(statements); + for (String statement : statements) { + try { + execute(statement); + } catch (SQLException ignored) { + } + } + } + + /** * @param sql * @return * @throws SQLException */ protected PreparedStatement prepareStatement(String sql) throws SQLException { + Log.debug(sql); return getConnection().prepareStatement(sql); } /** - * * @param toClose */ protected void close(AutoCloseable... toClose) { @@ -101,7 +119,6 @@ public abstract class Table { } /** - * * @return */ public String getTableName() { @@ -109,7 +126,6 @@ public abstract class Table { } /** - * * @return */ public boolean removeAllData() { @@ -123,7 +139,6 @@ public abstract class Table { } /** - * * @param * @param objects * @return @@ -131,4 +146,30 @@ public abstract class Table { protected List>> splitIntoBatches(Map> objects) { return DBUtils.splitIntoBatchesId(objects); } + + protected void addColumns(String... columnInfo) { + for (int i = 0; i < columnInfo.length; i++) { + columnInfo[i] = "ALTER TABLE " + tableName + " ADD " + (usingMySQL ? "" : "COLUMN ") + columnInfo[i]; + } + executeUnsafe(columnInfo); + } + + protected void removeColumns(String... columnNames) { + if (usingMySQL) { + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append("ALTER TABLE ").append(tableName); + for (int i = 0; i < columnNames.length; i++) { + sqlBuild.append(" DROP COLUMN ").append(columnNames[i]); + if (i < columnNames.length - 1) { + sqlBuild.append(","); + } + } + executeUnsafe(sqlBuild.toString()); + } + } + + @Override + public String toString() { + return tableName; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java index a144b477b..5d31f72b6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java @@ -3,11 +3,12 @@ package main.java.com.djrapitops.plan.database.tables; import com.djrapitops.plugin.utilities.player.Fetch; import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.time.GMTimes; +import main.java.com.djrapitops.plan.data.time.WorldTimes; 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; import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility; -import org.bukkit.GameMode; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -17,34 +18,50 @@ import java.util.function.Function; import java.util.stream.Collectors; /** - * * @author Rsl1122 */ public class UsersTable extends Table { private final String columnID; private final String columnUUID; - @Deprecated // Removed in 3.5.2 - private final String columnDemAge; - @Deprecated // Removed in 3.5.2 - private final String columnDemGender; private final String columnGeolocation; private final String columnLastGM; private final String columnLastGMSwapTime; private final String columnPlayTime; private final String columnLoginTimes; private final String columnLastPlayed; - private final String columnPlayerKills; private final String columnDeaths; private final String columnMobKills; + /** + * @since 3.3.0 + */ private final String columnRegistered; + /** + * @since 3.3.0 + */ private final String columnOP; + /** + * @since 3.3.0 + */ private final String columnName; + /** + * @since 3.3.0 + */ private final String columnBanned; + /** + * @since 3.3.0 + */ private final String columnContainsBukkitData; + /** + * @since 3.6.0 + */ + private final String columnLastWorldSwapTime; + /** + * @since 3.6.0 + */ + private final String columnLastWorld; /** - * * @param db * @param usingMySQL */ @@ -52,8 +69,6 @@ public class UsersTable extends Table { super("plan_users", db, usingMySQL); columnID = "id"; columnUUID = "uuid"; - columnDemAge = "age"; - columnDemGender = "gender"; columnGeolocation = "geolocation"; columnLastGM = "last_gamemode"; columnLastGMSwapTime = "last_gamemode_swap"; @@ -61,18 +76,19 @@ public class UsersTable extends Table { columnLoginTimes = "login_times"; columnLastPlayed = "last_played"; columnMobKills = "mob_kills"; - columnPlayerKills = "player_kills"; // Removed in 2.7.0 + columnDeaths = "deaths"; - // Added in 3.3.0 columnRegistered = "registered"; columnOP = "opped"; columnName = "name"; columnBanned = "banned"; columnContainsBukkitData = "contains_bukkit_data"; + + columnLastWorldSwapTime = "last_world_swap"; + columnLastWorld = "last_world"; } /** - * * @return */ @Override @@ -93,7 +109,9 @@ public class UsersTable extends Table { + columnOP + " boolean NOT NULL DEFAULT 0, " + columnName + " varchar(16) NOT NULL, " + columnBanned + " boolean NOT NULL DEFAULT 0, " - + columnContainsBukkitData + " boolean NOT NULL DEFAULT 0" + + columnContainsBukkitData + " boolean NOT NULL DEFAULT 0, " + + columnLastWorld + " varchar(255) NOT NULL, " + + columnLastWorldSwapTime + " bigint NOT NULL" + (usingMySQL ? ", PRIMARY KEY (" + columnID + ")" : "") + ")" ); @@ -107,6 +125,9 @@ public class UsersTable extends Table { if (version < 5) { alterTablesV5(); } + if (version < 8) { + alterTablesV8(); + } return true; } catch (SQLException ex) { Log.toLog(this.getClass().getName(), ex); @@ -114,68 +135,36 @@ public class UsersTable extends Table { } } + private void alterTablesV8() { + addColumns( + columnLastWorldSwapTime + " bigint NOT NULL DEFAULT 0", + columnLastWorld + " varchar(255) NOT NULL DEFAULT 'Unknown'" + ); + } + private void alterTablesV5() { - if (usingMySQL) { - try { - execute("ALTER TABLE " + tableName - + " DROP COLUMN " + columnDemAge + "," - + " DROP COLUMN " + columnDemGender); - } catch (Exception e) { - } - } + removeColumns("age", "gender"); } private void alterTablesV4() { - String[] queries; - if (usingMySQL) { - queries = new String[]{ - "ALTER TABLE " + tableName + " ADD " + columnContainsBukkitData + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD " + columnOP + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD " + columnBanned + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD " + columnName + " varchar(16) NOT NULL DEFAULT \'Unknown\'", - "ALTER TABLE " + tableName + " ADD " + columnRegistered + " bigint NOT NULL DEFAULT 0" - }; - } else { - queries = new String[]{ - "ALTER TABLE " + tableName + " ADD COLUMN " + columnContainsBukkitData + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD COLUMN " + columnOP + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD COLUMN " + columnBanned + " boolean NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + " varchar(16) NOT NULL DEFAULT \'Unknown\'", - "ALTER TABLE " + tableName + " ADD COLUMN " + columnRegistered + " bigint NOT NULL DEFAULT 0" - }; - } - for (String query : queries) { - try { - execute(query); - } catch (Exception e) { - } - } + addColumns( + columnContainsBukkitData + " boolean NOT NULL DEFAULT 0", + columnOP + " boolean NOT NULL DEFAULT 0", + columnBanned + " boolean NOT NULL DEFAULT 0", + columnName + " varchar(16) NOT NULL DEFAULT 'Unknown'", + columnRegistered + " bigint NOT NULL DEFAULT 0" + ); } private void alterTablesV3() { - String[] queries; - if (usingMySQL) { - queries = new String[]{ - "ALTER TABLE " + tableName + " ADD " + columnDeaths + " integer NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD " + columnMobKills + " integer NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " DROP INDEX " + columnPlayerKills - }; - } else { - queries = new String[]{ - "ALTER TABLE " + tableName + " ADD COLUMN " + columnDeaths + " integer NOT NULL DEFAULT 0", - "ALTER TABLE " + tableName + " ADD COLUMN " + columnMobKills + " integer NOT NULL DEFAULT 0" - }; - } - for (String query : queries) { - try { - execute(query); - } catch (Exception e) { - } - } + addColumns( + columnDeaths + " integer NOT NULL DEFAULT 0", + columnMobKills + " integer NOT NULL DEFAULT 0" + ); + removeColumns("player_kills"); } /** - * * @param uuid * @return * @throws SQLException @@ -185,7 +174,6 @@ public class UsersTable extends Table { } /** - * * @param uuid * @return * @throws SQLException @@ -209,7 +197,6 @@ public class UsersTable extends Table { } /** - * * @param userID * @return * @throws SQLException @@ -233,7 +220,6 @@ public class UsersTable extends Table { } /** - * * @return @throws SQLException */ public Set getSavedUUIDs() throws SQLException { @@ -257,7 +243,6 @@ public class UsersTable extends Table { } /** - * * @param uuid * @return */ @@ -266,7 +251,6 @@ public class UsersTable extends Table { } /** - * * @param uuid * @return */ @@ -285,7 +269,6 @@ public class UsersTable extends Table { } /** - * * @param uuid * @return * @throws SQLException @@ -324,7 +307,6 @@ public class UsersTable extends Table { } /** - * * @param uuids * @return * @throws SQLException @@ -353,7 +335,6 @@ public class UsersTable extends Table { } /** - * * @param uuids * @return * @throws SQLException @@ -399,14 +380,22 @@ public class UsersTable extends Table { long registered = set.getLong(columnRegistered); UserData data = new UserData(uuid, registered, op, gm, name, false); data.setBanned(banned); - data.setLastGamemode(gm); data.setGeolocation(set.getString(columnGeolocation)); - data.setLastGmSwapTime(set.getLong(columnLastGMSwapTime)); - data.setPlayTime(set.getLong(columnPlayTime)); + data.getGmTimes().setLastStateChange(set.getLong(columnLastGMSwapTime)); + long playTime = set.getLong(columnPlayTime); + data.setPlayTime(playTime); data.setLoginTimes(set.getInt(columnLoginTimes)); data.setLastPlayed(set.getLong(columnLastPlayed)); data.setDeaths(set.getInt(columnDeaths)); data.setMobKills(set.getInt(columnMobKills)); + WorldTimes worldTimes = data.getWorldTimes(); + worldTimes.setLastStateChange(set.getLong(columnLastWorldSwapTime)); + String lastWorld = set.getString(columnLastWorld); + if (!"Unknown".equals(lastWorld)) { + worldTimes.setState(lastWorld); + } else { + worldTimes.setLastStateChange(playTime); + } return data; } } finally { @@ -438,14 +427,22 @@ public class UsersTable extends Table { long registered = set.getLong(columnRegistered); UserData data = new UserData(uuid, registered, op, gm, name, false); data.setBanned(banned); - data.setLastGamemode(gm); data.setGeolocation(set.getString(columnGeolocation)); - data.setLastGmSwapTime(set.getLong(columnLastGMSwapTime)); - data.setPlayTime(set.getLong(columnPlayTime)); + data.getGmTimes().setLastStateChange(set.getLong(columnLastGMSwapTime)); + long playTime = set.getLong(columnPlayTime); + data.setPlayTime(playTime); data.setLoginTimes(set.getInt(columnLoginTimes)); data.setLastPlayed(set.getLong(columnLastPlayed)); data.setDeaths(set.getInt(columnDeaths)); data.setMobKills(set.getInt(columnMobKills)); + WorldTimes worldTimes = data.getWorldTimes(); + worldTimes.setLastStateChange(set.getLong(columnLastWorldSwapTime)); + String lastWorld = set.getString(columnLastWorld); + if (!"Unknown".equals(lastWorld)) { + worldTimes.setState(lastWorld); + } else { + worldTimes.setLastStateChange(playTime); + } datas.add(data); } } finally { @@ -457,7 +454,6 @@ public class UsersTable extends Table { } /** - * * @param data * @throws SQLException */ @@ -471,13 +467,23 @@ public class UsersTable extends Table { set = statement.executeQuery(); while (set.next()) { data.setGeolocation(set.getString(columnGeolocation)); - data.setLastGamemode(set.getString(columnLastGM)); - data.setLastGmSwapTime(set.getLong(columnLastGMSwapTime)); - data.setPlayTime(set.getLong(columnPlayTime)); + GMTimes gmTimes = data.getGmTimes(); + gmTimes.setState(set.getString(columnLastGM)); + gmTimes.setLastStateChange(set.getLong(columnLastGMSwapTime)); + long playTime = set.getLong(columnPlayTime); + data.setPlayTime(playTime); data.setLoginTimes(set.getInt(columnLoginTimes)); data.setLastPlayed(set.getLong(columnLastPlayed)); data.setDeaths(set.getInt(columnDeaths)); data.setMobKills(set.getInt(columnMobKills)); + WorldTimes worldTimes = data.getWorldTimes(); + worldTimes.setLastStateChange(set.getLong(columnLastWorldSwapTime)); + String lastWorld = set.getString(columnLastWorld); + if (!"Unknown".equals(lastWorld)) { + worldTimes.setState(lastWorld); + } else { + worldTimes.setLastStateChange(playTime); + } } } finally { close(set); @@ -487,7 +493,6 @@ public class UsersTable extends Table { } /** - * * @param data * @throws SQLException */ @@ -507,13 +512,23 @@ public class UsersTable extends Table { } UserData uData = userDatas.get(uuid); uData.setGeolocation(set.getString(columnGeolocation)); - uData.setLastGamemode(set.getString(columnLastGM)); - uData.setLastGmSwapTime(set.getLong(columnLastGMSwapTime)); - uData.setPlayTime(set.getLong(columnPlayTime)); + long playTime = set.getLong(columnPlayTime); + uData.setPlayTime(playTime); uData.setLoginTimes(set.getInt(columnLoginTimes)); uData.setLastPlayed(set.getLong(columnLastPlayed)); uData.setDeaths(set.getInt(columnDeaths)); uData.setMobKills(set.getInt(columnMobKills)); + GMTimes gmTimes = uData.getGmTimes(); + gmTimes.setState(set.getString(columnLastGM)); + gmTimes.setLastStateChange(set.getLong(columnLastGMSwapTime)); + WorldTimes worldTimes = uData.getWorldTimes(); + worldTimes.setLastStateChange(set.getLong(columnLastWorldSwapTime)); + String lastWorld = set.getString(columnLastWorld); + if (!"Unknown".equals(lastWorld)) { + worldTimes.setState(lastWorld); + } else { + worldTimes.setLastStateChange(playTime); + } } } finally { close(set); @@ -523,7 +538,6 @@ public class UsersTable extends Table { } /** - * * @param data * @throws SQLException */ @@ -539,13 +553,9 @@ public class UsersTable extends Table { statement = prepareStatement(sql); statement.setString(1, data.getGeolocation()); - String gm = data.getLastGamemode(); - if (gm != null) { - statement.setString(2, gm); - } else { - statement.setString(2, "SURVIVAL"); - } - statement.setLong(3, data.getLastGmSwapTime()); + GMTimes gmTimes = data.getGmTimes(); + statement.setString(2, gmTimes.getState()); + statement.setLong(3, gmTimes.getLastStateChange()); statement.setLong(4, data.getPlayTime()); statement.setInt(5, data.getLoginTimes()); statement.setLong(6, data.getLastPlayed()); @@ -556,7 +566,10 @@ public class UsersTable extends Table { statement.setBoolean(11, data.isBanned()); statement.setString(12, data.getName()); statement.setLong(13, data.getRegistered()); - statement.setString(14, uuid.toString()); + WorldTimes worldTimes = data.getWorldTimes(); + statement.setString(14, worldTimes.getState()); + statement.setLong(15, worldTimes.getLastStateChange()); + statement.setString(16, uuid.toString()); update = statement.executeUpdate(); } if (update == 0) { @@ -565,13 +578,9 @@ public class UsersTable extends Table { statement.setString(1, uuid.toString()); statement.setString(2, data.getGeolocation()); - String gm = data.getLastGamemode(); - if (gm != null) { - statement.setString(3, gm); - } else { - statement.setString(3, "SURVIVAL"); - } - statement.setLong(4, data.getLastGmSwapTime()); + GMTimes gmTimes = data.getGmTimes(); + statement.setString(3, gmTimes.getState()); + statement.setLong(4, gmTimes.getLastStateChange()); statement.setLong(5, data.getPlayTime()); statement.setInt(6, data.getLoginTimes()); statement.setLong(7, data.getLastPlayed()); @@ -582,6 +591,9 @@ public class UsersTable extends Table { statement.setBoolean(12, data.isBanned()); statement.setString(13, data.getName()); statement.setLong(14, data.getRegistered()); + WorldTimes worldTimes = data.getWorldTimes(); + statement.setString(15, worldTimes.getState()); + statement.setLong(16, worldTimes.getLastStateChange()); statement.execute(); } } finally { @@ -598,7 +610,7 @@ public class UsersTable extends Table { ResultSet set = null; try { try { - statement = prepareStatement("SELECT " + columnDemAge + " FROM " + tableName + " LIMIT 1"); + statement = prepareStatement("SELECT age FROM " + tableName + " LIMIT 1"); set = statement.executeQuery(); Log.debug("UsersTable has V4 columns."); return true; @@ -613,7 +625,7 @@ public class UsersTable extends Table { private String getInsertStatement() { final boolean hasV4Columns = tableHasV4Columns(); - String v4rows = hasV4Columns ? columnDemAge + ", " + columnDemGender + ", " : ""; + String v4rows = hasV4Columns ? "age, gender, " : ""; String v4values = hasV4Columns ? "-1, Deprecated, " : ""; return "INSERT INTO " + tableName + " (" + v4rows @@ -630,13 +642,15 @@ public class UsersTable extends Table { + columnOP + ", " + columnBanned + ", " + columnName + ", " - + columnRegistered - + ") VALUES (" + v4values + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + columnRegistered + ", " + + columnLastWorld + ", " + + columnLastWorldSwapTime + + ") VALUES (" + v4values + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; } private String getUpdateStatement() { final boolean hasV4Columns = tableHasV4Columns(); - String v4rows = hasV4Columns ? columnDemAge + "=-1, " + columnDemGender + "='Deprecated', " : ""; + String v4rows = hasV4Columns ? "age=-1, gender='Deprecated', " : ""; return "UPDATE " + tableName + " SET " + v4rows + columnGeolocation + "=?, " @@ -651,12 +665,13 @@ public class UsersTable extends Table { + columnOP + "=?, " + columnBanned + "=?, " + columnName + "=?, " - + columnRegistered + "=? " + + columnRegistered + "=?, " + + columnLastWorld + "=?, " + + columnLastWorldSwapTime + "=? " + "WHERE " + columnUUID + "=?"; } /** - * * @param data * @throws SQLException */ @@ -685,13 +700,9 @@ public class UsersTable extends Table { UUID uuid = uData.getUuid(); statement.setString(1, uuid.toString()); statement.setString(2, uData.getGeolocation()); - String gm = uData.getLastGamemode(); - if (gm != null) { - statement.setString(3, gm); - } else { - statement.setString(3, "SURVIVAL"); - } - statement.setLong(4, uData.getLastGmSwapTime()); + 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()); @@ -702,6 +713,9 @@ 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++; @@ -748,13 +762,9 @@ public class UsersTable extends Table { } uData.access(); statement.setString(1, uData.getGeolocation()); - String gm = uData.getLastGamemode(); - if (gm != null) { - statement.setString(2, gm); - } else { - statement.setString(2, GameMode.SURVIVAL.name()); - } - statement.setLong(3, uData.getLastGmSwapTime()); + GMTimes gmTimes = uData.getGmTimes(); + statement.setString(2, gmTimes.getState()); + statement.setLong(3, uData.getGmTimes().getLastStateChange()); statement.setLong(4, uData.getPlayTime()); statement.setInt(5, uData.getLoginTimes()); statement.setLong(6, uData.getLastPlayed()); @@ -765,7 +775,10 @@ public class UsersTable extends Table { statement.setBoolean(11, uData.isBanned()); statement.setString(12, uData.getName()); statement.setLong(13, uData.getRegistered()); - statement.setString(14, uuid.toString()); + WorldTimes worldTimes = uData.getWorldTimes(); + statement.setString(14, worldTimes.getState()); + statement.setLong(15, worldTimes.getLastStateChange()); + statement.setString(16, uuid.toString()); statement.addBatch(); uData.stopAccessing(); commitRequired = true; @@ -782,7 +795,6 @@ public class UsersTable extends Table { } /** - * * @param uuids * @return * @throws SQLException @@ -812,7 +824,6 @@ public class UsersTable extends Table { } /** - * * @return @throws SQLException */ public Map getAllUserIds() throws SQLException { @@ -837,7 +848,6 @@ public class UsersTable extends Table { } /** - * * @return @throws SQLException */ public Map getLoginTimes() throws SQLException { @@ -861,7 +871,6 @@ public class UsersTable extends Table { } /** - * * @return */ public String getColumnID() { @@ -869,7 +878,6 @@ public class UsersTable extends Table { } /** - * * @param playername * @return * @throws SQLException @@ -891,13 +899,4 @@ public class UsersTable extends Table { close(statement); } } - - /** - * - * @param uuids - * @return - */ - public Map getLoginTimes(Collection uuids) { - throw new UnsupportedOperationException("Not supported yet."); // TODO - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java index 47f5798f3..52629d805 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java @@ -1,19 +1,18 @@ package main.java.com.djrapitops.plan.database.tables; +import main.java.com.djrapitops.plan.Log; +import main.java.com.djrapitops.plan.database.databases.SQLDB; + import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.database.databases.SQLDB; /** - * * @author Rsl1122 */ public class VersionTable extends Table { /** - * * @param db * @param usingMySQL */ @@ -22,7 +21,6 @@ public class VersionTable extends Table { } /** - * * @return */ @Override @@ -40,7 +38,6 @@ public class VersionTable extends Table { } /** - * * @return @throws SQLException */ @Override @@ -62,7 +59,6 @@ public class VersionTable extends Table { } /** - * * @param version * @throws SQLException */ diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java new file mode 100644 index 000000000..2a0dc0154 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java @@ -0,0 +1,123 @@ +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.database.databases.SQLDB; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Table class representing database table plan_worlds. + *

+ * Used for storing id references to world names. + * + * @author Rsl1122 + * @since 3.6.0 / Database version 7 + */ +public class WorldTable extends Table { + + private final String columnWorldId; + private final String columnWorldName; + + /** + * Constructor. + * + * @param db Database this table is a part of. + * @param usingMySQL Database is a MySQL database. + */ + public WorldTable(SQLDB db, boolean usingMySQL) { + super("plan_worlds", db, usingMySQL); + columnWorldId = "world_id"; + columnWorldName = "world_name"; + } + + @Override + public boolean createTable() { + try { + execute("CREATE TABLE IF NOT EXISTS " + tableName + " (" + + columnWorldId + " integer " + ((usingMySQL) ? "NOT NULL AUTO_INCREMENT" : "PRIMARY KEY") + ", " + + columnWorldName + " varchar(100) NOT NULL" + + (usingMySQL ? ", PRIMARY KEY (" + columnWorldId + ")" : "") + + ")" + ); + return true; + } catch (SQLException ex) { + Log.toLog(this.getClass().getName(), ex); + return false; + } + } + + /** + * Used to get the available world names. + * + * @return List of all world names in the database. + * @throws SQLException Database error occurs. + */ + public List getWorlds() throws SQLException { + PreparedStatement statement = null; + ResultSet set = null; + try { + statement = prepareStatement("SELECT * FROM " + tableName); + set = statement.executeQuery(); + List worldNames = new ArrayList<>(); + while (set.next()) { + String worldName = set.getString(columnWorldName); + worldNames.add(worldName); + } + return worldNames; + } finally { + close(set, statement); + } + } + + /** + * Used to save a list of world names. + *

+ * Already saved names will not be saved. + * + * @param worlds List of world names. + * @throws SQLException Database error occurs. + */ + public void saveWorlds(Collection worlds) throws SQLException { + Verify.nullCheck(worlds); + + List saved = getWorlds(); + worlds.removeAll(saved); + if (Verify.isEmpty(worlds)) { + return; + } + + PreparedStatement statement = null; + try { + statement = prepareStatement("INSERT INTO " + tableName + " (" + + columnWorldName + + ") VALUES (?)"); + boolean commitRequired = false; + for (String world : worlds) { + statement.setString(1, world); + statement.addBatch(); + commitRequired = true; + } + if (commitRequired) { + statement.executeBatch(); + } + } finally { + close(statement); + } + } + + public String getColumnID() { + return columnWorldId; + } + + public String getColumnWorldName() { + return columnWorldName; + } + + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java new file mode 100644 index 000000000..c246b2de3 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java @@ -0,0 +1,325 @@ +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.database.databases.SQLDB; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Table class representing database table plan_world_times. + * + * @author Rsl1122 + * @since 3.6.0 / Database version 7 + */ +public class WorldTimesTable extends Table { + + private final WorldTable worldTable; + private final String worldIDColumn; + private final String worldNameColumn; + + private final String columnWorldId; + private final String columnUserID; + private final String columnPlaytime; + + private final String selectWorldIDsql; + + /** + * Constructor. + * + * @param db Database this table is a part of. + * @param usingMySQL Database is a MySQL database. + */ + public WorldTimesTable(SQLDB db, boolean usingMySQL) { + super("plan_world_times", db, usingMySQL); + worldTable = db.getWorldTable(); + worldIDColumn = worldTable + "." + worldTable.getColumnID(); + worldNameColumn = worldTable.getColumnWorldName(); + columnWorldId = "world_id"; + columnUserID = "user_id"; + columnPlaytime = "playtime"; + + selectWorldIDsql = "(SELECT " + worldIDColumn + " FROM " + worldTable + " WHERE (" + worldNameColumn + "=?))"; + } + + @Override + public boolean createTable() { + UsersTable usersTable = db.getUsersTable(); + try { + execute("CREATE TABLE IF NOT EXISTS " + tableName + " (" + + columnUserID + " integer NOT NULL, " + + columnWorldId + " integer NOT NULL, " + + columnPlaytime + " bigint NOT NULL, " + + "FOREIGN KEY(" + columnUserID + ") REFERENCES " + usersTable.getTableName() + "(" + usersTable.getColumnID() + "), " + + "FOREIGN KEY(" + columnWorldId + ") REFERENCES " + worldTable.getTableName() + "(" + worldTable.getColumnID() + ")" + + ")" + ); + return true; + } catch (SQLException ex) { + Log.toLog(this.getClass().getName(), ex); + return false; + } + } + + public boolean removeUserWorldTimes(int userId) { + PreparedStatement statement = null; + try { + statement = prepareStatement("DELETE FROM " + tableName + " WHERE (" + columnUserID + "=?)"); + statement.setInt(1, userId); + statement.execute(); + return true; + } catch (SQLException ex) { + Log.toLog(this.getClass().getName(), ex); + return false; + } finally { + close(statement); + } + } + + /** + * @param userId + * @return + * @throws SQLException + */ + public Map getWorldTimes(int userId) throws SQLException { + PreparedStatement statement = null; + ResultSet set = null; + try { + statement = prepareStatement("SELECT " + + columnPlaytime + ", " + + worldNameColumn + + " FROM " + tableName + ", " + worldTable + + " WHERE (" + columnUserID + "=?)" + + " AND (" + worldIDColumn + "=" + tableName + "." + columnWorldId + ")"); + statement.setInt(1, userId); + set = statement.executeQuery(); + HashMap times = new HashMap<>(); + while (set.next()) { + times.put(set.getString(worldNameColumn), set.getLong(columnPlaytime)); + } + return times; + } finally { + close(set); + close(statement); + } + } + + public Map> getWorldTimes(Collection userIds) throws SQLException { + PreparedStatement statement = null; + ResultSet set = null; + Map> times = new HashMap<>(); + for (Integer id : userIds) { + times.put(id, new HashMap<>()); + } + try { + statement = prepareStatement("SELECT " + + columnUserID + ", " + + columnPlaytime + ", " + + worldNameColumn + + " FROM " + tableName + ", " + worldTable + + " WHERE (" + worldIDColumn + "=" + tableName + "." + columnWorldId + ")"); + set = statement.executeQuery(); + while (set.next()) { + int id = set.getInt(columnUserID); + if (!userIds.contains(id)) { + continue; + } + Map worldTimes = times.get(id); + worldTimes.put(set.getString(worldNameColumn), set.getLong(columnPlaytime)); + } + return times; + } finally { + close(set); + close(statement); + } + } + + public void saveWorldTimes(int userId, Map worldTimes) throws SQLException { + if (Verify.isEmpty(worldTimes)) { + return; + } + Map saved = getWorldTimes(userId); + + Map newData = new HashMap<>(); + Map updateData = new HashMap<>(); + + for (Map.Entry entry : worldTimes.entrySet()) { + String world = entry.getKey(); + long time = entry.getValue(); + Long savedTime = saved.get(world); + + if (savedTime == null) { + newData.put(world, time); + } else { + if (savedTime < time) { + updateData.put(world, time); + } + } + } + insertWorlds(userId, newData); + updateWorlds(userId, updateData); + } + + private void updateWorlds(int userId, Map updateData) throws SQLException { + if (Verify.isEmpty(updateData)) { + return; + } + PreparedStatement statement = null; + try { + statement = prepareStatement( + "UPDATE " + tableName + " SET " + columnPlaytime + "=?" + + " WHERE (" + selectWorldIDsql + "=" + columnWorldId + ")" + + " AND (" + columnUserID + "=?)" + ); + boolean commitRequired = false; + for (Map.Entry entry : updateData.entrySet()) { + String worldName = entry.getKey(); + long time = entry.getValue(); + statement.setLong(1, time); + statement.setString(2, worldName); + statement.setInt(3, userId); + statement.addBatch(); + commitRequired = true; + } + if (commitRequired) { + statement.executeBatch(); + } + } finally { + close(statement); + } + } + + private void insertWorlds(int userId, Map newData) throws SQLException { + if (Verify.isEmpty(newData)) { + return; + } + PreparedStatement statement = null; + try { + statement = prepareStatement( + "INSERT INTO " + tableName + " (" + + columnUserID + ", " + + columnWorldId + ", " + + columnPlaytime + + ") VALUES (?, " + selectWorldIDsql + ", ?)" + ); + boolean commitRequired = false; + for (Map.Entry entry : newData.entrySet()) { + String worldName = entry.getKey(); + long time = entry.getValue(); + statement.setInt(1, userId); + statement.setString(2, worldName); + statement.setLong(3, time); + statement.addBatch(); + commitRequired = true; + } + if (commitRequired) { + statement.executeBatch(); + } + } finally { + close(statement); + } + } + + public void saveWorldTimes(Map> worldTimesMultiple) throws SQLException { + if (Verify.isEmpty(worldTimesMultiple)) { + return; + } + Map> saved = getWorldTimes(worldTimesMultiple.keySet()); + + Map> newData = new HashMap<>(); + Map> updateData = new HashMap<>(); + + for (Map.Entry> entry : worldTimesMultiple.entrySet()) { + int userId = entry.getKey(); + Map savedTimes = saved.get(userId); + Map worldTimes = entry.getValue(); + Map newTimes = new HashMap<>(worldTimes); + newTimes.keySet().removeAll(savedTimes.keySet()); + + newData.put(userId, newTimes); + + for (Map.Entry times : savedTimes.entrySet()) { + String world = times.getKey(); + long savedTime = times.getValue(); + Long toSave = worldTimes.get(world); + if (toSave != null && toSave <= savedTime) { + worldTimes.remove(world); + } + } + updateData.put(userId, worldTimes); + } + insertWorlds(newData); + updateWorlds(updateData); + } + + private void updateWorlds(Map> updateData) throws SQLException { + if (Verify.isEmpty(updateData)) { + return; + } + PreparedStatement statement = null; + try { + statement = prepareStatement( + "UPDATE " + tableName + " SET " + columnPlaytime + "=?" + + " WHERE (" + selectWorldIDsql + "=" + columnWorldId + ")" + + " AND (" + columnUserID + "=?)" + ); + boolean commitRequired = false; + for (Map.Entry> entry : updateData.entrySet()) { + int userId = entry.getKey(); + for (Map.Entry times : entry.getValue().entrySet()) { + String worldName = times.getKey(); + long time = times.getValue(); + statement.setLong(1, time); + statement.setString(2, worldName); + statement.setInt(3, userId); + statement.addBatch(); + commitRequired = true; + } + } + if (commitRequired) { + statement.executeBatch(); + } + } finally { + close(statement); + } + } + + private void insertWorlds(Map> newData) throws SQLException { + if (Verify.isEmpty(newData)) { + return; + } + PreparedStatement statement = null; + try { + statement = prepareStatement( + "INSERT INTO " + tableName + " (" + + columnUserID + ", " + + columnWorldId + ", " + + columnPlaytime + + ") VALUES (?, " + selectWorldIDsql + ", ?)" + ); + boolean commitRequired = false; + for (Map.Entry> entry : newData.entrySet()) { + int userId = entry.getKey(); + for (Map.Entry times : entry.getValue().entrySet()) { + String worldName = times.getKey(); + long time = times.getValue(); + statement.setInt(1, userId); + statement.setString(2, worldName); + statement.setLong(3, time); + statement.addBatch(); + commitRequired = true; + } + } + if (commitRequired) { + statement.executeBatch(); + } + } finally { + close(statement); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/DataRequestHandler.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/DataRequestHandler.java index 9d86498fa..6b2a475cd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/DataRequestHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/DataRequestHandler.java @@ -11,7 +11,6 @@ import java.io.FileNotFoundException; import java.util.UUID; /** - * * @author Rsl1122 */ public class DataRequestHandler { @@ -43,7 +42,7 @@ public class DataRequestHandler { * Returns the player.html as string with replaced placeholders. * * @param uuid UUID of player, whose UserData is used to replace - * placeholders with + * placeholders with * @return The html */ public String getInspectHtml(UUID uuid) { @@ -53,7 +52,7 @@ public class DataRequestHandler { return "

404 Data was not found in cache

"; } return HtmlUtils.replacePlaceholders( - HtmlUtils.getHtmlStringFromResource("player.html"), + HtmlUtils.getStringFromResource("player.html"), PlaceholderUtils.getInspectReplaceRules(data) ); } catch (FileNotFoundException ex) { @@ -72,9 +71,8 @@ public class DataRequestHandler { return "

404 Data was not found in cache

"; } return HtmlUtils.replacePlaceholders( - HtmlUtils.getHtmlStringFromResource("analysis.html"), - PlaceholderUtils.getAnalysisReplaceRules(analysisCache.getData()) - ); + HtmlUtils.getStringFromResource("analysis.html"), + PlaceholderUtils.getAnalysisReplaceRules(analysisCache.getData())); } catch (FileNotFoundException ex) { return "

404 analysis.html was not found

"; } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/Html.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/Html.java index 0fdafba58..f0dbb9605 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/Html.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/Html.java @@ -1,15 +1,15 @@ package main.java.com.djrapitops.plan.ui.html; import com.djrapitops.plugin.utilities.Verify; +import main.java.com.djrapitops.plan.Log; + import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; -import main.java.com.djrapitops.plan.Log; /** - * * @author Rsl1122 */ public enum Html { @@ -27,12 +27,12 @@ public enum Html { COLOR_7(""), COLOR_8(""), COLOR_9(""), - COLOR_a(""), - COLOR_b(""), - COLOR_c(""), - COLOR_d(""), - COLOR_e(""), - COLOR_f(""), + COLOR_A(""), + COLOR_B(""), + COLOR_C(""), + COLOR_D(""), + COLOR_E(""), + COLOR_F(""), // FONT_AWESOME_ICON(""), MINOTAR_SMALL_IMG("\"""), @@ -112,55 +112,27 @@ public enum Html { } /** - * - * @return - */ - public String parse() { - return html; - } - - /** - * - * @param p - * @return - */ - public String parse(String... p) { - Verify.nullCheck(p); - String returnValue = this.html; - for (int i = 0; i < p.length; i++) { - returnValue = returnValue.replace("REPLACE" + i, p[i]); - } - return returnValue; - } - - /** - * - * @param html - */ - public void setHtml(String html) { - this.html = html; - } - - /** - * * @param localeFile */ public static void loadLocale(File localeFile) { - try { - Scanner localeScanner = new Scanner(localeFile, "UTF-8"); + try (Scanner localeScanner = new Scanner(localeFile, "UTF-8")) { List localeRows = new ArrayList<>(); boolean html = false; + while (localeScanner.hasNextLine()) { String line = localeScanner.nextLine(); if (line.equals("<<<<<>>>>>")) { html = true; continue; } + if (!html) { continue; } + localeRows.add(line); } + for (String localeRow : localeRows) { try { String[] split = localeRow.split(" <> "); @@ -170,7 +142,34 @@ public enum Html { } } } catch (IOException e) { - + Log.error("Something went wrong at loading locale " + localeFile.getAbsoluteFile() + ": " + e.getCause()); } } + + /** + * @return + */ + public String parse() { + return html; + } + + /** + * @param p + * @return + */ + public String parse(String... p) { + Verify.nullCheck(p); + String returnValue = this.html; + for (int i = 0; i < p.length; i++) { + returnValue = returnValue.replace("REPLACE" + i, p[i]); + } + return returnValue; + } + + /** + * @param html + */ + public void setHtml(String html) { + this.html = html; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/RecentPlayersButtonsCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/RecentPlayersButtonsCreator.java index c3144f020..b0822ad5c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/RecentPlayersButtonsCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/RecentPlayersButtonsCreator.java @@ -5,11 +5,17 @@ import main.java.com.djrapitops.plan.utilities.HtmlUtils; import java.util.List; /** - * * @author Rsl1122 */ public class RecentPlayersButtonsCreator { + /** + * Constructor used to hide the public constructor + */ + private RecentPlayersButtonsCreator() { + throw new IllegalStateException("Utility class"); + } + /** * Creates recent players buttons inside a p-tag. * @@ -18,15 +24,18 @@ public class RecentPlayersButtonsCreator { * @return html p-tag list of recent log-ins. */ public static String createRecentLoginsButtons(List names, int limit) { - StringBuilder html = new StringBuilder(); - html.append("

"); - for (int i = 0; i < names.size(); i++) { - if (i < limit) { - String name = names.get(i); - html.append(Html.BUTTON.parse(HtmlUtils.getRelativeInspectUrl(name), name)); - html.append(" "); + StringBuilder html = new StringBuilder("

"); + + int i = 0; + for (String name : names) { + if (i >= limit) { + break; } + + html.append(Html.BUTTON.parse(HtmlUtils.getRelativeInspectUrl(name), name)).append(" "); + i++; } + html.append("

"); return html.toString(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/CPUGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/CPUGraphCreator.java index 9743b0670..b58a8a200 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/CPUGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/CPUGraphCreator.java @@ -1,20 +1,24 @@ package main.java.com.djrapitops.plan.ui.html.graphs; import main.java.com.djrapitops.plan.data.TPS; -import main.java.com.djrapitops.plan.utilities.FormatUtils; -import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.Point; import java.util.List; import java.util.stream.Collectors; public class CPUGraphCreator { - public static String buildScatterDataString(List tpsData, long scale) { - long now = MiscUtils.getTime(); + + /** + * Constructor used to hide the public constructor + */ + private CPUGraphCreator() { + throw new IllegalStateException("Utility class"); + } + + public static String buildSeriesDataString(List tpsData) { List points = tpsData.stream() - .filter(tps -> tps.getDate() >= now - scale) - .map(tps -> new Point(tps.getDate(), Double.parseDouble(FormatUtils.cutDecimals(tps.getCPUUsage()).replace(",", ".")))) + .map(tps -> new Point(tps.getDate(), tps.getCPUUsage())) .collect(Collectors.toList()); - return ScatterGraphCreator.scatterGraph(points, true); + return SeriesCreator.seriesGraph(points, true); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java index 959df1d1c..e7f0b8c0b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java @@ -1,12 +1,11 @@ package main.java.com.djrapitops.plan.ui.html.graphs; -import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.TPS; -import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.Point; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -15,35 +14,25 @@ import java.util.stream.Collectors; */ public class PlayerActivityGraphCreator { - public static String buildScatterDataString(List tpsData, long scale) { - long now = MiscUtils.getTime(); - List points = tpsData.stream() - .filter(tps -> tps.getDate() >= now - scale) - .map(tps -> new Point(tps.getDate(), tps.getPlayers())) - .collect(Collectors.toList()); - return ScatterGraphCreator.scatterGraph(points, true); + /** + * Constructor used to hide the public constructor + */ + private PlayerActivityGraphCreator() { + throw new IllegalStateException("Utility class"); } - public static String buildScatterDataStringSessions(List sessionData, long scale) { - long now = MiscUtils.getTime(); - long nowMinusScale = now - scale; - List filtered = filterSessions(sessionData, nowMinusScale); + public static String buildSeriesDataString(List tpsData) { + List points = tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getPlayers())) + .collect(Collectors.toList()); + return SeriesCreator.seriesGraph(points, true); + } - List points = filtered.stream() + public static String buildSeriesDataStringSessions(Collection sessions) { + List points = sessions.stream() .map(session -> new Point[]{new Point(session.getSessionStart(), 1), new Point(session.getSessionEnd(), 0)}) .flatMap(Arrays::stream) .collect(Collectors.toList()); - - Log.debug(points.stream().map(Point::getY).collect(Collectors.toList()).toString()); return ScatterGraphCreator.scatterGraph(points, true, false); } - - private static List filterSessions(List sessions, long nowMinusScale) { - return sessions.parallelStream() - .filter(session -> (session != null)) - .filter(session -> session.isValid() || session.getSessionEnd() == -1) - .filter((session) -> (session.getSessionStart() >= nowMinusScale || session.getSessionEnd() >= nowMinusScale)) - .distinct() - .collect(Collectors.toList()); - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PunchCardGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PunchCardGraphCreator.java index 07ac32a9a..09333ca71 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PunchCardGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PunchCardGraphCreator.java @@ -5,11 +5,8 @@ */ package main.java.com.djrapitops.plan.ui.html.graphs; -import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.data.SessionData; -import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import java.util.Collection; import java.util.List; @@ -17,43 +14,51 @@ import java.util.Objects; import java.util.stream.Collectors; /** + * Utility class for creating Punch Card Data Array for the JavaScripts. * * @author Rsl1122 + * @since 3.6.0 */ public class PunchCardGraphCreator { /** - * - * @param data - * @return + * Constructor used to hide the public constructor */ - public static String generateDataArray(Collection data) { - List sessionStarts = getSessionStarts(data); + private PunchCardGraphCreator() { + throw new IllegalStateException("Utility class"); + } + + /** + * Creates a PunchCard series data Array for HighCharts + * + * @param sessions Sessions (Unique/Player) to be placed into the PunchCard. + * @return Data array as a string. + */ + public static String createDataSeries(Collection sessions) { + List sessionStarts = getSessionStarts(sessions); List daysAndHours = AnalysisUtils.getDaysAndHours(sessionStarts); int[][] dataArray = createDataArray(daysAndHours); int big = findBiggestValue(dataArray); int[][] scaled = scale(dataArray, big); - StringBuilder arrayBuilder = buildString(scaled); - return arrayBuilder.toString(); - } - - private static StringBuilder buildString(int[][] scaled) { - StringBuilder arrayBuilder = new StringBuilder(); - arrayBuilder.append("["); + StringBuilder arrayBuilder = new StringBuilder("["); for (int i = 0; i < 7; i++) { for (int j = 0; j < 24; j++) { int value = scaled[i][j]; if (value == 0) { continue; } - arrayBuilder.append("{").append("x:").append(j).append(", y:").append(i).append(", r:").append(value).append("}"); + arrayBuilder.append("{x:").append(j * 3600000) + .append(", y:").append(i) + .append(", z:").append(value). + append(", marker: { radius:").append(value) + .append("}}"); if (i != 6 || j != 23) { arrayBuilder.append(","); } } } arrayBuilder.append("]"); - return arrayBuilder; + return arrayBuilder.toString(); } private static int[][] createDataArray(List daysAndHours) { @@ -63,58 +68,14 @@ public class PunchCardGraphCreator { int h = dAndH[1]; dataArray[d][h] = dataArray[d][h] + 1; } - if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) { - int avg = findAverage(dataArray); - double standardDeviation = getStandardDeviation(dataArray, avg); - if (standardDeviation > 3.5) { - for (int i = 0; i < 7; i++) { - for (int j = 0; j < 24; j++) { - int value = dataArray[i][j]; - if (value - avg > 3 * standardDeviation) { - dataArray[i][j] = avg; - } - } - } - } - } return dataArray; } - private static double getStandardDeviation(int[][] array, int avg) { - int[][] valueMinusAvg = new int[7][24]; - for (int i = 0; i < 7; i++) { - for (int j = 0; j < 24; j++) { - valueMinusAvg[i][j] = (int) Math.pow(Math.abs(array[i][j] - avg), 2); - } - } - int size = array.length * array[0].length; - int sum = sum(valueMinusAvg); - return Math.sqrt(sum / size); - } - - private static int findAverage(int[][] array) { - int total = sum(array); - int size = array.length * array[0].length; - return (int) MathUtils.average(total, size); - } - - private static int sum(int[][] array) { - int total = 0; - for (int[] is : array) { - for (int i : is) { - total += i; - } - } - return total; - } - private static List getSessionStarts(Collection data) { - long now = MiscUtils.getTime(); return data.stream() .filter(Objects::nonNull) .filter(SessionData::isValid) .map(SessionData::getSessionStart) - .filter(start -> now - start < (long) 2592000 * (long) 1000) .sorted() .collect(Collectors.toList()); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/RamGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/RamGraphCreator.java new file mode 100644 index 000000000..3bc56fdea --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/RamGraphCreator.java @@ -0,0 +1,37 @@ +package main.java.com.djrapitops.plan.ui.html.graphs; + +import main.java.com.djrapitops.plan.data.TPS; +import main.java.com.djrapitops.plan.utilities.analysis.Point; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Class for creating scatter graph data from RAM Usage snapshots with TPS task. + * + * @author Rsl1122 + * @since 3.6.0 + * @see main.java.com.djrapitops.plan.data.listeners.TPSCountTimer + */ +public class RamGraphCreator { + + /** + * Constructor used to hide the public constructor + */ + private RamGraphCreator() { + throw new IllegalStateException("Utility class"); + } + + /** + * Creates a series data string from given data. + * + * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. + * @return Series data for HighCharts + */ + public static String buildSeriesDataString(List tpsData) { + List points = tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getUsedMemory())) + .collect(Collectors.toList()); + return SeriesCreator.seriesGraph(points, true); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/ScatterGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/ScatterGraphCreator.java index 2f88c0b8b..8b4c03908 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/ScatterGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/ScatterGraphCreator.java @@ -5,15 +5,11 @@ */ package main.java.com.djrapitops.plan.ui.html.graphs; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.utilities.Verify; -import main.java.com.djrapitops.plan.utilities.analysis.DouglasPeckerAlgorithm; +import main.java.com.djrapitops.plan.utilities.analysis.DouglasPeuckerAlgorithm; import main.java.com.djrapitops.plan.utilities.analysis.Point; -import main.java.com.djrapitops.plan.utilities.comparators.PointComparator; +import main.java.com.djrapitops.plan.utilities.analysis.ReduceGapTriangles; -import java.util.HashSet; import java.util.List; -import java.util.Set; /** * Abstract scatter graph creator used by other graph creators. @@ -23,39 +19,26 @@ import java.util.Set; */ public class ScatterGraphCreator { + /** + * Constructor used to hide the public constructor + */ + private ScatterGraphCreator() { + throw new IllegalStateException("Utility class"); + } + public static String scatterGraph(List points, boolean reduceGapTriangles) { return scatterGraph(points, reduceGapTriangles, true); } public static String scatterGraph(List points, boolean reduceGapTriangles, boolean reducePoints) { - StringBuilder arrayBuilder = new StringBuilder(); - arrayBuilder.append("["); + StringBuilder arrayBuilder = new StringBuilder("["); if (reducePoints) { - points = DouglasPeckerAlgorithm.reducePoints(points, 0); + points = DouglasPeuckerAlgorithm.reducePoints(points, 0); } if (reduceGapTriangles) { - Point lastPoint = null; - - Set toAdd = new HashSet<>(); - for (Point point : points) { - if (Verify.notNull(point, lastPoint)) { - long date = (long) point.getX(); - long lastDate = (long) lastPoint.getX(); - double y = point.getY(); - double lastY = lastPoint.getY(); - if (y != lastY && Math.abs(lastY - y) > 0.5) { - if (lastDate < date - TimeAmount.MINUTE.ms() * 10L) { - toAdd.add(new Point(lastDate + 1, lastY)); - toAdd.add(new Point(date - 1, lastY)); - } - } - } - lastPoint = point; - } - points.addAll(toAdd); - points.sort(new PointComparator()); + points = ReduceGapTriangles.reduce(points); } int size = points.size(); diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SeriesCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SeriesCreator.java new file mode 100644 index 000000000..dc7cd7a0e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SeriesCreator.java @@ -0,0 +1,58 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package main.java.com.djrapitops.plan.ui.html.graphs; + +import main.java.com.djrapitops.plan.utilities.analysis.DouglasPeuckerAlgorithm; +import main.java.com.djrapitops.plan.utilities.analysis.Point; +import main.java.com.djrapitops.plan.utilities.analysis.ReduceGapTriangles; + +import java.util.List; + +/** + * Abstract scatter graph creator used by other graph creators. + * + * @author Rsl1122 + * @since 3.5.2 + */ +public class SeriesCreator { + + /** + * Constructor used to hide the public constructor + */ + private SeriesCreator() { + throw new IllegalStateException("Utility class"); + } + + public static String seriesGraph(List points, boolean reduceGapTriangles) { + return seriesGraph(points, reduceGapTriangles, true); + } + + public static String seriesGraph(List points, boolean reduceGapTriangles, boolean reducePoints) { + StringBuilder arrayBuilder = new StringBuilder("["); + + if (reducePoints) { + points = DouglasPeuckerAlgorithm.reducePoints(points, 0); + } + + if (reduceGapTriangles) { + points = ReduceGapTriangles.reduce(points); + } + + int size = points.size(); + for (int i = 0; i < size; i++) { + Point point = points.get(i); + double y = point.getY(); + long date = (long) point.getX(); + arrayBuilder.append("[").append(date).append(",").append(y).append("]"); + if (i < size - 1) { + arrayBuilder.append(","); + } + } + + arrayBuilder.append("]"); + return arrayBuilder.toString(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SessionLengthDistributionGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SessionLengthDistributionGraphCreator.java index e4a5b733b..f3871dc0c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SessionLengthDistributionGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/SessionLengthDistributionGraphCreator.java @@ -5,104 +5,67 @@ */ package main.java.com.djrapitops.plan.ui.html.graphs; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; -import main.java.com.djrapitops.plan.data.SessionData; -import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; /** - * * @author Rsl1122 */ public class SessionLengthDistributionGraphCreator { /** - * - * @param data - * @return + * Constructor used to hide the public constructor */ - public static String[] generateDataArraySessions(Collection data) { - List lengths = AnalysisUtils.transformSessionDataToLengths(data); - return generateDataArray(lengths); + private SessionLengthDistributionGraphCreator() { + throw new IllegalStateException("Utility class"); } /** + * Creates a data series of session lengths for Sessions bar chart. + *

+ * Contains values from 0 up to 120 minutes * - * @param lengths - * @return + * @param lengths Lengths of all sessions in a list. + * @return Data for HighCharts series. */ - public static String[] generateDataArray(Collection lengths) { - Map values = getValues(lengths); -// Map scaled = scale(values); - StringBuilder arrayBuilder = buildString(values); - StringBuilder labelBuilder = buildLabels(values); - return new String[]{arrayBuilder.toString(), labelBuilder.toString()}; - } + public static String createDataSeries(List lengths) { + Map bars = getValues(lengths); + List keys = new ArrayList<>(bars.keySet()); + Collections.sort(keys); - private static StringBuilder buildString(Map scaled) { - StringBuilder arrayBuilder = new StringBuilder(); - arrayBuilder.append("["); - - long big = MathUtils.getBiggestLong(scaled.keySet()); - for (long key = 0; key <= big; key++) { - Integer value = scaled.get(key); - if (value == null) { - continue; + StringBuilder arrayBuilder = new StringBuilder("["); + int i = 0; + int size = keys.size(); + for (Long key : keys) { + if (key > 120) { + break; } - arrayBuilder.append(value); - if (key != big) { + Integer value = bars.get(key); + arrayBuilder.append("['").append(key - 5).append(" - ").append(key).append(" min',").append(value).append("]"); + if (i < size) { arrayBuilder.append(", "); } + i++; } arrayBuilder.append("]"); - return arrayBuilder; - } - - private static StringBuilder buildLabels(Map scaled) { - StringBuilder arrayBuilder = new StringBuilder(); - arrayBuilder.append("["); - - long big = MathUtils.getBiggestLong(scaled.keySet()); - for (long key = 0; key <= big; key++) { - Integer value = scaled.get(key); - if (value == null) { - continue; - } - arrayBuilder.append("\'").append(key - 5).append(" - ").append(key).append(" min").append("\'"); - if (key != big) { - arrayBuilder.append(", "); - } - } - arrayBuilder.append("]"); - return arrayBuilder; + return arrayBuilder.toString(); } private static Map getValues(Collection lengths) { List unused = new ArrayList<>(lengths); Map values = new HashMap<>(); long lengthInMinutes = 5; - while (!unused.isEmpty() && lengthInMinutes < 120) { + + while (!unused.isEmpty() || lengthInMinutes <= 120) { long length = lengthInMinutes * 60 * 1000; List lessThan = unused.stream().filter(l -> l < length).collect(Collectors.toList()); - values.put(lengthInMinutes, lessThan.size()); - unused.removeAll(lessThan); + int amount = lessThan.size(); + if (amount != 0) { + values.put(lengthInMinutes, amount); + unused.removeAll(lessThan); + } lengthInMinutes += 5; } return values; } - - private static Map scale(Map values) { - Map scaled = new HashMap<>(); - int total = MathUtils.sumInt(values.values().stream().map(i -> (Serializable) i)); - for (long key : values.keySet()) { - scaled.put(key, (int) ((1.0 * values.get(key) / total) * 100)); - } - return scaled; - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java index f47412dbb..d8f9d2047 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java @@ -1,8 +1,6 @@ package main.java.com.djrapitops.plan.ui.html.graphs; import main.java.com.djrapitops.plan.data.TPS; -import main.java.com.djrapitops.plan.utilities.FormatUtils; -import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.analysis.Point; import java.util.List; @@ -10,21 +8,26 @@ import java.util.Objects; import java.util.stream.Collectors; /** - * * @author Rsl1122 * @since 3.5.0 */ public class TPSGraphCreator { - - public static String buildScatterDataStringTPS(List tpsData, long scale) { - long now = MiscUtils.getTime(); - List points = tpsData.stream() - .filter(tps -> tps.getDate() >= now - scale) - .map(tps -> new Point(tps.getDate(), Double.parseDouble(FormatUtils.cutDecimals(tps.getTps()).replace(",", ".")))) - .collect(Collectors.toList()); - return ScatterGraphCreator.scatterGraph(points, true); + + /** + * Constructor used to hide the public constructor + */ + private TPSGraphCreator() { + throw new IllegalStateException("Utility class"); } - + + public static String buildSeriesDataString(List tpsData) { + List points = tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getTps())) + .collect(Collectors.toList()); + return SeriesCreator.seriesGraph(points, true); + + } + public static List filterTPS(List tpsData, long nowMinusScale) { return tpsData.stream() .filter(Objects::nonNull) diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldLoadGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldLoadGraphCreator.java new file mode 100644 index 000000000..69ea4b7e6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldLoadGraphCreator.java @@ -0,0 +1,50 @@ +package main.java.com.djrapitops.plan.ui.html.graphs; + +import main.java.com.djrapitops.plan.data.TPS; +import main.java.com.djrapitops.plan.utilities.analysis.Point; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Class for creating scatter graph data from Chunk & Entity load snapshots with TPS task. + * + * @author Rsl1122 + * @since 3.6.0 + * @see main.java.com.djrapitops.plan.data.listeners.TPSCountTimer + */ +public class WorldLoadGraphCreator { + + /** + * Constructor used to hide the public constructor + */ + private WorldLoadGraphCreator() { + throw new IllegalStateException("Utility class"); + } + + /** + * Creates series graph data of entity load. + * + * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. + * @return Series data for HighCharts + */ + public static String buildSeriesDataStringEntities(List tpsData) { + List points = tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getEntityCount())) + .collect(Collectors.toList()); + return SeriesCreator.seriesGraph(points, true); + } + + /** + * Creates series data of chunk load. + * + * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. + * @return Series data for HighCharts + */ + public static String buildSeriesDataStringChunks(List tpsData) { + List points = tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getChunksLoaded())) + .collect(Collectors.toList()); + return SeriesCreator.seriesGraph(points, true); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldMapCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldMapCreator.java new file mode 100644 index 000000000..8dcf965ef --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldMapCreator.java @@ -0,0 +1,41 @@ +package main.java.com.djrapitops.plan.ui.html.graphs; + +import java.util.Map; + +public class WorldMapCreator { + + /** + * Constructor used to hide the public constructor + */ + private WorldMapCreator() { + throw new IllegalStateException("Utility class"); + } + + /** + * Creates a data series with iso-a3 specification of Country codes. + * + * @param geoCodeCounts + * @return + */ + public static String createDataSeries(Map geoCodeCounts) { + StringBuilder arrayBuilder = new StringBuilder("["); + + int i = 0; + int size = geoCodeCounts.size(); + for (Map.Entry entry : geoCodeCounts.entrySet()) { + String geoCode = entry.getKey(); + Integer players = entry.getValue(); + if (players != 0) { + arrayBuilder.append("{'code':'").append(geoCode).append("','value':").append(players).append("}"); + if (i < size - 1) { + arrayBuilder.append(","); + } + } + i++; + } + + + arrayBuilder.append("]"); + return arrayBuilder.toString(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldPieCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldPieCreator.java new file mode 100644 index 000000000..c70a9b4b6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/WorldPieCreator.java @@ -0,0 +1,29 @@ +package main.java.com.djrapitops.plan.ui.html.graphs; + +import java.util.Map; + +public class WorldPieCreator { + + private WorldPieCreator() { + throw new IllegalStateException("Utility Class"); + } + + public static String createSeriesData(Map worldTimes) { + StringBuilder arrayBuilder = new StringBuilder("["); + int i = 0; + int size = worldTimes.size(); + for (Map.Entry 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(","); + } + } + arrayBuilder.append("]"); + return arrayBuilder.toString(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/CommandUseTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/CommandUseTableCreator.java index 63ea09bfc..1b682c900 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/CommandUseTableCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/CommandUseTableCreator.java @@ -10,13 +10,18 @@ import java.util.List; import java.util.Map; /** - * * @author Rsl1122 */ public class CommandUseTableCreator { /** - * + * Constructor used to hide the public constructor + */ + private CommandUseTableCreator() { + throw new IllegalStateException("Utility class"); + } + + /** * @param commandUse * @return */ @@ -28,17 +33,20 @@ public class CommandUseTableCreator { html.append(Html.ERROR_TABLE_2.parse()); } else { Collections.reverse(sorted); + int i = 0; for (String[] values : sorted) { if (i >= 500) { break; } + try { html.append(Html.TABLELINE_2.parse(values[1], values[0])); } catch (IllegalArgumentException e) { Log.toLog("SortableCommandUseTableCreator", e); Log.toLog("Cause: " + values[0] + " " + values[1], Log.getErrorsFilename()); } + i++; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/KillsTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/KillsTableCreator.java index d3758befe..8cc79dbeb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/KillsTableCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/KillsTableCreator.java @@ -10,18 +10,24 @@ import main.java.com.djrapitops.plan.utilities.HtmlUtils; import java.util.List; /** - * * @author Rsl1122 */ public class KillsTableCreator { /** - * + * Constructor used to hide the public constructor + */ + private KillsTableCreator() { + throw new IllegalStateException("Utility class"); + } + + /** * @param killData * @return */ public static String createKillsTable(List killData) { StringBuilder html = new StringBuilder(Html.TABLE_KILLS_START.parse()); + if (killData.isEmpty()) { html.append(Html.TABLELINE_3.parse(Html.KILLDATA_NONE.parse(), "", "")); } else { @@ -34,7 +40,7 @@ public class KillsTableCreator { IOfflinePlayer victim = Fetch.getIOfflinePlayer(kill.getVictim()); String name = victim.getName(); html.append(Html.TABLELINE_3_CUSTOMKEY_1.parse( - date + "", FormatUtils.formatTimeStamp(date), + String.valueOf(date), FormatUtils.formatTimeStamp(date), Html.LINK.parse(HtmlUtils.getInspectUrl(name), name), kill.getWeapon() )); @@ -42,6 +48,7 @@ public class KillsTableCreator { } } html.append(Html.TABLE_END.parse()); + return html.toString(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/PlayersTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/PlayersTableCreator.java index e66f2f0df..7bf09b02e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/PlayersTableCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/tables/PlayersTableCreator.java @@ -16,6 +16,13 @@ import java.util.List; */ public class PlayersTableCreator { + /** + * Constructor used to hide the public constructor + */ + private PlayersTableCreator() { + throw new IllegalStateException("Utility class"); + } + /** * @param data * @return @@ -23,10 +30,11 @@ public class PlayersTableCreator { public static String createSortablePlayersTable(List data) { Benchmark.start("Create Players table"); StringBuilder html = new StringBuilder(); + long now = MiscUtils.getTime(); boolean showImages = Settings.PLAYERLIST_SHOW_IMAGES.isTrue(); + int i = 0; -// Collections.sort(data, new UserDataLastPlayedComparator()); // Already sorted. for (UserData uData : data) { if (i >= 750) { break; @@ -46,16 +54,18 @@ public class PlayersTableCreator { html.append(Html.TABLELINE_PLAYERS.parse( img + Html.LINK.parse(HtmlUtils.getInspectUrl(uData.getName()), uData.getName()), activityString, - uData.getPlayTime() + "", FormatUtils.formatTimeAmount(uData.getPlayTime()), - uData.getLoginTimes() + "", - uData.getRegistered() + "", FormatUtils.formatTimeStampYear(uData.getRegistered()), - uData.getLastPlayed() + "", FormatUtils.formatTimeStamp(uData.getLastPlayed()), - uData.getGeolocation() + String.valueOf(uData.getPlayTime()), FormatUtils.formatTimeAmount(uData.getPlayTime()), + String.valueOf(uData.getLoginTimes()), + String.valueOf(uData.getRegistered()), FormatUtils.formatTimeStampYear(uData.getRegistered()), + String.valueOf(uData.getLastPlayed()), FormatUtils.formatTimeStamp(uData.getLastPlayed()), + String.valueOf(uData.getGeolocation()) )); - } catch (NullPointerException e) { + } catch (NullPointerException ignored) { } + i++; } + Benchmark.stop("Create Players table"); return html.toString(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/text/TextUI.java b/Plan/src/main/java/com/djrapitops/plan/ui/text/TextUI.java index d6b37c168..5b56c79fa 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/text/TextUI.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/text/TextUI.java @@ -16,13 +16,18 @@ import org.bukkit.ChatColor; import java.util.UUID; /** - * * @author Rsl1122 */ public class TextUI { /** - * + * Constructor used to hide the public constructor + */ + private TextUI() { + throw new IllegalStateException("Utility class"); + } + + /** * @param uuid * @return */ @@ -41,19 +46,18 @@ public class TextUI { boolean online = d.isOnline(); String ball = sec + " " + Phrase.BALL + main; return new String[]{ - sec + " " + Phrase.BALL + (banned ? ChatColor.DARK_RED + " Banned" : ter + (active ? " Active" : " Inactive")) + (online ? ChatColor.GREEN + " Online" : ChatColor.RED + " Offline"), - ball + " Registered: " + sec + FormatUtils.formatTimeStampYear(d.getRegistered()), - ball + " Last seen: " + sec + FormatUtils.formatTimeStamp(d.getLastPlayed()), - ball + " Playtime: " + sec + FormatUtils.formatTimeAmount(d.getPlayTime()), - ball + " Login times: " + sec + d.getLoginTimes(), - ball + " Average session length: " + sec + FormatUtils.formatTimeAmount(MathUtils.averageLong(AnalysisUtils.transformSessionDataToLengths(d.getSessions()))), - ball + " Kills: " + sec + d.getPlayerKills().size() + main + " Mobs: " + sec + d.getMobKills() + main + " Deaths: " + sec + d.getDeaths(), - ball + " Geolocation: " + sec + d.getGeolocation() + sec + " " + Phrase.BALL + (banned ? ChatColor.DARK_RED + " Banned" : ter + (active ? " Active" : " Inactive")) + (online ? ChatColor.GREEN + " Online" : ChatColor.RED + " Offline"), + ball + " Registered: " + sec + FormatUtils.formatTimeStampYear(d.getRegistered()), + ball + " Last seen: " + sec + FormatUtils.formatTimeStamp(d.getLastPlayed()), + ball + " Playtime: " + sec + FormatUtils.formatTimeAmount(d.getPlayTime()), + ball + " Login times: " + sec + d.getLoginTimes(), + ball + " Average session length: " + sec + FormatUtils.formatTimeAmount(MathUtils.averageLong(AnalysisUtils.transformSessionDataToLengths(d.getSessions()))), + ball + " Kills: " + sec + d.getPlayerKills().size() + main + " Mobs: " + sec + d.getMobKills() + main + " Deaths: " + sec + d.getDeaths(), + ball + " Geolocation: " + sec + d.getGeolocation() }; } /** - * * @return */ public static String[] getAnalysisMessages() { @@ -72,21 +76,21 @@ public class TextUI { final PlayerCountPart count = d.getPlayerCountPart(); final TPSPart tps = d.getTpsPart(); return new String[]{ - ball + " Total Players: " + sec + count.getPlayerCount(), - // - ball + " Active: " + sec + activity.getActive().size() - + main + " Inactive: " + sec + activity.getInactive().size() - + main + " Single Join: " + sec + activity.getJoinedOnce().size() - + main + " Banned: " + sec + activity.getBans().size(), - // - ball + " New Players 24h: " + sec + join.get("npday") + main + " 7d: " + sec + d.get("npweek") + main + " 30d: " + sec + d.get("npmonth"), - "", - ball + " Total Playtime: " + sec + playtime.get("totalplaytime") + main + " Player Avg: " + sec + playtime.get("avgplaytime"), - ball + " Average Session Length: " + sec + activity.get("sessionaverage"), - ball + " Total Logintimes: " + sec + join.getLoginTimes(), - ball + " Kills: " + sec + kills.getAllPlayerKills().size() + main + " Mobs: " + sec + kills.getMobKills() + main + " Deaths: " + sec + kills.getDeaths(), - "", - ball + " Average TPS 24h: " + sec + tps.get("averagetpsday") + ball + " Total Players: " + sec + count.getPlayerCount(), + // + ball + " Active: " + sec + activity.getActive().size() + + main + " Inactive: " + sec + activity.getInactive().size() + + main + " Single Join: " + sec + activity.getJoinedOnce().size() + + main + " Banned: " + sec + activity.getBans().size(), + // + ball + " New Players 24h: " + sec + join.get("npday") + main + " 7d: " + sec + d.get("npweek") + main + " 30d: " + sec + d.get("npmonth"), + "", + ball + " Total Playtime: " + sec + playtime.get("totalplaytime") + main + " Player Avg: " + sec + playtime.get("avgplaytime"), + ball + " Average Session Length: " + sec + activity.get("sessionaverage"), + ball + " Total Logintimes: " + sec + join.getLoginTimes(), + ball + " Kills: " + sec + kills.getAllPlayerKills().size() + main + " Mobs: " + sec + kills.getMobKills() + main + " Deaths: " + sec + kills.getDeaths(), + "", + ball + " Average TPS 24h: " + sec + tps.get("averagetpsday") }; } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java index be42d1d0e..31686ec47 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java @@ -138,4 +138,13 @@ public class Request implements Closeable { public void close() throws IOException { close.close(); } + + @Override + public String toString() { + return "Request{" + + "request='" + request + '\'' + + ", target='" + target + '\'' + + ", authorization='" + authorization + '\'' + + '}'; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebServer.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebServer.java new file mode 100644 index 000000000..b1ab4dc6e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebServer.java @@ -0,0 +1,399 @@ +package main.java.com.djrapitops.plan.ui.webserver; + +import com.djrapitops.plugin.utilities.Verify; +import com.sun.net.httpserver.*; +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.data.WebUser; +import main.java.com.djrapitops.plan.data.cache.PageCacheHandler; +import main.java.com.djrapitops.plan.database.tables.SecurityTable; +import main.java.com.djrapitops.plan.ui.html.DataRequestHandler; +import main.java.com.djrapitops.plan.ui.webserver.response.*; +import main.java.com.djrapitops.plan.utilities.HtmlUtils; +import main.java.com.djrapitops.plan.utilities.PassEncryptUtil; +import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility; +import org.bukkit.ChatColor; + +import javax.net.ssl.*; +import java.io.*; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.file.Paths; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Base64; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @author Rsl1122 + */ +public class WebServer { + + private final Plan plugin; + private final DataRequestHandler dataReqHandler; + private boolean enabled = false; + private HttpServer server; + private final int port; + + private boolean usingHttps; + + /** + * Class Constructor. + *

+ * Initializes DataRequestHandler + * + * @param plugin Current instance of Plan + */ + public WebServer(Plan plugin) { + this.plugin = plugin; + this.port = Settings.WEBSERVER_PORT.getNumber(); + dataReqHandler = new DataRequestHandler(plugin); + } + + /** + * Starts up the Webserver in a Asynchronous thread. + */ + public void initServer() { + //Server is already enabled stop code + if (enabled) { + return; + } + Log.info(Phrase.WEBSERVER_INIT.toString()); + try { + usingHttps = startHttpsServer(); + + Log.debug(usingHttps ? "Https Start Successful." : "Https Start Failed."); + + if (!usingHttps) { + Log.infoColor(ChatColor.YELLOW + "User Authorization Disabled! (Not possible over http)"); + server = HttpServer.create(new InetSocketAddress(port), 10); + } + + server.createContext("/", new HttpHandler() { + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + URI uri = exchange.getRequestURI(); + String target = uri.toString(); + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/html;"); + WebUser user = null; + if (usingHttps) { + user = getUser(exchange.getRequestHeaders()); + + // Prompt authorization + if (user == null) { + + responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\";"); + } + } + Response response = getResponse(target, user); + + String content = response.getContent(); + exchange.sendResponseHeaders(response.getCode(), 0); + + try (BufferedOutputStream out = new BufferedOutputStream(exchange.getResponseBody()); + ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes())) { + byte[] buffer = new byte[2048]; + int count; + while ((count = bis.read(buffer)) != -1) { + out.write(buffer, 0, count); + } + } + } catch (Exception e) { + Log.toLog(this.getClass().getName(), e); + throw e; + } finally { + exchange.close(); + } + } + }); + server.setExecutor(new ThreadPoolExecutor(4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100))); + server.start(); + + enabled = true; + + Log.info(Phrase.WEBSERVER_RUNNING.parse(String.valueOf(server.getAddress().getPort()))); + } catch (IllegalArgumentException | IllegalStateException | IOException e) { + Log.toLog(this.getClass().getName(), e); + enabled = false; + } + } + + private WebUser getUser(Headers requestHeaders) { + try { + List authorization = requestHeaders.get("Authorization"); + if (Verify.isEmpty(authorization)) { + return null; + } + String auth = authorization.get(0); + if (auth.contains("Basic ")) { + auth = auth.split(" ")[1]; + } else { + throw new IllegalArgumentException("Wrong format of Auth"); + } + Base64.Decoder decoder = Base64.getDecoder(); + byte[] decoded = decoder.decode(auth); + String[] userInfo = new String(decoded).split(":"); + if (userInfo.length != 2) { + throw new IllegalArgumentException("User and Password not specified"); + } + String user = userInfo[0]; + String passwordRaw = userInfo[1]; + + SecurityTable securityTable = plugin.getDB().getSecurityTable(); + if (!securityTable.userExists(user)) { + throw new IllegalArgumentException("User Doesn't exist"); + } + + WebUser webUser = securityTable.getSecurityInfo(user); + + boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, webUser.getSaltedPassHash()); + if (!correctPass) { + throw new IllegalArgumentException("User and Password do not match"); + } + return webUser; + } catch (IllegalArgumentException e) { + Log.debug("WebServer: " + e.getMessage()); + return null; + } catch (Exception e) { + Log.toLog(this.getClass().getName(), e); + return null; + } + } + + private boolean startHttpsServer() throws IOException { + String keyStorePath = Settings.WEBSERVER_CERTIFICATE_PATH.toString(); + if (!Paths.get(keyStorePath).isAbsolute()) { + keyStorePath = plugin.getDataFolder() + File.separator + keyStorePath; + } + char[] storepass = Settings.WEBSERVER_CERTIFICATE_STOREPASS.toString().toCharArray(); + char[] keypass = Settings.WEBSERVER_CERTIFICATE_KEYPASS.toString().toCharArray(); + String alias = Settings.WEBSERVER_CERTIFICATE_ALIAS.toString(); + + boolean startSuccessful = false; + try (FileInputStream fIn = new FileInputStream(keyStorePath)) { + KeyStore keystore = KeyStore.getInstance("JKS"); + + keystore.load(fIn, storepass); + Certificate cert = keystore.getCertificate(alias); + + Log.info("Found Certificate: " + cert.getType()); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); + keyManagerFactory.init(keystore, keypass); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); + trustManagerFactory.init(keystore); + + server = HttpsServer.create(new InetSocketAddress(port), 10); + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(keyManagerFactory.getKeyManagers(), null/*trustManagerFactory.getTrustManagers()*/, null); + + ((HttpsServer) server).setHttpsConfigurator(new HttpsConfigurator(sslContext) { + @Override + public void configure(HttpsParameters params) { + SSLEngine engine = sslContext.createSSLEngine(); + + params.setNeedClientAuth(false); + params.setCipherSuites(engine.getEnabledCipherSuites()); + params.setProtocols(engine.getEnabledProtocols()); + + SSLParameters defaultSSLParameters = sslContext.getDefaultSSLParameters(); + params.setSSLParameters(defaultSSLParameters); + } + }); + startSuccessful = true; + } catch (KeyManagementException | NoSuchAlgorithmException e) { + Log.error("WebServer: SSL Context Initialization Failed."); + Log.toLog(this.getClass().getName(), e); + } catch (FileNotFoundException e) { + Log.infoColor(ChatColor.YELLOW + "WebServer: SSL Certificate KeyStore File not Found: " + keyStorePath); + Log.info("No Certificate -> Using Http server for Visualization."); + } catch (IOException e) { + Log.error("WebServer: " + e); + Log.toLog(this.getClass().getName(), e); + } catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) { + Log.error("WebServer: SSL Certificate loading Failed."); + Log.toLog(this.getClass().getName(), e); + } + return startSuccessful; + } + + private Response getResponse(String target, WebUser user) { + if ("/favicon.ico".equals(target)) { + return PageCacheHandler.loadPage("Redirect: favicon", () -> new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico")); + } + if (usingHttps) { + if (user == null) { + return PageCacheHandler.loadPage("promptAuthorization", PromptAuthorizationResponse::new); + } + + int permLevel = user.getPermLevel(); // Lower number has higher clearance. + int required = getRequiredPermLevel(target, user.getName()); + if (permLevel > required) { + return forbiddenResponse(permLevel, required); + } + } + String[] args = target.split("/"); + if (args.length < 2) { + return rootPageResponse(user); + } + + String page = args[1]; + switch (page) { + case "players": + return PageCacheHandler.loadPage("players", () -> new PlayersPageResponse(plugin)); + case "player": + return playerResponse(args); + case "server": + return serverResponse(); + default: + return notFoundResponse(); + } + } + + private Response forbiddenResponse(int permLevel, int required) { + return PageCacheHandler.loadPage("forbidden", () -> { + ForbiddenResponse response403 = new ForbiddenResponse(); + String content = "

403 Forbidden - Access Denied

" + + "

Unauthorized User.
" + + "Make sure your user has the correct access level.
" + + "This page requires permission level of " + String.valueOf(required) + ",
" + + "This user has permission level of " + String.valueOf(permLevel) + "

"; + response403.setContent(content); + return response403; + }); + } + + private Response rootPageResponse(WebUser user) { + if (user == null) { + return notFoundResponse(); + } + switch (user.getPermLevel()) { + case 0: + return serverResponse(); + case 1: + return PageCacheHandler.loadPage("players", () -> new PlayersPageResponse(plugin)); + case 2: + return playerResponse(new String[]{"", "", user.getName()}); + default: + return forbiddenResponse(user.getPermLevel(), 0); + } + } + + private Response serverResponse() { + if (!dataReqHandler.checkIfAnalysisIsCached()) { + String error = "Analysis Data was not cached.
Use /plan analyze to cache the Data."; + PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error)); + } + + return PageCacheHandler.loadPage("analysisPage", () -> new AnalysisPageResponse(dataReqHandler)); + } + + private Response playerResponse(String[] args) { + if (args.length < 3) { + return PageCacheHandler.loadPage("notFound", NotFoundResponse::new); + } + + String playerName = args[2].trim(); + UUID uuid = UUIDUtility.getUUIDOf(playerName); + + if (uuid == null) { + String error = "Player has no UUID"; + return PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error)); + } + + if (!dataReqHandler.checkIfCached(uuid)) { + String error = "Player's data was not cached.
Use /plan inspect " + playerName + " to cache the Data."; + return PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error)); + } + + return PageCacheHandler.loadPage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(dataReqHandler, uuid)); + } + + private Response notFoundResponse() { + String error = "

404 Not Found

" + + "

Make sure you're accessing a link given by a command, Examples:

" + + "

" + getProtocol() + HtmlUtils.getInspectUrl("") + " or
" + + getProtocol() + HtmlUtils.getServerAnalysisUrl() + "

"; + + return PageCacheHandler.loadPage("notFound: " + error, () -> { + Response response404 = new NotFoundResponse(); + response404.setContent(error); + return response404; + }); + } + + /** + * @return + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Shuts down the server - Async thread is closed with shutdown boolean. + */ + public void stop() { + Log.info(Phrase.WEBSERVER_CLOSE.toString()); + if (server != null) { + server.stop(0); + } + } + + /** + * Used to get the handler for Html content requests. + * + * @return DataRequestHandler used by the WebServer. + */ + public DataRequestHandler getDataReqHandler() { + return dataReqHandler; + } + + private int getRequiredPermLevel(String target, String user) { + String[] t = target.split("/"); + if (t.length < 2) { + return 100; + } + if (t.length > 3) { + return 0; + } + String page = t[1]; + switch (page) { + case "players": + return 1; + case "player": + // /player/ - 404 for perm lvl 1 + if (t.length < 3) { + return 1; + } + + final String wantedUser = t[2].toLowerCase().trim(); + final String theUser = user.trim().toLowerCase(); + + return wantedUser.equals(theUser) ? 2 : 1; + default: + return 0; + } + } + + public String getProtocol() { + return usingHttps ? "https" : "http"; + } + + public boolean usingHttps() { + return usingHttps; + } + + public boolean isAuthRequired() { + return usingHttps; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java deleted file mode 100644 index d0e13be2f..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java +++ /dev/null @@ -1,279 +0,0 @@ -package main.java.com.djrapitops.plan.ui.webserver; - -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.utilities.Verify; -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.data.WebUser; -import main.java.com.djrapitops.plan.database.tables.SecurityTable; -import main.java.com.djrapitops.plan.ui.html.DataRequestHandler; -import main.java.com.djrapitops.plan.ui.webserver.response.*; -import main.java.com.djrapitops.plan.utilities.Benchmark; -import main.java.com.djrapitops.plan.utilities.HtmlUtils; -import main.java.com.djrapitops.plan.utilities.MiscUtils; -import main.java.com.djrapitops.plan.utilities.PassEncryptUtil; -import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.sql.SQLException; -import java.util.Base64; -import java.util.UUID; - -/** - * - * @author Rsl1122 - */ -public class WebSocketServer { - - private final int PORT; - private boolean enabled = false; - private Socket sslServer; - private ServerSocket server; - - private final Plan plugin; - private final DataRequestHandler dataReqHandler; - - private boolean shutdown; - - /** - * Class Constructor. - * - * Initializes DataRequestHandler - * - * @param plugin Current instance of Plan - */ - public WebSocketServer(Plan plugin) { - this.plugin = plugin; - this.PORT = Settings.WEBSERVER_PORT.getNumber(); - shutdown = false; - dataReqHandler = new DataRequestHandler(plugin); - } - - /** - * Starts up the Webserver in a Asynchronous thread. - */ - public void initServer() { - //Server is already enabled stop code - if (enabled) { - return; - } - Log.info(Phrase.WEBSERVER_INIT.toString()); - try { - InetAddress ip = InetAddress.getByName(Settings.WEBSERVER_IP.toString()); -// SSLServerSocketFactory ssl = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); -// server = ssl.createServerSocket(PORT, 1, ip); - server = new ServerSocket(PORT, 1, ip); - - plugin.getRunnableFactory().createNew(new AbsRunnable("WebServerTask") { - @Override - public void run() { - while (!shutdown) { - /*SSL*/Socket socket = null; - InputStream input = null; - OutputStream output = null; - Request request = null; - try { - socket = /*(SSLSocket)*/ server.accept(); - Log.debug("New Socket Connection: " + socket.getInetAddress()); - input = socket.getInputStream(); - output = socket.getOutputStream(); - request = new Request(input); - Benchmark.start("Webserver Response"); - request.parse(); - Response response = getResponse(request, output); - Log.debug("Parsed response: " + response.getClass().getSimpleName()); - response.sendStaticResource(); - } catch (IOException | IllegalArgumentException e) { - } finally { - MiscUtils.close(input, request, output, socket); - Benchmark.stop("Webserver Response"); - } - } - this.cancel(); - } - }).runTaskAsynchronously(); - - enabled = true; - - Log.info(Phrase.WEBSERVER_RUNNING.parse(server.getLocalPort() + "")); - } catch (IllegalArgumentException | IllegalStateException | IOException e) { - Log.toLog(this.getClass().getName(), e); - enabled = false; - } - } - - // Used for deciding the Response appropriate for the Request. - private Response getResponse(Request request, OutputStream output) { - try { - Verify.nullCheck(request); - Verify.nullCheck(output); - - if (isFaviconRequest(request)) { - return new RedirectResponse(output, "https://puu.sh/tK0KL/6aa2ba141b.ico"); - } - -// if (!request.hasAuthorization()) { -// return new PromptAuthorizationResponse(output); -// } -// try { -// if (!isAuthorized(request)) { -// ForbiddenResponse response403 = new ForbiddenResponse(output); -// String content = "

403 Forbidden - Access Denied

" -// + "

Unauthorized User.
" -// + "Make sure your user has the correct access level.
" -// + "You can use /plan web check to check the permission level.

"; -// response403.setContent(content); -// return response403; -// } -// } catch (IllegalArgumentException e) { -// return new PromptAuthorizationResponse(output); -// } - String req = request.getRequest(); - String target = request.getTarget(); - if (!req.equals("GET") || target.equals("/")) { - return responseNotFound(output); - } - String[] args = target.split("/"); - if (args.length < 2) { - return responseNotFound(output); - } - String page = args[1]; - switch (page) { - case "players": - return new PlayersPageResponse(output, plugin); - case "player": - return playerResponse(args, output); - case "server": - return serverResponse(output); - default: - return responseNotFound(output); - } - } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); - return new InternalErrorResponse(output, e, request.getTarget()); - } - } - - private Response serverResponse(OutputStream output) { - if (!dataReqHandler.checkIfAnalysisIsCached()) { - return new NotFoundResponse(output, "Analysis data was not cached."); - } - return new AnalysisPageResponse(output, dataReqHandler); - } - - private Response playerResponse(String[] args, OutputStream output) { - if (args.length < 3) { - return new NotFoundResponse(output); - } - String playerName = args[2].trim(); - UUID uuid = UUIDUtility.getUUIDOf(playerName); - if (uuid == null) { - return new NotFoundResponse(output, "Player has no UUID"); - } - if (!dataReqHandler.checkIfCached(uuid)) { - return new NotFoundResponse(output, "Player's data was not cached."); - } - return new InspectPageResponse(output, dataReqHandler, uuid); - } - - private Response responseNotFound(OutputStream output) { - NotFoundResponse response404 = new NotFoundResponse(output); - String content = "

404 Not Found

" - + "

Make sure you're accessing a link given by a command, Examples:

" - + "

" + HtmlUtils.getInspectUrl("") + " or
" - + HtmlUtils.getServerAnalysisUrl() + "

"; - response404.setContent(content); - return response404; - } - - /** - * - * @return - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Shuts down the server - Async thread is closed with shutdown boolean. - */ - public void stop() { - Log.info(Phrase.WEBSERVER_CLOSE.toString()); - shutdown = true; - try { - if (server != null) { - server.close(); - } - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - } - - /** - * @return DataRequestHandler used by the WebServer. - */ - public DataRequestHandler getDataReqHandler() { - return dataReqHandler; - } - - private boolean isAuthorized(Request request) throws IllegalArgumentException, PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException, SQLException { - Base64.Decoder decoder = Base64.getDecoder(); - String auth = request.getAuthorization(); - byte[] decoded = decoder.decode(auth); - String[] userInfo = new String(decoded).split(":"); - if (userInfo.length != 2) { - throw new IllegalArgumentException("User and Password not specified"); - } - String user = userInfo[0]; - SecurityTable securityTable = plugin.getDB().getSecurityTable(); - if (!securityTable.userExists(user)) { - throw new IllegalArgumentException("User Doesn't exist"); - } - WebUser securityInfo = securityTable.getSecurityInfo(user); - String passwordRaw = userInfo[1]; - boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, securityInfo.getSaltedPassHash()); - if (!correctPass) { - throw new IllegalArgumentException("User and Password do not match"); - } - int permLevel = securityInfo.getPermLevel(); // Lower number has higher clearance. - int required = getRequiredPermLevel(request, securityInfo.getName()); - return permLevel <= required; - } - - private int getRequiredPermLevel(Request request, String user) { - String target = request.getTarget(); - String[] t = target.split("/"); - if (t.length < 3) { - return 0; - } - final String wantedUser = t[2].toLowerCase().trim(); - final String theUser = user.trim().toLowerCase(); - if (t[1].equals("players")) { - return 1; - } - if (t[1].equals("player")) { - if (wantedUser.equals(theUser)) { - return 2; - } else { - return 1; - } - } - return 0; - } - - private boolean isFaviconRequest(Request request) { - String[] args = request.getTarget().split("/"); - if (args.length < 2 || args.length > 2) { - return false; - } - String page = args[1]; - return page.equals("favicon.ico"); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/AnalysisPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/AnalysisPageResponse.java index 6c4c77b1a..54dd1e146 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/AnalysisPageResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/AnalysisPageResponse.java @@ -1,17 +1,14 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; import main.java.com.djrapitops.plan.ui.html.DataRequestHandler; /** - * * @author Rsl1122 * @since 3.5.2 */ public class AnalysisPageResponse extends Response { - public AnalysisPageResponse(OutputStream output, DataRequestHandler h) { - super(output); + public AnalysisPageResponse(DataRequestHandler h) { super.setHeader("HTTP/1.1 200 OK"); super.setContent(h.getAnalysisHtml()); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/ForbiddenResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/ForbiddenResponse.java index d8a633c85..001870539 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/ForbiddenResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/ForbiddenResponse.java @@ -1,16 +1,12 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; - /** - * * @author Rsl1122 * @since 3.5.2 */ public class ForbiddenResponse extends Response { - public ForbiddenResponse(OutputStream output) { - super(output); + public ForbiddenResponse() { super.setHeader("HTTP/1.1 403 Forbidden"); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InspectPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InspectPageResponse.java index 2c46df017..ea5a94580 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InspectPageResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InspectPageResponse.java @@ -1,18 +1,16 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; -import java.util.UUID; import main.java.com.djrapitops.plan.ui.html.DataRequestHandler; +import java.util.UUID; + /** - * * @author Rsl1122 * @since 3.5.2 */ public class InspectPageResponse extends Response { - public InspectPageResponse(OutputStream output, DataRequestHandler h, UUID uuid) { - super(output); + public InspectPageResponse(DataRequestHandler h, UUID uuid) { super.setHeader("HTTP/1.1 200 OK"); super.setContent(h.getInspectHtml(uuid)); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InternalErrorResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InternalErrorResponse.java index 9157e08c6..6585692d8 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InternalErrorResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/InternalErrorResponse.java @@ -1,17 +1,14 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; import main.java.com.djrapitops.plan.ui.html.Html; /** - * * @author Rsl1122 * @since 3.5.2 */ public class InternalErrorResponse extends Response { - public InternalErrorResponse(OutputStream output, Throwable e, String cause) { - super(output); + public InternalErrorResponse(Throwable e, String cause) { super.setHeader("HTTP/1.1 500 Internal Error"); StringBuilder content = new StringBuilder(); content.append("

500 Internal Error occurred

"); diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/JavaScriptResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/JavaScriptResponse.java new file mode 100644 index 000000000..acb972ecc --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/JavaScriptResponse.java @@ -0,0 +1,23 @@ +package main.java.com.djrapitops.plan.ui.webserver.response; + +import main.java.com.djrapitops.plan.Log; +import main.java.com.djrapitops.plan.utilities.HtmlUtils; + +import java.io.FileNotFoundException; + +/** + * @author Rsl1122 + * @since 3.5.2 + */ +public class JavaScriptResponse extends Response { + + public JavaScriptResponse(String resource) { + super.setHeader("HTTP/1.1 200 OK"); + try { + super.setContent(HtmlUtils.getStringFromResource(resource)); + } catch (FileNotFoundException e) { + Log.toLog(this.getClass().getName(), e); + super.setContent(""); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/NotFoundResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/NotFoundResponse.java index 751b4a612..aef95ec37 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/NotFoundResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/NotFoundResponse.java @@ -1,22 +1,17 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; - /** - * * @author Rsl1122 * @since 3.5.2 */ public class NotFoundResponse extends Response { - public NotFoundResponse(OutputStream output) { - super(output); + public NotFoundResponse() { super.setHeader("HTTP/1.1 404 Not Found"); super.setContent("

404 Not Found

Page does not exist.

"); } - public NotFoundResponse(OutputStream output, String msg) { - super(output); + public NotFoundResponse(String msg) { super.setHeader("HTTP/1.1 404 Not Found"); super.setContent("

404 Not Found

" + msg + "

"); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PlayersPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PlayersPageResponse.java index 15a640c1d..0cfd72c31 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PlayersPageResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PlayersPageResponse.java @@ -6,27 +6,24 @@ import main.java.com.djrapitops.plan.ui.html.Html; import main.java.com.djrapitops.plan.utilities.HtmlUtils; import main.java.com.djrapitops.plan.utilities.comparators.UserDataNameComparator; -import java.io.OutputStream; import java.util.List; /** - * * @author Rsl1122 * @since 3.5.2 */ public class PlayersPageResponse extends Response { - public PlayersPageResponse(OutputStream output, Plan plugin) { - super(output); + public PlayersPageResponse(Plan plugin) { super.setHeader("HTTP/1.1 200 OK"); super.setContent(buildContent(plugin.getInspectCache().getCachedUserData())); } public static String buildContent(List cached) { - StringBuilder html = new StringBuilder(); + StringBuilder html = new StringBuilder("

Cached Players

"); + int size = cached.size(); - html.append("

Cached Players

") - .append(size) + html.append(size) .append(" players. Use browser's Search to find players by name. (Chrome Ctrl+F)

"); cached.sort(new UserDataNameComparator()); int i = 1; @@ -34,14 +31,13 @@ public class PlayersPageResponse extends Response { String name = userData.getName(); String link = Html.LINK.parse(HtmlUtils.getRelativeInspectUrl(name), name); html.append(""); - if (i < size) { - if (i % 8 == 0) { - html.append(""); - } + if (i < size + && i % 8 == 0) { + html.append(""); } i++; } - html.append("
").append(link).append("
"); + html.append(""); return html.toString(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PromptAuthorizationResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PromptAuthorizationResponse.java index 6150255d0..293334866 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PromptAuthorizationResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/PromptAuthorizationResponse.java @@ -1,18 +1,14 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; - /** - * * @author Rsl1122 * @since 3.5.2 */ public class PromptAuthorizationResponse extends Response { - public PromptAuthorizationResponse(OutputStream output) { - super(output); + public PromptAuthorizationResponse() { super.setHeader("HTTP/1.1 401 Access Denied\r\n" - + "WWW-Authenticate: Basic realm=\"Analysis\";"); + + "WWW-Authenticate: Basic realm=\"/\";"); super.setContent("

401 Unauthorized

Authentication Failed.
" + "- Ensure you have registered a user with /plan register
" + "- Check that the username and password are correct
" diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/RedirectResponse.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/RedirectResponse.java index b25b8f3b1..4541f3ff1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/RedirectResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/RedirectResponse.java @@ -1,16 +1,12 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.OutputStream; - /** - * * @author Rsl1122 * @since 3.5.2 */ public class RedirectResponse extends Response { - public RedirectResponse(OutputStream output, String direct) { - super(output); + public RedirectResponse(String direct) { super.setHeader("HTTP/1.1 302 Found"); super.setContent("Location: " + direct); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java index 6002654ba..398da0bbe 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java @@ -1,43 +1,30 @@ package main.java.com.djrapitops.plan.ui.webserver.response; -import java.io.IOException; -import java.io.OutputStream; - /** - * * @author Rsl1122 * @since 3.5.2 */ public abstract class Response { - private final OutputStream output; - private String header; private String content; /** * Class Constructor. - * - * @param output Website OutputStream to write the response to. */ - public Response(OutputStream output) { - this.output = output; + public Response() { } - /** - * Writes the HTML to the OutputStream according to the requested page. - * - * @throws IOException - */ - public void sendStaticResource() throws IOException { - String response = header + "\r\n" + public String getResponse() { + return header + "\r\n" + "Content-Type: text/html;\r\n" + "Content-Length: " + content.length() + "\r\n" + "\r\n" + content; -// Log.debug("Response: " + response); // Responses should not be logged, html content large. - output.write(response.getBytes()); - output.flush(); + } + + public String getContent() { + return content; } public void setHeader(String header) { @@ -47,4 +34,8 @@ public abstract class Response { public void setContent(String content) { this.content = content; } + + public int getCode() { + return header == null ? 500 : Integer.parseInt(header.split(" ")[1]); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/Benchmark.java b/Plan/src/main/java/com/djrapitops/plan/utilities/Benchmark.java index db4f2f79b..a3238eacc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/Benchmark.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/Benchmark.java @@ -4,13 +4,18 @@ import main.java.com.djrapitops.plan.Log; import main.java.com.djrapitops.plan.Plan; /** - * * @author Rsl1122 */ public class Benchmark { /** - * + * Constructor used to hide the public constructor + */ + private Benchmark() { + throw new IllegalStateException("Utility class"); + } + + /** * @param source */ public static void start(String source) { @@ -19,7 +24,6 @@ public class Benchmark { } /** - * * @param source * @return */ diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/Check.java b/Plan/src/main/java/com/djrapitops/plan/utilities/Check.java index 2bcbbc792..4f093f0bf 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/Check.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/Check.java @@ -11,11 +11,18 @@ import main.java.com.djrapitops.plan.Log; */ public class Check { + /** + * Constructor used to hide the public constructor + */ + private Check() { + throw new IllegalStateException("Utility class"); + } + /** * If check is false, send message. * * @param condition Condition. - * @param message Message to send if Condition is false + * @param message Message to send if Condition is false * @return Condition */ public static boolean isTrue(boolean condition, String message) { @@ -29,8 +36,8 @@ public class Check { * If check is false, send message to sender. * * @param condition Condition. - * @param message Message to send if Condition is false - * @param sender Sender to send message to + * @param message Message to send if Condition is false + * @param sender Sender to send message to * @return Condition */ public static boolean isTrue(boolean condition, String message, ISender sender) { @@ -44,10 +51,10 @@ public class Check { * If check is false, send error message. * * @param condition Condition. - * @param message Message to send if Condition is false + * @param message Message to send if Condition is false * @return Condition */ - public static boolean isTrue_Error(boolean condition, String message) { + public static boolean ErrorIfFalse(boolean condition, String message) { if (!condition) { Log.error(message); Log.toLog(message, Log.getErrorsFilename()); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java index 780cb8950..aeac55a84 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java @@ -8,13 +8,20 @@ import org.bukkit.Location; import java.text.DecimalFormat; /** - * * @author Rsl1122 */ public class FormatUtils { + private static final DecimalFormat df = new DecimalFormat(Settings.FORMAT_DECIMALS.toString()); + + /** + * Constructor used to hide the public constructor + */ + private FormatUtils() { + throw new IllegalStateException("Utility class"); + } + /** - * * @param ms * @return */ @@ -23,7 +30,6 @@ public class FormatUtils { } /** - * * @param before * @param after * @return @@ -33,7 +39,6 @@ public class FormatUtils { } /** - * * @param epochMs * @return */ @@ -42,7 +47,6 @@ public class FormatUtils { } /** - * * @param epochMs * @return */ @@ -51,7 +55,6 @@ public class FormatUtils { } /** - * * @param epochMs * @return */ @@ -74,7 +77,6 @@ public class FormatUtils { } /** - * * @param dataPoint * @return */ @@ -103,33 +105,33 @@ public class FormatUtils { if (years == 1) { builder.append(Settings.FORMAT_YEAR.toString()); } else { - builder.append(Settings.FORMAT_YEARS.toString().replace("%years%", "" + years)); + builder.append(Settings.FORMAT_YEARS.toString().replace("%years%", String.valueOf(years))); } } if (days != 0) { if (days == 1) { builder.append(Settings.FORMAT_DAY.toString()); } else { - builder.append(Settings.FORMAT_DAYS.toString().replace("%days%", "" + days)); + builder.append(Settings.FORMAT_DAYS.toString().replace("%days%", String.valueOf(days))); } } if (hours != 0) { - String h = Settings.FORMAT_HOURS.toString().replace("%hours%", "" + hours); - if (h.contains("%zero%") && (hours + "").length() == 1) { + String h = Settings.FORMAT_HOURS.toString().replace("%hours%", String.valueOf(hours)); + if (h.contains("%zero%") && String.valueOf(hours).length() == 1) { builder.append('0'); } builder.append(h); } if (minutes != 0) { - String m = Settings.FORMAT_MINUTES.toString().replace("%minutes%", "" + minutes); - if (m.contains("%zero%") && (minutes + "").length() == 1) { + String m = Settings.FORMAT_MINUTES.toString().replace("%minutes%", String.valueOf(minutes)); + if (m.contains("%zero%") && String.valueOf(minutes).length() == 1) { builder.append('0'); } builder.append(m); } if (seconds != 0) { - String s = Settings.FORMAT_SECONDS.toString().replace("%seconds%", "" + seconds); - if (s.contains("%zero%") && (seconds + "").length() == 1) { + String s = Settings.FORMAT_SECONDS.toString().replace("%seconds%", String.valueOf(seconds)); + if (s.contains("%zero%") && String.valueOf(seconds).length() == 1) { builder.append('0'); } builder.append(s); @@ -173,13 +175,10 @@ public class FormatUtils { } /** - * * @param d * @return */ public static String cutDecimals(double d) { - DecimalFormat df = new DecimalFormat(Settings.FORMAT_DECIMALS.toString()); -// df.setRoundingMode(RoundingMode.CEILING); return df.format(d); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/HtmlUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/HtmlUtils.java index 6aab0ac0c..7ffbcb80f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/HtmlUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/HtmlUtils.java @@ -3,6 +3,7 @@ package main.java.com.djrapitops.plan.utilities; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.ui.html.Html; +import main.java.com.djrapitops.plan.ui.webserver.WebServer; import java.io.File; import java.io.FileNotFoundException; @@ -12,18 +13,23 @@ import java.util.Map; import java.util.Scanner; /** - * * @author Rsl1122 */ public class HtmlUtils { /** - * + * Constructor used to hide the public constructor + */ + private HtmlUtils() { + throw new IllegalStateException("Utility class"); + } + + /** * @param fileName * @return * @throws FileNotFoundException */ - public static String getHtmlStringFromResource(String fileName) throws FileNotFoundException { + public static String getStringFromResource(String fileName) throws FileNotFoundException { InputStream resourceStream = null; Scanner scanner = null; try { @@ -49,61 +55,71 @@ public class HtmlUtils { } /** - * * @param html * @param replaceMap * @return */ public static String replacePlaceholders(String html, Map replaceMap) { - for (String key : replaceMap.keySet()) { - html = html.replace(key, replaceMap.get(key)); + for (Map.Entry entrySet : replaceMap.entrySet()) { + String placeholder = entrySet.getKey(); + String replacer = entrySet.getValue(); + + html = html.replace(placeholder, replacer); } + return html; } /** - * * @return */ public static String getServerAnalysisUrlWithProtocol() { - return Settings.LINK_PROTOCOL.toString() + ":" + getServerAnalysisUrl(); + return getProtocol() + ":" + getServerAnalysisUrl(); } /** - * * @return */ public static String getServerAnalysisUrl() { - int port = Settings.WEBSERVER_PORT.getNumber(); - String ip = Plan.getInstance().getVariable().getIp() + ":" + port; - boolean useAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue(); - if (useAlternativeIP) { - ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", "" + port); - } + String ip = getIP(); return "//" + ip + "/server"; } /** + * Used to get the WebServer's IP with Port. * + * @return For example 127.0.0.1:8804 + */ + public static String getIP() { + int port = Settings.WEBSERVER_PORT.getNumber(); + String ip; + if (Settings.SHOW_ALTERNATIVE_IP.isTrue()) { + ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", String.valueOf(port)); + } else { + ip = Plan.getInstance().getVariable().getIp() + ":" + port; + } + return ip; + } + + private static String getProtocol() { + WebServer uiServer = Plan.getInstance().getUiServer(); + return uiServer.isEnabled() ? uiServer.getProtocol() : Settings.LINK_PROTOCOL.toString(); + } + + /** * @param playerName * @return */ public static String getInspectUrlWithProtocol(String playerName) { - return Settings.LINK_PROTOCOL.toString() + ":" + getInspectUrl(playerName); + return getProtocol() + ":" + getInspectUrl(playerName); } /** - * * @param playerName * @return */ public static String getInspectUrl(String playerName) { - int port = Settings.WEBSERVER_PORT.getNumber(); - String ip = Plan.getInstance().getVariable().getIp() + ":" + port; - boolean useAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue(); - if (useAlternativeIP) { - ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", "" + port); - } + String ip = getIP(); return "//" + ip + "/player/" + playerName; } @@ -112,7 +128,6 @@ public class HtmlUtils { } /** - * * @param string * @return */ @@ -124,7 +139,6 @@ public class HtmlUtils { } /** - * * @param pluginNames * @param placeholders * @return @@ -170,22 +184,23 @@ public class HtmlUtils { } /** - * * @param string * @return */ public static String swapColorsToSpan(String string) { Html[] replacer = new Html[]{Html.COLOR_0, Html.COLOR_1, Html.COLOR_2, Html.COLOR_3, - Html.COLOR_4, Html.COLOR_5, Html.COLOR_6, Html.COLOR_7, Html.COLOR_8, Html.COLOR_9, - Html.COLOR_a, Html.COLOR_b, Html.COLOR_c, Html.COLOR_d, Html.COLOR_e, Html.COLOR_f}; + Html.COLOR_4, Html.COLOR_5, Html.COLOR_6, Html.COLOR_7, Html.COLOR_8, Html.COLOR_9, + Html.COLOR_A, Html.COLOR_B, Html.COLOR_C, Html.COLOR_D, Html.COLOR_E, Html.COLOR_F}; for (Html html : replacer) { - string = string.replace("§" + html.name().charAt(6), html.parse()); + string = string.replace("§" + Character.toLowerCase(html.name().charAt(6)), html.parse()); } + int spans = string.split(" sessions) { - return containsCombinable(sessions, 5000); - } - - private static boolean containsCombinable(List sessions, int threshold) { - // Checks if there are starts & ends that are the same, or less than threshold ms away from each other. - return sessions.stream() - .anyMatch(s -> sessions.stream() - .filter(ses -> !ses.equals(s)) - .map(SessionData::getSessionStart) - .anyMatch(start -> Math.abs(s.getSessionEnd() - start) < threshold)); - } - - /** - * - * @param sessions - * @param loginTimes - * @return - */ - public static List combineSessions(List sessions, Integer loginTimes) { - return combineSessions(sessions, loginTimes, 5000); - } - - private static List combineSessions(List sessions, Integer loginTimes, int threshold) { - if (threshold >= 35000) { - return sessions; - } - List newSessions = new ArrayList<>(); - List removed = new ArrayList<>(); - for (SessionData session : sessions) { - if (removed.contains(session)) { - continue; - } - List close = sessions.stream().filter(ses -> Math.abs(session.getSessionEnd() - ses.getSessionStart()) < threshold).collect(Collectors.toList()); - if (!close.isEmpty()) { - long big = MathUtils.getBiggestLong(close.stream().map(SessionData::getSessionEnd).collect(Collectors.toList())); - session.endSession(big); - removed.addAll(close); - } - newSessions.add(session); - } - if (loginTimes == newSessions.size()) { - return newSessions; - } - boolean containsCombinable = containsCombinable(newSessions, threshold); - if (containsCombinable) { - return combineSessions(newSessions, threshold + 1000); - } else { - return newSessions; - } - } - public static Database getDB(Plan plugin, String dbName) { Database database = null; for (Database sqldb : plugin.getDatabases()) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java index ed00c3218..52e917aa1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java @@ -3,6 +3,10 @@ package main.java.com.djrapitops.plan.utilities; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.utilities.player.Fetch; +import com.djrapitops.plugin.utilities.player.IOfflinePlayer; +import main.java.com.djrapitops.plan.Permissions; +import main.java.com.djrapitops.plan.Phrase; + import java.io.Closeable; import java.io.IOException; import java.util.Collection; @@ -10,10 +14,6 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import com.djrapitops.plugin.utilities.player.IOfflinePlayer; -import main.java.com.djrapitops.plan.Permissions; -import main.java.com.djrapitops.plan.Phrase; - /** * Utility method class containing various static methods. * @@ -22,6 +22,13 @@ import main.java.com.djrapitops.plan.Phrase; */ public class MiscUtils { + /** + * Constructor used to hide the public constructor + */ + private MiscUtils() { + throw new IllegalStateException("Utility class"); + } + /** * Used to get the current time as milliseconds. * @@ -32,7 +39,6 @@ public class MiscUtils { } /** - * * @param args * @param sender * @return @@ -44,7 +50,7 @@ public class MiscUtils { /** * Used by the inspect command. * - * @param args Arguments of a command, must not be empty if console sender. + * @param args Arguments of a command, must not be empty if console sender. * @param sender Command sender * @param perm * @return The name of the player (first argument or sender) @@ -57,7 +63,7 @@ public class MiscUtils { } else if (args.length > 0) { if (sender.hasPermission(perm.getPermission())) { playerName = args[0]; - } else if (args[0].toLowerCase().equals(sender.getName().toLowerCase())) { + } else if (args[0].equalsIgnoreCase(sender.getName())) { playerName = sender.getName(); } else { sender.sendMessage(Phrase.COMMAND_NO_PERMISSION.toString()); @@ -93,7 +99,7 @@ public class MiscUtils { if (c != null) { try { c.close(); - } catch (IOException ex) { + } catch (IOException ignored) { } } } @@ -104,7 +110,7 @@ public class MiscUtils { if (c != null) { try { c.close(); - } catch (Exception ex) { + } catch (Exception ignored) { } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/NewPlayerCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/NewPlayerCreator.java index efe12999c..2ca0b656c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/NewPlayerCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/NewPlayerCreator.java @@ -6,11 +6,17 @@ import com.djrapitops.plugin.utilities.player.IPlayer; import main.java.com.djrapitops.plan.data.UserData; /** - * * @author Rsl1122 */ public class NewPlayerCreator { + /** + * Constructor used to hide the public constructor + */ + private NewPlayerCreator() { + throw new IllegalStateException("Utility class"); + } + /** * Creates a new instance of UserData with default values. * @@ -35,18 +41,16 @@ public class NewPlayerCreator { * Creates a new instance of UserData with default values. * * @param player Player the UserData is created for. - * @param gm Gamemode set as the starting Gamemode + * @param gm Gamemode set as the starting Gamemode * @return a new UserData object */ public static UserData createNewPlayer(IOfflinePlayer player, Gamemode gm) { long registered = player.getFirstPlayed(); - UserData data = new UserData(player.getUniqueId(), registered, player.isOp(), "SURVIVAL", player.getName(), player.isOnline()); - data.setLastGamemode(gm.name()); + UserData data = new UserData(player.getUniqueId(), registered, player.isOp(), gm.name(), player.getName(), player.isOnline()); data.setLastPlayed(MiscUtils.getTime()); data.setPlayTime(0L); data.setTimesKicked(0); data.setLoginTimes(0); - data.setLastGmSwapTime(0L); data.setDeaths(0); data.setMobKills(0); data.setBanned(false); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java b/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java index 97917ff82..22dd15f51 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java @@ -9,7 +9,7 @@ import java.security.spec.InvalidKeySpecException; /** * Password Encryption utility. - * + *

* https://github.com/defuse/password-hashing/blob/master/PasswordStorage.java * * @author Defuse @@ -17,37 +17,18 @@ import java.security.spec.InvalidKeySpecException; */ public class PassEncryptUtil { - @SuppressWarnings("serial") - static public class InvalidHashException extends Exception { - - public InvalidHashException(String message) { - super(message); - } - - public InvalidHashException(String message, Throwable source) { - super(message, source); - } - } - - @SuppressWarnings("serial") - static public class CannotPerformOperationException extends Exception { - - public CannotPerformOperationException(String message) { - super(message); - } - - public CannotPerformOperationException(String message, Throwable source) { - super(message, source); - } + /** + * Constructor used to hide the public constructor + */ + private PassEncryptUtil() { + throw new IllegalStateException("Utility class"); } public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1"; - // These constants may be changed without breaking existing hashes. public static final int SALT_BYTE_SIZE = 24; public static final int HASH_BYTE_SIZE = 18; public static final int PBKDF2_ITERATIONS = 64000; - // These constants define the encoding and may not be changed. public static final int HASH_SECTIONS = 5; public static final int HASH_ALGORITHM_INDEX = 0; @@ -94,7 +75,6 @@ public class PassEncryptUtil { // Currently, Java only supports SHA1. if (!params[HASH_ALGORITHM_INDEX].equals("sha1")) { throw new CannotPerformOperationException( - "Unsupported hash type." ); } @@ -146,7 +126,7 @@ public class PassEncryptUtil { ); } - // Compute the hash of the provided password, using the same salt, + // Compute the hash of the provided password, using the same salt, // iteration count, and hash length byte[] testHash = pbkdf2(password, salt, iterations, hash.length); // Compare the hashes in constant time. The password is correct if @@ -186,4 +166,28 @@ public class PassEncryptUtil { return DatatypeConverter.printBase64Binary(array); } + @SuppressWarnings("serial") + public static class InvalidHashException extends Exception { + + InvalidHashException(String message) { + super(message); + } + + InvalidHashException(String message, Throwable source) { + super(message, source); + } + } + + @SuppressWarnings("serial") + public static class CannotPerformOperationException extends Exception { + + CannotPerformOperationException() { + super("Unsupported hash type."); + } + + CannotPerformOperationException(String message, Throwable source) { + super(message, source); + } + } + } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java index 99c0d399c..e74b4ca11 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java @@ -1,29 +1,36 @@ package main.java.com.djrapitops.plan.utilities; -import com.djrapitops.plugin.api.TimeAmount; 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.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.analysis.GamemodePart; +import main.java.com.djrapitops.plan.data.time.WorldTimes; +import main.java.com.djrapitops.plan.database.tables.GMTimesTable; import main.java.com.djrapitops.plan.ui.html.Html; import main.java.com.djrapitops.plan.ui.html.graphs.PlayerActivityGraphCreator; import main.java.com.djrapitops.plan.ui.html.graphs.PunchCardGraphCreator; import main.java.com.djrapitops.plan.ui.html.graphs.SessionLengthDistributionGraphCreator; +import main.java.com.djrapitops.plan.ui.html.graphs.WorldPieCreator; import main.java.com.djrapitops.plan.ui.html.tables.KillsTableCreator; import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils; import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; /** - * * @author Rsl1122 */ public class PlaceholderUtils { + /** + * Constructor used to hide the public constructor + */ + private PlaceholderUtils() { + throw new IllegalStateException("Utility class"); + } + /** * Gets the HashMap that is used to replace placeholders in Analysis. * @@ -31,16 +38,14 @@ public class PlaceholderUtils { * @return HashMap that contains string for each placeholder. */ public static Map getAnalysisReplaceRules(AnalysisData data) { - Benchmark.start("Replace Placeholders Anaysis"); + Benchmark.start("Replace Placeholders Analysis"); HashMap replaceMap = new HashMap<>(); replaceMap.putAll(data.getReplaceMap()); replaceMap.put("%plugins%", data.replacePluginsTabLayout()); - replaceMap.put("%currenttime%", MiscUtils.getTime() + ""); replaceMap.put("%refresh%", FormatUtils.formatTimeAmountDifference(data.getRefreshDate(), MiscUtils.getTime())); replaceMap.put("%refreshlong%", data.getRefreshDate() + ""); - replaceMap.put("%graphmaxplayers%", Settings.GRAPH_PLAYERS_USEMAXPLAYERS_SCALE.isTrue() ? Plan.getInstance().getVariable().getMaxPlayers() + "" : "2"); replaceMap.put("%servername%", Settings.SERVER_NAME.toString()); // Html Theme colors @@ -51,7 +56,7 @@ public class PlaceholderUtils { replaceMap.put("#" + defaultCols[i], "#" + colors[i]); } } - Benchmark.stop("Replace Placeholders Anaysis"); + Benchmark.stop("Replace Placeholders Analysis"); return replaceMap; } @@ -67,16 +72,16 @@ public class PlaceholderUtils { HashMap replaceMap = new HashMap<>(); boolean showIPandUUID = Settings.SECURITY_IP_UUID.isTrue(); UUID uuid = data.getUuid(); - replaceMap.put("%uuid%", (showIPandUUID ? "" + uuid : Html.HIDDEN.parse())); + replaceMap.put("%uuid%", (showIPandUUID ? String.valueOf(uuid) : Html.HIDDEN.parse())); replaceMap.put("%lastseen%", FormatUtils.formatTimeStampYear(data.getLastPlayed())); - replaceMap.put("%logintimes%", "" + data.getLoginTimes()); + replaceMap.put("%logintimes%", String.valueOf(data.getLoginTimes())); replaceMap.put("%geoloc%", data.getGeolocation()); long now = MiscUtils.getTime(); boolean isActive = AnalysisUtils.isActive(now, data.getLastPlayed(), data.getPlayTime(), data.getLoginTimes()); replaceMap.put("%active%", isActive ? Html.ACTIVE.parse() : Html.INACTIVE.parse()); GamemodePart gmPart = new GamemodePart(); - Map gmTimes = data.getGmTimes(); - String[] gms = new String[]{"SURVIVAL", "CREATIVE", "ADVENTURE", "SPECTATOR"}; + Map gmTimes = data.getGmTimes().getTimes(); + String[] gms = GMTimesTable.getGMKeyArray(); for (String gm : gms) { Long time = gmTimes.get(gm); if (time != null) { @@ -95,24 +100,24 @@ public class PlaceholderUtils { replaceMap.put("%banned%", data.isBanned() ? Html.BANNED.parse() : ""); replaceMap.put("%op%", data.isOp() ? Html.OPERATOR.parse() : ""); replaceMap.put("%isonline%", (data.isOnline()) ? Html.ONLINE.parse() : Html.OFFLINE.parse()); - replaceMap.put("%deaths%", data.getDeaths() + ""); - replaceMap.put("%playerkills%", data.getPlayerKills().size() + ""); - replaceMap.put("%mobkills%", data.getMobKills() + ""); + replaceMap.put("%deaths%", String.valueOf(data.getDeaths())); + replaceMap.put("%playerkills%", String.valueOf(data.getPlayerKills().size())); + replaceMap.put("%mobkills%", String.valueOf(data.getMobKills())); replaceMap.put("%sessionaverage%", FormatUtils.formatTimeAmount(MathUtils.averageLong(AnalysisUtils.transformSessionDataToLengths(data.getSessions())))); replaceMap.put("%killstable%", KillsTableCreator.createKillsTable(data.getPlayerKills())); Plan plugin = Plan.getInstance(); replaceMap.put("%version%", plugin.getDescription().getVersion()); - replaceMap.put("%planlite%", ""); - replaceMap.put("%graphmaxplayers%", 2 + ""); - String scatterGraphData = PlayerActivityGraphCreator.buildScatterDataStringSessions(data.getSessions(), TimeAmount.WEEK.ms()); - replaceMap.put("%dataweek%", scatterGraphData); - replaceMap.put("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL + ""); - replaceMap.put("%playersgraphfill%", Settings.HCOLOR_ACT_ONL_FILL + ""); - replaceMap.put("%datapunchcard%", PunchCardGraphCreator.generateDataArray(data.getSessions())); - String[] distribution = SessionLengthDistributionGraphCreator.generateDataArraySessions(data.getSessions()); - replaceMap.put("%datasessiondistribution%", distribution[0]); - replaceMap.put("%labelssessiondistribution%", distribution[1]); - replaceMap.put("%inaccuratedatawarning%", (now - data.getRegistered() < 180000) ? Html.WARN_INACCURATE.parse() : ""); + replaceMap.put("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL.toString()); + + Set sessions = new HashSet<>(data.getSessions()); + List lengths = AnalysisUtils.transformSessionDataToLengths(sessions); + replaceMap.put("%punchcardseries%", PunchCardGraphCreator.createDataSeries(sessions)); + replaceMap.put("%sessionlengthseries%", SessionLengthDistributionGraphCreator.createDataSeries(lengths)); + replaceMap.put("%playersonlineseries%", PlayerActivityGraphCreator.buildSeriesDataStringSessions(sessions)); + WorldTimes worldTimes = data.getWorldTimes(); + replaceMap.put("%worldseries%", WorldPieCreator.createSeriesData(worldTimes.getTimes())); + replaceMap.put("%worldtotal%", FormatUtils.formatTimeAmount(worldTimes.getTotal())); + String[] colors = new String[]{Settings.HCOLOR_MAIN.toString(), Settings.HCOLOR_MAIN_DARK.toString(), Settings.HCOLOR_SEC.toString(), Settings.HCOLOR_TER.toString(), Settings.HCOLOR_TER_DARK.toString()}; String[] defaultCols = new String[]{"348e0f", "267F00", "5cb239", "89c471", "5da341"}; for (int i = 0; i < colors.length; i++) { @@ -120,8 +125,9 @@ public class PlaceholderUtils { replaceMap.put("#" + defaultCols[i], "#" + colors[i]); } } - replaceMap.put("%refreshlong%", plugin.getInspectCache().getCacheTime(uuid) + ""); - replaceMap.put("%currenttime%", MiscUtils.getTime() + ""); + long cacheTime = plugin.getInspectCache().getCacheTime(uuid); + replaceMap.put("%refresh%", FormatUtils.formatTimeAmountDifference(cacheTime, now)); + replaceMap.put("%refreshlong%", String.valueOf(cacheTime)); replaceMap.put("%servername%", Settings.SERVER_NAME.toString()); String pluginsTabHtml = plugin.getHookHandler().getPluginsTabLayoutForInspect(); Map additionalReplaceRules = plugin.getHookHandler().getAdditionalInspectReplaceRules(uuid); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java index f3955d49b..6aab4c71a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java @@ -14,8 +14,11 @@ import main.java.com.djrapitops.plan.data.analysis.*; 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.data.cache.PageCacheHandler; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.ui.html.tables.PlayersTableCreator; +import main.java.com.djrapitops.plan.ui.webserver.response.AnalysisPageResponse; +import main.java.com.djrapitops.plan.ui.webserver.response.PlayersPageResponse; import main.java.com.djrapitops.plan.utilities.Benchmark; import main.java.com.djrapitops.plan.utilities.HtmlUtils; import main.java.com.djrapitops.plan.utilities.MiscUtils; @@ -25,7 +28,6 @@ import java.util.*; import java.util.stream.Collectors; /** - * * @author Rsl1122 */ public class Analysis { @@ -46,9 +48,9 @@ public class Analysis { /** * Analyzes the data of all offline players on the server. - * + *

* First retrieves all offline players and checks those that are in the - * database. Then Runs a new Analysis Task Asynchronously. Saves AnalysisData + * database. Then runs a new Analysis Task asynchronously. Saves AnalysisData * to the provided Cache. Saves all UserData to InspectCache for 15 minutes. * * @param analysisCache Cache that the data is saved to. @@ -57,6 +59,7 @@ public class Analysis { if (isAnalysisBeingRun()) { return; } + plugin.processStatus().startExecution("Analysis"); log(Phrase.ANALYSIS_START.toString()); // Async task for Analysis @@ -75,13 +78,14 @@ public class Analysis { * Caches analyzed data of db to the provided cache analysisCache. * * @param analysisCache Cache that will contain AnalysisData result of this - * method. - * @param db Database which data will be analyzed. + * method. + * @param db Database which data will be analyzed. * @return Whether or not analysis was successful. */ public boolean analyze(AnalysisCacheHandler analysisCache, Database db) { - log(Phrase.ANALYSIS_FETCH_DATA + ""); + log(Phrase.ANALYSIS_FETCH_DATA.toString()); Benchmark.start("Analysis: Fetch Phase"); + plugin.processStatus().setStatus("Analysis", "Analysis Fetch Phase"); try { inspectCache.cacheAllUserData(db); @@ -89,23 +93,26 @@ public class Analysis { Log.toLog(this.getClass().getName(), ex); Log.error(Phrase.ERROR_ANALYSIS_FETCH_FAIL.toString()); } + List rawData = inspectCache.getCachedUserData(); if (rawData.isEmpty()) { Log.info(Phrase.ANALYSIS_FAIL_NO_DATA.toString()); return false; } + List tpsData = new ArrayList<>(); + try { tpsData = db.getTpsTable().getTPSData(); Log.debug("TPS Data Size: " + tpsData.size()); } catch (Exception ex) { Log.toLog(this.getClass().getName(), ex); } + return analyzeData(rawData, tpsData, analysisCache); } /** - * * @param rawData * @param tpsData * @param analysisCache @@ -132,7 +139,7 @@ public class Analysis { Benchmark.start("Analysis Phase"); plugin.processStatus().setStatus("Analysis", "Analysis Phase"); - log(Phrase.ANALYSIS_BEGIN_ANALYSIS.parse(rawData.size() + "", fetchPhaseLength + "")); + log(Phrase.ANALYSIS_BEGIN_ANALYSIS.parse(String.valueOf(rawData.size()), String.valueOf(fetchPhaseLength))); String playersTable = PlayersTableCreator.createSortablePlayersTable(rawData); analysisData.setPlayersTable(playersTable); @@ -148,11 +155,15 @@ public class Analysis { analysisCache.cache(analysisData); long time = plugin.processStatus().finishExecution("Analysis"); + if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) { - Log.info(Phrase.ANALYSIS_COMPLETE.parse(time + "", HtmlUtils.getServerAnalysisUrlWithProtocol())); + Log.info(Phrase.ANALYSIS_COMPLETE.parse(String.valueOf(time), HtmlUtils.getServerAnalysisUrlWithProtocol())); } + ExportUtility.export(plugin, analysisData, rawData); - } catch (Throwable e) { + PageCacheHandler.cachePage("analysisPage", () -> new AnalysisPageResponse(plugin.getUiServer().getDataReqHandler())); + PageCacheHandler.cachePage("players", () -> new PlayersPageResponse(plugin)); + } catch (Exception e) { Log.toLog(this.getClass().getName(), e); plugin.processStatus().setStatus("Analysis", "Error: " + e); return false; @@ -174,10 +185,10 @@ public class Analysis { .filter(p -> !p.getAnalysisTypes().isEmpty()) .collect(Collectors.toList()); final AnalysisType[] totalTypes = new AnalysisType[]{ - AnalysisType.INT_TOTAL, AnalysisType.LONG_TOTAL, AnalysisType.LONG_TIME_MS_TOTAL, AnalysisType.DOUBLE_TOTAL + AnalysisType.INT_TOTAL, AnalysisType.LONG_TOTAL, AnalysisType.LONG_TIME_MS_TOTAL, AnalysisType.DOUBLE_TOTAL }; final AnalysisType[] avgTypes = new AnalysisType[]{ - AnalysisType.INT_AVG, AnalysisType.LONG_AVG, AnalysisType.LONG_TIME_MS_AVG, AnalysisType.LONG_EPOCH_MS_MINUS_NOW_AVG, AnalysisType.DOUBLE_AVG + AnalysisType.INT_AVG, AnalysisType.LONG_AVG, AnalysisType.LONG_TIME_MS_AVG, AnalysisType.LONG_EPOCH_MS_MINUS_NOW_AVG, AnalysisType.DOUBLE_AVG }; final AnalysisType bool = AnalysisType.BOOLEAN_PERCENTAGE; final AnalysisType boolTot = AnalysisType.BOOLEAN_TOTAL; @@ -209,7 +220,7 @@ public class Analysis { if (analysisTypes.contains(boolTot)) { replaceMap.put(source.getPlaceholder(boolTot.getPlaceholderModifier()), AnalysisUtils.getBooleanTotal(boolTot, source, uuids)); } - } catch (Throwable e) { + } catch (Exception | NoClassDefFoundError | NoSuchFieldError e) { Log.error("A PluginData-source caused an exception: " + source.getPlaceholder("").replace("%", "")); Log.toLog(this.getClass().getName(), e); @@ -222,7 +233,6 @@ public class Analysis { } /** - * * @return */ public boolean isAnalysisBeingRun() { @@ -246,13 +256,14 @@ public class Analysis { KillPart killPart = analysisData.getKillPart(); PlayerCountPart playerCount = analysisData.getPlayerCountPart(); PlaytimePart playtime = analysisData.getPlaytimePart(); + WorldPart worldPart = analysisData.getWorldPart(); long now = MiscUtils.getTime(); Benchmark.start("Analysis: Fill Dataset"); - rawData.forEach((uData) -> { + rawData.forEach(uData -> { uData.access(); - Map gmTimes = uData.getGmTimes(); + Map gmTimes = uData.getGmTimes().getTimes(); String[] gms = new String[]{"SURVIVAL", "CREATIVE", "ADVENTURE", "SPECTATOR"}; if (gmTimes != null) { for (String gm : gms) { @@ -262,12 +273,17 @@ public class Analysis { } } } + Map worldTimes = uData.getWorldTimes().getTimes(); + for (Map.Entry world : worldTimes.entrySet()) { + worldPart.addToWorld(world.getKey(), world.getValue()); + } + final long playTime = uData.getPlayTime(); playtime.addToPlaytime(playTime); joinInfo.addToLoginTimes(uData.getLoginTimes()); joinInfo.addRegistered(uData.getRegistered()); - geolocPart.addGeoloc(uData.getGeolocation()); + geolocPart.addGeolocation(uData.getGeolocation()); final UUID uuid = uData.getUuid(); if (uData.isOp()) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java index b745e775b..5a2bc1c1e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java @@ -14,13 +14,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** - * * @author Rsl1122 */ public class AnalysisUtils { /** - * + * Constructor used to hide the public constructor + */ + private AnalysisUtils() { + throw new IllegalStateException("Utility class"); + } + + /** * @param now * @param lastPlayed * @param playTime @@ -29,41 +34,37 @@ public class AnalysisUtils { */ public static boolean isActive(long now, long lastPlayed, long playTime, int loginTimes) { int timeToActive = Settings.ANALYSIS_MINUTES_FOR_ACTIVE.getNumber(); + if (timeToActive < 0) { timeToActive = 0; } + long twoWeeks = 1209600000; - if (now - lastPlayed < twoWeeks) { - if (loginTimes > 3) { - if (playTime > 60 * timeToActive) { - return true; - } - } - } - return false; + + return now - lastPlayed < twoWeeks + && loginTimes > 3 + && playTime > 60 * timeToActive; } /** - * * @param registered * @param scale * @param now * @return */ - public static int getNewPlayers(List registered, long scale, long now) { - int newPlayers = 0; + public static long getNewPlayers(List registered, long scale, long now) { + long newPlayers = 0; if (!registered.isEmpty()) { newPlayers = registered.stream() - .filter((reg) -> (reg != null)) - .filter((reg) -> (reg > now - scale)) - .map((_item) -> 1).reduce(newPlayers, Integer::sum); + .filter(Objects::nonNull) + .filter(reg -> reg > now - scale) + .count(); } // Filters out register dates before scale return newPlayers; } /** - * * @param data * @return */ @@ -76,7 +77,6 @@ public class AnalysisUtils { } /** - * * @param analysisType * @param source * @param uuids @@ -104,8 +104,8 @@ public class AnalysisUtils { default: return source.parseContainer("", "Wrong Analysistype specified: " + analysisType.name()); } - return source.parseContainer(analysisType.getModifier(), total + ""); - } catch (Throwable e) { + return source.parseContainer(analysisType.getModifier(), String.valueOf(total)); + } catch (Exception | NoClassDefFoundError | NoSuchFieldError e) { return logPluginDataCausedError(source, e); } } @@ -118,7 +118,6 @@ public class AnalysisUtils { } /** - * * @param analysisType * @param source * @param uuids @@ -137,7 +136,7 @@ public class AnalysisUtils { return source.parseContainer(analysisType.getModifier(), FormatUtils.formatTimeAmount((long) average)); case LONG_AVG: long averageLong = MathUtils.averageLong(getCorrectValues(uuids, source).map(i -> (Long) i)); - return source.parseContainer(analysisType.getModifier(), averageLong + ""); + return source.parseContainer(analysisType.getModifier(), String.valueOf(averageLong)); case LONG_TIME_MS_AVG: average = MathUtils.averageLong(getCorrectValues(uuids, source).map(i -> (Long) i)); return source.parseContainer(analysisType.getModifier(), FormatUtils.formatTimeAmount((long) average)); @@ -151,13 +150,12 @@ public class AnalysisUtils { return source.parseContainer("Err ", "Wrong Analysistype specified: " + analysisType.name()); } return source.parseContainer(analysisType.getModifier(), FormatUtils.cutDecimals(average)); - } catch (Throwable e) { + } catch (Exception | NoClassDefFoundError | NoSuchFieldError e) { return logPluginDataCausedError(source, e); } } /** - * * @param analysisType * @param source * @param uuids @@ -170,8 +168,8 @@ public class AnalysisUtils { .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 (Throwable e) { + return source.parseContainer(analysisType.getModifier(), (((double) count / tempList.size()) * 100) + "%"); + } catch (Exception | NoClassDefFoundError | NoSuchFieldError e) { return logPluginDataCausedError(source, e); } } @@ -179,7 +177,6 @@ public class AnalysisUtils { } /** - * * @param analysisType * @param source * @param uuids @@ -193,7 +190,7 @@ public class AnalysisUtils { .collect(Collectors.toList()); long count = tempList.stream().filter(value -> value).count(); return source.parseContainer(analysisType.getModifier(), count + " / " + tempList.size()); - } catch (Throwable e) { + } catch (Exception e) { return logPluginDataCausedError(source, e); } } @@ -208,29 +205,26 @@ public class AnalysisUtils { } /** + * Used to calculate unique players that have played within the time frame determined by scale. * - * @param sessions - * @param scale - * @return + * @param sessions All sessions sorted in a map by User's UUID + * @param scale Scale (milliseconds), time before (Current epoch - scale) will be ignored. + * @return Amount of Unique joins within the time span. */ public static int getUniqueJoins(Map> sessions, long scale) { long now = MiscUtils.getTime(); long nowMinusScale = now - scale; Set uniqueJoins = new HashSet<>(); - sessions.keySet().forEach((uuid) -> { - List s = sessions.get(uuid); - for (SessionData session : s) { - if (session.getSessionStart() < nowMinusScale) { - continue; - } - uniqueJoins.add(uuid); - } - }); + sessions.forEach((uuid, s) -> + s.stream() + .filter(session -> session.getSessionStart() >= nowMinusScale) + .map(session -> uuid) + .forEach(uniqueJoins::add) + ); return uniqueJoins.size(); } /** - * * @param sessions * @param scale * @return @@ -239,13 +233,12 @@ public class AnalysisUtils { Map> uniqueJoins = new HashMap<>(); long now = MiscUtils.getTime(); long nowMinusScale = now - scale; - sessions.keySet().forEach((uuid) -> { - List s = sessions.get(uuid); + + sessions.forEach((uuid, s) -> { for (SessionData session : s) { - if (scale != -1) { - if (session.getSessionStart() < nowMinusScale) { - continue; - } + if (scale != -1 + && session.getSessionStart() < nowMinusScale) { + continue; } int day = getDayOfYear(session); @@ -254,33 +247,64 @@ public class AnalysisUtils { uniqueJoins.get(day).add(uuid); } }); + int total = MathUtils.sumInt(uniqueJoins.values().stream().map(Set::size)); - int size = uniqueJoins.keySet().size(); - if (size == 0) { + int numberOfDays = uniqueJoins.size(); + + if (numberOfDays == 0) { return 0; } - return total / size; + + return total / numberOfDays; + } + + public static long getNewUsersPerDay(List registers, long scale) { + long now = MiscUtils.getTime(); + long nowMinusScale = now - scale; + + Set days = new HashSet<>(); + for (Long date : registers) { + if (scale != -1) { + if (date < nowMinusScale) { + continue; + } + int day = getDayOfYear(date); + days.add(day); + } + } + + long total = registers.stream().filter(date -> date >= nowMinusScale).count(); + int numberOfDays = days.size(); + + if (numberOfDays == 0) { + return 0; + } + return total / numberOfDays; } /** + * Transforms the session start list into a list of int arrays. + *

+ * First number signifies the Day of Week. (0 = Monday, 6 = Sunday) + * Second number signifies the Hour of Day. (0 = 0 AM, 23 = 11 PM) * - * @param sessionStarts - * @return + * @param sessionStarts List of Session start Epoch ms. + * @return list of int arrays. */ public static List getDaysAndHours(List sessionStarts) { return sessionStarts.stream().map((Long start) -> { Calendar day = Calendar.getInstance(); day.setTimeInMillis(start); - int hourOfDay = day.get(Calendar.HOUR_OF_DAY); - int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2; - if (hourOfDay == 24) { + int hourOfDay = day.get(Calendar.HOUR_OF_DAY); // 0 AM is 0 + int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2; // Monday is 0, Sunday is -1 + if (hourOfDay == 24) { // Check if hour is 24 (Should be impossible but.) hourOfDay = 0; dayOfWeek += 1; } - if (dayOfWeek > 6) { + if (dayOfWeek > 6) { // If Hour added a day on Sunday, move to Monday dayOfWeek = 0; } - if (dayOfWeek < 0) { + if (dayOfWeek < 0) { // Move Sunday to 6 dayOfWeek = 6; } return new int[]{dayOfWeek, hourOfDay}; @@ -288,8 +312,13 @@ public class AnalysisUtils { } private static int getDayOfYear(SessionData session) { + return getDayOfYear(session.getSessionStart()); + + } + + private static int getDayOfYear(long date) { Calendar day = Calendar.getInstance(); - day.setTimeInMillis(session.getSessionStart()); + day.setTimeInMillis(date); return day.get(Calendar.DAY_OF_YEAR); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeckerAlgorithm.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java similarity index 79% rename from Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeckerAlgorithm.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java index 97d825d74..26622a89a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeckerAlgorithm.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java @@ -5,24 +5,33 @@ import java.util.Arrays; import java.util.List; /** - * Ramer-Douglas-Pecker Point Reduction Algorithm for reducing points from + * Ramer-Douglas-Peucker Point Reduction Algorithm for reducing points from * graphs. * * @author Rsl1122 * @since 3.5.2 */ -public class DouglasPeckerAlgorithm { +public class DouglasPeuckerAlgorithm { + + /** + * Constructor used to hide the public constructor + */ + private DouglasPeuckerAlgorithm() { + throw new IllegalStateException("Utility class"); + } public static List reducePoints(List points, double epsilon) { if (points.isEmpty()) { return points; } - if (epsilon == -1) { + + if (Double.compare(epsilon, -1) == 0) { epsilon = 0.002; } + int size = points.size(); final int lastIndex = size - 1; - final Point start = points.get(0); + final Point start = points.get(0); final Point end = points.get(lastIndex); // Max distance and it's index. @@ -52,5 +61,5 @@ public class DouglasPeckerAlgorithm { private static double perpendicularDistance(Point point, Line line) { return line.getPerpendicularDistance(point); - } + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ExportUtility.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ExportUtility.java index 8af43a2a4..0e26f9a31 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ExportUtility.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ExportUtility.java @@ -13,28 +13,33 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Collections; import java.util.List; /** - * * @author Rsl1122 * @since 3.4.0 */ public class ExportUtility { /** - * + * Constructor used to hide the public constructor + */ + private ExportUtility() { + throw new IllegalStateException("Utility class"); + } + + /** * @return */ public static File getFolder() { String path = Settings.ANALYSIS_EXPORT_PATH.toString(); - if (path.contains(":")) { + if (Paths.get(path).isAbsolute()) { File folder = new File(path); - if (folder.exists()) { - if (folder.isDirectory()) { - return folder; - } + if (folder.exists() + && folder.isDirectory()) { + return folder; } folder.mkdirs(); return folder; @@ -46,7 +51,6 @@ public class ExportUtility { } /** - * * @param plugin * @param analysisData * @param rawData @@ -74,7 +78,6 @@ public class ExportUtility { } /** - * * @param folder * @return */ @@ -85,7 +88,6 @@ public class ExportUtility { } /** - * * @param userData * @param playersFolder * @throws FileNotFoundException @@ -95,7 +97,7 @@ public class ExportUtility { if (!Settings.ANALYSIS_EXPORT.isTrue()) { return; } - String inspectHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getHtmlStringFromResource("player.html"), + String inspectHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getStringFromResource("player.html"), PlaceholderUtils.getInspectReplaceRules(userData)); File playerFolder = new File(playersFolder, userData.getName()); playerFolder.mkdir(); @@ -105,7 +107,6 @@ public class ExportUtility { } /** - * * @param analysisData * @param serverFolder * @throws FileNotFoundException @@ -115,7 +116,7 @@ public class ExportUtility { if (!Settings.ANALYSIS_EXPORT.isTrue()) { return; } - String analysisHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getHtmlStringFromResource("analysis.html"), + String analysisHtml = HtmlUtils.replacePlaceholders(HtmlUtils.getStringFromResource("analysis.html"), PlaceholderUtils.getAnalysisReplaceRules(analysisData)) .replace(HtmlUtils.getInspectUrl(""), "../player/"); File analysisHtmlFile = new File(serverFolder, "index.html"); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java index 5da917a21..03212d13e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java @@ -6,7 +6,6 @@ package main.java.com.djrapitops.plan.utilities.analysis; /** - * * @author ristolah */ public class Line { @@ -56,7 +55,6 @@ public class Line { public double getPerpendicularDistance(Point from) { double a = getA(); - double b = -1; double x = from.getX(); double y = from.getY(); return Math.abs(a * x - y + c) / Math.sqrt(Math.pow(a, 2) + 1); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java index 019ab5bdb..f085e12b7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java @@ -11,6 +11,16 @@ import java.util.stream.Stream; */ public class MathUtils { + /** + * Constructor used to hide the public constructor + */ + private MathUtils() { + throw new IllegalStateException("Utility class"); + } + + private static final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(Locale.ENGLISH); + private static final DecimalFormat decimalFormat = new DecimalFormat("#.##", decimalFormatSymbols); + /** * Gets the average of a Stream of Integers. * If there are no components in the Stream, it will return 0. @@ -168,9 +178,6 @@ public class MathUtils { return biggest.isPresent() ? biggest.getAsLong() : 1; } - private static final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(Locale.ENGLISH); - private static final DecimalFormat decimalFormat = new DecimalFormat("#.##", decimalFormatSymbols); - /** * Rounds the double to a double with two digits at the end. * Output: #.## diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java new file mode 100644 index 000000000..015e05cee --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java @@ -0,0 +1,53 @@ +package main.java.com.djrapitops.plan.utilities.analysis; + +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.utilities.Verify; +import main.java.com.djrapitops.plan.utilities.comparators.PointComparator; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by Fuzzlemann on 30.07.2017. + */ +public class ReduceGapTriangles { + + /** + * Constructor used to hide the public constructor + */ + private ReduceGapTriangles() { + throw new IllegalStateException("Utility class"); + } + + public static List reduce(List points) { + Point lastPoint = null; + + Set toAdd = new HashSet<>(); + for (Point point : points) { + if (!Verify.notNull(point, lastPoint)) { + lastPoint = point; + continue; + } + + long date = (long) point.getX(); + long lastDate = (long) lastPoint.getX(); + double y = point.getY(); + double lastY = lastPoint.getY(); + + if (Double.compare(y, lastY) != 0 + && Math.abs(lastY - y) > 0.5 + && lastDate < date - TimeAmount.MINUTE.ms() * 10L) { + toAdd.add(new Point(lastDate + 1, lastY)); + toAdd.add(new Point(date - 1, lastY)); + } + + lastPoint = point; + } + + points.addAll(toAdd); + points.sort(new PointComparator()); + + return points; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparator.java index 0db4b3601..a331d60df 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparator.java @@ -10,7 +10,6 @@ import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; import java.util.Comparator; /** - * * @author Rsl1122 */ public class HandlingInfoTimeComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java index 69b3d3db5..352fa9c77 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java @@ -6,11 +6,17 @@ import java.util.List; import java.util.Map; /** - * * @author Rsl1122 */ public class MapComparator { + /** + * Constructor used to hide the public constructor + */ + private MapComparator() { + throw new IllegalStateException("Utility class"); + } + /** * Sorts a HashMap of String, Integer by the Values of the HashMap. * @@ -20,19 +26,18 @@ public class MapComparator { */ public static List sortByValue(Map hashMap) { List sortedList = new ArrayList<>(); - hashMap.keySet().forEach((key) -> sortedList.add(new String[]{"" + hashMap.get(key), key})); + hashMap.keySet().forEach(key -> sortedList.add(new String[]{String.valueOf(hashMap.get(key)), key})); sortedList.sort(Comparator.comparingInt(strings -> Integer.parseInt(strings[0]))); return sortedList; } /** - * * @param hashMap * @return */ public static List sortByValueLong(Map hashMap) { List sortedList = new ArrayList<>(); - hashMap.keySet().forEach((key) -> sortedList.add(new String[]{"" + hashMap.get(key), key})); + hashMap.keySet().forEach(key -> sortedList.add(new String[]{String.valueOf(hashMap.get(key)), key})); sortedList.sort(Comparator.comparing(strings -> Long.valueOf(strings[0]))); return sortedList; } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java index 4b597a9f1..0e6e7fb58 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java @@ -5,19 +5,19 @@ */ package main.java.com.djrapitops.plan.utilities.comparators; -import java.util.Comparator; import main.java.com.djrapitops.plan.utilities.analysis.Point; +import java.util.Comparator; + /** - * * @author Rsl1122 * @since 3.5.2 */ -public class PointComparator implements Comparator{ +public class PointComparator implements Comparator { @Override public int compare(Point o1, Point o2) { return Double.compare(o1.getX(), o2.getX()); } - + } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionDataComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionDataComparator.java index f3fb389c5..f4eab60dd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionDataComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionDataComparator.java @@ -5,12 +5,10 @@ import main.java.com.djrapitops.plan.data.SessionData; import java.util.Comparator; /** - * * @author Rsl1122 */ public class SessionDataComparator implements Comparator { - // This method should only be used if FactionsHook.isEnabled() returns true. @Override public int compare(SessionData s1, SessionData s2) { return Long.compare(s1.getSessionStart(), s2.getSessionStart()); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/TPSComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/TPSComparator.java index 54f556735..35f6604d3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/TPSComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/TPSComparator.java @@ -1,10 +1,10 @@ package main.java.com.djrapitops.plan.utilities.comparators; -import java.util.Comparator; import main.java.com.djrapitops.plan.data.TPS; +import java.util.Comparator; + /** - * * @author Rsl1122 * @since 3.5.0 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataLastPlayedComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataLastPlayedComparator.java index 6f7a1cb31..51e6b38df 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataLastPlayedComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataLastPlayedComparator.java @@ -5,11 +5,11 @@ */ package main.java.com.djrapitops.plan.utilities.comparators; -import java.util.Comparator; import main.java.com.djrapitops.plan.data.UserData; +import java.util.Comparator; + /** - * * @author Risto */ public class UserDataLastPlayedComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataNameComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataNameComparator.java index c3596d9ed..90e9ecdac 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataNameComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/UserDataNameComparator.java @@ -5,11 +5,11 @@ */ package main.java.com.djrapitops.plan.utilities.comparators; -import java.util.Comparator; import main.java.com.djrapitops.plan.data.UserData; +import java.util.Comparator; + /** - * * @author Risto */ public class UserDataNameComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/WebUserComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/WebUserComparator.java index 018139554..e1bd3281d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/WebUserComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/WebUserComparator.java @@ -1,8 +1,9 @@ package main.java.com.djrapitops.plan.utilities.comparators; -import java.util.Comparator; import main.java.com.djrapitops.plan.data.WebUser; +import java.util.Comparator; + /** * Orders WebUsers in descending order by permission level. * diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java index 1d7af2e26..955966927 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java @@ -25,21 +25,16 @@ public class BStats { boolean analysisRefreshEnable = Settings.ANALYSIS_REFRESH_ON_ENABLE.isTrue(); boolean analysisAutoRefresh = Settings.ANALYSIS_AUTO_REFRESH.getNumber() != -1; boolean export = Settings.ANALYSIS_EXPORT.isTrue(); - boolean gatherChat = Settings.GATHERCHAT.isTrue(); - boolean gatherKills = Settings.GATHERKILLS.isTrue(); - boolean gatherGMTimes = Settings.GATHERGMTIMES.isTrue(); - boolean gatherCommands = Settings.GATHERCOMMANDS.isTrue(); addEnabledDisabledPie("webserver_enabled", webserver); addEnabledDisabledPie("analysis_enable_refresh", analysisRefreshEnable); addEnabledDisabledPie("analysis_auto_refresh", analysisAutoRefresh); addEnabledDisabledPie("html_export", export); - addEnabledDisabledPie("gather_chat", gatherChat); - addEnabledDisabledPie("gather_kills", gatherKills); - addEnabledDisabledPie("gather_gmtimes", gatherGMTimes); - addEnabledDisabledPie("gather_commands", gatherCommands); - String databaseType = Settings.DB_TYPE.toString(); + String serverType = plugin.getServer().getName(); + String databaseType = plugin.getDB().getName(); + + addStringSettingPie("server_type", serverType); addStringSettingPie("database_type", databaseType); } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java index 43ee473f8..7d390da0c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java @@ -24,11 +24,20 @@ import java.util.zip.GZIPOutputStream; /** * bStats collects some data for plugin authors. - * + *

* Check out https://bStats.org/ to learn more about bStats! */ public class Metrics { + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + // Should failed requests be logged? + private static boolean logFailedRequests; + // The uuid of the server + private static String serverUUID; + static { // You can use the property to disable the check in your test environment if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { @@ -43,18 +52,6 @@ public class Metrics { } } - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // The uuid of the server - private static String serverUUID; - // The plugin private final JavaPlugin plugin; @@ -96,7 +93,8 @@ public class Metrics { ).copyDefaults(true); try { config.save(configFile); - } catch (IOException ignored) { } + } catch (IOException ignored) { + } } // Load the data @@ -110,7 +108,8 @@ public class Metrics { service.getField("B_STATS_VERSION"); // Our identifier :) found = true; // We aren't the first break; - } catch (NoSuchFieldException ignored) { } + } catch (NoSuchFieldException ignored) { + } } // Register our service Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); @@ -121,6 +120,61 @@ public class Metrics { } } + /** + * Sends the data to the bStats server. + * + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(JSONObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + connection.getInputStream().close(); // We don't care about the response - Just send our data :) + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes("UTF-8")); + gzip.close(); + return outputStream.toByteArray(); + } + /** * Adds a custom chart. * @@ -149,7 +203,7 @@ public class Metrics { // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) Bukkit.getScheduler().runTask(plugin, () -> submitData()); } - }, 1000*60*5, 1000*60*30); + }, 1000 * 60 * 5, 1000 * 60 * 30); // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! // WARNING: Just don't do it! @@ -244,9 +298,11 @@ public class Metrics { for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { try { pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + } } - } catch (NoSuchFieldException ignored) { } + } catch (NoSuchFieldException ignored) { + } } data.put("plugins", pluginData); @@ -265,61 +321,6 @@ public class Metrics { }).start(); } - /** - * Sends the data to the bStats server. - * - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(JSONObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException("This method must not be called from the main thread!"); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); - outputStream.write(compressedData); - outputStream.flush(); - outputStream.close(); - - connection.getInputStream().close(); // We don't care about the response - Just send our data :) - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes("UTF-8")); - gzip.close(); - return outputStream.toByteArray(); - } - /** * Represents a custom chart. */ @@ -350,9 +351,9 @@ public class Metrics { return null; } chart.put("data", data); - } catch (Throwable t) { + } catch (Exception e) { if (logFailedRequests) { - Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, e); } return null; } @@ -373,7 +374,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SimplePie(String chartId, Callable callable) { @@ -404,7 +405,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public AdvancedPie(String chartId, Callable> callable) { @@ -448,7 +449,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public DrilldownPie(String chartId, Callable>> callable) { @@ -497,7 +498,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SingleLineChart(String chartId, Callable callable) { @@ -529,7 +530,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public MultiLineChart(String chartId, Callable> callable) { @@ -574,7 +575,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public SimpleBarChart(String chartId, Callable> callable) { @@ -612,7 +613,7 @@ public class Metrics { /** * Class constructor. * - * @param chartId The id of the chart. + * @param chartId The id of the chart. * @param callable The callable which is used to request the chart data. */ public AdvancedBarChart(String chartId, Callable> callable) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java b/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java index 4c651939d..779e7e2ae 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java @@ -14,13 +14,18 @@ import java.sql.SQLException; import java.util.UUID; /** - * * @author Rsl1122 */ public class UUIDUtility { /** - * + * Constructor used to hide the public constructor + */ + private UUIDUtility() { + throw new IllegalStateException("Utility class"); + } + + /** * @param playername * @return */ @@ -33,7 +38,6 @@ public class UUIDUtility { } /** - * * @param playername * @param db * @return @@ -49,7 +53,7 @@ public class UUIDUtility { if (uuid == null) { uuid = UUIDFetcher.getUUIDOf(playername); } - } catch (Exception e) { + } catch (Exception ignored) { } return uuid; } diff --git a/Plan/src/main/resources/Cert.keystore b/Plan/src/main/resources/Cert.keystore new file mode 100644 index 000000000..9f95d3807 Binary files /dev/null and b/Plan/src/main/resources/Cert.keystore differ diff --git a/Plan/src/main/resources/analysis.html b/Plan/src/main/resources/analysis.html index 06f435d1f..62d10ced7 100644 --- a/Plan/src/main/resources/analysis.html +++ b/Plan/src/main/resources/analysis.html @@ -7,276 +7,277 @@ - @@ -325,7 +326,7 @@

Player Activity - Last 24h
+ class="header-text"> Player Activity
@@ -336,12 +337,12 @@ %npday%
- New Players + New Players / 24h
- +

Unique Players: %uniquejoinsday% | Unique/Day: %avguniquejoinsday%

@@ -382,70 +383,17 @@ Total Login times: %totallogins%
Average Unique Players/Day: - %avguniquejoins%
+ %avguniquejoins% | Average New/Day: + %newperday%
Player kills: %playerkills% | Mob kills: %mobkills% | Deaths: %deaths%

-

Gamemode Usage


-
-
-
- -
-
-
- %gm0% -
-
- Survival -
-
-
-
-
- -
-
-
- %gm1% -
-
- Creative -
-
-
-
-
- -
-
-
- %gm2% -
-
- Adventure -
-
-
-
-
- -
-
-
- %gm3% -
-
- Spectator -
-
-
-
- +
+
+
+
@@ -455,82 +403,49 @@
Player Activity - Last 24h
+ class="header-text"> Player Activity
-
+
-
+
- %npday% + %newperdaymonth%
- New Players + New Players / Day
- -

Unique Players: %uniquejoinsday% | Unique/Day: %avguniquejoinsday%

+
-
-
-
Player Activity - Last 7d
-
-
-
- -
-
-
- %npweek% -
-
- New Players -
-
-
-
- -

Unique Players: %uniquejoinsweek% | Unique/Day: %avguniquejoinsweek%

-
-
-
-
-
Player Activity - Last 30d
-
-
-
- -
-
-
- %npmonth% -
-
- New Players -
-
-
-
- -

Unique Players: %uniquejoinsmonth% | Unique/Day: %avguniquejoinsmonth% -

+

Month:
+ Unique Players: %uniquejoinsmonth%
+ Unique/Day: %avguniquejoinsmonth% +
+ New Players: %npmonth%
+ New Players / Day: %newperdaymonth%

+

Week:
+ Unique Players: %uniquejoinsweek%
+ Unique/Day: %avguniquejoinsweek%
+ New Players: %npweek%
+ New Players / Day: %newperdayweek%

+

Day:
+ Unique Players: %uniquejoinsday%
+ Unique/Day: %avguniquejoinsday%
+ New Players: %npday%
+ New Players / Day: %newperdayday%

-
+
Playerbase Composition
+ class="header-text"> Playerbase
@@ -546,63 +461,7 @@
-
-
-
- -
-
-
- %active% -
-
- __Active -
-
-
-
-
- -
-
-
- %inactive% -
-
- Inactive -
-
-
-
-
- -
-
-
- %joinleaver% -
-
- Single_join -
-
-
-
-
- -
-
-
- %banned% -
-
- Banned -
-
-
-
-

- -
+

- +
@@ -660,7 +519,7 @@
- +
@@ -668,57 +527,36 @@
-
-
TPS - 7d
-
-
-
- -
-
-
- %averagetps% -
-
- Average 7d -
-
+
+
Performance
- +

Week:
+ Average TPS: %averagetpsweek%
+ Average CPU: %averagecpuweek%
+ Average RAM: %averagememoryweek%Mb
+ Avg. Entities: %averageentitiesweek%
+ Average Chunks: %averagechunksweek% +

+

Day:
+ Average TPS: %averagetpsday%
+ Average CPU: %averagecpuday%
+ Average RAM: %averagememoryday%Mb
+ Avg. Entities: %averageentitiesday%
+ Average Chunks: %averagechunksday%

- +
-
-
-
TPS - 24h
-
-
-
- -
-
-
- %averagetpsday% -
-
- Average 24h -
-
-
-
- +
- +
-

If CPU Graph displays '-1' CPU usage is not available for this platform.

@@ -743,7 +581,7 @@
- +
@@ -784,7 +622,7 @@ -
Player
+
@@ -821,7 +659,7 @@
-
+
@@ -831,51 +669,615 @@ + + + + + + + + + + + + + + + - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/Plan/src/main/resources/config.yml b/Plan/src/main/resources/config.yml index 0c7a184b8..a8db910d9 100644 --- a/Plan/src/main/resources/config.yml +++ b/Plan/src/main/resources/config.yml @@ -5,13 +5,11 @@ Settings: Data: ChatListener: true GatherKillData: true - GamemodeChangeListener: true GatherCommandUsage: true Analysis: LogProgressOnConsole: false NotifyWhenFinished: true MinutesPlayedUntilConsidiredActive: 10 - RemoveOutliersFromVisualization: true Export: Enabled: false DestinationFolder: 'Analysis Results' @@ -34,9 +32,14 @@ Settings: InternalIP: 0.0.0.0 ShowAlternativeServerIP: false AlternativeIP: your.ip.here:%port% - LinkProtocol: http + ExternalWebServerLinkProtocol: http Security: DisplayIPsAndUUIDs: true + Certificate: + KeyStorePath: 'SSLCertificate.keystore' + KeyPass: 'default' + StorePass: 'default' + Alias: 'alias' Customization: ServerName: 'Plan' @@ -44,9 +47,6 @@ Customization: Data: DoNotLogUnknownCommands: false CombineCommandAliasesToMainCommand: false - Graphs: - PlayersOnlineGraph: - UseMaxPlayersAsScale: true Formats: TimeAmount: Year: '1 year, ' @@ -71,13 +71,12 @@ Customization: TertiaryDark: 5da341 ActivityGraph: OnlinePlayers: '1E90FF' - OnlinePlayersFill: '75BBFF' NewPlayers: '228B22' GamemodePie: - Survival: '951800' - Creative: '01A1DB' - Adventure: '769316' - Spectator: '228B22' + Survival: '438c99' + Creative: '639A67' + Adventure: 'D8EBB5' + Spectator: 'D9BF77' ActivityPie: Active: '228B22' Banned: '951800' diff --git a/Plan/src/main/resources/player.html b/Plan/src/main/resources/player.html index e84a71481..f111fd04a 100644 --- a/Plan/src/main/resources/player.html +++ b/Plan/src/main/resources/player.html @@ -7,313 +7,313 @@ @@ -379,80 +379,10 @@ Has Connected from ips: %ips%

-
-
-
Gamemode Usage
-
-
-
- -
-
-
- %gmtotal% -
-
- Total -
-
-
-
-
-
-
- -
-
-
- %gm0% -
-
- Survival -
-
-
-
-
- -
-
-
- %gm1% -
-
- Creative -
-
-
-
-
- -
-
-
- %gm2% -
-
- Adventure -
-
-
-
-
- -
-
-
- %gm3% -
-
- Spectator -
-
-
-
- +
+
+
+
@@ -476,13 +406,13 @@
- +
Last 10 Kills
+ class="header-text"> Last 25 Kills
@@ -524,7 +454,7 @@
- +
@@ -548,7 +478,7 @@
- +
@@ -557,10 +487,234 @@ + + + + + + + + - - - - diff --git a/Plan/src/main/resources/plugin.yml b/Plan/src/main/resources/plugin.yml index 1d827e17c..fdce47d5d 100644 --- a/Plan/src/main/resources/plugin.yml +++ b/Plan/src/main/resources/plugin.yml @@ -1,8 +1,7 @@ name: Plan author: Rsl1122 main: main.java.com.djrapitops.plan.Plan -version: 3.5.5 - +version: 3.6.0 softdepend: - OnTime - EssentialsX @@ -106,4 +105,5 @@ permissions: plan.*: children: plan.manage: true - plan.staff: true \ No newline at end of file + plan.staff: true + apf.notify: true \ No newline at end of file diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/PermissionsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/PermissionsTest.java index ec7567731..de7276592 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/PermissionsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/PermissionsTest.java @@ -6,11 +6,11 @@ package test.java.main.java.com.djrapitops.plan; import main.java.com.djrapitops.plan.Permissions; -import static org.junit.Assert.*; import org.junit.Test; +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ public class PermissionsTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/PhraseTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/PhraseTest.java index 5c784fc12..8af82d60f 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/PhraseTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/PhraseTest.java @@ -3,7 +3,6 @@ package test.java.main.java.com.djrapitops.plan; import main.java.com.djrapitops.plan.Phrase; import org.bukkit.ChatColor; import org.bukkit.plugin.java.JavaPlugin; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,8 +10,9 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.TestInit; +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -30,7 +30,7 @@ public class PhraseTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); } /** @@ -49,7 +49,7 @@ public class PhraseTest { * */ @Test - public void testParse_0args() { + public void testParseWithZeroArgs() { Phrase instance = Phrase.DEM_UNKNOWN; String expResult = "Not Known"; String result = instance.parse(); @@ -60,7 +60,7 @@ public class PhraseTest { * */ @Test - public void testParse_StringArr() { + public void testParseStringArr() { Phrase instance = Phrase.REPLACE0; String expResult = "Test"; String result = instance.parse(expResult); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/SettingsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/SettingsTest.java index 1062de811..d0bf2470b 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/SettingsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/SettingsTest.java @@ -5,11 +5,8 @@ */ package test.java.main.java.com.djrapitops.plan; -import java.util.ArrayList; -import java.util.List; import main.java.com.djrapitops.plan.Settings; import org.bukkit.plugin.java.JavaPlugin; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,8 +14,13 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.TestInit; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -36,7 +38,7 @@ public class SettingsTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); } /** diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/KillDataTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/KillDataTest.java index 47b5fe096..bef1aa2fc 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/KillDataTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/KillDataTest.java @@ -5,13 +5,14 @@ */ package test.java.main.java.com.djrapitops.plan.data; -import java.util.UUID; import main.java.com.djrapitops.plan.data.KillData; -import static org.junit.Assert.*; import org.junit.Test; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ public class KillDataTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/SessionDataTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/SessionDataTest.java index 750c38254..02a51e290 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/SessionDataTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/SessionDataTest.java @@ -6,12 +6,13 @@ package test.java.main.java.com.djrapitops.plan.data; import main.java.com.djrapitops.plan.data.SessionData; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class SessionDataTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/Tep.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/Tep.java deleted file mode 100644 index 11d2f8209..000000000 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/Tep.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package test.java.main.java.com.djrapitops.plan.data; - -/** - * - * @author ristolah - */ -public class Tep { - -} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/UserDataTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/UserDataTest.java index a5af5809c..3fa5a8ba2 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/UserDataTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/UserDataTest.java @@ -16,13 +16,14 @@ import test.java.utils.TestInit; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -48,7 +49,6 @@ public class UserDataTest { } /** - * * @throws UnknownHostException */ @Test @@ -66,7 +66,6 @@ public class UserDataTest { } /** - * * @throws UnknownHostException */ @Test @@ -145,45 +144,6 @@ public class UserDataTest { assertTrue("Added something", test.getNicknames().isEmpty()); } - /** - * - */ - @Test - public void testSetGMTime() { - test.setGMTime("SURVIVAL", 1L); - final Long result = test.getGmTimes().get("SURVIVAL"); - assertTrue("" + result, result == 1L); - } - - /** - * - */ - @Test - public void testSetGMTimeWhenGMTimesNull() { - test.setGmTimes(null); - String gm = "SURVIVAL"; - test.setGMTime(gm, 1L); - final Long result = test.getGmTimes().get(gm); - assertTrue("" + result, result == 1L); - } - - /** - * - */ - @Test - public void testSetAllGMTimes() { - HashMap gmTimes = new HashMap<>(); - gmTimes.put(null, 0L); - test.setGmTimes(gmTimes); - test.setAllGMTimes(1L, 2L, 3L, 4L); - Map times = test.getGmTimes(); - assertTrue("Cleared gmTimes", !times.containsKey(null)); - assertTrue("Not equal 0", times.get("SURVIVAL") == 1L); - assertTrue("Not equal 1", times.get("CREATIVE") == 2L); - assertTrue("Not equal 2", times.get("ADVENTURE") == 3L); - assertTrue("Not equal 3", times.get("SPECTATOR") == 4L); - } - /** * */ @@ -241,16 +201,6 @@ public class UserDataTest { assertTrue("Added something", test.getSessions().isEmpty()); } - /** - * - */ - @Test - public void testSetCurrentSession() { - SessionData s = new SessionData(0); - test.setCurrentSession(s); - assertEquals(test.getCurrentSession(), s); - } - /** * */ @@ -342,7 +292,6 @@ public class UserDataTest { } /** - * * @throws IOException */ @Test @@ -366,7 +315,6 @@ public class UserDataTest { } /** - * * @throws IOException */ @Test diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/additional/AnalysisTypeTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/additional/AnalysisTypeTest.java index 8d207a246..0d4165f61 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/additional/AnalysisTypeTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/additional/AnalysisTypeTest.java @@ -6,11 +6,11 @@ package test.java.main.java.com.djrapitops.plan.data.additional; import main.java.com.djrapitops.plan.data.additional.AnalysisType; -import static org.junit.Assert.*; import org.junit.Test; +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ public class AnalysisTypeTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/DataCacheHandlerTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/DataCacheHandlerTest.java index e3ce13a20..d50ed8847 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/DataCacheHandlerTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/DataCacheHandlerTest.java @@ -5,11 +5,6 @@ */ package test.java.main.java.com.djrapitops.plan.data.cache; -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; @@ -26,20 +21,25 @@ import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; +import test.java.utils.TestInit; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.powermock.api.mockito.PowerMockito.when; -import test.java.utils.TestInit; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @PrepareForTest(JavaPlugin.class) public class DataCacheHandlerTest { - private Plan plan; private Database db; private DataCacheHandler handler; private boolean calledSaveCommandUse; @@ -58,7 +58,7 @@ public class DataCacheHandlerTest { @Before public void setUp() throws Exception { TestInit t = TestInit.init(); - plan = t.getPlanMock(); + Plan plan = t.getPlanMock(); calledSaveCommandUse = false; calledSaveUserData = false; db = new SQLiteDB(plan, "debug" + MiscUtils.getTime()) { @@ -73,7 +73,7 @@ public class DataCacheHandlerTest { } @Override - public HashMap getCommandUse() { + public Map getCommandUse() { return new HashMap<>(); } @@ -116,7 +116,6 @@ public class DataCacheHandlerTest { } /** - * * @throws SQLException */ @After @@ -125,7 +124,6 @@ public class DataCacheHandlerTest { } /** - * * @throws SQLException * @throws InterruptedException */ @@ -135,19 +133,13 @@ public class DataCacheHandlerTest { // db.init(); UserData data = MockUtils.mockUser(); db.saveUserData(data); - handler.getUserDataForProcessing(new DBCallableProcessor() { - @Override - public void process(UserData d) { - assertTrue(d.equals(data)); - } - }, data.getUuid()); + handler.getUserDataForProcessing(d -> assertTrue(d.equals(data)), data.getUuid()); Thread.sleep(1000); assertTrue(handler.getDataCache().containsKey(data.getUuid())); assertTrue(handler.getDataCache().get(data.getUuid()).equals(data)); } /** - * * @throws SQLException * @throws InterruptedException */ @@ -156,12 +148,7 @@ public class DataCacheHandlerTest { public void testGetUserDataForProcessingDontCache() throws SQLException, InterruptedException { UserData data = MockUtils.mockUser(); db.saveUserData(data); - handler.getUserDataForProcessing(new DBCallableProcessor() { - @Override - public void process(UserData d) { - assertTrue(d.equals(data)); - } - }, data.getUuid(), false); + handler.getUserDataForProcessing(d -> assertTrue(d.equals(data)), data.getUuid(), false); Thread.sleep(1000); assertTrue(!handler.getDataCache().containsKey(data.getUuid())); assertTrue(handler.getDataCache().get(data.getUuid()) == null); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java index b81e99127..9815f778d 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java @@ -5,7 +5,6 @@ */ package test.java.main.java.com.djrapitops.plan.data.cache; -import java.util.UUID; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.SessionCache; @@ -16,11 +15,13 @@ import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; -import static org.junit.Assert.assertTrue; import test.java.utils.TestInit; +import java.util.UUID; + +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -40,7 +41,7 @@ public class SessionCacheTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); test = new SessionCache(); } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheClearQueueTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheClearQueueTest.java index 7270964dd..b84013953 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheClearQueueTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheClearQueueTest.java @@ -18,16 +18,12 @@ import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.TestInit; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @PrepareForTest({JavaPlugin.class}) public class DataCacheClearQueueTest { - private Plan plan; - private DataCacheHandler handler; - /** * */ @@ -40,8 +36,8 @@ public class DataCacheClearQueueTest { @Before public void setUp() throws Exception { TestInit t = TestInit.init(); - plan = t.getPlanMock(); - handler = new DataCacheHandler(plan) { + Plan plan = t.getPlanMock(); + DataCacheHandler handler = new DataCacheHandler(plan) { @Override public boolean getCommandUseFromDb() { return true; diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueueTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueueTest.java index a02444d03..0861f37dc 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueueTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheGetQueueTest.java @@ -36,7 +36,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -54,7 +53,6 @@ public class DataCacheGetQueueTest { } /** - * * @throws IOException * @throws Exception */ @@ -91,7 +89,6 @@ public class DataCacheGetQueueTest { } /** - * * @throws IOException * @throws SQLException */ @@ -115,12 +112,7 @@ public class DataCacheGetQueueTest { UserData exp = MockUtils.mockUser2(); DataCacheGetQueue instance = new DataCacheGetQueue(plan); - instance.scheduleForGet(exp.getUuid(), new DBCallableProcessor() { - @Override - public void process(UserData data) { - assertTrue(data.equals(exp)); - } - }); + instance.scheduleForGet(exp.getUuid(), (DBCallableProcessor) data -> assertTrue(data.equals(exp))); } /** @@ -131,11 +123,6 @@ public class DataCacheGetQueueTest { public void testStop() { DataCacheGetQueue instance = new DataCacheGetQueue(plan); instance.stop(); - instance.scheduleForGet(MockUtils.getPlayerUUID(), new DBCallableProcessor() { - @Override - public void process(UserData data) { - fail("Called get process after stop."); - } - }); + instance.scheduleForGet(MockUtils.getPlayerUUID(), (DBCallableProcessor) data -> fail("Called get process after stop.")); } } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueueTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueueTest.java index 24c63acf6..fd6613001 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueueTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheProcessQueueTest.java @@ -5,9 +5,6 @@ */ package test.java.main.java.com.djrapitops.plan.data.cache.queue; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; @@ -17,7 +14,6 @@ import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; import main.java.com.djrapitops.plan.data.handling.info.InfoType; import org.bukkit.plugin.java.JavaPlugin; import org.junit.After; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -27,8 +23,14 @@ import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; import test.java.utils.TestInit; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -48,7 +50,7 @@ public class DataCacheProcessQueueTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); handler = new DataCacheHandler(Plan.getInstance()) { @Override public boolean getCommandUseFromDb() { @@ -84,7 +86,6 @@ public class DataCacheProcessQueueTest { } /** - * * @throws InterruptedException */ @Ignore("Scheduler") @@ -105,7 +106,6 @@ public class DataCacheProcessQueueTest { } /** - * * @throws InterruptedException */ @Ignore("Scheduler") @@ -130,7 +130,6 @@ public class DataCacheProcessQueueTest { } /** - * * @throws InterruptedException */ @Ignore("Inconsistant") diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueueTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueueTest.java index eb0312559..3ead38450 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueueTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/cache/queue/DataCacheSaveQueueTest.java @@ -5,7 +5,6 @@ */ package test.java.main.java.com.djrapitops.plan.data.cache.queue; -import java.sql.SQLException; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.database.Database; @@ -19,19 +18,19 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import static org.powermock.api.mockito.PowerMockito.when; import test.java.utils.TestInit; +import java.sql.SQLException; + +import static org.powermock.api.mockito.PowerMockito.when; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @PrepareForTest({JavaPlugin.class}) public class DataCacheSaveQueueTest { - private Plan plan; - private Database db; private boolean calledSaveUserData; private boolean calledSaveUserData2; @@ -47,10 +46,10 @@ public class DataCacheSaveQueueTest { @Before public void setUp() throws Exception { TestInit t = TestInit.init(); - plan = t.getPlanMock(); + Plan plan = t.getPlanMock(); calledSaveUserData = false; calledSaveUserData2 = false; - db = new SQLiteDB(plan, "debug" + MiscUtils.getTime()) { + Database db = new SQLiteDB(plan, "debug" + MiscUtils.getTime()) { @Override public void startConnectionPingTask() { @@ -62,7 +61,6 @@ public class DataCacheSaveQueueTest { calledSaveUserData2 = true; } calledSaveUserData = true; - } }; when(plan.getDB()).thenReturn(db); @@ -76,7 +74,6 @@ public class DataCacheSaveQueueTest { } /** - * * @throws InterruptedException */ @Ignore @@ -90,7 +87,6 @@ public class DataCacheSaveQueueTest { } /** - * * @throws InterruptedException */ @Ignore("Inconsistant") @@ -109,7 +105,6 @@ public class DataCacheSaveQueueTest { } /** - * * @throws InterruptedException */ @Ignore @@ -136,7 +131,6 @@ public class DataCacheSaveQueueTest { } /** - * * @throws InterruptedException */ @Ignore diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/ChatHandlingTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/ChatHandlingTest.java index 352a1b8d3..7a7d46dfe 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/ChatHandlingTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/ChatHandlingTest.java @@ -8,7 +8,6 @@ package test.java.main.java.com.djrapitops.plan.data.handling; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.ChatHandling; import org.bukkit.plugin.java.JavaPlugin; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,8 +16,9 @@ import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; import test.java.utils.TestInit; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -36,7 +36,7 @@ public class ChatHandlingTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); } /** @@ -46,7 +46,7 @@ public class ChatHandlingTest { public void testProcessChatInfoAddedNickname() { UserData data = MockUtils.mockUser2(); String expected = "TestNicknameChatHandling"; - ChatHandling.processChatInfo(data, expected, ""); + ChatHandling.processChatInfo(data, expected); assertTrue("Didn't add nickname", data.getNicknames().contains(expected)); } } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/GamemodeHandlingTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/GamemodeHandlingTest.java deleted file mode 100644 index d172a7e17..000000000 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/GamemodeHandlingTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package test.java.main.java.com.djrapitops.plan.data.handling; - -import com.djrapitops.plugin.utilities.player.Gamemode; -import main.java.com.djrapitops.plan.data.UserData; -import main.java.com.djrapitops.plan.data.handling.GamemodeHandling; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; -import test.java.utils.MockUtils; - -/** - * - * @author Rsl1122 - */ -public class GamemodeHandlingTest { - - /** - * - */ - public GamemodeHandlingTest() { - } - - /** - * - */ - @Before - public void setUp() throws Exception { - } - - /** - * - */ - @Test - public void testProcessGamemodeInfo() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("CREATIVE"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeHandling.processGamemodeInfo(data, time, Gamemode.SURVIVAL); - Long result = data.getGmTimes().get(Gamemode.CREATIVE.name()); - assertTrue("Gamemode time was " + result, result == 1050L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 1100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 2000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", lastGM.equals("SURVIVAL")); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 1100L); - } - - /** - * - */ - @Test - public void testProcessGamemodeInfoSameGM() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("SURVIVAL"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeHandling.processGamemodeInfo(data, time, Gamemode.SURVIVAL); - Long result = data.getGmTimes().get(Gamemode.SURVIVAL.name()); - assertTrue("Gamemode time was " + result, result == 1050L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 1100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 2000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", "SURVIVAL".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 1100L); - } - - /** - * - */ - @Test - public void testProcessGamemodeInfoNullNewGM() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("SURVIVAL"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeHandling.processGamemodeInfo(data, time, null); - Long result = data.getGmTimes().get(Gamemode.SURVIVAL.name()); - assertTrue("Gamemode time was " + result, result == 0L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 1000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", "SURVIVAL".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 50L); - } - - /** - * - */ - @Test - public void testProcessGamemodeInfoNullOldGM() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode(null); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeHandling.processGamemodeInfo(data, time, Gamemode.SURVIVAL); - Long result = data.getGmTimes().get(Gamemode.SURVIVAL.name()); - assertTrue("Gamemode time was " + result, result == 1050L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 1100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 2000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", "SURVIVAL".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 1100L); - } - - /** - * - */ - @Test - public void testProcessGamemodeInfoNullGMTimes() { - UserData data = MockUtils.mockUser(); - data.setGmTimes(null); - data.setPlayTime(100L); - data.setLastGamemode(null); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeHandling.processGamemodeInfo(data, time, Gamemode.SURVIVAL); - Long result = data.getGmTimes().get(Gamemode.SURVIVAL.name()); - assertTrue("Gamemode time was " + result, result == 1050L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 1100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 2000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", "SURVIVAL".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 1100L); - } - -} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/KillHandlingTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/KillHandlingTest.java index 0fd8a69a6..6663fea02 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/KillHandlingTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/KillHandlingTest.java @@ -12,6 +12,7 @@ import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.KillHandling; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.database.databases.SQLiteDB; +import main.java.com.djrapitops.plan.database.tables.UsersTable; import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -26,13 +27,13 @@ import test.java.utils.TestInit; import java.io.IOException; import java.sql.SQLException; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.powermock.api.mockito.PowerMockito.when; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -64,12 +65,24 @@ public class KillHandlingTest { public void convertBukkitDataToDB() { } + + @Override + public UsersTable getUsersTable() { + return new UsersTable(null, false) { + @Override + public int getUserId(UUID uuid) { + if (uuid.equals(MockUtils.getPlayerUUID())) { + return -1; + } + return 1; + } + }; + } }; when(plan.getDB()).thenReturn(db); } /** - * * @throws SQLException */ @After @@ -78,15 +91,12 @@ public class KillHandlingTest { } /** - * * @throws SQLException */ @Test public void testProcessKillInfoPlayer() throws SQLException { UserData data = MockUtils.mockUser(); IPlayer dead = MockUtils.mockIPlayer2(); - db.init(); - db.saveUserData(new UserData(dead)); KillHandling.processKillInfo(data, 10L, (Player) dead.getWrappedPlayerClass(), "TestWeapon"); KillData expected = new KillData(dead.getUuid(), 1, "TestWeapon", 10L); assertTrue("Didn't add the kill", data.getPlayerKills().size() == 1); @@ -98,21 +108,18 @@ public class KillHandlingTest { } /** - * * @throws SQLException * @throws IOException */ @Test public void testProcessKillInfoException() throws SQLException, IOException { - db.init(); - UserData data = MockUtils.mockUser(); - Player dead = (Player) MockUtils.mockIPlayer2().getWrappedPlayerClass(); + UserData data = MockUtils.mockUser2(); + Player dead = (Player) MockUtils.mockIPlayer().getWrappedPlayerClass(); KillHandling.processKillInfo(data, 10L, dead, "TestWeapon"); assertTrue("Added the kill", data.getPlayerKills().isEmpty()); } /** - * * @throws SQLException */ @Test diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LoginHandlingTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LoginHandlingTest.java index d986bdf97..4ecd60903 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LoginHandlingTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LoginHandlingTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -45,7 +44,6 @@ public class LoginHandlingTest { } /** - * * @throws UnknownHostException */ @Test @@ -68,7 +66,6 @@ public class LoginHandlingTest { } /** - * * @throws UnknownHostException */ @Test diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LogoutHandlingTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LogoutHandlingTest.java index db4d0b90d..3c15e98bd 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LogoutHandlingTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/LogoutHandlingTest.java @@ -7,13 +7,13 @@ package test.java.main.java.com.djrapitops.plan.data.handling; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.LogoutHandling; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import test.java.utils.MockUtils; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class LogoutHandlingTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ChatInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ChatInfoTest.java index 7e5f393cb..8116986e9 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ChatInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ChatInfoTest.java @@ -7,13 +7,13 @@ package test.java.main.java.com.djrapitops.plan.data.handling.info; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.ChatInfo; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import test.java.utils.MockUtils; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class ChatInfoTest { @@ -32,19 +32,8 @@ public class ChatInfoTest { public void testProcessNick() { UserData data = MockUtils.mockUser(); String expected = "TestNicknameChatInfo"; - ChatInfo i = new ChatInfo(data.getUuid(), expected, "im 18 male"); + ChatInfo i = new ChatInfo(data.getUuid(), expected); assertTrue("Didn't succeed", i.process(data)); assertTrue("Didn't add nickname", data.getNicknames().contains(expected)); } - - /** - * - */ - @Test - public void testProcessWrongUUID() { - UserData data = MockUtils.mockUser(); - String expected = "TestNicknameChatInfo"; - ChatInfo i = new ChatInfo(null, expected, "im 18 male"); - assertTrue("Succeeded.", !i.process(data)); - } } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/DeathInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/DeathInfoTest.java index 84dd699de..3f2556173 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/DeathInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/DeathInfoTest.java @@ -7,13 +7,14 @@ package test.java.main.java.com.djrapitops.plan.data.handling.info; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.DeathInfo; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import test.java.utils.MockUtils; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class DeathInfoTest { @@ -41,16 +42,4 @@ public class DeathInfoTest { assertTrue(i.process(data)); assertEquals(1, data.getDeaths()); } - - /** - * - */ - @Test - public void testProcessWrongUUID() { - UserData data = MockUtils.mockUser(); - DeathInfo i = new DeathInfo(null); - assertTrue(!i.process(data)); - assertEquals(0, data.getDeaths()); - } - } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfoTest.java deleted file mode 100644 index f83d695bc..000000000 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/GamemodeInfoTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package test.java.main.java.com.djrapitops.plan.data.handling.info; - -import com.djrapitops.plugin.utilities.player.Gamemode; -import main.java.com.djrapitops.plan.data.UserData; -import main.java.com.djrapitops.plan.data.handling.info.GamemodeInfo; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; -import test.java.utils.MockUtils; - -/** - * - * @author Rsl1122 - */ -public class GamemodeInfoTest { - - /** - * - */ - public GamemodeInfoTest() { - } - - /** - * - */ - @Before - public void setUp() throws Exception { - } - - /** - * - */ - @Test - public void testProcess() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("CREATIVE"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeInfo i = new GamemodeInfo(data.getUuid(), time, Gamemode.SURVIVAL); - assertTrue(i.process(data)); - Long result = data.getGmTimes().get(Gamemode.CREATIVE.name()); - assertTrue("Gamemode time was " + result, result == 1050L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 1100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 2000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Survival", "SURVIVAL".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 1100L); - } - - /** - * - */ - @Test - public void testProcessWrongUUID() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("CREATIVE"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeInfo i = new GamemodeInfo(null, time, Gamemode.SURVIVAL); - assertTrue(!i.process(data)); - Long result = data.getGmTimes().get(Gamemode.CREATIVE.name()); - assertTrue("Gamemode time was " + result, result == 0L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 1000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Creative", "CREATIVE".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 50L); - } - - /** - * - */ - @Test - public void testProcessNullGM() { - UserData data = MockUtils.mockUser(); - data.setPlayTime(100L); - data.setLastGamemode("CREATIVE"); - data.setLastGmSwapTime(50L); - data.setLastPlayed(1000L); - long time = 2000L; - GamemodeInfo i = new GamemodeInfo(data.getUuid(), time, null); - assertTrue(!i.process(data)); - Long result = data.getGmTimes().get(Gamemode.CREATIVE.name()); - assertTrue("Gamemode time was " + result, result == 0L); - result = data.getPlayTime(); - assertTrue("Playtime was" + result, result == 100L); - result = data.getLastPlayed(); - assertTrue("Last Played was" + result, result == 1000L); - String lastGM = data.getLastGamemode(); - assertTrue("Last gm not Creative", "CREATIVE".equals(lastGM)); - result = data.getLastGmSwapTime(); - assertTrue("Last swaptime was " + result, result == 50L); - } - -} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/HandlingInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/HandlingInfoTest.java index f2a808570..428ae0cf6 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/HandlingInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/HandlingInfoTest.java @@ -5,15 +5,16 @@ */ package test.java.main.java.com.djrapitops.plan.data.handling.info; -import java.util.UUID; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; import main.java.com.djrapitops.plan.data.handling.info.InfoType; -import static org.junit.Assert.assertEquals; import org.junit.Test; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ public class HandlingInfoTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/InfoUuidCorrectionTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/InfoUuidCorrectionTest.java new file mode 100644 index 000000000..0662d2dcf --- /dev/null +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/InfoUuidCorrectionTest.java @@ -0,0 +1,33 @@ +package test.java.main.java.com.djrapitops.plan.data.handling.info; + +import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.handling.info.*; +import main.java.com.djrapitops.plan.utilities.MiscUtils; +import org.junit.Test; +import test.java.utils.MockUtils; + +import java.util.UUID; + +import static org.junit.Assert.assertTrue; + +public class InfoUuidCorrectionTest { + private final UserData wrong = MockUtils.mockUser2(); + private final UUID test = MockUtils.getPlayerUUID(); + + @Test + public void testAllInfoBooleanReturn() { + long now = MiscUtils.getTime(); + HandlingInfo[] h = new HandlingInfo[]{ + new ChatInfo(test, ""), + new DeathInfo(test), + new KillInfo(test, now, null, ""), + new LoginInfo(test, now, null, false, "", "", 0, ""), + new LogoutInfo(test, now, false, "", null, ""), + new PlaytimeDependentInfo(test, InfoType.OTHER, now, "", ""), + new ReloadInfo(test, now, null, false, "", "", "") + }; + for (HandlingInfo info : h) { + assertTrue(info.getClass().getSimpleName(), !info.process(wrong)); + } + } +} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KickInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KickInfoTest.java index a01ddb4a3..7aa312247 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KickInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KickInfoTest.java @@ -8,7 +8,6 @@ package test.java.main.java.com.djrapitops.plan.data.handling.info; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.KickInfo; import org.bukkit.plugin.java.JavaPlugin; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,8 +16,10 @@ import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; import test.java.utils.TestInit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -36,7 +37,7 @@ public class KickInfoTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); } /** diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KillInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KillInfoTest.java index a0ca0a5fc..7e4c33f97 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KillInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/KillInfoTest.java @@ -5,30 +5,32 @@ */ package test.java.main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Fetch; -import java.sql.SQLException; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.data.KillData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.KillInfo; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.database.databases.SQLiteDB; +import main.java.com.djrapitops.plan.database.tables.UsersTable; import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -import org.junit.After; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; -import static org.powermock.api.mockito.PowerMockito.when; import test.java.utils.TestInit; +import java.sql.SQLException; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -60,29 +62,30 @@ public class KillInfoTest { public void convertBukkitDataToDB() { } + + @Override + public UsersTable getUsersTable() { + return new UsersTable(null, false) { + @Override + public int getUserId(UUID uuid) { + if (uuid.equals(MockUtils.getPlayerUUID())) { + return 2; + } + return 1; + } + }; + } }; when(plan.getDB()).thenReturn(db); } /** - * - * @throws SQLException - */ - @After - public void tearDown() throws SQLException { - db.close(); - } - - /** - * * @throws SQLException */ @Test public void testProcess() throws SQLException { UserData data = MockUtils.mockUser(); Player dead = MockUtils.mockPlayer2(); - db.init(); - db.saveUserData(new UserData(Fetch.wrapBukkit(dead))); KillInfo i = new KillInfo(data.getUuid(), 10L, dead, "TestWeapon"); assertTrue(i.process(data)); KillData expected = new KillData(dead.getUniqueId(), 1, "TestWeapon", 10L); @@ -95,7 +98,6 @@ public class KillInfoTest { } /** - * * @throws SQLException */ @Test @@ -106,18 +108,4 @@ public class KillInfoTest { assertTrue("Added a kill", data.getPlayerKills().isEmpty()); assertEquals(1, data.getMobKills()); } - - /** - * - * @throws SQLException - */ - @Test - public void testProcessMobKillWrongUUID() throws SQLException { - UserData data = MockUtils.mockUser(); - KillInfo i = new KillInfo(null, 10L, null, "TestWeapon"); - assertTrue(!i.process(data)); - assertTrue("Added a kill", data.getPlayerKills().isEmpty()); - assertEquals(0, data.getMobKills()); - } - } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LoginInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LoginInfoTest.java index 042a8c9f9..6003b0e20 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LoginInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LoginInfoTest.java @@ -5,7 +5,6 @@ */ package test.java.main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.LoginInfo; import org.bukkit.plugin.java.JavaPlugin; @@ -24,7 +23,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -46,7 +44,6 @@ public class LoginInfoTest { } /** - * * @throws UnknownHostException */ @Test @@ -56,7 +53,7 @@ public class LoginInfoTest { long time = 10L; int loginTimes = data.getLoginTimes(); String nick = "TestProcessLoginInfo"; - LoginInfo i = new LoginInfo(data.getUuid(), time, ip, true, nick, Gamemode.CREATIVE, 1); + LoginInfo i = new LoginInfo(data.getUuid(), time, ip, true, nick, "CREATIVE", 1, "World"); assertTrue(i.process(data)); assertTrue("LastPlayed wrong: " + data.getLastPlayed(), data.getLastPlayed() == time); assertTrue("Ip not added", data.getIps().contains(ip)); @@ -65,29 +62,7 @@ public class LoginInfoTest { assertTrue("Nick not last nick", data.getLastNick().equals(nick)); String geo = data.getGeolocation(); assertTrue("Wrong location " + geo, geo.equals("United States")); - assertTrue("Didn't process gamemode", data.getLastGamemode().equals("CREATIVE")); + assertEquals("CREATIVE", data.getGmTimes().getState()); + assertEquals("World", data.getWorldTimes().getState()); } - - /** - * - * @throws UnknownHostException - */ - @Test - public void testProcessWrongUUID() throws UnknownHostException { - UserData data = MockUtils.mockUser(); - data.setLastPlayed(0L); - InetAddress ip = InetAddress.getByName("137.19.188.146"); - long time = 10L; - String nick = "TestProcessLoginInfo"; - LoginInfo i = new LoginInfo(null, time, ip, true, nick, Gamemode.CREATIVE, 1); - assertTrue(!i.process(data)); - assertEquals(0L, data.getLastPlayed()); - assertTrue("Ip not added", !data.getIps().contains(ip)); - assertTrue("Logintimes not +1", data.getLoginTimes() == 0); - assertTrue("Nick not added", !data.getNicknames().contains(nick)); - String geo = data.getGeolocation(); - assertTrue("Wrong location " + geo, geo.equals("Not Known")); - assertTrue("Didn't process gamemode", data.getLastGamemode().equals("SURVIVAL")); - } - } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LogoutInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LogoutInfoTest.java index ec223151f..be53a9dc7 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LogoutInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/LogoutInfoTest.java @@ -5,17 +5,17 @@ */ package test.java.main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.LogoutInfo; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import test.java.utils.MockUtils; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class LogoutInfoTest { @@ -42,39 +42,14 @@ public class LogoutInfoTest { data.setLastPlayed(10L); data.updateBanned(false); long time = 20L; - Exception ex = null; - data.setLastGamemode("SURVIVAL"); - LogoutInfo i = new LogoutInfo(data.getUuid(), time, true, Gamemode.CREATIVE, new SessionData(0, 1)); + data.getGmTimes().setState("SURVIVAL"); + LogoutInfo i = new LogoutInfo(data.getUuid(), time, true, "CREATIVE", new SessionData(0, 1), "World"); assertTrue(i.process(data)); assertTrue("Last Played wrong", data.getLastPlayed() == 20L); assertTrue("Playtime wrong", data.getPlayTime() == 10L); assertTrue("Banned wrong", data.isBanned()); - assertTrue("Didn't process gamemode", data.getLastGamemode().equals("CREATIVE")); + assertEquals("CREATIVE", data.getGmTimes().getState()); + assertEquals("World", data.getWorldTimes().getState()); assertEquals(1, data.getSessions().size()); } - - /** - * - */ - @Test - public void testProcessWrongUUID() { - UserData data = MockUtils.mockUser(); - data.setLastPlayed(10L); - data.updateBanned(false); - long time = 20L; - Exception ex = null; - LogoutInfo i = new LogoutInfo(null, time, true, Gamemode.CREATIVE, new SessionData(0, 1)); - try { - assertTrue(!i.process(data)); - } catch (NullPointerException e) { - ex = e; - } - assertTrue("Caught endSessionException", ex == null); - assertTrue("Last Played wrong", data.getLastPlayed() == 10L); - assertTrue("Playtime wrong", data.getPlayTime() == 0L); - assertTrue("Banned wrong", !data.isBanned()); - assertTrue("Didn't process gamemode", data.getLastGamemode().equals("SURVIVAL")); - assertEquals(0, data.getSessions().size()); - } - } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ReloadInfoTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ReloadInfoTest.java index 9548e4714..b0a10a28f 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ReloadInfoTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/handling/info/ReloadInfoTest.java @@ -5,9 +5,9 @@ */ package test.java.main.java.com.djrapitops.plan.data.handling.info; -import com.djrapitops.plugin.utilities.player.Gamemode; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.handling.info.ReloadInfo; +import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.plugin.java.JavaPlugin; import org.junit.Before; import org.junit.Test; @@ -20,10 +20,10 @@ import test.java.utils.TestInit; import java.net.InetAddress; import java.net.UnknownHostException; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -45,17 +45,16 @@ public class ReloadInfoTest { } /** - * * @throws UnknownHostException */ @Test public void testProcess() throws UnknownHostException { UserData data = MockUtils.mockUser(); InetAddress ip = InetAddress.getByName("137.19.188.146"); - long time = 10L; + long time = MiscUtils.getTime(); int loginTimes = data.getLoginTimes(); String nick = "TestProcessLoginInfo"; - ReloadInfo i = new ReloadInfo(data.getUuid(), time, ip, true, nick, Gamemode.CREATIVE); + ReloadInfo i = new ReloadInfo(data.getUuid(), time, ip, true, nick, "CREATIVE", "World"); assertTrue(i.process(data)); assertTrue("LastPlayed wrong: " + data.getLastPlayed(), data.getLastPlayed() == time); assertTrue("Ip not added", data.getIps().contains(ip)); @@ -64,20 +63,7 @@ public class ReloadInfoTest { assertTrue("Nick not last nick", data.getLastNick().equals(nick)); String geo = data.getGeolocation(); assertTrue("Wrong location " + geo, geo.equals("United States")); - assertTrue("Didn't process gamemode", data.getLastGamemode().equals("CREATIVE")); - } - - /** - * - * @throws UnknownHostException - */ - @Test - public void testProcessWrongUUID() throws UnknownHostException { - UserData data = MockUtils.mockUser(); - InetAddress ip = InetAddress.getByName("137.19.188.146"); - long time = 10L; - String nick = "TestProcessLoginInfo"; - ReloadInfo i = new ReloadInfo(null, time, ip, true, nick, Gamemode.CREATIVE); - assertTrue(!i.process(data)); + assertEquals("CREATIVE", data.getGmTimes().getState()); + assertEquals("World", data.getWorldTimes().getState()); } } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/data/time/GMTimesTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/data/time/GMTimesTest.java new file mode 100644 index 000000000..f934db212 --- /dev/null +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/data/time/GMTimesTest.java @@ -0,0 +1,103 @@ +package test.java.main.java.com.djrapitops.plan.data.time; + +import main.java.com.djrapitops.plan.data.time.GMTimes; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertTrue; + +public class GMTimesTest { + @Test + public void setAllGMTimes() throws Exception { + GMTimes test = new GMTimes(); + test.setAllGMTimes(1L, 2L, 3L, 4L); + Map times = test.getTimes(); + assertTrue(times.get("SURVIVAL") == 1L); + assertTrue(times.get("CREATIVE") == 2L); + assertTrue(times.get("ADVENTURE") == 3L); + assertTrue(times.get("SPECTATOR") == 4L); + } + + @Test + public void setAllGMTimesTooFew() throws Exception { + GMTimes test = new GMTimes(); + test.setAllGMTimes(1L, 2L); + Map times = test.getTimes(); + assertTrue(times.get("SURVIVAL") == 1L); + assertTrue(times.get("CREATIVE") == 2L); + assertTrue(times.get("ADVENTURE") == 0L); + assertTrue(times.get("SPECTATOR") == 0L); + } + + @Test + public void setAllGMTimesTooMany() throws Exception { + GMTimes test = new GMTimes(); + test.setAllGMTimes(1L, 2L, 3L, 4L, 5L, 6L); + Map times = test.getTimes(); + assertTrue(times.get("SURVIVAL") == 1L); + assertTrue(times.get("CREATIVE") == 2L); + assertTrue(times.get("ADVENTURE") == 3L); + assertTrue(times.get("SPECTATOR") == 4L); + } + + @Test + public void resetTimes() throws Exception { + GMTimes test = new GMTimes(); + test.setAllGMTimes(4, 3, 2, 1); + test.resetTimes(10); + assertTrue(10L == test.getTime("SURVIVAL")); + assertTrue(0L == test.getTime("ADVENTURE")); + } + + @Test + public void setTime() throws Exception { + GMTimes test = new GMTimes(); + test.setTime("SURVIVAL", 5L); + assertTrue(5L == test.getTime("SURVIVAL")); + } + + @Test + public void renameState() throws Exception { + GMTimes test = new GMTimes(); + test.setAllGMTimes(5L); + test.renameState("SURVIVAL", "Survival"); + assertTrue(0L == test.getTime("SURVIVAL")); + assertTrue(5L == test.getTime("Survival")); + } + + @Test + public void changeStateNormal() throws Exception { + GMTimes test = new GMTimes(new HashMap<>(), "SURVIVAL", 0); + test.changeState("CREATIVE", 5L); + assertTrue(5L == test.getTime("SURVIVAL")); + assertTrue(0L == test.getTime("CREATIVE")); + test.changeState("ADVENTURE", 20L); + assertTrue(5L == test.getTime("SURVIVAL")); + assertTrue(15L == test.getTime("CREATIVE")); + assertTrue(0L == test.getTime("ADVENTURE")); + } + + @Test + public void changeStateMissingStartTime() throws Exception { + GMTimes test = new GMTimes("SURVIVAL"); + test.changeState("CREATIVE", 5L); + assertTrue(5L == test.getTime("SURVIVAL")); + assertTrue(0L == test.getTime("CREATIVE")); + test.changeState("ADVENTURE", 20L); + assertTrue(5L == test.getTime("SURVIVAL")); + assertTrue(15L == test.getTime("CREATIVE")); + assertTrue(0L == test.getTime("ADVENTURE")); + } + + @Test + public void changeStateMissingStartState() throws Exception { + GMTimes test = new GMTimes(); + test.changeState("CREATIVE", 5L); + assertTrue(5L == test.getTime("CREATIVE")); + test.changeState("ADVENTURE", 20L); + assertTrue(20L == test.getTime("CREATIVE")); + assertTrue(0L == test.getTime("ADVENTURE")); + } +} \ No newline at end of file diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/database/DBUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/database/DBUtilsTest.java index 425a7c476..7d954173a 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/database/DBUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/database/DBUtilsTest.java @@ -19,7 +19,6 @@ import java.util.Map; import static org.junit.Assert.assertEquals; /** - * * @author ristolah */ public class DBUtilsTest { diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/database/DatabaseTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/database/DatabaseTest.java index d41791af3..b8ed1fad1 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/database/DatabaseTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/database/DatabaseTest.java @@ -11,6 +11,8 @@ import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.TPS; import main.java.com.djrapitops.plan.data.UserData; import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor; +import main.java.com.djrapitops.plan.data.time.GMTimes; +import main.java.com.djrapitops.plan.data.time.WorldTimes; import main.java.com.djrapitops.plan.database.Database; import main.java.com.djrapitops.plan.database.databases.MySQLDB; import main.java.com.djrapitops.plan.database.databases.SQLiteDB; @@ -48,7 +50,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -67,7 +68,6 @@ public class DatabaseTest { } /** - * * @throws IOException * @throws Exception */ @@ -94,7 +94,6 @@ public class DatabaseTest { } /** - * * @throws IOException * @throws SQLException */ @@ -177,7 +176,6 @@ public class DatabaseTest { } /** - * * @throws SQLException */ @Test @@ -198,7 +196,6 @@ public class DatabaseTest { } /** - * * @throws SQLException */ @Test @@ -224,19 +221,28 @@ public class DatabaseTest { } /** - * * @throws SQLException */ @Test public void testSaveUserData() throws SQLException { db.init(); UserData data = MockUtils.mockUser(); + GMTimes gmTimes = data.getGmTimes(); + gmTimes.setAllGMTimes(5L, 10L, 15L, 20L); + gmTimes.setState("SURVIVAL"); + gmTimes.setLastStateChange(10L); + WorldTimes worldTimes = data.getWorldTimes(); + worldTimes.setTime("World", 20L); + worldTimes.setState("World"); + worldTimes.setLastStateChange(10L); 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)); } }; @@ -244,7 +250,6 @@ public class DatabaseTest { } /** - * * @throws SQLException */ @Test @@ -259,7 +264,6 @@ public class DatabaseTest { } /** - * * @throws SQLException * @throws java.net.UnknownHostException */ @@ -267,6 +271,8 @@ public class DatabaseTest { public void testSaveMultipleUserData() throws SQLException, UnknownHostException { db.init(); UserData data = MockUtils.mockUser(); + data.getGmTimes().setAllGMTimes(5L, 10L, 15L, 20L); + data.getWorldTimes().setTime("World", 20L); data.addIpAddress(InetAddress.getByName("185.64.113.61")); data.addSession(new SessionData(1286349L, 2342978L)); data.addNickname("TestNick"); @@ -277,6 +283,7 @@ public class DatabaseTest { System.out.println(data.toString()); data.addNickname("TestUpdateForSave"); UserData data2 = MockUtils.mockUser2(); + data2.getGmTimes().setAllGMTimes(5L, 10L, 15L, 20L); data2.addNickname("Alright"); data.addNickname("TestNick2"); data2.addIpAddress(InetAddress.getByName("185.64.113.60")); @@ -287,28 +294,17 @@ public class DatabaseTest { list.add(data2); db.saveMultipleUserData(list); data.addPlayerKill(new KillData(MockUtils.getPlayer2UUID(), 2, "DiamondSword", 75843759L)); - DBCallableProcessor process = new DBCallableProcessor() { - @Override - public void process(UserData d) { - System.out.println("\n" + data.toString()); - System.out.println(d.toString()); - assertTrue("Not Equals", data.equals(d)); - } - }; - db.giveUserDataToProcessors(data.getUuid(), process); - DBCallableProcessor process2 = new DBCallableProcessor() { - @Override - public void process(UserData d) { - System.out.println("\n" + data2.toString()); - System.out.println(d.toString()); - assertTrue("Not Equals", data2.equals(d)); - } - }; - db.giveUserDataToProcessors(data2.getUuid(), process2); + List userDataForUUIDS = db.getUserDataForUUIDS(MockUtils.getUUIDs()); + + System.out.println("\nData1:" + data.toString()); + System.out.println("Data2:" + data2.toString() + "\n"); + for (UserData uData : userDataForUUIDS) { + System.out.println("uData:" + uData.toString()); + assertTrue("Not Equals", (data.equals(uData) || data2.equals(uData))); + } } /** - * * @throws SQLException */ @Test @@ -321,10 +317,10 @@ public class DatabaseTest { } /** - * * @throws SQLException */ @Test + @Ignore("Backup has to be rewritten") public void testBackup() throws SQLException { db.init(); UserData data = MockUtils.mockUser(); @@ -352,11 +348,11 @@ public class DatabaseTest { } /** - * * @throws SQLException */ // Big test because @Test + @Ignore("Backup has to be rewritten") public void testRestore() throws SQLException { db.init(); UserData data = MockUtils.mockUser(); @@ -401,13 +397,20 @@ public class DatabaseTest { TPSTable tpsTable = db.getTpsTable(); List expected = new ArrayList<>(); Random r = new Random(); + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); int availableProcessors = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); final double averageCPUUsage = MathUtils.round(operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0); - expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); + + final long usedMemory = 51231251254L; + final int entityCount = 6123; + final int chunksLoaded = 2134; + + expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(r.nextLong(), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + tpsTable.saveTPSData(expected); assertEquals(expected, tpsTable.getTPSData()); } @@ -420,14 +423,21 @@ public class DatabaseTest { List expected = new ArrayList<>(); Random r = new Random(); long now = System.currentTimeMillis(); + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); int availableProcessors = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); final double averageCPUUsage = MathUtils.round(operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0); - expected.add(new TPS(now, r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(now - 1000L, r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(now - 3000L, r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - expected.add(new TPS(now - (690000L * 1000L), r.nextDouble(), r.nextInt(100000000), averageCPUUsage)); - TPS tooOldTPS = new TPS(now - (691400L * 1000L), r.nextDouble(), r.nextInt(100000000), averageCPUUsage); + + final long usedMemory = 51231251254L; + final int entityCount = 6123; + final int chunksLoaded = 2134; + + expected.add(new TPS(now, r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(now - 1000L, r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(now - 3000L, r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + expected.add(new TPS(now - (690000L * 1000L), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded)); + TPS tooOldTPS = new TPS(now - (691400L * 1000L), r.nextDouble(), r.nextInt(100000000), averageCPUUsage, usedMemory, entityCount, chunksLoaded); + expected.add(tooOldTPS); tpsTable.saveTPSData(expected); tpsTable.clean(); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/HtmlTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/HtmlTest.java index 7c3a76f1d..47248be64 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/HtmlTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/HtmlTest.java @@ -6,11 +6,12 @@ package test.java.main.java.com.djrapitops.plan.ui; import main.java.com.djrapitops.plan.ui.html.Html; -import static org.junit.Assert.*; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ public class HtmlTest { @@ -25,7 +26,7 @@ public class HtmlTest { * */ @Test - public void testParse_0args() { + public void testParseWithZeroArgs() { Html instance = Html.REPLACE0; String expResult = "REPLACE0"; String result = instance.parse(); @@ -36,7 +37,7 @@ public class HtmlTest { * */ @Test - public void testParse_StringArr() { + public void testParseStringArr() { Html instance = Html.REPLACE0; String expResult = "Test"; String result = instance.parse(expResult); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java index 71d4c9587..ea2a8cb6e 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java @@ -2,8 +2,6 @@ package test.java.main.java.com.djrapitops.plan.ui.graphs; import main.java.com.djrapitops.plan.data.SessionData; import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; import java.util.ArrayList; import java.util.Date; @@ -15,13 +13,6 @@ import java.util.Random; */ public class PlayerActivityGraphCreatorTest { - /** - * - */ - @Before - public void setUp() throws Exception { - } - /** * */ @@ -47,34 +38,7 @@ public class PlayerActivityGraphCreatorTest { /** * */ - @Test - @Ignore("Outdated") - public void testFilterSessions() { - List test = new ArrayList<>(); - SessionData invalid = new SessionData(0); - test.add(invalid); - long now = 10000L; - long nowMinusScale = now - 3000L; - SessionData valid1 = new SessionData(9000L, 11000L); - test.add(valid1); - SessionData valid2 = new SessionData(8000L, 10000L); - test.add(valid2); - SessionData valid3 = new SessionData(7000L, 9000L); - test.add(valid3); - SessionData invalid2 = new SessionData(5000L, 5500L); - test.add(invalid2); -// List> result = PlayerActivityGraphCreator.filterAndTransformSessions(test, nowMinusScale); -// List starts = result.get(0); -// List ends = result.get(1); -// assertTrue("Contained invalid session" + starts, !starts.contains(invalid.getSessionStart())); -// assertTrue("Contained invalid session" + starts, !starts.contains(invalid2.getSessionStart())); -// assertTrue("Contained invalid session" + ends, !ends.contains(invalid2.getSessionEnd())); -// assertTrue("Contained invalid session" + ends, !ends.contains(invalid2.getSessionEnd())); -// assertTrue("Did not contain valid session" + starts, starts.contains(valid1.getSessionStart())); -// assertTrue("Did not contain valid session" + ends, ends.contains(valid1.getSessionEnd())); -// assertTrue("Did not contain valid session" + starts, starts.contains(valid2.getSessionStart())); -// assertTrue("Did not contain valid session" + ends, ends.contains(valid2.getSessionEnd())); -// assertTrue("Did not contain valid session" + starts, starts.contains(valid3.getSessionStart())); -// assertTrue("Did not contain valid session" + ends, ends.contains(valid3.getSessionEnd())); + @Before + public void setUp() throws Exception { } } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java index 574c0371a..4e34b2116 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java @@ -18,32 +18,32 @@ import java.util.Date; import static org.junit.Assert.*; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @PrepareForTest(JavaPlugin.class) public class FormatUtilsTest { - /** - * - */ - @Before - public void setUp() { - } - /** * */ public FormatUtilsTest() { } + /** + * + */ + @Before + public void setUp() throws Exception{ + TestInit.init(); + } + /** * */ @Test public void testFormatTimeAmount() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); long second = 1000L; String expResult = "1s"; String result = FormatUtils.formatTimeAmount(second); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java index 8f2120562..7ec73baa8 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java @@ -14,14 +14,12 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.TestInit; -import java.io.FileNotFoundException; import java.util.HashMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -42,14 +40,13 @@ public class HtmlUtilsTest { } /** - * * @throws Exception */ @Test public void testGetHtmlStringFromResource() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); String fileName = "player.html"; - String result = HtmlUtils.getHtmlStringFromResource(fileName); + String result = HtmlUtils.getStringFromResource(fileName); assertTrue("Result empty", !result.isEmpty()); } @@ -78,30 +75,6 @@ public class HtmlUtilsTest { assertEquals(result, exp); } - /** - * - * @throws FileNotFoundException - */ - @Test - public void testGetServerAnalysisUrl() throws Exception { - TestInit.init(); - String result = HtmlUtils.getServerAnalysisUrlWithProtocol(); - String exp = "http://0.0.0.0:8804/server"; - assertEquals(exp, result); - } - - /** - * - */ - @Test - public void testGetInspectUrl() throws Exception { - TestInit.init(); - String playerName = "Test"; - String expResult = "http://0.0.0.0:8804/player/Test"; - String result = HtmlUtils.getInspectUrlWithProtocol(playerName); - assertEquals(expResult, result); - } - /** * */ diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/ManageUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/ManageUtilsTest.java deleted file mode 100644 index 61c5187d6..000000000 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/ManageUtilsTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package test.java.main.java.com.djrapitops.plan.utilities; - -import main.java.com.djrapitops.plan.data.SessionData; -import main.java.com.djrapitops.plan.utilities.ManageUtils; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.java.utils.TestInit; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({JavaPlugin.class}) -public class ManageUtilsTest { - - private final int threshold = 5000; - - /** - * - */ - public ManageUtilsTest() { - } - - /** - * - * @throws IOException - * @throws Exception - */ - @Before - public void setUp() throws Exception { - TestInit t = TestInit.init(); - } - - /** - * - */ - @Test - public void testContainsCombinable() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold - 100, threshold * 2)); - data.add(new SessionData(threshold * 2 + 100, threshold * 3)); - assertTrue(ManageUtils.containsCombinable(data)); - } - - /** - * - */ - @Test - public void testContainsCombinableFalse() { - List data = new ArrayList<>(); - data.add(new SessionData(0, threshold)); - data.add(new SessionData(threshold * 3, threshold * 4)); - assertTrue(!ManageUtils.containsCombinable(data)); - } - - /** - * - */ - @Test - public void testContainsCombinableFalse2() { - List data = new ArrayList<>(); - data.add(new SessionData(0, threshold * 2)); - data.add(new SessionData(threshold * 3, threshold * 4)); - assertTrue(!ManageUtils.containsCombinable(data)); - } - - /** - * - */ - @Test - public void testContainsCombinableFalse3() { - List data = new ArrayList<>(); - data.add(new SessionData(0, threshold * 2)); - data.add(new SessionData(threshold * 3 + 200, threshold * 4)); - assertTrue(!ManageUtils.containsCombinable(data)); - } - - /** - * - */ - @Test - public void testCombineSessions() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold, threshold * 2)); - data.add(new SessionData(threshold * 2 + 100, threshold * 3)); - SessionData get = ManageUtils.combineSessions(data, 1).get(0); - SessionData exp = new SessionData(0, threshold * 3); - assertEquals(exp, get); - } - - /** - * - */ - @Test - public void testCombineSessions2() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold, threshold * 2)); - data.add(new SessionData(threshold * 2 + 100, threshold * 3)); - data.add(new SessionData(threshold * 3 + 200, threshold * 4)); - SessionData get = ManageUtils.combineSessions(data, 1).get(0); - SessionData exp = new SessionData(0, threshold * 4); - assertEquals(exp, get); - } - - /** - * - */ - @Test - public void testCombineSessions3() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold, threshold * 2)); - data.add(new SessionData(threshold * 3 + 200, threshold * 4)); - List result = ManageUtils.combineSessions(data, 2); - SessionData exp = new SessionData(0, threshold * 2); - assertEquals(exp, result.get(0)); - SessionData exp2 = new SessionData(threshold * 3 + 200, threshold * 4); - assertEquals(exp2, result.get(1)); - } - - /** - * - */ - @Test - public void testCombineSessions4() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold, threshold * 2)); - data.add(new SessionData(threshold * 3 + 200, threshold * 4)); - data.add(new SessionData(threshold * 5 - 200, threshold * 5)); - List result = ManageUtils.combineSessions(data, 2); - SessionData exp = new SessionData(0, threshold * 2); - assertEquals(exp, result.get(0)); - SessionData exp2 = new SessionData(threshold * 3 + 200, threshold * 5); - assertEquals(exp2, result.get(1)); - } - - /** - * - */ - @Test - public void testCombineSessions5() { - List data = new ArrayList<>(); - data.add(new SessionData(0, 100)); - data.add(new SessionData(threshold, threshold * 2)); - data.add(new SessionData(threshold * 5, threshold * 5 + 100)); - data.add(new SessionData(threshold * 8, threshold * 8 + 200)); - data.add(new SessionData(threshold * 9 - 200, threshold * 10)); - List result = ManageUtils.combineSessions(data, 3); - SessionData exp = new SessionData(0, threshold * 2); - assertEquals(exp, result.get(0)); - SessionData exp2 = new SessionData(threshold * 5, threshold * 5 + 100); - assertEquals(exp2, result.get(1)); - SessionData exp3 = new SessionData(threshold * 8, threshold * 10); - assertEquals(exp3, result.get(2)); - } -} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java index 72ae69664..45ceb55bb 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java @@ -7,11 +7,9 @@ package test.java.main.java.com.djrapitops.plan.utilities; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.bukkit.BukkitCMDSender; -import java.util.List; import main.java.com.djrapitops.plan.utilities.MiscUtils; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -20,8 +18,11 @@ import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; import test.java.utils.TestInit; +import java.util.List; + +import static org.junit.Assert.assertEquals; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/NewPlayerCreatorTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/NewPlayerCreatorTest.java index b4f8e7939..84159b03f 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/NewPlayerCreatorTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/NewPlayerCreatorTest.java @@ -15,7 +15,6 @@ import main.java.com.djrapitops.plan.utilities.MiscUtils; import main.java.com.djrapitops.plan.utilities.NewPlayerCreator; import org.bukkit.plugin.java.JavaPlugin; import org.junit.After; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,8 +22,9 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import test.java.utils.MockUtils; +import static org.junit.Assert.assertTrue; + /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -59,13 +59,11 @@ public class NewPlayerCreatorTest { IOfflinePlayer p = BukkitOfflinePlayer.wrap(MockUtils.mockPlayer2()); UserData result = NewPlayerCreator.createNewOfflinePlayer(p); UserData exp = new UserData(p); - exp.setLastGamemode("SURVIVAL"); + exp.getGmTimes().setState("SURVIVAL"); exp.setLastPlayed(MiscUtils.getTime()); - long zero = Long.parseLong("0"); - exp.setPlayTime(zero); + exp.setPlayTime(0); exp.setTimesKicked(0); exp.setLoginTimes(0); - exp.setLastGmSwapTime(zero); exp.setDeaths(0); exp.setMobKills(0); assertTrue(exp.equals(result)); @@ -79,13 +77,11 @@ public class NewPlayerCreatorTest { IPlayer p = BukkitPlayer.wrap(MockUtils.mockPlayer2()); UserData result = NewPlayerCreator.createNewPlayer(p); UserData exp = new UserData(p); - exp.setLastGamemode("SPECTATOR"); + exp.getGmTimes().setState("SPECTATOR"); exp.setLastPlayed(MiscUtils.getTime()); - long zero = Long.parseLong("0"); - exp.setPlayTime(zero); + exp.setPlayTime(0); exp.setTimesKicked(0); exp.setLoginTimes(0); - exp.setLastGmSwapTime(zero); exp.setDeaths(0); exp.setMobKills(0); assertTrue(exp.equals(result)); @@ -99,13 +95,11 @@ public class NewPlayerCreatorTest { IOfflinePlayer p = BukkitOfflinePlayer.wrap(MockUtils.mockPlayer()); UserData result = NewPlayerCreator.createNewPlayer(p, Gamemode.CREATIVE); UserData exp = new UserData(p); - exp.setLastGamemode("CREATIVE"); + exp.getGmTimes().setState("CREATIVE"); exp.setLastPlayed(MiscUtils.getTime()); - long zero = Long.parseLong("0"); - exp.setPlayTime(zero); + exp.setPlayTime(0); exp.setTimesKicked(0); exp.setLoginTimes(0); - exp.setLastGmSwapTime(zero); exp.setDeaths(0); exp.setMobKills(0); assertTrue(exp.equals(result)); diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java index 34808450c..c698f6c78 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java @@ -23,7 +23,6 @@ import java.util.List; import static org.junit.Assert.assertEquals; /** - * * @author Rsl1122 */ @RunWith(PowerMockRunner.class) @@ -41,7 +40,7 @@ public class AnalysisUtilsTest { */ @Before public void setUp() throws Exception { - TestInit t = TestInit.init(); + TestInit.init(); } /** @@ -102,9 +101,8 @@ public class AnalysisUtilsTest { registered.add(1L); long scale = 8L; long now = 10L; - int expResult = 1; - int result = AnalysisUtils.getNewPlayers(registered, scale, now); - assertEquals(expResult, result); + long result = AnalysisUtils.getNewPlayers(registered, scale, now); + assertEquals(1L, result); } /** @@ -115,9 +113,8 @@ public class AnalysisUtilsTest { List registered = new ArrayList<>(); long scale = 1L; long now = 2L; - int expResult = 0; - int result = AnalysisUtils.getNewPlayers(registered, scale, now); - assertEquals(expResult, result); + long result = AnalysisUtils.getNewPlayers(registered, scale, now); + assertEquals(0L, result); } /** diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java index 2b54062de..6424f233c 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java @@ -5,16 +5,17 @@ */ package test.java.main.java.com.djrapitops.plan.utilities.analysis; +import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; +import org.junit.Test; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Random; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; + import static org.junit.Assert.assertTrue; -import org.junit.Test; /** - * * @author Rsl1122 */ public class MathUtilsTest { @@ -37,7 +38,7 @@ public class MathUtilsTest { l.add(5); l.add(15); double result = MathUtils.averageInt(l.stream()); - assertTrue(exp == result); + assertTrue(Double.compare(exp, result) == 0); } /** @@ -48,7 +49,7 @@ public class MathUtilsTest { List l = new ArrayList<>(); double exp = 0; double result = MathUtils.averageInt(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -63,7 +64,7 @@ public class MathUtilsTest { l.add(5L); l.add(15L); double result = MathUtils.averageLong(l); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -78,7 +79,7 @@ public class MathUtilsTest { l.add(4.5); l.add(15.0); double result = MathUtils.averageDouble(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } @@ -89,7 +90,7 @@ public class MathUtilsTest { public void testAverage() { double exp = 10; double result = MathUtils.average(40, 4); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -106,7 +107,7 @@ public class MathUtilsTest { l.add(false); } long result = MathUtils.countTrueBoolean(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -121,7 +122,7 @@ public class MathUtilsTest { l.add(5); l.add(15); double result = MathUtils.sumInt(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -136,7 +137,7 @@ public class MathUtilsTest { l.add(5L); l.add(15L); long result = MathUtils.sumLong(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } /** @@ -151,7 +152,6 @@ public class MathUtilsTest { l.add(45.0); l.add(5.0531541); double result = MathUtils.sumDouble(l.stream()); - assertTrue(result + "/" + exp, exp == result); + assertTrue(result + "/" + exp, Double.compare(exp, result) == 0); } - } diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java new file mode 100644 index 000000000..786f43e98 --- /dev/null +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java @@ -0,0 +1,122 @@ +package test.java.main.java.com.djrapitops.plan.utilities.comparators; + +import main.java.com.djrapitops.plan.data.SessionData; +import main.java.com.djrapitops.plan.data.TPS; +import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.WebUser; +import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; +import main.java.com.djrapitops.plan.utilities.analysis.Point; +import main.java.com.djrapitops.plan.utilities.comparators.*; +import org.junit.Test; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; + +public class ComparatorTest { + + private Random r = new Random(); + + @Test + public void testHandlingInfoComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + test.add(new HandlingInfo(null, null, r.nextLong()) { + @Override + public boolean process(UserData uData) { + return false; + } + }); + } + List longValues = test.stream().map(HandlingInfo::getTime).collect(Collectors.toList()); + longValues.sort(Long::compare); + test.sort(new HandlingInfoTimeComparator()); + List afterSort = test.stream().map(HandlingInfo::getTime).collect(Collectors.toList()); + assertEquals(longValues, afterSort); + } + + @Test + public void testPointComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + test.add(new Point(r.nextLong(), r.nextLong())); + } + + List longValues = test.stream().map(Point::getX).map(i -> (long) (double) i).collect(Collectors.toList()); + longValues.sort(Long::compare); + test.sort(new PointComparator()); + List afterSort = test.stream().map(Point::getX).map(i -> (long) (double) i).collect(Collectors.toList()); + assertEquals(longValues, afterSort); + } + + @Test + public void testSessionDataComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + test.add(new SessionData(r.nextLong(), r.nextLong())); + } + List longValues = test.stream().map(SessionData::getSessionStart).collect(Collectors.toList()); + longValues.sort(Long::compare); + test.sort(new SessionDataComparator()); + List afterSort = test.stream().map(SessionData::getSessionStart).collect(Collectors.toList()); + assertEquals(longValues, afterSort); + } + + @Test + public void testTPSComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + test.add(new TPS(r.nextLong(), 0, 0, 0, 0, 0, 0)); + } + List longValues = test.stream().map(TPS::getDate).collect(Collectors.toList()); + longValues.sort(Long::compare); + test.sort(new TPSComparator()); + List afterSort = test.stream().map(TPS::getDate).collect(Collectors.toList()); + assertEquals(longValues, afterSort); + } + + @Test + public void testUserDataLastPlayedComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + UserData uD = new UserData(null, 0, false, "", "", false); + uD.setLastPlayed(r.nextLong()); + test.add(uD); + } + List longValues = test.stream().map(UserData::getLastPlayed).collect(Collectors.toList()); + longValues.sort(Long::compare); + Collections.reverse(longValues); + test.sort(new UserDataLastPlayedComparator()); + List afterSort = test.stream().map(UserData::getLastPlayed).collect(Collectors.toList()); + assertEquals(longValues, afterSort); + } + + @Test + public void testUserDataNameComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + String randomName = UUID.randomUUID().toString().split("-")[0]; + test.add(new UserData(null, 0, false, "", randomName, false)); + } + List stringValues = test.stream().map(UserData::getName).collect(Collectors.toList()); + Collections.sort(stringValues); + test.sort(new UserDataNameComparator()); + List afterSort = test.stream().map(UserData::getName).collect(Collectors.toList()); + assertEquals(stringValues, afterSort); + } + + @Test + public void testWebUserComparator() { + List test = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + test.add(new WebUser("", "", r.nextInt())); + } + List intValues = test.stream().map(WebUser::getPermLevel).collect(Collectors.toList()); + intValues.sort(Integer::compare); + Collections.reverse(intValues); + test.sort(new WebUserComparator()); + List afterSort = test.stream().map(WebUser::getPermLevel).collect(Collectors.toList()); + assertEquals(intValues, afterSort); + } +} diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparatorTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparatorTest.java deleted file mode 100644 index bb29d10fc..000000000 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/utilities/comparators/HandlingInfoTimeComparatorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package test.java.main.java.com.djrapitops.plan.utilities.comparators; - -import com.djrapitops.plugin.utilities.player.Gamemode; -import java.util.ArrayList; -import java.util.List; -import main.java.com.djrapitops.plan.data.handling.info.GamemodeInfo; -import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo; -import main.java.com.djrapitops.plan.utilities.comparators.HandlingInfoTimeComparator; -import static org.junit.Assert.assertEquals; -import org.junit.Test; - -/** - * - * @author Rsl1122 - */ -public class HandlingInfoTimeComparatorTest { - - /** - * - */ - public HandlingInfoTimeComparatorTest() { - } - - /** - * - */ - @Test - public void testCompare() { - List i = new ArrayList<>(); - GamemodeInfo one = new GamemodeInfo(null, 500L, Gamemode.CREATIVE); - i.add(one); - GamemodeInfo two = new GamemodeInfo(null, 400L, Gamemode.CREATIVE); - i.add(two); - GamemodeInfo three = new GamemodeInfo(null, 100L, Gamemode.CREATIVE); - i.add(three); - GamemodeInfo four = new GamemodeInfo(null, 700L, Gamemode.CREATIVE); - i.add(four); - i.sort(new HandlingInfoTimeComparator()); - assertEquals(three, i.get(0)); - assertEquals(two, i.get(1)); - assertEquals(one, i.get(2)); - assertEquals(four, i.get(3)); - - } - -} diff --git a/Plan/src/test/java/utils/MockUtils.java b/Plan/src/test/java/utils/MockUtils.java index 9aa004ec0..3bff73764 100644 --- a/Plan/src/test/java/utils/MockUtils.java +++ b/Plan/src/test/java/utils/MockUtils.java @@ -2,9 +2,11 @@ package test.java.utils; import com.djrapitops.plugin.utilities.player.Fetch; import com.djrapitops.plugin.utilities.player.IPlayer; +import com.sun.net.httpserver.HttpServer; import main.java.com.djrapitops.plan.data.KillData; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.UserData; +import main.java.com.djrapitops.plan.data.time.GMTimes; import main.java.com.djrapitops.plan.utilities.NewPlayerCreator; import org.bukkit.GameMode; import org.bukkit.Location; @@ -15,18 +17,20 @@ import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import static org.powermock.api.mockito.PowerMockito.when; /** - * * @author Rsl1122 */ public class MockUtils { /** - * * @return */ public static World mockWorld() { @@ -45,12 +49,13 @@ public class MockUtils { mock.addNickname("MoreNicks"); mock.addPlayerKill(new KillData(getPlayer2UUID(), 1, "WEP", 126873643232L)); mock.addSession(new SessionData(12345L, 23456L)); - mock.setAllGMTimes(1234, 2345, 4356, 4767); + GMTimes gmTimes = mock.getGmTimes(); + gmTimes.setAllGMTimes(1234, 2345, 4356, 4767); + gmTimes.setState("ADVENTURE"); mock.setDeaths(5); mock.setTimesKicked(5); mock.setPlayTime(34438926); mock.setGeolocation("Finland"); - mock.setLastGamemode("ADVENTURE"); mock.setLoginTimes(5); mock.setMobKills(5); return mock; @@ -61,7 +66,6 @@ public class MockUtils { } /** - * * @return */ public static IPlayer mockIPlayer() { @@ -84,7 +88,6 @@ public class MockUtils { } /** - * * @return */ public static UUID getPlayerUUID() { @@ -92,7 +95,6 @@ public class MockUtils { } /** - * * @return */ public static IPlayer mockIPlayer2() { @@ -115,15 +117,20 @@ public class MockUtils { } /** - * * @return */ public static UUID getPlayer2UUID() { return UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80"); } + public static Set getUUIDs() { + Set uuids = new HashSet<>(); + uuids.add(getPlayerUUID()); + uuids.add(getPlayer2UUID()); + return uuids; + } + /** - * * @return */ public static IPlayer mockBrokenPlayer() { @@ -141,10 +148,16 @@ public class MockUtils { } /** - * * @return */ public static CommandSender mockConsoleSender() { return PowerMockito.mock(CommandSender.class); } + + public static HttpServer mockHTTPServer() throws UnknownHostException { + HttpServer httpServer = PowerMockito.mock(HttpServer.class); + when(httpServer.getAddress()).thenReturn(InetSocketAddress.createUnresolved("127.0.0.1", 80)); + when(httpServer.getExecutor()).thenReturn(command -> System.out.println("HTTP Server command received")); + return httpServer; + } } diff --git a/Plan/src/test/java/utils/TestInit.java b/Plan/src/test/java/utils/TestInit.java index 6b902c0f8..b4ea433f4 100644 --- a/Plan/src/test/java/utils/TestInit.java +++ b/Plan/src/test/java/utils/TestInit.java @@ -23,7 +23,6 @@ import java.util.logging.Logger; import static org.powermock.api.mockito.PowerMockito.when; /** - * * @author Rsl1122 */ public class TestInit { @@ -106,14 +105,13 @@ public class TestInit { } private YamlConfiguration mockConfig() throws IOException, InvalidConfigurationException { - File configfile = new File(getClass().getResource("/config.yml").getPath()); + File configFile = new File(getClass().getResource("/config.yml").getPath()); YamlConfiguration configuration = new YamlConfiguration(); - configuration.load(configfile.getAbsolutePath()); + configuration.load(configFile.getAbsolutePath()); return configuration; } /** - * * @return */ public Plan getPlanMock() { diff --git a/PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_5_0.xml b/PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_6_0.xml similarity index 62% rename from PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_5_0.xml rename to PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_6_0.xml index d868b5062..33dbd4ca9 100644 --- a/PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_5_0.xml +++ b/PlanPluginBridge/.idea/artifacts/PlanPluginBridge_3_6_0.xml @@ -1,7 +1,7 @@ - + $PROJECT_DIR$/target - + diff --git a/PlanPluginBridge/.idea/libraries/Maven__com_djrapitops_Plan_3_6_0.xml b/PlanPluginBridge/.idea/libraries/Maven__com_djrapitops_Plan_3_6_0.xml new file mode 100644 index 000000000..85b0ed7cf --- /dev/null +++ b/PlanPluginBridge/.idea/libraries/Maven__com_djrapitops_Plan_3_6_0.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlanPluginBridge/.idea/shelf/Fix__198.xml b/PlanPluginBridge/.idea/shelf/Fix__198.xml new file mode 100644 index 000000000..cccccdbda --- /dev/null +++ b/PlanPluginBridge/.idea/shelf/Fix__198.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/PlanPluginBridge/PlanPluginBridge-3.5.0.jar b/PlanPluginBridge/PlanPluginBridge-3.6.0.jar similarity index 75% rename from PlanPluginBridge/PlanPluginBridge-3.5.0.jar rename to PlanPluginBridge/PlanPluginBridge-3.6.0.jar index b3a864a2d..ae8ac0249 100644 Binary files a/PlanPluginBridge/PlanPluginBridge-3.5.0.jar and b/PlanPluginBridge/PlanPluginBridge-3.6.0.jar differ diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml index 62a3cd94a..343b10cda 100644 --- a/PlanPluginBridge/pom.xml +++ b/PlanPluginBridge/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.djrapitops PlanPluginBridge - 3.5.0 + 3.6.0 jar @@ -23,7 +23,7 @@ com.djrapitops Plan - 3.5.5 + 3.6.0 provided diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimArea.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimArea.java index 64850b7bd..0874ec825 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimArea.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimArea.java @@ -1,15 +1,15 @@ package com.djrapitops.pluginbridge.plan.griefprevention; -import java.io.Serializable; -import java.util.UUID; - import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.data.additional.AnalysisType; import main.java.com.djrapitops.plan.data.additional.PluginData; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import me.ryanhamshire.GriefPrevention.Claim; import me.ryanhamshire.GriefPrevention.DataStore; +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + /** * PluginData class for GriefPrevention-plugin. * @@ -37,6 +37,7 @@ public class GriefPreventionClaimArea extends PluginData { public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) { Verify.nullCheck(uuid); int area = dataStore.getClaims().stream() + .filter(Objects::nonNull) .filter(claim -> uuid.equals(claim.ownerID)) .map(Claim::getArea).mapToInt(i -> i).sum(); return parseContainer(modifierPrefix, area + ""); @@ -46,6 +47,7 @@ public class GriefPreventionClaimArea extends PluginData { public Serializable getValue(UUID uuid) { Verify.nullCheck(uuid); return dataStore.getClaims().stream() + .filter(Objects::nonNull) .filter(claim -> uuid.equals(claim.ownerID)) .map(Claim::getArea).mapToInt(i -> i).sum(); } diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimTable.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimTable.java index 9ac8f0fb2..9e2279a68 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimTable.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaimTable.java @@ -1,13 +1,15 @@ package com.djrapitops.pluginbridge.plan.griefprevention; -import java.io.Serializable; -import java.util.UUID; - import com.djrapitops.plugin.utilities.FormattingUtils; +import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.data.additional.PluginData; import main.java.com.djrapitops.plan.ui.html.Html; import me.ryanhamshire.GriefPrevention.DataStore; +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + /** * PluginData class for GriefPrevention-plugin. * @@ -43,9 +45,12 @@ public class GriefPreventionClaimTable extends PluginData { } private String getTableLines(UUID uuid) { + Verify.nullCheck(uuid); + StringBuilder html = new StringBuilder(); dataStore.getClaims().stream() - .filter(claim -> claim.ownerID.equals(uuid)) + .filter(Objects::nonNull) + .filter(claim -> uuid.equals(claim.ownerID)) .forEach(claim -> { String location = FormattingUtils.formatLocation(claim.getGreaterBoundaryCorner()); String area = claim.getArea() + ""; diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaims.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaims.java index 642636a4d..f318ca9e3 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaims.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/griefprevention/GriefPreventionClaims.java @@ -1,16 +1,17 @@ package com.djrapitops.pluginbridge.plan.griefprevention; -import java.io.Serializable; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.data.additional.AnalysisType; import main.java.com.djrapitops.plan.data.additional.PluginData; import me.ryanhamshire.GriefPrevention.Claim; import me.ryanhamshire.GriefPrevention.DataStore; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + /** * PluginData class for GriefPrevention-plugin. * @@ -38,6 +39,7 @@ public class GriefPreventionClaims extends PluginData { public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) { Verify.nullCheck(uuid); List claims = dataStore.getClaims().stream() + .filter(Objects::nonNull) .filter(claim -> uuid.equals(claim.ownerID)) .collect(Collectors.toList()); return parseContainer(modifierPrefix, claims.size()+""); @@ -47,6 +49,7 @@ public class GriefPreventionClaims extends PluginData { public Serializable getValue(UUID uuid) { Verify.nullCheck(uuid); return dataStore.getClaims().stream() + .filter(Objects::nonNull) .filter(claim -> uuid.equals(claim.ownerID)) .collect(Collectors.toList()).size(); } diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/importing/OnTimeImporter.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/importing/OnTimeImporter.java index 1cb122ccb..0d14398ca 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/importing/OnTimeImporter.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/importing/OnTimeImporter.java @@ -47,9 +47,7 @@ public class OnTimeImporter extends Importer { } if (playTime > uData.getPlayTime()) { uData.setPlayTime(playTime); - uData.setLastGamemode("SURVIVAL"); - uData.setAllGMTimes(playTime, 0, 0, 0); - uData.setLastGmSwapTime(playTime); + uData.getGmTimes().resetTimes(playTime); } return true; } diff --git a/documentation/CertificateTutorial.md b/documentation/CertificateTutorial.md new file mode 100644 index 000000000..3712b2f80 --- /dev/null +++ b/documentation/CertificateTutorial.md @@ -0,0 +1,76 @@ +![Player Analytics](https://puu.sh/t8vin.png) + +# HTTPS Configuration + +## How to configure Plan to use SSL Encryption: +- Obtain a Java Keystore file (More below) +- Place the keystore file in the /plugins/Plan/ folder +(If you have a keystore file elsewhere on the machine, you can specify the full path to the file.) +- Change the config settings under **WebServer**: + +Config.Setting | Description +------------------- | --------------- +Certificate.KeyStorePath | The absolute path to the certificate file, you can directly use “KEYSTORE.FILE” if the certificate is placed in the Plan folder, if it’s elsewhere, use the direct path to it. +Certificate.KeyPass | The password of the certificate +Certificate.StorePass | The password of the keystore +Certificate.Alias | The alias of the keystore + +# Obtaining a Java Keystore File + +## How to get a certificate issued by Let’s Encrypt: +See here: +https://letsencrypt.org/getting-started/ + +## How to convert the certificate files into a Java KeyStore: + +Execute keytool command in the Command Prompt (Windows) or in the Shell (Linux) + +`keytool -importcert -file $CERTIFICATE -keystore $KEYSTORE -alias “$ALIAS”` + +After executing the command, you need to enter the password of the keystore currently being created. + +Notes: +The password for the keystore must be at least 6 characters long. + +**NOTE FOR WINDOWS USERS:** +The keytool command is only going to work, when the Command Prompt is opened in `$JAVA_HOME\jre$VERSION\lib\security` +You can manage that by going to that path using +`cd $JAVA_HOME\jre$VERSION\lib\security` + +## If you’re unable to obtain a certificate + +If you do not have a domain for certificate registration, or can not create a self signed one, Plan.jar contains a self signed RSA 2048 certificate that can be used. + +Open Plan.jar in any archive manager (Like WinRAR) and drop the Certificate.keystore file in the /plugins/Plan/ folder. +Set the config settings as follows so that the Certificate works. + +Config.Setting | Value +------------------- | --------------- +Certificate.KeyStorePath | Cert.keystore +Certificate.KeyPass | MnD3bU5HpmPXag0e +Certificate.StorePass | wDwwf663NLTm73gL +Certificate.Alias | DefaultPlanCert + +Self signed certificates cause browsers to display security warning: +![Certificate Warning](http://puu.sh/wY5Gs/91883c1ced.jpg) + +You can ignore this warning. [“Dangers” of self signed certificates, Article](https://www.globalsign.com/en/ssl-information-center/dangers-self-signed-certificates/) + +### Displaying a Green HTTPS Lock with Cloudflare + +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) + +Connect your domain to Cloudflare +Add a DNS record of the type “A” which points to your Server IP +Go to “Crypto” -> “SSL” and set the option to “Flexible” + +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) + +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.
Command