mirror of
https://github.com/ChestShop-authors/ChestShop-3.git
synced 2025-02-02 11:31:21 +01:00
- Added selling/buying of Enchanted items
- Modified /iteminfo command to show enchantments (and their id) - Fixed LWC problem - Added an option to ignore creative mode - Fixed broken inventory.addItem(ItemStack) (adds up to custom Material max stack amount now) @Bukkit
This commit is contained in:
parent
353dacf1a0
commit
2e489774d8
@ -10,7 +10,6 @@ import com.Acrobot.ChestShop.DB.Queue;
|
||||
import com.Acrobot.ChestShop.DB.Transaction;
|
||||
import com.Acrobot.ChestShop.Listeners.*;
|
||||
import com.Acrobot.ChestShop.Logging.FileWriterQueue;
|
||||
import com.Acrobot.ChestShop.Protection.MaskChest;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.lennardf1989.bukkitex.Database;
|
||||
import org.bukkit.Server;
|
||||
@ -59,7 +58,8 @@ 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);
|
||||
//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!
|
||||
getCommand("iteminfo").setExecutor(new ItemInfo());
|
||||
|
@ -3,14 +3,19 @@ package com.Acrobot.ChestShop.Commands;
|
||||
import com.Acrobot.ChestShop.Config.Config;
|
||||
import com.Acrobot.ChestShop.Config.Language;
|
||||
import com.Acrobot.ChestShop.Items.Items;
|
||||
import com.Acrobot.ChestShop.Utils.uEnchantment;
|
||||
import com.Acrobot.ChestShop.Utils.uSign;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Acrobot
|
||||
*/
|
||||
@ -21,14 +26,41 @@ public class ItemInfo implements CommandExecutor {
|
||||
if (!(sender instanceof Player)) return false;
|
||||
item = ((Player) sender).getItemInHand();
|
||||
} else {
|
||||
item = Items.getItemStack(args[0]);
|
||||
item = Items.getItemStack(joinArray(args));
|
||||
}
|
||||
|
||||
if (item == null || item.getType() == Material.AIR) return false;
|
||||
|
||||
String durability = (item.getDurability() != 0 ? ChatColor.DARK_GREEN + ":" + item.getDurability() : "");
|
||||
String ench = uEnchantment.getEnchantment(item);
|
||||
String enchantment = (ench != null ? ChatColor.DARK_AQUA + "-" + ench : "");
|
||||
|
||||
sender.sendMessage(Config.getLocal(Language.iteminfo));
|
||||
sender.sendMessage(item.getTypeId() + (item.getDurability() != 0 ? " : " + item.getDurability() : "") + " - " + ChatColor.GRAY + item.getType().name());
|
||||
sender.sendMessage(ChatColor.GRAY + uSign.capitalizeFirst(item.getType().name())
|
||||
+ ChatColor.WHITE + " " + item.getTypeId() + durability + enchantment + ChatColor.WHITE);
|
||||
|
||||
Map<Enchantment, Integer> map = item.getEnchantments();
|
||||
for (Map.Entry<Enchantment, Integer> e : map.entrySet())
|
||||
sender.sendMessage(ChatColor.DARK_GRAY + uSign.capitalizeFirst(e.getKey().getName()) + ' ' + intToRoman(e.getValue()));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private static String intToRoman(int integer){
|
||||
if (integer == 1) return "I";
|
||||
if (integer == 2) return "II";
|
||||
if (integer == 3) return "III";
|
||||
if (integer == 4) return "IV";
|
||||
if (integer == 5) return "V";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String joinArray(String[] array){
|
||||
StringBuilder b = new StringBuilder(array.length);
|
||||
for (String s : array) b.append(s).append(' ');
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ 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!"),
|
||||
//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?"),
|
||||
@ -29,7 +30,8 @@ public enum Property {
|
||||
WORLDGUARD_INTEGRATION(false, "Do you want to only let people build inside plots?"),
|
||||
TAX_AMOUNT(0, "Percent of the price that should go to the server's account. (100 = 100 percent)"),
|
||||
SHOP_REFUND_PRICE(0, "How much money do you get back when destroying a sign?"),
|
||||
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?");
|
||||
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?");
|
||||
|
||||
|
||||
private final Object value;
|
||||
|
@ -1,9 +1,13 @@
|
||||
package com.Acrobot.ChestShop.Items;
|
||||
|
||||
import com.Acrobot.ChestShop.Utils.uEnchantment;
|
||||
import com.Acrobot.ChestShop.Utils.uNumber;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Acrobot
|
||||
* Manages ItemStack names and ID's
|
||||
@ -31,33 +35,42 @@ public class Items {
|
||||
public static ItemStack getItemStack(String itemName) {
|
||||
ItemStack toReturn = getFromOddItem(itemName);
|
||||
if (toReturn != null) return toReturn;
|
||||
|
||||
String[] split = itemName.split(":|-");
|
||||
|
||||
Material material = getMaterial(itemName);
|
||||
if (material != null) return new ItemStack(material, 1);
|
||||
String[] space = split[0].split(" ");
|
||||
Material material = getMaterial(split[0]);
|
||||
|
||||
return getItemStackWithDataValue(itemName);
|
||||
for (int i = (space.length > 1 ? 1 : 0); i >= 0 && material == null; i--) material = getMaterial(space[i]);
|
||||
|
||||
if (material == null) return null;
|
||||
|
||||
toReturn = new ItemStack(material, 1);
|
||||
|
||||
for (int i = 1; i < split.length; i++){
|
||||
split[i] = split[i].trim();
|
||||
if (uNumber.isInteger(split[i])) toReturn.setDurability((short) Integer.parseInt(split[i]));
|
||||
else {
|
||||
try{ toReturn.addEnchantments(getEnchantment(split[i]));
|
||||
} catch (Exception ignored){}
|
||||
}
|
||||
}
|
||||
short data = getDataFromWord(space[0], material);
|
||||
if (data != 0) toReturn.setDurability(data);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private static Map<Enchantment, Integer> getEnchantment(String itemName){
|
||||
return uEnchantment.decodeEnchantment(itemName);
|
||||
}
|
||||
|
||||
private static ItemStack getFromOddItem(String itemName) {
|
||||
return !Odd.isInitialized() ? null : Odd.returnItemStack(itemName.replace(":", ";"));
|
||||
}
|
||||
|
||||
private static ItemStack getItemStackWithDataValue(String itemName) {
|
||||
if (!itemName.contains(":")) return getItemStackWithDataValueFromWord(itemName);
|
||||
|
||||
String[] word = itemName.split(":");
|
||||
if (word.length < 2 || !uNumber.isInteger(word[1])) return null;
|
||||
|
||||
Material item = getMaterial(word[0]);
|
||||
return item == null ? null : new ItemStack(item, 1, Short.parseShort(word[1]));
|
||||
}
|
||||
|
||||
private static ItemStack getItemStackWithDataValueFromWord(String itemName) {
|
||||
int indexOfChar = itemName.indexOf(' ');
|
||||
|
||||
if (indexOfChar == -1) return null;
|
||||
Material item = getMaterial(itemName.substring(indexOfChar));
|
||||
return item == null ? null : new ItemStack(item, 1, DataValue.get(itemName.substring(0, indexOfChar), item));
|
||||
private static short getDataFromWord(String name, Material material) {
|
||||
return DataValue.get(name, material);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import com.Acrobot.ChestShop.Utils.uLongName;
|
||||
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;
|
||||
@ -31,7 +32,7 @@ import java.util.HashMap;
|
||||
public class playerInteract extends PlayerListener {
|
||||
|
||||
private static final HashMap<Player, Long> lastTransactionTime = new HashMap<Player, Long>(); //Last player's transaction
|
||||
private static final int interval = 100;//Minimal interval between transactions
|
||||
public static int interval = 100;//Minimal interval between transactions
|
||||
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
Action action = event.getAction();
|
||||
@ -54,6 +55,11 @@ public class playerInteract extends PlayerListener {
|
||||
|
||||
if (!uSign.isValid(sign) || !enoughTimeHasPassed(player) || player.isSneaking()) return;
|
||||
|
||||
if (Config.getBoolean(Property.IGNORE_CREATIVE_MODE) && player.getGameMode() == GameMode.CREATIVE){
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
lastTransactionTime.put(player, System.currentTimeMillis());
|
||||
|
||||
if (action == Action.RIGHT_CLICK_BLOCK) event.setCancelled(true);
|
||||
|
@ -94,7 +94,6 @@ public class signChange extends BlockListener {
|
||||
dropSign(event);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean canAccess = !Security.isProtected(chestBlock) || Security.canAccess(player, chestBlock);
|
||||
|
||||
if (!canAccess) {
|
||||
@ -150,18 +149,17 @@ public class signChange extends BlockListener {
|
||||
}
|
||||
|
||||
private static String formatFourthLine(String fourthLine, Material material) {
|
||||
String[] split = fourthLine.split(":");
|
||||
if (uNumber.isInteger(split[0])) {
|
||||
String materialLine = material.name();
|
||||
if (split.length == 2) {
|
||||
int maxLength = (14 - split[1].length()); //15 - length - 1
|
||||
if (materialLine.length() > maxLength) materialLine = materialLine.substring(0, maxLength);
|
||||
materialLine = materialLine + ':' + split[1];
|
||||
}
|
||||
fourthLine = materialLine;
|
||||
}
|
||||
fourthLine = fourthLine.replace("_", " ");
|
||||
return fourthLine;
|
||||
int index = (fourthLine.indexOf(':') != -1 ? fourthLine.indexOf(':') : 9999);
|
||||
if (fourthLine.indexOf('-') < index && fourthLine.indexOf('-') != -1) index = fourthLine.indexOf('-');
|
||||
|
||||
StringBuilder toReturn = new StringBuilder(3);
|
||||
String matName = uSign.capitalizeFirst(material.name());
|
||||
if (index != 9999 && matName.length() > (15 - (fourthLine.length() - index))) matName = matName.substring(0, 15 - (fourthLine.length() - index));
|
||||
if (Items.getMaterial(matName) == material) toReturn.append(matName);
|
||||
else toReturn.append(material.getId());
|
||||
|
||||
if (index != -1 && index != 9999) toReturn.append(fourthLine.substring(index));
|
||||
return toReturn.toString();
|
||||
}
|
||||
|
||||
private static boolean formatFirstLine(String line1, Player player) {
|
||||
|
@ -29,7 +29,7 @@ public class Default implements Protection {
|
||||
Chest neighborChest = uBlock.findNeighbor(block);
|
||||
Sign neighborSign = (neighborChest != null ? uBlock.findSign2(neighborChest.getBlock()) : null);
|
||||
|
||||
return neighborSign != null && uLongName.stripName(playerName).equals(neighborSign.getLine(0));
|
||||
return neighborSign == null || uLongName.stripName(playerName).equals(neighborSign.getLine(0));
|
||||
}
|
||||
|
||||
public boolean protect(String name, Block block) {
|
||||
|
41
com/Acrobot/ChestShop/Utils/uEnchantment.java
Normal file
41
com/Acrobot/ChestShop/Utils/uEnchantment.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.Acrobot.ChestShop.Utils;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Acrobot
|
||||
*/
|
||||
public class uEnchantment {
|
||||
public static String getEnchantment(ItemStack item){
|
||||
return encodeEnchantment(item.getEnchantments());
|
||||
}
|
||||
|
||||
public static String encodeEnchantment(Map<Enchantment, Integer> map){
|
||||
int integer = 0;
|
||||
for (Map.Entry<Enchantment, Integer> entry : map.entrySet()){
|
||||
integer = integer * 1000 + (entry.getKey().getId()) * 10 + entry.getValue();
|
||||
}
|
||||
return (integer != 0 ? Integer.toString(integer, 32) : null);
|
||||
}
|
||||
|
||||
public static Map<Enchantment, Integer> decodeEnchantment(String base32){
|
||||
if (base32 == null) return new HashMap<Enchantment, Integer>();
|
||||
Map<Enchantment, Integer> map = new HashMap<Enchantment, Integer>();
|
||||
|
||||
String integer = String.valueOf(Integer.parseInt(base32, 32));
|
||||
|
||||
for (int i = 0; i < (integer.length() / 3); i++){
|
||||
String item = integer.substring(i * 3, i * 3 + 3);
|
||||
Enchantment ench = Enchantment.getById(Integer.parseInt(item.substring(0, 2)));
|
||||
if (ench == null) continue;
|
||||
int level = Integer.parseInt(item.substring(2));
|
||||
if (ench.getMaxLevel() < level || level < ench.getStartLevel()) continue;
|
||||
map.put(ench, level);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ import org.bukkit.Material;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author Acrobot
|
||||
*/
|
||||
@ -26,7 +24,7 @@ public class uInventory {
|
||||
ItemStack currentItem = inv.getItem(slot);
|
||||
if (currentItem == null || currentItem.getType() == Material.AIR) continue;
|
||||
|
||||
if (currentItem.getType() == itemMaterial && (durability == -1 || currentItem.getDurability() == durability)) {
|
||||
if (equals(currentItem, item, durability)) {
|
||||
int currentAmount = currentItem.getAmount();
|
||||
if (amount == currentAmount) {
|
||||
currentItem = null;
|
||||
@ -41,36 +39,53 @@ public class uInventory {
|
||||
inv.setItem(slot, currentItem);
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
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);
|
||||
HashMap<Integer, ItemStack> items = inv.addItem(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;
|
||||
return amount;*/ //TODO: Fix this in CraftBukkit's code
|
||||
|
||||
return addManually(inv, item, amount);
|
||||
}
|
||||
|
||||
private static int addManually(Inventory inv, ItemStack item, int amount) {
|
||||
return addManually(inv, item, amount, item.getType().getMaxStackSize());
|
||||
}
|
||||
|
||||
public static int addAndStackTo64(Inventory inv, ItemStack item, int amount) {
|
||||
Material type = item.getType();
|
||||
for (int slot = 0; slot < inv.getSize(); slot++) {
|
||||
if (amount <= 0) return 0;
|
||||
return addManually(inv, item, amount, 64);
|
||||
}
|
||||
|
||||
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++){
|
||||
ItemStack curItem = inv.getItem(slot);
|
||||
ItemStack dupe = item.clone();
|
||||
|
||||
if (curItem == null || curItem.getType() == Material.AIR) {
|
||||
item.setAmount((amount > 64 ? 64 : amount));
|
||||
amount -= item.getAmount();
|
||||
inv.setItem(slot, item);
|
||||
} else if (curItem.getType() == type && curItem.getDurability() == item.getDurability() && curItem.getAmount() != 64) {
|
||||
int toFill = (64 - curItem.getAmount());
|
||||
item.setAmount((amount > toFill ? 64 : curItem.getAmount() + amount));
|
||||
amount -= item.getAmount();
|
||||
inv.setItem(slot, item);
|
||||
dupe.setAmount((amount > max ? max : amount));
|
||||
dupe.addEnchantments(item.getEnchantments());
|
||||
amount -= dupe.getAmount();
|
||||
inv.setItem(slot, dupe);
|
||||
} else if (equals(item, curItem, item.getDurability()) && curItem.getAmount() != max) {
|
||||
int cA = curItem.getAmount();
|
||||
int amountAdded = amount > max - cA ? max - cA : amount;
|
||||
dupe.setAmount(cA + amountAdded);
|
||||
amount -= amountAdded;
|
||||
dupe.addEnchantments(item.getEnchantments());
|
||||
inv.setItem(slot, dupe);
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
@ -79,14 +94,13 @@ public class uInventory {
|
||||
|
||||
int amount = 0;
|
||||
for (ItemStack i : inv.getContents()) {
|
||||
if (i != null && i.getType() == item.getType() && (durability == -1 || i.getDurability() == durability)) amount += i.getAmount();
|
||||
if (equals(i, item, durability)) amount += i.getAmount();
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
public static int fits(Inventory inv, ItemStack item, int amount, short durability) {
|
||||
Material itemMaterial = item.getType();
|
||||
int maxStackSize = (Config.getBoolean(Property.STACK_UNSTACKABLES) ? 64 : itemMaterial.getMaxStackSize());
|
||||
int maxStackSize = (Config.getBoolean(Property.STACK_UNSTACKABLES) ? 64 : item.getType().getMaxStackSize());
|
||||
int amountLeft = amount;
|
||||
|
||||
for (ItemStack currentItem : inv.getContents()) {
|
||||
@ -99,11 +113,18 @@ public class uInventory {
|
||||
|
||||
int currentAmount = currentItem.getAmount();
|
||||
|
||||
if (currentAmount != maxStackSize && currentItem.getType() == itemMaterial && (durability == -1 || currentItem.getDurability() == durability)) {
|
||||
if (currentAmount != maxStackSize && equals(currentItem, item, durability)) {
|
||||
amountLeft = currentAmount + amountLeft <= maxStackSize ? 0 : amountLeft - (maxStackSize - currentAmount);
|
||||
}
|
||||
}
|
||||
|
||||
return amountLeft;
|
||||
}
|
||||
|
||||
private static boolean equals(ItemStack i, ItemStack item, short durability){
|
||||
return i != null
|
||||
&& i.getType() == item.getType()
|
||||
&& i.getEnchantments().equals(item.getEnchantments())
|
||||
&& (durability == -1 || i.getDurability() == durability);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ public class uSign {
|
||||
Pattern.compile("^$|^\\w.+$"),
|
||||
Pattern.compile("[0-9]+"),
|
||||
Pattern.compile(".+"),
|
||||
Pattern.compile("[\\w :]+")
|
||||
Pattern.compile("[\\w : -]+")
|
||||
};
|
||||
|
||||
public static Towny towny; //Moved this here - somehow, java fails at try/catch
|
||||
@ -82,4 +82,17 @@ public class uSign {
|
||||
return (amount >= 1 ? amount : 1);
|
||||
} else return 1;
|
||||
}
|
||||
|
||||
public static String capitalizeFirst(String name){
|
||||
return capitalizeFirst(name, '_');
|
||||
}
|
||||
|
||||
public static String capitalizeFirst(String name, char separator){
|
||||
name = name.toLowerCase();
|
||||
String[] split = name.split(Character.toString(separator));
|
||||
StringBuilder total = new StringBuilder(3);
|
||||
for (String s : split) total.append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).append(' ');
|
||||
|
||||
return total.toString().trim();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ name: ChestShop
|
||||
|
||||
main: com.Acrobot.ChestShop.ChestShop
|
||||
|
||||
version: 3.29
|
||||
version: 3.30
|
||||
|
||||
|
||||
author: Acrobot
|
||||
|
Loading…
Reference in New Issue
Block a user