378 lines
12 KiB
Java
378 lines
12 KiB
Java
/*
|
|
* Player Analytics Bukkit plugin for monitoring server activity.
|
|
* Copyright (C) 2016 Risto Lahtela / Rsl1122
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the Plan License. (licence.yml)
|
|
* Modified software can only be redistributed if allowed in the licence.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* License for more details.
|
|
*
|
|
* You should have received a copy of the License
|
|
* along with this program.
|
|
* If not it should be visible on the distribution page.
|
|
* Or here
|
|
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/licence.yml
|
|
*/
|
|
|
|
package com.djrapitops.plan;
|
|
|
|
import com.djrapitops.plan.command.PlanCommand;
|
|
import com.djrapitops.plan.api.API;
|
|
import com.djrapitops.plan.data.cache.AnalysisCacheHandler;
|
|
import com.djrapitops.plan.utilities.MiscUtils;
|
|
import com.djrapitops.plan.database.Database;
|
|
import com.djrapitops.plan.database.databases.*;
|
|
import com.djrapitops.plan.data.cache.*;
|
|
import com.djrapitops.plan.data.listeners.*;
|
|
import java.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.net.URL;
|
|
import java.util.Date;
|
|
import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer;
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
|
|
import java.util.HashSet;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import main.java.com.djrapitops.plan.Settings;
|
|
import main.java.com.djrapitops.plan.data.listeners.PlanDeathEventListener;
|
|
import main.java.com.djrapitops.plan.ui.Html;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.command.ConsoleCommandSender;
|
|
import org.bukkit.plugin.PluginManager;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
import org.bukkit.scheduler.BukkitTask;
|
|
|
|
/* TODO 2.6.0
|
|
Placeholder API
|
|
Database cleaning
|
|
Play session length
|
|
Location Analysis to view meaningful locations on Dynmap (Investigate dynmap api)
|
|
Integrate PlanLite features to Plan and discontinue PlanLite
|
|
Seperate serverdata and userdata saving
|
|
Database Cleaning of useless data
|
|
Fix any bugs that come up
|
|
- New Players not counted for some reason.
|
|
Sortable player table.
|
|
Add -n argument for nickname search.
|
|
*/
|
|
/**
|
|
*
|
|
* @author Rsl1122
|
|
*/
|
|
public class Plan extends JavaPlugin {
|
|
|
|
private API api;
|
|
private PlanLiteHook planLiteHook;
|
|
private DataCacheHandler handler;
|
|
private InspectCacheHandler inspectCache;
|
|
private AnalysisCacheHandler analysisCache;
|
|
private Database db;
|
|
private HashSet<Database> databases;
|
|
private WebSocketServer uiServer;
|
|
|
|
private int bootAnalysisTaskID;
|
|
|
|
/**
|
|
* OnEnable method.
|
|
*
|
|
* Creates the config file. Checks for new version. Initializes Database.
|
|
* Hooks PlanLite. Initializes DataCaches. Registers Listeners. Registers
|
|
* Command /plan and initializes API. Enables Webserver & analysis tasks if
|
|
* enabled in config. Warns about possible mistakes made in config.
|
|
*/
|
|
@Override
|
|
public void onEnable() {
|
|
getDataFolder().mkdirs();
|
|
|
|
initLocale();
|
|
|
|
databases = new HashSet<>();
|
|
databases.add(new MySQLDB(this));
|
|
databases.add(new SQLiteDB(this));
|
|
|
|
getConfig().options().copyDefaults(true);
|
|
getConfig().options().header(Phrase.CONFIG_HEADER + "");
|
|
saveConfig();
|
|
|
|
log(MiscUtils.checkVersion());
|
|
|
|
log(Phrase.DB_INIT + "");
|
|
if (initDatabase()) {
|
|
log(Phrase.DB_ESTABLISHED.parse(db.getConfigName()));
|
|
} else {
|
|
logError(Phrase.DATABASE_FAILURE_DISABLE.toString());
|
|
getServer().getPluginManager().disablePlugin(this);
|
|
return;
|
|
}
|
|
|
|
hookPlanLite();
|
|
this.handler = new DataCacheHandler(this);
|
|
this.inspectCache = new InspectCacheHandler(this);
|
|
this.analysisCache = new AnalysisCacheHandler(this);
|
|
registerListeners();
|
|
|
|
getCommand("plan").setExecutor(new PlanCommand(this));
|
|
|
|
this.api = new API(this);
|
|
handler.handleReload();
|
|
ConsoleCommandSender consoleSender = getServer().getConsoleSender();
|
|
|
|
bootAnalysisTaskID = -1;
|
|
if (Settings.WEBSERVER_ENABLED.isTrue()) {
|
|
uiServer = new WebSocketServer(this);
|
|
uiServer.initServer();
|
|
if (Settings.ANALYSIS_REFRESH_ON_ENABLE.isTrue()) {
|
|
startBootRefreshTask();
|
|
}
|
|
int analysisRefreshMinutes = Settings.ANALYSIS_AUTO_REFRESH.getNumber();
|
|
if (analysisRefreshMinutes != -1) {
|
|
startAnalysisRefreshTask(analysisRefreshMinutes);
|
|
}
|
|
} else if (!(Settings.SHOW_ALTERNATIVE_IP.isTrue())
|
|
|| (Settings.USE_ALTERNATIVE_UI.isTrue()
|
|
&& planLiteHook.isEnabled())) {
|
|
consoleSender.sendMessage(Phrase.PREFIX + "" + Phrase.ERROR_NO_DATA_VIEW);
|
|
}
|
|
if (!Settings.SHOW_ALTERNATIVE_IP.isTrue() && getServer().getIp().isEmpty()) {
|
|
consoleSender.sendMessage(Phrase.NOTIFY_EMPTY_IP + "");
|
|
}
|
|
|
|
log(Phrase.ENABLED + "");
|
|
}
|
|
|
|
/**
|
|
* Hooks PlanLite for UI and/or additional data.
|
|
*/
|
|
public void hookPlanLite() {
|
|
try {
|
|
planLiteHook = new PlanLiteHook(this);
|
|
} catch (NoClassDefFoundError | Exception e) {
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disables the plugin.
|
|
*
|
|
* Stops the webserver, cancels all tasks and saves cache to the database.
|
|
*/
|
|
@Override
|
|
public void onDisable() {
|
|
if (uiServer != null) {
|
|
uiServer.stop();
|
|
}
|
|
Bukkit.getScheduler().cancelTasks(this);
|
|
if (handler != null) {
|
|
log(Phrase.SAVE_CACHE + "");
|
|
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
|
scheduler.execute(() -> {
|
|
handler.saveCacheOnDisable();
|
|
});
|
|
|
|
scheduler.shutdown();
|
|
}
|
|
log(Phrase.DISABLED + "");
|
|
}
|
|
|
|
/**
|
|
* Logs the message to the console.
|
|
*
|
|
* @param message
|
|
*/
|
|
public void log(String message) {
|
|
getLogger().info(message);
|
|
}
|
|
|
|
/**
|
|
* Logs an error message to the console.
|
|
*
|
|
* @param message
|
|
*/
|
|
public void logError(String message) {
|
|
getLogger().severe(message);
|
|
}
|
|
|
|
/**
|
|
* @return Plan API
|
|
*/
|
|
public API getAPI() {
|
|
return api;
|
|
}
|
|
|
|
private void registerListeners() {
|
|
final PluginManager pluginManager = getServer().getPluginManager();
|
|
pluginManager.registerEvents(new PlanChatListener(this), this);
|
|
pluginManager.registerEvents(new PlanPlayerListener(this), this);
|
|
pluginManager.registerEvents(new PlanGamemodeChangeListener(this), this);
|
|
pluginManager.registerEvents(new PlanCommandPreprocessListener(this), this);
|
|
pluginManager.registerEvents(new PlanDeathEventListener(this), this);
|
|
if (Settings.GATHERLOCATIONS.isTrue()) {
|
|
pluginManager.registerEvents(new PlanPlayerMoveListener(this), this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
public boolean initDatabase() {
|
|
String type = Settings.DB_TYPE + "";
|
|
|
|
db = null;
|
|
|
|
for (Database database : databases) {
|
|
if (type.equalsIgnoreCase(database.getConfigName())) {
|
|
this.db = database;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (db == null) {
|
|
log(Phrase.DATABASE_TYPE_DOES_NOT_EXIST.toString());
|
|
return false;
|
|
}
|
|
|
|
if (!db.init()) {
|
|
log(Phrase.DATABASE_FAILURE_DISABLE.toString());
|
|
setEnabled(false);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void startAnalysisRefreshTask(int analysisRefreshMinutes) throws IllegalStateException, IllegalArgumentException {
|
|
(new BukkitRunnable() {
|
|
@Override
|
|
public void run() {
|
|
if (!analysisCache.isCached()) {
|
|
analysisCache.updateCache();
|
|
} else if (new Date().getTime() - analysisCache.getData().getRefreshDate() > 60000) {
|
|
analysisCache.updateCache();
|
|
}
|
|
}
|
|
}).runTaskTimerAsynchronously(this, analysisRefreshMinutes * 60 * 20, analysisRefreshMinutes * 60 * 20);
|
|
}
|
|
|
|
private void startBootRefreshTask() throws IllegalStateException, IllegalArgumentException {
|
|
log(Phrase.ANALYSIS_BOOT_NOTIFY + "");
|
|
BukkitTask analysis = (new BukkitRunnable() {
|
|
@Override
|
|
public void run() {
|
|
log(Phrase.ANALYSIS_BOOT + "");
|
|
analysisCache.updateCache();
|
|
this.cancel();
|
|
}
|
|
}).runTaskLater(this, 30 * 20);
|
|
bootAnalysisTaskID = analysis.getTaskId();
|
|
}
|
|
|
|
/**
|
|
* @return Currnet instance of the AnalysisCacheHandler
|
|
*/
|
|
public AnalysisCacheHandler getAnalysisCache() {
|
|
return analysisCache;
|
|
}
|
|
|
|
/**
|
|
* @return Currnet instance of the InspectCacheHandler
|
|
*/
|
|
public InspectCacheHandler getInspectCache() {
|
|
return inspectCache;
|
|
}
|
|
|
|
/**
|
|
* @return Currnet instance of the DataCacheHandler
|
|
*/
|
|
public DataCacheHandler getHandler() {
|
|
return handler;
|
|
}
|
|
|
|
/**
|
|
* @return PlanLiteHook
|
|
*/
|
|
public PlanLiteHook getPlanLiteHook() {
|
|
return planLiteHook;
|
|
}
|
|
|
|
/**
|
|
* @return the Database
|
|
*/
|
|
public Database getDB() {
|
|
return db;
|
|
}
|
|
|
|
/**
|
|
* @return the Webserver
|
|
*/
|
|
public WebSocketServer getUiServer() {
|
|
return uiServer;
|
|
}
|
|
|
|
/**
|
|
* @return Set containing SqLite & MySQL classes.
|
|
*/
|
|
public HashSet<Database> getDatabases() {
|
|
return databases;
|
|
}
|
|
|
|
/**
|
|
* @return
|
|
*/
|
|
public int getBootAnalysisTaskID() {
|
|
return bootAnalysisTaskID;
|
|
}
|
|
|
|
private void initLocale() {
|
|
String locale = Settings.LOCALE.toString().toUpperCase();
|
|
File localeFile = new File(getDataFolder(), "locale.txt");
|
|
boolean skipLoc = false;
|
|
String usingLocale = "";
|
|
if (localeFile.exists()) {
|
|
Phrase.loadLocale(localeFile);
|
|
Html.loadLocale(localeFile);
|
|
skipLoc = true;
|
|
usingLocale = "locale.txt";
|
|
}
|
|
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 = 0;
|
|
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) {
|
|
logError("Attempted using locale that doesn't exist.");
|
|
usingLocale = "Default: EN";
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
} else {
|
|
usingLocale = "Default: EN";
|
|
}
|
|
log("Using locale: " + usingLocale);
|
|
}
|
|
}
|