/** * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2012 Kristian S. * Stangeland *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later * version. *
* 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 GNU General Public License for more * details. *
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.comphenix.protocol;
import com.comphenix.protocol.async.AsyncFilterManager;
import com.comphenix.protocol.error.BasicErrorReporter;
import com.comphenix.protocol.error.DelegatedErrorReporter;
import com.comphenix.protocol.error.DetailedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.InternalManager;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.metrics.Statistics;
import com.comphenix.protocol.scheduler.DefaultScheduler;
import com.comphenix.protocol.scheduler.FoliaScheduler;
import com.comphenix.protocol.scheduler.ProtocolScheduler;
import com.comphenix.protocol.scheduler.Task;
import com.comphenix.protocol.updater.Updater;
import com.comphenix.protocol.updater.Updater.UpdateType;
import com.comphenix.protocol.utility.*;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Server;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
/**
* The main entry point for ProtocolLib.
*
* @author Kristian
*/
public class ProtocolLib extends JavaPlugin {
// Every possible error or warning report type
public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType(
"Cannot delete old ProtocolLib configuration.");
public static final ReportType REPORT_PLUGIN_LOAD_ERROR = new ReportType("Cannot load ProtocolLib.");
public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
public static final ReportType REPORT_PLUGIN_ENABLE_ERROR = new ReportType("Cannot enable ProtocolLib.");
public static final ReportType REPORT_METRICS_IO_ERROR = new ReportType(
"Unable to enable metrics due to network problems.");
public static final ReportType REPORT_METRICS_GENERIC_ERROR = new ReportType(
"Unable to enable metrics due to network problems.");
public static final ReportType REPORT_CANNOT_PARSE_MINECRAFT_VERSION = new ReportType(
"Unable to retrieve current Minecraft version. Assuming %s");
public static final ReportType REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS = new ReportType(
"Unable to detect conflicting plugin versions.");
public static final ReportType REPORT_CANNOT_REGISTER_COMMAND = new ReportType("Cannot register command %s: %s");
public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType(
"Unable to create packet timeout task.");
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot perform automatic updates.");
/**
* The number of milliseconds per second.
*/
static final long MILLI_PER_SECOND = TimeUnit.SECONDS.toMillis(1);
private static final int ASYNC_MANAGER_DELAY = 1;
private static final String PERMISSION_INFO = "protocol.info";
// these fields are only existing once, we can make them static
private static Logger logger;
private static ProtocolConfig config;
private static InternalManager protocolManager;
private static ErrorReporter reporter = new BasicErrorReporter();
private Statistics statistics;
private Task packetTask = null;
private int tickCounter = 0;
private int configExpectedMod = -1;
// updater
private Updater updater;
private Handler redirectHandler;
private ProtocolScheduler scheduler;
// commands
private CommandProtocol commandProtocol;
private CommandPacket commandPacket;
private CommandFilter commandFilter;
private PacketLogging packetLogging;
// Whether disabling field resetting is needed
private boolean skipDisable;
@Override
public void onLoad() {
// Logging
logger = this.getLogger();
ProtocolLogger.init(this);
// Initialize enhancer factory
ByteBuddyFactory.getInstance().setClassLoader(this.getClassLoader());
// Add global parameters
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
reporter = this.getFilteredReporter(detailedReporter);
// Configuration
this.saveDefaultConfig();
this.reloadConfig();
try {
config = new ProtocolConfig(this);
} catch (Exception exception) {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(exception));
// Load it again
if (this.deleteConfig()) {
config = new ProtocolConfig(this);
} else {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_DELETE_CONFIG));
}
}
// Print the state of the debug mode
if (config.isDebug()) {
logger.warning("Debug mode is enabled!");
}
// And the state of the error reporter
if (config.isDetailedErrorReporting()) {
detailedReporter.setDetailedReporting(true);
logger.warning("Detailed error reporting enabled!");
}
try {
this.scheduler = Util.isUsingFolia()
? new FoliaScheduler(this)
: new DefaultScheduler(this);
// Check for other versions
this.checkConflictingVersions();
// Handle unexpected Minecraft versions
MinecraftVersion version = this.verifyMinecraftVersion();
// Set updater - this will not perform any update automatically
this.updater = Updater.create(this, 0, this.getFile(), UpdateType.NO_DOWNLOAD, true);
// api init
protocolManager = PacketFilterManager.newBuilder()
.server(this.getServer())
.library(this)
.minecraftVersion(version)
.reporter(reporter)
.build();
ProtocolLibrary.init(this, config, protocolManager, scheduler, reporter);
// Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager);
// Send logging information to player listeners too
this.initializeCommands();
this.setupBroadcastUsers(PERMISSION_INFO);
} catch (Exception e) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager));
this.disablePlugin();
}
}
/**
* Initialize all command handlers.
*/
private void initializeCommands() {
// Initialize command handlers
for (ProtocolCommand command : ProtocolCommand.values()) {
try {
switch (command) {
case PROTOCOL:
this.commandProtocol = new CommandProtocol(reporter, this, this.updater, config);
break;
case FILTER:
this.commandFilter = new CommandFilter(reporter, this, config);
break;
case PACKET:
this.commandPacket = new CommandPacket(reporter, this, logger, this.commandFilter, protocolManager);
break;
case LOGGING:
this.packetLogging = new PacketLogging(this, protocolManager);
break;
}
} catch (OutOfMemoryError e) {
throw e;
} catch (LinkageError e) {
logger.warning("Failed to register command " + command.name() + ": " + e);
} catch (Throwable e) {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND)
.messageParam(command.name(), e.getMessage()).error(e));
}
}
}
/**
* Retrieve a error reporter that may be filtered by the configuration.
*
* @return The new default error reporter.
*/
private ErrorReporter getFilteredReporter(ErrorReporter reporter) {
return new DelegatedErrorReporter(reporter) {
private int lastModCount = -1;
private Set
* Note that this method may return NULL when the server is reloading or shutting down. It is also NULL if metrics has
* been disabled.
*
* @return Metrics instance container.
*/
public Statistics getStatistics() {
return this.statistics;
}
public ProtocolConfig getProtocolConfig() {
return config;
}
public ProtocolScheduler getScheduler() {
return scheduler;
}
// Different commands
private enum ProtocolCommand {
FILTER,
PACKET,
PROTOCOL,
LOGGING
}
}