- Changed to the new, more robust event system

- Added partial transactions (You have 5 items, shop wants 10 - you can sell your items for half the price)
- Added a warning to the HTML generator
- Fixed Towny integration
- Fixed occasional ArrayOutOfBoundsExceptions
- Fixed an error when a shop couldn't be created because a sign (not shop sign) was on other side of the block
- Added SCL (SimpleChestLock) protection plugin to supported plugins
- Updated Metrics (and added a new asynch thread for startup)
- Removed Bukkit-1.0 workaround
- Fixed plugin.yml formatting
This commit is contained in:
Acrobot 2012-02-16 19:09:37 +01:00
parent c3b084fd1a
commit a49d51ce97
22 changed files with 279 additions and 193 deletions

View File

@ -13,8 +13,6 @@ import com.Acrobot.ChestShop.Logging.FileWriterQueue;
import com.avaje.ebean.EbeanServer;
import com.lennardf1989.bukkitex.Database;
import org.bukkit.Server;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@ -77,24 +75,13 @@ public class ChestShop extends JavaPlugin {
////////////////// REGISTER EVENTS, SCHEDULER & STATS ///////////////////////////
private void registerEvents() {
blockBreak blockBreak = new blockBreak();
registerEvent(Event.Type.BLOCK_BREAK, blockBreak);
registerEvent(Event.Type.BLOCK_PLACE, new blockPlace());
registerEvent(Event.Type.SIGN_CHANGE, new signChange());
registerEvent(Event.Type.PLAYER_INTERACT, new playerInteract(), Event.Priority.Highest);
registerEvent(Event.Type.PLUGIN_ENABLE, new pluginEnable());
if (!Config.getBoolean(Property.USE_BUILT_IN_PROTECTION)) return;
registerEvent(Event.Type.BLOCK_PISTON_EXTEND, blockBreak);
registerEvent(Event.Type.BLOCK_PISTON_RETRACT, blockBreak);
registerEvent(Event.Type.ENTITY_EXPLODE, new entityExplode());
}
private void registerEvent(Event.Type type, Listener listener) {
registerEvent(type, listener, Event.Priority.Normal);
}
private void registerEvent(Event.Type type, Listener listener, Event.Priority priority) {
pm.registerEvent(type, listener, priority, this);
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new blockBreak(), this);
pm.registerEvents(new blockPlace(), this);
pm.registerEvents(new signChange(), this);
pm.registerEvents(new playerInteract(), this);
pm.registerEvents(new entityExplode(), this);
}
private void scheduleTask(Runnable runnable, long startTime, long repetetionTime) {

View File

@ -54,7 +54,7 @@ public class ItemInfo implements CommandExecutor {
if (integer == 3) return "III";
if (integer == 4) return "IV";
if (integer == 5) return "V";
return null;
return Integer.toString(integer);
}

View File

@ -35,7 +35,8 @@ public enum Property {
ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK(false, "Do you want to allow other players to build a shop on a block where there's one already?"),
SHOP_INTERACTION_INTERVAL(100, "(In 1/1000th of a second) How often can a player use a shop sign?"),
HEROES_EXP(100, "How much Heroes exp should people get for creating a ChestShop?"),
BLOCK_UPDATE(false, "EXPERIMENTAL: Should every ChestShop transaction result in a block update?");
BLOCK_UPDATE(false, "EXPERIMENTAL: Should every ChestShop transaction result in a block update?"),
ALLOW_PARTIAL_TRANSACTIONS(true, "Can shops be used even when the seller doesn't have enough items? (The price will be scaled adequatly to the item amount)");
private final Object value;

View File

@ -24,6 +24,7 @@ public class Generator implements Runnable {
private static BufferedWriter buf;
public void run() {
if (row.isEmpty()) System.out.println(ChestShop.chatPrefix + "You lack the necessary HTML files in your plugins/ChestShop/HTML folder!");
generateStats();
}

View File

@ -39,7 +39,7 @@ public class Queue implements Runnable {
.getDB()
.find(Transaction.class)
.where()
.lt("sec", System.currentTimeMillis() / 1000 - Config.getInteger(Property.RECORD_TIME_TO_LIVE))
.lt("sec", (System.currentTimeMillis() / 1000L) - Config.getInteger(Property.RECORD_TIME_TO_LIVE))
.findList();
}
}

View File

@ -41,7 +41,7 @@ public class Economy {
}
public static void subtract(String name, float amount) {
economy.subtract(name, amount);
economy.subtract(uLongName.getName(name), amount);
}
public static boolean hasEnough(String name, float amount) {

View File

@ -50,8 +50,12 @@ public class Items {
public static ItemStack getItemStack(String itemName) {
ItemStack toReturn = getFromOddItem(itemName);
if (toReturn != null) return toReturn;
String first = itemName.split(":|-")[0];
if (itemName == null) itemName = "";
String[] split = itemName.split(":|-");
if (split.length == 0) return null;
String first = split[0];
String[] space = first.split(" ");
Material material = getMaterial(first);

View File

@ -14,8 +14,9 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.material.PistonBaseMaterial;
@ -26,7 +27,7 @@ import java.util.List;
/**
* @author Acrobot
*/
public class blockBreak extends BlockListener {
public class blockBreak implements Listener {
public static boolean cancellingBlockBreak(Block block, Player player) {
if (block == null) return false;
if (player != null && (Permission.has(player, Permission.ADMIN) || Permission.has(player, Permission.MOD))) return false;
@ -55,7 +56,8 @@ public class blockBreak extends BlockListener {
return uBlock.findRestrictedSign(block) != null;
}
public void onBlockBreak(BlockBreakEvent event) {
@EventHandler
public static void onBlockBreak(BlockBreakEvent event) {
if (cancellingBlockBreak(event.getBlock(), event.getPlayer())) event.setCancelled(true);
}
@ -72,7 +74,8 @@ public class blockBreak extends BlockListener {
&& !Permission.otherName(player, sign.getLine(0)));
}
public void onBlockPistonExtend(BlockPistonExtendEvent event) {
@EventHandler
public static void onBlockPistonExtend(BlockPistonExtendEvent event) {
for (Block b : getExtendBlocks(event)) {
if (cancellingBlockBreak(b, null)) {
event.setCancelled(true);
@ -81,7 +84,8 @@ public class blockBreak extends BlockListener {
}
}
public void onBlockPistonRetract(BlockPistonRetractEvent event) {
@EventHandler
public static void onBlockPistonRetract(BlockPistonRetractEvent event) {
if (cancellingBlockBreak(getRetractBlock(event), null)) event.setCancelled(true);
}

View File

@ -9,14 +9,16 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.block.Sign;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
/**
* @author Acrobot
*/
public class blockPlace extends BlockListener {
public void onBlockPlace(BlockPlaceEvent event) {
public class blockPlace implements Listener {
@EventHandler
public static void onBlockPlace(BlockPlaceEvent event) {
Block block = event.getBlockAgainst();
if (uSign.isSign(block) && uSign.isValid((Sign) block.getState())) {
event.setCancelled(true);

View File

@ -1,14 +1,16 @@
package com.Acrobot.ChestShop.Listeners;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityListener;
/**
* @author Acrobot
*/
public class entityExplode extends EntityListener {
public void onEntityExplode(EntityExplodeEvent event) {
public class entityExplode implements Listener {
@EventHandler
public static void onEntityExplode(EntityExplodeEvent event) {
if (event.isCancelled() || event.blockList() == null) return;
for (Block block : event.blockList()) {
if (blockBreak.cancellingBlockBreak(block, null)) {

View File

@ -19,21 +19,24 @@ 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.event.player.PlayerListener;
import java.util.HashMap;
/**
* @author Acrobot
*/
public class playerInteract extends PlayerListener {
public class playerInteract implements Listener {
private static final HashMap<Player, Long> lastTransactionTime = new HashMap<Player, Long>(); //Last player's transaction
public static int interval = 100;//Minimal interval between transactions
public void onPlayerInteract(PlayerInteractEvent event) {
@EventHandler(priority = EventPriority.HIGHEST)
public static void onPlayerInteract(PlayerInteractEvent event) {
Action action = event.getAction();
if (action != Action.LEFT_CLICK_BLOCK && action != Action.RIGHT_CLICK_BLOCK) return;

View File

@ -1,14 +1,12 @@
package com.Acrobot.ChestShop.Listeners;
import com.Acrobot.ChestShop.ChestShop;
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.DeadboltPlugin;
import com.Acrobot.ChestShop.Protection.Plugins.Default;
import com.Acrobot.ChestShop.Protection.Plugins.LWCplugin;
import com.Acrobot.ChestShop.Protection.Plugins.LockettePlugin;
import com.Acrobot.ChestShop.Protection.Plugins.*;
import com.Acrobot.ChestShop.Protection.Security;
import com.Acrobot.ChestShop.Utils.uHeroes;
import com.Acrobot.ChestShop.Utils.uNumber;
@ -22,8 +20,8 @@ import com.nijikokun.register.payment.forChestShop.Method;
import com.nijikokun.register.payment.forChestShop.Methods;
import com.palmergames.bukkit.towny.Towny;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.webkonsept.bukkit.simplechestlock.SCL;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.event.server.ServerListener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.RegisteredServiceProvider;
@ -32,7 +30,7 @@ import org.yi.acru.bukkit.Lockette.Lockette;
/**
* @author Acrobot
*/
public class pluginEnable extends ServerListener {
public class pluginEnable {
public static void initializePlugins() {
Security.protections.add(new Default()); //Initialize basic protection
@ -46,7 +44,10 @@ public class pluginEnable extends ServerListener {
private static void loadRegister(){
if (com.Acrobot.ChestShop.Economy.Economy.economy == null) {
Method m = Methods.load(ChestShop.pm);
if (m == null) return;
if (m == null) {
com.Acrobot.ChestShop.Economy.Economy.economy = new NoProvider();
return;
}
Register.eco = m;
com.Acrobot.ChestShop.Economy.Economy.economy = new Register();
System.out.println(ChestShop.chatPrefix + m.getName() + " loaded.");
@ -66,7 +67,6 @@ public class pluginEnable extends ServerListener {
DeadboltPlugin.deadbolt = (Deadbolt) plugin;
Security.protections.add(new DeadboltPlugin());
} else if (name.equals("OddItem")) {
if (Odd.isInitialized()) return;
if (plugin.getDescription().getVersion().startsWith("0.7")) { System.out.println(generateOutdatedVersion(name, plugin.getDescription().getVersion(), "0.8")); return; }
Odd.isInitialized = true;
} else if (name.equals("Towny")) {
@ -87,6 +87,9 @@ public class pluginEnable extends ServerListener {
return;
} else if (name.equals("Heroes")){
uHeroes.heroes = (Heroes) plugin;
} else if (name.equals("SimpleChestLock")) {
SCLplugin.scl = (SCL) plugin;
Security.protections.add(new SCLplugin());
}
PluginDescriptionFile description = plugin.getDescription();

View File

@ -15,16 +15,18 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.inventory.ItemStack;
/**
* @author Acrobot
*/
public class signChange extends BlockListener {
public class signChange implements Listener {
public void onSignChange(SignChangeEvent event) {
@EventHandler
public static void onSignChange(SignChangeEvent event) {
Block signBlock = event.getBlock();
String[] line = event.getLines();

View File

@ -1,52 +1,40 @@
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 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.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
/**
* Tooling to post to metrics.griefcraft.com
@ -72,6 +60,12 @@ public class Metrics {
*/
public abstract int getValue();
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode() + getValue();
@ -92,7 +86,7 @@ public class Metrics {
/**
* The metrics revision number
*/
private final static int REVISION = 3;
private final static int REVISION = 4;
/**
* The base url of the metrics domain
@ -172,10 +166,20 @@ public class Metrics {
*/
public void beginMeasuringPlugin(final Plugin plugin) throws IOException {
// Did we opt out?
if (configuration.getBoolean("opt-out", false)) return;
if (configuration.getBoolean("opt-out", false)) {
return;
}
// First tell the server about us
postPlugin(plugin, false);
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
plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
@ -183,12 +187,76 @@ public class Metrics {
try {
postPlugin(plugin, true);
} catch (IOException e) {
System.out.println("[ChestShop] There was an error while submitting statistics.");
System.out.println("[Metrics] " + e.getMessage());
}
}
}, PING_INTERVAL * 1200, PING_INTERVAL * 1200);
}
/**
* Generic method that posts a plugin to the metrics website
*
* @param plugin
*/
private void postPlugin(Plugin plugin, boolean isPing) throws IOException {
// 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)));
// If we're pinging, append it
if (isPing) {
data.append(gField("ping", "true"));
}
// Add any custom data (if applicable)
Set<Plotter> plotters = customData.get(plugin);
if (plotters != null) {
for (Plotter plotter : plotters) {
data.append(gField("Custom" + plotter.getColumnName(), Integer.toString(plotter.getValue())));
}
}
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, plugin.getDescription().getName()));
// Connect to the website
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
// Write the data
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data.toString());
writer.flush();
// Now read the response
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
response = reader.readLine();
// close resources
writer.close();
reader.close();
if (response.startsWith("ERR")) {
throw new IOException(response); //Throw the exception
} 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();
}
}
}
}
//if (response.startsWith("OK")) - We should get "OK" followed by an optional description if everything goes right
}
/**
* Generates a field
* @param name Field name
@ -200,56 +268,6 @@ public class Metrics {
return '&' + encode(name) + '=' + encode(data);
}
/**
* Generic method that posts a plugin to the metrics website
*
* @param plugin
*/
private void postPlugin(Plugin plugin, boolean isPing) throws IOException {
// Construct the post data
String response = "ERR No response";
String data = encode("guid") + '=' + encode(guid)
+ gField("version", plugin.getDescription().getVersion())
+ gField("server", Bukkit.getVersion())
+ gField("players", String.valueOf(Bukkit.getServer().getOnlinePlayers().length))
+ gField("revision", String.valueOf(REVISION));
// If we're pinging, append it
if (isPing) {
data += gField("ping", "true");
}
// Add any custom data (if applicable)
Set<Plotter> plotters = customData.get(plugin);
if (plotters != null) {
for (Plotter plotter : plotters) {
data += gField("Custom" + plotter.getColumnName(), Integer.toString(plotter.getValue()));
}
}
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, plugin.getDescription().getName()));
// Connect to the website
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
// Write the data
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data);
writer.flush();
// Now read the response
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
response = reader.readLine();
// close resources
writer.close();
reader.close();
if (response.startsWith("ERR")) throw new IOException(response);
}
/**
* Encode text as UTF-8
*

View File

@ -0,0 +1,25 @@
package com.Acrobot.ChestShop.Protection.Plugins;
import com.Acrobot.ChestShop.Protection.Protection;
import com.webkonsept.bukkit.simplechestlock.SCL;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
/**
* @author Acrobot
*/
public class SCLplugin implements Protection {
public static SCL scl;
public boolean isProtected(Block block) {
return scl.chests.isLocked(block);
}
public boolean canAccess(Player player, Block block) {
return scl.chests.getOwner(block).equalsIgnoreCase(player.getName());
}
public boolean protect(String name, Block block) {
return false;
}
}

View File

@ -42,7 +42,7 @@ public class Security {
private static boolean thereIsAnotherSignByPlayer(Block baseBlock, Block signBlock, String shortName) {
for (BlockFace bf : faces) {
Block block = baseBlock.getRelative(bf);
if (uSign.isSign(block) && !block.equals(signBlock) && blockBreak.getAttachedFace((Sign) block.getState()).equals(baseBlock) && !((Sign) block.getState()).getLine(0).equals(shortName))
if (uSign.isSign(block) && uSign.isValid((Sign) block.getState()) && !block.equals(signBlock) && blockBreak.getAttachedFace((Sign) block.getState()).equals(baseBlock) && !((Sign) block.getState()).getLine(0).equals(shortName))
return true;
}
return false;

View File

@ -23,9 +23,9 @@ public class Shop {
private final ChestObject chest;
public final ItemStack stock;
public final int stockAmount;
public final float buyPrice;
public final float sellPrice;
public int stockAmount;
public float buyPrice;
public float sellPrice;
public final String owner;
private final Sign sign;
@ -55,8 +55,14 @@ public class Shop {
}
String playerName = player.getName();
if (!Economy.hasEnough(playerName, buyPrice)) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_MONEY));
return;
int items = calculateItemAmount(Economy.balance(playerName), true);
if (!Config.getBoolean(Property.ALLOW_PARTIAL_TRANSACTIONS) || items < 1) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_MONEY));
return;
} else {
buyPrice = (buyPrice / stockAmount) * items;
stockAmount = items;
}
}
if (!stockFitsPlayer(player)) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_SPACE_IN_INVENTORY));
@ -66,10 +72,17 @@ public class Shop {
String materialName = stock.getType().name();
if (!isAdminShop() && !hasEnoughStock()) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_STOCK));
if (!Config.getBoolean(Property.SHOW_MESSAGE_OUT_OF_STOCK)) return;
sendMessageToOwner(Config.getLocal(Language.NOT_ENOUGH_STOCK_IN_YOUR_SHOP).replace("%material", materialName));
return;
int items = stockAmount(stock, durability);
if (!Config.getBoolean(Property.ALLOW_PARTIAL_TRANSACTIONS) || items < 1) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_STOCK));
if (!Config.getBoolean(Property.SHOW_MESSAGE_OUT_OF_STOCK)) return;
sendMessageToOwner(Config.getLocal(Language.NOT_ENOUGH_STOCK_IN_YOUR_SHOP).replace("%material", materialName));
return;
} else {
buyPrice = (buyPrice / stockAmount) * items;
stockAmount = items;
}
}
String account = getOwnerAccount();
@ -102,7 +115,7 @@ public class Shop {
.replace("%buyer", playerName)
.replace("%price", formatedPrice));
}
if (Config.getBoolean(Property.BLOCK_UPDATE)) uBlock.blockUpdate(sign.getBlock());
}
@ -124,20 +137,31 @@ public class Shop {
boolean accountExists = !account.isEmpty() && Economy.hasAccount(account);
if (accountExists && !Economy.hasEnough(account, sellPrice)) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_MONEY_SHOP));
return;
int items = calculateItemAmount(Economy.balance(account), false);
if (!Config.getBoolean(Property.ALLOW_PARTIAL_TRANSACTIONS) || items < 1) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_MONEY_SHOP));
return;
} else {
sellPrice = (sellPrice / stockAmount) * items;
stockAmount = items;
}
}
if (uInventory.amount(player.getInventory(), stock, durability) < stockAmount) {
int items = uInventory.amount(player.getInventory(), stock, durability);
if (!Config.getBoolean(Property.ALLOW_PARTIAL_TRANSACTIONS) || items < 1) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_ITEMS_TO_SELL));
return;
} else {
sellPrice = (sellPrice / stockAmount) * items;
stockAmount = items;
}
}
if (!isAdminShop() && !stockFitsChest(chest)) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_SPACE_IN_CHEST));
return;
}
if (uInventory.amount(player.getInventory(), stock, durability) < stockAmount) {
player.sendMessage(Config.getLocal(Language.NOT_ENOUGH_ITEMS_TO_SELL));
return;
}
if (accountExists) Economy.subtract(account, sellPrice);
if (!isAdminShop()) chest.addItem(stock, stockAmount);
@ -180,6 +204,10 @@ public class Shop {
private boolean hasEnoughStock() {
return chest.hasEnough(stock, stockAmount, durability);
}
private int stockAmount(ItemStack item, short durability){
return chest.amount(item, durability);
}
private boolean stockFitsPlayer(Player player) {
return uInventory.fits(player.getInventory(), stock, stockAmount, durability) <= 0;
@ -189,6 +217,10 @@ public class Shop {
return chest.fits(stock, stockAmount, durability);
}
private int calculateItemAmount(double money, boolean buy) {
return (int) Math.floor(money / ((buy ? buyPrice : sellPrice) / stockAmount));
}
private void sendMessageToOwner(String msg) {
if (!isAdminShop()) {
Player player = ChestShop.getBukkitServer().getPlayer(owner);

View File

@ -6,6 +6,8 @@ import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
/**
* @author Acrobot
*/
@ -45,29 +47,24 @@ public class uInventory {
public static int add(Inventory inv, ItemStack item, int amount) {
amount = (amount > 0 ? amount : 1);
if (Config.getBoolean(Property.STACK_UNSTACKABLES)) return addAndStackTo64(inv, item, amount);
/*ItemStack itemstack = new ItemStack(item.getType(), amount, item.getDurability());
ItemStack itemstack = new ItemStack(item.getType(), amount, item.getDurability());
itemstack.addEnchantments(item.getEnchantments());
HashMap<Integer, ItemStack> items = inv.addItem(itemstack);
amount = 0;
for (ItemStack toAdd : items.values()) amount += toAdd.getAmount();
return amount;*/ //TODO: revert when Bukkit releases new RB
return addManually(inv, item, amount);
}
private static int addManually(Inventory inv, ItemStack item, int amount) {
return addManually(inv, item, amount, (item.getType() != Material.POTION ? item.getType().getMaxStackSize() : 1)); //TODO Change it when it's repaired in Bukkit
return amount;
}
public static int addAndStackTo64(Inventory inv, ItemStack item, int amount) {
return addManually(inv, item, amount, 64);
}
public static int addManually(Inventory inv, ItemStack item, int amount, int max){
public static int addManually(Inventory inv, ItemStack item, int amount, int max) {
if (amount <= 0) return 0;
for (int slot = 0; slot < inv.getSize() && amount > 0; slot++){
for (int slot = 0; slot < inv.getSize() && amount > 0; slot++) {
ItemStack curItem = inv.getItem(slot);
ItemStack dupe = item.clone();
@ -101,7 +98,6 @@ public class uInventory {
public static int fits(Inventory inv, ItemStack item, int amount, short durability) {
int maxStackSize = (Config.getBoolean(Property.STACK_UNSTACKABLES) ? 64 : item.getType().getMaxStackSize());
if (item.getType() == Material.POTION) maxStackSize = 1; //TODO Bukkit, can you fix that?
int amountLeft = amount;
@ -122,8 +118,8 @@ public class uInventory {
return amountLeft;
}
private static boolean equals(ItemStack i, ItemStack item, short durability){
private static boolean equals(ItemStack i, ItemStack item, short durability) {
return i != null
&& i.getType() == item.getType()
&& i.getEnchantments().equals(item.getEnchantments())

View File

@ -10,7 +10,7 @@ public class uNumber {
try {
Integer.parseInt(string);
return true;
} catch (Exception e) {
} catch (NumberFormatException e) {
return false;
}
}
@ -19,7 +19,7 @@ public class uNumber {
try {
Float.parseFloat(string);
return true;
} catch (Exception e) {
} catch (NumberFormatException e) {
return false;
}
}
@ -28,7 +28,7 @@ public class uNumber {
try {
Double.parseDouble(string);
return true;
} catch (Exception e) {
} catch (NumberFormatException e) {
return false;
}
}

View File

@ -5,6 +5,7 @@ import com.Acrobot.ChestShop.Config.Property;
import com.palmergames.bukkit.towny.NotRegisteredException;
import com.palmergames.bukkit.towny.object.TownBlockType;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -21,12 +22,16 @@ public class uTowny {
return isResident(player, chestLocation) && isResident(player, signLocation);
}
public static boolean isNotInTheWilderness(Location chestLocation, Location signLocation) {
return !uSign.towny.getTownyUniverse().isWilderness(chestLocation.getBlock()) && !uSign.towny.getTownyUniverse().isWilderness(signLocation.getBlock());
public static boolean isInWilderness(Location chestLocation, Location signLocation) {
return isInWilderness(chestLocation.getBlock()) || isInWilderness(signLocation.getBlock());
}
private static boolean isInWilderness(Block block){
return uSign.towny.getTownyUniverse().isWilderness(block);
}
public static boolean canBuild(Player player, Location chestLocation, Location signLocation) {
return uSign.towny == null || !Config.getBoolean(Property.TOWNY_INTEGRATION) || (isNotInTheWilderness(chestLocation, signLocation) && isInsideShopPlot(chestLocation, signLocation) && isPlotOwner(player, chestLocation, signLocation));
return uSign.towny == null || !Config.getBoolean(Property.TOWNY_INTEGRATION) || (!isInWilderness(chestLocation, signLocation) && isInsideShopPlot(chestLocation, signLocation) && isPlotOwner(player, chestLocation, signLocation));
}
private static boolean isBlockOwner(Player player, Location location) {

View File

@ -75,7 +75,7 @@ public class BOSE7 implements Method {
}
public MethodAccount getAccount(String name) {
if(!hasAccount(name))
if(!hasAccount(name))
return null;
return new BOSEAccount(name, this.BOSEconomy);
@ -98,7 +98,7 @@ public class BOSE7 implements Method {
BOSEconomy = (BOSEconomy)plugin;
}
public class BOSEAccount implements MethodAccount {
public static class BOSEAccount implements MethodAccount {
private String name;
private BOSEconomy BOSEconomy;
@ -155,7 +155,7 @@ public class BOSE7 implements Method {
}
}
public class BOSEBankAccount implements MethodBankAccount, MethodAccount {
public static class BOSEBankAccount implements MethodBankAccount, MethodAccount {
private String bank;
private BOSEconomy BOSEconomy;

View File

@ -2,7 +2,7 @@ name: ChestShop
main: com.Acrobot.ChestShop.ChestShop
version: 3.34
version: 3.35
author: Acrobot
@ -10,7 +10,8 @@ description: >
A chest shop for economy plugins.
softdepend: [Permissions, LWC, Lockette, Deadbolt, OddItem, Towny, WorldGuard, Vault, Heroes]
softdepend: [Permissions, LWC, Lockette, Deadbolt, OddItem, Towny, WorldGuard, Vault, Heroes,
iConomy, BOSEconomy, Essentials, 3co, MultiCurrency, Currency, SimpleChestLock]
commands:
iteminfo:
aliases: [iinfo]
@ -106,7 +107,7 @@ permissions:
ChestShop.shop.create.292: true #IronHoe
ChestShop.shop.create.goldgrade:
description: Allows to create a shop that sells gold gear
children:
children:
ChestShop.shop.create.314: true #GoldHelm
ChestShop.shop.create.315: true #GoldChestplate
ChestShop.shop.create.316: true #GoldLeggings
@ -118,7 +119,7 @@ permissions:
ChestShop.shop.create.294: true #GoldHoe
ChestShop.shop.create.stonegrade:
description: Allows to create a shop that sells stone tools and chain armor
children:
children:
ChestShop.shop.create.302: true #ChainHelm
ChestShop.shop.create.303: true #ChainChestplate
ChestShop.shop.create.304: true #ChainLeggings
@ -130,7 +131,7 @@ permissions:
ChestShop.shop.create.291: true #StoneHoe
ChestShop.shop.create.woodgrade:
description: Allows to create a shop that sells wood tools and leather armor
children:
children:
ChestShop.shop.create.298: true #LeatherHelm
ChestShop.shop.create.299: true #LeatherChestplate
ChestShop.shop.create.300: true #LeatherLeggings