2012-04-26 23:36:43 +02:00
package fr.neatmonster.nocheatplus ;
2012-04-05 18:24:39 +02:00
import java.util.ArrayList ;
2013-04-15 16:11:08 +02:00
import java.util.Collection ;
2012-09-10 10:10:45 +02:00
import java.util.Collections ;
import java.util.HashMap ;
2013-02-26 01:58:21 +01:00
import java.util.HashSet ;
2015-01-05 16:12:05 +01:00
import java.util.LinkedHashMap ;
2013-01-25 23:51:29 +01:00
import java.util.LinkedHashSet ;
2012-09-04 06:48:21 +02:00
import java.util.LinkedList ;
2012-04-05 18:24:39 +02:00
import java.util.List ;
2012-09-10 10:10:45 +02:00
import java.util.Map ;
import java.util.Map.Entry ;
2012-11-09 14:29:51 +01:00
import java.util.Set ;
2013-05-21 22:49:05 +02:00
import java.util.concurrent.Callable ;
2012-04-05 18:24:39 +02:00
import org.bukkit.Bukkit ;
2012-08-21 02:49:14 +02:00
import org.bukkit.ChatColor ;
2013-02-26 01:58:21 +01:00
import org.bukkit.command.CommandSender ;
2012-11-07 05:30:21 +01:00
import org.bukkit.command.PluginCommand ;
2012-04-05 18:24:39 +02:00
import org.bukkit.entity.Player ;
import org.bukkit.event.EventHandler ;
import org.bukkit.event.EventPriority ;
import org.bukkit.event.Listener ;
2012-11-09 14:29:51 +01:00
import org.bukkit.event.player.PlayerChangedWorldEvent ;
2012-04-05 18:24:39 +02:00
import org.bukkit.event.player.PlayerJoinEvent ;
2012-11-09 14:29:51 +01:00
import org.bukkit.event.player.PlayerKickEvent ;
2012-09-10 10:10:45 +02:00
import org.bukkit.event.player.PlayerLoginEvent ;
import org.bukkit.event.player.PlayerLoginEvent.Result ;
2012-11-09 14:29:51 +01:00
import org.bukkit.event.player.PlayerQuitEvent ;
2013-02-26 01:58:21 +01:00
import org.bukkit.permissions.Permissible ;
2013-06-12 02:08:22 +02:00
import org.bukkit.permissions.PermissionDefault ;
2012-04-05 18:24:39 +02:00
import org.bukkit.plugin.PluginDescriptionFile ;
import org.bukkit.plugin.java.JavaPlugin ;
2013-02-27 18:00:44 +01:00
import org.bukkit.scheduler.BukkitScheduler ;
2012-04-05 18:24:39 +02:00
2012-04-26 23:36:43 +02:00
import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakListener ;
2012-08-06 02:43:01 +02:00
import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractListener ;
2012-04-26 23:36:43 +02:00
import fr.neatmonster.nocheatplus.checks.blockplace.BlockPlaceListener ;
import fr.neatmonster.nocheatplus.checks.chat.ChatListener ;
2014-08-01 21:06:23 +02:00
import fr.neatmonster.nocheatplus.checks.combined.CombinedData ;
2012-09-10 08:52:27 +02:00
import fr.neatmonster.nocheatplus.checks.combined.CombinedListener ;
2012-08-05 13:09:57 +02:00
import fr.neatmonster.nocheatplus.checks.fight.FightListener ;
2012-08-05 20:00:05 +02:00
import fr.neatmonster.nocheatplus.checks.inventory.InventoryListener ;
2012-04-26 23:36:43 +02:00
import fr.neatmonster.nocheatplus.checks.moving.MovingListener ;
2013-01-18 22:37:23 +01:00
import fr.neatmonster.nocheatplus.clients.ModUtil ;
2013-06-11 20:30:34 +02:00
import fr.neatmonster.nocheatplus.command.NoCheatPlusCommand ;
2015-01-11 18:52:08 +01:00
import fr.neatmonster.nocheatplus.command.admin.VersionCommand ;
2014-12-01 00:06:41 +01:00
import fr.neatmonster.nocheatplus.compat.BridgeMisc ;
2013-05-22 12:24:48 +02:00
import fr.neatmonster.nocheatplus.compat.DefaultComponentFactory ;
2012-12-06 22:16:07 +01:00
import fr.neatmonster.nocheatplus.compat.MCAccess ;
2015-06-06 22:30:37 +02:00
import fr.neatmonster.nocheatplus.compat.MCAccessConfig ;
2012-12-06 22:16:07 +01:00
import fr.neatmonster.nocheatplus.compat.MCAccessFactory ;
2015-01-11 18:52:08 +01:00
import fr.neatmonster.nocheatplus.compat.versions.BukkitVersion ;
2015-11-26 09:38:05 +01:00
import fr.neatmonster.nocheatplus.compat.versions.GenericVersion ;
2015-01-11 18:52:08 +01:00
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion ;
2013-04-15 16:11:08 +02:00
import fr.neatmonster.nocheatplus.components.ComponentRegistry ;
2012-11-08 10:58:43 +01:00
import fr.neatmonster.nocheatplus.components.ComponentWithName ;
2013-02-27 18:00:44 +01:00
import fr.neatmonster.nocheatplus.components.ConsistencyChecker ;
2013-09-19 21:00:57 +02:00
import fr.neatmonster.nocheatplus.components.DisableListener ;
2013-04-15 16:11:08 +02:00
import fr.neatmonster.nocheatplus.components.IHoldSubComponents ;
2012-11-02 10:40:37 +01:00
import fr.neatmonster.nocheatplus.components.INeedConfig ;
2013-05-21 22:49:05 +02:00
import fr.neatmonster.nocheatplus.components.INotifyReload ;
2013-03-08 03:44:54 +01:00
import fr.neatmonster.nocheatplus.components.JoinLeaveListener ;
2013-01-30 04:22:06 +01:00
import fr.neatmonster.nocheatplus.components.MCAccessHolder ;
2012-11-12 09:04:43 +01:00
import fr.neatmonster.nocheatplus.components.NCPListener ;
2012-11-09 14:29:51 +01:00
import fr.neatmonster.nocheatplus.components.NameSetPermState ;
2012-11-02 10:40:37 +01:00
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI ;
2012-11-09 14:29:51 +01:00
import fr.neatmonster.nocheatplus.components.PermStateReceiver ;
2013-01-14 04:23:39 +01:00
import fr.neatmonster.nocheatplus.components.TickListener ;
2013-07-18 01:22:59 +02:00
import fr.neatmonster.nocheatplus.components.order.SetupOrder ;
2012-04-26 23:36:43 +02:00
import fr.neatmonster.nocheatplus.config.ConfPaths ;
2012-08-24 14:52:24 +02:00
import fr.neatmonster.nocheatplus.config.ConfigFile ;
2012-04-26 23:36:43 +02:00
import fr.neatmonster.nocheatplus.config.ConfigManager ;
2012-11-08 10:43:44 +01:00
import fr.neatmonster.nocheatplus.event.IHaveMethodOrder ;
2012-11-07 12:56:25 +01:00
import fr.neatmonster.nocheatplus.event.ListenerManager ;
2012-09-16 20:34:01 +02:00
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager ;
2015-06-07 20:09:00 +02:00
import fr.neatmonster.nocheatplus.hooks.NCPHookManager ;
import fr.neatmonster.nocheatplus.hooks.allviolations.AllViolationsConfig ;
import fr.neatmonster.nocheatplus.hooks.allviolations.AllViolationsHook ;
2014-12-04 15:41:47 +01:00
import fr.neatmonster.nocheatplus.logging.BukkitLogManager ;
2014-11-19 00:00:31 +01:00
import fr.neatmonster.nocheatplus.logging.LogManager ;
2014-11-17 11:25:51 +01:00
import fr.neatmonster.nocheatplus.logging.StaticLog ;
2014-11-19 00:00:31 +01:00
import fr.neatmonster.nocheatplus.logging.Streams ;
2012-11-07 05:30:21 +01:00
import fr.neatmonster.nocheatplus.permissions.PermissionUtil ;
import fr.neatmonster.nocheatplus.permissions.PermissionUtil.CommandProtectionEntry ;
2012-11-06 10:11:17 +01:00
import fr.neatmonster.nocheatplus.permissions.Permissions ;
2012-09-20 20:16:00 +02:00
import fr.neatmonster.nocheatplus.players.DataManager ;
2013-06-11 20:06:57 +02:00
import fr.neatmonster.nocheatplus.players.PlayerData ;
2013-07-14 22:04:42 +02:00
import fr.neatmonster.nocheatplus.players.PlayerMessageSender ;
2014-07-27 18:26:58 +02:00
import fr.neatmonster.nocheatplus.stats.Counters ;
2013-05-22 12:24:48 +02:00
import fr.neatmonster.nocheatplus.updates.Updates ;
2012-09-15 10:09:45 +02:00
import fr.neatmonster.nocheatplus.utilities.BlockProperties ;
2013-08-10 01:41:34 +02:00
import fr.neatmonster.nocheatplus.utilities.ColorUtil ;
2013-04-18 17:10:12 +02:00
import fr.neatmonster.nocheatplus.utilities.OnDemandTickListener ;
2013-04-15 16:11:08 +02:00
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil ;
2015-01-11 18:52:08 +01:00
import fr.neatmonster.nocheatplus.utilities.StringUtil ;
2012-09-08 20:16:10 +02:00
import fr.neatmonster.nocheatplus.utilities.TickTask ;
2012-04-05 18:24:39 +02:00
2012-08-03 16:48:06 +02:00
/ * *
* This is the main class of NoCheatPlus . The commands , events listeners and tasks are registered here .
* /
2012-11-09 14:29:51 +01:00
public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
2014-08-07 18:56:05 +02:00
private static final String MSG_NOTIFY_OFF = ChatColor . RED + " NCP: " + ChatColor . WHITE + " Notifications are turned " + ChatColor . RED + " OFF " + ChatColor . WHITE + " . " ;
// Static API
/ * *
* Convenience method .
* @deprecated Use fr . neatmonster . nocheatplus . utilities . NCPAPIProvider . getNoCheatPlusAPI ( ) instead , this method might get removed .
* @return
* /
public static NoCheatPlusAPI getAPI ( ) {
return NCPAPIProvider . getNoCheatPlusAPI ( ) ;
}
// Not static.
2015-01-05 16:12:05 +01:00
2014-11-19 00:00:31 +01:00
/** Central logging access point. */
2014-12-04 15:41:47 +01:00
private BukkitLogManager logManager = null ; // Not final, but intended to stay, once set [change to init=syso?].
2014-08-07 18:56:05 +02:00
/** Names of players with a certain permission. */
protected final NameSetPermState nameSetPerms = new NameSetPermState ( Permissions . NOTIFY ) ;
/** Lower case player name to milliseconds point of time of release */
private final Map < String , Long > denyLoginNames = Collections . synchronizedMap ( new HashMap < String , Long > ( ) ) ;
/** MCAccess instance. */
protected MCAccess mcAccess = null ;
2013-05-21 22:49:05 +02:00
2013-07-14 19:14:37 +02:00
/** Configuration problems (likely put to ConfigManager later). */
protected String configProblems = null ;
2013-05-21 22:49:05 +02:00
2014-08-07 18:56:05 +02:00
// /** Is a new update available? */
// private boolean updateAvailable = false;
2013-05-21 22:49:05 +02:00
/** Player data future stuff. */
protected final DataManager dataMan = new DataManager ( ) ;
2014-08-07 18:56:05 +02:00
private int dataManTaskId = - 1 ;
/ * *
* Commands that were changed for protecting them against tab complete or
* use .
* /
protected List < CommandProtectionEntry > changedCommands = null ;
private final ListenerManager listenerManager = new ListenerManager ( this , false ) ;
private boolean manageListeners = true ;
2015-11-15 04:17:15 +01:00
protected boolean lateListenerRegistered = false ;
2014-08-07 18:56:05 +02:00
/** The event listeners. */
2013-05-21 22:49:05 +02:00
private final List < Listener > listeners = new ArrayList < Listener > ( ) ;
2014-08-07 18:56:05 +02:00
2014-07-27 15:17:08 +02:00
/** Storage for generic instances registration. */
private final Map < Class < ? > , Object > genericInstances = new HashMap < Class < ? > , Object > ( ) ;
2014-08-07 18:56:05 +02:00
2013-05-21 22:49:05 +02:00
/ * * Components that need notification on reloading .
* ( Kept here , for if during runtime some might get added . ) * /
private final List < INotifyReload > notifyReload = new LinkedList < INotifyReload > ( ) ;
2014-08-07 18:56:05 +02:00
2013-06-11 20:06:57 +02:00
/** If to use subscriptions or not. */
protected boolean useSubscriptions = false ;
2014-08-07 18:56:05 +02:00
/** Permission states stored on a per-world basis, updated with join/quit/kick. */
protected final List < PermStateReceiver > permStateReceivers = new ArrayList < PermStateReceiver > ( ) ;
/** Components that check consistency. */
protected final List < ConsistencyChecker > consistencyCheckers = new ArrayList < ConsistencyChecker > ( ) ;
/** Index at which to continue. */
protected int consistencyCheckerIndex = 0 ;
protected int consistencyCheckerTaskId = - 1 ;
/** Listeners for players joining and leaving (monitor level) */
protected final List < JoinLeaveListener > joinLeaveListeners = new ArrayList < JoinLeaveListener > ( ) ;
/** Sub component registries. */
protected final List < ComponentRegistry < ? > > subRegistries = new ArrayList < ComponentRegistry < ? > > ( ) ;
/** Queued sub component holders, emptied on the next tick usually. */
protected final List < IHoldSubComponents > subComponentholders = new ArrayList < IHoldSubComponents > ( 20 ) ;
private final List < DisableListener > disableListeners = new ArrayList < DisableListener > ( ) ;
/** All registered components. */
protected Set < Object > allComponents = new LinkedHashSet < Object > ( 50 ) ;
2015-01-05 16:12:05 +01:00
/** Feature tags by keys, for features that might not be available. */
private final LinkedHashMap < String , LinkedHashSet < String > > featureTags = new LinkedHashMap < String , LinkedHashSet < String > > ( ) ;
2015-06-07 20:09:00 +02:00
/** Hook for logging all violations. */
protected final AllViolationsHook allViolationsHook = new AllViolationsHook ( ) ;
2014-08-07 18:56:05 +02:00
/** Tick listener that is only needed sometimes (component registration). */
protected final OnDemandTickListener onDemandTickListener = new OnDemandTickListener ( ) {
@Override
public boolean delegateTick ( final int tick , final long timeLast ) {
processQueuedSubComponentHolders ( ) ;
return false ;
}
} ;
2015-01-13 01:19:56 +01:00
private class PostEnableTask implements Runnable {
private final NoCheatPlusCommand commandHandler ;
private final Player [ ] onlinePlayers ;
protected PostEnableTask ( NoCheatPlusCommand commandHandler , Player [ ] onlinePlayers ) {
this . commandHandler = commandHandler ;
this . onlinePlayers = onlinePlayers ;
}
@Override
public void run ( ) {
postEnable ( commandHandler , onlinePlayers ) ;
}
}
2014-08-07 18:56:05 +02:00
/** Access point for thread safe message queuing. */
private final PlayerMessageSender playerMessageSender = new PlayerMessageSender ( ) ;
2015-01-19 17:47:09 +01:00
private boolean clearExemptionsOnJoin = true ;
private boolean clearExemptionsOnLeave = true ;
2014-08-07 18:56:05 +02:00
/ * *
* Remove expired entries .
* /
2013-05-21 22:49:05 +02:00
private void checkDenyLoginsNames ( ) {
2014-08-07 18:56:05 +02:00
final long ts = System . currentTimeMillis ( ) ;
final List < String > rem = new LinkedList < String > ( ) ;
synchronized ( denyLoginNames ) {
for ( final Entry < String , Long > entry : denyLoginNames . entrySet ( ) ) {
if ( entry . getValue ( ) . longValue ( ) < ts ) rem . add ( entry . getKey ( ) ) ;
}
for ( final String name : rem ) {
denyLoginNames . remove ( name ) ;
}
}
}
2013-05-21 22:49:05 +02:00
@Override
public boolean allowLogin ( String playerName ) {
2014-08-07 18:56:05 +02:00
playerName = playerName . trim ( ) . toLowerCase ( ) ;
final Long time = denyLoginNames . remove ( playerName ) ;
if ( time = = null ) return false ;
return System . currentTimeMillis ( ) < = time ;
2012-09-15 18:16:32 +02:00
}
2014-08-07 18:56:05 +02:00
2013-05-21 22:49:05 +02:00
@Override
public int allowLoginAll ( ) {
2014-08-07 18:56:05 +02:00
int denied = 0 ;
final long now = System . currentTimeMillis ( ) ;
for ( final String playerName : denyLoginNames . keySet ( ) ) {
final Long time = denyLoginNames . get ( playerName ) ;
if ( time ! = null & & time > now ) denied + + ;
}
denyLoginNames . clear ( ) ;
return denied ;
2013-03-13 05:41:17 +01:00
}
2014-08-07 18:56:05 +02:00
2013-05-21 22:49:05 +02:00
@Override
2014-08-07 18:56:05 +02:00
public void denyLogin ( String playerName , long duration ) {
final long ts = System . currentTimeMillis ( ) + duration ;
playerName = playerName . trim ( ) . toLowerCase ( ) ;
synchronized ( denyLoginNames ) {
final Long oldTs = denyLoginNames . get ( playerName ) ;
if ( oldTs ! = null & & ts < oldTs . longValue ( ) ) return ;
denyLoginNames . put ( playerName , ts ) ;
// TODO: later maybe save these ?
}
checkDenyLoginsNames ( ) ;
}
2013-05-21 22:49:05 +02:00
@Override
2014-08-07 18:56:05 +02:00
public boolean isLoginDenied ( String playerName ) {
return isLoginDenied ( playerName , System . currentTimeMillis ( ) ) ;
}
2013-05-21 22:49:05 +02:00
@Override
2014-08-07 18:56:05 +02:00
public String [ ] getLoginDeniedPlayers ( ) {
checkDenyLoginsNames ( ) ;
String [ ] kicked = new String [ denyLoginNames . size ( ) ] ;
denyLoginNames . keySet ( ) . toArray ( kicked ) ;
return kicked ;
}
2012-09-10 10:10:45 +02:00
2013-05-21 22:49:05 +02:00
@Override
2014-08-07 18:56:05 +02:00
public boolean isLoginDenied ( String playerName , long time ) {
playerName = playerName . trim ( ) . toLowerCase ( ) ;
final Long oldTs = denyLoginNames . get ( playerName ) ;
if ( oldTs = = null ) return false ;
else return time < oldTs . longValue ( ) ;
}
2013-05-21 22:49:05 +02:00
@Override
2014-08-07 18:56:05 +02:00
public int sendAdminNotifyMessage ( final String message ) {
if ( useSubscriptions ) {
// TODO: Might respect console settings, or add extra config section (e.g. notifications).
return sendAdminNotifyMessageSubscriptions ( message ) ;
}
else {
return sendAdminNotifyMessageStored ( message ) ;
}
}
2013-06-11 20:06:57 +02:00
private final boolean hasTurnedOffNotifications ( final String playerName ) {
2014-08-07 18:56:05 +02:00
final PlayerData data = DataManager . getPlayerData ( playerName , false ) ;
return data ! = null & & data . getNotifyOff ( ) ;
}
/ * *
* Send notification to players with stored notify - permission ( world changes , login , permissions are not re - checked here ) .
* @param message
* @return
* /
public int sendAdminNotifyMessageStored ( final String message ) {
final Set < String > names = nameSetPerms . getPlayers ( Permissions . NOTIFY ) ;
if ( names = = null ) return 0 ;
int done = 0 ;
for ( final String name : names ) {
if ( hasTurnedOffNotifications ( name ) ) {
// Has turned off notifications.
continue ;
}
final Player player = DataManager . getPlayerExact ( name ) ;
if ( player ! = null ) {
player . sendMessage ( message ) ;
done + + ;
}
}
return done ;
}
/ * *
* Send notification to all CommandSenders found in permission subscriptions for the notify - permission as well as players that have stored permissions ( those get re - checked here ) .
* @param message
* @return
* /
public int sendAdminNotifyMessageSubscriptions ( final String message ) {
final Set < Permissible > permissibles = Bukkit . getPluginManager ( ) . getPermissionSubscriptions ( Permissions . NOTIFY ) ;
final Set < String > names = nameSetPerms . getPlayers ( Permissions . NOTIFY ) ;
final Set < String > done = new HashSet < String > ( permissibles . size ( ) + ( names = = null ? 0 : names . size ( ) ) ) ;
for ( final Permissible permissible : permissibles ) {
if ( permissible instanceof CommandSender & & permissible . hasPermission ( Permissions . NOTIFY ) ) {
final CommandSender sender = ( CommandSender ) permissible ;
if ( ( sender instanceof Player ) & & hasTurnedOffNotifications ( ( ( Player ) sender ) . getName ( ) ) ) {
continue ;
}
sender . sendMessage ( message ) ;
done . add ( sender . getName ( ) ) ;
}
}
// Fall-back checking for players.
if ( names ! = null ) {
for ( final String name : names ) {
if ( ! done . contains ( name ) ) {
final Player player = DataManager . getPlayerExact ( name ) ;
if ( player ! = null & & player . hasPermission ( Permissions . NOTIFY ) ) {
if ( hasTurnedOffNotifications ( player . getName ( ) ) ) {
continue ;
}
player . sendMessage ( message ) ;
done . add ( name ) ;
}
}
}
}
return done . size ( ) ;
}
/ * ( non - Javadoc )
* @see fr . neatmonster . nocheatplus . components . NoCheatPlusAPI # sendMessageDelayed ( java . lang . String , java . lang . String )
* /
@Override
public void sendMessageOnTick ( final String playerName , final String message ) {
playerMessageSender . sendMessageThreadSafe ( playerName , message ) ;
}
@SuppressWarnings ( " unchecked " )
@Override
public < T > Collection < ComponentRegistry < T > > getComponentRegistries ( final Class < ComponentRegistry < T > > clazz ) {
final List < ComponentRegistry < T > > result = new LinkedList < ComponentRegistry < T > > ( ) ;
for ( final ComponentRegistry < ? > registry : subRegistries ) {
if ( clazz . isAssignableFrom ( registry . getClass ( ) ) ) {
try {
result . add ( ( ComponentRegistry < T > ) registry ) ;
}
catch ( Throwable t ) {
// Ignore.
}
}
}
return result ;
2013-06-11 20:06:57 +02:00
}
2014-08-07 18:56:05 +02:00
/ * *
* Convenience method to add components according to implemented interfaces ,
2013-04-15 16:11:08 +02:00
* like Listener , INotifyReload , INeedConfig . < br >
* For the NoCheatPlus instance this must be done after the configuration has been initialized .
* This will also register ComponentRegistry instances if given .
2014-08-07 18:56:05 +02:00
* /
@Override
public boolean addComponent ( final Object obj ) {
return addComponent ( obj , true ) ;
}
/ * *
* Convenience method to add components according to implemented interfaces ,
2013-04-15 16:11:08 +02:00
* like Listener , INotifyReload , INeedConfig . < br >
* For the NoCheatPlus instance this must be done after the configuration has been initialized .
* @param allowComponentRegistry Only registers ComponentRegistry instances if this is set to true .
2014-08-07 18:56:05 +02:00
* /
@Override
public boolean addComponent ( final Object obj , final boolean allowComponentRegistry ) {
// TODO: Allow to add ComponentFactory + contract (renew with reload etc.)?
if ( obj = = this ) throw new IllegalArgumentException ( " Can not register NoCheatPlus with itself. " ) ;
if ( allComponents . contains ( obj ) ) {
// All added components are in here.
return false ;
}
boolean added = false ;
if ( obj instanceof Listener ) {
addListener ( ( Listener ) obj ) ;
added = true ;
}
if ( obj instanceof INotifyReload ) {
notifyReload . add ( ( INotifyReload ) obj ) ;
if ( obj instanceof INeedConfig ) {
( ( INeedConfig ) obj ) . onReload ( ) ;
}
added = true ;
}
if ( obj instanceof TickListener ) {
TickTask . addTickListener ( ( TickListener ) obj ) ;
added = true ;
}
if ( obj instanceof PermStateReceiver ) {
// No immediate update done.
permStateReceivers . add ( ( PermStateReceiver ) obj ) ;
added = true ;
}
if ( obj instanceof MCAccessHolder ) {
// These will get notified in initMcAccess (iterates over allComponents).
( ( MCAccessHolder ) obj ) . setMCAccess ( getMCAccess ( ) ) ;
added = true ;
}
if ( obj instanceof ConsistencyChecker ) {
consistencyCheckers . add ( ( ConsistencyChecker ) obj ) ;
added = true ;
}
if ( obj instanceof JoinLeaveListener ) {
joinLeaveListeners . add ( ( JoinLeaveListener ) obj ) ;
added = true ;
}
if ( obj instanceof DisableListener ) {
disableListeners . add ( ( DisableListener ) obj ) ;
added = true ;
}
// Add to sub registries.
for ( final ComponentRegistry < ? > registry : subRegistries ) {
final Object res = ReflectionUtil . invokeGenericMethodOneArg ( registry , " addComponent " , obj ) ;
if ( res ! = null & & ( res instanceof Boolean ) & & ( ( Boolean ) res ) . booleanValue ( ) ) {
added = true ;
}
}
// Add ComponentRegistry instances after adding to sub registries to prevent adding it to itself.
if ( allowComponentRegistry & & ( obj instanceof ComponentRegistry < ? > ) ) {
subRegistries . add ( ( ComponentRegistry < ? > ) obj ) ;
added = true ;
}
// Components holding more components to register later.
if ( obj instanceof IHoldSubComponents ) {
subComponentholders . add ( ( IHoldSubComponents ) obj ) ;
onDemandTickListener . register ( ) ;
added = true ; // Convention.
}
// Add to allComponents if in fact added.
if ( added ) allComponents . add ( obj ) ;
return added ;
}
/ * *
* Interfaces checked for managed listeners : IHaveMethodOrder ( method ) , ComponentWithName ( tag ) < br >
* @param listener
* /
private void addListener ( final Listener listener ) {
// private: Use addComponent.
if ( manageListeners ) {
String tag = " NoCheatPlus " ;
if ( listener instanceof ComponentWithName ) {
tag = ( ( ComponentWithName ) listener ) . getComponentName ( ) ;
}
listenerManager . registerAllEventHandlers ( listener , tag ) ;
listeners . add ( listener ) ;
}
else {
Bukkit . getPluginManager ( ) . registerEvents ( listener , this ) ;
if ( listener instanceof IHaveMethodOrder ) {
// TODO: Might log the order too, might prevent registration ?
// TODO: Alternative: queue listeners and register after startup (!)
2015-11-15 02:15:20 +01:00
logManager . warning ( Streams . INIT , " Listener demands registration order, but listeners are not managed: " + listener . getClass ( ) . getName ( ) ) ;
2014-08-07 18:56:05 +02:00
}
}
}
/ * *
* Test if NCP uses the ListenerManager at all .
* @return If so .
* /
public boolean doesManageListeners ( ) {
return manageListeners ;
}
@Override
public void removeComponent ( final Object obj ) {
if ( obj instanceof Listener ) {
listeners . remove ( obj ) ;
listenerManager . remove ( ( Listener ) obj ) ;
}
if ( obj instanceof PermStateReceiver ) {
permStateReceivers . remove ( ( PermStateReceiver ) obj ) ;
}
if ( obj instanceof TickListener ) {
TickTask . removeTickListener ( ( TickListener ) obj ) ;
}
if ( obj instanceof INotifyReload ) {
notifyReload . remove ( obj ) ;
}
if ( obj instanceof ConsistencyChecker ) {
consistencyCheckers . remove ( obj ) ;
}
if ( obj instanceof JoinLeaveListener ) {
joinLeaveListeners . remove ( ( JoinLeaveListener ) obj ) ;
}
if ( obj instanceof DisableListener ) {
disableListeners . remove ( obj ) ;
}
// Remove sub registries.
if ( obj instanceof ComponentRegistry < ? > ) {
subRegistries . remove ( obj ) ;
}
// Remove from present registries, order prevents to remove from itself.
for ( final ComponentRegistry < ? > registry : subRegistries ) {
ReflectionUtil . invokeGenericMethodOneArg ( registry , " removeComponent " , obj ) ;
}
allComponents . remove ( obj ) ;
}
2012-08-03 16:48:06 +02:00
/ * ( non - Javadoc )
* @see org . bukkit . plugin . java . JavaPlugin # onDisable ( )
* /
2012-04-05 18:24:39 +02:00
@Override
public void onDisable ( ) {
2014-08-07 18:56:05 +02:00
2015-01-25 03:18:24 +01:00
final boolean verbose = ConfigManager . getConfigFile ( ) . getBoolean ( ConfPaths . LOGGING_EXTENDED_STATUS ) ;
2014-08-07 18:56:05 +02:00
// Remove listener references.
if ( verbose ) {
if ( listenerManager . hasListenerMethods ( ) ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Cleanup ListenerManager... " ) ;
2014-08-07 18:56:05 +02:00
}
else {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " (ListenerManager not in use, prevent registering...) " ) ;
2014-08-07 18:56:05 +02:00
}
}
listenerManager . setRegisterDirectly ( false ) ;
listenerManager . clear ( ) ;
2015-11-15 04:17:15 +01:00
lateListenerRegistered = false ;
2014-08-07 18:56:05 +02:00
BukkitScheduler sched = getServer ( ) . getScheduler ( ) ;
// Stop data-man task.
if ( dataManTaskId ! = - 1 ) {
sched . cancelTask ( dataManTaskId ) ;
dataManTaskId = - 1 ;
}
2012-09-08 20:16:10 +02:00
// Stop the tickTask.
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Stop TickTask... " ) ;
2014-08-07 18:56:05 +02:00
}
2012-12-02 17:03:43 +01:00
TickTask . setLocked ( true ) ;
2012-12-02 17:39:50 +01:00
TickTask . purge ( ) ;
2012-09-08 20:16:10 +02:00
TickTask . cancel ( ) ;
2013-01-30 04:22:06 +01:00
TickTask . removeAllTickListeners ( ) ;
2013-01-13 20:44:23 +01:00
// (Keep the tick task locked!)
2014-08-07 18:56:05 +02:00
// Stop consistency checking task.
if ( consistencyCheckerTaskId ! = - 1 ) {
sched . cancelTask ( consistencyCheckerTaskId ) ;
consistencyCheckerTaskId = - 1 ;
}
2012-09-08 20:16:10 +02:00
// Just to be sure nothing gets left out.
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Stop all remaining tasks... " ) ;
2014-08-07 18:56:05 +02:00
}
2013-02-27 18:00:44 +01:00
sched . cancelTasks ( this ) ;
2012-04-05 18:24:39 +02:00
2015-06-07 20:09:00 +02:00
// Remove hooks.
allViolationsHook . unregister ( ) ;
NCPHookManager . removeAllHooks ( ) ;
2013-01-25 23:51:29 +01:00
// Exemptions cleanup.
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Reset ExemptionManager... " ) ;
2014-08-07 18:56:05 +02:00
}
2013-01-25 23:51:29 +01:00
NCPExemptionManager . clear ( ) ;
2014-08-07 18:56:05 +02:00
// Data cleanup.
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " onDisable calls (include DataManager cleanup)... " ) ;
2014-08-07 18:56:05 +02:00
}
for ( final DisableListener dl : disableListeners ) {
try {
dl . onDisable ( ) ;
} catch ( Throwable t ) {
2014-11-19 00:00:31 +01:00
logManager . severe ( Streams . INIT , " DisableListener ( " + dl . getClass ( ) . getName ( ) + " ): " + t . getClass ( ) . getSimpleName ( ) + " / " + t . getMessage ( ) ) ;
logManager . severe ( Streams . INIT , t ) ;
2014-08-07 18:56:05 +02:00
}
}
// Write some debug/statistics.
final Counters counters = getGenericInstance ( Counters . class ) ;
2015-01-25 03:18:24 +01:00
if ( counters ! = null ) {
// Ensure we get this kind of information for the time being.
if ( verbose ) {
logManager . info ( Streams . INIT , counters . getMergedCountsString ( true ) ) ; // Server logger needs info level.
} else {
logManager . debug ( Streams . TRACE_FILE , counters . getMergedCountsString ( true ) ) ;
}
2014-08-07 18:56:05 +02:00
}
// Hooks:
// (Expect external plugins to unregister their hooks on their own.)
// (No native hooks present, yet.)
// Unregister all added components explicitly.
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Unregister all registered components... " ) ;
2014-08-07 18:56:05 +02:00
}
final ArrayList < Object > allComponents = new ArrayList < Object > ( this . allComponents ) ;
2013-04-15 16:11:08 +02:00
for ( int i = allComponents . size ( ) - 1 ; i > = 0 ; i - - ) {
2014-08-07 18:56:05 +02:00
removeComponent ( allComponents . get ( i ) ) ;
2013-01-25 23:51:29 +01:00
}
2014-08-07 18:56:05 +02:00
2013-01-30 03:22:58 +01:00
// Cleanup BlockProperties.
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Cleanup BlockProperties... " ) ;
2014-08-07 18:56:05 +02:00
}
2013-01-30 03:22:58 +01:00
BlockProperties . cleanup ( ) ;
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Cleanup some mappings... " ) ;
2014-08-07 18:56:05 +02:00
}
2013-01-25 23:51:29 +01:00
// Remove listeners.
listeners . clear ( ) ;
// Remove config listeners.
notifyReload . clear ( ) ;
// World specific permissions.
2014-08-07 18:56:05 +02:00
permStateReceivers . clear ( ) ;
// Sub registries.
subRegistries . clear ( ) ;
// Just in case: clear the subComponentHolders.
subComponentholders . clear ( ) ;
// Generic instances registry.
genericInstances . clear ( ) ;
2015-01-05 16:12:05 +01:00
// Feature tags.
featureTags . clear ( ) ;
2014-08-07 18:56:05 +02:00
// Clear command changes list (compatibility issues with NPCs, leads to recalculation of perms).
if ( changedCommands ! = null ) {
changedCommands . clear ( ) ;
changedCommands = null ;
}
// // Restore changed commands.
2015-11-15 02:15:20 +01:00
// if (verbose) LogUtil.logInfo("Undo command changes...");
2014-08-07 18:56:05 +02:00
// undoCommandChanges();
// Cleanup the configuration manager.
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Cleanup ConfigManager... " ) ;
2014-08-07 18:56:05 +02:00
}
ConfigManager . cleanup ( ) ;
// Cleanup file logger.
if ( verbose ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Shutdown LogManager... " ) ;
2014-08-07 18:56:05 +02:00
}
2014-11-21 23:45:02 +01:00
StaticLog . setUseLogManager ( false ) ;
2014-11-23 15:47:10 +01:00
StaticLog . setStreamID ( Streams . INIT ) ;
2014-11-19 00:00:31 +01:00
logManager . shutdown ( ) ;
2014-08-07 18:56:05 +02:00
2014-11-23 15:47:10 +01:00
// Tell the server administrator that we finished unloading NoCheatPlus.
2014-08-07 18:56:05 +02:00
if ( verbose ) {
2015-11-15 02:15:20 +01:00
Bukkit . getLogger ( ) . info ( " All cleanup done. " ) ;
2014-08-07 18:56:05 +02:00
}
final PluginDescriptionFile pdfFile = getDescription ( ) ;
2015-11-15 02:15:20 +01:00
Bukkit . getLogger ( ) . info ( " Version " + pdfFile . getVersion ( ) + " is disabled. " ) ;
2014-08-07 18:56:05 +02:00
}
/ * *
* Does not undo 100 % , but restore old permission , permission - message , label ( unlikely to be changed ) , permission default .
* @deprecated Leads to compatibility issues with NPC plugins such as Citizens 2 , due to recalculation of permissions ( specifically during disabling ) .
* /
public void undoCommandChanges ( ) {
if ( changedCommands ! = null ) {
while ( ! changedCommands . isEmpty ( ) ) {
final CommandProtectionEntry entry = changedCommands . remove ( changedCommands . size ( ) - 1 ) ;
entry . restore ( ) ;
}
changedCommands = null ;
}
}
protected void setupCommandProtection ( ) {
// TODO: Might re-check with plugins enabling during runtime (!).
final List < CommandProtectionEntry > changedCommands = new LinkedList < CommandProtectionEntry > ( ) ;
// Read lists and messages from config.
final ConfigFile config = ConfigManager . getConfigFile ( ) ;
// (Might add options to invert selection.)
// "No permission".
// TODO: Could/should set permission message to null here (server default), might use keyword "default".
final List < String > noPerm = config . getStringList ( ConfPaths . PROTECT_PLUGINS_HIDE_NOPERMISSION_CMDS ) ;
if ( noPerm ! = null & & ! noPerm . isEmpty ( ) ) {
final String noPermMsg = ColorUtil . replaceColors ( ConfigManager . getConfigFile ( ) . getString ( ConfPaths . PROTECT_PLUGINS_HIDE_NOPERMISSION_MSG ) ) ;
changedCommands . addAll ( PermissionUtil . protectCommands ( Permissions . FILTER_COMMAND , noPerm , true , false , noPermMsg ) ) ;
}
// "Unknown command", override the other option.
final List < String > noCommand = config . getStringList ( ConfPaths . PROTECT_PLUGINS_HIDE_NOCOMMAND_CMDS ) ;
if ( noCommand ! = null & & ! noCommand . isEmpty ( ) ) {
final String noCommandMsg = ColorUtil . replaceColors ( ConfigManager . getConfigFile ( ) . getString ( ConfPaths . PROTECT_PLUGINS_HIDE_NOCOMMAND_MSG ) ) ;
changedCommands . addAll ( PermissionUtil . protectCommands ( Permissions . FILTER_COMMAND , noCommand , true , false , noCommandMsg ) ) ;
}
// Add to changes history for undoing.
if ( this . changedCommands = = null ) {
this . changedCommands = changedCommands ;
}
else {
this . changedCommands . addAll ( changedCommands ) ;
}
}
/ * ( non - Javadoc )
* @see org . bukkit . plugin . java . JavaPlugin # onLoad ( )
* /
@Override
public void onLoad ( ) {
2015-11-15 02:15:20 +01:00
Bukkit . getLogger ( ) . info ( " onLoad: Early set up of static API, configuration, logging. " ) ;
2015-01-17 05:20:18 +01:00
setupBasics ( ) ;
}
/ * *
* Lazy initialization of basics ( static API , configuration , logging ) .
* /
private void setupBasics ( ) {
if ( NCPAPIProvider . getNoCheatPlusAPI ( ) = = null ) {
NCPAPIProvider . setNoCheatPlusAPI ( this ) ;
}
2015-11-26 09:38:05 +01:00
if ( ServerVersion . getMinecraftVersion ( ) = = GenericVersion . UNKNOWN_VERSION ) {
2015-01-17 05:20:18 +01:00
BukkitVersion . init ( ) ;
}
if ( ! ConfigManager . isInitialized ( ) ) {
ConfigManager . init ( this ) ;
}
if ( logManager = = null | | logManager . getStreamID ( Streams . STATUS . name ) ! = Streams . STATUS ) {
logManager = new BukkitLogManager ( this ) ;
StaticLog . setStreamID ( Streams . INIT ) ;
StaticLog . setUseLogManager ( true ) ;
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Logging system initialized. " ) ;
logManager . info ( Streams . INIT , " Detected Minecraft version: " + ServerVersion . getMinecraftVersion ( ) ) ;
2015-01-17 05:20:18 +01:00
}
2014-08-07 18:56:05 +02:00
}
/ * ( non - Javadoc )
2012-08-03 16:48:06 +02:00
* @see org . bukkit . plugin . java . JavaPlugin # onEnable ( )
* /
2012-04-05 18:24:39 +02:00
@Override
public void onEnable ( ) {
2014-08-07 18:56:05 +02:00
// Reset TickTask (just in case).
TickTask . setLocked ( true ) ;
TickTask . purge ( ) ;
TickTask . cancel ( ) ;
TickTask . reset ( ) ;
2015-01-05 16:12:05 +01:00
2015-01-17 05:20:18 +01:00
// Allow entries to TickTask.
2014-11-19 23:09:14 +01:00
TickTask . setLocked ( false ) ;
2015-01-05 16:12:05 +01:00
2015-01-17 05:20:18 +01:00
// Re-check basic setup (if onLoad gets skipped by some custom thing).
setupBasics ( ) ;
2015-01-05 16:12:05 +01:00
2014-11-19 23:09:14 +01:00
// Start logger task(s).
logManager . startTasks ( ) ;
2015-01-05 16:12:05 +01:00
2015-01-17 05:20:18 +01:00
final ConfigFile config = ConfigManager . getConfigFile ( ) ;
2015-01-19 17:47:09 +01:00
// Set some instance members.
setInstanceMembers ( config ) ;
2015-01-05 16:12:05 +01:00
2015-01-17 05:20:18 +01:00
// Listener manager.
2014-08-07 18:56:05 +02:00
manageListeners = config . getBoolean ( ConfPaths . COMPATIBILITY_MANAGELISTENERS ) ;
if ( manageListeners ) {
listenerManager . setRegisterDirectly ( true ) ;
listenerManager . registerAllWithBukkit ( ) ;
}
else {
// Just for safety.
listenerManager . setRegisterDirectly ( false ) ;
listenerManager . clear ( ) ;
}
2014-11-19 23:09:14 +01:00
// Register some generic stuff.
// Counters: debugging purposes, maybe integrated for statistics later.
registerGenericInstance ( new Counters ( ) ) ;
// Initialize MCAccess.
initMCAccess ( config ) ;
// Initialize BlockProperties.
initBlockProperties ( config ) ;
// Initialize data manager.
disableListeners . add ( 0 , dataMan ) ;
dataMan . onEnable ( ) ;
2015-01-05 16:12:05 +01:00
2014-11-19 23:09:14 +01:00
// Register components.
2014-08-07 18:56:05 +02:00
@SetupOrder ( priority = - 100 )
class ReloadHook implements INotifyReload {
@Override
public void onReload ( ) {
// Only for reloading, not INeedConfig.
processReload ( ) ;
}
}
// Add the "low level" system components first.
for ( final Object obj : new Object [ ] {
nameSetPerms ,
getCoreListener ( ) ,
// Put ReloadListener first, because Checks could also listen to it.
new ReloadHook ( ) ,
dataMan ,
} ) {
addComponent ( obj ) ;
// Register sub-components (allow later added to use registries, if any).
2013-05-22 12:24:48 +02:00
processQueuedSubComponentHolders ( ) ;
2014-08-07 18:56:05 +02:00
}
// Register "higher level" components (check listeners).
2012-09-20 20:16:00 +02:00
for ( final Object obj : new Object [ ] {
2014-08-07 18:56:05 +02:00
new BlockInteractListener ( ) ,
new BlockBreakListener ( ) ,
new BlockPlaceListener ( ) ,
new ChatListener ( ) ,
new CombinedListener ( ) ,
// Do mind registration order: Combined must come before Fight.
new FightListener ( ) ,
new InventoryListener ( ) ,
new MovingListener ( ) ,
2012-09-04 06:48:21 +02:00
} ) {
2014-08-07 18:56:05 +02:00
addComponent ( obj ) ;
2013-05-22 12:24:48 +02:00
// Register sub-components (allow later added to use registries, if any).
processQueuedSubComponentHolders ( ) ;
2012-09-04 06:48:21 +02:00
}
2014-08-07 18:56:05 +02:00
2013-05-22 12:24:48 +02:00
// Register optional default components.
final DefaultComponentFactory dcf = new DefaultComponentFactory ( ) ;
2014-07-12 22:30:51 +02:00
for ( final Object obj : dcf . getAvailableComponentsOnEnable ( this ) ) {
2014-08-07 18:56:05 +02:00
addComponent ( obj ) ;
// Register sub-components to enable registries for optional components.
2013-05-22 12:24:48 +02:00
processQueuedSubComponentHolders ( ) ;
}
2014-08-07 18:56:05 +02:00
2012-09-04 08:52:03 +02:00
// Register the commands handler.
2013-06-12 02:08:22 +02:00
final PluginCommand command = getCommand ( " nocheatplus " ) ;
final NoCheatPlusCommand commandHandler = new NoCheatPlusCommand ( this , notifyReload ) ;
2012-11-07 05:30:21 +01:00
command . setExecutor ( commandHandler ) ;
// (CommandHandler is TabExecutor.)
2014-08-07 18:56:05 +02:00
2012-09-08 20:16:10 +02:00
// Set up the tick task.
TickTask . start ( this ) ;
2014-08-07 18:56:05 +02:00
2013-01-29 17:12:04 +01:00
this . dataManTaskId = Bukkit . getScheduler ( ) . scheduleSyncRepeatingTask ( this , new Runnable ( ) {
2014-08-07 18:56:05 +02:00
@Override
public void run ( ) {
dataMan . checkExpiration ( ) ;
}
} , 1207 , 1207 ) ;
2013-02-27 18:00:44 +01:00
// Set up consistency checking.
scheduleConsistencyCheckers ( ) ;
2012-08-20 19:40:00 +02:00
2015-06-07 20:09:00 +02:00
// Setup allViolationsHook
allViolationsHook . setConfig ( new AllViolationsConfig ( config ) ) ;
2014-08-07 18:56:05 +02:00
// if (config.getBoolean(ConfPaths.MISCELLANEOUS_CHECKFORUPDATES)){
// // Is a new update available?
// final int timeout = config.getInt(ConfPaths.MISCELLANEOUS_UPDATETIMEOUT, 4) * 1000;
// getServer().getScheduler().scheduleAsyncDelayedTask(this, new Runnable() {
// @Override
// public void run() {
// updateAvailable = Updates.checkForUpdates(getDescription().getVersion(), timeout);
// }
// });
// }
2012-08-22 02:41:28 +02:00
2013-07-14 19:14:37 +02:00
// Is the version the configuration was created with consistent with the current one?
if ( configProblems ! = null & & config . getBoolean ( ConfPaths . CONFIGVERSION_NOTIFY ) ) {
2014-08-07 18:56:05 +02:00
// Could use custom prefix from logging, however ncp should be mentioned then.
2015-11-15 02:15:20 +01:00
logManager . warning ( Streams . INIT , " " + configProblems ) ;
2014-08-07 18:56:05 +02:00
}
// Care for already online players.
2014-12-01 00:06:41 +01:00
final Player [ ] onlinePlayers = BridgeMisc . getOnlinePlayers ( ) ;
2014-08-07 18:56:05 +02:00
// TODO: re-map ExemptionManager !
// TODO: Disable all checks for these players for one tick ?
// TODO: Prepare check data for players [problem: permissions]?
2015-01-13 01:19:56 +01:00
Bukkit . getScheduler ( ) . scheduleSyncDelayedTask ( this , new PostEnableTask ( commandHandler , onlinePlayers ) ) ;
2015-01-05 16:12:05 +01:00
2014-11-23 15:47:10 +01:00
// Set StaticLog to more efficient output.
StaticLog . setStreamID ( Streams . STATUS ) ;
2014-08-07 18:56:05 +02:00
// Tell the server administrator that we finished loading NoCheatPlus now.
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Version " + getDescription ( ) . getVersion ( ) + " is enabled. " ) ;
2014-08-07 18:56:05 +02:00
}
2013-09-13 02:53:09 +02:00
/ * *
* Actions to be done after enable of all plugins . This aims at reloading mainly .
* /
2015-01-13 01:19:56 +01:00
protected void postEnable ( final NoCheatPlusCommand commandHandler , final Player [ ] onlinePlayers ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Post-enable running... " ) ;
2015-01-13 01:19:56 +01:00
try {
// Set child permissions for commands for faster checking.
PermissionUtil . addChildPermission ( commandHandler . getAllSubCommandPermissions ( ) , Permissions . FILTER_COMMAND_NOCHEATPLUS , PermissionDefault . OP ) ;
} catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " Failed to complement permissions: " + t . getClass ( ) . getSimpleName ( ) ) ;
2015-01-13 01:19:56 +01:00
logManager . severe ( Streams . INIT , t ) ;
}
try {
// Command protection feature.
if ( ConfigManager . getConfigFile ( ) . getBoolean ( ConfPaths . PROTECT_PLUGINS_HIDE_ACTIVE ) ) {
setupCommandProtection ( ) ;
2014-08-01 21:06:23 +02:00
}
2015-01-13 01:19:56 +01:00
} catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " Failed to apply command protection: " + t . getClass ( ) . getSimpleName ( ) ) ;
2015-01-13 01:19:56 +01:00
logManager . severe ( Streams . INIT , t ) ;
2014-08-01 21:06:23 +02:00
}
for ( final Player player : onlinePlayers ) {
updatePermStateReceivers ( player ) ;
if ( player . isSleeping ( ) ) {
CombinedData . getData ( player ) . wasInBed = true ;
}
}
// TODO: if (online.lenght > 0) LogUtils.logInfo("[NCP] Updated " + online.length + "players (post-enable).")
2015-11-15 04:17:15 +01:00
// Register late listener.
Bukkit . getPluginManager ( ) . registerEvents ( getLateListener ( ) , this ) ;
lateListenerRegistered = true ;
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " Post-enable finished. " ) ;
2015-01-11 18:52:08 +01:00
logManager . info ( Streams . DEFAULT_FILE , StringUtil . join ( VersionCommand . getVersionInfo ( ) , " \ n " ) ) ; // Queued (!).
2013-09-13 02:53:09 +02:00
}
2013-07-09 16:50:10 +02:00
2014-08-07 18:56:05 +02:00
/ * *
2013-04-15 16:11:08 +02:00
* Empties and registers the subComponentHolders list .
* /
protected void processQueuedSubComponentHolders ( ) {
2014-08-07 18:56:05 +02:00
if ( subComponentholders . isEmpty ( ) ) return ;
final List < IHoldSubComponents > copied = new ArrayList < IHoldSubComponents > ( subComponentholders ) ;
subComponentholders . clear ( ) ;
for ( final IHoldSubComponents holder : copied ) {
for ( final Object component : holder . getSubComponents ( ) ) {
addComponent ( component ) ;
}
}
2013-04-15 16:11:08 +02:00
}
2014-08-07 18:56:05 +02:00
2013-03-01 19:14:51 +01:00
/ * *
* All action done on reload .
* /
protected void processReload ( ) {
2014-08-07 18:56:05 +02:00
final ConfigFile config = ConfigManager . getConfigFile ( ) ;
2015-01-19 17:47:09 +01:00
setInstanceMembers ( config ) ;
2014-08-07 18:56:05 +02:00
// TODO: Process registered ComponentFactory instances.
// Set up MCAccess.
initMCAccess ( config ) ;
// Initialize BlockProperties
initBlockProperties ( config ) ;
// Reset Command protection.
undoCommandChanges ( ) ;
if ( config . getBoolean ( ConfPaths . PROTECT_PLUGINS_HIDE_ACTIVE ) ) {
setupCommandProtection ( ) ;
}
// (Re-) schedule consistency checking.
scheduleConsistencyCheckers ( ) ;
2015-06-07 20:09:00 +02:00
// Cache some things. TODO: Where is this comment from !?
// Re-setup allViolationsHook.
allViolationsHook . setConfig ( new AllViolationsConfig ( config ) ) ;
2015-01-19 17:47:09 +01:00
}
/ * *
* Set instance members based on the given configuration . This is meant to
* work after reloading the configuration too .
*
* @param config
* /
private void setInstanceMembers ( final ConfigFile config ) {
configProblems = Updates . isConfigUpToDate ( config ) ;
2014-08-07 18:56:05 +02:00
useSubscriptions = config . getBoolean ( ConfPaths . LOGGING_BACKEND_INGAMECHAT_SUBSCRIPTIONS ) ;
2015-01-19 17:47:09 +01:00
clearExemptionsOnJoin = config . getBoolean ( ConfPaths . COMPATIBILITY_EXEMPTIONS_REMOVE_JOIN ) ;
clearExemptionsOnLeave = config . getBoolean ( ConfPaths . COMPATIBILITY_EXEMPTIONS_REMOVE_LEAVE ) ;
2014-08-07 18:56:05 +02:00
}
2015-01-05 16:12:05 +01:00
2014-11-19 00:00:31 +01:00
@Override
public LogManager getLogManager ( ) {
return logManager ;
}
2014-08-07 18:56:05 +02:00
@Override
public MCAccess getMCAccess ( ) {
if ( mcAccess = = null ) initMCAccess ( ) ;
return mcAccess ;
}
/ * *
* Fall - back method to initialize from factory , only if not yet set . Uses the BukkitScheduler to ensure this works if called from async checks .
* /
private void initMCAccess ( ) {
getServer ( ) . getScheduler ( ) . callSyncMethod ( this , new Callable < MCAccess > ( ) {
@Override
public MCAccess call ( ) throws Exception {
if ( mcAccess ! = null ) return mcAccess ;
return initMCAccess ( ConfigManager . getConfigFile ( ) ) ;
}
} ) ;
2013-03-01 19:14:51 +01:00
}
2014-08-07 18:56:05 +02:00
2013-01-20 05:59:46 +01:00
/ * *
2013-05-21 22:49:05 +02:00
* Re - setup MCAccess from internal factory and pass it to MCAccessHolder components , only call from the main thread .
2013-01-30 04:22:06 +01:00
* @param config
2013-01-20 05:59:46 +01:00
* /
2013-05-21 22:49:05 +02:00
public MCAccess initMCAccess ( final ConfigFile config ) {
2014-08-07 18:56:05 +02:00
// Reset MCAccess.
// TODO: Might fire a NCPSetMCAccessFromFactoryEvent (include getting and setting)!
2015-06-06 22:30:37 +02:00
final MCAccess mcAccess = new MCAccessFactory ( ) . getMCAccess ( new MCAccessConfig ( ) ) ;
2014-08-07 18:56:05 +02:00
setMCAccess ( mcAccess ) ;
return mcAccess ;
}
2013-05-21 22:49:05 +02:00
/ * *
* Set and propagate to registered MCAccessHolder instances .
* /
@Override
public void setMCAccess ( final MCAccess mcAccess ) {
2014-08-07 18:56:05 +02:00
// Just sets it and propagates it.
// TODO: Might fire a NCPSetMCAccessEvent (include getting and setting)!
this . mcAccess = mcAccess ;
for ( final Object obj : this . allComponents ) {
if ( obj instanceof MCAccessHolder ) {
try {
( ( MCAccessHolder ) obj ) . setMCAccess ( mcAccess ) ;
} catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " MCAccessHolder( " + obj . getClass ( ) . getName ( ) + " ) failed to set MCAccess: " + t . getClass ( ) . getSimpleName ( ) ) ;
2014-11-19 00:00:31 +01:00
logManager . severe ( Streams . INIT , t ) ;
2014-08-07 18:56:05 +02:00
}
}
}
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . INIT , " McAccess set to: " + mcAccess . getMCVersion ( ) + " / " + mcAccess . getServerVersionTag ( ) ) ;
2013-05-21 22:49:05 +02:00
}
2013-01-30 04:22:06 +01:00
2014-08-07 18:56:05 +02:00
/ * *
2013-01-30 04:22:06 +01:00
* Initialize BlockProperties , including config .
* /
protected void initBlockProperties ( ConfigFile config ) {
2013-01-20 05:59:46 +01:00
// Set up BlockProperties.
2013-01-30 10:42:29 +01:00
BlockProperties . init ( getMCAccess ( ) , ConfigManager . getWorldConfigProvider ( ) ) ;
2013-01-20 05:59:46 +01:00
BlockProperties . applyConfig ( config , ConfPaths . COMPATIBILITY_BLOCKS ) ;
2013-02-20 22:30:55 +01:00
// Schedule dumping the blocks properties (to let other plugins override).
Bukkit . getScheduler ( ) . scheduleSyncDelayedTask ( this , new Runnable ( ) {
2014-08-07 18:56:05 +02:00
@Override
public void run ( ) {
// Debug information about unknown blocks.
// (Probably removed later.)
ConfigFile config = ConfigManager . getConfigFile ( ) ;
2014-12-04 02:02:37 +01:00
BlockProperties . dumpBlocks ( config . getBoolean ( ConfPaths . BLOCKBREAK_DEBUG , config . getBoolean ( ConfPaths . CHECKS_DEBUG , false ) ) ) ;
2014-08-07 18:56:05 +02:00
}
} ) ;
2013-01-20 05:59:46 +01:00
}
2014-08-07 18:56:05 +02:00
2015-11-15 04:17:15 +01:00
/ * *
* Listener to be registered in postEnable . Flag must be set elsewhere .
*
* @return
* /
private Listener getLateListener ( ) {
return new NCPListener ( ) {
@EventHandler ( priority = EventPriority . LOWEST ) // Do update comment in NoCheatPlusAPI with changing.
public void onPlayerJoinLowestLate ( final PlayerJoinEvent event ) {
updatePermStateReceivers ( event . getPlayer ( ) ) ;
}
} ;
}
2012-10-17 17:44:12 +02:00
/ * *
2014-08-07 18:56:05 +02:00
* Quick solution to hide the listener methods , expect refactoring .
* @return
* /
private Listener getCoreListener ( ) {
return new NCPListener ( ) {
@EventHandler ( priority = EventPriority . NORMAL )
public void onPlayerLogin ( final PlayerLoginEvent event ) {
// (NORMAL to have chat checks come after this.)
if ( event . getResult ( ) ! = Result . ALLOWED ) return ;
final Player player = event . getPlayer ( ) ;
// Check if login is denied:
checkDenyLoginsNames ( ) ;
if ( player . hasPermission ( Permissions . BYPASS_DENY_LOGIN ) ) return ;
if ( isLoginDenied ( player . getName ( ) ) ) {
// TODO: display time for which the player is banned.
event . setResult ( Result . KICK_OTHER ) ;
// TODO: Make message configurable.
event . setKickMessage ( " You are temporarily denied to join this server. " ) ;
}
}
@EventHandler ( priority = EventPriority . LOWEST ) // Do update comment in NoCheatPlusAPI with changing.
public void onPlayerJoinLowest ( final PlayerJoinEvent event ) {
final Player player = event . getPlayer ( ) ;
2015-11-15 04:17:15 +01:00
if ( ! lateListenerRegistered ) {
// Let's see if this gets logged with big servers :).
NCPAPIProvider . getNoCheatPlusAPI ( ) . getLogManager ( ) . warning ( Streams . STATUS , " Player " + player . getName ( ) + " joins before the post-enable task has run. " ) ;
// (Assume postEnable will run and call updatePermStateReceivers(player).)
} else {
updatePermStateReceivers ( player ) ;
}
2015-01-19 17:47:09 +01:00
if ( clearExemptionsOnJoin ) {
NCPExemptionManager . unexempt ( player ) ;
}
2014-08-07 18:56:05 +02:00
}
@EventHandler ( priority = EventPriority . LOW )
public void onPlayerJoinLow ( final PlayerJoinEvent event ) {
// LOWEST is for DataMan and CombinedListener.
onJoinLow ( event . getPlayer ( ) ) ;
}
@EventHandler ( priority = EventPriority . LOWEST )
public void onPlayerchangedWorld ( final PlayerChangedWorldEvent event )
{
final Player player = event . getPlayer ( ) ;
updatePermStateReceivers ( player ) ;
}
@EventHandler ( priority = EventPriority . MONITOR , ignoreCancelled = true )
public void onPlayerKick ( final PlayerKickEvent event ) {
onLeave ( event . getPlayer ( ) ) ;
}
@EventHandler ( priority = EventPriority . MONITOR )
public void onPlayerQuit ( final PlayerQuitEvent event ) {
onLeave ( event . getPlayer ( ) ) ;
}
} ;
}
protected void onJoinLow ( final Player player ) {
final String playerName = player . getName ( ) ;
if ( nameSetPerms . hasPermission ( playerName , Permissions . NOTIFY ) ) {
// Login notifications...
final PlayerData data = DataManager . getPlayerData ( playerName , true ) ;
// // Update available.
// if (updateAvailable) player.sendMessage(ChatColor.RED + "NCP: " + ChatColor.WHITE + "A new update of NoCheatPlus is available.\n" + "Download it at http://nocheatplus.org/update");
// Inconsistent config version.
if ( configProblems ! = null & & ConfigManager . getConfigFile ( ) . getBoolean ( ConfPaths . CONFIGVERSION_NOTIFY ) ) {
// Could use custom prefix from logging, however ncp should be mentioned then.
sendMessageOnTick ( playerName , ChatColor . RED + " NCP: " + ChatColor . WHITE + configProblems ) ;
}
// Message if notify is turned off.
if ( data . getNotifyOff ( ) ) {
sendMessageOnTick ( playerName , MSG_NOTIFY_OFF ) ;
}
}
// JoinLeaveListenerS: Do update comment in NoCheatPlusAPI with changing event priority.
for ( final JoinLeaveListener jlListener : joinLeaveListeners ) {
try {
jlListener . playerJoins ( player ) ;
}
catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " JoinLeaveListener( " + jlListener . getClass ( ) . getName ( ) + " ) generated an exception (join): " + t . getClass ( ) . getSimpleName ( ) ) ;
2014-11-19 00:00:31 +01:00
logManager . severe ( Streams . INIT , t ) ;
2014-08-07 18:56:05 +02:00
}
}
// Mod message (left on low instead of lowest to allow some permissions plugins compatibility).
ModUtil . motdOnJoin ( player ) ;
}
protected void onLeave ( final Player player ) {
for ( final PermStateReceiver pr : permStateReceivers ) {
pr . removePlayer ( player . getName ( ) ) ;
}
for ( final JoinLeaveListener jlListener : joinLeaveListeners ) {
try {
jlListener . playerLeaves ( player ) ;
}
catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " JoinLeaveListener( " + jlListener . getClass ( ) . getName ( ) + " ) generated an exception (leave): " + t . getClass ( ) . getSimpleName ( ) ) ;
2014-11-19 00:00:31 +01:00
logManager . severe ( Streams . INIT , t ) ;
2014-08-07 18:56:05 +02:00
}
}
2015-01-19 17:47:09 +01:00
if ( clearExemptionsOnLeave ) {
NCPExemptionManager . unexempt ( player ) ;
}
2014-08-07 18:56:05 +02:00
}
protected void updatePermStateReceivers ( final Player player ) {
final Map < String , Boolean > checked = new HashMap < String , Boolean > ( 20 ) ;
final String name = player . getName ( ) ;
for ( final PermStateReceiver pr : permStateReceivers ) {
for ( final String permission : pr . getDefaultPermissions ( ) ) {
Boolean state = checked . get ( permission ) ;
if ( state = = null ) {
state = player . hasPermission ( permission ) ;
checked . put ( permission , state ) ;
}
pr . setPermission ( name , permission , state ) ;
}
}
}
protected void scheduleConsistencyCheckers ( ) {
BukkitScheduler sched = getServer ( ) . getScheduler ( ) ;
if ( consistencyCheckerTaskId ! = - 1 ) {
sched . cancelTask ( consistencyCheckerTaskId ) ;
}
ConfigFile config = ConfigManager . getConfigFile ( ) ;
if ( ! config . getBoolean ( ConfPaths . DATA_CONSISTENCYCHECKS_CHECK , true ) ) return ;
// Schedule task in seconds.
final long delay = 20L * config . getInt ( ConfPaths . DATA_CONSISTENCYCHECKS_INTERVAL , 1 , 3600 , 10 ) ;
consistencyCheckerTaskId = sched . scheduleSyncRepeatingTask ( this , new Runnable ( ) {
@Override
public void run ( ) {
runConsistencyChecks ( ) ;
}
} , delay , delay ) ;
}
/ * *
* Run consistency checks for at most the configured duration . If not finished , a task will be scheduled to continue .
* /
protected void runConsistencyChecks ( ) {
final long tStart = System . currentTimeMillis ( ) ;
final ConfigFile config = ConfigManager . getConfigFile ( ) ;
if ( ! config . getBoolean ( ConfPaths . DATA_CONSISTENCYCHECKS_CHECK ) | | consistencyCheckers . isEmpty ( ) ) {
consistencyCheckerIndex = 0 ;
return ;
}
final long tEnd = tStart + config . getLong ( ConfPaths . DATA_CONSISTENCYCHECKS_MAXTIME , 1 , 50 , 2 ) ;
if ( consistencyCheckerIndex > = consistencyCheckers . size ( ) ) consistencyCheckerIndex = 0 ;
2014-12-01 00:06:41 +01:00
final Player [ ] onlinePlayers = BridgeMisc . getOnlinePlayers ( ) ;
2014-08-07 18:56:05 +02:00
// Loop
while ( consistencyCheckerIndex < consistencyCheckers . size ( ) ) {
final ConsistencyChecker checker = consistencyCheckers . get ( consistencyCheckerIndex ) ;
try {
checker . checkConsistency ( onlinePlayers ) ;
}
catch ( Throwable t ) {
2015-11-15 02:15:20 +01:00
logManager . severe ( Streams . INIT , " ConsistencyChecker( " + checker . getClass ( ) . getName ( ) + " ) encountered an exception: " ) ;
2014-11-19 00:00:31 +01:00
logManager . severe ( Streams . INIT , t ) ;
2014-08-07 18:56:05 +02:00
}
consistencyCheckerIndex + + ; // Do not remove :).
final long now = System . currentTimeMillis ( ) ;
if ( now < tStart | | now > = tEnd ) {
break ;
}
}
// (The index might be bigger than size by now.)
2015-01-25 03:18:24 +01:00
final boolean debug = config . getBoolean ( ConfPaths . LOGGING_EXTENDED_STATUS ) ;
2014-08-07 18:56:05 +02:00
// If not finished, schedule further checks.
if ( consistencyCheckerIndex < consistencyCheckers . size ( ) ) {
getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( this , new Runnable ( ) {
@Override
public void run ( ) {
runConsistencyChecks ( ) ;
}
} ) ;
if ( debug ) {
2015-11-15 02:15:20 +01:00
logManager . info ( Streams . STATUS , " Interrupted consistency checking until next tick. " ) ;
2014-08-07 18:56:05 +02:00
}
}
}
@Override
public < T > T registerGenericInstance ( T instance ) {
@SuppressWarnings ( " unchecked " )
Class < T > clazz = ( Class < T > ) instance . getClass ( ) ;
T registered = getGenericInstance ( clazz ) ;
genericInstances . put ( clazz , instance ) ;
return registered ;
}
@Override
public < T , TI extends T > T registerGenericInstance ( Class < T > registerFor , TI instance ) {
T registered = getGenericInstance ( registerFor ) ;
genericInstances . put ( registerFor , instance ) ;
return registered ;
}
@SuppressWarnings ( " unchecked " )
@Override
public < T > T getGenericInstance ( Class < T > registeredFor ) {
return ( T ) genericInstances . get ( registeredFor ) ;
}
@Override
public < T > T unregisterGenericInstance ( Class < T > registeredFor ) {
T registered = getGenericInstance ( registeredFor ) ; // Convenience.
genericInstances . remove ( registeredFor ) ;
return registered ;
}
2014-07-27 15:17:08 +02:00
2015-01-05 16:12:05 +01:00
@Override
public void addFeatureTags ( String key , Collection < String > featureTags ) {
LinkedHashSet < String > present = this . featureTags . get ( key ) ;
if ( present = = null ) {
present = new LinkedHashSet < String > ( ) ;
this . featureTags . put ( key , present ) ;
}
present . addAll ( featureTags ) ;
}
@Override
public void setFeatureTags ( String key , Collection < String > featureTags ) {
LinkedHashSet < String > present = new LinkedHashSet < String > ( ) ;
this . featureTags . put ( key , present ) ;
present . addAll ( featureTags ) ;
}
2015-02-09 21:59:37 +01:00
@Override
public boolean hasFeatureTag ( final String key , final String feature ) {
final Collection < String > features = this . featureTags . get ( key ) ;
return features = = null ? false : features . contains ( feature ) ;
}
2015-01-05 16:12:05 +01:00
@Override
public Map < String , Set < String > > getAllFeatureTags ( ) {
final LinkedHashMap < String , Set < String > > allTags = new LinkedHashMap < String , Set < String > > ( ) ;
for ( final Entry < String , LinkedHashSet < String > > entry : this . featureTags . entrySet ( ) ) {
allTags . put ( entry . getKey ( ) , Collections . unmodifiableSet ( entry . getValue ( ) ) ) ;
}
return Collections . unmodifiableMap ( allTags ) ;
}
2012-04-05 18:24:39 +02:00
}