mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-12-24 18:19:03 +01:00
Initial commit.
This commit is contained in:
commit
3aa265b553
15
INSTALL.txt
Normal file
15
INSTALL.txt
Normal file
@ -0,0 +1,15 @@
|
||||
Installation
|
||||
------------
|
||||
|
||||
This plugin requires Hey0's server modification.
|
||||
|
||||
1. Create a "plugins" folder inside your "bin" folder.
|
||||
|
||||
2. Copy WorldProtect.jar into "plugins".
|
||||
|
||||
3. Add "WorldProtect" to the "plugins" line of your server.properties file.
|
||||
If it's not already there, add the line. The line should look like this:
|
||||
|
||||
plugins=WorldProtect
|
||||
|
||||
If you have multiple plugins, separate plugin names with commas.
|
165
LICENSE.txt
Normal file
165
LICENSE.txt
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
107
README.txt
Normal file
107
README.txt
Normal file
@ -0,0 +1,107 @@
|
||||
WorldProtect
|
||||
Copyright (c) 2010 sk89q <http://www.sk89q.com>
|
||||
Licensed under the GNU Lesser General Public License v3
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
WorldProtect has a number of features, any of which you can choose to
|
||||
use or not:
|
||||
|
||||
- Enforce only one session for a player on a server (can't login twice).
|
||||
- Block creeper explosions.
|
||||
- Block TNT explosions.
|
||||
- Block lighters from setting fires.
|
||||
- Block all fires.
|
||||
- Allow fire but prevent it from burning certain blocks.
|
||||
- Prevent lava from starting fires.
|
||||
- Restrict lava spreading to only some block types.
|
||||
- Simulate classic-esque water by letting water infinitely expand in
|
||||
area (only if there is a block underneath).
|
||||
- Simulate the sponge.
|
||||
- Block the use, desturction and/or placement of some items or block types.
|
||||
- Notify admins when a certain block type or item is used, destroyed,
|
||||
or place.
|
||||
- Log the use, destruction, and/or placement of some blocks/items.
|
||||
- Kick for the use, destruction, and/or placement of some blocks.
|
||||
|
||||
hMod is required as WorldProtect is a plugin for hMod.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
A "worldprotect.properties" will be created the first the time that you load
|
||||
WorldProtect on your server. You can either restart your server or use
|
||||
/reloadplugin WorldProtect to reload the configuraton file after editing it.
|
||||
|
||||
- classic-water (def. false)
|
||||
Toggle use of classic water. Be foreward that your world may be
|
||||
flooded if you are not careful. If you have WorldEdit, you can use
|
||||
//drain in such an event, although that will drain the entire pool
|
||||
as well. This classic-esque water will only spread infinitely over
|
||||
ground, but if there are air blocks underneath, the water will not
|
||||
spread (preventing waterfalls from becoming tsunamis).
|
||||
|
||||
- simulate-sponge (def. false)
|
||||
Toggle simulation of the sponge. The sponge only prevents water
|
||||
from spreading. It will not take away existing water. Simulation of
|
||||
the sponge requires iterating over a 9x9x9 cuboid around the water
|
||||
block and the resource impact of this has not been quantified.
|
||||
|
||||
- enforce-single-session (def. true)
|
||||
Enforce single sessions. If the player is already found to be on
|
||||
the server when s/he logs in, the other player will be kicked with
|
||||
an informative message. The inventory will have been saved before
|
||||
the new session starts.
|
||||
|
||||
- blacklist-log-console (def. true)
|
||||
For log actions, print to console as well.
|
||||
|
||||
- blacklist-log-file (no default)
|
||||
File to log to. Log files are automatically rotated based on size, and
|
||||
you can use these patterns in the path:
|
||||
%t the system temporary directory
|
||||
%h the value of the "user.home" system property
|
||||
%g the generation number to distinguish rotated logs
|
||||
%u a unique number to resolve conflicts
|
||||
%% translates to a single percent sign "%"
|
||||
There is no way to put the date in the filename or rotate by date.
|
||||
|
||||
- blacklist-log-file-limit (def. 5242880)
|
||||
Size in bytes before the log file is rotated.
|
||||
|
||||
- blacklist-log-file-count (def. 10)
|
||||
Number of log files to keep in rotation at maximum.
|
||||
|
||||
- block-tnt (def. false)
|
||||
Block TNT explosions. TNT will still explode client-side but the blocks
|
||||
will be "restored" in a few seconds afterwards.
|
||||
|
||||
- block-lighter (def. false)
|
||||
Block flint and steel fires. Those with access to the commands
|
||||
/uselighter or /lighter can bypass this. /uselighter is not a real
|
||||
command; it is only used for permissions.
|
||||
|
||||
- block-creepers (def. false)
|
||||
Block creeper explosions. They will not explode client-side.
|
||||
|
||||
- disable-lava-fire (def. false)
|
||||
Prevent lava from starting fires.
|
||||
|
||||
- allowed-lava-spread-blocks (no default)
|
||||
List of block names/IDs to allow lava to spread to. Leave blank
|
||||
to disable this feature.
|
||||
|
||||
- disable-all-fire-spread (def. false)
|
||||
Disable all fire from spreading.
|
||||
|
||||
- disallowed-fire-spread-blocks (no default)
|
||||
List of block names/IDs to prevent fire from spreading to. Leave blank
|
||||
to disable this feature. Enabling disable-all-fire-spread will
|
||||
override this function.
|
||||
|
||||
Blacklists
|
||||
----------
|
||||
|
||||
Edit the included worldprotect-blacklist.txt file and follow the
|
||||
instructions inside.
|
2
manifest.mf
Normal file
2
manifest.mf
Normal file
@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
WorldProtect-Version: 1.0
|
267
src/BlacklistEntry.java
Normal file
267
src/BlacklistEntry.java
Normal file
@ -0,0 +1,267 @@
|
||||
// $Id$
|
||||
/*
|
||||
* WorldProtect
|
||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class BlacklistEntry {
|
||||
/**
|
||||
* Used to prevent spamming.
|
||||
*/
|
||||
private static Map<String,Integer> lastAffected =
|
||||
new HashMap<String,Integer>();
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger("WorldProtect.Blacklist");
|
||||
/**
|
||||
* List of groups to not affect.
|
||||
*/
|
||||
private Set<String> ignoreGroups;
|
||||
/**
|
||||
* List of actions to perform on destruction.
|
||||
*/
|
||||
private String[] destroyActions;
|
||||
/**
|
||||
* List of actions to perform on left click.
|
||||
*/
|
||||
private String[] leftClickActions;
|
||||
/**
|
||||
* List of actions to perform on right click.
|
||||
*/
|
||||
private String[] rightClickActions;
|
||||
|
||||
/**
|
||||
* @return the ignoreGroups
|
||||
*/
|
||||
public String[] getIgnoreGroups() {
|
||||
return ignoreGroups.toArray(new String[ignoreGroups.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ignoreGroups the ignoreGroups to set
|
||||
*/
|
||||
public void setIgnoreGroups(String[] ignoreGroups) {
|
||||
Set<String> ignoreGroupsSet = new HashSet<String>();
|
||||
for (String group : ignoreGroups) {
|
||||
ignoreGroupsSet.add(group.toLowerCase());
|
||||
}
|
||||
this.ignoreGroups = ignoreGroupsSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destroyActions
|
||||
*/
|
||||
public String[] getDestroyActions() {
|
||||
return destroyActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param destroyActions the destroyActions to set
|
||||
*/
|
||||
public void setDestroyActions(String[] destroyActions) {
|
||||
this.destroyActions = destroyActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the leftClickActions
|
||||
*/
|
||||
public String[] getLeftClickActions() {
|
||||
return leftClickActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftClickActions the leftClickActions to set
|
||||
*/
|
||||
public void setLeftClickActions(String[] leftClickActions) {
|
||||
this.leftClickActions = leftClickActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rightClickActions
|
||||
*/
|
||||
public String[] getRightClickActions() {
|
||||
return rightClickActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rightClickActions the rightClickActions to set
|
||||
*/
|
||||
public void setRightClickActions(String[] rightClickActions) {
|
||||
this.rightClickActions = rightClickActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this player should be ignored.
|
||||
*
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public boolean shouldIgnore(Player player) {
|
||||
if (ignoreGroups == null) {
|
||||
return false;
|
||||
}
|
||||
for (String group : player.getGroups()) {
|
||||
if (ignoreGroups.contains(group.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Announces a message to all administrators.
|
||||
*
|
||||
* @param str
|
||||
*/
|
||||
public void notifyAdmins(String str) {
|
||||
for (Player player : etc.getServer().getPlayerList()) {
|
||||
if (player.canUseCommand("/wprotectalerts")) {
|
||||
player.sendMessage(Colors.LightPurple + "WorldProtect: " + str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void log(String message) {
|
||||
logger.log(Level.INFO, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on block destruction. Returns true to let the action pass
|
||||
* through.
|
||||
*
|
||||
* @param block
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public boolean onDestroy(Block block, Player player) {
|
||||
if (destroyActions == null) {
|
||||
return true;
|
||||
}
|
||||
boolean ret = process(block.getType(), player, destroyActions);
|
||||
lastAffected.put(player.getName(), block.getType());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on left click. Returns true to let the action pass through.
|
||||
*
|
||||
* @param item
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public boolean onLeftClick(int item, Player player) {
|
||||
if (leftClickActions == null) {
|
||||
return true;
|
||||
}
|
||||
boolean ret = process(item, player, leftClickActions);
|
||||
lastAffected.put(player.getName(), item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on right right. Returns true to let the action pass through.
|
||||
*
|
||||
* @param item
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public boolean onRightClick(int item, Player player) {
|
||||
if (rightClickActions == null) {
|
||||
return true;
|
||||
}
|
||||
boolean ret = process(item, player, rightClickActions);
|
||||
lastAffected.put(player.getName(), item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to handle the actions.
|
||||
*
|
||||
* @param id
|
||||
* @param player
|
||||
* @param actions
|
||||
* @return
|
||||
*/
|
||||
private boolean process(int id, Player player, String[] actions) {
|
||||
if (shouldIgnore(player)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String name = player.getName();
|
||||
boolean repeating = lastAffected.containsKey(name)
|
||||
&& lastAffected.get(name) == id;
|
||||
|
||||
boolean ret = true;
|
||||
|
||||
for (String action : actions) {
|
||||
if (action.equalsIgnoreCase("deny")) {
|
||||
ret = false;
|
||||
} else if (action.equalsIgnoreCase("kick")) {
|
||||
player.kick("Performed disallowed action with "
|
||||
+ etc.getDataSource().getItem(id) + ".");
|
||||
} else if (!repeating) {
|
||||
if (action.equalsIgnoreCase("notify")) {
|
||||
notifyAdmins(player.getName() + " on destroy: "
|
||||
+ etc.getDataSource().getItem(id));
|
||||
} else if (action.equalsIgnoreCase("log")) {
|
||||
log(player.getName() + " on destroy: "
|
||||
+ etc.getDataSource().getItem(id));
|
||||
} else if (!repeating && action.equalsIgnoreCase("tell")) {
|
||||
player.sendMessage("Can't do that with "
|
||||
+ etc.getDataSource().getItem(id) + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget a player.
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
public static void forgetPlayer(Player player) {
|
||||
lastAffected.remove(player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget all players.
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
public static void forgetAllPlayers() {
|
||||
lastAffected = new HashMap<String,Integer>();
|
||||
}
|
||||
}
|
102
src/WorldProtect.java
Normal file
102
src/WorldProtect.java
Normal file
@ -0,0 +1,102 @@
|
||||
// $Id$
|
||||
/*
|
||||
* WorldProtect
|
||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.jar.Attributes;
|
||||
import java.net.URL;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Entry point for the plugin for hey0's mod.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class WorldProtect extends Plugin {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger("Minecraft.WorldProtect");
|
||||
/**
|
||||
* Listener for the plugin system.
|
||||
*/
|
||||
private static final WorldProtectListener listener =
|
||||
new WorldProtectListener();
|
||||
|
||||
/**
|
||||
* Initializes the plugin.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
PluginLoader loader = etc.getLoader();
|
||||
|
||||
loader.addListener(PluginLoader.Hook.EXPLODE, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.IGNITE, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.FLOW, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.LOGINCHECK, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.BLOCK_CREATED, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.BLOCK_DESTROYED, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
loader.addListener(PluginLoader.Hook.DISCONNECT, listener, this,
|
||||
PluginListener.Priority.HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the plugin.
|
||||
*/
|
||||
@Override
|
||||
public void enable() {
|
||||
listener.loadConfiguration();
|
||||
|
||||
logger.log(Level.INFO, "WorldProtect version " + getVersion() + " loaded");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the plugin.
|
||||
*/
|
||||
@Override
|
||||
public void disable() {
|
||||
BlacklistEntry.forgetAllPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WorldProtect version.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getVersion() {
|
||||
try {
|
||||
String classContainer = WorldProtect.class.getProtectionDomain()
|
||||
.getCodeSource().getLocation().toString();
|
||||
URL manifestUrl = new URL("jar:" + classContainer + "!/META-INF/MANIFEST.MF");
|
||||
Manifest manifest = new Manifest(manifestUrl.openStream());
|
||||
Attributes attrib = manifest.getMainAttributes();
|
||||
String ver = (String)attrib.getValue("WorldProtect-Version");
|
||||
return ver != null ? ver : "(unavailable)";
|
||||
} catch (IOException e) {
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
}
|
434
src/WorldProtectListener.java
Normal file
434
src/WorldProtectListener.java
Normal file
@ -0,0 +1,434 @@
|
||||
// $Id$
|
||||
/*
|
||||
* WorldProtect
|
||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.io.*;
|
||||
import com.sk89q.worldprotect.*;
|
||||
import java.util.logging.FileHandler;
|
||||
|
||||
/**
|
||||
* Event listener for Hey0's server mod.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class WorldProtectListener extends PluginListener {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger("Minecraft.WorldProtect");
|
||||
/**
|
||||
* Properties file for CraftBook.
|
||||
*/
|
||||
private PropertiesFile properties = new PropertiesFile("worldprotect.properties");
|
||||
|
||||
private boolean enforceOneSession;
|
||||
private boolean blockCreepers;
|
||||
private boolean blockTNT;
|
||||
private boolean blockLighter;
|
||||
private boolean preventLavaFire;
|
||||
private boolean disableAllFire;
|
||||
private boolean simulateSponge;
|
||||
private Set<Integer> fireNoSpreadBlocks;
|
||||
private Set<Integer> allowedLavaSpreadOver;
|
||||
private boolean classicWater;
|
||||
private Map<Integer,BlacklistEntry> blacklist;
|
||||
|
||||
/**
|
||||
* Convert a comma-delimited list to a set of integers.
|
||||
*
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
private static Set<Integer> toBlockIDSet(String str) {
|
||||
if (str.trim().length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] items = str.split(",");
|
||||
Set<Integer> result = new HashSet<Integer>();
|
||||
|
||||
for (String item : items) {
|
||||
try {
|
||||
result.add(Integer.parseInt(item.trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
int id = etc.getDataSource().getItem(item.trim());
|
||||
if (id != 0) {
|
||||
result.add(id);
|
||||
} else {
|
||||
logger.log(Level.WARNING, "WorldProtect: Unknown block name: "
|
||||
+ item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configuration
|
||||
*/
|
||||
public void loadConfiguration() {
|
||||
properties.load();
|
||||
|
||||
enforceOneSession = properties.getBoolean("enforce-single-session", true);
|
||||
blockCreepers = properties.getBoolean("block-creepers", false);
|
||||
blockTNT = properties.getBoolean("block-tnt", false);
|
||||
blockLighter = properties.getBoolean("block-lighter", false);
|
||||
preventLavaFire = properties.getBoolean("disable-lava-fire", false);
|
||||
disableAllFire = properties.getBoolean("disable-all-fire-spread", false);
|
||||
fireNoSpreadBlocks = toBlockIDSet(properties.getString("disallowed-fire-spread-blocks", ""));
|
||||
allowedLavaSpreadOver = toBlockIDSet(properties.getString("allowed-lava-spread-blocks", ""));
|
||||
classicWater = properties.getBoolean("classic-water", false);
|
||||
simulateSponge = properties.getBoolean("simulate-sponge", false);
|
||||
|
||||
try {
|
||||
blacklist = loadBlacklist(new File("worldprotect-blacklist.txt"));
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.log(Level.WARNING, "WorldProtect blacklist does not exist.");
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.WARNING, "Could not load WorldProtect blacklist: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
Logger blacklistLogger = Logger.getLogger("WorldProtect.Blacklist");
|
||||
blacklistLogger.setUseParentHandlers(false);
|
||||
for (Handler handler : blacklistLogger.getHandlers()) {
|
||||
blacklistLogger.removeHandler(handler);
|
||||
}
|
||||
|
||||
// Blacklist log to console
|
||||
if (properties.getBoolean("blacklist-log-console", true)) {
|
||||
Handler handler = new ConsoleHandler();
|
||||
handler.setFormatter(new ConsoleLogFormat());
|
||||
blacklistLogger.addHandler(handler);
|
||||
}
|
||||
|
||||
// Blacklist log file
|
||||
String logFile = properties.getString("blacklist-log-file", "").trim();
|
||||
int limit = properties.getInt("blacklist-log-file-limit", 1024 * 1024 * 5);
|
||||
int count = properties.getInt("blacklist-log-file-count", 10);
|
||||
if (logFile.length() > 0) {
|
||||
try {
|
||||
Handler handler = new FileHandler(logFile, limit, count, true);
|
||||
handler.setFormatter(new SimpleLogFormat());
|
||||
blacklistLogger.addHandler(handler);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.WARNING, "Could not open blacklist log file: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during the early login process to check whether or not to kick the
|
||||
* player
|
||||
*
|
||||
* @param user
|
||||
* @return kick reason. null if you don't want to kick the player.
|
||||
*/
|
||||
public String onLoginChecks(String user) {
|
||||
if (enforceOneSession) {
|
||||
for (Player player : etc.getServer().getPlayerList()) {
|
||||
if (player.getName().equalsIgnoreCase(user)) {
|
||||
player.kick("Logged in from another location.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when someone presses right click. If they right clicked with a
|
||||
* block you can return true to cancel that. You can intercept this to add
|
||||
* your own right click actions to different item types (see itemInHand)
|
||||
*
|
||||
* @param player
|
||||
* @param blockPlaced
|
||||
* @param blockClicked
|
||||
* @param itemInHand
|
||||
* @return false if you want the action to go through
|
||||
*/
|
||||
public boolean onBlockCreate(Player player, Block blockPlaced, Block blockClicked,
|
||||
int itemInHand) {
|
||||
if (blacklist != null) {
|
||||
BlacklistEntry entry = blacklist.get(itemInHand);
|
||||
if (entry != null) {
|
||||
if (!entry.onRightClick(itemInHand, player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a person left clicks a block.
|
||||
*
|
||||
* @param player
|
||||
* @param block
|
||||
* @return
|
||||
*/
|
||||
public boolean onBlockDestroy(Player player, Block block) {
|
||||
if (blacklist != null) {
|
||||
BlacklistEntry entry = blacklist.get(player.getItemInHand());
|
||||
if (entry != null) {
|
||||
if (entry.onLeftClick(player.getItemInHand(), player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
entry = blacklist.get(block.getType());
|
||||
if (entry != null) {
|
||||
if (!entry.onDestroy(block, player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when either a lava block or a lighter tryes to light something on fire.
|
||||
* block status depends on the light source:
|
||||
* 1 = lava.
|
||||
* 2 = lighter (flint + steel).
|
||||
* 3 = spread (dynamic spreading of fire).
|
||||
* @param block
|
||||
* block that the fire wants to spawn in.
|
||||
*
|
||||
* @return true if you dont want the fire to ignite.
|
||||
*/
|
||||
public boolean onIgnite(Block block, Player player) {
|
||||
if (preventLavaFire && block.getStatus() == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (blockLighter && block.getStatus() == 2) {
|
||||
return !player.canUseCommand("/uselighter")
|
||||
&& !player.canUseCommand("/lighter");
|
||||
}
|
||||
|
||||
if (disableAllFire && block.getStatus() == 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fireNoSpreadBlocks != null && block.getStatus() == 3) {
|
||||
int x = block.getX();
|
||||
int y = block.getY();
|
||||
int z = block.getZ();
|
||||
if (fireNoSpreadBlocks.contains(etc.getServer().getBlockIdAt(x, y - 1, z))
|
||||
|| fireNoSpreadBlocks.contains(etc.getServer().getBlockIdAt(x + 1, y, z))
|
||||
|| fireNoSpreadBlocks.contains(etc.getServer().getBlockIdAt(x - 1, y, z))
|
||||
|| fireNoSpreadBlocks.contains(etc.getServer().getBlockIdAt(x, y, z - 1))
|
||||
|| fireNoSpreadBlocks.contains(etc.getServer().getBlockIdAt(x, y, z + 1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a dynamite block or a creeper is triggerd.
|
||||
* block status depends on explosive compound:
|
||||
* 1 = dynamite.
|
||||
* 2 = creeper.
|
||||
* @param block
|
||||
* dynamite block/creeper location block.
|
||||
*
|
||||
* @return true if you dont the block to explode.
|
||||
*/
|
||||
public boolean onExplode(Block block) {
|
||||
if (blockCreepers && block.getStatus() == 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (blockTNT && block.getStatus() == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when lava wants to flow to a certain block.
|
||||
* block status represents the type that wants to flow.
|
||||
* (10 & 11 for lava and 8 & 9 for water)
|
||||
*
|
||||
* @param block
|
||||
* the block beneath where the substance wants to flow to.
|
||||
*
|
||||
* for example:
|
||||
* lava want to flow to block x,y,z then the param block is the block x,y-1,z.
|
||||
*
|
||||
* @return true if you dont want the substance to flow.
|
||||
*/
|
||||
public boolean onFlow(Block block) {
|
||||
if (simulateSponge && (block.getStatus() == 8 || block.getStatus() == 9)) {
|
||||
int ox = block.getX();
|
||||
int oy = block.getY() + 1;
|
||||
int oz = block.getZ();
|
||||
|
||||
Server server = etc.getServer();
|
||||
|
||||
for (int x = -4; x <= 4; x++) {
|
||||
for (int y = -4; y <= 4; y++) {
|
||||
for (int z = -4; z <= 4; z++) {
|
||||
if (server.getBlockIdAt(ox + x, oy + y, oz + z) == 19) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classicWater && (block.getStatus() == 8 || block.getStatus() == 9)) {
|
||||
int blockBelow = etc.getServer().getBlockIdAt(block.getX(), block.getY(), block.getZ());
|
||||
if (blockBelow != 0 && blockBelow != 8 && blockBelow != 9) {
|
||||
etc.getServer().setBlockAt(9, block.getX(), block.getY() + 1, block.getZ());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedLavaSpreadOver != null && (block.getStatus() == 10 || block.getStatus() == 11)) {
|
||||
if (!allowedLavaSpreadOver.contains(block.getType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on player disconnect
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
public void onDisconnect(Player player) {
|
||||
BlacklistEntry.forgetPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the blacklist.
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Map<Integer,BlacklistEntry> loadBlacklist(File file)
|
||||
throws IOException {
|
||||
FileReader input = null;
|
||||
Map<Integer,BlacklistEntry> blacklist = new HashMap<Integer,BlacklistEntry>();
|
||||
|
||||
try {
|
||||
input = new FileReader(file);
|
||||
BufferedReader buff = new BufferedReader(input);
|
||||
|
||||
String line;
|
||||
List<BlacklistEntry> entries = null;
|
||||
while ((line = buff.readLine()) != null) {
|
||||
line = line.trim();
|
||||
|
||||
// Blank line
|
||||
if (line.length() == 0) {
|
||||
continue;
|
||||
} else if (line.charAt(0) == ';' || line.charAt(0) == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.matches("^\\[.*\\]$")) {
|
||||
String[] items = line.substring(1, line.length() - 1).split(",");
|
||||
entries = new ArrayList<BlacklistEntry>();
|
||||
|
||||
for (String item : items) {
|
||||
int id = 0;
|
||||
|
||||
try {
|
||||
id = Integer.parseInt(item.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
id = etc.getDataSource().getItem(item.trim());
|
||||
if (id == 0) {
|
||||
logger.log(Level.WARNING, "WorldProtect: Unknown block name: "
|
||||
+ item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistEntry entry = new BlacklistEntry();
|
||||
blacklist.put(id, entry);
|
||||
entries.add(entry);
|
||||
}
|
||||
} else if (entries != null) {
|
||||
String[] parts = line.split("=");
|
||||
|
||||
if (parts.length == 1) {
|
||||
logger.log(Level.WARNING, "Found option with no value "
|
||||
+ file.getName() + " for '" + line + "'");
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean unknownOption = false;
|
||||
|
||||
for (BlacklistEntry entry : entries) {
|
||||
if (parts[0].equalsIgnoreCase("ignore-groups")) {
|
||||
entry.setIgnoreGroups(parts[1].split(","));
|
||||
} else if(parts[0].equalsIgnoreCase("on-destroy")) {
|
||||
entry.setDestroyActions(parts[1].split(","));
|
||||
} else if(parts[0].equalsIgnoreCase("on-left")) {
|
||||
entry.setLeftClickActions(parts[1].split(","));
|
||||
} else if(parts[0].equalsIgnoreCase("on-right")) {
|
||||
entry.setRightClickActions(parts[1].split(","));
|
||||
} else {
|
||||
unknownOption = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (unknownOption) {
|
||||
logger.log(Level.WARNING, "Unknown option '" + parts[0]
|
||||
+ "' in " + file.getName() + " for '" + line + "'");
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "Found option with no heading "
|
||||
+ file.getName() + " for '" + line + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return blacklist.isEmpty() ? null : blacklist;
|
||||
} finally {
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
}
|
||||
} catch (IOException e2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
src/com/sk89q/worldprotect/ConsoleLogFormat.java
Normal file
64
src/com/sk89q/worldprotect/ConsoleLogFormat.java
Normal file
@ -0,0 +1,64 @@
|
||||
// $Id$
|
||||
/*
|
||||
* WorldProtect
|
||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldprotect;
|
||||
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Level;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Used for formatting.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class ConsoleLogFormat extends Formatter {
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
Level level = record.getLevel();
|
||||
|
||||
if (level == Level.FINEST) {
|
||||
text.append("[FINEST] ");
|
||||
} else if (level == Level.FINER) {
|
||||
text.append("[FINER] ");
|
||||
} else if (level == Level.FINE) {
|
||||
text.append("[FINE] ");
|
||||
} else if (level == Level.INFO) {
|
||||
text.append("[INFO] ");
|
||||
} else if (level == Level.WARNING) {
|
||||
text.append("[WARNING] ");
|
||||
} else if (level == Level.SEVERE) {
|
||||
text.append("[SEVERE] ");
|
||||
}
|
||||
|
||||
text.append(record.getMessage());
|
||||
text.append("\r\n");
|
||||
|
||||
Throwable t = record.getThrown();
|
||||
if (t != null) {
|
||||
StringWriter writer = new StringWriter();
|
||||
t.printStackTrace(new PrintWriter(writer));
|
||||
text.append(writer.toString());
|
||||
}
|
||||
|
||||
return text.toString();
|
||||
}
|
||||
}
|
47
src/com/sk89q/worldprotect/SimpleLogFormat.java
Normal file
47
src/com/sk89q/worldprotect/SimpleLogFormat.java
Normal file
@ -0,0 +1,47 @@
|
||||
// $Id$
|
||||
/*
|
||||
* WorldProtect
|
||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldprotect;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Used for formatting.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class SimpleLogFormat extends Formatter {
|
||||
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
Level level = record.getLevel();
|
||||
|
||||
text.append("[");
|
||||
text.append(dateFormat.format(new Date(record.getMillis())));
|
||||
text.append("] ");
|
||||
text.append(record.getMessage());
|
||||
text.append("\r\n");
|
||||
|
||||
return text.toString();
|
||||
}
|
||||
}
|
32
worldprotect-blacklist.txt
Normal file
32
worldprotect-blacklist.txt
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is the blacklist for WorldProtect. Comments start with # and they
|
||||
# are ignored so you can put your own notes.
|
||||
#
|
||||
# Format:
|
||||
# [item1,item2,itemN]
|
||||
# option1=options
|
||||
# event1=action1,action2,actionN
|
||||
# eventN=action1,action2,actionN
|
||||
#
|
||||
# Events/Options:
|
||||
# - ignore-groups (comma-delimited list of groups to not affect)
|
||||
# - on-destroy (when a block of this type is destroyed)
|
||||
# - on-left (when this item is held and the player is left clicking)
|
||||
# - on-right (when this item is held and the player is right clicking)
|
||||
#
|
||||
# Actions:
|
||||
# - deny (deny completely)
|
||||
# - notify (notify admins)
|
||||
# - log (log to console/file)
|
||||
# - kick (kick player)
|
||||
# - tell (tell a player that that's not allowed)
|
||||
#
|
||||
# Some examples follow.
|
||||
#
|
||||
#[lavabucket]
|
||||
#on-left=deny,log,kick
|
||||
#on-right=deny,tell
|
||||
#[coalore,goldore,ironore]
|
||||
#on-destroy=notify,deny,log
|
||||
#[cobblestone]
|
||||
#on-right=deny,tell,log
|
Loading…
Reference in New Issue
Block a user