Breaking changes:

- Permissions 2/3 are no longer supported
- Changed ChestShop.shop.create permission to consist of 2 different permissions: ChestShop.shop.create.buy and ChestShop.shop.create.sell
- (Experimental) Ability to add max item prices to the config
- (Experimental) Added a custom "chestshop" WorldGuard flag using reflection

- Switched to new Config system
- Updated Metrics
- Removed chest masking option
This commit is contained in:
Acrobot 2012-03-01 22:03:59 +01:00
parent a49d51ce97
commit 7f8af7b5b3
27 changed files with 679 additions and 302 deletions

View File

@ -0,0 +1,30 @@
package com.Acrobot.ChestShop.BukkitFixes;
import com.Acrobot.ChestShop.Chests.MinecraftChest;
import net.minecraft.server.TileEntityChest;
import org.bukkit.block.Chest;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
import org.bukkit.inventory.Inventory;
/**
* Temporary class until this is fixed in Bukkit
* @author Acrobot
*/
public class bInventoryFix {
public static Inventory getInventory(Chest chest) {
MinecraftChest mchest = new MinecraftChest(chest);
TileEntityChest teChest = (TileEntityChest) ((CraftWorld) chest.getWorld()).getTileEntityAt(chest.getX(), chest.getY(), chest.getZ());
CraftInventory ci = new CraftInventory(teChest);
if (mchest.getNeighbor() != null) {
Chest nb = mchest.getNeighbor();
TileEntityChest neighbor = (TileEntityChest) ((CraftWorld) chest.getWorld()).getTileEntityAt(nb.getX(), nb.getY(), nb.getZ());
return new CraftInventoryDoubleChest(ci, new CraftInventory(neighbor));
}
return ci;
}
}

View File

@ -13,10 +13,10 @@ import com.Acrobot.ChestShop.Logging.FileWriterQueue;
import com.avaje.ebean.EbeanServer;
import com.lennardf1989.bukkitex.Database;
import org.bukkit.Server;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;
import java.io.File;
import java.util.ArrayList;
@ -56,7 +56,6 @@ public class ChestShop extends JavaPlugin {
if (Config.getBoolean(Property.LOG_TO_DATABASE) || Config.getBoolean(Property.GENERATE_STATISTICS_PAGE)) setupDB();
if (Config.getBoolean(Property.GENERATE_STATISTICS_PAGE)) scheduleTask(new Generator(), 300L, (long) Config.getDouble(Property.STATISTICS_PAGE_GENERATION_INTERVAL) * 20L);
if (Config.getBoolean(Property.LOG_TO_FILE)) scheduleTask(new FileWriterQueue(), 201L, 201L);
//if (Config.getBoolean(Property.MASK_CHESTS_AS_OTHER_BLOCKS)) scheduleTask(new MaskChest(), 40L, 40L); //Disabled due to bug //TODO Fix that
playerInteract.interval = Config.getInteger(Property.SHOP_INTERACTION_INTERVAL);
//Register our commands!
@ -65,12 +64,10 @@ public class ChestShop extends JavaPlugin {
//Start the statistics pinger
startStatistics();
System.out.println('[' + getPluginName() + "] version " + getVersion() + " initialized!");
}
public void onDisable() {
System.out.println('[' + getPluginName() + "] version " + getVersion() + " shutting down!");
getServer().getScheduler().cancelTasks(this);
}
////////////////// REGISTER EVENTS, SCHEDULER & STATS ///////////////////////////
@ -97,10 +94,8 @@ public class ChestShop extends JavaPlugin {
}
///////////////////// DATABASE STUFF ////////////////////////////////
private static Configuration getBukkitConfig() {
Configuration config = new Configuration(new File("bukkit.yml"));
config.load();
return config;
private static YamlConfiguration getBukkitConfig() {
return YamlConfiguration.loadConfiguration(new File("bukkit.yml"));
}
private static Database database;
@ -114,7 +109,7 @@ public class ChestShop extends JavaPlugin {
}
};
Configuration config = getBukkitConfig();
YamlConfiguration config = getBukkitConfig();
database.initializeDatabase(
config.getString("database.driver"),
@ -150,7 +145,7 @@ public class ChestShop extends JavaPlugin {
return DB;
}
public static ArrayList getDependencies() {
return (ArrayList) description.getSoftDepend();
public static List getDependencies() {
return (List) description.getSoftDepend();
}
}

View File

@ -74,7 +74,7 @@ public class MinecraftChest implements ChestObject {
return main.getInventory().getSize() + (neighbor != null ? neighbor.getInventory().getSize() : 0);
}
private Chest getNeighbor() {
public Chest getNeighbor() {
return uBlock.findNeighbor(main);
}

View File

@ -20,6 +20,10 @@ public class Config {
public static float getFloat(Property value) {
return new Float(getValue(value.name()).toString());
}
public static float getFloat(String value) {
return new Float(getValue(value).toString());
}
public static String getString(Property value) {
return (String) getValue(value.name());
@ -40,6 +44,10 @@ public class Config {
public static String getLocal(Language lang) {
return getColored(config.getLanguageConfig().getString(Language.prefix.name()) + config.getLanguageConfig().getString(lang.name()));
}
public static boolean exists(String value) {
return getValue(value) != null;
}
private static Object getValue(String node) {
return config.getProperty(node);

View File

@ -2,7 +2,9 @@ package com.Acrobot.ChestShop.Config;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Utils.uLongName;
import org.bukkit.util.config.Configuration;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.FileWriter;
@ -13,35 +15,33 @@ import java.io.FileWriter;
public class ConfigObject {
private final File configFile = new File(ChestShop.folder, "config.yml");
private final File langFile = new File(ChestShop.folder, "local.yml");
private final Configuration config = new Configuration(configFile);
private final Configuration language = new Configuration(langFile);
private final YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
private final YamlConfiguration language = YamlConfiguration.loadConfiguration(langFile);
public ConfigObject() {
if (!ChestShop.folder.exists()) ChestShop.folder.mkdir();
reloadConfig();
config.load();
load(config, configFile);
reloadLanguage();
language.load();
load(language, langFile);
uLongName.config = new Configuration(new File(ChestShop.folder, "longName.storage"));
uLongName.config.load();
uLongName.configFile = new File(ChestShop.folder, "longName.storage");
uLongName.config = YamlConfiguration.loadConfiguration(uLongName.configFile);
}
private void reloadConfig() {
config.load();
for (Property def : Property.values()) {
if (config.getProperty(def.name()) == null) {
if (config.get(def.name()) == null) {
writeToFile('\n' + def.name() + ": " + def.getValue() + "\n#" + def.getComment(), configFile);
}
}
}
private void reloadLanguage() {
language.load();
for (Language def : Language.values()) {
if (language.getProperty(def.name()) == null) {
if (language.get(def.name()) == null) {
writeToFile('\n' + def.name() + ": \"" + def.toString() + '\"', langFile);
}
}
@ -62,6 +62,27 @@ public class ConfigObject {
}
public Object getProperty(String property) {
return config.getProperty(property);
return config.get(property);
}
public static void load(FileConfiguration config, File file) {
try {
config.load(file);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void save(FileConfiguration config, File file) {
try {
config.save(file);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void reloadConfig(FileConfiguration config, File file) {
save(config, file);
load(config, file);
}
}

View File

@ -0,0 +1,29 @@
package com.Acrobot.ChestShop.Config;
import org.bukkit.Material;
/**
* @author Acrobot
*/
public class MaxPrice {
public static boolean canCreate(float buyPrice, float sellPrice, Material mat) {
float bPrice = maxBuyPrice(mat.getId());
float sPrice = maxSellPrice(mat.getId());
return (bPrice == -1 || buyPrice <= maxBuyPrice(mat.getId()))
&& (sPrice == -1 || sellPrice <= maxSellPrice(mat.getId()));
}
public static float maxBuyPrice(int itemID) {
return getPrice("buy", itemID);
}
public static float maxSellPrice(int itemID) {
return getPrice("sell", itemID);
}
public static float getPrice(String value, int itemID) {
String node = "max-" + value + "-price-" + itemID;
return Config.exists(node) ? Config.getFloat(node) : -1;
}
}

View File

@ -21,14 +21,13 @@ public enum Property {
USE_BUILT_IN_PROTECTION(true, "Do you want to use built-in protection against chest destruction?"),
PROTECT_CHEST_WITH_LWC(false, "Do you want to protect shop chests with LWC?"),
PROTECT_SIGN_WITH_LWC(false, "Do you want to protect shop signs with LWC?"),
//MASK_CHESTS_AS_OTHER_BLOCKS(false, "Do you want to mask shop chests as other blocks? HIGHLY EXPERIMENTAL, CAN LAG!"),
IGNORE_CREATIVE_MODE(true, "Do you want to allow using shops to people in creative mode?"),
SHOW_MESSAGE_OUT_OF_STOCK(true, "Do you want to show \"Out of stock\" messages?"),
SHOW_TRANSACTION_INFORMATION_CLIENT(true, "Do you want to show \"You bought/sold... \" messages?"),
SHOW_TRANSACTION_INFORMATION_OWNER(true, "Do you want to show \"Somebody bought/sold... \" messages?"),
TOWNY_INTEGRATION(false, "Do you want to only let people build inside shop plots?"),
TOWNY_SHOPS_FOR_OWNERS_ONLY(true, "If true, only plot owners are able to build inside a shop plot. If false, every town's resident is able to build there."),
WORLDGUARD_INTEGRATION(false, "Do you want to only let people build inside plots?"),
WORLDGUARD_INTEGRATION(false, "Do you want to only let people build inside regions with /region flag chestshop allowed?"),
TAX_AMOUNT(0, "Percent of the price that should go to the server's account. (100 = 100 percent)"),
SERVER_TAX_AMOUNT(0, "Percent of the price that should go to the server's account when buying from an Admin Shop"),
SHOP_REFUND_PRICE(0, "How much money do you get back when destroying a sign?"),

View File

@ -17,13 +17,17 @@ public class Generator implements Runnable {
private static double generationTime;
private static final String header = fileToString("header");
private static final String row = fileToString("row");
private static final String footer = fileToString("footer");
private static String header;
private static String row;
private static String footer;
private static BufferedWriter buf;
public void run() {
header = fileToString("header");
row = fileToString("row");
footer = fileToString("footer");
if (row.isEmpty()) System.out.println(ChestShop.chatPrefix + "You lack the necessary HTML files in your plugins/ChestShop/HTML folder!");
generateStats();
}
@ -42,7 +46,7 @@ public class Generator implements Runnable {
private static String fileToString(String fileName) {
try {
File f = new File(ChestShop.folder + "/HTML/" + fileName + ".html");
File f = new File(ChestShop.folder + File.separator + "HTML" + File.separator + fileName + ".html");
FileReader rd = new FileReader(f);
char[] buf = new char[(int) f.length()];
rd.read(buf);
@ -113,6 +117,7 @@ public class Generator implements Runnable {
private static void generateStats() {
try {
File f = new File(filePath).getParentFile();
if (!f.exists()) f.mkdir();

View File

@ -19,7 +19,8 @@ public class Queue implements Runnable {
}
public void run() {
deleteOld();
if (Config.getInteger(Property.RECORD_TIME_TO_LIVE) != -1)
deleteOld();
ChestShop.getDB().save(queue);
queue.clear();

View File

@ -58,6 +58,8 @@ public class Items {
String first = split[0];
String[] space = first.split(" ");
if (space.length == 0) return null;
Material material = getMaterial(first);
for (int i = (space.length > 1 ? 1 : 0); i >= 0 && material == null; i--) material = getMaterial(space[i]);

View File

@ -1,5 +1,6 @@
package com.Acrobot.ChestShop.Listeners;
import com.Acrobot.ChestShop.BukkitFixes.bInventoryFix;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Language;
import com.Acrobot.ChestShop.Config.Property;
@ -9,21 +10,18 @@ import com.Acrobot.ChestShop.Shop.ShopManagement;
import com.Acrobot.ChestShop.Signs.restrictedSign;
import com.Acrobot.ChestShop.Utils.uBlock;
import com.Acrobot.ChestShop.Utils.uSign;
import net.minecraft.server.IInventory;
import net.minecraft.server.InventoryLargeChest;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.block.Sign;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory;
import java.util.HashMap;
@ -96,12 +94,7 @@ public class playerInteract implements Listener {
player.sendMessage(Config.getLocal(Language.NO_CHEST_DETECTED));
return;
}
IInventory inventory = ((CraftInventory) chest.getInventory()).getInventory();
chest = uBlock.findNeighbor(chest);
if (chest != null) inventory = new InventoryLargeChest("Large chest", inventory, ((CraftInventory) chest.getInventory()).getInventory());
((CraftPlayer) player).getHandle().a(inventory); //Show inventory on the screen
Inventory chestInv = bInventoryFix.getInventory(chest);
player.openInventory(chestInv);
}
}

View File

@ -5,17 +5,15 @@ import com.Acrobot.ChestShop.Economy.NoProvider;
import com.Acrobot.ChestShop.Economy.Register;
import com.Acrobot.ChestShop.Economy.Vault;
import com.Acrobot.ChestShop.Items.Odd;
import com.Acrobot.ChestShop.Permission;
import com.Acrobot.ChestShop.Protection.Plugins.*;
import com.Acrobot.ChestShop.Protection.Security;
import com.Acrobot.ChestShop.Utils.WorldGuard.uWorldGuard;
import com.Acrobot.ChestShop.Utils.uHeroes;
import com.Acrobot.ChestShop.Utils.uNumber;
import com.Acrobot.ChestShop.Utils.uSign;
import com.Acrobot.ChestShop.Utils.uWorldGuard;
import com.daemitus.deadbolt.Deadbolt;
import com.griefcraft.lwc.LWCPlugin;
import com.herocraftonline.dev.heroes.Heroes;
import com.nijikokun.bukkit.Permissions.Permissions;
import com.nijikokun.register.payment.forChestShop.Method;
import com.nijikokun.register.payment.forChestShop.Methods;
import com.palmergames.bukkit.towny.Towny;
@ -50,14 +48,12 @@ public class pluginEnable {
}
Register.eco = m;
com.Acrobot.ChestShop.Economy.Economy.economy = new Register();
System.out.println(ChestShop.chatPrefix + m.getName() + " loaded.");
System.out.println(ChestShop.chatPrefix + m.getName() + " version " + m.getName() + " loaded.");
}
}
private static void initializePlugin(String name, Plugin plugin) { //Really messy, right? But it's short and fast :)
if (name.equals("Permissions")) {
Permission.permissions = ((Permissions) plugin).getHandler();
} else if (name.equals("LWC")) {
if (name.equals("LWC")) {
LWCplugin.setLWC(((LWCPlugin) plugin).getLWC());
Security.protections.add(new LWCplugin());
} else if (name.equals("Lockette")) {
@ -77,6 +73,7 @@ public class pluginEnable {
uSign.towny = (Towny) plugin;
} else if (name.equals("WorldGuard")) {
uWorldGuard.worldGuard = (WorldGuardPlugin) plugin;
uWorldGuard.injectHax(); //Inject hax into WorldGuard
} else if (name.equals("Vault")) {
if (com.Acrobot.ChestShop.Economy.Economy.economy != null) return;
RegisteredServiceProvider<Economy> rsp = ChestShop.getBukkitServer().getServicesManager().getRegistration(Economy.class);
@ -90,6 +87,8 @@ public class pluginEnable {
} else if (name.equals("SimpleChestLock")) {
SCLplugin.scl = (SCL) plugin;
Security.protections.add(new SCLplugin());
} else {
return;
}
PluginDescriptionFile description = plugin.getDescription();

View File

@ -2,6 +2,7 @@ package com.Acrobot.ChestShop.Listeners;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Language;
import com.Acrobot.ChestShop.Config.MaxPrice;
import com.Acrobot.ChestShop.Config.Property;
import com.Acrobot.ChestShop.Economy.Economy;
import com.Acrobot.ChestShop.Items.Items;
@ -9,6 +10,7 @@ import com.Acrobot.ChestShop.Permission;
import com.Acrobot.ChestShop.Protection.Security;
import com.Acrobot.ChestShop.Signs.restrictedSign;
import com.Acrobot.ChestShop.Utils.*;
import com.Acrobot.ChestShop.Utils.WorldGuard.uWorldGuard;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@ -38,18 +40,12 @@ public class signChange implements Listener {
boolean playerIsAdmin = Permission.has(player, Permission.ADMIN);
if (isAlmostReady) {
if (mat == null) {
player.sendMessage(Config.getLocal(Language.INCORRECT_ITEM_ID));
dropSign(event);
return;
}
if (!canCreateShop(player, mat.getId())) {
player.sendMessage(Config.getLocal(Language.YOU_CANNOT_CREATE_SHOP));
dropSign(event);
return;
}
} else {
if (restrictedSign.isRestricted(line)) {
if (!restrictedSign.hasPermission(player, line)) {
@ -91,8 +87,9 @@ public class signChange implements Listener {
}
Block chestBlock = chest.getBlock();
boolean cantBuildTowny = uSign.towny != null && !uTowny.canBuild(player, signBlock.getLocation(), chestBlock.getLocation());
if (!uWorldGuard.isNotOutsideWGplot(signBlock.getLocation()) || (uSign.towny != null && !uTowny.canBuild(player, signBlock.getLocation(), chestBlock.getLocation()))) {
if (!uWorldGuard.canBuildShopHere(signBlock.getLocation()) && cantBuildTowny){
player.sendMessage(Config.getLocal(Language.TOWNY_CANNOT_CREATE_SHOP_HERE));
dropSign(event);
return;
@ -107,7 +104,14 @@ public class signChange implements Listener {
}
}
float buyPrice = uSign.buyPrice(thirdLine);
float sellPrice = uSign.sellPrice(thirdLine);
if (!playerIsAdmin && (!canCreateShop(player, mat.getId(), buyPrice != -1, sellPrice != -1) || !MaxPrice.canCreate(buyPrice, sellPrice, mat))) {
player.sendMessage(Config.getLocal(Language.YOU_CANNOT_CREATE_SHOP));
dropSign(event);
return;
}
float shopCreationPrice = Config.getFloat(Property.SHOP_CREATION_PRICE);
boolean paid = shopCreationPrice != 0 && !isAdminShop && !Permission.has(player, Permission.NOFEE);
@ -134,14 +138,13 @@ public class signChange implements Listener {
uHeroes.addHeroExp(player);
}
private static boolean canCreateShop(Player player, boolean isAdmin, int ID) {
return isAdmin ||
Permission.has(player, Permission.SHOP_CREATION) ||
Permission.has(player, Permission.SHOP_CREATION.toString() + '.' + ID);
}
private static boolean canCreateShop(Player player, int ID, boolean buy, boolean sell) {
if (Permission.has(player, Permission.SHOP_CREATION_ID + Integer.toString(ID))) return true;
if (buy && !Permission.has(player, Permission.SHOP_CREATION_BUY)) return false;
if (sell && !Permission.has(player, Permission.SHOP_CREATION_SELL)) return false;
private static boolean canCreateShop(Player player, int ID) {
return canCreateShop(player, Permission.has(player, Permission.ADMIN), ID);
return true;
}
private static String formatThirdLine(String thirdLine) {

View File

@ -1,92 +1,63 @@
package com.Acrobot.ChestShop;/*
* Copyright 2011 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.Acrobot.ChestShop;
/*
* Copyright 2011 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Tooling to post to metrics.griefcraft.com
*/
public class Metrics {
/**
* Interface used to collect custom data for a plugin
* The current revision number
*/
public static abstract class Plotter {
/**
* Get the column name for the plotted point
*
* @return the plotted point's column name
*/
public abstract String getColumnName();
/**
* Get the current value for the plotted point
*
* @return
*/
public abstract int getValue();
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode() + getValue();
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Plotter)) {
return false;
}
Plotter plotter = (Plotter) object;
return plotter.getColumnName().equals(getColumnName()) && plotter.getValue() == getValue();
}
}
/**
* The metrics revision number
*/
private final static int REVISION = 4;
private final static int REVISION = 5;
/**
* The base url of the metrics domain
@ -104,14 +75,25 @@ public class Metrics {
private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml";
/**
* Interval of time to ping in minutes
* The separator to use for custom data. This MUST NOT change unless you are hosting your own
* version of metrics and want to change it.
*/
private static final String CUSTOM_DATA_SEPARATOR = "~~";
/**
* Interval of time to ping (in minutes)
*/
private final static int PING_INTERVAL = 10;
/**
* A map of the custom data plotters for plugins
* A map of all of the graphs for each plugin
*/
private Map<Plugin, Set<Plotter>> customData = Collections.synchronizedMap(new HashMap<Plugin, Set<Plotter>>());
private Map<Plugin, Set<Graph>> graphs = Collections.synchronizedMap(new HashMap<Plugin, Set<Graph>>());
/**
* A convenient map of the default Graph objects (used by addCustomData mainly)
*/
private Map<Plugin, Graph> defaultGraphs = Collections.synchronizedMap(new HashMap<Plugin, Graph>());
/**
* The plugin configuration file
@ -142,6 +124,33 @@ public class Metrics {
guid = configuration.getString("guid");
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs
* on the metrics website. Plotters can be added to the graph object returned.
*
* @param plugin
* @param type
* @param name
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
*/
public Graph createGraph(Plugin plugin, Graph.Type type, String name) {
if (plugin == null || type == null || name == null) {
throw new IllegalArgumentException("All arguments must not be null");
}
// Construct the graph object
Graph graph = new Graph(type, name);
// Get the graphs for the plugin
Set<Graph> graphs = getOrCreateGraphs(plugin);
// Now we can add our graph
graphs.add(graph);
// and return back
return graph;
}
/**
* Adds a custom data plotter for a given plugin
*
@ -149,14 +158,14 @@ public class Metrics {
* @param plotter
*/
public void addCustomData(Plugin plugin, Plotter plotter) {
Set<Plotter> plotters = customData.get(plugin);
// The default graph for the plugin
Graph graph = getOrCreateDefaultGraph(plugin);
if (plotters == null) {
plotters = Collections.synchronizedSet(new LinkedHashSet<Plotter>());
customData.put(plugin, plotters);
}
// Add the plotter to the graph o/
graph.addPlotter(plotter);
plotters.add(plotter);
// Ensure the default graph is included in the submitted graphs
getOrCreateGraphs(plugin).add(graph);
}
/**
@ -164,33 +173,31 @@ public class Metrics {
*
* @param plugin
*/
public void beginMeasuringPlugin(final Plugin plugin) throws IOException {
public void beginMeasuringPlugin(final Plugin plugin) {
// Did we opt out?
if (configuration.getBoolean("opt-out", false)) {
return;
}
// First tell the server about us
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
public void run() {
try {
postPlugin(plugin, false);
} catch (IOException e) {
System.out.println("[Metrics] " + e.getMessage());
}
}
}, 20L);
// Ping the server in intervals
// Begin hitting the server with glorious data
plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
postPlugin(plugin, true);
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(plugin, !firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
System.out.println("[Metrics] " + e.getMessage());
}
}
}, PING_INTERVAL * 1200, PING_INTERVAL * 1200);
}, 0, PING_INTERVAL * 1200);
}
/**
@ -199,26 +206,61 @@ public class Metrics {
* @param plugin
*/
private void postPlugin(Plugin plugin, boolean isPing) throws IOException {
// The plugin's description file containg all of the plugin data such as name, version, author, etc
PluginDescriptionFile description = plugin.getDescription();
// The author string, created with description.getAuthors()
// Authors are separated by a comma
String authors = "";
// Add each author to the string
for (String author : description.getAuthors()) {
authors += author + ", ";
}
// If there were any authors at all, we need to remove the last 2 characters
// the last 2 characters are the last comma and space
if (!authors.isEmpty()) {
authors = authors.substring(0, authors.length() - 2);
}
// Construct the post data
String response = "ERR No response";
StringBuilder data = new StringBuilder(10);
data.append(encode("guid")).append('=').append(encode(guid))
.append(gField("version", plugin.getDescription().getVersion()))
.append(gField("server", Bukkit.getVersion()))
.append(gField("players", String.valueOf(Bukkit.getServer().getOnlinePlayers().length)))
.append(gField("revision", String.valueOf(REVISION)));
String data = encode("guid") + '=' + encode(guid)
+ encodeDataPair("authors", authors)
+ encodeDataPair("version", description.getVersion())
+ encodeDataPair("server", Bukkit.getVersion())
+ encodeDataPair("players", Integer.toString(Bukkit.getServer().getOnlinePlayers().length))
+ encodeDataPair("revision", String.valueOf(REVISION));
// If we're pinging, append it
if (isPing) {
data.append(gField("ping", "true"));
data += encodeDataPair("ping", "true");
}
// Add any custom data (if applicable)
Set<Plotter> plotters = customData.get(plugin);
// Add any custom data available for the plugin
Set<Graph> graphs = getOrCreateGraphs(plugin);
if (plotters != null) {
for (Plotter plotter : plotters) {
data.append(gField("Custom" + plotter.getColumnName(), Integer.toString(plotter.getValue())));
// Acquire a lock on the graphs, which lets us make the assumption we also lock everything
// inside of the graph (e.g plotters)
synchronized(graphs) {
for (Graph graph : graphs) {
// Because we have a lock on the graphs set already, it is reasonable to assume
// that our lock transcends down to the individual plotters in the graphs also.
// Because our methods are private, no one but us can reasonably access this list
// without reflection so this is a safe assumption without adding more code.
for (Plotter plotter : graph.getPlotters()) {
// The key name to send to the metrics server
// The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top
// Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME
String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName());
// The value to send, which for the foreseeable future is just the string
// value of plotter.getValue()
String value = Integer.toString(plotter.getValue());
// Add it to the http post data :)
data += encodeDataPair(key, value);
}
}
}
@ -226,17 +268,26 @@ public class Metrics {
URL url = new URL(BASE_URL + String.format(REPORT_URL, plugin.getDescription().getName()));
// Connect to the website
URLConnection connection = url.openConnection();
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
connection.setDoOutput(true);
// Write the data
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data.toString());
writer.write(data);
writer.flush();
// Now read the response
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
response = reader.readLine();
String response = reader.readLine();
// close resources
writer.close();
@ -247,9 +298,15 @@ public class Metrics {
} else {
// Is this the first update this hour?
if (response.contains("OK This is your first update this hour")) {
if (plotters != null) {
for (Plotter plotter : plotters) {
plotter.reset();
synchronized (graphs) {
Iterator<Graph> iter = graphs.iterator();
while (iter.hasNext()) {
Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
plotter.reset();
}
}
}
}
@ -258,14 +315,68 @@ public class Metrics {
}
/**
* Generates a field
* @param name Field name
* @param data Data assigned to the field
* @return Field
* @throws UnsupportedEncodingException
* Get or create the Set of graphs for a specific plugin
*
* @param plugin
* @return
*/
private static String gField(String name, String data) throws UnsupportedEncodingException {
return '&' + encode(name) + '=' + encode(data);
private Set<Graph> getOrCreateGraphs(Plugin plugin) {
Set<Graph> theGraphs = graphs.get(plugin);
// Create the Set if it does not already exist
if (theGraphs == null) {
theGraphs = Collections.synchronizedSet(new HashSet<Graph>());
graphs.put(plugin, theGraphs);
}
return theGraphs;
}
/**
* Get the default graph for a plugin and if it does not exist, create one
*
* @param plugin
* @return
*/
private Graph getOrCreateDefaultGraph(Plugin plugin) {
Graph graph = defaultGraphs.get(plugin);
// Not yet created :(
if (graph == null) {
graph = new Graph(Graph.Type.Line, "Default");
defaultGraphs.put(plugin, graph);
}
return graph;
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return
*/
private static boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first
* key/value pair MUST be included manually, e.g:
* <p>
* String httpData = encode("guid") + "=" + encode("1234") + encodeDataPair("authors") + "..";
* </p>
*
* @param key
* @param value
* @return
*/
private static String encodeDataPair(String key, String value) throws UnsupportedEncodingException {
return '&' + encode(key) + '=' + encode(value);
}
/**
@ -278,4 +389,177 @@ public class Metrics {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website
*/
public static class Graph {
/**
* The graph's type that will be visible on the website
*/
public static enum Type {
/**
* A simple line graph which also includes a scrollable timeline viewer to view
* as little or as much of the data as possible.
*/
Line,
/**
* An area graph. This is the same as a line graph except the area under the curve is shaded
*/
Area,
/**
* A column graph, which is a graph where the data is represented by columns on the vertical axis,
* i.e they go up and down.
*/
Column,
/**
* A pie graph. The graph is generated by taking the data for the last hour and summing it
* together. Then the percentage for each plotter is calculated via round( (plot / total) * 100, 2 )
*/
Pie
}
/**
* What the graph should be plotted as
*/
private final Type type;
/**
* The graph's name, alphanumeric and spaces only :)
* If it does not comply to the above when submitted, it is rejected
*/
private final String name;
/**
* The set of plotters that are contained within this graph
*/
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
private Graph(Type type, String name) {
this.type = type;
this.name = name;
}
/**
* Gets the graph's name
*
* @return
*/
public String getName() {
return name;
}
/**
* Add a plotter to the graph, which will be used to plot entries
*
* @param plotter
*/
public void addPlotter(Plotter plotter) {
plotters.add(plotter);
}
/**
* Remove a plotter from the graph
*
* @param plotter
*/
public void removePlotter(Plotter plotter) {
plotters.remove(plotter);
}
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
* @return
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(plotters);
}
@Override
public int hashCode() {
return (type.hashCode() * 17) ^ name.hashCode();
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Graph)) {
return false;
}
Graph graph = (Graph) object;
return graph.type == type && graph.name.equals(name);
}
}
/**
* Interface used to collect custom data for a plugin
*/
public static abstract class Plotter {
/**
* The plot's name
*/
private final String name;
/**
* Construct a plotter with the default plot name
*/
public Plotter() {
this("Default");
}
/**
* Construct a plotter with a specific plot name
*
* @param name
*/
public Plotter(String name) {
this.name = name;
}
/**
* Get the current value for the plotted point
*
* @return
*/
public abstract int getValue();
/**
* Get the column name for the plotted point
*
* @return the plotted point's column name
*/
public String getColumnName() {
return name;
}
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode() + getValue();
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Plotter)) {
return false;
}
Plotter plotter = (Plotter) object;
return plotter.name.equals(name) && plotter.getValue() == getValue();
}
}
}

View File

@ -1,17 +1,22 @@
package com.Acrobot.ChestShop;
import com.nijiko.permissions.PermissionHandler;
import org.bukkit.entity.Player;
/**
* @author Acrobot
*/
public enum Permission {
SHOP_CREATION("ChestShop.shop.create"),
SHOP_CREATION_BUY("ChestShop.shop.create.buy"),
SHOP_CREATION_SELL("ChestShop.shop.create.sell"),
SHOP_CREATION_ID("ChestShop.shop.create."),
BUY("ChestShop.shop.buy"),
BUY_ID("ChestShop.shop.buy."),
SELL_ID("ChestShop.shop.sell."),
SELL("ChestShop.shop.sell"),
ADMIN("ChestShop.admin"),
MOD("ChestShop.mod"),
OTHER_NAME("ChestShop.name."),
@ -24,21 +29,17 @@ public enum Permission {
this.permission = permission;
}
public static PermissionHandler permissions;
public static boolean has(Player player, Permission permission) {
return has(player, permission.permission);
}
public static boolean has(Player player, String node) {
if (permissions != null) return permissions.has(player, node) || permissions.has(player, node.toLowerCase());
return player.hasPermission(node) || player.hasPermission(node.toLowerCase());
}
public static boolean otherName(Player p, String name){
if (has(p, Permission.ADMIN)) return false;
String node = OTHER_NAME + name;
if (permissions != null) return permissions.has(p, node) || permissions.has(p, node.toLowerCase());
return hasPermissionSet(p, node) || hasPermissionSet(p, node.toLowerCase());
}

View File

@ -1,62 +0,0 @@
package com.Acrobot.ChestShop.Protection;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Utils.uBlock;
import com.Acrobot.ChestShop.Utils.uSign;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
/**
* @author Acrobot
*/
public class MaskChest implements Runnable {
private final BlockFace[] bf = {BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN};
public void run() {
Player[] players = ChestShop.getBukkitServer().getOnlinePlayers();
for (Player player : players) {
World world = player.getWorld();
Location location = player.getLocation();
int pX = location.getBlockX();
int pY = location.getBlockY();
int pZ = location.getBlockZ();
int radius = 25;
for (int x = -radius; x < radius; x++) {
for (int y = -radius; y < radius; y++) {
for (int z = -radius; z < radius; z++) {
Block block = world.getBlockAt(x + pX, y + pY, z + pZ);
if (block.getType() == Material.CHEST) {
if (uBlock.findSign2(block) != null) {
Chest neighbor = uBlock.findNeighbor(block);
Material nMat = returnNearestMat(block);
if (neighbor != null) {
player.sendBlockChange(neighbor.getBlock().getLocation(), nMat, (byte) 0);
}
player.sendBlockChange(block.getLocation(), nMat, (byte) 0);
}
}
}
}
}
}
}
private Material returnNearestMat(Block block) {
for (BlockFace face : bf) {
Block faceBlock = block.getRelative(face);
Material type = faceBlock.getType();
if (type != Material.AIR && !uSign.isSign(faceBlock) && type != Material.CHEST) return type;
}
return Material.CHEST;
}
}

View File

@ -43,10 +43,7 @@ public class restrictedSign {
public static boolean hasPermission(Player p, String[] lines){
if (Permission.has(p, Permission.ADMIN)) return true;
String world = p.getWorld().getName();
String playerName = p.getName();
for (int i = 1; i <= 3; i++) {
if (Permission.permissions != null && Permission.permissions.inGroup(world, playerName, lines[i])) return true;
if (p.hasPermission(Permission.GROUP.toString() + lines[i])) return true;
}
return false;

View File

@ -0,0 +1,87 @@
package com.Acrobot.ChestShop.Utils.WorldGuard;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Property;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import org.bukkit.Location;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Acrobot
*/
public class uWorldGuard {
public static WorldGuardPlugin worldGuard;
private static final ChestShopFlag flag = new ChestShopFlag();
/*public static boolean isNotOutsideWGplot(Location l2) {
return worldGuard == null || !Config.getBoolean(Property.WORLDGUARD_INTEGRATION) || worldGuard.getGlobalRegionManager().get(l2.getWorld()).getApplicableRegions(BukkitUtil.toVector(l2)).size() != 0;
}*/
public static void injectHax() {
if (!Config.getBoolean(Property.WORLDGUARD_INTEGRATION)) return;
try {
Field field = DefaultFlag.class.getDeclaredField("flagsList");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.setAccessible(true);
List<Flag> elements = new ArrayList(Arrays.asList(DefaultFlag.getFlags()));
elements.add(flag);
Flag<?> list[] = new Flag<?>[elements.size()];
for (int i = 0; i < elements.size(); i++) {
list[i] = elements.get(i);
}
field.set(null, list);
Field grm = WorldGuardPlugin.class.getDeclaredField("globalRegionManager");
grm.setAccessible(true);
GlobalRegionManager globalRegionManager = (GlobalRegionManager) grm.get(ChestShop.getBukkitServer().getPluginManager().getPlugin("WorldGuard"));
globalRegionManager.preload();
} catch (Exception e) {
System.out.println(ChestShop.chatPrefix + "Oh noes! Something wrong happened! Be sure to paste that in your bug report:");
e.printStackTrace();
}
}
public static boolean canBuildShopHere(Location loc) {
return turnedOn() && canCreateShops(getRegions(loc));
}
public static boolean canCreateShops(ApplicableRegionSet set){
return set.allows(flag);
}
public static ApplicableRegionSet getRegions(Location loc) {
return worldGuard.getGlobalRegionManager().get(loc.getWorld()).getApplicableRegions(BukkitUtil.toVector(loc));
}
private static boolean turnedOn() {
return worldGuard != null && Config.getBoolean(Property.WORLDGUARD_INTEGRATION);
}
private static class ChestShopFlag extends StateFlag {
public ChestShopFlag() {
super("chestshop", false);
}
}
}

View File

@ -1,7 +1,7 @@
package com.Acrobot.ChestShop.Utils;
import com.Acrobot.ChestShop.ChestShop;
import org.bukkit.util.config.Configuration;
import com.Acrobot.ChestShop.Config.ConfigObject;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
@ -9,7 +9,8 @@ import java.io.File;
* @author Acrobot
*/
public class uLongName {
public static Configuration config = new Configuration(new File(ChestShop.folder, "longName.storage"));
public static YamlConfiguration config;
public static File configFile;
public static String getName(final String shortName) {
return config.getString(shortName, shortName);
@ -17,16 +18,11 @@ public class uLongName {
public static void saveName(String name) {
if (name.length() != 16) return;
config.setProperty(name.substring(0, 15), name);
reloadConfig();
config.set(name.substring(0, 15), name);
ConfigObject.reloadConfig(config, configFile);
}
public static String stripName(String name) {
return (name.length() > 15 ? name.substring(0, 15) : name);
}
private static void reloadConfig() {
config.save();
config.load();
}
}

View File

@ -1,18 +0,0 @@
package com.Acrobot.ChestShop.Utils;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Property;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.Location;
/**
* @author Acrobot
*/
public class uWorldGuard {
public static WorldGuardPlugin worldGuard;
public static boolean isNotOutsideWGplot(Location l2) {
return worldGuard == null || !Config.getBoolean(Property.WORLDGUARD_INTEGRATION) || worldGuard.getGlobalRegionManager().get(l2.getWorld()).getApplicableRegions(BukkitUtil.toVector(l2)).size() != 0;
}
}

View File

@ -99,7 +99,7 @@ public class BOSE6 implements Method {
BOSEconomy = (BOSEconomy) plugin;
}
public class BOSEAccount implements MethodAccount {
public static class BOSEAccount implements MethodAccount {
private final String name;
private final BOSEconomy BOSEconomy;
@ -161,7 +161,7 @@ public class BOSE6 implements Method {
}
}
public class BOSEBankAccount implements MethodBankAccount {
public static class BOSEBankAccount implements MethodBankAccount {
private final String bank;
private final BOSEconomy BOSEconomy;

View File

@ -28,7 +28,7 @@ public class EE17 implements Method {
}
public String getVersion() {
return "2.2";
return "2.8.2";
}
public int fractionalDigits() {
@ -102,7 +102,7 @@ public class EE17 implements Method {
Essentials = (Essentials)plugin;
}
public class EEcoAccount implements MethodAccount {
public static class EEcoAccount implements MethodAccount {
private String name;
public EEcoAccount(String name) {

View File

@ -81,7 +81,7 @@ public class MCUR implements Method {
currencyList = (Currency) plugin;
}
public class MCurrencyAccount implements MethodAccount{
public static class MCurrencyAccount implements MethodAccount{
private String name;
public MCurrencyAccount(String name) {

View File

@ -97,7 +97,7 @@ public class iCo4 implements Method {
iConomy = (iConomy)plugin;
}
public class iCoAccount implements MethodAccount {
public static class iCoAccount implements MethodAccount {
private Account account;
public iCoAccount(Account account) {

View File

@ -91,7 +91,7 @@ public class iCo5 implements Method {
iConomy = (iConomy)plugin;
}
public class iCoAccount implements MethodAccount {
public static class iCoAccount implements MethodAccount {
private Account account;
private Holdings holdings;
@ -161,7 +161,7 @@ public class iCo5 implements Method {
}
}
public class iCoBankAccount implements MethodBankAccount {
public static class iCoBankAccount implements MethodBankAccount {
private BankAccount account;
private Holdings holdings;

View File

@ -83,7 +83,7 @@ public class iCo6 implements Method {
iConomy = (iConomy)plugin;
}
public class iCoAccount implements MethodAccount {
public static class iCoAccount implements MethodAccount {
private Account account;
private Holdings holdings;

View File

@ -2,7 +2,7 @@ name: ChestShop
main: com.Acrobot.ChestShop.ChestShop
version: 3.35
version: 3.36
author: Acrobot
@ -10,7 +10,7 @@ description: >
A chest shop for economy plugins.
softdepend: [Permissions, LWC, Lockette, Deadbolt, OddItem, Towny, WorldGuard, Vault, Heroes,
softdepend: [LWC, Lockette, Deadbolt, OddItem, Towny, WorldGuard, Vault, Heroes,
iConomy, BOSEconomy, Essentials, 3co, MultiCurrency, Currency, SimpleChestLock]
commands:
iteminfo:
@ -40,14 +40,21 @@ permissions:
ChestShop.shop.buy: true
ChestShop.shop.sell: true
default: true
ChestShop.shop.create:
description: Allows the user to create a shop that sells and buys any item
children:
ChestShop.shop.create.buy: true
ChestShop.shop.create.sell: true
ChestShop.shop.create.buy:
description: Allows the user to create a shop that sells any item
ChestShop.shop.create.sell:
description: Allows the user to create a shop that buy any item
ChestShop.shop.create.(itemID):
description: Allows user to create a shop that sells item with itemID like in the permission node (replace (itemID) with NUMERICAL item ID)
ChestShop.shop.buy.(itemID):
description: Allows user to buy certain (itemID) from a shop (replace (itemID) with NUMERICAL item ID)
ChestShop.shop.sell.(itemID):
description: Allows user to sell certain (itemID) from a shop (replace (itemID) with NUMERICAL item ID)
ChestShop.shop.create:
description: Allows user to create a shop that sells any item
ChestShop.shop.buy:
description: Allows user to buy from a shop
ChestShop.shop.sell: