Added new Permissions support, and defined permissions in plugin.yml

Added Tips-and-Tricks on startup
This commit is contained in:
Evenprime 2011-07-18 17:18:26 +02:00
parent c438eee164
commit cd99a78718
9 changed files with 634 additions and 440 deletions

View File

@ -3,7 +3,7 @@ name: NoCheat
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheat
version: 1.10a
version: 1.11
softdepend: [ Permissions, CraftIRC ]
@ -15,3 +15,46 @@ commands:
Example: /<command> | Displays version, enabled checks and bugfixes
Example: /<command> -p | Get your permissions, * = check disabled globally
Example: /<command> -p [player] | Get permissions of the player, * = check disabled globally
permissions:
nocheat.all:
description: Allow the player to do everything (except for getting log messages)
children:
nocheat.moving: true
nocheat.speedhack: true
nocheat.airbuild: true
nocheat.bogusitems: true
nocheat.nuke: true
nocheat.flying: true
nocheat.fakesneak: true
nocheat.fastswim: true
nocheat.moving:
description: Allow to player to move/fly without getting checked at all
default: op
nocheat.speedhack:
description: Don't observe the number of move events sent by the player
default: op
nocheat.airbuild:
description: Allow placing blocks against air/in midair
default: op
nocheat.bogusitems:
description: Allow the use of items with invalid values e.g. negative stacksize
default: op
nocheat.nuke:
description: Allow breaking of blocks that are not in the field of view of the player
default: op
nocheat.notify:
description: Receive log messages in chat
default: op
nocheat.flying:
description: Allow the player to fly at normal walking speed
default: op
nocheat.fakesneak:
description: Allow the player to sneak at normal walking speed
default: op
nocheat.fastswim:
description: Allow the player to swim at normal walking speed
default: op

View File

@ -0,0 +1,106 @@
package cc.co.evenprime.bukkit.nocheat;
import java.util.Set;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
public class CustomCommandSender implements CommandSender {
private final Server server;
public CustomCommandSender(Server server) {
this.server = server;
}
@Override
public boolean isPermissionSet(String name) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean isPermissionSet(Permission perm) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean hasPermission(String name) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean hasPermission(Permission perm) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name,
boolean value) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name,
boolean value, int ticks) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
// Whatever it is, I don't care
return null;
}
@Override
public void removeAttachment(PermissionAttachment attachment) {
// Whatever it is, I don't care
}
@Override
public void recalculatePermissions() {
// Nothing to calculate
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
// Nothing
return null;
}
@Override
public void setOp(boolean value) {
// Nothing
}
@Override
public void sendMessage(String message) {
// we don't receive messages
}
@Override
public boolean isOp() {
// We declare ourselves to be OP to be allowed to do more commands
return true;
}
@Override
public Server getServer() {
return server;
}
}

View File

@ -32,9 +32,13 @@ public class DataManager {
Iterator<Map.Entry<Player, NoCheatData>> it = playerData.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Player, NoCheatData> pairs = (Map.Entry<Player, NoCheatData>)it.next();
if(!pairs.getKey().isOnline())
if(!pairs.getKey().isOnline()) {
// Cancel all referenced tasks before removing the entry
cancelTasks(pairs.getValue());
it.remove();
}
}
}
}
@ -127,9 +131,14 @@ public class DataManager {
synchronized(playerData) {
Iterator<Map.Entry<Player, NoCheatData>> it = playerData.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Player, NoCheatData> pairs = (Map.Entry<Player, NoCheatData>)it.next();
cancelTasks(it.next().getValue());
}
}
}
AirbuildData d = pairs.getValue().airbuild;
private void cancelTasks(NoCheatData data) {
AirbuildData d = data.airbuild;
if(d != null) {
int id = d.summaryTask;
@ -143,7 +152,7 @@ public class DataManager {
}
}
MovingData d2 = pairs.getValue().moving;
MovingData d2 = data.moving;
if(d2 != null) {
int id = d2.summaryTask;
@ -157,7 +166,4 @@ public class DataManager {
}
}
}
}
}
}

View File

@ -1,6 +1,5 @@
package cc.co.evenprime.bukkit.nocheat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@ -35,11 +34,12 @@ import org.bukkit.plugin.Plugin;
*
* NoCheat
*
* Check various player events for their plausibility and log/deny them based on configuration
* Check various player events for their plausibility and log/deny them based on
* configuration
*
* @author Evenprime
*/
public class NoCheat extends JavaPlugin implements CommandSender {
public class NoCheat extends JavaPlugin {
private MovingCheck movingCheck;
private SpeedhackCheck speedhackCheck;
@ -50,6 +50,8 @@ public class NoCheat extends JavaPlugin implements CommandSender {
private NoCheatConfiguration config;
private boolean useNewPermissionSystem = false;
private long exceptionWithPermissions = 0;
private int cleanUpTaskId = -1;
@ -72,40 +74,43 @@ public class NoCheat extends JavaPlugin implements CommandSender {
private String ircTag;
private NukeCheck nukeCheck;
private DataManager dataManager;
private CustomCommandSender sender;
private boolean showStartupMessages = true;
public NoCheat() {
}
@Override
public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args)
{
if(args.length == 0) {
sender.sendMessage("NC: Using "+ ((permissions == null) ? "isOp()" : "Permissions") + ". Activated checks/bugfixes: " + getActiveChecksAsString() + ". Total time used for moving check so far: " + (movingCheck.statisticElapsedTimeNano / 1000000L + " ms. Average time per move event: " + (movingCheck.statisticElapsedTimeNano/1000L)/movingCheck.statisticTotalEvents + " us"));
return true;
public String[] getMessagesOfTheDay() {
return new String[] {"NoCheat now supports the new Bukkit-Permission system. You can activate it in the config file.", "There will be a change in the near future to how movement in CraftBukkit works, which will break NoCheats moving-check(s) completely, causing tons of false positives. Be careful if you tend to run bleeding edge builds of CraftBukkit.", "This version of NoCheat was written for CraftBukkit RB 1000, but may still work for some older or newer versions.", "You can find detailed information about all configuration options of NoCheat in the file \"descriptions.txt\" in your \"plugins/NoCheat\" folder", "You can deactivate these Messages in the config file, if they annoy you."};
}
else if(args.length == 1 && args[0] != null && args[0].trim().equals("-p")) {
@Override
public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) {
if(args.length == 0) {
sender.sendMessage("NC: Using " + ((permissions == null) ? "isOp()" : "Permissions") + ". Activated checks/bugfixes: " + getActiveChecksAsString() + ". Total time used for moving check so far: " + (movingCheck.statisticElapsedTimeNano / 1000000L + " ms. Average time per move event: " + (movingCheck.statisticElapsedTimeNano / 1000L) / movingCheck.statisticTotalEvents + " us"));
return true;
} else if(args.length == 1 && args[0] != null && args[0].trim().equals("-p")) {
if(sender instanceof Player) {
Player p = (Player) sender;
sender.sendMessage("NC: You have permissions: " + getPermissionsForPlayerAsString(p));
return true;
}
else {
} else {
sender.sendMessage("NC: You have to be a player to use this command");
return true;
}
}
else if(args.length == 2 && args[0] != null && args[0].trim().equals("-p")) {
} else if(args.length == 2 && args[0] != null && args[0].trim().equals("-p")) {
Player p = getServer().getPlayer(args[1]);
if(p != null) {
sender.sendMessage("NC: "+p.getName() + " has permissions: " + getPermissionsForPlayerAsString(p));
sender.sendMessage("NC: " + p.getName() + " has permissions: " + getPermissionsForPlayerAsString(p));
return true;
}
else {
} else {
sender.sendMessage("NC: Player " + args[1] + " was not found.");
return true;
}
@ -114,8 +119,6 @@ public class NoCheat extends JavaPlugin implements CommandSender {
return false;
}
public void onDisable() {
PluginDescriptionFile pdfFile = this.getDescription();
@ -124,18 +127,20 @@ public class NoCheat extends JavaPlugin implements CommandSender {
config.cleanup();
try {
dataManager.cancelPlayerDataTasks();
teardownCleanupTask();
teardownServerLagMeasureTask();
dataManager.cancelPlayerDataTasks();
} catch(Exception e) { /* Can't do much in case of error here... */
}
catch(Exception e) { /* Can't do much in case of error here... */ }
Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is disabled.");
Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is disabled.");
}
public void onEnable() {
dataManager = new DataManager();
sender = new CustomCommandSender(getServer());
// parse the nocheat.yml config file
setupConfig();
@ -146,19 +151,26 @@ public class NoCheat extends JavaPlugin implements CommandSender {
nukeCheck = new NukeCheck(this, config);
// just for convenience
checks = new Check[] { movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck };
checks = new Check[] {movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck};
if(!allowFlightSet && movingCheck.isActive()) {
Logger.getLogger("Minecraft").warning( "[NoCheat] you have set \"allow-flight=false\" in your server.properties file. That builtin anti-flying-mechanism will likely conflict with this plugin. Please consider deactivating it by setting it to \"true\"");
Logger.getLogger("Minecraft").warning("[NoCheat] you have set \"allow-flight=false\" in your server.properties file. That builtin anti-flying-mechanism will likely conflict with this plugin. Please consider deactivating it by setting it to \"true\"");
}
for(String s : getMessagesOfTheDay()) {
if(showStartupMessages)
Logger.getLogger("Minecraft").info("(NoCheat) Did you know? " + s);
}
PluginDescriptionFile pdfFile = this.getDescription();
// Get, if available, the Permissions and irc plugin
if(!useNewPermissionSystem) {
setupPermissions();
}
setupIRC();
Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is enabled with the following checks: "+getActiveChecksAsString());
Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is enabled with the following checks: " + getActiveChecksAsString());
setupCleanupTask();
@ -166,52 +178,67 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
public DataManager getDataManager() {
return dataManager;
}
private void setupCleanupTask() {
if(cleanUpTaskId != -1) return;
if(cleanUpTaskId != -1) {
return;
}
try {
cleanUpTaskId = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() {
@Override
public void run() {
dataManager.cleanPlayerDataCollection();
try {
if(getDataManager() != null) {
getDataManager().cleanPlayerDataCollection();
}
} catch(Exception e) {}
}
}, 5000, 5000);
}
catch(Exception e) {
// It's not THAT important, so if it fails for whatever reason, just let it be.
} catch(Exception e) {
// It's not THAT important, so if it fails for whatever reason, just
// let it be.
}
}
private void teardownCleanupTask() {
if(cleanUpTaskId != -1)
if(cleanUpTaskId != -1) {
Bukkit.getServer().getScheduler().cancelTask(cleanUpTaskId);
}
}
private void setupServerLagMeasureTask() {
if(serverLagMeasureTaskSetup != -1) return;
if(serverLagMeasureTaskSetup != -1) {
return;
}
serverLagMeasureTaskSetup = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() {
@Override
public void run() {
serverTicks += 10;
long time = System.currentTimeMillis();
serverLagInMilliSeconds = Math.abs((time - lastServerTime - 500)*2);
serverLagInMilliSeconds = Math.abs((time - lastServerTime - 500) * 2);
lastServerTime = time;
}
}, 10, 10);
}
private void teardownServerLagMeasureTask() {
if(serverLagMeasureTaskSetup != -1)
if(serverLagMeasureTaskSetup != -1) {
Bukkit.getServer().getScheduler().cancelTask(serverLagMeasureTaskSetup);
}
}
/**
* Get, if available, a reference to the Permissions-plugin
@ -220,8 +247,8 @@ public class NoCheat extends JavaPlugin implements CommandSender {
Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions");
if (this.permissions == null) {
if (permissionsPlugin != null) {
if(this.permissions == null) {
if(permissionsPlugin != null) {
this.permissions = ((Permissions) permissionsPlugin).getHandler();
} else {
PluginDescriptionFile pdfFile = this.getDescription();
@ -234,12 +261,13 @@ public class NoCheat extends JavaPlugin implements CommandSender {
* Get, if available, a reference to the Permissions-plugin
*/
private void setupIRC() {
CraftIRC p = null;
Plugin test = this.getServer().getPluginManager().getPlugin("CraftIRC");
if(test != null && test instanceof CraftIRC) {
p = (CraftIRC)test;
p = (CraftIRC) test;
}
if(p == null) {
@ -252,9 +280,11 @@ public class NoCheat extends JavaPlugin implements CommandSender {
/**
* Log a violation message to all locations declared in the config file
*
* @param message
*/
public void log(Level l, String message) {
if(l != null && message != null) {
message = "NC: " + message;
config.logger.log(l, message);
@ -266,43 +296,49 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
private void logToChat(Level l, String message) {
if(chatLevel.intValue() <= l.intValue()) {
for(Player player : getServer().getOnlinePlayers()) {
if(hasPermission(player, PermissionData.PERMISSION_NOTIFY, false)) {
player.sendMessage("["+l.getName()+"] " + message);
player.sendMessage("[" + l.getName() + "] " + message);
}
}
}
}
private void logToIRC(Level l, String message) {
if(irc != null && ircLevel.intValue() <= l.intValue()) {
irc.sendMessageToTag("["+l.getName()+"] " + message , ircTag);
irc.sendMessageToTag("[" + l.getName() + "] " + message, ircTag);
}
}
private void logToConsole(Level l, String message) {
if( consoleLevel.intValue() <= l.intValue()) {
if(consoleLevel.intValue() <= l.intValue()) {
Logger.getLogger("Minecraft").log(l, message);
}
}
public boolean hasPermission(Player player, int permission, boolean ignoreOPstatus) {
public boolean hasPermission(Player player, int permission, boolean checkOPs) {
if(player == null)
return false;
if(player == null) return false;
if(useNewPermissionSystem) {
//System.out.println("New permissions system asked for " + PermissionData.permissionNames[permission] + " got " + player.hasPermission(PermissionData.permissionNames[permission]));
return player.hasPermission(PermissionData.permissionNames[permission]);
}
try {
if(permissions == null) {
if(checkOPs) {
if(ignoreOPstatus) {
// OPs don't get special treatment
return false;
}
else {
} else {
return player.isOp();
}
}
else {
} else {
PermissionData data = dataManager.getPermissionData(player);
long time = System.currentTimeMillis();
if(data.lastUpdate[permission] + 10000 < time) {
@ -311,13 +347,12 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
return data.cache[permission];
}
}
catch(Throwable e) {
} catch(Throwable e) {
if(this.exceptionWithPermissions + 60000 < System.currentTimeMillis()) {
// Prevent spam and recursion by definitely doing this only once
this.exceptionWithPermissions = System.currentTimeMillis();
String logtext = "Asking Permissions-Plugin if "+player.getName()+" has permission "+PermissionData.permissionNames[permission]+" caused an Exception "+ e.getMessage() + ". Please review your permissions config file. This message is displayed at most once every 60 seconds.";
String logtext = "Asking Permissions-Plugin if " + player.getName() + " has permission " + PermissionData.permissionNames[permission] + " caused an Exception " + e.getMessage() + ". Please review your permissions config file. This message is displayed at most once every 60 seconds.";
log(Level.SEVERE, logtext);
for(StackTraceElement s : e.getStackTrace()) {
config.logger.log(Level.SEVERE, s.toString());
@ -331,6 +366,7 @@ public class NoCheat extends JavaPlugin implements CommandSender {
* Read the config file
*/
private void setupConfig() {
if(this.config == null)
this.config = new NoCheatConfiguration(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile));
else
@ -343,7 +379,10 @@ public class NoCheat extends JavaPlugin implements CommandSender {
this.ircLevel = config.getLogLevelValue("logging.logtoirc");
this.consoleLevel = config.getLogLevelValue("logging.logtoconsole");
this.ircTag = config.getStringValue("logging.logtoirctag");
} catch (ConfigurationException e) {
this.useNewPermissionSystem = this.config.getBooleanValue("newpermsystem");
this.showStartupMessages = this.config.getBooleanValue("showinfomessages");
} catch(ConfigurationException e) {
e.printStackTrace();
this.setEnabled(false);
}
@ -359,12 +398,12 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
}
} catch (Exception e) {
} catch(Exception e) {
e.printStackTrace();
// ignore errors
}
}
}
private String getActiveChecksAsString() {
@ -381,7 +420,6 @@ public class NoCheat extends JavaPlugin implements CommandSender {
return s;
}
private String getPermissionsForPlayerAsString(Player p) {
String s = "";
@ -400,10 +438,12 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
public int getServerTicks() {
return serverTicks;
}
public long getServerLag() {
return this.serverLagInMilliSeconds;
}
@ -419,33 +459,18 @@ public class NoCheat extends JavaPlugin implements CommandSender {
if(com != null) {
if(commandParts.length > 1) { // Command + parameters
String[] commandArgs = commandParts[1].split(" ");
com.execute(this, commandName, commandArgs);
}
else {
com.execute(sender, commandName, commandArgs);
} else {
String[] commandArgs = new String[0];
com.execute(this, commandName, commandArgs);
com.execute(sender, commandName, commandArgs);
}
}
else
{
} else {
// The standard server should do it
Bukkit.getServer().dispatchCommand(this, command);
Bukkit.getServer().dispatchCommand(sender, command);
}
}
catch(Exception e) {
this.log(Level.WARNING, "NoCheat couldn't execute custom server command: \""+command+"\"");
} catch(Exception e) {
this.log(Level.WARNING, "NoCheat couldn't execute custom server command: \"" + command + "\"");
}
}
@Override
public void sendMessage(String message) {
// we don't receive messages
}
@Override
public boolean isOp() {
// We declare ourselves to be OP to be allowed to do more commands
return true;
}
}

View File

@ -53,9 +53,11 @@ public class AirbuildCheck extends Check {
@Override
public void run() {
try {
summary(p, data);
// deleting its own reference
data.summaryTask = -1;
}catch(Exception e) {}
}
};

View File

@ -223,6 +223,8 @@ public class MovingCheck extends Check {
@Override
public void run() {
try {
if(data.highestLogLevel != null) {
String logString = String.format(summaryMessage, p.getName(), ticksBeforeSummary/20, data.violationsInARow[0], data.violationsInARow[1],data.violationsInARow[2]);
plugin.log(data.highestLogLevel, logString);
@ -236,6 +238,8 @@ public class MovingCheck extends Check {
data.violationsInARow[1] = 0;
data.violationsInARow[2] = 0;
}
catch(Exception e) { }
}
};
// Give a summary in x ticks. 20 ticks ~ 1 second

View File

@ -92,6 +92,9 @@ public class NoCheatConfiguration {
SimpleYaml.getString("logging.logtoirctag", "nocheat", yamlContent)));
}
root.add(new BooleanOption("newpermsystem", SimpleYaml.getBoolean("newpermsystem", false, yamlContent)));
root.add(new BooleanOption("showinfomessages", SimpleYaml.getBoolean("showinfomessages", true, yamlContent)));
/*** ACTIVE section ***/
{
ParentOption activeNode = new ParentOption("active", false);

View File

@ -11,10 +11,10 @@ public class PermissionData {
public static final int PERMISSION_FLYING = 1;
public static final int PERMISSION_SPEEDHACK = 2;
public static final int PERMISSION_AIRBUILD = 3;
public static final int PERMISSION_BEDTELEPORT = 4;
public static final int PERMISSION_BEDTELEPORT = 4; // No longer used
public static final int PERMISSION_BOGUSITEMS = 5;
public static final int PERMISSION_NOTIFY = 6;
public static final int PERMISSION_ITEMDUPE = 7;
public static final int PERMISSION_ITEMDUPE = 7; // No longer used
public static final int PERMISSION_FAKESNEAK = 8;
public static final int PERMISSION_FASTSWIM = 9;
public static final int PERMISSION_NUKE = 10;

View File

@ -37,6 +37,11 @@ public class Explainations {
"blocks that are outside his field of sight, he'll get kicked from the server.\n" +
"This is only a temporary solution (and will probably not hold for long), but it's better than nothing, I guess...");
set("newpermsystem", "If activated, NoCheat will fully rely on the new Permission system of Bukkit, introduced with build 1000.\n" +
"This only makes sense if you also have a permission plugin that is capable of managing permissions in the new system.");
set("showinfomessages", "If activated, NoCheat will give useful advice and information on startup, about recent changes and potential \n" +
"problems with your servers configuration or conflicts with other plugins.");
set("logging.filename", "Determines where the various messages by NoCheat are stored at, if logging to file is activated.");
set("logging.logtofile", "Determine what severeness messages need to have to be printed to the logfile.\n" +
"The values that can be used are:\n" +