mirror of
https://e.coding.net/circlecloud/QuickShop.git
synced 2025-10-02 12:37:27 +00:00
Compare commits
128 Commits
Author | SHA1 | Date | |
---|---|---|---|
8edb488ab2 | |||
686dc054de | |||
72d3e24b8a | |||
0948887e4b | |||
82c2591c9b | |||
a11686a839 | |||
de3fa516e1 | |||
2b82a8430d | |||
4a18053026 | |||
d768f93c6c | |||
ccedc8cfea | |||
7a74e88cd1 | |||
4b41bdff57 | |||
4f3ee83b47 | |||
1a624a8384 | |||
1b519fe90f | |||
c193f2bc95 | |||
5dd8dd78af | |||
e42701f376 | |||
55cd9e386c | |||
ea61beb719 | |||
bd2c2aedf9 | |||
664e5c7734 | |||
979efda24b | |||
5cb710c00f | |||
20dd524044 | |||
8916dc0d53 | |||
833fe1ac43 | |||
b3995f3b2f | |||
dec12d75cb | |||
ec2498fc48 | |||
36dd2ac988 | |||
b90049aad7 | |||
3c5e4c2cf6 | |||
49c0b8ecd7 | |||
b110da8f73 | |||
16571a6035 | |||
00f6466061 | |||
fce1e797b9 | |||
219bbb5539 | |||
9c12bb5f91 | |||
0c9a014c13 | |||
db7e6c0f4c | |||
923abada16 | |||
2131ee1746 | |||
9fce7de6b4 | |||
b10c601ce7 | |||
665d6d77d1 | |||
9a5b3cb09f | |||
bbea4b57f8 | |||
e3223aa25f | |||
e0de9dbe30 | |||
6dae73e6b7 | |||
abe7fd3412 | |||
918c329b2c | |||
c2ac919c40 | |||
44ec03bd30 | |||
43c6c7a0ef | |||
c05dd7ea0f | |||
a0e826f8fc | |||
75f21b43f4 | |||
79c5036384 | |||
365125674f | |||
671932e34b | |||
70ba973a9b | |||
ad95e07c94 | |||
a8f0fe2600 | |||
4ab5a1aa67 | |||
82f6c99c01 | |||
9669c6cc8e | |||
764f8a8446 | |||
abc81b93ed | |||
f8888f5c9f | |||
0284355c87 | |||
f91a647dd8 | |||
b00e35dc17 | |||
062534af1f | |||
56503fee2b | |||
c6f51981fd | |||
ceeeb5802c | |||
79ea58412a | |||
86d0eb796e | |||
1a93f43afe | |||
1934b5748c | |||
2397e33d35 | |||
8c26cd6fa4 | |||
00349aecae | |||
62bfb22bec | |||
fba0fbab53 | |||
4bb7e63266 | |||
56fd3f20ed | |||
f64af66f09 | |||
a6b810e140 | |||
ddb78cf045 | |||
c9a527b04a | |||
f09901f0b5 | |||
ab54e56821 | |||
8aa88ddfef | |||
2467855766 | |||
a0f4846fd1 | |||
5fa9ec9142 | |||
a98acb58de | |||
d5f7f5d429 | |||
70cba23dc8 | |||
0de3e1a0c7 | |||
f2c7c9c2b1 | |||
f89f58ba40 | |||
d8e8678d31 | |||
b4623befa9 | |||
a545a62ef0 | |||
31db322e36 | |||
1d951ac2bd | |||
bcf33b9133 | |||
56e0fd8430 | |||
fa9eead0a9 | |||
6ed44b3def | |||
5b6abc1c07 | |||
7d908ff59a | |||
c83ace24c9 | |||
b409fcc32f | |||
714ce2fa32 | |||
7f1c37ec4e | |||
3f781c473c | |||
5bab17a117 | |||
b9a9fe292c | |||
efb4e18617 | |||
f807c054d4 | |||
037f5138bb |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,4 @@
|
|||||||
# Eclipse stuff
|
# Eclipse stuff
|
||||||
/.classpath
|
|
||||||
/.project
|
|
||||||
/.settings
|
/.settings
|
||||||
|
|
||||||
# netbeans
|
# netbeans
|
||||||
|
BIN
lib/Vault.jar
BIN
lib/Vault.jar
Binary file not shown.
Binary file not shown.
108
pom.xml
108
pom.xml
@ -3,7 +3,8 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.maxgamer</groupId>
|
<groupId>org.maxgamer</groupId>
|
||||||
<artifactId>QuickShop</artifactId>
|
<artifactId>QuickShop</artifactId>
|
||||||
<version>1.4</version>
|
<version>2.3.1</version>
|
||||||
|
<description>快捷商店重置版本...</description>
|
||||||
<build>
|
<build>
|
||||||
<finalName>${project.name}</finalName>
|
<finalName>${project.name}</finalName>
|
||||||
<resources>
|
<resources>
|
||||||
@ -13,34 +14,21 @@
|
|||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<source>1.7</source>
|
|
||||||
<target>1.7</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.3</version>
|
<version>2.4.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
<minimizeJar>true</minimizeJar>
|
<minimizeJar>true</minimizeJar>
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<includes>
|
<includes>
|
||||||
<include>cn.citycraft:PluginHelper</include>
|
<include>pw.yumc:YumCore</include>
|
||||||
<include>org.mcstats.*:*</include>
|
|
||||||
</includes>
|
</includes>
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
<relocations>
|
<relocations>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>org.mcstats</pattern>
|
<pattern>pw.yumc.YumCore</pattern>
|
||||||
<shadedPattern>${project.groupId}.${project.artifactId}.mcstats</shadedPattern>
|
|
||||||
</relocation>
|
|
||||||
<relocation>
|
|
||||||
<pattern>cn.citycraft.PluginHelper</pattern>
|
|
||||||
<shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern>
|
<shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
@ -56,55 +44,57 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<ciManagement>
|
||||||
|
<system>Jenkins</system>
|
||||||
|
<url>http://ci.yumc.pw/job/${project.artifactId}/</url>
|
||||||
|
</ciManagement>
|
||||||
|
<properties>
|
||||||
|
<env.GIT_COMMIT>DEBUG</env.GIT_COMMIT>
|
||||||
|
<update.description>§a全新版本 §c修复大量问题§e(有问题找jiongjiong)...</update.description>
|
||||||
|
<update.changes>
|
||||||
|
§b2.3.1 - §cfix: 修复低版本服务端不兼容的问题;
|
||||||
|
§b2.3.0 - §afeat: 修复大量BUG(感谢jiongjiong提交的PR 下面都是他修复的);
|
||||||
|
§b - §cfix: 修复不必要的获取离线玩家导致创建大量getProfile线程导致服务端崩溃的问题;
|
||||||
|
§b - §cfix: 连接池线程安全修正;
|
||||||
|
§b - §cfix: 让修改价格等行为异步操作数据库;
|
||||||
|
§b - §cfix: 异步调用数据库删除方法(BlockBreakEvent触发);
|
||||||
|
§b - §cfix: 异步保存商店到数据库;
|
||||||
|
§b - §cfix: 修复收购商店不触发ShopPurchaseEvent的问题,并且调整触发的时机,避免没钱购买也触发这个事件;
|
||||||
|
§b - §cfix: 修复一些奇怪的问题;
|
||||||
|
§b - §cfix: 修复一处线程安全问题;
|
||||||
|
§b - §cfix: 修复匹配两个物品是否相同的问题;
|
||||||
|
§b - §cfix: 删除不必要的监听器
|
||||||
|
</update.changes>
|
||||||
|
<update.changelog>
|
||||||
|
§b2.2.0 - §cfix: 修复 1.12 不兼容的问题;
|
||||||
|
§b2.1.2 - §e移除过期的监听方法...;
|
||||||
|
§b2.1.0 - §c修复大箱子刷物品的问题...;
|
||||||
|
§b2.0.1 - §a使用新类库 兼容最新版本...;
|
||||||
|
§b1.9.5 - §a1.10+兼容虚拟悬浮物...;
|
||||||
|
</update.changelog>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-repo</id>
|
<id>yumc-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
<url>https://repo.yumc.pw/repository/maven-public/</url>
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>sumcraft-repo</id>
|
|
||||||
<url>http://ci.sumcraft.net:8080/plugin/repository/everything/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>Plugin Metrics</id>
|
|
||||||
<url>http://repo.mcstats.org/content/repositories/public</url>
|
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>jtb</id>
|
||||||
|
<name>YUMC</name>
|
||||||
|
<url>https://repo.yumc.pw/repository/yumcenter/</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>pw.yumc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>YumCore</artifactId>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
<version>[1.8.1,)</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.milkbowl.vault</groupId>
|
|
||||||
<artifactId>VaultAPI</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
<scope>system</scope>
|
|
||||||
<systemPath>${project.basedir}/lib/Vault.jar</systemPath>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sk89q</groupId>
|
|
||||||
<artifactId>WorldEdit</artifactId>
|
|
||||||
<version>5.4.5</version>
|
|
||||||
<scope>system</scope>
|
|
||||||
<systemPath>${project.basedir}/lib/WorldEdit.jar</systemPath>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.citycraft</groupId>
|
|
||||||
<artifactId>PluginHelper</artifactId>
|
|
||||||
<type>jar</type>
|
|
||||||
<version>1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mcstats.bukkit</groupId>
|
|
||||||
<artifactId>metrics</artifactId>
|
|
||||||
<version>R8-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
</project>
|
</project>
|
@ -1,45 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ShopType;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandBuy extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandBuy(final QuickShop plugin) {
|
|
||||||
super("buy");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.create.buy");
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setDescription(MsgUtil.p("command.description.buy"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null && shop.getOwner().equals(((Player) sender).getName())) {
|
|
||||||
shop.setShopType(ShopType.BUYING);
|
|
||||||
shop.setSignText();
|
|
||||||
shop.update();
|
|
||||||
sender.sendMessage(MsgUtil.p("command.now-buying", shop.getDataName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandClean extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandClean(final QuickShop plugin) {
|
|
||||||
super("clean");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.clean");
|
|
||||||
setDescription(MsgUtil.p("command.description.clean"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
sender.sendMessage(MsgUtil.p("command.cleaning"));
|
|
||||||
final Iterator<Shop> shIt = plugin.getShopManager().getShopIterator();
|
|
||||||
int i = 0;
|
|
||||||
while (shIt.hasNext()) {
|
|
||||||
final Shop shop = shIt.next();
|
|
||||||
try {
|
|
||||||
if (shop.getLocation().getWorld() != null && shop.isSelling() && shop.getRemainingStock() == 0 && shop instanceof ContainerShop) {
|
|
||||||
final ContainerShop cs = (ContainerShop) shop;
|
|
||||||
if (cs.isDoubleShop()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
shIt.remove(); // Is selling, but has no stock, and is a chest shop, but is not a double shop. Can be deleted safely.
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
} catch (final IllegalStateException e) {
|
|
||||||
// shIt.remove(); // The shop is not there anymore, remove it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MsgUtil.clean();
|
|
||||||
sender.sendMessage(MsgUtil.p("command.cleaned", "" + i));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandEmpty extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandEmpty(final QuickShop plugin) {
|
|
||||||
super("empty");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.refill");
|
|
||||||
setDescription(MsgUtil.p("command.description.empty"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null) {
|
|
||||||
if (shop instanceof ContainerShop) {
|
|
||||||
final ContainerShop cs = (ContainerShop) shop;
|
|
||||||
cs.getInventory().clear();
|
|
||||||
sender.sendMessage(MsgUtil.p("empty-success"));
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Database.Database;
|
|
||||||
import org.maxgamer.QuickShop.Database.MySQLCore;
|
|
||||||
import org.maxgamer.QuickShop.Database.SQLiteCore;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandExport extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandExport(final QuickShop plugin) {
|
|
||||||
super("export");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.export");
|
|
||||||
setMinimumArguments(1);
|
|
||||||
setPossibleArguments("[mysql|sqlite]");
|
|
||||||
setDescription(MsgUtil.p("command.description.export"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final String type = args[0].toLowerCase();
|
|
||||||
if (type.startsWith("mysql")) {
|
|
||||||
if (plugin.getDB().getCore() instanceof MySQLCore) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "数据已保存在 MySQL 无需转换!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ConfigurationSection cfg = plugin.getConfig().getConfigurationSection("database");
|
|
||||||
final String host = cfg.getString("host");
|
|
||||||
final String port = cfg.getString("port");
|
|
||||||
final String user = cfg.getString("user");
|
|
||||||
final String pass = cfg.getString("password");
|
|
||||||
final String name = cfg.getString("database");
|
|
||||||
final MySQLCore core = new MySQLCore(host, user, pass, name, port);
|
|
||||||
Database target;
|
|
||||||
try {
|
|
||||||
target = new Database(core);
|
|
||||||
QuickShop.instance.getDB().copyTo(target);
|
|
||||||
sender.sendMessage(ChatColor.GREEN + "导出成功 - 数据已保存至 MySQL " + user + "@" + host + "." + name);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
sender.sendMessage(ChatColor.RED + "导出数据到 MySQL 失败 " + user + "@" + host + "." + name + ChatColor.DARK_RED + " 由于: " + e.getMessage());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (type.startsWith("sql") || type.contains("file")) {
|
|
||||||
if (plugin.getDB().getCore() instanceof SQLiteCore) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "数据已保存在 SQLite 无需转换!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final File file = new File(plugin.getDataFolder(), "shops.db");
|
|
||||||
if (file.exists()) {
|
|
||||||
if (file.delete() == false) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "警告: 删除旧的数据文件 shops.db 失败. 可能会导致部分信息错误.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final SQLiteCore core = new SQLiteCore(file);
|
|
||||||
try {
|
|
||||||
final Database target = new Database(core);
|
|
||||||
QuickShop.instance.getDB().copyTo(target);
|
|
||||||
sender.sendMessage(ChatColor.GREEN + "导出成功 - 数据已保存至 SQLite: " + file.toString());
|
|
||||||
} catch (final Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
sender.sendMessage(ChatColor.RED + "导出数据到 SQLite: " + file.toString() + " 失败 由于: " + e.getMessage());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
import cn.citycraft.PluginHelper.utils.StringUtil;
|
|
||||||
|
|
||||||
public class CommandFind extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandFind(final QuickShop plugin) {
|
|
||||||
super("find");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setMinimumArguments(2);
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setPermission("quickshop.find");
|
|
||||||
setDescription(MsgUtil.p("command.description.find"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
String lookFor = StringUtil.consolidateStrings(args, 0);
|
|
||||||
lookFor = lookFor.toLowerCase();
|
|
||||||
final Player p = (Player) sender;
|
|
||||||
final Location loc = p.getEyeLocation().clone();
|
|
||||||
final double minDistance = plugin.getConfig().getInt("shop.find-distance");
|
|
||||||
double minDistanceSquared = minDistance * minDistance;
|
|
||||||
final int chunkRadius = (int) minDistance / 16 + 1;
|
|
||||||
Shop closest = null;
|
|
||||||
final Chunk c = loc.getChunk();
|
|
||||||
for (int x = -chunkRadius + c.getX(); x < chunkRadius + c.getX(); x++) {
|
|
||||||
for (int z = -chunkRadius + c.getZ(); z < chunkRadius + c.getZ(); z++) {
|
|
||||||
final Chunk d = c.getWorld().getChunkAt(x, z);
|
|
||||||
final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(d);
|
|
||||||
if (inChunk == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (final Shop shop : inChunk.values()) {
|
|
||||||
if (shop.getDataName().toLowerCase().contains(lookFor) && shop.getLocation().distanceSquared(loc) < minDistanceSquared) {
|
|
||||||
closest = shop;
|
|
||||||
minDistanceSquared = shop.getLocation().distanceSquared(loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (closest == null) {
|
|
||||||
sender.sendMessage(MsgUtil.p("no-nearby-shop", args[0]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Location lookat = closest.getLocation().clone().add(0.5, 0.5, 0.5);
|
|
||||||
// Hack fix to make /qs find not used by /back
|
|
||||||
p.teleport(this.lookAt(loc, lookat).add(0, -1.62, 0), TeleportCause.PLUGIN);
|
|
||||||
p.sendMessage(MsgUtil.p("nearby-shop-this-way", "" + (int) Math.floor(Math.sqrt(minDistanceSquared))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns loc with modified pitch/yaw angles so it faces lookat
|
|
||||||
*
|
|
||||||
* @param loc
|
|
||||||
* The location a players head is
|
|
||||||
* @param lookat
|
|
||||||
* The location they should be looking
|
|
||||||
* @return The location the player should be facing to have their crosshairs
|
|
||||||
* on the location lookAt Kudos to bergerkiller for most of this
|
|
||||||
* function
|
|
||||||
*/
|
|
||||||
public Location lookAt(Location loc, final Location lookat) {
|
|
||||||
// Clone the loc to prevent applied changes to the input loc
|
|
||||||
loc = loc.clone();
|
|
||||||
// Values of change in distance (make it relative)
|
|
||||||
final double dx = lookat.getX() - loc.getX();
|
|
||||||
final double dy = lookat.getY() - loc.getY();
|
|
||||||
final double dz = lookat.getZ() - loc.getZ();
|
|
||||||
// Set yaw
|
|
||||||
if (dx != 0) {
|
|
||||||
// Set yaw start value based on dx
|
|
||||||
if (dx < 0) {
|
|
||||||
loc.setYaw((float) (1.5 * Math.PI));
|
|
||||||
} else {
|
|
||||||
loc.setYaw((float) (0.5 * Math.PI));
|
|
||||||
}
|
|
||||||
loc.setYaw(loc.getYaw() - (float) Math.atan(dz / dx));
|
|
||||||
} else if (dz < 0) {
|
|
||||||
loc.setYaw((float) Math.PI);
|
|
||||||
}
|
|
||||||
// Get the distance from dx/dz
|
|
||||||
final double dxz = Math.sqrt(Math.pow(dx, 2) + Math.pow(dz, 2));
|
|
||||||
final float pitch = (float) -Math.atan(dy / dxz);
|
|
||||||
// Set values, convert to degrees
|
|
||||||
// Minecraft yaw (vertical) angles are inverted (negative)
|
|
||||||
loc.setYaw(-loc.getYaw() * 180f / (float) Math.PI + 360);
|
|
||||||
// But pitch angles are normal
|
|
||||||
loc.setPitch(pitch * 180f / (float) Math.PI);
|
|
||||||
return loc;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ShopChunk;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandInfo extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandInfo(final QuickShop plugin) {
|
|
||||||
super("info");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.info");
|
|
||||||
setDescription(MsgUtil.p("command.description.info"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
int buying, selling, doubles, chunks, worlds;
|
|
||||||
buying = selling = doubles = chunks = worlds = 0;
|
|
||||||
int nostock = 0;
|
|
||||||
sender.sendMessage(ChatColor.RED + "开始检索商店信息中...");
|
|
||||||
for (final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld : plugin.getShopManager().getShops().values()) {
|
|
||||||
worlds++;
|
|
||||||
for (final HashMap<Location, Shop> inChunk : inWorld.values()) {
|
|
||||||
chunks++;
|
|
||||||
for (final Shop shop : inChunk.values()) {
|
|
||||||
if (shop.isBuying()) {
|
|
||||||
buying++;
|
|
||||||
} else if (shop.isSelling()) {
|
|
||||||
selling++;
|
|
||||||
}
|
|
||||||
if (shop instanceof ContainerShop && ((ContainerShop) shop).isDoubleShop()) {
|
|
||||||
doubles++;
|
|
||||||
} else if (shop.isSelling() && shop.getRemainingStock() == 0) {
|
|
||||||
nostock++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("info.title", chunks, buying + selling, worlds));
|
|
||||||
sender.sendMessage(MsgUtil.p("info.selling", selling));
|
|
||||||
sender.sendMessage(MsgUtil.p("info.buying", buying));
|
|
||||||
sender.sendMessage(MsgUtil.p("info.double", doubles));
|
|
||||||
sender.sendMessage(MsgUtil.p("info.canclean", nostock));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandPrice extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandPrice(final QuickShop plugin) {
|
|
||||||
super("price");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setMinimumArguments(1);
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setPossibleArguments("<价格>");
|
|
||||||
setPermission("quickshop.create.changeprice");
|
|
||||||
setDescription(MsgUtil.p("command.description.price"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final Player p = (Player) sender;
|
|
||||||
double price;
|
|
||||||
try {
|
|
||||||
price = Double.parseDouble(args[0]);
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
sender.sendMessage(MsgUtil.p("thats-not-a-number"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (price < 0.01) {
|
|
||||||
sender.sendMessage(MsgUtil.p("price-too-cheap"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double fee = 0;
|
|
||||||
if (plugin.getConfigManager().isPriceChangeRequiresFee()) {
|
|
||||||
fee = plugin.getConfigManager().getFeeForPriceChange();
|
|
||||||
if (fee > 0 && plugin.getEcon().getBalance(p.getName()) < fee) {
|
|
||||||
sender.sendMessage(MsgUtil.p("you-cant-afford-to-change-price", plugin.getEcon().format(fee)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final BlockIterator bIt = new BlockIterator(p, 10);
|
|
||||||
// Loop through every block they're looking at upto 10 blocks away
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null && (shop.getOwner().equals(p.getName()) || sender.hasPermission("quickshop.other.price"))) {
|
|
||||||
if (shop.getPrice() == price) {
|
|
||||||
// Stop here if there isn't a price change
|
|
||||||
sender.sendMessage(MsgUtil.p("no-price-change"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (fee > 0) {
|
|
||||||
if (!plugin.getEcon().withdraw(p.getName(), fee)) {
|
|
||||||
sender.sendMessage(MsgUtil.p("you-cant-afford-to-change-price", plugin.getEcon().format(fee)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("fee-charged-for-price-change", plugin.getEcon().format(fee)));
|
|
||||||
plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), fee);
|
|
||||||
}
|
|
||||||
// Update the shop
|
|
||||||
shop.setPrice(price);
|
|
||||||
shop.setSignText();
|
|
||||||
shop.update();
|
|
||||||
sender.sendMessage(MsgUtil.p("price-is-now", plugin.getEcon().format(shop.getPrice())));
|
|
||||||
// Chest shops can be double shops.
|
|
||||||
if (shop instanceof ContainerShop) {
|
|
||||||
final ContainerShop cs = (ContainerShop) shop;
|
|
||||||
if (cs.isDoubleShop()) {
|
|
||||||
final Shop nextTo = cs.getAttachedShop();
|
|
||||||
if (cs.isSelling()) {
|
|
||||||
if (cs.getPrice() < nextTo.getPrice()) {
|
|
||||||
sender.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Buying
|
|
||||||
if (cs.getPrice() > nextTo.getPrice()) {
|
|
||||||
sender.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandRefill extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandRefill(final QuickShop plugin) {
|
|
||||||
super("refill");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setMinimumArguments(1);
|
|
||||||
setPossibleArguments("<数量>");
|
|
||||||
setPermission("quickshop.refill");
|
|
||||||
setDescription(MsgUtil.p("command.description.refill"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
int add;
|
|
||||||
try {
|
|
||||||
add = Integer.parseInt(args[0]);
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
sender.sendMessage(MsgUtil.p("thats-not-a-number"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null) {
|
|
||||||
shop.add(shop.getItem(), add);
|
|
||||||
sender.sendMessage(MsgUtil.p("refill-success"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandReload extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandReload(final QuickShop plugin) {
|
|
||||||
super("reload");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.reload");
|
|
||||||
setDescription(MsgUtil.p("command.description.reload"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
sender.sendMessage(MsgUtil.p("command.reloading"));
|
|
||||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
|
||||||
Bukkit.getPluginManager().enablePlugin(plugin);
|
|
||||||
plugin.reloadConfig();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandRemove extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandRemove(final QuickShop plugin) {
|
|
||||||
super("remove", "delete");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setPermission("quickshop.delete");
|
|
||||||
setDescription(MsgUtil.p("command.description.remove"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final Player p = (Player) sender;
|
|
||||||
final BlockIterator bIt = new BlockIterator(p, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null) {
|
|
||||||
if (shop.getOwner().equals(p.getName())) {
|
|
||||||
shop.delete();
|
|
||||||
sender.sendMessage(ChatColor.GREEN + "商店已成功移除");
|
|
||||||
} else {
|
|
||||||
p.sendMessage(ChatColor.RED + "这个不是你的商店!");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.sendMessage(ChatColor.RED + "未找到商店!");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.ShopType;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandSell extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandSell(final QuickShop plugin) {
|
|
||||||
super("sell");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.create.sell");
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setDescription(MsgUtil.p("command.description.sell"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null && shop.getOwner().equals(((Player) sender).getUniqueId())) {
|
|
||||||
shop.setShopType(ShopType.SELLING);
|
|
||||||
shop.setSignText();
|
|
||||||
shop.update();
|
|
||||||
sender.sendMessage(MsgUtil.p("command.now-selling", shop.getDataName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandSetOwner extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandSetOwner(final QuickShop plugin) {
|
|
||||||
super("setowner");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setPermission("quickshop.setowner");
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setDescription(MsgUtil.p("command.description.setowner"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
if (args.length < 2) {
|
|
||||||
sender.sendMessage(MsgUtil.p("command.no-owner-given"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null) {
|
|
||||||
final OfflinePlayer p = this.plugin.getServer().getOfflinePlayer(args[1]);
|
|
||||||
shop.setOwner(p.getName());
|
|
||||||
shop.update();
|
|
||||||
sender.sendMessage(MsgUtil.p("command.new-owner", this.plugin.getServer().getOfflinePlayer(shop.getOwner()).getName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandException;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.BlockIterator;
|
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.BaseCommand;
|
|
||||||
|
|
||||||
public class CommandUnlimited extends BaseCommand {
|
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public CommandUnlimited(final QuickShop plugin) {
|
|
||||||
super("unlimited");
|
|
||||||
this.plugin = plugin;
|
|
||||||
setOnlyPlayerExecutable();
|
|
||||||
setDescription(MsgUtil.p("command.description.unlimited"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final CommandSender sender, final Command command, final String label, final String[] args) throws CommandException {
|
|
||||||
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
|
||||||
while (bIt.hasNext()) {
|
|
||||||
final Block b = bIt.next();
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop != null) {
|
|
||||||
shop.setUnlimited(!shop.isUnlimited());
|
|
||||||
shop.update();
|
|
||||||
sender.sendMessage(MsgUtil.p("command.toggle-unlimited", (shop.isUnlimited() ? "无限模式" : "有限模式")));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,45 +1,439 @@
|
|||||||
package org.maxgamer.QuickShop.Command;
|
package org.maxgamer.QuickShop.Command;
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
import java.io.File;
|
||||||
import org.bukkit.command.CommandException;
|
import java.util.HashMap;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||||
|
import org.bukkit.util.BlockIterator;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
import org.maxgamer.QuickShop.Database.Database;
|
||||||
|
import org.maxgamer.QuickShop.Database.MySQLCore;
|
||||||
|
import org.maxgamer.QuickShop.Database.SQLiteCore;
|
||||||
|
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
||||||
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
|
import org.maxgamer.QuickShop.Shop.ShopChunk;
|
||||||
|
import org.maxgamer.QuickShop.Shop.ShopType;
|
||||||
|
import org.maxgamer.QuickShop.Util.MsgUtil;
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.commands.DefaultCommand;
|
import pw.yumc.YumCore.bukkit.P;
|
||||||
import cn.citycraft.PluginHelper.commands.HandlerSubCommand;
|
import pw.yumc.YumCore.commands.CommandSub;
|
||||||
|
import pw.yumc.YumCore.commands.annotation.Cmd;
|
||||||
|
import pw.yumc.YumCore.commands.annotation.Help;
|
||||||
|
import pw.yumc.YumCore.commands.annotation.Sort;
|
||||||
|
import pw.yumc.YumCore.commands.interfaces.Executor;
|
||||||
|
import pw.yumc.YumCore.commands.interfaces.HelpParse;
|
||||||
|
|
||||||
public class QuickShopCommands implements CommandExecutor, DefaultCommand {
|
public class QuickShopCommands implements Executor, HelpParse {
|
||||||
HandlerSubCommand hsc;
|
QuickShop plugin = P.getPlugin();
|
||||||
QuickShop plugin;
|
|
||||||
|
|
||||||
public QuickShopCommands(final QuickShop plugin) {
|
public QuickShopCommands() {
|
||||||
this.plugin = plugin;
|
new CommandSub("qs", this).setHelpParse(this);
|
||||||
hsc = new HandlerSubCommand(plugin);
|
}
|
||||||
hsc.setDefaultCommand(this);
|
|
||||||
hsc.registerCommand(new CommandClean(plugin));
|
@Sort(1)
|
||||||
hsc.registerCommand(new CommandEmpty(plugin));
|
@Cmd(aliases = "b", permission = "quickshop.create.buy", executor = Cmd.Executor.PLAYER)
|
||||||
hsc.registerCommand(new CommandExport(plugin));
|
@Help("command.description.buy")
|
||||||
hsc.registerCommand(new CommandFind(plugin));
|
public void buy(Player player) {
|
||||||
hsc.registerCommand(new CommandInfo(plugin));
|
changeShopType(player, ShopType.BUYING);
|
||||||
hsc.registerCommand(new CommandPrice(plugin));
|
}
|
||||||
hsc.registerCommand(new CommandRefill(plugin));
|
|
||||||
hsc.registerCommand(new CommandReload(plugin));
|
@Sort(7)
|
||||||
hsc.registerCommand(new CommandRemove(plugin));
|
@Cmd(aliases = "c", permission = "quickshop.clean")
|
||||||
hsc.registerCommand(new CommandBuy(plugin));
|
@Help("command.description.clean")
|
||||||
hsc.registerCommand(new CommandSetOwner(plugin));
|
public void clean(CommandSender sender) {
|
||||||
hsc.registerCommand(new CommandSell(plugin));
|
sender.sendMessage(MsgUtil.p("command.cleaning"));
|
||||||
hsc.registerCommand(new CommandUnlimited(plugin));
|
final Iterator<Shop> shIt = plugin.getShopManager().getShopIterator();
|
||||||
|
int i = 0;
|
||||||
|
while (shIt.hasNext()) {
|
||||||
|
final Shop shop = shIt.next();
|
||||||
|
try {
|
||||||
|
if (shop.getLocation().getWorld() != null && shop.isSelling() && shop.getRemainingStock() == 0 && shop instanceof ContainerShop) {
|
||||||
|
final ContainerShop cs = (ContainerShop) shop;
|
||||||
|
if (cs.isDoubleShop()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
shIt.remove(); // Is selling, but has no stock, and is a chest shop, but is not a double shop. Can be deleted safely.
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} catch (final IllegalStateException ex) {
|
||||||
|
// shIt.remove(); // The shop is not there anymore, remove it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MsgUtil.clean();
|
||||||
|
sender.sendMessage(MsgUtil.p("command.cleaned", "" + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(5)
|
||||||
|
@Cmd(aliases = "e", permission = "quickshop.empty", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.empty")
|
||||||
|
public void empty(Player player) {
|
||||||
|
final BlockIterator bIt = new BlockIterator(player, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
if (shop instanceof ContainerShop) {
|
||||||
|
final ContainerShop cs = (ContainerShop) shop;
|
||||||
|
cs.getInventory().clear();
|
||||||
|
player.sendMessage(MsgUtil.p("empty-success"));
|
||||||
|
} else {
|
||||||
|
player.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd(minimumArguments = 1, permission = "quickshop.export")
|
||||||
|
@Help(value = "command.description.export", possibleArguments = "[mysql|sqlite]")
|
||||||
|
public void export(CommandSender sender, String type) {
|
||||||
|
if (type.startsWith("mysql")) {
|
||||||
|
if (plugin.getDB().getCore() instanceof MySQLCore) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "数据已保存在 MySQL 无需转换!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ConfigurationSection cfg = plugin.getConfig().getConfigurationSection("database");
|
||||||
|
final String host = cfg.getString("host");
|
||||||
|
final String port = cfg.getString("port");
|
||||||
|
final String user = cfg.getString("user");
|
||||||
|
final String pass = cfg.getString("password");
|
||||||
|
final String name = cfg.getString("database");
|
||||||
|
final MySQLCore core = new MySQLCore(host, user, pass, name, port);
|
||||||
|
Database target;
|
||||||
|
try {
|
||||||
|
target = new Database(core);
|
||||||
|
QuickShop.instance.getDB().copyTo(target);
|
||||||
|
sender.sendMessage(ChatColor.GREEN + "导出成功 - 数据已保存至 MySQL " + user + "@" + host + "." + name);
|
||||||
|
} catch (final Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
sender.sendMessage(ChatColor.RED + "导出数据到 MySQL 失败 " + user + "@" + host + "." + name + ChatColor.DARK_RED + " 由于: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type.startsWith("sql") || type.contains("file")) {
|
||||||
|
if (plugin.getDB().getCore() instanceof SQLiteCore) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "数据已保存在 SQLite 无需转换!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final File file = new File(plugin.getDataFolder(), "shops.db");
|
||||||
|
if (file.exists() && !file.delete()) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "警告: 删除旧的数据文件 shops.db 失败. 可能会导致部分信息错误.");
|
||||||
|
}
|
||||||
|
final SQLiteCore core = new SQLiteCore(file);
|
||||||
|
try {
|
||||||
|
final Database target = new Database(core);
|
||||||
|
QuickShop.instance.getDB().copyTo(target);
|
||||||
|
sender.sendMessage(ChatColor.GREEN + "导出成功 - 数据已保存至 SQLite: " + file.toString());
|
||||||
|
} catch (final Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
sender.sendMessage(ChatColor.RED + "导出数据到 SQLite: " + file.toString() + " 失败 由于: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd(aliases = "f", minimumArguments = 1, permission = "quickshop.find", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.find")
|
||||||
|
public void find(Player p, String lookFor) {
|
||||||
|
lookFor = lookFor.toLowerCase();
|
||||||
|
final Location loc = p.getEyeLocation().clone();
|
||||||
|
final double minDistance = plugin.getConfig().getInt("shop.find-distance");
|
||||||
|
double minDistanceSquared = minDistance * minDistance;
|
||||||
|
final int chunkRadius = (int) minDistance / 16 + 1;
|
||||||
|
Shop closest = null;
|
||||||
|
final Chunk c = loc.getChunk();
|
||||||
|
for (int x = -chunkRadius + c.getX(); x < chunkRadius + c.getX(); x++) {
|
||||||
|
for (int z = -chunkRadius + c.getZ(); z < chunkRadius + c.getZ(); z++) {
|
||||||
|
final Chunk d = c.getWorld().getChunkAt(x, z);
|
||||||
|
final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(d);
|
||||||
|
if (inChunk == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (final Shop shop : inChunk.values()) {
|
||||||
|
if (shop.getDataName().toLowerCase().contains(lookFor) && shop.getLocation().distanceSquared(loc) < minDistanceSquared) {
|
||||||
|
closest = shop;
|
||||||
|
minDistanceSquared = shop.getLocation().distanceSquared(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (closest == null) {
|
||||||
|
p.sendMessage(MsgUtil.p("no-nearby-shop", lookFor));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Location lookat = closest.getLocation().clone().add(0.5, 0.5, 0.5);
|
||||||
|
// Hack fix to make /qs find not used by /back
|
||||||
|
p.teleport(this.lookAt(loc, lookat).add(0, -1.62, 0), TeleportCause.PLUGIN);
|
||||||
|
p.sendMessage(MsgUtil.p("nearby-shop-this-way", "" + (int) Math.floor(Math.sqrt(minDistanceSquared))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd(aliases = "i", permission = "quickshop.info")
|
||||||
|
@Help("command.description.info")
|
||||||
|
public void info(CommandSender sender) {
|
||||||
|
int buying, selling, doubles, chunks, worlds, unlimited;
|
||||||
|
buying = selling = doubles = chunks = worlds = unlimited = 0;
|
||||||
|
int nostock = 0;
|
||||||
|
sender.sendMessage(ChatColor.RED + "开始检索商店信息中...");
|
||||||
|
for (final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld : plugin.getShopManager().getShops().values()) {
|
||||||
|
worlds++;
|
||||||
|
for (final HashMap<Location, Shop> inChunk : inWorld.values()) {
|
||||||
|
chunks++;
|
||||||
|
for (final Shop shop : inChunk.values()) {
|
||||||
|
if (shop.isUnlimited()) {
|
||||||
|
unlimited++;
|
||||||
|
}
|
||||||
|
if (shop.isBuying()) {
|
||||||
|
buying++;
|
||||||
|
} else if (shop.isSelling()) {
|
||||||
|
selling++;
|
||||||
|
}
|
||||||
|
if (shop instanceof ContainerShop && ((ContainerShop) shop).isDoubleShop()) {
|
||||||
|
doubles++;
|
||||||
|
} else if (shop.isSelling() && shop.getRemainingStock() == 0) {
|
||||||
|
nostock++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("info.title", chunks, buying + selling, worlds));
|
||||||
|
sender.sendMessage(MsgUtil.p("info.selling", selling));
|
||||||
|
sender.sendMessage(MsgUtil.p("info.buying", buying));
|
||||||
|
sender.sendMessage(MsgUtil.p("info.unlimited", unlimited));
|
||||||
|
sender.sendMessage(MsgUtil.p("info.double", doubles));
|
||||||
|
sender.sendMessage(MsgUtil.p("info.canclean", nostock));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void defaultExecute(final CommandSender sender, final Command command, final String label) throws CommandException {
|
public String parse(final String str) {
|
||||||
hsc.sendHelp(sender, label);
|
return MsgUtil.p(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Sort(4)
|
||||||
public boolean onCommand(final CommandSender sender, final Command cmd, final String label, final String[] args) {
|
@Cmd(aliases = "p", minimumArguments = 1, permission = "quickshop.create.changeprice", executor = Cmd.Executor.PLAYER)
|
||||||
return hsc.onCommand(sender, cmd, label, args);
|
@Help(value = "command.description.price", possibleArguments = "<价格>")
|
||||||
|
public void price(Player sender, Double price) {
|
||||||
|
if (price < 0.01) {
|
||||||
|
sender.sendMessage(MsgUtil.p("price-too-cheap"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double fee = 0;
|
||||||
|
if (plugin.getConfigManager().isPriceChangeRequiresFee()) {
|
||||||
|
fee = plugin.getConfigManager().getFeeForPriceChange();
|
||||||
|
if (fee > 0 && plugin.getEcon().getBalance(sender.getName()) < fee) {
|
||||||
|
sender.sendMessage(MsgUtil.p("you-cant-afford-to-change-price", plugin.getEcon().format(fee)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final BlockIterator bIt = new BlockIterator(sender, 10);
|
||||||
|
// Loop through every block they're looking at upto 10 blocks away
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null && (shop.getOwner().equals(sender.getName()) || sender.hasPermission("quickshop.other.price"))) {
|
||||||
|
if (shop.getPrice() == price) {
|
||||||
|
// Stop here if there isn't a price change
|
||||||
|
sender.sendMessage(MsgUtil.p("no-price-change"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fee > 0) {
|
||||||
|
if (!plugin.getEcon().withdraw(sender.getName(), fee)) {
|
||||||
|
sender.sendMessage(MsgUtil.p("you-cant-afford-to-change-price", plugin.getEcon().format(fee)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("fee-charged-for-price-change", plugin.getEcon().format(fee)));
|
||||||
|
plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), fee);
|
||||||
|
}
|
||||||
|
// Update the shop
|
||||||
|
shop.setPrice(price);
|
||||||
|
shop.setSignText();
|
||||||
|
shop.update();
|
||||||
|
sender.sendMessage(MsgUtil.p("price-is-now", plugin.getEcon().format(shop.getPrice())));
|
||||||
|
// Chest shops can be double shops.
|
||||||
|
if (shop instanceof ContainerShop) {
|
||||||
|
final ContainerShop cs = (ContainerShop) shop;
|
||||||
|
if (cs.isDoubleShop()) {
|
||||||
|
final Shop nextTo = cs.getAttachedShop();
|
||||||
|
if (cs.isSelling()) {
|
||||||
|
if (cs.getPrice() < nextTo.getPrice()) {
|
||||||
|
sender.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Buying
|
||||||
|
if (cs.getPrice() > nextTo.getPrice()) {
|
||||||
|
sender.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(6)
|
||||||
|
@Cmd(minimumArguments = 1, permission = "quickshop.refill", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help(value = "command.description.refill", possibleArguments = "<数量>")
|
||||||
|
public void refill(Player sender, Integer add) {
|
||||||
|
final BlockIterator bIt = new BlockIterator(sender, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
shop.add(shop.getItem(), add);
|
||||||
|
sender.sendMessage(MsgUtil.p("refill-success"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd(permission = "quickshop.reload")
|
||||||
|
@Help("command.description.reload")
|
||||||
|
public void reload(CommandSender sender) {
|
||||||
|
sender.sendMessage(MsgUtil.p("command.reloading"));
|
||||||
|
plugin.reloadConfig();
|
||||||
|
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||||
|
Bukkit.getPluginManager().enablePlugin(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(6)
|
||||||
|
@Cmd(aliases = "r", permission = "quickshop.delete", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.remove")
|
||||||
|
public void remove(Player p) {
|
||||||
|
final BlockIterator bIt = new BlockIterator(p, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
if (shop.getOwner().equals(p.getName())) {
|
||||||
|
shop.delete();
|
||||||
|
p.sendMessage(ChatColor.GREEN + "商店已成功移除");
|
||||||
|
} else {
|
||||||
|
p.sendMessage(ChatColor.RED + "这个不是你的商店!");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.sendMessage(ChatColor.RED + "未找到商店!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(2)
|
||||||
|
@Cmd(aliases = "s", permission = "quickshop.create.sell", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.sell")
|
||||||
|
public void sell(Player player) {
|
||||||
|
changeShopType(player, ShopType.SELLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(3)
|
||||||
|
@Cmd(aliases = "so", minimumArguments = 1, permission = "quickshop.setowner", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.setowner")
|
||||||
|
public void setowner(CommandSender sender, String owner) {
|
||||||
|
final BlockIterator bIt = new BlockIterator((Player) sender, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
shop.setOwner(owner);
|
||||||
|
shop.update();
|
||||||
|
sender.sendMessage(MsgUtil.p("command.new-owner", owner));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Sort(0)
|
||||||
|
@Cmd(permission = "quickshop.unlimited", executor = Cmd.Executor.PLAYER)
|
||||||
|
@Help("command.description.unlimited")
|
||||||
|
public void unlimited(Player sender) {
|
||||||
|
final BlockIterator bIt = new BlockIterator(sender, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
shop.setUnlimited(!shop.isUnlimited());
|
||||||
|
shop.update();
|
||||||
|
sender.sendMessage(MsgUtil.p("command.toggle-unlimited", (shop.isUnlimited() ? "无限模式" : "有限模式")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeShopType(final Player sender, final ShopType shopType) {
|
||||||
|
final BlockIterator bIt = new BlockIterator(sender, 10);
|
||||||
|
while (bIt.hasNext()) {
|
||||||
|
final Block b = bIt.next();
|
||||||
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop != null && shop.getOwner().equals(sender.getName())) {
|
||||||
|
shop.setShopType(shopType);
|
||||||
|
shop.setSignText();
|
||||||
|
shop.update();
|
||||||
|
String msgtype = "";
|
||||||
|
switch (shopType) {
|
||||||
|
case BUYING:
|
||||||
|
msgtype = "command.now-buying";
|
||||||
|
break;
|
||||||
|
case SELLING:
|
||||||
|
msgtype = "command.now-selling";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p(msgtype, shop.getDataName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(MsgUtil.p("not-looking-at-shop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns loc with modified pitch/yaw angles so it faces lookat
|
||||||
|
*
|
||||||
|
* @param loc
|
||||||
|
* The location a players head is
|
||||||
|
* @param lookat
|
||||||
|
* The location they should be looking
|
||||||
|
* @return The location the player should be facing to have their crosshairs
|
||||||
|
* on the location lookAt Kudos to bergerkiller for most of this
|
||||||
|
* function
|
||||||
|
*/
|
||||||
|
private Location lookAt(Location loc, final Location lookat) {
|
||||||
|
// Clone the loc to prevent applied changes to the input loc
|
||||||
|
loc = loc.clone();
|
||||||
|
// Values of change in distance (make it relative)
|
||||||
|
final double dx = lookat.getX() - loc.getX();
|
||||||
|
final double dy = lookat.getY() - loc.getY();
|
||||||
|
final double dz = lookat.getZ() - loc.getZ();
|
||||||
|
// Set yaw
|
||||||
|
if (dx != 0) {
|
||||||
|
// Set yaw start value based on dx
|
||||||
|
if (dx < 0) {
|
||||||
|
loc.setYaw((float) (1.5 * Math.PI));
|
||||||
|
} else {
|
||||||
|
loc.setYaw((float) (0.5 * Math.PI));
|
||||||
|
}
|
||||||
|
loc.setYaw(loc.getYaw() - (float) Math.atan(dz / dx));
|
||||||
|
} else if (dz < 0) {
|
||||||
|
loc.setYaw((float) Math.PI);
|
||||||
|
}
|
||||||
|
// Get the distance from dx/dz
|
||||||
|
final double dxz = Math.sqrt(Math.pow(dx, 2) + Math.pow(dz, 2));
|
||||||
|
final float pitch = (float) -Math.atan(dy / dxz);
|
||||||
|
// Set values, convert to degrees
|
||||||
|
// ServerInfo yaw (vertical) angles are inverted (negative)
|
||||||
|
loc.setYaw(-loc.getYaw() * 180f / (float) Math.PI + 360);
|
||||||
|
// But pitch angles are normal
|
||||||
|
loc.setPitch(pitch * 180f / (float) Math.PI);
|
||||||
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,52 +1,63 @@
|
|||||||
package org.maxgamer.QuickShop.Config;
|
package org.maxgamer.QuickShop.Config;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.maxgamer.QuickShop.Listeners.ChunkListener;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
import org.maxgamer.QuickShop.Shop.Item.DisplayItem;
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.config.FileConfig;
|
import pw.yumc.YumCore.bukkit.Log;
|
||||||
|
import pw.yumc.YumCore.config.FileConfig;
|
||||||
|
import pw.yumc.YumCore.tellraw.Tellraw;
|
||||||
|
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
|
private boolean enableMagicLib = false;
|
||||||
/** Whether debug info should be shown in the console */
|
/** Whether debug info should be shown in the console */
|
||||||
protected boolean debug = false;
|
private final boolean debug = false;
|
||||||
/** Whether we should use display items or not */
|
|
||||||
protected boolean display = true;
|
|
||||||
protected double feeForPriceChange = 0.0;
|
|
||||||
protected int findDistance = 30;
|
|
||||||
protected String guiTitle;
|
|
||||||
/** Whether or not to limit players shop amounts */
|
|
||||||
protected boolean limit = false;
|
|
||||||
|
|
||||||
protected int limitdefault = 0;
|
/** Whether we should use display items or not */
|
||||||
protected final HashMap<String, Integer> limits = new HashMap<String, Integer>();
|
private boolean display = true;
|
||||||
protected boolean logAction = true;
|
private double feeForPriceChange = 0.0;
|
||||||
protected boolean preventhopper = false;
|
private int findDistance = 30;
|
||||||
|
private String guiTitle = "§6[§b快捷商店§6]§r";
|
||||||
|
/** Whether or not to limit players shop amounts */
|
||||||
|
private boolean limit = false;
|
||||||
|
|
||||||
|
private int limitdefault = 0;
|
||||||
|
private final HashMap<String, Integer> limits = new HashMap<>();
|
||||||
|
private boolean logAction = true;
|
||||||
|
private boolean preventhopper = false;
|
||||||
/**
|
/**
|
||||||
* Whether we players are charged a fee to change the price on their shop
|
* Whether we players are charged a fee to change the price on their shop
|
||||||
* (To help deter endless undercutting
|
* (To help deter endless undercutting
|
||||||
*/
|
*/
|
||||||
protected boolean priceChangeRequiresFee = false;
|
private boolean priceChangeRequiresFee = false;
|
||||||
protected boolean shopLock = true;
|
private boolean shopLock = true;
|
||||||
protected boolean showTax;
|
private boolean showTax = false;
|
||||||
/** Whether players are required to sneak to create/buy from a shop */
|
/** Whether players are required to sneak to create/buy from a shop */
|
||||||
protected boolean sneak;
|
private boolean sneak = false;
|
||||||
/** Whether players are required to sneak to create a shop */
|
/** Whether players are required to sneak to create a shop */
|
||||||
protected boolean sneakCreate;
|
private boolean sneakCreate = false;
|
||||||
/** Whether players are required to sneak to trade with a shop */
|
/** Whether players are required to sneak to trade with a shop */
|
||||||
protected boolean sneakTrade;
|
private boolean sneakTrade = false;
|
||||||
protected Material superItem = Material.GOLD_AXE;
|
private Material superItem = Material.GOLD_AXE;
|
||||||
protected double tax = 0;
|
private double tax = 0;
|
||||||
protected String taxAccount;
|
private final String taxAccount;
|
||||||
/** Use SpoutPlugin to get item / block names */
|
private boolean fakeItem = false;
|
||||||
protected boolean useSpout = false;
|
private List<String> prevent;
|
||||||
/**
|
/**
|
||||||
* A set of players who have been warned
|
* A set of players who have been warned
|
||||||
* ("Your shop isn't automatically locked")
|
* ("Your shop isn't automatically locked")
|
||||||
*/
|
*/
|
||||||
protected HashSet<String> warnings = new HashSet<String>();
|
private Set<String> warnings = new HashSet<>();
|
||||||
|
|
||||||
public ConfigManager(final QuickShop plugin) {
|
public ConfigManager(final QuickShop plugin) {
|
||||||
final FileConfig config = (FileConfig) plugin.getConfig();
|
final FileConfig config = (FileConfig) plugin.getConfig();
|
||||||
@ -60,8 +71,8 @@ public class ConfigManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.superItem = Enum.valueOf(Material.class, config.getString("superitem"));
|
this.superItem = Material.valueOf(config.getString("superitem"));
|
||||||
} catch (final Exception e) {
|
} catch (final Exception ignored) {
|
||||||
}
|
}
|
||||||
this.tax = config.getDouble("tax");
|
this.tax = config.getDouble("tax");
|
||||||
this.showTax = config.getBoolean("show-tax");
|
this.showTax = config.getBoolean("show-tax");
|
||||||
@ -76,7 +87,29 @@ public class ConfigManager {
|
|||||||
this.findDistance = config.getInt("shop.find-distance");
|
this.findDistance = config.getInt("shop.find-distance");
|
||||||
this.feeForPriceChange = config.getDouble("shop.fee-for-price-change");
|
this.feeForPriceChange = config.getDouble("shop.fee-for-price-change");
|
||||||
this.preventhopper = config.getBoolean("preventhopper");
|
this.preventhopper = config.getBoolean("preventhopper");
|
||||||
this.guiTitle = config.getMessage("guititle");
|
this.guiTitle = config.getMessage("guititle", guiTitle);
|
||||||
|
this.warnings = Collections.emptySet();
|
||||||
|
this.prevent = config.getStringList("prevent");
|
||||||
|
if (display) {
|
||||||
|
Bukkit.getServer().getPluginManager().registerEvents(new ChunkListener(), plugin);
|
||||||
|
DisplayItem.init(config.getBoolean("fakeitem", true));
|
||||||
|
}
|
||||||
|
if (config.getBoolean("usemagiclib", true)) {
|
||||||
|
try {
|
||||||
|
plugin.getLogger().info("启用魔改库 尝试启动中...");
|
||||||
|
final Tellraw fm = Tellraw.create("test");
|
||||||
|
fm.then("item").item(new ItemStack(Material.DIAMOND_SWORD));
|
||||||
|
fm.then("link").link("yumc.pw");
|
||||||
|
fm.then("suggest").suggest("qs help");
|
||||||
|
fm.toJsonString();
|
||||||
|
plugin.getLogger().info("魔改库功能测试正常...");
|
||||||
|
this.enableMagicLib = true;
|
||||||
|
} catch (final Error | Exception e) {
|
||||||
|
Log.d("+=========================================");
|
||||||
|
Log.d("| 警告: 启动魔改库失败 将使用GUI商店界面...");
|
||||||
|
Log.d("+=========================================");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getFeeForPriceChange() {
|
public double getFeeForPriceChange() {
|
||||||
@ -111,7 +144,7 @@ public class ConfigManager {
|
|||||||
return taxAccount;
|
return taxAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<String> getWarnings() {
|
public Set<String> getWarnings() {
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +156,14 @@ public class ConfigManager {
|
|||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnableMagicLib() {
|
||||||
|
return enableMagicLib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFakeItem() {
|
||||||
|
return fakeItem;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isLimit() {
|
public boolean isLimit() {
|
||||||
return limit;
|
return limit;
|
||||||
}
|
}
|
||||||
@ -159,8 +200,19 @@ public class ConfigManager {
|
|||||||
return sneakTrade;
|
return sneakTrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUseSpout() {
|
public void setEnableMagicLib(final boolean enableMagicLib) {
|
||||||
return useSpout;
|
this.enableMagicLib = enableMagicLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFakeItem(final boolean fakeItem) {
|
||||||
|
this.fakeItem = fakeItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPrevent() {
|
||||||
|
return prevent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrevent(List<String> prevent) {
|
||||||
|
this.prevent = prevent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Config;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.config.FileConfig;
|
|
||||||
|
|
||||||
public class ItemConfig {
|
|
||||||
public static FileConfig config;
|
|
||||||
public static File file;
|
|
||||||
private static String CONFIG_NAME = "item.yml";
|
|
||||||
|
|
||||||
public static String getItemName(final ItemStack i) {
|
|
||||||
if (i.hasItemMeta() && i.getItemMeta().hasDisplayName()) {
|
|
||||||
return i.getItemMeta().getDisplayName();
|
|
||||||
}
|
|
||||||
final String name = i.getType().name();
|
|
||||||
final int dur = i.getDurability();
|
|
||||||
final String dura = i.getMaxStackSize() != 1 ? dur != 0 ? "_" + dur : "" : "";
|
|
||||||
final String iname = name + dura;
|
|
||||||
return getItemName(iname);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getItemName(final String iname) {
|
|
||||||
String aname = config.getString(iname);
|
|
||||||
if (aname == null) {
|
|
||||||
aname = iname;
|
|
||||||
config.set(iname, iname);
|
|
||||||
config.save();
|
|
||||||
}
|
|
||||||
return aname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void load(final Plugin p) {
|
|
||||||
config = new FileConfig(p, CONFIG_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reload() {
|
|
||||||
config.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -112,8 +112,7 @@ public class Database {
|
|||||||
PreparedStatement ps = this.getConnection().prepareStatement(query);
|
PreparedStatement ps = this.getConnection().prepareStatement(query);
|
||||||
ResultSet rs = ps.executeQuery();
|
ResultSet rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
rs.getString(column); // Throws an exception if it can't find
|
rs.getString(column); // Throws an exception if it can't find that column
|
||||||
// that column
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@ -149,7 +148,7 @@ public class Database {
|
|||||||
*/
|
*/
|
||||||
public void copyTo(Database db) throws SQLException {
|
public void copyTo(Database db) throws SQLException {
|
||||||
ResultSet rs = getConnection().getMetaData().getTables(null, null, "%", null);
|
ResultSet rs = getConnection().getMetaData().getTables(null, null, "%", null);
|
||||||
List<String> tables = new LinkedList<String>();
|
List<String> tables = new LinkedList<>();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
tables.add(rs.getString("TABLE_NAME"));
|
tables.add(rs.getString("TABLE_NAME"));
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ package org.maxgamer.QuickShop.Database;
|
|||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
|
||||||
public interface DatabaseCore {
|
public interface DatabaseCore {
|
||||||
public Connection getConnection();
|
Connection getConnection();
|
||||||
|
|
||||||
public void queue(BufferStatement bs);
|
void queue(BufferStatement bs);
|
||||||
|
|
||||||
public void flush();
|
void flush();
|
||||||
|
|
||||||
public void close();
|
void close();
|
||||||
}
|
}
|
@ -19,20 +19,20 @@ public class DatabaseHelper {
|
|||||||
* Verifies that all required columns exist.
|
* Verifies that all required columns exist.
|
||||||
*/
|
*/
|
||||||
public static void checkColumns(Database db) {
|
public static void checkColumns(Database db) {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps;
|
||||||
try {
|
try {
|
||||||
// V3.4.2
|
// V3.4.2
|
||||||
ps = db.getConnection().prepareStatement("ALTER TABLE shops MODIFY COLUMN price double(32,2) NOT NULL AFTER owner");
|
ps = db.getConnection().prepareStatement("ALTER TABLE shops MODIFY COLUMN price double(32,2) NOT NULL AFTER owner");
|
||||||
ps.execute();
|
ps.execute();
|
||||||
ps.close();
|
ps.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException ignored) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// V3.4.3
|
// V3.4.3
|
||||||
ps = db.getConnection().prepareStatement("ALTER TABLE messages MODIFY COLUMN time BIGINT(32) NOT NULL AFTER message");
|
ps = db.getConnection().prepareStatement("ALTER TABLE messages MODIFY COLUMN time BIGINT(32) NOT NULL AFTER message");
|
||||||
ps.execute();
|
ps.execute();
|
||||||
ps.close();
|
ps.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,8 @@ public class DatabaseHelper {
|
|||||||
*/
|
*/
|
||||||
public static void createShopsTable(Database db) throws SQLException {
|
public static void createShopsTable(Database db) throws SQLException {
|
||||||
Statement st = db.getConnection().createStatement();
|
Statement st = db.getConnection().createStatement();
|
||||||
String createTable = "CREATE TABLE shops (" + "owner TEXT(32) NOT NULL, " + "price double(32, 2) NOT NULL, " + "itemConfig TEXT CHARSET utf8 NOT NULL, " + "x INTEGER(32) NOT NULL, " + "y INTEGER(32) NOT NULL, " + "z INTEGER(32) NOT NULL, " + "world VARCHAR(32) NOT NULL, " + "unlimited boolean, " + "type boolean, " + "PRIMARY KEY (x, y, z, world) " + ");";
|
String createTable = "CREATE TABLE shops (" + "owner TEXT(32) NOT NULL, " + "price double(32, 2) NOT NULL, " + "itemConfig TEXT CHARSET utf8 NOT NULL, " + "x INTEGER(32) NOT NULL, "
|
||||||
|
+ "y INTEGER(32) NOT NULL, " + "z INTEGER(32) NOT NULL, " + "world VARCHAR(32) NOT NULL, " + "unlimited boolean, " + "type boolean, " + "PRIMARY KEY (x, y, z, world) " + ");";
|
||||||
st.execute(createTable);
|
st.execute(createTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,18 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
public class MySQLCore implements DatabaseCore {
|
public class MySQLCore implements DatabaseCore {
|
||||||
private String url;
|
private String url;
|
||||||
/** The connection properties... user, pass, autoReconnect.. */
|
/**
|
||||||
|
* The connection properties... user, pass, autoReconnect..
|
||||||
|
*/
|
||||||
private Properties info;
|
private Properties info;
|
||||||
private static final int MAX_CONNECTIONS = 8;
|
private static final int MAX_CONNECTIONS = 8;
|
||||||
private static ArrayList<Connection> pool = new ArrayList<Connection>();
|
private static final List<Connection> POOL = Collections.synchronizedList(new ArrayList<Connection>());
|
||||||
|
|
||||||
public MySQLCore(String host, String user, String pass, String database, String port) {
|
public MySQLCore(String host, String user, String pass, String database, String port) {
|
||||||
info = new Properties();
|
info = new Properties();
|
||||||
@ -22,8 +26,7 @@ public class MySQLCore implements DatabaseCore {
|
|||||||
info.put("useUnicode", "true");
|
info.put("useUnicode", "true");
|
||||||
info.put("characterEncoding", "utf8");
|
info.put("characterEncoding", "utf8");
|
||||||
this.url = "jdbc:mysql://" + host + ":" + port + "/" + database;
|
this.url = "jdbc:mysql://" + host + ":" + port + "/" + database;
|
||||||
for (int i = 0; i < MAX_CONNECTIONS; i++)
|
for (int i = 0; i < MAX_CONNECTIONS; i++) {POOL.add(null);}
|
||||||
pool.add(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,9 +34,10 @@ public class MySQLCore implements DatabaseCore {
|
|||||||
*
|
*
|
||||||
* @return The database connection
|
* @return The database connection
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Connection getConnection() {
|
public Connection getConnection() {
|
||||||
for (int i = 0; i < MAX_CONNECTIONS; i++) {
|
for (int i = 0; i < MAX_CONNECTIONS; i++) {
|
||||||
Connection connection = pool.get(i);
|
Connection connection = POOL.get(i);
|
||||||
try {
|
try {
|
||||||
// If we have a current connection, fetch it
|
// If we have a current connection, fetch it
|
||||||
if (connection != null && !connection.isClosed()) {
|
if (connection != null && !connection.isClosed()) {
|
||||||
@ -43,7 +47,7 @@ public class MySQLCore implements DatabaseCore {
|
|||||||
// Else, it is invalid, so we return another connection.
|
// Else, it is invalid, so we return another connection.
|
||||||
}
|
}
|
||||||
connection = DriverManager.getConnection(this.url, info);
|
connection = DriverManager.getConnection(this.url, info);
|
||||||
pool.set(i, connection);
|
POOL.set(i, connection);
|
||||||
return connection;
|
return connection;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -59,7 +63,7 @@ public class MySQLCore implements DatabaseCore {
|
|||||||
while (con == null) {
|
while (con == null) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(15);
|
Thread.sleep(15);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
// Try again
|
// Try again
|
||||||
this.getConnection();
|
this.getConnection();
|
||||||
@ -69,7 +73,6 @@ public class MySQLCore implements DatabaseCore {
|
|||||||
ps.close();
|
ps.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,26 +10,49 @@ import java.util.LinkedList;
|
|||||||
|
|
||||||
public class SQLiteCore implements DatabaseCore {
|
public class SQLiteCore implements DatabaseCore {
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
private File dbFile;
|
private final File dbFile;
|
||||||
private volatile Thread watcher;
|
private volatile Thread watcher;
|
||||||
private volatile LinkedList<BufferStatement> queue = new LinkedList<BufferStatement>();
|
private final LinkedList<BufferStatement> queue = new LinkedList<BufferStatement>();
|
||||||
|
|
||||||
public SQLiteCore(File dbFile) {
|
public SQLiteCore(final File dbFile) {
|
||||||
this.dbFile = dbFile;
|
this.dbFile = dbFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
BufferStatement bs;
|
||||||
|
synchronized (queue) {
|
||||||
|
bs = queue.removeFirst();
|
||||||
|
}
|
||||||
|
synchronized (dbFile) {
|
||||||
|
try {
|
||||||
|
final PreparedStatement ps = bs.prepareStatement(getConnection());
|
||||||
|
ps.execute();
|
||||||
|
ps.close();
|
||||||
|
} catch (final SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the database connection for executing queries on.
|
* Gets the database connection for executing queries on.
|
||||||
*
|
*
|
||||||
* @return The database connection
|
* @return The database connection
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Connection getConnection() {
|
public Connection getConnection() {
|
||||||
try {
|
try {
|
||||||
// If we have a current connection, fetch it
|
// If we have a current connection, fetch it
|
||||||
if (this.connection != null && !this.connection.isClosed()) {
|
if (this.connection != null && !this.connection.isClosed()) { return this.connection; }
|
||||||
return this.connection;
|
} catch (final SQLException e) {
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
if (this.dbFile.exists()) {
|
if (this.dbFile.exists()) {
|
||||||
@ -38,14 +61,11 @@ public class SQLiteCore implements DatabaseCore {
|
|||||||
Class.forName("org.sqlite.JDBC");
|
Class.forName("org.sqlite.JDBC");
|
||||||
this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbFile);
|
this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbFile);
|
||||||
return this.connection;
|
return this.connection;
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (final ClassNotFoundException | SQLException e) {
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// So we need a new file too.
|
// So we need a new file too.
|
||||||
try {
|
try {
|
||||||
// Create the file
|
// Create the file
|
||||||
@ -53,15 +73,14 @@ public class SQLiteCore implements DatabaseCore {
|
|||||||
// Now we won't need a new file, just a connection.
|
// Now we won't need a new file, just a connection.
|
||||||
// This will return that new connection.
|
// This will return that new connection.
|
||||||
return this.getConnection();
|
return this.getConnection();
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queue(BufferStatement bs) {
|
public void queue(final BufferStatement bs) {
|
||||||
synchronized (queue) {
|
synchronized (queue) {
|
||||||
queue.add(bs);
|
queue.add(bs);
|
||||||
}
|
}
|
||||||
@ -70,37 +89,13 @@ public class SQLiteCore implements DatabaseCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
while (queue.isEmpty() == false) {
|
|
||||||
BufferStatement bs;
|
|
||||||
synchronized (queue) {
|
|
||||||
bs = queue.removeFirst();
|
|
||||||
}
|
|
||||||
synchronized (dbFile) {
|
|
||||||
try {
|
|
||||||
PreparedStatement ps = bs.prepareStatement(getConnection());
|
|
||||||
ps.execute();
|
|
||||||
ps.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startWatcher() {
|
private void startWatcher() {
|
||||||
watcher = new Thread() {
|
watcher = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(30000);
|
Thread.sleep(30000);
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,15 @@ package org.maxgamer.QuickShop.Economy;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Economy implements EconomyCore {
|
public class Economy implements EconomyCore {
|
||||||
private EconomyCore core;
|
private final EconomyCore core;
|
||||||
|
|
||||||
public Economy(EconomyCore core) {
|
public Economy(final EconomyCore core) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Checks that this economy is valid. Returns false if it is not valid.
|
public String currencyNamePlural() {
|
||||||
*
|
return this.core.currencyNamePlural();
|
||||||
* @return True if this economy will work, false if it will not.
|
|
||||||
*/
|
|
||||||
public boolean isValid() {
|
|
||||||
return core.isValid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,24 +23,66 @@ public class Economy implements EconomyCore {
|
|||||||
* The amount to give them
|
* The amount to give them
|
||||||
* @return True if success (Should be almost always)
|
* @return True if success (Should be almost always)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean deposit(String name, double amount) {
|
public boolean deposit(final String name, final double amount) {
|
||||||
return core.deposit(name, amount);
|
return this.core.deposit(name, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deposit(final UUID name, final double amount) {
|
||||||
|
return this.core.deposit(name, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Withdraws a given amount of money from the given username and turns it to
|
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
|
||||||
* thin air.
|
* Dollars 5 Cents
|
||||||
|
*
|
||||||
|
* @param balance
|
||||||
|
* The given number
|
||||||
|
* @return The balance in human readable text.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String format(final double balance) {
|
||||||
|
return this.core.format(balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the balance of the given account name
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The exact (case insensitive) username to take money from
|
* The name of the account
|
||||||
* @param amount
|
* @return Their current balance.
|
||||||
* The amount to take from them
|
|
||||||
* @return True if success, false if they didn't have enough cash
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean withdraw(String name, double amount) {
|
public double getBalance(final String name) {
|
||||||
return core.withdraw(name, amount);
|
return this.core.getBalance(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBalance(final UUID name) {
|
||||||
|
return this.core.getBalance(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public boolean has(final String name, final double amount) {
|
||||||
|
return this.core.getBalance(name) >= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that this economy is valid. Returns false if it is not valid.
|
||||||
|
*
|
||||||
|
* @return True if this economy will work, false if it will not.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return this.core.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.core.getClass().getName().split("_")[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,61 +97,35 @@ public class Economy implements EconomyCore {
|
|||||||
* @return true if success (Payer had enough cash, receiver was able to
|
* @return true if success (Payer had enough cash, receiver was able to
|
||||||
* receive the funds)
|
* receive the funds)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean transfer(String from, String to, double amount) {
|
public boolean transfer(final String from, final String to, final double amount) {
|
||||||
return core.transfer(from, to, amount);
|
return this.core.transfer(from, to, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean transfer(final UUID from, final UUID to, final double amount) {
|
||||||
|
return this.core.transfer(from, to, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the balance of the given account name
|
* Withdraws a given amount of money from the given username and turns it to
|
||||||
|
* thin air.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The name of the account
|
* The exact (case insensitive) username to take money from
|
||||||
* @return Their current balance.
|
* @param amount
|
||||||
|
* The amount to take from them
|
||||||
|
* @return True if success, false if they didn't have enough cash
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public double getBalance(String name) {
|
public boolean withdraw(final String name, final double amount) {
|
||||||
return core.getBalance(name);
|
return this.core.withdraw(name, amount);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
|
|
||||||
* Dollars 5 Cents
|
|
||||||
*
|
|
||||||
* @param balance
|
|
||||||
* The given number
|
|
||||||
* @return The balance in human readable text.
|
|
||||||
*/
|
|
||||||
public String format(double balance) {
|
|
||||||
return core.format(balance);
|
|
||||||
}
|
|
||||||
@Deprecated
|
|
||||||
public boolean has(String name, double amount) {
|
|
||||||
return core.getBalance(name) >= amount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public boolean withdraw(final UUID name, final double amount) {
|
||||||
return core.getClass().getName().split("_")[1];
|
return this.core.withdraw(name, amount);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean deposit(UUID name, double amount) {
|
|
||||||
return core.deposit(name,amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean withdraw(UUID name, double amount) {
|
|
||||||
return core.withdraw(name, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean transfer(UUID from, UUID to, double amount) {
|
|
||||||
return core.transfer(from, to, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getBalance(UUID name) {
|
|
||||||
return core.getBalance(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,12 +6,7 @@ import java.util.UUID;
|
|||||||
* @author netherfoam Represents an economy.
|
* @author netherfoam Represents an economy.
|
||||||
*/
|
*/
|
||||||
public interface EconomyCore {
|
public interface EconomyCore {
|
||||||
/**
|
public String currencyNamePlural();
|
||||||
* Checks that this economy is valid. Returns false if it is not valid.
|
|
||||||
*
|
|
||||||
* @return True if this economy will work, false if it will not.
|
|
||||||
*/
|
|
||||||
public boolean isValid();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deposits a given amount of money from thin air to the given username.
|
* Deposits a given amount of money from thin air to the given username.
|
||||||
@ -26,17 +21,51 @@ public interface EconomyCore {
|
|||||||
public boolean deposit(String name, double amount);
|
public boolean deposit(String name, double amount);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Withdraws a given amount of money from the given username and turns it to
|
* Deposits a given amount of money from thin air to the given username.
|
||||||
* thin air.
|
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The exact (case insensitive) username to take money from
|
* The exact (case insensitive) username to give money to
|
||||||
* @param amount
|
* @param amount
|
||||||
* The amount to take from them
|
* The amount to give them
|
||||||
* @return True if success, false if they didn't have enough cash
|
* @return True if success (Should be almost always)
|
||||||
|
*/
|
||||||
|
public boolean deposit(UUID name, double amount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
|
||||||
|
* Dollars 5 Cents
|
||||||
|
*
|
||||||
|
* @param balance
|
||||||
|
* The given number
|
||||||
|
* @return The balance in human readable text.
|
||||||
|
*/
|
||||||
|
public String format(double balance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the balance of the given account name
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the account
|
||||||
|
* @return Their current balance.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean withdraw(String name, double amount);
|
public double getBalance(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the balance of the given account name
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the account
|
||||||
|
* @return Their current balance.
|
||||||
|
*/
|
||||||
|
public double getBalance(UUID name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that this economy is valid. Returns false if it is not valid.
|
||||||
|
*
|
||||||
|
* @return True if this economy will work, false if it will not.
|
||||||
|
*/
|
||||||
|
public boolean isValid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfers the given amount of money from Player1 to Player2
|
* Transfers the given amount of money from Player1 to Player2
|
||||||
@ -53,55 +82,6 @@ public interface EconomyCore {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean transfer(String from, String to, double amount);
|
public boolean transfer(String from, String to, double amount);
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the balance of the given account name
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The name of the account
|
|
||||||
* @return Their current balance.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public double getBalance(String name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
|
|
||||||
* Dollars 5 Cents
|
|
||||||
*
|
|
||||||
* @param balance
|
|
||||||
* The given number
|
|
||||||
* @return The balance in human readable text.
|
|
||||||
*/
|
|
||||||
public String format(double balance);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deposits a given amount of money from thin air to the given username.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The exact (case insensitive) username to give money to
|
|
||||||
* @param amount
|
|
||||||
* The amount to give them
|
|
||||||
* @return True if success (Should be almost always)
|
|
||||||
*/
|
|
||||||
public boolean deposit(UUID name, double amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Withdraws a given amount of money from the given username and turns it to
|
|
||||||
* thin air.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The exact (case insensitive) username to take money from
|
|
||||||
* @param amount
|
|
||||||
* The amount to take from them
|
|
||||||
* @return True if success, false if they didn't have enough cash
|
|
||||||
*/
|
|
||||||
public boolean withdraw(UUID name, double amount);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfers the given amount of money from Player1 to Player2
|
* Transfers the given amount of money from Player1 to Player2
|
||||||
*
|
*
|
||||||
@ -117,11 +97,27 @@ public interface EconomyCore {
|
|||||||
public boolean transfer(UUID from, UUID to, double amount);
|
public boolean transfer(UUID from, UUID to, double amount);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the balance of the given account name
|
* Withdraws a given amount of money from the given username and turns it to
|
||||||
|
* thin air.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The name of the account
|
* The exact (case insensitive) username to take money from
|
||||||
* @return Their current balance.
|
* @param amount
|
||||||
|
* The amount to take from them
|
||||||
|
* @return True if success, false if they didn't have enough cash
|
||||||
*/
|
*/
|
||||||
public double getBalance(UUID name);
|
@Deprecated
|
||||||
|
public boolean withdraw(String name, double amount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraws a given amount of money from the given username and turns it to
|
||||||
|
* thin air.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The exact (case insensitive) username to take money from
|
||||||
|
* @param amount
|
||||||
|
* The amount to take from them
|
||||||
|
* @return True if success, false if they didn't have enough cash
|
||||||
|
*/
|
||||||
|
public boolean withdraw(UUID name, double amount);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@ public class Economy_Vault implements EconomyCore {
|
|||||||
setupEconomy();
|
setupEconomy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String currencyNamePlural() {
|
||||||
|
return this.vault.currencyNamePlural();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean deposit(final String name, final double amount) {
|
public boolean deposit(final String name, final double amount) {
|
||||||
@ -31,7 +36,7 @@ public class Economy_Vault implements EconomyCore {
|
|||||||
public String format(final double balance) {
|
public String format(final double balance) {
|
||||||
try {
|
try {
|
||||||
return this.vault.format(balance);
|
return this.vault.format(balance);
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException ignored) {
|
||||||
}
|
}
|
||||||
return "" + balance;
|
return "" + balance;
|
||||||
}
|
}
|
||||||
@ -99,10 +104,13 @@ public class Economy_Vault implements EconomyCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupEconomy() {
|
private boolean setupEconomy() {
|
||||||
|
try {
|
||||||
final RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServicesManager().getRegistration(Economy.class);
|
final RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServicesManager().getRegistration(Economy.class);
|
||||||
if (economyProvider != null) {
|
if (economyProvider != null) {
|
||||||
this.vault = (economyProvider.getProvider());
|
vault = (economyProvider.getProvider());
|
||||||
}
|
}
|
||||||
return this.vault != null;
|
} catch (final Exception ignored) {
|
||||||
|
}
|
||||||
|
return vault != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,6 +22,8 @@ import org.maxgamer.QuickShop.Shop.ShopAction;
|
|||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
import org.maxgamer.QuickShop.Util.MsgUtil;
|
||||||
import org.maxgamer.QuickShop.Util.Util;
|
import org.maxgamer.QuickShop.Util.Util;
|
||||||
|
|
||||||
|
import pw.yumc.YumCore.bukkit.Log;
|
||||||
|
|
||||||
public class BlockListener implements Listener {
|
public class BlockListener implements Listener {
|
||||||
private final QuickShop plugin;
|
private final QuickShop plugin;
|
||||||
|
|
||||||
@ -39,9 +41,7 @@ public class BlockListener implements Listener {
|
|||||||
// If the shop was a chest
|
// If the shop was a chest
|
||||||
if (b.getState() instanceof InventoryHolder) {
|
if (b.getState() instanceof InventoryHolder) {
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
if (shop == null) {
|
if (shop == null) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If they're either survival or the owner, they can break it
|
// If they're either survival or the owner, they can break it
|
||||||
final ItemStack pinh = p.getItemInHand();
|
final ItemStack pinh = p.getItemInHand();
|
||||||
if (p.getName().equals(shop.getOwner()) || p.getGameMode() == GameMode.SURVIVAL || pinh == null || pinh.getType() == plugin.getConfigManager().getSuperItem()) {
|
if (p.getName().equals(shop.getOwner()) || p.getGameMode() == GameMode.SURVIVAL || pinh == null || pinh.getType() == plugin.getConfigManager().getSuperItem()) {
|
||||||
@ -55,53 +55,57 @@ public class BlockListener implements Listener {
|
|||||||
} else {
|
} else {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
p.sendMessage(MsgUtil.p("no-creative-break"));
|
p.sendMessage(MsgUtil.p("no-creative-break"));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else if (b.getType() == Material.WALL_SIGN) {
|
} else if (b.getType() == Material.WALL_SIGN) {
|
||||||
final Shop shop = getShopNextTo(b.getLocation());
|
final Shop shop = getShopNextTo(b.getLocation());
|
||||||
if (shop == null) {
|
if (shop == null) { return; }
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles shops breaking through explosions
|
* Handles shops breaking through explosions
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onExplode(final EntityExplodeEvent e) {
|
public void onExplode(final EntityExplodeEvent e) {
|
||||||
if (e.isCancelled()) {
|
if (e.isCancelled()) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < e.blockList().size(); i++) {
|
for (int i = 0; i < e.blockList().size(); i++) {
|
||||||
final Block b = e.blockList().get(i);
|
Block b = e.blockList().get(i);
|
||||||
|
if (b.getType() == Material.WALL_SIGN) {
|
||||||
|
b = Util.getAttached(b);
|
||||||
|
}
|
||||||
|
if (b != null) {
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
if (shop != null) {
|
if (shop != null) {
|
||||||
shop.delete();
|
shop.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for chest placement, so a doublechest shop can't be created.
|
* Listens for chest placement, so a doublechest shop can't be created.
|
||||||
*/
|
*/
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onPlace(final BlockPlaceEvent e) {
|
public void onPlace(final BlockPlaceEvent e) {
|
||||||
if (e.isCancelled()) {
|
if (e.isCancelled()) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final BlockState bs = e.getBlock().getState();
|
final BlockState bs = e.getBlock().getState();
|
||||||
if (bs instanceof DoubleChest == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Block b = e.getBlock();
|
final Block b = e.getBlock();
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
final Block chest = Util.getSecondHalf(b);
|
final Block chest = Util.getSecondHalf(b);
|
||||||
if (chest != null && plugin.getShopManager().getShop(chest.getLocation()) != null && !p.hasPermission("quickshop.create.double")) {
|
if (chest != null) {
|
||||||
|
Shop shop = plugin.getShopManager().getShop(chest.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
if (!p.getName().equals(shop.getOwner())) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
p.sendMessage(MsgUtil.p("no-double-chests"));
|
p.sendMessage(MsgUtil.p("no-double-chests"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!p.hasPermission("quickshop.create.double")) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
p.sendMessage(MsgUtil.p("no-double-chests"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +119,7 @@ public class BlockListener implements Listener {
|
|||||||
private Shop getShopNextTo(final Location loc) {
|
private Shop getShopNextTo(final Location loc) {
|
||||||
final Block b = Util.getAttached(loc.getBlock());
|
final Block b = Util.getAttached(loc.getBlock());
|
||||||
// Util.getAttached(b)
|
// Util.getAttached(b)
|
||||||
if (b == null) {
|
if (b == null) { return null; }
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return plugin.getShopManager().getShop(b.getLocation());
|
return plugin.getShopManager().getShop(b.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package org.maxgamer.QuickShop.Listeners;
|
package org.maxgamer.QuickShop.Listeners;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@ -7,12 +8,10 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
|
|||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Netherfoam
|
* @author Netherfoam
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ChatListener implements Listener {
|
public class ChatListener implements Listener {
|
||||||
QuickShop plugin;
|
private QuickShop plugin;
|
||||||
|
|
||||||
public ChatListener(final QuickShop plugin) {
|
public ChatListener(final QuickShop plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -23,7 +22,7 @@ public class ChatListener implements Listener {
|
|||||||
if (!plugin.getShopManager().getActions().containsKey(e.getPlayer().getName())) {
|
if (!plugin.getShopManager().getActions().containsKey(e.getPlayer().getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
plugin.getShopManager().handleChat(e.getPlayer(), e.getMessage());
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> plugin.getShopManager().handleChat(e.getPlayer(), e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,21 +12,17 @@ import org.bukkit.event.world.ChunkUnloadEvent;
|
|||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
|
|
||||||
public class ChunkListener implements Listener {
|
import pw.yumc.YumCore.bukkit.P;
|
||||||
private QuickShop plugin;
|
|
||||||
|
|
||||||
public ChunkListener(QuickShop plugin) {
|
public class ChunkListener implements Listener {
|
||||||
this.plugin = plugin;
|
private QuickShop plugin = P.getPlugin();
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onChunkLoad(ChunkLoadEvent e) {
|
public void onChunkLoad(ChunkLoadEvent e) {
|
||||||
Chunk c = e.getChunk();
|
Chunk c = e.getChunk();
|
||||||
if (plugin.getShopManager().getShops() == null)
|
if (plugin.getShopManager().getShops() == null) return;
|
||||||
return;
|
|
||||||
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
|
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
|
||||||
if (inChunk == null)
|
if (inChunk == null) return;
|
||||||
return;
|
|
||||||
for (Shop shop : inChunk.values()) {
|
for (Shop shop : inChunk.values()) {
|
||||||
shop.onLoad();
|
shop.onLoad();
|
||||||
}
|
}
|
||||||
@ -36,8 +32,7 @@ public class ChunkListener implements Listener {
|
|||||||
public void onChunkUnload(ChunkUnloadEvent e) {
|
public void onChunkUnload(ChunkUnloadEvent e) {
|
||||||
Chunk c = e.getChunk();
|
Chunk c = e.getChunk();
|
||||||
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
|
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
|
||||||
if (inChunk == null)
|
if (inChunk == null) return;
|
||||||
return;
|
|
||||||
for (Shop shop : inChunk.values()) {
|
for (Shop shop : inChunk.values()) {
|
||||||
shop.onUnload();
|
shop.onUnload();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package org.maxgamer.QuickShop.Listeners;
|
package org.maxgamer.QuickShop.Listeners;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -33,80 +36,96 @@ public class LockListener implements Listener {
|
|||||||
// If the chest was a chest
|
// If the chest was a chest
|
||||||
if (Util.canBeShop(b)) {
|
if (Util.canBeShop(b)) {
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
if (shop == null) {
|
if (shop == null) { return; // Wasn't a shop
|
||||||
return; // Wasn't a shop
|
|
||||||
}
|
}
|
||||||
// If they owned it or have bypass perms, they can destroy it
|
// If they owned it or have bypass perms, they can destroy it
|
||||||
if (!shop.getOwner().equals(p.getName()) && !p.hasPermission("quickshop.other.destroy")) {
|
if (!shop.getOwner().equals(p.getName()) && !p.hasPermission("quickshop.other.destroy")) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
p.sendMessage(MsgUtil.p("no-permission"));
|
p.sendMessage(MsgUtil.p("no-permission"));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else if (b.getType() == Material.WALL_SIGN) {
|
} else if (b.getType() == Material.WALL_SIGN) {
|
||||||
b = Util.getAttached(b);
|
b = Util.getAttached(b);
|
||||||
if (b == null) {
|
if (b == null) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
if (shop == null) {
|
if (shop == null) { return; }
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onClick(final PlayerInteractEvent e) {
|
public void onClick(final PlayerInteractEvent e) {
|
||||||
Block b = e.getClickedBlock();
|
Block b = e.getClickedBlock();
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) { return; // Didn't right click it, we dont care.
|
||||||
return; // Didn't right click it, we dont care.
|
|
||||||
}
|
}
|
||||||
if (!Util.canBeShop(b)) {
|
if (!Util.canBeShop(b)) { return; // Interacted with air
|
||||||
return; // Interacted with air
|
|
||||||
}
|
}
|
||||||
Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
// Make sure they're not using the non-shop half of a double chest.
|
// Make sure they're not using the non-shop half of a double chest.
|
||||||
if (shop == null) {
|
if (!hasSecondHalf(shop, b)) { return; }
|
||||||
b = Util.getSecondHalf(b);
|
if (shop != null && !p.getName().equals(shop.getOwner())) {
|
||||||
if (b == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
shop = plugin.getShopManager().getShop(b.getLocation());
|
|
||||||
if (shop == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!shop.getOwner().equals(p.getName())) {
|
|
||||||
if (p.hasPermission("quickshop.other.open")) {
|
if (p.hasPermission("quickshop.other.open")) {
|
||||||
p.sendMessage(MsgUtil.p("bypassing-lock"));
|
p.sendMessage(MsgUtil.p("bypassing-lock"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.sendMessage(MsgUtil.p("that-is-locked"));
|
p.sendMessage(MsgUtil.p("that-is-locked"));
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasSecondHalf(Shop shop, Block b) {
|
||||||
|
if (shop == null) {
|
||||||
|
b = Util.getSecondHalf(b);
|
||||||
|
if (b == null) { return false; }
|
||||||
|
shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
if (shop == null) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles shops breaking through explosions
|
* Handles shops breaking through explosions
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.LOW)
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
public void onExplode(final EntityExplodeEvent e) {
|
public void onExplode(final EntityExplodeEvent e) {
|
||||||
if (e.isCancelled()) {
|
if (e.isCancelled()) { return; }
|
||||||
return;
|
List<Block> removed = new ArrayList<>();
|
||||||
}
|
|
||||||
for (int i = 0; i < e.blockList().size(); i++) {
|
for (int i = 0; i < e.blockList().size(); i++) {
|
||||||
final Block b = e.blockList().get(i);
|
Block b = e.blockList().get(i);
|
||||||
final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
if (shop != null) {
|
if (shop != null) {
|
||||||
// ToDo: Shouldn't I be decrementing 1 here? Concurrency and
|
removed.add(b);
|
||||||
// all..
|
} else if (b.getType() == Material.WALL_SIGN) {
|
||||||
e.blockList().remove(b);
|
Block s = Util.getAttached(b);
|
||||||
|
if (s != null) {
|
||||||
|
shop = plugin.getShopManager().getShop(s.getLocation());
|
||||||
|
if (shop != null) {
|
||||||
|
removed.add(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
e.blockList().removeAll(removed);
|
||||||
|
// for (int i = 0; i < e.blockList().size(); i++) {
|
||||||
|
// Block b = e.blockList().get(i);
|
||||||
|
// if (b.getType() == Material.WALL_SIGN) {
|
||||||
|
// Block s = Util.getAttached(b);
|
||||||
|
// if (s != null) {
|
||||||
|
// final Shop shop = plugin.getShopManager().getShop(s.getLocation());
|
||||||
|
// if (shop != null) {
|
||||||
|
// // ToDo: Shouldn't I be decrementing 1 here? Concurrency and all..
|
||||||
|
// e.blockList().remove(b);
|
||||||
|
// e.blockList().remove(s);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// final Shop shop = plugin.getShopManager().getShop(b.getLocation());
|
||||||
|
// if (shop != null) {
|
||||||
|
// // ToDo: Shouldn't I be decrementing 1 here? Concurrency and all..
|
||||||
|
// e.blockList().remove(b);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles hopper placement
|
* Handles hopper placement
|
||||||
@ -115,37 +134,22 @@ public class LockListener implements Listener {
|
|||||||
public void onPlace(final BlockPlaceEvent e) {
|
public void onPlace(final BlockPlaceEvent e) {
|
||||||
final Block b = e.getBlock();
|
final Block b = e.getBlock();
|
||||||
try {
|
try {
|
||||||
if (b.getType() != Material.HOPPER) {
|
if (b.getType() != Material.HOPPER) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (final NoSuchFieldError er) {
|
} catch (final NoSuchFieldError er) {
|
||||||
return; // Your server doesn't have hoppers
|
return; // Your server doesn't have hoppers
|
||||||
}
|
}
|
||||||
Block c = e.getBlockAgainst();
|
Block c = e.getBlockAgainst();
|
||||||
if (Util.canBeShop(c) == false) {
|
if (!Util.canBeShop(c)) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
Shop shop = plugin.getShopManager().getShop(c.getLocation());
|
Shop shop = plugin.getShopManager().getShop(c.getLocation());
|
||||||
if (shop == null) {
|
if (!hasSecondHalf(shop, b)) { return; }
|
||||||
c = Util.getSecondHalf(c);
|
if (!p.getName().equals(shop.getOwner())) {
|
||||||
if (c == null) {
|
|
||||||
return; // You didn't place a hopper on a shop. Meh.
|
|
||||||
} else {
|
|
||||||
shop = plugin.getShopManager().getShop(c.getLocation());
|
|
||||||
}
|
|
||||||
if (shop == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p.getName().equals(shop.getOwner()) == false) {
|
|
||||||
if (p.hasPermission("quickshop.other.open")) {
|
if (p.hasPermission("quickshop.other.open")) {
|
||||||
p.sendMessage(MsgUtil.p("bypassing-lock"));
|
p.sendMessage(MsgUtil.p("bypassing-lock"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.sendMessage(MsgUtil.p("that-is-locked"));
|
p.sendMessage(MsgUtil.p("that-is-locked"));
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package org.maxgamer.QuickShop.Listeners;
|
package org.maxgamer.QuickShop.Listeners;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
@ -16,7 +16,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
|
|||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.util.BlockIterator;
|
import org.bukkit.util.BlockIterator;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
@ -34,18 +34,15 @@ public class PlayerListener implements Listener {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
/**
|
/**
|
||||||
* Handles players left clicking a chest. Left click a NORMAL chest with
|
* Handles players left clicking a chest. Left click a NORMAL chest with
|
||||||
* item : Send creation menu Left click a SHOP chest : Send purchase menu
|
* item : Send creation menu Left click a SHOP chest : Send purchase menu
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onClick(final PlayerInteractEvent e) {
|
public void onClick(final PlayerInteractEvent e) {
|
||||||
final Block b = e.getClickedBlock();
|
final Block b = e.getClickedBlock();
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
if (e.getAction() != Action.LEFT_CLICK_BLOCK || (e.getMaterial() == plugin.getConfigManager().getSuperItem() && b.getType() == Material.WALL_SIGN)) {
|
if (e.getAction() != Action.LEFT_CLICK_BLOCK || p.getGameMode() == GameMode.CREATIVE) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Location loc = b.getLocation();
|
final Location loc = b.getLocation();
|
||||||
final ItemStack item = e.getItem();
|
final ItemStack item = e.getItem();
|
||||||
// Get the shop
|
// Get the shop
|
||||||
@ -62,17 +59,15 @@ public class PlayerListener implements Listener {
|
|||||||
shop.onClick();
|
shop.onClick();
|
||||||
// Text menu
|
// Text menu
|
||||||
MsgUtil.sendShopInfo(p, shop);
|
MsgUtil.sendShopInfo(p, shop);
|
||||||
if (shop.isSelling()) {
|
if (!plugin.getConfigManager().isEnableMagicLib() && b.getType() == Material.WALL_SIGN) {
|
||||||
p.sendMessage(MsgUtil.p("how-many-buy"));
|
final Inventory in = Bukkit.createInventory(null, 9, plugin.getConfigManager().getGuiTitle());
|
||||||
} else {
|
in.setItem(4, shop.getItem());
|
||||||
final int items = Util.countItems(p.getInventory(), shop.getItem());
|
p.openInventory(in);
|
||||||
p.sendMessage(MsgUtil.p("how-many-sell", items));
|
|
||||||
}
|
}
|
||||||
// Add the new action
|
// Add the new action
|
||||||
final HashMap<String, Info> actions = plugin.getShopManager().getActions();
|
final Map<String, Info> actions = plugin.getShopManager().getActions();
|
||||||
final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop);
|
final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop);
|
||||||
actions.put(p.getName(), info);
|
actions.put(p.getName(), info);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// Handles creating shops
|
// Handles creating shops
|
||||||
else if (shop == null && item != null && item.getType() != Material.AIR && p.hasPermission("quickshop.create.sell") && Util.canBeShop(b) && p.getGameMode() != GameMode.CREATIVE
|
else if (shop == null && item != null && item.getType() != Material.AIR && p.hasPermission("quickshop.create.sell") && Util.canBeShop(b) && p.getGameMode() != GameMode.CREATIVE
|
||||||
@ -139,7 +134,6 @@ public class PlayerListener implements Listener {
|
|||||||
p.sendMessage(MsgUtil.p("shop-purchase-cancelled"));
|
p.sendMessage(MsgUtil.p("shop-purchase-cancelled"));
|
||||||
}
|
}
|
||||||
plugin.getShopManager().getActions().remove(p.getName());
|
plugin.getShopManager().getActions().remove(p.getName());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,44 +144,43 @@ public class PlayerListener implements Listener {
|
|||||||
plugin.getShopManager().getActions().remove(e.getPlayer().getName());
|
plugin.getShopManager().getActions().remove(e.getPlayer().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onSuperItemClick(final PlayerInteractEvent e) {
|
public void onSuperItemClick(final PlayerInteractEvent e) {
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
if (p.getGameMode() != GameMode.SURVIVAL || e.getMaterial() != plugin.getConfigManager().getSuperItem()) {
|
if (p.getGameMode() != GameMode.SURVIVAL || e.getMaterial() != plugin.getConfigManager().getSuperItem()) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Block b = e.getClickedBlock();
|
final Block b = e.getClickedBlock();
|
||||||
|
if (b == null || b.getType() == null) { return; }
|
||||||
// If that wasn't a shop, search nearby shops
|
// If that wasn't a shop, search nearby shops
|
||||||
if (b.getType() == Material.WALL_SIGN) {
|
if (b.getType() == Material.WALL_SIGN) {
|
||||||
final Block attached = Util.getAttached(b);
|
final Block attached = Util.getAttached(b);
|
||||||
final Shop shop = attached == null ? null : plugin.getShopManager().getShop(attached.getLocation());
|
final Shop shop = attached == null ? null : plugin.getShopManager().getShop(attached.getLocation());
|
||||||
if (shop != null) {
|
if (shop != null) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
final Location loc = shop.getLocation();
|
||||||
|
String shopmode = "";
|
||||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||||
if (p.hasPermission("quickshop.unlimited")) {
|
if (p.hasPermission("quickshop.unlimited") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
|
||||||
shop.setUnlimited(!shop.isUnlimited());
|
shop.setUnlimited(!shop.isUnlimited());
|
||||||
p.sendMessage(MsgUtil.p("command.toggle-unlimited", (shop.isUnlimited() ? "§e无限模式" : "§c有限模式")));
|
shopmode = shop.isUnlimited() ? "§e无限模式" : "§c有限模式";
|
||||||
return;
|
p.sendMessage(MsgUtil.p("command.toggle-unlimited", shopmode));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (shop.getShopType() == ShopType.BUYING && p.hasPermission("quickshop.create.sell")) {
|
if (shop.getShopType() == ShopType.BUYING && p.hasPermission("quickshop.create.sell") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
|
||||||
shop.setShopType(ShopType.SELLING);
|
shop.setShopType(ShopType.SELLING);
|
||||||
p.sendMessage(MsgUtil.p("command.now-selling", shop.getDataName()));
|
p.sendMessage(MsgUtil.p("command.now-selling", shop.getDataName()));
|
||||||
return;
|
shopmode = "出售模式";
|
||||||
} else if (shop.getShopType() == ShopType.SELLING && p.hasPermission("quickshop.create.buy")) {
|
} else if (shop.getShopType() == ShopType.SELLING && p.hasPermission("quickshop.create.buy") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
|
||||||
shop.setShopType(ShopType.BUYING);
|
shop.setShopType(ShopType.BUYING);
|
||||||
p.sendMessage(MsgUtil.p("command.now-buying", shop.getDataName()));
|
p.sendMessage(MsgUtil.p("command.now-buying", shop.getDataName()));
|
||||||
return;
|
shopmode = "收购模式";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!shopmode.isEmpty()) {
|
||||||
|
plugin.log(String.format("玩家: %s 将 %s(%s,%s,%s) 的商店切换为 %s !", p.getName(), loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), shopmode));
|
||||||
|
}
|
||||||
shop.setSignText();
|
shop.setSignText();
|
||||||
shop.update();
|
shop.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
public void onTeleport(final PlayerTeleportEvent e) {
|
|
||||||
final PlayerMoveEvent me = new PlayerMoveEvent(e.getPlayer(), e.getFrom(), e.getTo());
|
|
||||||
onMove(me);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -2,11 +2,12 @@ package org.maxgamer.QuickShop.Listeners;
|
|||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.block.DoubleChest;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.ItemDespawnEvent;
|
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||||
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||||
@ -14,8 +15,11 @@ import org.bukkit.event.inventory.InventoryType;
|
|||||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
import org.maxgamer.QuickShop.Util.MarkUtil;
|
import org.maxgamer.QuickShop.Util.MarkUtil;
|
||||||
|
|
||||||
public class ProtectListener implements Listener {
|
public class ProtectListener implements Listener {
|
||||||
@ -26,18 +30,39 @@ public class ProtectListener implements Listener {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Shop getShop(final Inventory inv) {
|
||||||
|
if (inv == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InventoryHolder holder = inv.getHolder();
|
||||||
|
if (holder instanceof DoubleChest) {
|
||||||
|
holder = ((DoubleChest) holder).getLeftSide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holder instanceof BlockState) {
|
||||||
|
final Block block = ((BlockState) holder).getBlock();
|
||||||
|
final Shop sp = plugin.getShopManager().getShop(block.getLocation());
|
||||||
|
if (sp != null) {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInvMove(final InventoryMoveItemEvent e) {
|
public void onInvMove(final InventoryMoveItemEvent e) {
|
||||||
final ItemStack ci = e.getItem();
|
final ItemStack ci = e.getItem();
|
||||||
if (MarkUtil.hasMark(ci)) {
|
if (MarkUtil.hasMark(ci)) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
final ItemStack[] items = e.getSource().getContents();
|
|
||||||
for (final ItemStack itemStack : items) {
|
|
||||||
if (MarkUtil.hasMark(itemStack)) {
|
|
||||||
itemStack.setType(Material.AIR);
|
|
||||||
}
|
}
|
||||||
}
|
final Inventory src = e.getSource();
|
||||||
e.getSource().setContents(items);
|
final Inventory me = e.getInitiator();
|
||||||
|
final Inventory des = e.getDestination();
|
||||||
|
final Shop srcshop = getShop(src);
|
||||||
|
final Shop meshop = getShop(me);
|
||||||
|
final Shop desshop = getShop(des);
|
||||||
|
if (srcshop != null && meshop == null || meshop != null && desshop == null || srcshop != null && srcshop.getOwner() != null && !srcshop.getOwner().equalsIgnoreCase(desshop.getOwner())) {
|
||||||
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +84,7 @@ public class ProtectListener implements Listener {
|
|||||||
final Inventory inv = e.getInventory();
|
final Inventory inv = e.getInventory();
|
||||||
final int solt = e.getSlot();
|
final int solt = e.getSlot();
|
||||||
if (inv.getType() != InventoryType.PLAYER && inv.getType() != InventoryType.HOPPER) {
|
if (inv.getType() != InventoryType.PLAYER && inv.getType() != InventoryType.HOPPER) {
|
||||||
if (inv.getTitle().equalsIgnoreCase(plugin.getConfigManager().getGuiTitle())) {
|
if (inv.getTitle() != null && inv.getTitle().equalsIgnoreCase(plugin.getConfigManager().getGuiTitle())) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
p.closeInventory();
|
p.closeInventory();
|
||||||
}
|
}
|
||||||
@ -68,32 +93,37 @@ public class ProtectListener implements Listener {
|
|||||||
try {
|
try {
|
||||||
if (MarkUtil.hasMark(ci)) {
|
if (MarkUtil.hasMark(ci)) {
|
||||||
inv.setItem(solt, new ItemStack(Material.AIR));
|
inv.setItem(solt, new ItemStack(Material.AIR));
|
||||||
Bukkit.broadcastMessage("§6[§b快捷商店§6] §4警告 " + p.getDisplayName() + " §c非法 §d§l获取 " + ci.getItemMeta().getDisplayName() + " §a已清理...");
|
sendWarning(p, ci, "§d§l获取");
|
||||||
p.closeInventory();
|
p.closeInventory();
|
||||||
}
|
}
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ignored) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
||||||
public void onItemDespawn(final ItemDespawnEvent e) {
|
|
||||||
final ItemStack ci = e.getEntity().getItemStack();
|
|
||||||
if (MarkUtil.hasMark(ci)) {
|
|
||||||
e.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerHandlerItem(final PlayerItemHeldEvent e) {
|
public void onPlayerHandlerItem(final PlayerItemHeldEvent e) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
final Player p = e.getPlayer();
|
final Player p = e.getPlayer();
|
||||||
final ItemStack[] cis = p.getInventory().getArmorContents();
|
final PlayerInventory inv = p.getInventory();
|
||||||
for (final ItemStack itemStack : cis) {
|
final ItemStack[] cis = inv.getArmorContents();
|
||||||
|
for (int i = 0; i < cis.length; i++) {
|
||||||
|
final ItemStack itemStack = cis[i];
|
||||||
if (MarkUtil.hasMark(itemStack)) {
|
if (MarkUtil.hasMark(itemStack)) {
|
||||||
Bukkit.broadcastMessage("§6[§b快捷商店§6] §4警告 " + p.getDisplayName() + " §c非法 §e§l穿戴 " + itemStack.getItemMeta().getDisplayName() + " §a已清理...");
|
cis[i] = new ItemStack(Material.AIR);
|
||||||
itemStack.setType(Material.AIR);
|
sendWarning(p, itemStack, "§e§l穿戴");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.getInventory().setArmorContents(cis);
|
inv.setArmorContents(cis);
|
||||||
|
final int newslot = e.getNewSlot();
|
||||||
|
final ItemStack newItem = inv.getItem(newslot);
|
||||||
|
if (MarkUtil.hasMark(newItem)) {
|
||||||
|
inv.setItem(newslot, new ItemStack(Material.AIR));
|
||||||
|
sendWarning(p, newItem, "§3§l使用");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -103,4 +133,29 @@ public class ProtectListener implements Listener {
|
|||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearIllegalItem(final Player player) {
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Inventory inv = player.getInventory();
|
||||||
|
int clearnum = 0;
|
||||||
|
for (final ItemStack itemStack : inv) {
|
||||||
|
if (MarkUtil.hasMark(itemStack)) {
|
||||||
|
inv.remove(itemStack);
|
||||||
|
clearnum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (clearnum != 0) {
|
||||||
|
Bukkit.broadcastMessage(plugin.getConfigManager().getGuiTitle() + " §4提示 §d扫描完毕 §d已清理 §a" + player.getName() + " §c非法获取的物品 §4" + clearnum + " §c个物品...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendWarning(final Player p, final ItemStack ci, final String action) {
|
||||||
|
Bukkit.broadcastMessage(plugin.getConfigManager().getGuiTitle() + " §4警告 " + p.getDisplayName() + " §c非法 " + action + " " + ci.getItemMeta().getDisplayName());
|
||||||
|
Bukkit.broadcastMessage(plugin.getConfigManager().getGuiTitle() + " §4提示 §d系统 §d已清理 §a" + p.getName() + " §c非法获取的物品 §a并扫描玩家背包...");
|
||||||
|
clearIllegalItem(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package org.maxgamer.QuickShop.Listeners;
|
package org.maxgamer.QuickShop.Listeners;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -14,6 +11,9 @@ import org.maxgamer.QuickShop.QuickShop;
|
|||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
import org.maxgamer.QuickShop.Shop.ShopChunk;
|
import org.maxgamer.QuickShop.Shop.ShopChunk;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class WorldListener implements Listener {
|
public class WorldListener implements Listener {
|
||||||
QuickShop plugin;
|
QuickShop plugin;
|
||||||
|
|
||||||
@ -32,16 +32,14 @@ public class WorldListener implements Listener {
|
|||||||
*/
|
*/
|
||||||
final World world = e.getWorld();
|
final World world = e.getWorld();
|
||||||
// New world data
|
// New world data
|
||||||
final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = new HashMap<ShopChunk, HashMap<Location, Shop>>(1);
|
final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = new HashMap<>(1);
|
||||||
// Old world data
|
// Old world data
|
||||||
final HashMap<ShopChunk, HashMap<Location, Shop>> oldInWorld = plugin.getShopManager().getShops(world.getName());
|
final HashMap<ShopChunk, HashMap<Location, Shop>> oldInWorld = plugin.getShopManager().getShops(world.getName());
|
||||||
// Nothing in the old world, therefore we don't care. No locations to
|
// Nothing in the old world, therefore we don't care. No locations to
|
||||||
// update.
|
// update.
|
||||||
if (oldInWorld == null) {
|
if (oldInWorld == null) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (final Entry<ShopChunk, HashMap<Location, Shop>> oldInChunk : oldInWorld.entrySet()) {
|
for (final Entry<ShopChunk, HashMap<Location, Shop>> oldInChunk : oldInWorld.entrySet()) {
|
||||||
final HashMap<Location, Shop> inChunk = new HashMap<Location, Shop>(1);
|
final HashMap<Location, Shop> inChunk = new HashMap<>(1);
|
||||||
// Put the new chunk were the old chunk was
|
// Put the new chunk were the old chunk was
|
||||||
inWorld.put(oldInChunk.getKey(), inChunk);
|
inWorld.put(oldInChunk.getKey(), inChunk);
|
||||||
for (final Entry<Location, Shop> entry : oldInChunk.getValue().entrySet()) {
|
for (final Entry<Location, Shop> entry : oldInChunk.getValue().entrySet()) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.maxgamer.QuickShop;
|
package org.maxgamer.QuickShop;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
@ -21,12 +20,12 @@ import org.bukkit.configuration.file.FileConfiguration;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
import org.maxgamer.QuickShop.Command.QuickShopCommands;
|
import org.maxgamer.QuickShop.Command.QuickShopCommands;
|
||||||
import org.maxgamer.QuickShop.Config.ConfigManager;
|
import org.maxgamer.QuickShop.Config.ConfigManager;
|
||||||
import org.maxgamer.QuickShop.Config.ItemConfig;
|
|
||||||
import org.maxgamer.QuickShop.Database.Database;
|
import org.maxgamer.QuickShop.Database.Database;
|
||||||
import org.maxgamer.QuickShop.Database.DatabaseCore;
|
import org.maxgamer.QuickShop.Database.DatabaseCore;
|
||||||
import org.maxgamer.QuickShop.Database.DatabaseHelper;
|
import org.maxgamer.QuickShop.Database.DatabaseHelper;
|
||||||
@ -37,7 +36,6 @@ import org.maxgamer.QuickShop.Economy.EconomyCore;
|
|||||||
import org.maxgamer.QuickShop.Economy.Economy_Vault;
|
import org.maxgamer.QuickShop.Economy.Economy_Vault;
|
||||||
import org.maxgamer.QuickShop.Listeners.BlockListener;
|
import org.maxgamer.QuickShop.Listeners.BlockListener;
|
||||||
import org.maxgamer.QuickShop.Listeners.ChatListener;
|
import org.maxgamer.QuickShop.Listeners.ChatListener;
|
||||||
import org.maxgamer.QuickShop.Listeners.ChunkListener;
|
|
||||||
import org.maxgamer.QuickShop.Listeners.LockListener;
|
import org.maxgamer.QuickShop.Listeners.LockListener;
|
||||||
import org.maxgamer.QuickShop.Listeners.PlayerListener;
|
import org.maxgamer.QuickShop.Listeners.PlayerListener;
|
||||||
import org.maxgamer.QuickShop.Listeners.ProtectListener;
|
import org.maxgamer.QuickShop.Listeners.ProtectListener;
|
||||||
@ -48,41 +46,30 @@ import org.maxgamer.QuickShop.Shop.ShopManager;
|
|||||||
import org.maxgamer.QuickShop.Shop.ShopType;
|
import org.maxgamer.QuickShop.Shop.ShopType;
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
import org.maxgamer.QuickShop.Util.MsgUtil;
|
||||||
import org.maxgamer.QuickShop.Util.Util;
|
import org.maxgamer.QuickShop.Util.Util;
|
||||||
import org.maxgamer.QuickShop.Watcher.ItemWatcher;
|
|
||||||
import org.maxgamer.QuickShop.Watcher.LogWatcher;
|
import org.maxgamer.QuickShop.Watcher.LogWatcher;
|
||||||
import org.mcstats.Metrics;
|
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.config.FileConfig;
|
import pw.yumc.YumCore.config.FileConfig;
|
||||||
import cn.citycraft.PluginHelper.utils.VersionChecker;
|
import pw.yumc.YumCore.global.L10N;
|
||||||
import mkremins.fanciful.FancyMessage;
|
import pw.yumc.YumCore.statistic.Statistics;
|
||||||
|
import pw.yumc.YumCore.update.SubscribeTask;
|
||||||
|
|
||||||
public class QuickShop extends JavaPlugin {
|
public class QuickShop extends JavaPlugin {
|
||||||
/** The active instance of QuickShop */
|
/** 初始化 QuickShop 的接口 */
|
||||||
public static QuickShop instance;
|
public static QuickShop instance;
|
||||||
/** The plugin default config */
|
/** 插件的配置文件 */
|
||||||
public FileConfig config;
|
public FileConfig config;
|
||||||
// private HeroChatListener heroChatListener;
|
// private HeroChatListener heroChatListener;
|
||||||
// Listeners (These don't)
|
// Listeners (These don't)
|
||||||
private final BlockListener blockListener = new BlockListener(this);
|
|
||||||
// Listeners - We decide which one to use at runtime
|
|
||||||
private ChatListener chatListener;
|
|
||||||
private final ChunkListener chunkListener = new ChunkListener(this);
|
|
||||||
/** The Config Manager used to read config */
|
/** The Config Manager used to read config */
|
||||||
private ConfigManager configManager;
|
private ConfigManager configManager;
|
||||||
|
|
||||||
/** The database for storing all our data for persistence */
|
/** The database for storing all our data for persistence */
|
||||||
private Database database;
|
private Database database;
|
||||||
/** The economy we hook into for transactions */
|
/** The economy we hook into for transactions */
|
||||||
private Economy economy;
|
private Economy economy;
|
||||||
private boolean enableMagicLib;
|
public BukkitTask itemWatcherTask;
|
||||||
private BukkitTask itemWatcherTask;
|
|
||||||
|
|
||||||
private LogWatcher logWatcher;
|
private LogWatcher logWatcher;
|
||||||
private final PlayerListener playerListener = new PlayerListener(this);
|
|
||||||
private final ProtectListener protectListener = new ProtectListener(this);
|
|
||||||
/** The Shop Manager used to store shops */
|
/** The Shop Manager used to store shops */
|
||||||
private ShopManager shopManager;
|
private ShopManager shopManager;
|
||||||
private final WorldListener worldListener = new WorldListener(this);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints debug information if QuickShop is configured to do so.
|
* Prints debug information if QuickShop is configured to do so.
|
||||||
@ -91,9 +78,7 @@ public class QuickShop extends JavaPlugin {
|
|||||||
* The string to print.
|
* The string to print.
|
||||||
*/
|
*/
|
||||||
public void debug(final String s) {
|
public void debug(final String s) {
|
||||||
if (!configManager.isDebug()) {
|
if (!configManager.isDebug()) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.getLogger().info(ChatColor.YELLOW + "[Debug] " + s);
|
this.getLogger().info(ChatColor.YELLOW + "[Debug] " + s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,8 +107,6 @@ public class QuickShop extends JavaPlugin {
|
|||||||
return economy;
|
return economy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The plugin metrics from Hidendra */
|
|
||||||
// public Metrics getMetrics(){ return metrics; }
|
|
||||||
public int getShopLimit(final Player p) {
|
public int getShopLimit(final Player p) {
|
||||||
int max = configManager.getLimitdefault();
|
int max = configManager.getLimitdefault();
|
||||||
for (final Entry<String, Integer> entry : configManager.getLimits().entrySet()) {
|
for (final Entry<String, Integer> entry : configManager.getLimits().entrySet()) {
|
||||||
@ -144,10 +127,6 @@ public class QuickShop extends JavaPlugin {
|
|||||||
return this.shopManager;
|
return this.shopManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnableMagicLib() {
|
|
||||||
return enableMagicLib;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to load the economy and its core. If this fails, it will try to use
|
* Tries to load the economy and its core. If this fails, it will try to use
|
||||||
* vault. If that fails, it will return false.
|
* vault. If that fails, it will return false.
|
||||||
@ -158,124 +137,22 @@ public class QuickShop extends JavaPlugin {
|
|||||||
public boolean loadEcon() {
|
public boolean loadEcon() {
|
||||||
final EconomyCore core = new Economy_Vault();
|
final EconomyCore core = new Economy_Vault();
|
||||||
if (!core.isValid()) {
|
if (!core.isValid()) {
|
||||||
// getLogger().severe("Economy is not valid!");
|
|
||||||
getLogger().warning("无法找到经济管理类插件...");
|
getLogger().warning("无法找到经济管理类插件...");
|
||||||
getLogger().warning("卸载插件!!!");
|
getLogger().warning("卸载插件!!!");
|
||||||
this.getPluginLoader().disablePlugin(this);
|
this.getPluginLoader().disablePlugin(this);
|
||||||
// if(econ.equals("Vault"))
|
|
||||||
// getLogger().severe("(Does Vault have an Economy to hook into?!)");
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
this.economy = new Economy(core);
|
this.economy = new Economy(core);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void loadShop() {
|
||||||
* Logs the given string to qs.log, if QuickShop is configured to do so.
|
/* 从数据库载入商店信息到内存 */
|
||||||
*
|
int count = 0; // 商店个数
|
||||||
* @param s
|
|
||||||
* The string to log. It will be prefixed with the date and time.
|
|
||||||
*/
|
|
||||||
public void log(final String s) {
|
|
||||||
if (this.logWatcher == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Date date = Calendar.getInstance().getTime();
|
|
||||||
final Timestamp time = new Timestamp(date.getTime());
|
|
||||||
this.logWatcher.add("[" + time.toString() + "] " + s);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
if (itemWatcherTask != null) {
|
|
||||||
itemWatcherTask.cancel();
|
|
||||||
}
|
|
||||||
if (logWatcher != null) {
|
|
||||||
logWatcher.task.cancel();
|
|
||||||
logWatcher.close(); // Closes the file
|
|
||||||
}
|
|
||||||
/* Remove all display items, and any dupes we can find */
|
|
||||||
shopManager.clear();
|
|
||||||
/* Empty the buffer */
|
|
||||||
database.close();
|
|
||||||
try {
|
|
||||||
this.database.getConnection().close();
|
|
||||||
} catch (final SQLException e) {
|
|
||||||
}
|
|
||||||
configManager.getWarnings().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
instance = this;
|
|
||||||
if (loadEcon() == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Initialize Util
|
|
||||||
Util.initialize();
|
|
||||||
// Create the shop manager.
|
|
||||||
configManager = new ConfigManager(this);
|
|
||||||
shopManager = new ShopManager(this);
|
|
||||||
if (configManager.isLogAction()) {
|
|
||||||
// Logger Handler
|
|
||||||
this.logWatcher = new LogWatcher(this, new File(this.getDataFolder(), "qs.log"));
|
|
||||||
logWatcher.task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, this.logWatcher, 150, 150);
|
|
||||||
}
|
|
||||||
if (configManager.isShopLock()) {
|
|
||||||
final LockListener ll = new LockListener(this);
|
|
||||||
getServer().getPluginManager().registerEvents(ll, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
getLogger().info("尝试启动魔改库...");
|
|
||||||
final FancyMessage fm = new FancyMessage("test");
|
|
||||||
fm.then("item").itemTooltip(new ItemStack(Material.DIAMOND_SWORD));
|
|
||||||
fm.then("link").link("ci.citycraft.cn");
|
|
||||||
fm.then("suggest").suggest("qs help");
|
|
||||||
fm.toJSONString();
|
|
||||||
getLogger().info("魔改库功能测试正常...");
|
|
||||||
this.enableMagicLib = true;
|
|
||||||
} catch (final NoClassDefFoundError | NoSuchMethodError | Exception e) {
|
|
||||||
getLogger().warning("+=========================================");
|
|
||||||
getLogger().warning("| 警告: 启动魔改库失败 部分功能将被禁用...");
|
|
||||||
getLogger().warning("+=========================================");
|
|
||||||
this.enableMagicLib = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final ConfigurationSection dbCfg = getConfig().getConfigurationSection("database");
|
|
||||||
DatabaseCore dbCore;
|
|
||||||
if (dbCfg.getBoolean("mysql")) {
|
|
||||||
getLogger().info("启用MySQL 开始连接数据库...");
|
|
||||||
// MySQL database - Required database be created first.
|
|
||||||
final String user = dbCfg.getString("user");
|
|
||||||
final String pass = dbCfg.getString("password");
|
|
||||||
final String host = dbCfg.getString("host");
|
|
||||||
final String port = dbCfg.getString("port");
|
|
||||||
final String database = dbCfg.getString("database");
|
|
||||||
dbCore = new MySQLCore(host, user, pass, database, port);
|
|
||||||
} else {
|
|
||||||
// SQLite database - Doing this handles file creation
|
|
||||||
dbCore = new SQLiteCore(new File(this.getDataFolder(), "shops.db"));
|
|
||||||
}
|
|
||||||
this.database = new Database(dbCore);
|
|
||||||
// Make the database up to date
|
|
||||||
DatabaseHelper.setup(getDB());
|
|
||||||
} catch (final Exception e) {
|
|
||||||
getLogger().warning("数据库连接错误或配置错误...");
|
|
||||||
getLogger().warning("错误信息: " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
getLogger().warning("关闭插件!!!");
|
|
||||||
getServer().getPluginManager().disablePlugin(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Load shops from database to memory */
|
|
||||||
int count = 0; // Shops count
|
|
||||||
int unload = 0;
|
int unload = 0;
|
||||||
Connection con;
|
Connection con;
|
||||||
try {
|
try {
|
||||||
getLogger().info("从数据库载入商店数据...");
|
getLogger().info("开始从数据库载入商店数据...");
|
||||||
con = database.getConnection();
|
con = database.getConnection();
|
||||||
final PreparedStatement ps = con.prepareStatement("SELECT * FROM shops");
|
final PreparedStatement ps = con.prepareStatement("SELECT * FROM shops");
|
||||||
final ResultSet rs = ps.executeQuery();
|
final ResultSet rs = ps.executeQuery();
|
||||||
@ -296,7 +173,7 @@ public class QuickShop extends JavaPlugin {
|
|||||||
final double price = rs.getDouble("price");
|
final double price = rs.getDouble("price");
|
||||||
final Location loc = new Location(world, x, y, z);
|
final Location loc = new Location(world, x, y, z);
|
||||||
/* Skip invalid shops, if we know of any */
|
/* Skip invalid shops, if we know of any */
|
||||||
if (world != null && loc.getChunk().isLoaded() && (loc.getBlock().getState() instanceof InventoryHolder) == false) {
|
if (world != null && loc.getChunk().isLoaded() && !(loc.getBlock().getState() instanceof InventoryHolder)) {
|
||||||
getLogger().info("商店不是一个可存储的方块 坐标 " + rs.getString("world") + ", " + x + ", " + y + ", " + z + ". 删除...");
|
getLogger().info("商店不是一个可存储的方块 坐标 " + rs.getString("world") + ", " + x + ", " + y + ", " + z + ". 删除...");
|
||||||
database.execute("DELETE FROM shops WHERE x = ? AND y = ? and z = ? and world = ?", x, y, z, worldName);
|
database.execute("DELETE FROM shops WHERE x = ? AND y = ? and z = ? and world = ?", x, y, z, worldName);
|
||||||
continue;
|
continue;
|
||||||
@ -332,49 +209,124 @@ public class QuickShop extends JavaPlugin {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
getLogger().info("已载入 " + count + " 个商店 剩余 " + unload + " 个商店将在区块载入后加载...");
|
getLogger().info("已载入 " + count + " 个商店 剩余 " + unload + " 个商店将在区块载入后加载...");
|
||||||
MsgUtil.loadTransactionMessages();
|
|
||||||
MsgUtil.clean();
|
|
||||||
// Register events
|
|
||||||
final PluginManager pm = this.getServer().getPluginManager();
|
|
||||||
pm.registerEvents(blockListener, this);
|
|
||||||
pm.registerEvents(playerListener, this);
|
|
||||||
pm.registerEvents(worldListener, this);
|
|
||||||
pm.registerEvents(protectListener, this);
|
|
||||||
if (configManager.isDisplay()) {
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(chunkListener, this);
|
|
||||||
// Display item handler thread
|
|
||||||
getLogger().info("开启商店检查以及悬浮物刷新线程...");
|
|
||||||
final ItemWatcher itemWatcher = new ItemWatcher(this);
|
|
||||||
itemWatcherTask = Bukkit.getScheduler().runTaskTimer(this, itemWatcher, 20, 1800);
|
|
||||||
}
|
}
|
||||||
this.chatListener = new ChatListener(this);
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(chatListener, this);
|
/**
|
||||||
// Command handlers
|
* Logs the given string to qs.log, if QuickShop is configured to do so.
|
||||||
final QuickShopCommands commandExecutor = new QuickShopCommands(this);
|
*
|
||||||
getCommand("qs").setExecutor(commandExecutor);
|
* @param s
|
||||||
if (configManager.getFindDistance() > 100) {
|
* The string to log. It will be prefixed with the date and time.
|
||||||
getLogger().warning("商店查找半径过大 可能导致服务器Lag! 推荐使用低于 100 的配置!");
|
*/
|
||||||
|
public void log(final String s) {
|
||||||
|
if (this.logWatcher == null) { return; }
|
||||||
|
final Date date = Calendar.getInstance().getTime();
|
||||||
|
final Timestamp time = new Timestamp(date.getTime());
|
||||||
|
this.logWatcher.add("[" + time.toString() + "] " + s);
|
||||||
}
|
}
|
||||||
this.getLogger().info("载入完成! 版本: " + this.getDescription().getVersion() + " 重制 by 喵♂呜");
|
|
||||||
new VersionChecker(this);
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (itemWatcherTask != null) {
|
||||||
|
itemWatcherTask.cancel();
|
||||||
|
}
|
||||||
|
if (logWatcher != null) {
|
||||||
|
logWatcher.task.cancel();
|
||||||
|
logWatcher.close(); // Closes the file
|
||||||
|
}
|
||||||
|
/* Remove all display items, and any dupes we can find */
|
||||||
|
if (shopManager != null) {
|
||||||
|
shopManager.clear();
|
||||||
|
}
|
||||||
|
/* Empty the buffer */
|
||||||
|
if (database != null) {
|
||||||
|
database.close();
|
||||||
try {
|
try {
|
||||||
final Metrics metrics = new Metrics(this);
|
database.getConnection().close();
|
||||||
metrics.start();
|
} catch (final SQLException ignored) {
|
||||||
} catch (final IOException e) {
|
}
|
||||||
|
}
|
||||||
|
if (configManager != null) {
|
||||||
|
configManager.getWarnings().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
if (!loadEcon()) { return; }
|
||||||
|
Util.initialize();
|
||||||
|
// Create the shop manager.
|
||||||
|
shopManager = new ShopManager(this);
|
||||||
|
configManager = new ConfigManager(this);
|
||||||
|
// Initialize Util
|
||||||
|
if (configManager.isLogAction()) {
|
||||||
|
// Logger Handler
|
||||||
|
this.logWatcher = new LogWatcher(this, new File(this.getDataFolder(), "qs.log"));
|
||||||
|
logWatcher.task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, this.logWatcher, 150, 150);
|
||||||
|
}
|
||||||
|
if (configManager.isShopLock()) {
|
||||||
|
final LockListener ll = new LockListener(this);
|
||||||
|
getServer().getPluginManager().registerEvents(ll, this);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final ConfigurationSection dbCfg = getConfig().getConfigurationSection("database");
|
||||||
|
DatabaseCore dbCore;
|
||||||
|
if (dbCfg != null && dbCfg.getBoolean("mysql")) {
|
||||||
|
getLogger().info("启用MySQL 开始连接数据库...");
|
||||||
|
// MySQL database - Required database be created first.
|
||||||
|
final String user = dbCfg.getString("user");
|
||||||
|
final String pass = dbCfg.getString("password");
|
||||||
|
final String host = dbCfg.getString("host");
|
||||||
|
final String port = dbCfg.getString("port");
|
||||||
|
final String database = dbCfg.getString("database");
|
||||||
|
dbCore = new MySQLCore(host, user, pass, database, port);
|
||||||
|
} else {
|
||||||
|
// SQLite database - Doing this handles file creation
|
||||||
|
dbCore = new SQLiteCore(new File(this.getDataFolder(), "shops.db"));
|
||||||
|
}
|
||||||
|
this.database = new Database(dbCore);
|
||||||
|
// Make the database up to date
|
||||||
|
DatabaseHelper.setup(getDB());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
getLogger().warning("数据库连接错误或配置错误...");
|
||||||
|
getLogger().warning("错误信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
getLogger().warning("关闭插件!!!");
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadShop();
|
||||||
|
MsgUtil.loadTransactionMessages();
|
||||||
|
MsgUtil.clean();
|
||||||
|
// Register events
|
||||||
|
final PluginManager pm = this.getServer().getPluginManager();
|
||||||
|
pm.registerEvents(new BlockListener(this), this);
|
||||||
|
pm.registerEvents(new PlayerListener(this), this);
|
||||||
|
pm.registerEvents(new WorldListener(this), this);
|
||||||
|
pm.registerEvents(new ProtectListener(this), this);
|
||||||
|
pm.registerEvents(new ChatListener(this), this);
|
||||||
|
// Command handlers
|
||||||
|
new QuickShopCommands();
|
||||||
|
|
||||||
|
if (configManager.getFindDistance() > 100) {
|
||||||
|
getLogger().warning("商店查找半径过大 可能导致服务器Lag! 推荐使用低于 100 的配置!");
|
||||||
|
}
|
||||||
|
this.getLogger().info("载入完成! 版本: " + this.getDescription().getVersion() + " 重制 by 喵♂呜");
|
||||||
|
new Statistics();
|
||||||
|
new SubscribeTask();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
config = new FileConfig(this);
|
instance = this;
|
||||||
ItemConfig.load(this);
|
config = new FileConfig();
|
||||||
MsgUtil.init(this);
|
MsgUtil.init(this);
|
||||||
|
L10N.getItemName(new ItemStack(Material.AIR));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reloads QuickShops config */
|
/** Reloads QuickShops config */
|
||||||
@Override
|
@Override
|
||||||
public void reloadConfig() {
|
public void reloadConfig() {
|
||||||
config.reload();
|
config.reload();
|
||||||
ItemConfig.reload();
|
L10N.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ import java.util.Map;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
@ -19,15 +18,19 @@ import org.bukkit.inventory.Inventory;
|
|||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
import org.maxgamer.QuickShop.Shop.Item.DisplayItem;
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
import org.maxgamer.QuickShop.Util.MsgUtil;
|
||||||
import org.maxgamer.QuickShop.Util.Util;
|
import org.maxgamer.QuickShop.Util.Util;
|
||||||
|
|
||||||
|
import pw.yumc.YumCore.bukkit.P;
|
||||||
|
|
||||||
public class ContainerShop implements Shop {
|
public class ContainerShop implements Shop {
|
||||||
|
private final QuickShop plugin = (QuickShop) P.instance;
|
||||||
|
private final String signTitle = plugin.getConfigManager().getGuiTitle();
|
||||||
private DisplayItem displayItem;
|
private DisplayItem displayItem;
|
||||||
private final ItemStack item;
|
private final ItemStack item;
|
||||||
private final Location loc;
|
private final Location loc;
|
||||||
private String owner;
|
private String owner;
|
||||||
private final QuickShop plugin;
|
|
||||||
private double price;
|
private double price;
|
||||||
private ShopType shopType;
|
private ShopType shopType;
|
||||||
private boolean unlimited;
|
private boolean unlimited;
|
||||||
@ -50,11 +53,8 @@ public class ContainerShop implements Shop {
|
|||||||
this.price = price;
|
this.price = price;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.item = item.clone();
|
this.item = item.clone();
|
||||||
this.plugin = (QuickShop) Bukkit.getPluginManager().getPlugin("QuickShop");
|
|
||||||
this.item.setAmount(1);
|
this.item.setAmount(1);
|
||||||
if (plugin.getConfigManager().isDisplay()) {
|
this.displayItem = DisplayItem.create(this);
|
||||||
this.displayItem = new DisplayItem(this, this.item);
|
|
||||||
}
|
|
||||||
this.shopType = ShopType.SELLING;
|
this.shopType = ShopType.SELLING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,6 @@ public class ContainerShop implements Shop {
|
|||||||
this.shopType = s.shopType;
|
this.shopType = s.shopType;
|
||||||
this.item = s.item;
|
this.item = s.item;
|
||||||
this.loc = s.loc;
|
this.loc = s.loc;
|
||||||
this.plugin = s.plugin;
|
|
||||||
this.unlimited = s.unlimited;
|
this.unlimited = s.unlimited;
|
||||||
this.owner = s.owner;
|
this.owner = s.owner;
|
||||||
this.price = s.price;
|
this.price = s.price;
|
||||||
@ -80,9 +79,7 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void add(final ItemStack item, final int amount) {
|
public void add(final ItemStack item, final int amount) {
|
||||||
if (this.unlimited) {
|
if (this.unlimited) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Inventory inv = this.getInventory();
|
final Inventory inv = this.getInventory();
|
||||||
int remains = amount;
|
int remains = amount;
|
||||||
while (remains > 0) {
|
while (remains > 0) {
|
||||||
@ -99,8 +96,6 @@ public class ContainerShop implements Shop {
|
|||||||
*
|
*
|
||||||
* @param p
|
* @param p
|
||||||
* The player to buy from
|
* The player to buy from
|
||||||
* @param item
|
|
||||||
* The itemStack to buy
|
|
||||||
* @param amount
|
* @param amount
|
||||||
* The amount to buy
|
* The amount to buy
|
||||||
*/
|
*/
|
||||||
@ -200,7 +195,13 @@ public class ContainerShop implements Shop {
|
|||||||
final int y = this.getLocation().getBlockY();
|
final int y = this.getLocation().getBlockY();
|
||||||
final int z = this.getLocation().getBlockZ();
|
final int z = this.getLocation().getBlockZ();
|
||||||
final String world = this.getLocation().getWorld().getName();
|
final String world = this.getLocation().getWorld().getName();
|
||||||
|
// Async database execute
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
plugin.getDB().execute("DELETE FROM shops WHERE x = '" + x + "' AND y = '" + y + "' AND z = '" + z + "' AND world = '" + world + "'");
|
plugin.getDB().execute("DELETE FROM shops WHERE x = '" + x + "' AND y = '" + y + "' AND z = '" + z + "' AND world = '" + world + "'");
|
||||||
|
}
|
||||||
|
});
|
||||||
// Refund if necessary
|
// Refund if necessary
|
||||||
if (plugin.getConfig().getBoolean("shop.refund")) {
|
if (plugin.getConfig().getBoolean("shop.refund")) {
|
||||||
plugin.getEcon().deposit(this.getOwner(), plugin.getConfig().getDouble("shop.cost"));
|
plugin.getEcon().deposit(this.getOwner(), plugin.getConfig().getDouble("shop.cost"));
|
||||||
@ -218,10 +219,9 @@ public class ContainerShop implements Shop {
|
|||||||
* null if this shop is not attached to another.
|
* null if this shop is not attached to another.
|
||||||
*/
|
*/
|
||||||
public ContainerShop getAttachedShop() {
|
public ContainerShop getAttachedShop() {
|
||||||
|
if (this.getLocation() != null) { return null; }
|
||||||
final Block c = Util.getSecondHalf(this.getLocation().getBlock());
|
final Block c = Util.getSecondHalf(this.getLocation().getBlock());
|
||||||
if (c == null) {
|
if (c == null) { return null; }
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final Shop shop = plugin.getShopManager().getShop(c.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(c.getLocation());
|
||||||
return shop == null ? null : (ContainerShop) shop;
|
return shop == null ? null : (ContainerShop) shop;
|
||||||
}
|
}
|
||||||
@ -265,12 +265,11 @@ public class ContainerShop implements Shop {
|
|||||||
* @return The chest this shop is based on.
|
* @return The chest this shop is based on.
|
||||||
*/
|
*/
|
||||||
public Inventory getInventory() throws IllegalStateException {
|
public Inventory getInventory() throws IllegalStateException {
|
||||||
InventoryHolder container;
|
|
||||||
try {
|
try {
|
||||||
container = (InventoryHolder) this.loc.getBlock().getState();
|
final InventoryHolder container = (InventoryHolder) this.loc.getBlock().getState();
|
||||||
return container.getInventory();
|
return container.getInventory();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new IllegalStateException("Inventory doesn't exist anymore");
|
throw new IllegalStateException("容器已经不存在了!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,15 +314,11 @@ public class ContainerShop implements Shop {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of free spots in the chest for the particular item.
|
* Returns the number of free spots in the chest for the particular item.
|
||||||
*
|
|
||||||
* @param stackSize
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getRemainingSpace() {
|
public int getRemainingSpace() {
|
||||||
if (this.unlimited) {
|
if (this.unlimited) { return 10000; }
|
||||||
return 10000;
|
|
||||||
}
|
|
||||||
return Util.countSpace(this.getInventory(), item);
|
return Util.countSpace(this.getInventory(), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,9 +329,7 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getRemainingStock() {
|
public int getRemainingStock() {
|
||||||
if (this.unlimited) {
|
if (this.unlimited) { return 10000; }
|
||||||
return 10000;
|
|
||||||
}
|
|
||||||
return Util.countItems(this.getInventory(), this.getItem());
|
return Util.countItems(this.getInventory(), this.getItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,10 +347,8 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Sign> getSigns() {
|
public List<Sign> getSigns() {
|
||||||
final ArrayList<Sign> signs = new ArrayList<Sign>(1);
|
final ArrayList<Sign> signs = new ArrayList<>(1);
|
||||||
if (this.getLocation().getWorld() == null) {
|
if (this.getLocation().getWorld() == null) { return signs; }
|
||||||
return signs;
|
|
||||||
}
|
|
||||||
final Block[] blocks = new Block[4];
|
final Block[] blocks = new Block[4];
|
||||||
blocks[0] = loc.getBlock().getRelative(1, 0, 0);
|
blocks[0] = loc.getBlock().getRelative(1, 0, 0);
|
||||||
blocks[1] = loc.getBlock().getRelative(-1, 0, 0);
|
blocks[1] = loc.getBlock().getRelative(-1, 0, 0);
|
||||||
@ -371,7 +362,7 @@ public class ContainerShop implements Shop {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final Sign sign = (Sign) b.getState();
|
final Sign sign = (Sign) b.getState();
|
||||||
if (sign.getLine(0).contains("[QuickShop]")) {
|
if (sign.getLine(0).contains("[QuickShop]") || signTitle.startsWith(sign.getLine(0))) {
|
||||||
signs.add(sign);
|
signs.add(sign);
|
||||||
} else {
|
} else {
|
||||||
boolean text = false;
|
boolean text = false;
|
||||||
@ -411,23 +402,19 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
public boolean isDoubleShop() {
|
public boolean isDoubleShop() {
|
||||||
final ContainerShop nextTo = this.getAttachedShop();
|
final ContainerShop nextTo = this.getAttachedShop();
|
||||||
if (nextTo == null) {
|
if (nextTo == null) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (nextTo.matches(this.getItem())) {
|
if (nextTo.matches(this.getItem())) {
|
||||||
// They're both trading the same item
|
// They're both trading the same item
|
||||||
if (this.getShopType() == nextTo.getShopType()) {
|
if (this.getShopType() == nextTo.getShopType()) {
|
||||||
// They're both buying or both selling => Not a double shop,
|
// They're both buying or both selling => Not a double shop,
|
||||||
// just two shops.
|
// just two shops.
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
// One is buying, one is selling.
|
// One is buying, one is selling.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSelling() {
|
public boolean isSelling() {
|
||||||
@ -486,9 +473,7 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void remove(final ItemStack item, final int amount) {
|
public void remove(final ItemStack item, final int amount) {
|
||||||
if (this.unlimited) {
|
if (this.unlimited) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Inventory inv = this.getInventory();
|
final Inventory inv = this.getInventory();
|
||||||
int remains = amount;
|
int remains = amount;
|
||||||
while (remains > 0) {
|
while (remains > 0) {
|
||||||
@ -514,7 +499,7 @@ public class ContainerShop implements Shop {
|
|||||||
this.buy(p, -amount);
|
this.buy(p, -amount);
|
||||||
}
|
}
|
||||||
// Items to drop on floor
|
// Items to drop on floor
|
||||||
final ArrayList<ItemStack> floor = new ArrayList<ItemStack>(5);
|
final ArrayList<ItemStack> floor = new ArrayList<>(5);
|
||||||
final Inventory pInv = p.getInventory();
|
final Inventory pInv = p.getInventory();
|
||||||
if (this.isUnlimited()) {
|
if (this.isUnlimited()) {
|
||||||
final ItemStack item = this.item.clone();
|
final ItemStack item = this.item.clone();
|
||||||
@ -549,8 +534,8 @@ public class ContainerShop implements Shop {
|
|||||||
// We now have to update the chests inventory manually.
|
// We now have to update the chests inventory manually.
|
||||||
this.getInventory().setContents(chestContents);
|
this.getInventory().setContents(chestContents);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < floor.size(); i++) {
|
for (ItemStack aFloor : floor) {
|
||||||
p.getWorld().dropItem(p.getLocation(), floor.get(i));
|
p.getWorld().dropItem(p.getLocation(), aFloor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,20 +580,27 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setSignText() {
|
public void setSignText() {
|
||||||
if (Util.isLoaded(this.getLocation()) == false) {
|
if (!Util.isLoaded(this.getLocation())) { return; }
|
||||||
return;
|
final ContainerShop shop = this;
|
||||||
}
|
// 1.9不能异步修改木牌
|
||||||
|
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
final String[] lines = new String[4];
|
final String[] lines = new String[4];
|
||||||
lines[0] = ChatColor.RED + "[QuickShop]";
|
lines[0] = signTitle;
|
||||||
if (this.isBuying()) {
|
if (shop.isBuying()) {
|
||||||
lines[1] = MsgUtil.p("signs.buying", "" + this.getRemainingSpace());
|
final int remsp = shop.getRemainingSpace();
|
||||||
|
lines[1] = MsgUtil.p("signs.buying", "" + (remsp == 10000 ? "无限" : remsp));
|
||||||
}
|
}
|
||||||
if (this.isSelling()) {
|
if (shop.isSelling()) {
|
||||||
lines[1] = MsgUtil.p("signs.selling", "" + this.getRemainingStock());
|
final int remst = shop.getRemainingStock();
|
||||||
|
lines[1] = MsgUtil.p("signs.selling", "" + (remst == 10000 ? "无限" : remst));
|
||||||
}
|
}
|
||||||
lines[2] = Util.getNameForSign(this.item);
|
lines[2] = Util.getNameForSign(shop.item);
|
||||||
lines[3] = MsgUtil.p("signs.price", "" + this.getPrice());
|
lines[3] = MsgUtil.p("signs.price", "" + shop.getPrice());
|
||||||
this.setSignText(lines);
|
shop.setSignText(lines);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -619,16 +611,21 @@ public class ContainerShop implements Shop {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setSignText(final String[] lines) {
|
public void setSignText(final String[] lines) {
|
||||||
if (Util.isLoaded(this.getLocation()) == false) {
|
if (!Util.isLoaded(this.getLocation())) { return; }
|
||||||
return;
|
final List<Sign> signs = this.getSigns();
|
||||||
}
|
// 1.9不能异步修改木牌
|
||||||
for (final Sign sign : this.getSigns()) {
|
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (final Sign sign : signs) {
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
sign.setLine(i, lines[i]);
|
sign.setLine(i, lines[i]);
|
||||||
}
|
}
|
||||||
sign.update();
|
sign.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUnlimited(final boolean unlimited) {
|
public void setUnlimited(final boolean unlimited) {
|
||||||
@ -639,12 +636,12 @@ public class ContainerShop implements Shop {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuilder sb = new StringBuilder("商店 " + (loc.getWorld() == null ? "世界尚未载入" : "坐标: " + loc.getWorld().getName()) + "(" + loc.getBlockX() + ", " + loc.getBlockY() + ", "
|
final StringBuilder sb = new StringBuilder("商店 " + (loc.getWorld() == null ? "世界尚未载入" : "坐标: " + loc.getWorld().getName()) + "(" + loc.getBlockX() + ", " + loc.getBlockY() + ", "
|
||||||
+ loc.getBlockZ() + ")");
|
+ loc.getBlockZ() + ")");
|
||||||
sb.append(" 所有者: " + getOwner());
|
sb.append(" 所有者: ").append(getOwner());
|
||||||
if (isUnlimited()) {
|
if (isUnlimited()) {
|
||||||
sb.append("无限模式: true");
|
sb.append(" 无限模式: true");
|
||||||
}
|
}
|
||||||
sb.append("价格: " + getPrice());
|
sb.append(" 价格: ").append(getPrice());
|
||||||
sb.append("物品: " + getItem().toString());
|
sb.append(" 物品: ").append(getItem().toString());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,25 +656,31 @@ public class ContainerShop implements Shop {
|
|||||||
final String world = this.getLocation().getWorld().getName();
|
final String world = this.getLocation().getWorld().getName();
|
||||||
final int unlimited = this.isUnlimited() ? 1 : 0;
|
final int unlimited = this.isUnlimited() ? 1 : 0;
|
||||||
final String q = "UPDATE shops SET owner = ?, itemConfig = ?, unlimited = ?, type = ?, price = ? WHERE x = ? AND y = ? and z = ? and world = ?";
|
final String q = "UPDATE shops SET owner = ?, itemConfig = ?, unlimited = ?, type = ?, price = ? WHERE x = ? AND y = ? and z = ? and world = ?";
|
||||||
|
final String owner = this.getOwner();
|
||||||
|
final String item = Util.serialize(this.getItem());
|
||||||
|
double price = this.getPrice();
|
||||||
|
// Async database execute
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
try {
|
try {
|
||||||
plugin.getDB().execute(q, this.getOwner(), Util.serialize(this.getItem()), unlimited, shopType.toID(), this.getPrice(), x, y, z, world);
|
plugin.getDB().execute(q, owner, item, unlimited, shopType.toID(), price, x, y, z, world);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
plugin.getLogger().warning("无法保存商店到数据库!!!");
|
plugin.getLogger().warning("无法保存商店到数据库!!!");
|
||||||
plugin.getLogger().warning("错误信息: " + e.getMessage());
|
plugin.getLogger().warning("错误信息: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDisplay() {
|
private void checkDisplay() {
|
||||||
if (plugin.getConfigManager().isDisplay() == false) {
|
if (!plugin.getConfigManager().isDisplay()) { return; }
|
||||||
return;
|
if (getLocation().getWorld() == null) { return; // not loaded
|
||||||
}
|
|
||||||
if (getLocation().getWorld() == null) {
|
|
||||||
return; // not loaded
|
|
||||||
}
|
}
|
||||||
final boolean trans = Util.isTransparent(getLocation().clone().add(0.5, 1.2, 0.5).getBlock().getType());
|
final boolean trans = Util.isTransparent(getLocation().clone().add(0.5, 1.2, 0.5).getBlock().getType());
|
||||||
if (trans && this.getDisplayItem() == null) {
|
if (trans && this.getDisplayItem() == null) {
|
||||||
this.displayItem = new DisplayItem(this, this.getItem());
|
this.displayItem = DisplayItem.create(this);
|
||||||
this.getDisplayItem().spawn();
|
this.getDisplayItem().spawn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -687,8 +690,11 @@ public class ContainerShop implements Shop {
|
|||||||
this.displayItem = null;
|
this.displayItem = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.getLocation().getWorld() == null) { return;// Ignore if world not loaded...
|
||||||
|
}
|
||||||
final DisplayItem disItem = this.getDisplayItem();
|
final DisplayItem disItem = this.getDisplayItem();
|
||||||
final Location dispLoc = disItem.getDisplayLocation();
|
final Location dispLoc = disItem.getDisplayLocation();
|
||||||
|
if (dispLoc.getWorld() == null) { return; }
|
||||||
if (dispLoc.getBlock() != null && dispLoc.getBlock().getType() == Material.WATER) { // Flowing
|
if (dispLoc.getBlock() != null && dispLoc.getBlock().getType() == Material.WATER) { // Flowing
|
||||||
// water.Stationery water does not move items.
|
// water.Stationery water does not move items.
|
||||||
disItem.remove();
|
disItem.remove();
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
package org.maxgamer.QuickShop.Shop;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Item;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import org.maxgamer.QuickShop.Util.NMS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Netherfoam A display item, that spawns a block above the chest and
|
|
||||||
* cannot be interacted with.
|
|
||||||
*/
|
|
||||||
public class DisplayItem {
|
|
||||||
private final ItemStack iStack;
|
|
||||||
private Item item;
|
|
||||||
private final Shop shop;
|
|
||||||
|
|
||||||
// private Location displayLoc;
|
|
||||||
/**
|
|
||||||
* Creates a new display item.
|
|
||||||
*
|
|
||||||
* @param shop
|
|
||||||
* The shop (See Shop)
|
|
||||||
* @param iStack
|
|
||||||
* The item stack to clone properties of the display item from.
|
|
||||||
*/
|
|
||||||
public DisplayItem(final Shop shop, final ItemStack iStack) {
|
|
||||||
this.shop = shop;
|
|
||||||
this.iStack = iStack.clone();
|
|
||||||
// this.displayLoc = shop.getLocation().clone().add(0.5, 1.2, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Returns the exact location of the display item. (1 above shop
|
|
||||||
* block, in the center)
|
|
||||||
*/
|
|
||||||
public Location getDisplayLocation() {
|
|
||||||
return this.shop.getLocation().clone().add(0.5, 1.2, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the reference to this shops item. Do not modify.
|
|
||||||
*/
|
|
||||||
public Item getItem() {
|
|
||||||
return this.item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the display item.
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
if (this.item == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.item.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all items floating ontop of the chest that aren't the display
|
|
||||||
* item.
|
|
||||||
*/
|
|
||||||
public boolean removeDupe() {
|
|
||||||
if (shop.getLocation().getWorld() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final Location displayLoc = shop.getLocation().getBlock().getRelative(0, 1, 0).getLocation();
|
|
||||||
boolean removed = false;
|
|
||||||
final Chunk c = displayLoc.getChunk();
|
|
||||||
for (final Entity e : c.getEntities()) {
|
|
||||||
if (!(e instanceof Item)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (this.item != null && e.getEntityId() == this.item.getEntityId()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final Location eLoc = e.getLocation().getBlock().getLocation();
|
|
||||||
if (eLoc.equals(displayLoc) || eLoc.equals(shop.getLocation())) {
|
|
||||||
final ItemStack near = ((Item) e).getItemStack();
|
|
||||||
// if its the same its a dupe
|
|
||||||
if (this.shop.matches(near)) {
|
|
||||||
e.remove();
|
|
||||||
removed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spawns the new display item. Does not remove duplicate items.
|
|
||||||
*/
|
|
||||||
public void respawn() {
|
|
||||||
remove();
|
|
||||||
spawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spawns the dummy item on top of the shop.
|
|
||||||
*/
|
|
||||||
public void spawn() {
|
|
||||||
if (shop.getLocation().getWorld() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Location dispLoc = this.getDisplayLocation();
|
|
||||||
try {
|
|
||||||
this.item = shop.getLocation().getWorld().dropItem(dispLoc, this.iStack);
|
|
||||||
this.item.setVelocity(new Vector(0, 0.1, 0));
|
|
||||||
NMS.safeGuard(this.item);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,9 +18,9 @@ public class Info {
|
|||||||
* The location they clicked (Block.getLocation())
|
* The location they clicked (Block.getLocation())
|
||||||
* @param action
|
* @param action
|
||||||
* The action (ShopAction.*)
|
* The action (ShopAction.*)
|
||||||
* @param material
|
* @param item
|
||||||
* The material they were holding
|
* The material they were holding
|
||||||
* @param data
|
* @param last
|
||||||
* The data value of the material
|
* The data value of the material
|
||||||
*/
|
*/
|
||||||
public Info(Location loc, ShopAction action, ItemStack item, Block last) {
|
public Info(Location loc, ShopAction action, ItemStack item, Block last) {
|
||||||
@ -38,9 +38,9 @@ public class Info {
|
|||||||
* The location they clicked (Block.getLocation())
|
* The location they clicked (Block.getLocation())
|
||||||
* @param action
|
* @param action
|
||||||
* The action (ShopAction.*)
|
* The action (ShopAction.*)
|
||||||
* @param material
|
* @param item
|
||||||
* The material they were holding
|
* The material they were holding
|
||||||
* @param data
|
* @param last
|
||||||
* The data value of the material
|
* The data value of the material
|
||||||
* @param shop
|
* @param shop
|
||||||
* The shop they interacted with, or null if none
|
* The shop they interacted with, or null if none
|
||||||
@ -67,9 +67,7 @@ public class Info {
|
|||||||
return true;
|
return true;
|
||||||
if (!this.shop.getLocation().equals(shop.getLocation()))
|
if (!this.shop.getLocation().equals(shop.getLocation()))
|
||||||
return true;
|
return true;
|
||||||
if (!this.shop.matches(shop.getItem()))
|
return !this.shop.matches(shop.getItem());
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShopAction getAction() {
|
public ShopAction getAction() {
|
||||||
|
121
src/main/java/org/maxgamer/QuickShop/Shop/Item/DisplayItem.java
Normal file
121
src/main/java/org/maxgamer/QuickShop/Shop/Item/DisplayItem.java
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
|
import org.maxgamer.QuickShop.Listeners.ChunkListener;
|
||||||
|
import org.maxgamer.QuickShop.Shop.ContainerShop;
|
||||||
|
import org.maxgamer.QuickShop.Watcher.ItemWatcher;
|
||||||
|
|
||||||
|
import pw.yumc.YumCore.bukkit.Log;
|
||||||
|
import pw.yumc.YumCore.bukkit.P;
|
||||||
|
import pw.yumc.YumCore.bukkit.compatible.C;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Netherfoam A display item, that spawns a block above the chest and
|
||||||
|
* cannot be interacted with.
|
||||||
|
*/
|
||||||
|
public abstract class DisplayItem {
|
||||||
|
private static QuickShop plugin = P.getPlugin();
|
||||||
|
|
||||||
|
private static Class<? extends DisplayItem> displayItemClass = NormalItem.class;
|
||||||
|
|
||||||
|
private static Constructor<? extends DisplayItem> constructor;
|
||||||
|
|
||||||
|
public static void init(boolean fakeItem) {
|
||||||
|
if (fakeItem) {
|
||||||
|
Log.i("启用虚拟悬浮物 尝试启动中...");
|
||||||
|
String nms = C.getNMSVersion();
|
||||||
|
Class<? extends DisplayItem> c = null;
|
||||||
|
switch (nms) {
|
||||||
|
case "v1_7_R4":
|
||||||
|
c = FakeItem_17.class;
|
||||||
|
break;
|
||||||
|
case "v1_8_R3":
|
||||||
|
c = FakeItem_18.class;
|
||||||
|
break;
|
||||||
|
case "v1_9_R1":
|
||||||
|
case "v1_9_R2":
|
||||||
|
case "v1_10_R1":
|
||||||
|
case "v1_11_R1":
|
||||||
|
c = FakeItem_19_111.class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c != null) {
|
||||||
|
FakeItem.register(plugin);
|
||||||
|
try {
|
||||||
|
c.getConstructor(Location.class, ItemStack.class).newInstance(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), new ItemStack(Material.STONE)).spawn();
|
||||||
|
displayItemClass = c;
|
||||||
|
Log.i("虚拟悬浮物功能测试正常(%s)...", c.getSimpleName());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.d(e);
|
||||||
|
Log.w("+=========================================");
|
||||||
|
Log.w("| 警告: 启动虚拟物品失败 使用原版悬浮物品...");
|
||||||
|
Log.w("+=========================================");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i("没有可用的虚拟物品类 使用原版悬浮物品...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
constructor = displayItemClass.getConstructor(Location.class, ItemStack.class);
|
||||||
|
if (displayItemClass == NormalItem.class) {
|
||||||
|
// Display item handler thread
|
||||||
|
Log.i("开启商店检查以及悬浮物刷新线程...");
|
||||||
|
final ItemWatcher itemWatcher = new ItemWatcher(plugin);
|
||||||
|
plugin.itemWatcherTask = Bukkit.getScheduler().runTaskTimer(plugin, itemWatcher, 20, 1800);
|
||||||
|
}
|
||||||
|
} catch (NoSuchMethodException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DisplayItem create(final ContainerShop shop) {
|
||||||
|
if (plugin.getConfigManager().isDisplay()) try {
|
||||||
|
return constructor.newInstance(shop.getLocation(), shop.getItem());
|
||||||
|
} catch (InstantiationException | InvocationTargetException | IllegalAccessException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得悬浮物地点
|
||||||
|
*
|
||||||
|
* @return 获得悬浮地点
|
||||||
|
*/
|
||||||
|
public abstract Location getDisplayLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@link Item}
|
||||||
|
*/
|
||||||
|
public abstract Item getItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除悬浮物
|
||||||
|
*/
|
||||||
|
public abstract void remove();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除多余物品
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract boolean removeDupe();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新悬浮物
|
||||||
|
*/
|
||||||
|
public abstract void respawn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷出悬浮物
|
||||||
|
*/
|
||||||
|
public abstract void spawn();
|
||||||
|
}
|
189
src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem.java
Normal file
189
src/main/java/org/maxgamer/QuickShop/Shop/Item/FakeItem.java
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft 虚拟悬浮物品工具类 需要depend ProtocolLib 4.x
|
||||||
|
*
|
||||||
|
* @author 橙子(chengzi)
|
||||||
|
* @version 1.1.1
|
||||||
|
*/
|
||||||
|
public abstract class FakeItem extends DisplayItem {
|
||||||
|
|
||||||
|
private static Map<String, List<FakeItem>> fakes = new HashMap<>();
|
||||||
|
private static boolean registered = false;
|
||||||
|
private static int lastId = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
protected final ItemStack itemStack;
|
||||||
|
protected final Location location;
|
||||||
|
protected final int eid;
|
||||||
|
protected boolean created = false;
|
||||||
|
|
||||||
|
public FakeItem(Location loc, final ItemStack item) {
|
||||||
|
this.itemStack = item;
|
||||||
|
this.location = loc.clone().add(0.5, 1, 0.5);
|
||||||
|
this.eid = getFakeEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRegistered() {
|
||||||
|
return registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(final Plugin plugin) {
|
||||||
|
if (registered) { return; }
|
||||||
|
final PluginManager pm = Bukkit.getPluginManager();
|
||||||
|
final Plugin p = pm.getPlugin("ProtocolLib");
|
||||||
|
if (p != null) {
|
||||||
|
if (!p.isEnabled()) {
|
||||||
|
pm.enablePlugin(p);
|
||||||
|
}
|
||||||
|
if (!p.isEnabled()) { throw new IllegalStateException("前置插件ProtocolLib启动失败 请检查版本."); }
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("服务器未找到前置插件ProtocolLib.");
|
||||||
|
}
|
||||||
|
final PacketAdapter chunkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(final PacketEvent event) {
|
||||||
|
try {
|
||||||
|
final PacketContainer packet = event.getPacket();
|
||||||
|
final Player p = event.getPlayer();
|
||||||
|
final int chunkX = packet.getIntegers().read(0);
|
||||||
|
final int chunkZ = packet.getIntegers().read(1);
|
||||||
|
final List<FakeItem> fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunkX, chunkZ)));
|
||||||
|
sendChunkPacket(p, fakesInChunk);
|
||||||
|
} catch (final Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(chunkPacketListener);
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendChunkPacket(Player p, List<FakeItem> fakesInChunk) throws InvocationTargetException {
|
||||||
|
if (fakesInChunk != null) {
|
||||||
|
for (final FakeItem fake : fakesInChunk) {
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getVelocityPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getChunkIdentifyString(final Chunk chunk) {
|
||||||
|
return chunk.getWorld().getName() + "@@" + chunk.getX() + "@@" + chunk.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getFakeEntityId() {
|
||||||
|
return lastId--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getDisplayLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
destory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeDupe() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respawn() {
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDestoryPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getSpawnPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getVelocityPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getMetadataPacket());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawn() {
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void create() {
|
||||||
|
if (!registered) { throw new IllegalStateException("You have to call the register method first."); }
|
||||||
|
if (created) { return; }
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getSpawnPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getVelocityPacket());
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getMetadataPacket());
|
||||||
|
|
||||||
|
final String chunkId = getChunkIdentifyString(location.getChunk());
|
||||||
|
List<FakeItem> fakesInChunk = fakes.get(chunkId);
|
||||||
|
if (fakesInChunk == null) {
|
||||||
|
fakesInChunk = new ArrayList<>();
|
||||||
|
}
|
||||||
|
fakesInChunk.add(this);
|
||||||
|
fakes.put(chunkId, fakesInChunk);
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destory() {
|
||||||
|
if (!created) { return; }
|
||||||
|
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDestoryPacket());
|
||||||
|
|
||||||
|
final String chunkId = getChunkIdentifyString(location.getChunk());
|
||||||
|
final List<FakeItem> fakesInChunk = fakes.get(chunkId);
|
||||||
|
if (fakesInChunk == null) {
|
||||||
|
// NOTE: This is what should not happens if everything is correct.
|
||||||
|
created = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fakesInChunk.remove(this);
|
||||||
|
fakes.put(chunkId, fakesInChunk);
|
||||||
|
created = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PacketContainer getDestoryPacket() {
|
||||||
|
final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_DESTROY, true);
|
||||||
|
fakePacket.getIntegerArrays().write(0, new int[] { eid });
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PacketContainer getVelocityPacket() {
|
||||||
|
final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_VELOCITY);
|
||||||
|
fakePacket.getIntegers().write(0, eid);
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PacketContainer getMetadataPacket() {
|
||||||
|
return setMetadataPacket(ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_METADATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract PacketContainer setMetadataPacket(PacketContainer fakePacket);
|
||||||
|
|
||||||
|
protected PacketContainer getSpawnPacket() {
|
||||||
|
return setSpawnPacket(ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.SPAWN_ENTITY));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract PacketContainer setSpawnPacket(PacketContainer fakePacket);
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft 虚拟悬浮物品工具类
|
||||||
|
* 需要depend ProtocolLib
|
||||||
|
*
|
||||||
|
* @author 橙子(chengzi)
|
||||||
|
* @version 1.0.1
|
||||||
|
*/
|
||||||
|
public class FakeItem_17 extends FakeItem {
|
||||||
|
|
||||||
|
public FakeItem_17(Location loc, final ItemStack item) {
|
||||||
|
super(loc, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer setMetadataPacket(PacketContainer fakePacket) {
|
||||||
|
fakePacket.getIntegers().write(0, eid);
|
||||||
|
final WrappedWatchableObject itemMeta = new WrappedWatchableObject(10, itemStack);
|
||||||
|
final List<WrappedWatchableObject> entityMetaList = new ArrayList<>(1);
|
||||||
|
entityMetaList.add(itemMeta);
|
||||||
|
fakePacket.getWatchableCollectionModifier().write(0, entityMetaList);
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer setSpawnPacket(PacketContainer fakePacket) {
|
||||||
|
StructureModifier<Integer> is = fakePacket.getIntegers();
|
||||||
|
is.write(0, eid);
|
||||||
|
is.write(1, (int) location.getX());
|
||||||
|
is.write(2, (int) location.getY());
|
||||||
|
is.write(3, (int) location.getZ());
|
||||||
|
is.write(9, 2);
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer getVelocityPacket() {
|
||||||
|
PacketContainer packet = super.getVelocityPacket();
|
||||||
|
StructureModifier<Integer> pint = packet.getIntegers();
|
||||||
|
pint.write(1, 0);
|
||||||
|
pint.write(2, 0);
|
||||||
|
pint.write(3, 0);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft 虚拟悬浮物品工具类
|
||||||
|
* 需要depend ProtocolLib
|
||||||
|
*
|
||||||
|
* @author 橙子(chengzi)
|
||||||
|
* @version 1.0.1
|
||||||
|
*/
|
||||||
|
public class FakeItem_18 extends FakeItem_17 {
|
||||||
|
|
||||||
|
public FakeItem_18(Location loc, final ItemStack item) {
|
||||||
|
super(loc, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer setSpawnPacket(PacketContainer fakePacket) {
|
||||||
|
StructureModifier<Integer> is = fakePacket.getIntegers();
|
||||||
|
is.write(0, eid);
|
||||||
|
is.write(1, (int) location.getX() * 32);
|
||||||
|
is.write(2, (int) location.getY() * 32);
|
||||||
|
is.write(3, (int) location.getZ() * 32);
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft 虚拟悬浮物品工具类
|
||||||
|
* 需要depend ProtocolLib 4.x
|
||||||
|
*
|
||||||
|
* @author 橙子(chengzi)
|
||||||
|
* @version 1.1.0
|
||||||
|
*/
|
||||||
|
public class FakeItem_19_111 extends FakeItem {
|
||||||
|
protected final UUID uuid;
|
||||||
|
|
||||||
|
public FakeItem_19_111(Location loc, final ItemStack item) {
|
||||||
|
super(loc, item);
|
||||||
|
uuid = UUID.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer setMetadataPacket(PacketContainer fakePacket) {
|
||||||
|
fakePacket.getIntegers().write(0, eid);
|
||||||
|
final WrappedDataWatcher wr = new WrappedDataWatcher();
|
||||||
|
final Serializer serializer = WrappedDataWatcher.Registry.getItemStackSerializer(true);
|
||||||
|
final WrappedDataWatcherObject object = new WrappedDataWatcherObject(6, serializer);
|
||||||
|
wr.setObject(object, Optional.of(itemStack));
|
||||||
|
fakePacket.getWatchableCollectionModifier().write(0, wr.getWatchableObjects());
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PacketContainer setSpawnPacket(PacketContainer fakePacket) {
|
||||||
|
StructureModifier<Object> mdf = fakePacket.getModifier();
|
||||||
|
mdf.write(0, eid);
|
||||||
|
mdf.write(1, uuid);
|
||||||
|
mdf.write(2, location.getX());
|
||||||
|
mdf.write(3, location.getY());
|
||||||
|
mdf.write(4, location.getZ());
|
||||||
|
mdf.write(10, 2);
|
||||||
|
return fakePacket;
|
||||||
|
}
|
||||||
|
}
|
111
src/main/java/org/maxgamer/QuickShop/Shop/Item/NormalItem.java
Normal file
111
src/main/java/org/maxgamer/QuickShop/Shop/Item/NormalItem.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package org.maxgamer.QuickShop.Shop.Item;
|
||||||
|
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
|
import org.maxgamer.QuickShop.Util.NMS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Netherfoam A display item, that spawns a block above the chest and
|
||||||
|
* cannot be interacted with.
|
||||||
|
*/
|
||||||
|
public class NormalItem extends DisplayItem {
|
||||||
|
private final ItemStack iStack;
|
||||||
|
private Item item;
|
||||||
|
private final Location location;
|
||||||
|
|
||||||
|
// private Location displayLoc;
|
||||||
|
/**
|
||||||
|
* Creates a new display item.
|
||||||
|
*
|
||||||
|
* @param location
|
||||||
|
* The shop (See Shop)
|
||||||
|
* @param iStack
|
||||||
|
* The item stack to clone properties of the display item from.
|
||||||
|
*/
|
||||||
|
public NormalItem(final Location location, final ItemStack iStack) {
|
||||||
|
this.location = location;
|
||||||
|
this.iStack = iStack.clone();
|
||||||
|
// this.displayLoc = location().clone().add(0.5, 1.2, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the exact location of the display item. (1 above shop
|
||||||
|
* block, in the center)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Location getDisplayLocation() {
|
||||||
|
return this.location.clone().add(0.5, 1.2, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reference to this shops item. Do not modify.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Item getItem() {
|
||||||
|
return this.item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the display item.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
if (this.item == null) { return; }
|
||||||
|
this.item.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all items floating ontop of the chest that aren't the display
|
||||||
|
* item.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean removeDupe() {
|
||||||
|
if (location.getWorld() == null) { return false; }
|
||||||
|
final Location displayLoc = location.getBlock().getRelative(0, 1, 0).getLocation();
|
||||||
|
boolean removed = false;
|
||||||
|
final Chunk c = displayLoc.getChunk();
|
||||||
|
for (final Entity e : c.getEntities()) {
|
||||||
|
if (!(e instanceof Item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.item != null && e.getEntityId() == this.item.getEntityId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final Location eLoc = e.getLocation().getBlock().getLocation();
|
||||||
|
if (eLoc.equals(displayLoc) || eLoc.equals(location)) {
|
||||||
|
e.remove();
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns the new display item. Does not remove duplicate items.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void respawn() {
|
||||||
|
remove();
|
||||||
|
spawn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns the dummy item on top of the shop.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void spawn() {
|
||||||
|
if (location.getWorld() == null) { return; }
|
||||||
|
final Location dispLoc = this.getDisplayLocation();
|
||||||
|
try {
|
||||||
|
this.item = location.getWorld().dropItem(dispLoc, this.iStack);
|
||||||
|
this.item.setVelocity(new Vector(0, 0.1, 0));
|
||||||
|
NMS.safeGuard(this.item);
|
||||||
|
} catch (final Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,70 +8,70 @@ import org.bukkit.block.Sign;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
public abstract interface Shop {
|
public interface Shop {
|
||||||
public abstract void add(ItemStack paramItemStack, int paramInt);
|
void add(ItemStack paramItemStack, int paramInt);
|
||||||
|
|
||||||
public abstract void buy(Player paramPlayer, int paramInt);
|
void buy(Player paramPlayer, int paramInt);
|
||||||
|
|
||||||
public abstract Shop clone();
|
Shop clone();
|
||||||
|
|
||||||
public abstract void delete();
|
void delete();
|
||||||
|
|
||||||
public abstract void delete(boolean paramBoolean);
|
void delete(boolean paramBoolean);
|
||||||
|
|
||||||
public abstract String getDataName();
|
String getDataName();
|
||||||
|
|
||||||
public abstract short getDurability();
|
short getDurability();
|
||||||
|
|
||||||
public abstract ItemStack getItem();
|
ItemStack getItem();
|
||||||
|
|
||||||
public abstract Location getLocation();
|
Location getLocation();
|
||||||
|
|
||||||
public abstract String getOwner();
|
String getOwner();
|
||||||
|
|
||||||
public abstract double getPrice();
|
double getPrice();
|
||||||
|
|
||||||
public abstract int getRemainingSpace();
|
int getRemainingSpace();
|
||||||
|
|
||||||
public abstract int getRemainingStock();
|
int getRemainingStock();
|
||||||
|
|
||||||
public abstract ShopType getShopType();
|
ShopType getShopType();
|
||||||
|
|
||||||
public abstract List<Sign> getSigns();
|
List<Sign> getSigns();
|
||||||
|
|
||||||
public abstract boolean isAttached(Block paramBlock);
|
boolean isAttached(Block paramBlock);
|
||||||
|
|
||||||
public abstract boolean isBuying();
|
boolean isBuying();
|
||||||
|
|
||||||
public abstract boolean isSelling();
|
boolean isSelling();
|
||||||
|
|
||||||
public abstract boolean isUnlimited();
|
boolean isUnlimited();
|
||||||
|
|
||||||
public abstract boolean isValid();
|
boolean isValid();
|
||||||
|
|
||||||
public abstract boolean matches(ItemStack paramItemStack);
|
boolean matches(ItemStack paramItemStack);
|
||||||
|
|
||||||
public abstract void onClick();
|
void onClick();
|
||||||
|
|
||||||
public abstract void onLoad();
|
void onLoad();
|
||||||
|
|
||||||
public abstract void onUnload();
|
void onUnload();
|
||||||
|
|
||||||
public abstract void remove(ItemStack paramItemStack, int paramInt);
|
void remove(ItemStack paramItemStack, int paramInt);
|
||||||
|
|
||||||
public abstract void sell(Player paramPlayer, int paramInt);
|
void sell(Player paramPlayer, int paramInt);
|
||||||
|
|
||||||
public abstract void setOwner(String paramString);
|
void setOwner(String paramString);
|
||||||
|
|
||||||
public abstract void setPrice(double paramDouble);
|
void setPrice(double paramDouble);
|
||||||
|
|
||||||
public abstract void setShopType(ShopType paramShopType);
|
void setShopType(ShopType paramShopType);
|
||||||
|
|
||||||
public abstract void setSignText();
|
void setSignText();
|
||||||
|
|
||||||
public abstract void setSignText(String[] paramArrayOfString);
|
void setSignText(String[] paramArrayOfString);
|
||||||
|
|
||||||
public abstract void setUnlimited(boolean paramBoolean);
|
void setUnlimited(boolean paramBoolean);
|
||||||
|
|
||||||
public abstract void update();
|
void update();
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package org.maxgamer.QuickShop.Shop;
|
package org.maxgamer.QuickShop.Shop;
|
||||||
|
|
||||||
public enum ShopAction {
|
public enum ShopAction {
|
||||||
BUY(), CREATE(), CANCELLED();
|
BUY(),
|
||||||
|
CREATE(),
|
||||||
|
CANCELLED()
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package org.maxgamer.QuickShop.Shop;
|
package org.maxgamer.QuickShop.Shop;
|
||||||
|
|
||||||
public class ShopChunk {
|
public class ShopChunk {
|
||||||
private String world;
|
private final String world;
|
||||||
private int x;
|
private final int x;
|
||||||
private int z;
|
private final int z;
|
||||||
private int hash = 0;
|
private int hash = 0;
|
||||||
|
|
||||||
public ShopChunk(String world, int x, int z) {
|
public ShopChunk(final String world, final int x, final int z) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
@ -15,6 +15,19 @@ public class ShopChunk {
|
|||||||
// memory
|
// memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj.getClass() != this.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ShopChunk shopChunk = (ShopChunk) obj;
|
||||||
|
return (this.getWorld().equals(shopChunk.getWorld()) && this.getX() == shopChunk.getX() && this.getZ() == shopChunk.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWorld() {
|
||||||
|
return this.world;
|
||||||
|
}
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return this.x;
|
return this.x;
|
||||||
}
|
}
|
||||||
@ -23,20 +36,6 @@ public class ShopChunk {
|
|||||||
return this.z;
|
return this.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWorld() {
|
|
||||||
return this.world;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj.getClass() != this.getClass()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
ShopChunk shopChunk = (ShopChunk) obj;
|
|
||||||
return (this.getWorld().equals(shopChunk.getWorld()) && this.getX() == shopChunk.getX() && this.getZ() == shopChunk.getZ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return hash;
|
return hash;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package org.maxgamer.QuickShop.Shop;
|
package org.maxgamer.QuickShop.Shop;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -19,16 +21,16 @@ import org.bukkit.event.block.Action;
|
|||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.material.Sign;
|
import org.bukkit.material.Sign;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
|
||||||
import org.maxgamer.QuickShop.Database.Database;
|
import org.maxgamer.QuickShop.Database.Database;
|
||||||
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
import org.maxgamer.QuickShop.Util.MsgUtil;
|
import org.maxgamer.QuickShop.Util.MsgUtil;
|
||||||
import org.maxgamer.QuickShop.Util.Util;
|
import org.maxgamer.QuickShop.Util.Util;
|
||||||
|
|
||||||
public class ShopManager {
|
public class ShopManager {
|
||||||
private final HashMap<String, Info> actions = new HashMap<String, Info>();
|
|
||||||
|
|
||||||
|
private final Map<String, Info> actions = new ConcurrentHashMap<String, Info>();
|
||||||
private final QuickShop plugin;
|
private final QuickShop plugin;
|
||||||
private final HashMap<String, HashMap<ShopChunk, HashMap<Location, Shop>>> shops = new HashMap<String, HashMap<ShopChunk, HashMap<Location, Shop>>>();
|
private final HashMap<String, HashMap<ShopChunk, HashMap<Location, Shop>>> shops = new HashMap<>();
|
||||||
|
|
||||||
public ShopManager(final QuickShop plugin) {
|
public ShopManager(final QuickShop plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -45,6 +47,10 @@ public class ShopManager {
|
|||||||
* @return True if they're allowed to place a shop there.
|
* @return True if they're allowed to place a shop there.
|
||||||
*/
|
*/
|
||||||
public boolean canBuildShop(final Player p, final Block b, final BlockFace bf) {
|
public boolean canBuildShop(final Player p, final Block b, final BlockFace bf) {
|
||||||
|
if (plugin.getConfigManager().getPrevent().contains(b.getWorld().getName().toLowerCase())) {
|
||||||
|
p.sendMessage(MsgUtil.p("prevent-create"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (plugin.getConfigManager().isLimit()) {
|
if (plugin.getConfigManager().isLimit()) {
|
||||||
int owned = 0;
|
int owned = 0;
|
||||||
final Iterator<Shop> it = getShopIterator();
|
final Iterator<Shop> it = getShopIterator();
|
||||||
@ -59,18 +65,21 @@ public class ShopManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final PlayerInteractEvent pie = new PlayerInteractEvent(p, Action.RIGHT_CLICK_BLOCK, new ItemStack(Material.AIR), b, bf); // PIE = PlayerInteractEvent - What else?
|
/* 修复其他插件调用产生的报错... */
|
||||||
|
try {
|
||||||
|
final PlayerInteractEvent pie = new PlayerInteractEvent(p,
|
||||||
|
Action.RIGHT_CLICK_BLOCK,
|
||||||
|
new ItemStack(Material.AIR),
|
||||||
|
b,
|
||||||
|
bf); // PIE = PlayerInteractEvent - What else?
|
||||||
Bukkit.getPluginManager().callEvent(pie);
|
Bukkit.getPluginManager().callEvent(pie);
|
||||||
pie.getPlayer().closeInventory(); // If the player has chat open, this will close their chat.
|
pie.getPlayer().closeInventory(); // If the player has chat open, this will close their chat.
|
||||||
if (pie.isCancelled()) {
|
if (pie.isCancelled()) { return false; }
|
||||||
return false;
|
} catch (final Exception ignored) {
|
||||||
}
|
}
|
||||||
final ShopPreCreateEvent spce = new ShopPreCreateEvent(p, b.getLocation());
|
final ShopPreCreateEvent spce = new ShopPreCreateEvent(p, b.getLocation());
|
||||||
Bukkit.getPluginManager().callEvent(spce);
|
Bukkit.getPluginManager().callEvent(spce);
|
||||||
if (spce.isCancelled()) {
|
return !spce.isCancelled();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,19 +107,38 @@ public class ShopManager {
|
|||||||
public void createShop(final Shop shop) {
|
public void createShop(final Shop shop) {
|
||||||
final Location loc = shop.getLocation();
|
final Location loc = shop.getLocation();
|
||||||
final ItemStack item = shop.getItem();
|
final ItemStack item = shop.getItem();
|
||||||
|
final String serializeItem = Util.serialize(item);
|
||||||
|
final String worldName = loc.getWorld().getName();
|
||||||
|
final int x = loc.getBlockX();
|
||||||
|
final int y = loc.getBlockY();
|
||||||
|
final int z = loc.getBlockZ();
|
||||||
|
// Async database execute
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// Write it to the database
|
// Write it to the database
|
||||||
final String q = "INSERT INTO shops (owner, price, itemConfig, x, y, z, world, unlimited, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
final String q = "INSERT INTO shops (owner, price, itemConfig, x, y, z, world, unlimited, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
plugin.getDB().execute(q, shop.getOwner().toString(), shop.getPrice(), Util.serialize(item), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), loc.getWorld().getName(),
|
plugin.getDB().execute(q,
|
||||||
(shop.isUnlimited() ? 1 : 0), shop.getShopType().toID());
|
shop.getOwner(),
|
||||||
// Add it to the world
|
shop.getPrice(),
|
||||||
addShop(loc.getWorld().getName(), shop);
|
serializeItem,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
worldName,
|
||||||
|
(shop.isUnlimited() ? 1 : 0),
|
||||||
|
shop.getShopType().toID());
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
plugin.getLogger().warning("无法保存商店到数据库! 下次重启商店将会消失!");
|
plugin.getLogger().warning("无法保存商店到数据库! 下次重启商店将会消失!");
|
||||||
plugin.getLogger().warning("错误信息: " + e.getMessage());
|
plugin.getLogger().warning("错误信息: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
// Add it to the world
|
||||||
|
addShop(worldName, shop);
|
||||||
|
}
|
||||||
|
|
||||||
public String format(final double d) {
|
public String format(final double d) {
|
||||||
return plugin.getEcon().format(d);
|
return plugin.getEcon().format(d);
|
||||||
@ -120,7 +148,7 @@ public class ShopManager {
|
|||||||
* @return Returns the HashMap<Player name, shopInfo>. Info contains what
|
* @return Returns the HashMap<Player name, shopInfo>. Info contains what
|
||||||
* their last question etc was.
|
* their last question etc was.
|
||||||
*/
|
*/
|
||||||
public HashMap<String, Info> getActions() {
|
public Map<String, Info> getActions() {
|
||||||
return this.actions;
|
return this.actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,9 +165,7 @@ public class ShopManager {
|
|||||||
*/
|
*/
|
||||||
public Shop getShop(final Location loc) {
|
public Shop getShop(final Location loc) {
|
||||||
final HashMap<Location, Shop> inChunk = getShops(loc.getChunk());
|
final HashMap<Location, Shop> inChunk = getShops(loc.getChunk());
|
||||||
if (inChunk == null) {
|
if (inChunk == null) { return null; }
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// We can do this because WorldListener updates the world reference so
|
// We can do this because WorldListener updates the world reference so
|
||||||
// the world in loc is the same as world in inChunk.get(loc)
|
// the world in loc is the same as world in inChunk.get(loc)
|
||||||
return inChunk.get(loc);
|
return inChunk.get(loc);
|
||||||
@ -174,11 +200,10 @@ public class ShopManager {
|
|||||||
*/
|
*/
|
||||||
public HashMap<Location, Shop> getShops(final Chunk c) {
|
public HashMap<Location, Shop> getShops(final Chunk c) {
|
||||||
// long start = System.nanoTime();
|
// long start = System.nanoTime();
|
||||||
final HashMap<Location, Shop> shops = getShops(c.getWorld().getName(), c.getX(), c.getZ());
|
|
||||||
// long end = System.nanoTime();
|
// long end = System.nanoTime();
|
||||||
// System.out.println("Chunk lookup in " + ((end - start)/1000000.0) +
|
// System.out.println("Chunk lookup in " + ((end - start)/1000000.0) +
|
||||||
// "ms.");
|
// "ms.");
|
||||||
return shops;
|
return getShops(c.getWorld().getName(), c.getX(), c.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,132 +220,24 @@ public class ShopManager {
|
|||||||
|
|
||||||
public HashMap<Location, Shop> getShops(final String world, final int chunkX, final int chunkZ) {
|
public HashMap<Location, Shop> getShops(final String world, final int chunkX, final int chunkZ) {
|
||||||
final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops(world);
|
final HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops(world);
|
||||||
if (inWorld == null) {
|
if (inWorld == null) { return null; }
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final ShopChunk shopChunk = new ShopChunk(world, chunkX, chunkZ);
|
final ShopChunk shopChunk = new ShopChunk(world, chunkX, chunkZ);
|
||||||
return inWorld.get(shopChunk);
|
return inWorld.get(shopChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleChat(final Player p, final String msg) {
|
public void handleChat(final Player p, final String msgs) {
|
||||||
final String message = ChatColor.stripColor(msg);
|
final String message = ChatColor.stripColor(msgs);
|
||||||
// Use from the main thread, because Bukkit hates life
|
final Map<String, Info> actions = getActions();
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final HashMap<String, Info> actions = getActions();
|
|
||||||
// They wanted to do something.
|
// They wanted to do something.
|
||||||
final Info info = actions.remove(p.getName());
|
final Info info = actions.remove(p.getName());
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return; // multithreaded means this can happen
|
return; // multithreaded means this can happen
|
||||||
}
|
}
|
||||||
if (info.getLocation().getWorld() != p.getLocation().getWorld()) {
|
|
||||||
p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (info.getLocation().distanceSquared(p.getLocation()) > 25) {
|
|
||||||
p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Creation handling */
|
/* Creation handling */
|
||||||
if (info.getAction() == ShopAction.CREATE) {
|
if (info.getAction() == ShopAction.CREATE) {
|
||||||
try {
|
create(p, info, message);
|
||||||
// Checking the shop can be created
|
} else if (/* Purchase Handling */info.getAction() == ShopAction.BUY) {
|
||||||
if (plugin.getShopManager().getShop(info.getLocation()) != null) {
|
int amount;
|
||||||
p.sendMessage(MsgUtil.p("shop-already-owned"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Util.getSecondHalf(info.getLocation().getBlock()) != null && !p.hasPermission("quickshop.create.double")) {
|
|
||||||
p.sendMessage(MsgUtil.p("no-double-chests"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Util.canBeShop(info.getLocation().getBlock()) == false) {
|
|
||||||
p.sendMessage(MsgUtil.p("chest-was-removed"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Price per item
|
|
||||||
double price;
|
|
||||||
if (plugin.getConfig().getBoolean("whole-number-prices-only")) {
|
|
||||||
price = Integer.parseInt(message);
|
|
||||||
} else {
|
|
||||||
price = Double.parseDouble(message);
|
|
||||||
}
|
|
||||||
if (price < 0.01) {
|
|
||||||
p.sendMessage(MsgUtil.p("price-too-cheap"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final double tax = plugin.getConfig().getDouble("shop.cost");
|
|
||||||
// Tax refers to the cost to create a shop. Not actual
|
|
||||||
// tax, that would be silly
|
|
||||||
if (tax != 0 && plugin.getEcon().getBalance(p.getName()) < tax) {
|
|
||||||
p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Create the sample shop.
|
|
||||||
final Shop shop = new ContainerShop(info.getLocation(), price, info.getItem(), p.getName());
|
|
||||||
// This must be called after the event has been called.
|
|
||||||
// Else, if the event is cancelled, they won't get their
|
|
||||||
// money back.
|
|
||||||
if (tax != 0) {
|
|
||||||
if (!plugin.getEcon().withdraw(p.getName(), tax)) {
|
|
||||||
p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), tax);
|
|
||||||
}
|
|
||||||
final ShopCreateEvent e = new ShopCreateEvent(shop, p);
|
|
||||||
Bukkit.getPluginManager().callEvent(e);
|
|
||||||
if (e.isCancelled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
shop.onLoad();
|
|
||||||
/* The shop has hereforth been successfully created */
|
|
||||||
createShop(shop);
|
|
||||||
p.sendMessage(MsgUtil.p("success-created-shop"));
|
|
||||||
final Location loc = shop.getLocation();
|
|
||||||
plugin.log(p.getName() + " created a " + shop.getDataName() + " shop at (" + loc.getWorld().getName() + " - " + loc.getX() + "," + loc.getY() + "," + loc.getZ() + ")");
|
|
||||||
if (!plugin.getConfig().getBoolean("shop.lock")) {
|
|
||||||
// Warn them if they haven't been warned since
|
|
||||||
// reboot
|
|
||||||
final HashSet<String> warings = plugin.getConfigManager().getWarnings();
|
|
||||||
if (!warings.contains(p.getName())) {
|
|
||||||
p.sendMessage(MsgUtil.p("shops-arent-locked"));
|
|
||||||
warings.add(p.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Figures out which way we should put the sign on and
|
|
||||||
// sets its text.
|
|
||||||
if (info.getSignBlock() != null && info.getSignBlock().getType() == Material.AIR && plugin.getConfig().getBoolean("shop.auto-sign")) {
|
|
||||||
final BlockState bs = info.getSignBlock().getState();
|
|
||||||
final BlockFace bf = info.getLocation().getBlock().getFace(info.getSignBlock());
|
|
||||||
bs.setType(Material.WALL_SIGN);
|
|
||||||
final Sign sign = (Sign) bs.getData();
|
|
||||||
sign.setFacingDirection(bf);
|
|
||||||
bs.update(true);
|
|
||||||
shop.setSignText();
|
|
||||||
}
|
|
||||||
if (shop instanceof ContainerShop) {
|
|
||||||
final ContainerShop cs = (ContainerShop) shop;
|
|
||||||
if (cs.isDoubleShop()) {
|
|
||||||
final Shop nextTo = cs.getAttachedShop();
|
|
||||||
if (nextTo.getPrice() > shop.getPrice()) {
|
|
||||||
// The one next to it must always be a
|
|
||||||
// buying shop.
|
|
||||||
p.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* They didn't enter a number. */
|
|
||||||
catch (final NumberFormatException ex) {
|
|
||||||
p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Purchase Handling */
|
|
||||||
else if (info.getAction() == ShopAction.BUY) {
|
|
||||||
int amount = 0;
|
|
||||||
try {
|
try {
|
||||||
amount = Integer.parseInt(message);
|
amount = Integer.parseInt(message);
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
@ -330,7 +247,7 @@ public class ShopManager {
|
|||||||
// Get the shop they interacted with
|
// Get the shop they interacted with
|
||||||
final Shop shop = plugin.getShopManager().getShop(info.getLocation());
|
final Shop shop = plugin.getShopManager().getShop(info.getLocation());
|
||||||
// It's not valid anymore
|
// It's not valid anymore
|
||||||
if (shop == null || Util.canBeShop(info.getLocation().getBlock()) == false) {
|
if (shop == null || !Util.canBeShop(info.getLocation().getBlock())) {
|
||||||
p.sendMessage(MsgUtil.p("chest-was-removed"));
|
p.sendMessage(MsgUtil.p("chest-was-removed"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -339,139 +256,12 @@ public class ShopManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (shop.isSelling()) {
|
if (shop.isSelling()) {
|
||||||
final int stock = shop.getRemainingStock();
|
sale(p, shop, amount);
|
||||||
if (stock < amount) {
|
|
||||||
p.sendMessage(MsgUtil.p("shop-stock-too-low", "" + shop.getRemainingStock(), shop.getDataName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (amount == 0) {
|
|
||||||
// Dumb.
|
|
||||||
MsgUtil.sendPurchaseSuccess(p, shop, amount);
|
|
||||||
return;
|
|
||||||
} else if (amount < 0) {
|
|
||||||
// & Dumber
|
|
||||||
p.sendMessage(MsgUtil.p("negative-amount"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final int pSpace = Util.countSpace(p.getInventory(), shop.getItem());
|
|
||||||
if (amount > pSpace) {
|
|
||||||
p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
|
|
||||||
Bukkit.getPluginManager().callEvent(e);
|
|
||||||
if (e.isCancelled()) {
|
|
||||||
return; // Cancelled
|
|
||||||
}
|
|
||||||
// Money handling
|
|
||||||
if (!p.getName().equals(shop.getOwner())) {
|
|
||||||
// Check their balance. Works with *most* economy
|
|
||||||
// plugins*
|
|
||||||
if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) {
|
|
||||||
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName()))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Don't tax them if they're purchasing from
|
|
||||||
// themselves.
|
|
||||||
// Do charge an amount of tax though.
|
|
||||||
final double tax = plugin.getConfigManager().getTax();
|
|
||||||
final double total = amount * shop.getPrice();
|
|
||||||
if (!plugin.getEcon().withdraw(p.getName(), total)) {
|
|
||||||
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName()))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) {
|
|
||||||
plugin.getEcon().deposit(shop.getOwner(), total * (1 - tax));
|
|
||||||
if (tax != 0) {
|
|
||||||
plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Notify the shop owner
|
|
||||||
if (plugin.getConfigManager().isShowTax()) {
|
|
||||||
String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total)));
|
|
||||||
if (stock == amount) {
|
|
||||||
msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(),
|
|
||||||
shop.getDataName());
|
|
||||||
}
|
|
||||||
MsgUtil.send(shop.getOwner(), msg);
|
|
||||||
} else {
|
|
||||||
String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName());
|
|
||||||
if (stock == amount) {
|
|
||||||
msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(),
|
|
||||||
shop.getDataName());
|
|
||||||
}
|
|
||||||
MsgUtil.send(shop.getOwner(), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Transfers the item from A to B
|
|
||||||
shop.sell(p, amount);
|
|
||||||
MsgUtil.sendPurchaseSuccess(p, shop, amount);
|
|
||||||
plugin.log(String.format("%s 从 %s 购买了 %s 件商品 花费 %s", p.getName(), shop.toString(), amount, shop.getPrice() * amount));
|
|
||||||
} else if (shop.isBuying()) {
|
} else if (shop.isBuying()) {
|
||||||
final int space = shop.getRemainingSpace();
|
buy(p, shop, amount);
|
||||||
if (space < amount) {
|
|
||||||
p.sendMessage(MsgUtil.p("shop-has-no-space", "" + space, shop.getDataName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final int count = Util.countItems(p.getInventory(), shop.getItem());
|
|
||||||
// Not enough items
|
|
||||||
if (amount > count) {
|
|
||||||
p.sendMessage(MsgUtil.p("you-dont-have-that-many-items", "" + count, shop.getDataName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (amount == 0) {
|
|
||||||
// Dumb.
|
|
||||||
MsgUtil.sendPurchaseSuccess(p, shop, amount);
|
|
||||||
return;
|
|
||||||
} else if (amount < 0) {
|
|
||||||
// & Dumber
|
|
||||||
p.sendMessage(MsgUtil.p("negative-amount"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Money handling
|
|
||||||
if (!p.getName().equals(shop.getOwner())) {
|
|
||||||
// Don't tax them if they're purchasing from
|
|
||||||
// themselves.
|
|
||||||
// Do charge an amount of tax though.
|
|
||||||
final double tax = plugin.getConfigManager().getTax();
|
|
||||||
final double total = amount * shop.getPrice();
|
|
||||||
if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) {
|
|
||||||
// Tries to check their balance nicely to see if
|
|
||||||
// they can afford it.
|
|
||||||
if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) {
|
|
||||||
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner()))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check for plugins faking econ.has(amount)
|
|
||||||
if (!plugin.getEcon().withdraw(shop.getOwner(), total)) {
|
|
||||||
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner()))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tax != 0) {
|
|
||||||
plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Give them the money after we know we succeeded
|
|
||||||
plugin.getEcon().deposit(p.getName(), total * (1 - tax));
|
|
||||||
// Notify the owner of the purchase.
|
|
||||||
String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName());
|
|
||||||
if (space == amount) {
|
|
||||||
msg += "\n" + MsgUtil.p("shop-out-of-space", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ());
|
|
||||||
}
|
|
||||||
MsgUtil.send(shop.getOwner(), msg);
|
|
||||||
}
|
|
||||||
shop.buy(p, amount);
|
|
||||||
MsgUtil.sendSellSuccess(p, shop, amount);
|
|
||||||
plugin.log(String.format("%s 出售了 %s 件商品 到 %s 获得 %s", p.getName(), amount, shop.toString(), shop.getPrice() * amount));
|
|
||||||
}
|
}
|
||||||
shop.setSignText(); // Update the signs count
|
shop.setSignText(); // Update the signs count
|
||||||
}
|
}
|
||||||
/* If it was already cancelled (from destroyed) */
|
|
||||||
else {
|
|
||||||
return; // It was cancelled, go away.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -518,7 +308,7 @@ public class ShopManager {
|
|||||||
HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops().get(world);
|
HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops().get(world);
|
||||||
// There's no world storage yet. We need to create that hashmap.
|
// There's no world storage yet. We need to create that hashmap.
|
||||||
if (inWorld == null) {
|
if (inWorld == null) {
|
||||||
inWorld = new HashMap<ShopChunk, HashMap<Location, Shop>>(3);
|
inWorld = new HashMap<>(3);
|
||||||
// Put it in the data universe
|
// Put it in the data universe
|
||||||
this.getShops().put(world, inWorld);
|
this.getShops().put(world, inWorld);
|
||||||
}
|
}
|
||||||
@ -531,7 +321,7 @@ public class ShopManager {
|
|||||||
HashMap<Location, Shop> inChunk = inWorld.get(shopChunk);
|
HashMap<Location, Shop> inChunk = inWorld.get(shopChunk);
|
||||||
// That chunk data hasn't been created yet - Create it!
|
// That chunk data hasn't been created yet - Create it!
|
||||||
if (inChunk == null) {
|
if (inChunk == null) {
|
||||||
inChunk = new HashMap<Location, Shop>(1);
|
inChunk = new HashMap<>(1);
|
||||||
// Put it in the world
|
// Put it in the world
|
||||||
inWorld.put(shopChunk, inChunk);
|
inWorld.put(shopChunk, inChunk);
|
||||||
}
|
}
|
||||||
@ -539,6 +329,254 @@ public class ShopManager {
|
|||||||
inChunk.put(shop.getLocation(), shop);
|
inChunk.put(shop.getLocation(), shop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buy(final Player p, final Shop shop, final int amount) {
|
||||||
|
final int space = shop.getRemainingSpace();
|
||||||
|
if (space < amount) {
|
||||||
|
p.sendMessage(MsgUtil.p("shop-has-no-space", "" + space, shop.getDataName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int count = Util.countItems(p.getInventory(), shop.getItem());
|
||||||
|
// Not enough items
|
||||||
|
if (amount > count) {
|
||||||
|
p.sendMessage(MsgUtil.p("you-dont-have-that-many-items", "" + count, shop.getDataName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!checkAmount(p, shop, amount)) { return; }
|
||||||
|
// Money handling
|
||||||
|
if (!p.getName().equals(shop.getOwner())) {
|
||||||
|
// Don't tax them if they're purchasing from
|
||||||
|
// themselves.
|
||||||
|
// Do charge an amount of tax though.
|
||||||
|
final double tax = plugin.getConfigManager().getTax();
|
||||||
|
final double total = amount * shop.getPrice();
|
||||||
|
if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) {
|
||||||
|
// Tries to check their balance nicely to see if
|
||||||
|
// they can afford it.
|
||||||
|
if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) {
|
||||||
|
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you",
|
||||||
|
format(amount * shop.getPrice()),
|
||||||
|
format(plugin.getEcon().getBalance(shop.getOwner()))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
|
||||||
|
Bukkit.getPluginManager().callEvent(e);
|
||||||
|
if (e.isCancelled()) {
|
||||||
|
return; // Cancelled
|
||||||
|
}
|
||||||
|
// Check for plugins faking econ.has(amount)
|
||||||
|
if (!plugin.getEcon().withdraw(shop.getOwner(), total)) {
|
||||||
|
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you",
|
||||||
|
format(amount * shop.getPrice()),
|
||||||
|
format(plugin.getEcon().getBalance(shop.getOwner()))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tax != 0) {
|
||||||
|
plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Give them the money after we know we succeeded
|
||||||
|
plugin.getEcon().deposit(p.getName(), total * (1 - tax));
|
||||||
|
// Notify the owner of the purchase.
|
||||||
|
String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName());
|
||||||
|
if (space == amount) {
|
||||||
|
msg += "\n" + MsgUtil.p("shop-out-of-space",
|
||||||
|
"" + shop.getLocation().getBlockX(),
|
||||||
|
"" + shop.getLocation().getBlockY(),
|
||||||
|
"" + shop.getLocation().getBlockZ());
|
||||||
|
}
|
||||||
|
MsgUtil.send(shop.getOwner(), msg);
|
||||||
|
}
|
||||||
|
shop.buy(p, amount);
|
||||||
|
MsgUtil.sendSellSuccess(p, shop, amount);
|
||||||
|
plugin.log(String.format("玩家: %s 出售了 %s 件商品 到 %s 获得 %s", p.getName(), amount, shop.toString(), shop.getPrice() * amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void create(final Player p, final Info info, final String message) {
|
||||||
|
try {
|
||||||
|
// Checking the shop can be created
|
||||||
|
if (plugin.getShopManager().getShop(info.getLocation()) != null) {
|
||||||
|
p.sendMessage(MsgUtil.p("shop-already-owned"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Util.getSecondHalf(info.getLocation().getBlock()) != null && !p.hasPermission("quickshop.create.double")) {
|
||||||
|
p.sendMessage(MsgUtil.p("no-double-chests"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Util.canBeShop(info.getLocation().getBlock())) {
|
||||||
|
p.sendMessage(MsgUtil.p("chest-was-removed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Price per item
|
||||||
|
double price;
|
||||||
|
if (plugin.getConfig().getBoolean("whole-number-prices-only")) {
|
||||||
|
price = Integer.parseInt(message);
|
||||||
|
} else {
|
||||||
|
price = Double.parseDouble(message);
|
||||||
|
}
|
||||||
|
if (price < 0.01) {
|
||||||
|
p.sendMessage(MsgUtil.p("price-too-cheap"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final double tax = plugin.getConfig().getDouble("shop.cost");
|
||||||
|
// Tax refers to the cost to create a shop. Not actual
|
||||||
|
// tax, that would be silly
|
||||||
|
if (tax != 0 && plugin.getEcon().getBalance(p.getName()) < tax) {
|
||||||
|
p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create the sample shop.
|
||||||
|
final Shop shop = new ContainerShop(info.getLocation(), price, info.getItem(), p.getName());
|
||||||
|
// This must be called after the event has been called.
|
||||||
|
// Else, if the event is cancelled, they won't get their
|
||||||
|
// money back.
|
||||||
|
if (tax != 0) {
|
||||||
|
if (!plugin.getEcon().withdraw(p.getName(), tax)) {
|
||||||
|
p.sendMessage(MsgUtil.p("you-cant-afford-a-new-shop", format(tax)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.getEcon().deposit(plugin.getConfig().getString("tax-account"), tax);
|
||||||
|
}
|
||||||
|
final ShopCreateEvent e = new ShopCreateEvent(shop, p);
|
||||||
|
Bukkit.getPluginManager().callEvent(e);
|
||||||
|
if (e.isCancelled()) { return; }
|
||||||
|
shop.onLoad();
|
||||||
|
/* The shop has hereforth been successfully created */
|
||||||
|
createShop(shop);
|
||||||
|
p.sendMessage(MsgUtil.p("success-created-shop"));
|
||||||
|
final Location loc = shop.getLocation();
|
||||||
|
plugin.log(String.format("玩家: %s 创建了一个 %s 商店 在 (%s - %s, %s, %s)",
|
||||||
|
p.getName(),
|
||||||
|
shop.getDataName(),
|
||||||
|
loc.getWorld().getName(),
|
||||||
|
loc.getX(),
|
||||||
|
loc.getY(),
|
||||||
|
loc.getZ()));
|
||||||
|
if (!plugin.getConfig().getBoolean("shop.lock")) {
|
||||||
|
// Warn them if they haven't been warned since
|
||||||
|
// reboot
|
||||||
|
final Set<String> warings = plugin.getConfigManager().getWarnings();
|
||||||
|
if (!warings.contains(p.getName())) {
|
||||||
|
p.sendMessage(MsgUtil.p("shops-arent-locked"));
|
||||||
|
warings.add(p.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Figures out which way we should put the sign on and
|
||||||
|
// sets its text.
|
||||||
|
if (info.getSignBlock() != null && info.getSignBlock().getType() == Material.AIR && plugin.getConfig().getBoolean("shop.auto-sign")) {
|
||||||
|
final BlockState bs = info.getSignBlock().getState();
|
||||||
|
final BlockFace bf = info.getLocation().getBlock().getFace(info.getSignBlock());
|
||||||
|
bs.setType(Material.WALL_SIGN);
|
||||||
|
final Sign sign = (Sign) bs.getData();
|
||||||
|
sign.setFacingDirection(bf);
|
||||||
|
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
bs.update(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
shop.setSignText();
|
||||||
|
}
|
||||||
|
final ContainerShop cs = (ContainerShop) shop;
|
||||||
|
if (cs.isDoubleShop()) {
|
||||||
|
final Shop nextTo = cs.getAttachedShop();
|
||||||
|
if (nextTo.getPrice() > shop.getPrice()) {
|
||||||
|
// The one next to it must always be a
|
||||||
|
// buying shop.
|
||||||
|
p.sendMessage(MsgUtil.p("buying-more-than-selling"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* They didn't enter a number. */ catch (final NumberFormatException ex) {
|
||||||
|
p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sale(final Player p, final Shop shop, final int amount) {
|
||||||
|
final int stock = shop.getRemainingStock();
|
||||||
|
if (stock < amount) {
|
||||||
|
p.sendMessage(MsgUtil.p("shop-stock-too-low", "" + shop.getRemainingStock(), shop.getDataName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!checkAmount(p, shop, amount)) { return; }
|
||||||
|
final int pSpace = Util.countSpace(p.getInventory(), shop.getItem());
|
||||||
|
if (amount > pSpace) {
|
||||||
|
p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Money handling
|
||||||
|
if (!p.getName().equals(shop.getOwner())) {
|
||||||
|
// Check their balance. Works with *most* economy
|
||||||
|
// plugins*
|
||||||
|
if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) {
|
||||||
|
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy",
|
||||||
|
format(amount * shop.getPrice()),
|
||||||
|
format(plugin.getEcon().getBalance(p.getName()))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
|
||||||
|
Bukkit.getPluginManager().callEvent(e);
|
||||||
|
if (e.isCancelled()) {
|
||||||
|
return; // Cancelled
|
||||||
|
}
|
||||||
|
// Don't tax them if they're purchasing from
|
||||||
|
// themselves.
|
||||||
|
// Do charge an amount of tax though.
|
||||||
|
final double tax = plugin.getConfigManager().getTax();
|
||||||
|
final double total = amount * shop.getPrice();
|
||||||
|
if (!plugin.getEcon().withdraw(p.getName(), total)) {
|
||||||
|
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy",
|
||||||
|
format(amount * shop.getPrice()),
|
||||||
|
format(plugin.getEcon().getBalance(p.getName()))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) {
|
||||||
|
plugin.getEcon().deposit(shop.getOwner(), total * (1 - tax));
|
||||||
|
if (tax != 0) {
|
||||||
|
plugin.getEcon().deposit(plugin.getConfigManager().getTaxAccount(), total * tax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Notify the shop owner
|
||||||
|
if (plugin.getConfigManager().isShowTax()) {
|
||||||
|
String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total)));
|
||||||
|
if (stock == amount) {
|
||||||
|
msg += "\n" + MsgUtil.p("shop-out-of-stock",
|
||||||
|
"" + shop.getLocation().getBlockX(),
|
||||||
|
"" + shop.getLocation().getBlockY(),
|
||||||
|
"" + shop.getLocation().getBlockZ(),
|
||||||
|
shop.getDataName());
|
||||||
|
}
|
||||||
|
MsgUtil.send(shop.getOwner(), msg);
|
||||||
|
} else {
|
||||||
|
String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName());
|
||||||
|
if (stock == amount) {
|
||||||
|
msg += "\n" + MsgUtil.p("shop-out-of-stock",
|
||||||
|
"" + shop.getLocation().getBlockX(),
|
||||||
|
"" + shop.getLocation().getBlockY(),
|
||||||
|
"" + shop.getLocation().getBlockZ(),
|
||||||
|
shop.getDataName());
|
||||||
|
}
|
||||||
|
MsgUtil.send(shop.getOwner(), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Transfers the item from A to B
|
||||||
|
shop.sell(p, amount);
|
||||||
|
MsgUtil.sendPurchaseSuccess(p, shop, amount);
|
||||||
|
plugin.log(String.format("玩家: %s 从 %s 购买了 %s 件商品 花费 %s", p.getName(), shop.toString(), amount, shop.getPrice() * amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAmount(Player p, Shop shop, int amount) {
|
||||||
|
if (amount == 0) {
|
||||||
|
// Dumb.
|
||||||
|
MsgUtil.sendPurchaseSuccess(p, shop, amount);
|
||||||
|
return false;
|
||||||
|
} else if (amount < 0) {
|
||||||
|
// & Dumber
|
||||||
|
p.sendMessage(MsgUtil.p("negative-amount"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public class ShopIterator implements Iterator<Shop> {
|
public class ShopIterator implements Iterator<Shop> {
|
||||||
private Iterator<HashMap<Location, Shop>> chunks;
|
private Iterator<HashMap<Location, Shop>> chunks;
|
||||||
private Shop current;
|
private Shop current;
|
||||||
@ -556,17 +594,13 @@ public class ShopManager {
|
|||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
if (shops == null || !shops.hasNext()) {
|
if (shops == null || !shops.hasNext()) {
|
||||||
if (chunks == null || !chunks.hasNext()) {
|
if (chunks == null || !chunks.hasNext()) {
|
||||||
if (!worlds.hasNext()) {
|
if (!worlds.hasNext()) { return false; }
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
chunks = worlds.next().values().iterator();
|
chunks = worlds.next().values().iterator();
|
||||||
return hasNext();
|
return hasNext();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
shops = chunks.next().values().iterator();
|
shops = chunks.next().values().iterator();
|
||||||
return hasNext();
|
return hasNext();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,9 +612,7 @@ public class ShopManager {
|
|||||||
public Shop next() {
|
public Shop next() {
|
||||||
if (shops == null || !shops.hasNext()) {
|
if (shops == null || !shops.hasNext()) {
|
||||||
if (chunks == null || !chunks.hasNext()) {
|
if (chunks == null || !chunks.hasNext()) {
|
||||||
if (!worlds.hasNext()) {
|
if (!worlds.hasNext()) { throw new NoSuchElementException("No more shops to iterate over!"); }
|
||||||
throw new NoSuchElementException("No more shops to iterate over!");
|
|
||||||
}
|
|
||||||
chunks = worlds.next().values().iterator();
|
chunks = worlds.next().values().iterator();
|
||||||
}
|
}
|
||||||
shops = chunks.next().values().iterator();
|
shops = chunks.next().values().iterator();
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package org.maxgamer.QuickShop.Shop;
|
package org.maxgamer.QuickShop.Shop;
|
||||||
|
|
||||||
public enum ShopType {
|
public enum ShopType {
|
||||||
SELLING(0), BUYING(1);
|
SELLING(0),
|
||||||
|
BUYING(1);
|
||||||
private int id;
|
private int id;
|
||||||
private ShopType(int id){
|
|
||||||
|
ShopType(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShopType fromID(int id) {
|
public static ShopType fromID(int id) {
|
||||||
for(ShopType type:ShopType.values()){
|
for (ShopType type : ShopType.values()) {
|
||||||
if(type.id==id){
|
if (type.id == id) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,17 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
import org.maxgamer.QuickShop.Shop.Shop;
|
import org.maxgamer.QuickShop.Shop.Shop;
|
||||||
|
|
||||||
import cn.citycraft.PluginHelper.config.FileConfig;
|
import pw.yumc.YumCore.bukkit.Log;
|
||||||
import mkremins.fanciful.FancyMessage;
|
import pw.yumc.YumCore.config.FileConfig;
|
||||||
|
import pw.yumc.YumCore.tellraw.Tellraw;
|
||||||
|
|
||||||
public class MsgUtil {
|
public class MsgUtil {
|
||||||
private static FileConfig messages;
|
private static FileConfig messages;
|
||||||
private static HashMap<String, LinkedList<String>> player_messages = new HashMap<String, LinkedList<String>>();
|
private static HashMap<String, LinkedList<String>> player_messages = new HashMap<>();
|
||||||
private static QuickShop plugin;
|
private static QuickShop plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +40,7 @@ public class MsgUtil {
|
|||||||
* The player to message
|
* The player to message
|
||||||
* @return true if success, false if the player is offline or null
|
* @return true if success, false if the player is offline or null
|
||||||
*/
|
*/
|
||||||
public static boolean flush(final OfflinePlayer p) {
|
public static void flush(final OfflinePlayer p) {
|
||||||
if (p != null && p.isOnline()) {
|
if (p != null && p.isOnline()) {
|
||||||
final String pName = p.getName();
|
final String pName = p.getName();
|
||||||
final LinkedList<String> msgs = player_messages.get(pName);
|
final LinkedList<String> msgs = player_messages.get(pName);
|
||||||
@ -51,15 +51,13 @@ public class MsgUtil {
|
|||||||
plugin.getDB().execute("DELETE FROM messages WHERE owner = ?", pName);
|
plugin.getDB().execute("DELETE FROM messages WHERE owner = ?", pName);
|
||||||
msgs.clear();
|
msgs.clear();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init(final QuickShop plugin) {
|
public static void init(final QuickShop plugin) {
|
||||||
MsgUtil.plugin = plugin;
|
MsgUtil.plugin = plugin;
|
||||||
// Load messages.yml
|
// Load messages.yml
|
||||||
messages = new FileConfig(plugin, "messages.yml");
|
messages = new FileConfig("messages.yml");
|
||||||
// Parse colour codes
|
// Parse colour codes
|
||||||
Util.parseColours(messages);
|
Util.parseColours(messages);
|
||||||
}
|
}
|
||||||
@ -74,33 +72,30 @@ public class MsgUtil {
|
|||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
final String owner = rs.getString("owner");
|
final String owner = rs.getString("owner");
|
||||||
final String message = rs.getString("message");
|
final String message = rs.getString("message");
|
||||||
LinkedList<String> msgs = player_messages.get(owner);
|
LinkedList<String> msgs = player_messages.computeIfAbsent(owner, k -> new LinkedList<>());
|
||||||
if (msgs == null) {
|
|
||||||
msgs = new LinkedList<String>();
|
|
||||||
player_messages.put(owner, msgs);
|
|
||||||
}
|
|
||||||
msgs.add(message);
|
msgs.add(message);
|
||||||
}
|
}
|
||||||
} catch (final SQLException e) {
|
} catch (final SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
System.out.println("无法从数据库获得玩家的交易记录 跳过...");
|
Log.d("无法从数据库获得玩家的交易记录 跳过...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String p(final String loc, final Object... args) {
|
public static String p(final String loc, final Object... args) {
|
||||||
String raw = messages.getString(loc);
|
String raw = messages.getString(loc);
|
||||||
if (raw == null || raw.isEmpty()) {
|
if (raw == null || raw.isEmpty()) { return ChatColor.RED + "语言文件词条丢失: " + loc; }
|
||||||
return "语言文件词条丢失: " + loc;
|
if (args == null) { return raw; }
|
||||||
}
|
|
||||||
if (args == null) {
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
raw = raw.replace("{" + i + "}", args[i] == null ? "null" : args[i].toString());
|
raw = raw.replace("{" + i + "}", args[i] == null ? "null" : args[i].toString());
|
||||||
}
|
}
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void reload() {
|
||||||
|
messages.reload();
|
||||||
|
Util.parseColours(messages);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param player
|
* @param player
|
||||||
* The name of the player to message
|
* The name of the player to message
|
||||||
@ -110,27 +105,25 @@ public class MsgUtil {
|
|||||||
* them in the database.
|
* them in the database.
|
||||||
*/
|
*/
|
||||||
public static void send(final String player, final String message) {
|
public static void send(final String player, final String message) {
|
||||||
@SuppressWarnings("deprecation")
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
final OfflinePlayer p = Bukkit.getOfflinePlayer(player);
|
final Player p = Bukkit.getPlayerExact(player);
|
||||||
if (p == null || !p.isOnline()) {
|
if (p == null || !p.isOnline()) {
|
||||||
LinkedList<String> msgs = player_messages.get(player);
|
LinkedList<String> msgs = player_messages.computeIfAbsent(player, k -> new LinkedList<>());
|
||||||
if (msgs == null) {
|
|
||||||
msgs = new LinkedList<String>();
|
|
||||||
player_messages.put(player, msgs);
|
|
||||||
}
|
|
||||||
msgs.add(message);
|
msgs.add(message);
|
||||||
final String q = "INSERT INTO messages (owner, message, time) VALUES (?, ?, ?)";
|
final String q = "INSERT INTO messages (owner, message, time) VALUES (?, ?, ?)";
|
||||||
plugin.getDB().execute(q, player.toString(), message, System.currentTimeMillis());
|
plugin.getDB().execute(q, player, message, System.currentTimeMillis());
|
||||||
} else {
|
} else {
|
||||||
p.getPlayer().sendMessage(message);
|
p.getPlayer().sendMessage(message);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendItemMessage(final Player p, final ItemStack is, final String msg) {
|
public static void sendItemMessage(final Player p, final ItemStack is, final String msg) {
|
||||||
try {
|
try {
|
||||||
final FancyMessage fm = new FancyMessage();
|
final Tellraw fm = Tellraw.create();
|
||||||
fm.text(msg).itemTooltip(is).send(p);
|
fm.text(msg).item(is).send(p);
|
||||||
} catch (Exception | NoClassDefFoundError | NoSuchMethodError e) {
|
} catch (Exception | NoClassDefFoundError | NoSuchMethodError e) {
|
||||||
|
plugin.getConfigManager().setEnableMagicLib(false);
|
||||||
p.sendMessage(msg);
|
p.sendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,26 +158,25 @@ public class MsgUtil {
|
|||||||
sendShopInfo(p, shop, shop.getRemainingStock());
|
sendShopInfo(p, shop, shop.getRemainingStock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static void sendShopInfo(final Player p, final Shop shop, final int stock) {
|
public static void sendShopInfo(final Player p, final Shop shop, final int stock) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
// Potentially faster with an array?
|
// Potentially faster with an array?
|
||||||
final ItemStack items = shop.getItem();
|
final ItemStack item = shop.getItem();
|
||||||
p.sendMessage("");
|
p.sendMessage("");
|
||||||
p.sendMessage("");
|
p.sendMessage("");
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
|
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information"));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information"));
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| "
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.owner", shop.getOwner() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : shop.getOwner()));
|
||||||
+ MsgUtil.p("menu.owner", Bukkit.getOfflinePlayer(shop.getOwner()).getName() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : Bukkit.getOfflinePlayer(shop.getOwner()).getName()));
|
|
||||||
final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName());
|
final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName());
|
||||||
sendItemMessage(p, shop.getItem(), msg);
|
sendItemMessage(p, shop.getItem(), msg);
|
||||||
if (Util.isTool(items.getType())) {
|
if (Util.isTool(item.getType())) {
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.damage-percent-remaining", Util.getToolPercentage(items)));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.damage-percent-remaining", Util.getToolPercentage(item)));
|
||||||
}
|
}
|
||||||
if (shop.isSelling()) {
|
if (shop.isSelling()) {
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.stock", "" + stock));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.stock", "" + (stock == 10000 ? "无限" : stock)));
|
||||||
} else {
|
} else {
|
||||||
final int space = shop.getRemainingSpace();
|
final int space = shop.getRemainingSpace();
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.space", "" + space));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.space", "" + (space == 10000 ? "无限" : space)));
|
||||||
}
|
}
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.price-per", shop.getDataName(), Util.format(shop.getPrice())));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.price-per", shop.getDataName(), Util.format(shop.getPrice())));
|
||||||
if (shop.isBuying()) {
|
if (shop.isBuying()) {
|
||||||
@ -193,10 +185,12 @@ public class MsgUtil {
|
|||||||
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-selling"));
|
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-selling"));
|
||||||
}
|
}
|
||||||
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
|
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
|
||||||
if (!plugin.isEnableMagicLib()) {
|
if (shop.isSelling()) {
|
||||||
final Inventory in = Bukkit.createInventory(null, 9, plugin.getConfigManager().getGuiTitle());
|
p.sendMessage(MsgUtil.p("how-many-buy"));
|
||||||
in.setItem(4, items);
|
} else {
|
||||||
p.openInventory(in);
|
final int items = Util.countItems(p.getInventory(), shop.getItem());
|
||||||
|
p.sendMessage(MsgUtil.p("how-many-sell", items));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,5 @@
|
|||||||
package org.maxgamer.QuickShop.Util;
|
package org.maxgamer.QuickShop.Util;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Item;
|
import org.bukkit.entity.Item;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
@ -10,41 +7,7 @@ public class NMS {
|
|||||||
|
|
||||||
public static void safeGuard(final Item item) throws ClassNotFoundException {
|
public static void safeGuard(final Item item) throws ClassNotFoundException {
|
||||||
rename(item.getItemStack());
|
rename(item.getItemStack());
|
||||||
protect(item);
|
item.setPickupDelay(Integer.MAX_VALUE);
|
||||||
item.setPickupDelay(2147483647);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void protect(final Item item) {
|
|
||||||
try {
|
|
||||||
final Field itemField = item.getClass().getDeclaredField("item");
|
|
||||||
itemField.setAccessible(true);
|
|
||||||
final Object nmsEntityItem = itemField.get(item);
|
|
||||||
Method getItemStack;
|
|
||||||
try {
|
|
||||||
getItemStack = nmsEntityItem.getClass().getMethod("getItemStack", new Class[0]);
|
|
||||||
} catch (final NoSuchMethodException e) {
|
|
||||||
try {
|
|
||||||
getItemStack = nmsEntityItem.getClass().getMethod("d", new Class[0]);
|
|
||||||
} catch (final NoSuchMethodException e2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Object itemStack = getItemStack.invoke(nmsEntityItem, new Object[0]);
|
|
||||||
Field countField;
|
|
||||||
try {
|
|
||||||
countField = itemStack.getClass().getDeclaredField("count");
|
|
||||||
} catch (final NoSuchFieldException e) {
|
|
||||||
countField = itemStack.getClass().getDeclaredField("a");
|
|
||||||
}
|
|
||||||
countField.setAccessible(true);
|
|
||||||
countField.set(itemStack, Integer.valueOf(1));
|
|
||||||
} catch (final NoSuchFieldException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println("[QuickShop] Could not protect item from pickup properly! Dupes are now possible.");
|
|
||||||
} catch (final Exception e) {
|
|
||||||
System.out.println("Other error");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void rename(final ItemStack iStack) {
|
private static void rename(final ItemStack iStack) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.maxgamer.QuickShop.Util;
|
package org.maxgamer.QuickShop.Util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -17,22 +19,30 @@ import org.bukkit.enchantments.Enchantment;
|
|||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
import org.bukkit.material.MaterialData;
|
import org.bukkit.material.MaterialData;
|
||||||
import org.bukkit.material.Sign;
|
import org.bukkit.material.Sign;
|
||||||
import org.maxgamer.QuickShop.QuickShop;
|
import org.maxgamer.QuickShop.QuickShop;
|
||||||
import org.maxgamer.QuickShop.Config.ItemConfig;
|
|
||||||
|
import pw.yumc.YumCore.global.L10N;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class Util {
|
public class Util {
|
||||||
private static HashSet<Material> blacklist = new HashSet<Material>();
|
|
||||||
|
private static HashSet<Material> blacklist = new HashSet<>();
|
||||||
|
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
|
||||||
private static QuickShop plugin;
|
private static QuickShop plugin;
|
||||||
private static HashSet<Material> shoppables = new HashSet<Material>();
|
private static HashSet<Material> shoppables = new HashSet<>();
|
||||||
private static HashSet<Material> tools = new HashSet<Material>();
|
private static HashSet<Material> tools = new HashSet<>();
|
||||||
private static HashSet<Material> transparent = new HashSet<Material>();
|
private static HashSet<Material> transparent = new HashSet<>();
|
||||||
|
|
||||||
|
private static boolean hasCheckedMethodCompatibility = false;
|
||||||
|
private static boolean useNewGetContentMethod = false;
|
||||||
|
|
||||||
public static void addTransparentBlock(final Material m) {
|
public static void addTransparentBlock(final Material m) {
|
||||||
if (transparent.add(m) == false) {
|
if (!transparent.add(m)) {
|
||||||
System.out.println("已添加透明方块: " + m.toString());
|
System.out.println("已添加透明方块: " + m.toString());
|
||||||
}
|
}
|
||||||
if (!m.isBlock()) {
|
if (!m.isBlock()) {
|
||||||
@ -50,10 +60,7 @@ public class Util {
|
|||||||
public static boolean canBeShop(final Block b) {
|
public static boolean canBeShop(final Block b) {
|
||||||
try {
|
try {
|
||||||
final BlockState bs = b.getState();
|
final BlockState bs = b.getState();
|
||||||
if (bs instanceof InventoryHolder == false) {
|
return bs instanceof InventoryHolder && shoppables.contains(bs.getType());
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return shoppables.contains(bs.getType());
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -70,6 +77,21 @@ public class Util {
|
|||||||
* @return The number of items that match in this inventory.
|
* @return The number of items that match in this inventory.
|
||||||
*/
|
*/
|
||||||
public static int countItems(final Inventory inv, final ItemStack item) {
|
public static int countItems(final Inventory inv, final ItemStack item) {
|
||||||
|
if (!hasCheckedMethodCompatibility) {
|
||||||
|
if (hasGetStorageContentsMethod()) {
|
||||||
|
useNewGetContentMethod = true;
|
||||||
|
hasCheckedMethodCompatibility = true;
|
||||||
|
return newCountItems(inv, item);
|
||||||
|
} else {
|
||||||
|
useNewGetContentMethod = false;
|
||||||
|
hasCheckedMethodCompatibility = true;
|
||||||
|
return oldCountItems(inv, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return useNewGetContentMethod ? newCountItems(inv, item) : oldCountItems(inv, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int oldCountItems(final Inventory inv, final ItemStack item) {
|
||||||
int items = 0;
|
int items = 0;
|
||||||
for (final ItemStack iStack : inv.getContents()) {
|
for (final ItemStack iStack : inv.getContents()) {
|
||||||
if (iStack == null) {
|
if (iStack == null) {
|
||||||
@ -82,6 +104,19 @@ public class Util {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int newCountItems(final Inventory inv, final ItemStack item) {
|
||||||
|
int items = 0;
|
||||||
|
for (final ItemStack iStack : inv.getStorageContents()) {
|
||||||
|
if (iStack == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Util.matches(item, iStack)) {
|
||||||
|
items += iStack.getAmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of items that can be given to the inventory safely.
|
* Returns the number of items that can be given to the inventory safely.
|
||||||
*
|
*
|
||||||
@ -93,6 +128,33 @@ public class Util {
|
|||||||
* @return The number of items that can be given to the inventory safely.
|
* @return The number of items that can be given to the inventory safely.
|
||||||
*/
|
*/
|
||||||
public static int countSpace(final Inventory inv, final ItemStack item) {
|
public static int countSpace(final Inventory inv, final ItemStack item) {
|
||||||
|
if (!hasCheckedMethodCompatibility) {
|
||||||
|
if (hasGetStorageContentsMethod()) {
|
||||||
|
useNewGetContentMethod = true;
|
||||||
|
hasCheckedMethodCompatibility = true;
|
||||||
|
return newCountSpace(inv, item);
|
||||||
|
} else {
|
||||||
|
useNewGetContentMethod = false;
|
||||||
|
hasCheckedMethodCompatibility = true;
|
||||||
|
return oldCountSpace(inv, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return useNewGetContentMethod ? newCountSpace(inv, item) : oldCountSpace(inv, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int newCountSpace(final Inventory inv, final ItemStack item) {
|
||||||
|
int space = 0;
|
||||||
|
for (final ItemStack iStack : inv.getStorageContents()) {
|
||||||
|
if (iStack == null || iStack.getType() == Material.AIR) {
|
||||||
|
space += item.getMaxStackSize();
|
||||||
|
} else if (matches(item, iStack)) {
|
||||||
|
space += item.getMaxStackSize() - iStack.getAmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int oldCountSpace(final Inventory inv, final ItemStack item) {
|
||||||
int space = 0;
|
int space = 0;
|
||||||
for (final ItemStack iStack : inv.getContents()) {
|
for (final ItemStack iStack : inv.getContents()) {
|
||||||
if (iStack == null || iStack.getType() == Material.AIR) {
|
if (iStack == null || iStack.getType() == Material.AIR) {
|
||||||
@ -107,16 +169,14 @@ public class Util {
|
|||||||
public static ItemStack deserialize(final String config) throws InvalidConfigurationException {
|
public static ItemStack deserialize(final String config) throws InvalidConfigurationException {
|
||||||
final YamlConfiguration cfg = new YamlConfiguration();
|
final YamlConfiguration cfg = new YamlConfiguration();
|
||||||
cfg.loadFromString(config);
|
cfg.loadFromString(config);
|
||||||
final ItemStack stack = cfg.getItemStack("item");
|
return cfg.getItemStack("item");
|
||||||
return stack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String firstUppercase(final String string) {
|
public static String firstUppercase(final String string) {
|
||||||
if (string.length() > 1) {
|
if (string.length() > 1) {
|
||||||
return Character.toUpperCase(string.charAt(0)) + string.substring(1).toLowerCase();
|
return Character.toUpperCase(string.charAt(0)) + string.substring(1).toLowerCase();
|
||||||
} else {
|
|
||||||
return string.toUpperCase();
|
|
||||||
}
|
}
|
||||||
|
return string.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,16 +187,16 @@ public class Util {
|
|||||||
*/
|
*/
|
||||||
public static String format(final double n) {
|
public static String format(final double n) {
|
||||||
try {
|
try {
|
||||||
return plugin.getEcon().format(n);
|
return DECIMAL_FORMAT.format(n) + plugin.getEcon().currencyNamePlural();
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
return "" + n;
|
return n + "元";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the block which the given sign is attached to
|
* Fetches the block which the given sign is attached to
|
||||||
*
|
*
|
||||||
* @param sign
|
* @param b
|
||||||
* The sign which is attached
|
* The sign which is attached
|
||||||
* @return The block the sign is attached to
|
* @return The block the sign is attached to
|
||||||
*/
|
*/
|
||||||
@ -160,16 +220,12 @@ public class Util {
|
|||||||
* @return The human readable item name.
|
* @return The human readable item name.
|
||||||
*/
|
*/
|
||||||
public static String getName(final ItemStack i) {
|
public static String getName(final ItemStack i) {
|
||||||
// final String vanillaName = getDataName(i.getType(), i.getDurability());
|
return L10N.getItemName(i);
|
||||||
final String vanillaName = ItemConfig.getItemName(i);
|
|
||||||
return prettifyText(vanillaName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's make very long names shorter for our sign
|
// Let's make very long names shorter for our sign
|
||||||
public static String getNameForSign(final ItemStack itemStack) {
|
public static String getNameForSign(final ItemStack itemStack) {
|
||||||
// final String name = getDataName(itemStack.getType(), itemStack.getDurability());
|
|
||||||
String name = getName(itemStack);
|
String name = getName(itemStack);
|
||||||
|
|
||||||
if (name.length() > 16) {
|
if (name.length() > 16) {
|
||||||
name = name.substring(0, 16);
|
name = name.substring(0, 16);
|
||||||
}
|
}
|
||||||
@ -185,7 +241,7 @@ public class Util {
|
|||||||
* @return the block which is also a chest and connected to b.
|
* @return the block which is also a chest and connected to b.
|
||||||
*/
|
*/
|
||||||
public static Block getSecondHalf(final Block b) {
|
public static Block getSecondHalf(final Block b) {
|
||||||
if (b.getType().toString().contains("CHEST") == false) {
|
if (!b.getType().toString().contains("CHEST")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Block[] blocks = new Block[4];
|
final Block[] blocks = new Block[4];
|
||||||
@ -219,14 +275,13 @@ public class Util {
|
|||||||
blacklist.clear();
|
blacklist.clear();
|
||||||
shoppables.clear();
|
shoppables.clear();
|
||||||
transparent.clear();
|
transparent.clear();
|
||||||
|
|
||||||
plugin = QuickShop.instance;
|
plugin = QuickShop.instance;
|
||||||
for (final String s : plugin.getConfig().getStringList("shop-blocks")) {
|
for (final String s : plugin.getConfig().getStringList("shop-blocks")) {
|
||||||
Material mat = Material.getMaterial(s.toUpperCase());
|
Material mat = Material.getMaterial(s.toUpperCase());
|
||||||
if (mat == null) {
|
if (mat == null) {
|
||||||
try {
|
try {
|
||||||
mat = Material.getMaterial(Integer.parseInt(s));
|
mat = Material.getMaterial(Integer.parseInt(s));
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mat == null) {
|
if (mat == null) {
|
||||||
@ -405,16 +460,13 @@ public class Util {
|
|||||||
}
|
}
|
||||||
// Calculate the chunks coordinates. These are 1,2,3 for each chunk, NOT
|
// Calculate the chunks coordinates. These are 1,2,3 for each chunk, NOT
|
||||||
// location rounded to the nearest 16.
|
// location rounded to the nearest 16.
|
||||||
final int x = (int) Math.floor((loc.getBlockX()) / 16.0);
|
if (loc.getWorld().isChunkLoaded(loc.getBlockX() >> 4, loc.getBlockZ() >> 4)) {
|
||||||
final int z = (int) Math.floor((loc.getBlockZ()) / 16.0);
|
|
||||||
if (loc.getWorld().isChunkLoaded(x, z)) {
|
|
||||||
// System.out.println("Chunk is loaded " + x + ", " + z);
|
// System.out.println("Chunk is loaded " + x + ", " + z);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
// System.out.println("Chunk is NOT loaded " + x + ", " + z);
|
// System.out.println("Chunk is NOT loaded " + x + ", " + z);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mat
|
* @param mat
|
||||||
@ -427,8 +479,7 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isTransparent(final Material m) {
|
public static boolean isTransparent(final Material m) {
|
||||||
final boolean trans = transparent.contains(m);
|
return transparent.contains(m);
|
||||||
return trans;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -470,7 +521,8 @@ public class Util {
|
|||||||
* The first item stack
|
* The first item stack
|
||||||
* @param stack2
|
* @param stack2
|
||||||
* The second item stack
|
* The second item stack
|
||||||
* @return true if the itemstacks match. (Material, durability, enchants, name)
|
* @return true if the itemstacks match. (Material, durability, enchants,
|
||||||
|
* name)
|
||||||
*/
|
*/
|
||||||
public static boolean matches(final ItemStack stack1, final ItemStack stack2) {
|
public static boolean matches(final ItemStack stack1, final ItemStack stack2) {
|
||||||
if (stack1 == stack2) {
|
if (stack1 == stack2) {
|
||||||
@ -497,6 +549,72 @@ public class Util {
|
|||||||
return false; // one of the item stacks have a display name
|
return false; // one of the item stacks have a display name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (stack1.getItemMeta().hasLore() || stack2.getItemMeta().hasLore()) {
|
||||||
|
if (stack1.getItemMeta().hasLore() && stack2.getItemMeta().hasLore()) {
|
||||||
|
if (!stack1.getItemMeta().getLore().equals(stack2.getItemMeta().getLore())) {
|
||||||
|
return false; // items have different lore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false; // one of the item stacks have lore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not the same material and not same durability has returned to false
|
||||||
|
if (stack1.getType() == Material.SKULL_ITEM) {
|
||||||
|
if (stack1.getDurability() == 3) {
|
||||||
|
SkullMeta skullMeta1 = (SkullMeta) stack1.getItemMeta();
|
||||||
|
SkullMeta skullMeta2 = (SkullMeta) stack2.getItemMeta();
|
||||||
|
if (skullMeta1.hasOwner() || skullMeta2.hasOwner()) {
|
||||||
|
if (skullMeta1.hasOwner() && skullMeta2.hasOwner()) {
|
||||||
|
if (!skullMeta1.getOwner().equals(skullMeta1.getOwner())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (stack1.getType() == Material.WRITTEN_BOOK) {
|
||||||
|
if (stack1.hasItemMeta() || stack2.hasItemMeta()) {
|
||||||
|
if (stack1.hasItemMeta() && stack2.hasItemMeta()) {
|
||||||
|
BookMeta bookMeta1 = (BookMeta) stack1.getItemMeta();
|
||||||
|
BookMeta bookMeta2 = (BookMeta) stack2.getItemMeta();
|
||||||
|
// title
|
||||||
|
if (bookMeta1.hasTitle() || bookMeta2.hasTitle()) {
|
||||||
|
if (bookMeta1.hasTitle() && bookMeta2.hasTitle()) {
|
||||||
|
if (!bookMeta1.getTitle().equals(bookMeta2.getTitle())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// author
|
||||||
|
if (bookMeta1.hasAuthor() || bookMeta2.hasAuthor()) {
|
||||||
|
if (bookMeta1.hasAuthor() && bookMeta2.hasAuthor()) {
|
||||||
|
if (!bookMeta1.getAuthor().equals(bookMeta2.getAuthor())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// content
|
||||||
|
if (bookMeta1.hasPages() || bookMeta2.hasPages()) {
|
||||||
|
if (bookMeta1.hasPages() && bookMeta2.hasPages()) {
|
||||||
|
if (!bookMeta1.getPages().equals(bookMeta2.getPages())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Class.forName("org.bukkit.inventory.meta.EnchantmentStorageMeta");
|
Class.forName("org.bukkit.inventory.meta.EnchantmentStorageMeta");
|
||||||
final boolean book1 = stack1.getItemMeta() instanceof EnchantmentStorageMeta;
|
final boolean book1 = stack1.getItemMeta() instanceof EnchantmentStorageMeta;
|
||||||
@ -504,7 +622,7 @@ public class Util {
|
|||||||
if (book1 != book2) {
|
if (book1 != book2) {
|
||||||
return false;// One has enchantment meta, the other does not.
|
return false;// One has enchantment meta, the other does not.
|
||||||
}
|
}
|
||||||
if (book1 == true) { // They are the same here (both true or both
|
if (book1) { // They are the same here (both true or both
|
||||||
// false). So if one is true, the other is
|
// false). So if one is true, the other is
|
||||||
// true.
|
// true.
|
||||||
final Map<Enchantment, Integer> ench1 = ((EnchantmentStorageMeta) stack1.getItemMeta()).getStoredEnchants();
|
final Map<Enchantment, Integer> ench1 = ((EnchantmentStorageMeta) stack1.getItemMeta()).getStoredEnchants();
|
||||||
@ -531,31 +649,25 @@ public class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a name like IRON_INGOT into Iron Ingot to improve readability
|
|
||||||
*
|
|
||||||
* @param ugly
|
|
||||||
* The string such as IRON_INGOT
|
|
||||||
* @return A nicer version, such as Iron Ingot
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static String prettifyText(final String ugly) {
|
|
||||||
final String[] nameParts = ugly.split("_");
|
|
||||||
if (nameParts.length == 1) {
|
|
||||||
return firstUppercase(ugly);
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
for (final String part : nameParts) {
|
|
||||||
sb.append(firstUppercase(part) + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String serialize(final ItemStack iStack) {
|
public static String serialize(final ItemStack iStack) {
|
||||||
final YamlConfiguration cfg = new YamlConfiguration();
|
final YamlConfiguration cfg = new YamlConfiguration();
|
||||||
cfg.set("item", iStack);
|
cfg.set("item", iStack);
|
||||||
return cfg.saveToString();
|
return cfg.saveToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasGetStorageContentsMethod() {
|
||||||
|
try {
|
||||||
|
Class<?> inventory = Class.forName("org.bukkit.inventory.Inventory");
|
||||||
|
if (inventory != null) {
|
||||||
|
for (Method method : inventory.getDeclaredMethods()) {
|
||||||
|
if (method != null && method.getName().equals("getStorageContents")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,36 +12,26 @@ import org.maxgamer.QuickShop.QuickShop;
|
|||||||
|
|
||||||
public class LogWatcher implements Runnable {
|
public class LogWatcher implements Runnable {
|
||||||
private PrintStream ps;
|
private PrintStream ps;
|
||||||
private ArrayList<String> logs = new ArrayList<String>(5);
|
private final ArrayList<String> logs = new ArrayList<String>(5);
|
||||||
public BukkitTask task;
|
public BukkitTask task;
|
||||||
|
|
||||||
public LogWatcher(QuickShop plugin, File log) {
|
public LogWatcher(final QuickShop plugin, final File log) {
|
||||||
try {
|
try {
|
||||||
if (!log.exists()) {
|
if (!log.exists()) {
|
||||||
log.createNewFile();
|
log.createNewFile();
|
||||||
}
|
}
|
||||||
FileOutputStream fos = new FileOutputStream(log, true);
|
final FileOutputStream fos = new FileOutputStream(log, true);
|
||||||
this.ps = new PrintStream(fos);
|
this.ps = new PrintStream(fos, true, "UTF-8");
|
||||||
} catch (FileNotFoundException e) {
|
} catch (final FileNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
plugin.getLogger().severe("Log file not found!");
|
plugin.getLogger().severe("日志文件未找到!");
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
plugin.getLogger().severe("Could not create log file!");
|
plugin.getLogger().severe("无法创建日志文件!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void add(final String s) {
|
||||||
public void run() {
|
|
||||||
synchronized (logs) {
|
|
||||||
for (String s : logs) {
|
|
||||||
ps.println(s);
|
|
||||||
}
|
|
||||||
logs.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(String s) {
|
|
||||||
synchronized (logs) {
|
synchronized (logs) {
|
||||||
logs.add(s);
|
logs.add(s);
|
||||||
}
|
}
|
||||||
@ -50,4 +40,14 @@ public class LogWatcher implements Runnable {
|
|||||||
public void close() {
|
public void close() {
|
||||||
this.ps.close();
|
this.ps.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (logs) {
|
||||||
|
for (final String s : logs) {
|
||||||
|
ps.println(s);
|
||||||
|
}
|
||||||
|
logs.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
Version: 1.1
|
Version: 1.8
|
||||||
|
|
||||||
#超级工具(OP可以用该工具在创造模式打破所有商店)
|
#超级工具(OP可以用该工具在创造模式打破所有商店)
|
||||||
superitem: GOLD_AXE
|
superitem: GOLD_AXE
|
||||||
@ -6,23 +6,25 @@ superitem: GOLD_AXE
|
|||||||
preventhopper: false
|
preventhopper: false
|
||||||
#商店GUI的标题
|
#商店GUI的标题
|
||||||
guititle: '&6[&b快捷商店&6]&r'
|
guititle: '&6[&b快捷商店&6]&r'
|
||||||
|
#启用魔改库支持
|
||||||
|
usemagiclib: true
|
||||||
|
#启用虚拟悬浮物
|
||||||
|
fakeitem: true
|
||||||
|
#禁止使用商店的世界(请全部小写)
|
||||||
|
prevent:
|
||||||
|
- 'preventworld'
|
||||||
|
|
||||||
#Tax amount (decimal) - Eg, P1 buys $50 worth of stuff from P2. Therefore, P1 loses $50, P2 gains $(1-0.05)*50, and tax-account gains $(0.05)*50.
|
#税收数量 (decimal) - 例如 税收是0.05 玩家1 在玩家2的商店 购买了 50元的东西,那么,玩家1 减少 50, 玩家2 账户增加(1-0.05)*50, 并且 玩家2税收账户增加 (0.05)*50.
|
||||||
tax: 0.00
|
tax: 0.00
|
||||||
#The fake player who money from taxing people goes to
|
#税收账户名称
|
||||||
tax-account: tax
|
tax-account: tax
|
||||||
#Whether or not to show taxes paid when selling to a shop
|
#是否显示税收额度
|
||||||
show-tax: false
|
show-tax: false
|
||||||
|
|
||||||
#Should we log transactions/creations to Bukkit\Plugins\QuickShop\qs.log?
|
#是否需要记录玩家操作 保存在 服务器根目录\Plugins\QuickShop\qs.log?
|
||||||
log-actions: true
|
log-actions: true
|
||||||
|
|
||||||
#For item-item based economies that don't use virtual coins.
|
#数据库配置
|
||||||
whole-number-prices-only: false
|
|
||||||
|
|
||||||
#Force bukkit chat handler (https://github.com/KaiKikuchi/QuickShop/issues/10)
|
|
||||||
force-bukkit-chat-handler: false
|
|
||||||
|
|
||||||
database:
|
database:
|
||||||
mysql: false
|
mysql: false
|
||||||
host: localhost
|
host: localhost
|
||||||
@ -31,25 +33,26 @@ database:
|
|||||||
user: root
|
user: root
|
||||||
password: passwd
|
password: passwd
|
||||||
|
|
||||||
#Limits the number of shops a person can create and own at a single time.
|
#限制玩家同一时间最多可以建造的商店
|
||||||
limits:
|
limits:
|
||||||
#Disable these if you're not using them! If this is false, the rest of this section is ignored
|
#关闭则忽略限制
|
||||||
use: false
|
use: false
|
||||||
#The default number of shops players can make
|
#默认限制
|
||||||
default: 10
|
default: 10
|
||||||
#Players with these permissions can create these amounts of shops.
|
#如果玩家有以下权限则拥有对应的数量
|
||||||
ranks:
|
ranks:
|
||||||
#Anyone with 'quickshop.vip' permissions, can create 20 shops instead of 10.
|
#例如有 'quickshop.vip' 权限, 可以创建20个商店
|
||||||
quickshop.vip: 20 #Players with quickshop.vip can make 20 shops.
|
quickshop.vip: 20
|
||||||
|
|
||||||
#A list of block (materials) which can be used to create shops.
|
#下列列表允许玩家创建商店
|
||||||
#By default, chests are added to this list.
|
#箱子已经默认添加了
|
||||||
#This will only work for blocks which implement InventoryHolder
|
#他只能工作在继承于 InventoryHolder 的方块上面
|
||||||
#in other words, no enderchest shops, no shops on dirt blocks, etc.
|
#换句话说就是 末影箱不行 泥土不行 石头也不行 等等...
|
||||||
#May cause unexpected behaviour with some blocks... Eg don't make a
|
#而且不要尝试写入有行为操作的方块
|
||||||
#shop on a hopper (It sucks the display item in) and furnace shops
|
#例如漏斗 (他会把悬浮物吸进去)
|
||||||
#allow players to put whatever item they want in all 3 slots and
|
#例如酿造台 (他不能放置所有物品)
|
||||||
#dispenser shops aren't protected from redstone... Etc.
|
#例如发射器/投掷器 (他不能被保护 当有红石的时候)
|
||||||
|
#注意: 所有非法方块将在下一次载入到服务器时被清理
|
||||||
shop-blocks:
|
shop-blocks:
|
||||||
- CHEST
|
- CHEST
|
||||||
- TRAPPED_CHEST
|
- TRAPPED_CHEST
|
||||||
@ -73,18 +76,15 @@ shop:
|
|||||||
|
|
||||||
#是否需要自动创建木牌在箱子上?
|
#是否需要自动创建木牌在箱子上?
|
||||||
auto-sign: true
|
auto-sign: true
|
||||||
#If a player owns an unlimited shop, should they receive the cash from it or not?
|
#是否给无限商店的店主支付金钱
|
||||||
#If you buy from YOUR unlimited shop, you will NEVER be charged $$, regardless of this setting
|
|
||||||
pay-unlimited-shop-owners: false
|
pay-unlimited-shop-owners: false
|
||||||
#Should we place display items on the chests?
|
#是否显示悬浮物品(拔刀剑MOD必须关闭)
|
||||||
display-items: true
|
display-items: true
|
||||||
#Should we place item frames on chests?
|
#当使用 /qs find <item>, 能查找多远的商店?
|
||||||
frame-items: true
|
#这个命令可能会使服务器Lag 请谨慎调整数据...
|
||||||
#When someone uses /qs find <item>, how far should we search in blocks?
|
#如果半径 > 100 可能会导致服务器崩溃. 请不要尝试, 不然你哭都来不及.
|
||||||
#This command lets users shop quickly without wasting time searching
|
|
||||||
#Settings > 100 WILL cause lag. Don't do it, or don't cry when your server lags.
|
|
||||||
find-distance: 45
|
find-distance: 45
|
||||||
|
|
||||||
#List of items to disallow selling of. Anyone with quickshop.bypass.<itemID> can bypass it
|
#物品的黑名单. 使用 quickshop.bypass.<itemID> 权限可以忽略限制
|
||||||
blacklist:
|
blacklist:
|
||||||
- 7 #Bedrock
|
- 7 #Bedrock
|
@ -1,426 +0,0 @@
|
|||||||
Version: 1.0
|
|
||||||
|
|
||||||
AIR_-1: 爪子
|
|
||||||
AIR: 爪子
|
|
||||||
STONE: 石头
|
|
||||||
GRASS: 草方块
|
|
||||||
DIRT: 泥土
|
|
||||||
COBBLESTONE: 圆石
|
|
||||||
WOOD: 木板
|
|
||||||
SAPLING: 橡木树苗
|
|
||||||
SAPLING_1: 云杉树苗
|
|
||||||
SAPLING_2: 白桦树苗
|
|
||||||
SAPLING_3: 丛林树苗
|
|
||||||
SAPLING_4: 金合欢树苗
|
|
||||||
SAPLING_5: 深色橡木树苗
|
|
||||||
BEDROCK: 基岩
|
|
||||||
WATER: 水
|
|
||||||
STATIONARY_WATER: 静态的水
|
|
||||||
LAVA: 岩浆
|
|
||||||
STATIONARY_LAVA: 静态的岩浆
|
|
||||||
SAND: 沙子
|
|
||||||
GRAVEL: 沙砾
|
|
||||||
GOLD_ORE: 金矿石
|
|
||||||
IRON_ORE: 铁矿石
|
|
||||||
COAL_ORE: 煤矿石
|
|
||||||
LOG: 橡木
|
|
||||||
LEAVES: 橡木树叶
|
|
||||||
SPONGE: 海绵
|
|
||||||
GLASS: 玻璃
|
|
||||||
LAPIS_ORE: 青金石矿石
|
|
||||||
LAPIS_BLOCK: 青金石块
|
|
||||||
DISPENSER: 发射器
|
|
||||||
SANDSTONE: 沙石
|
|
||||||
NOTE_BLOCK: 音符盒
|
|
||||||
BED_BLOCK: 床
|
|
||||||
POWERED_RAIL: 动力铁轨
|
|
||||||
DETECTOR_RAIL: 探测铁轨
|
|
||||||
PISTON_STICKY_BASE: 粘性活塞
|
|
||||||
WEB: 蜘蛛网
|
|
||||||
LONG_GRASS: 灌木
|
|
||||||
DEAD_BUSH: 枯死的灌木
|
|
||||||
PISTON_BASE: 活塞
|
|
||||||
PISTON_EXTENSION: 活塞帽
|
|
||||||
WOOL: 羊毛
|
|
||||||
PISTON_MOVING_PIECE: PISTON_MOVING_PIECE
|
|
||||||
YELLOW_FLOWER: 蒲公英
|
|
||||||
RED_ROSE: 罂粟
|
|
||||||
BROWN_MUSHROOM: 棕色蘑菇
|
|
||||||
RED_MUSHROOM: 红色蘑菇
|
|
||||||
GOLD_BLOCK: 金块
|
|
||||||
IRON_BLOCK: 铁块
|
|
||||||
DOUBLE_STEP: 石台阶(两层)
|
|
||||||
STEP: 石台阶
|
|
||||||
BRICK: 砖块
|
|
||||||
TNT: TNT
|
|
||||||
BOOKSHELF: 书架
|
|
||||||
MOSSY_COBBLESTONE: 苔石
|
|
||||||
OBSIDIAN: 黑曜石
|
|
||||||
TORCH: 火把
|
|
||||||
FIRE: 火
|
|
||||||
MOB_SPAWNER: 刷怪笼
|
|
||||||
WOOD_STAIRS: 橡木楼梯
|
|
||||||
CHEST: 箱子
|
|
||||||
REDSTONE_WIRE: 红石粉
|
|
||||||
DIAMOND_ORE: 钻石原矿
|
|
||||||
DIAMOND_BLOCK: 钻石块
|
|
||||||
WORKBENCH: 工作台
|
|
||||||
CROPS: 农作物
|
|
||||||
SOIL: 耕地
|
|
||||||
FURNACE: 熔炉
|
|
||||||
BURNING_FURNACE: 燃烧的熔炉
|
|
||||||
SIGN_POST: 木牌
|
|
||||||
WOODEN_DOOR: 橡木门
|
|
||||||
LADDER: 梯子
|
|
||||||
RAILS: 铁轨
|
|
||||||
COBBLESTONE_STAIRS: 圆石台阶
|
|
||||||
WALL_SIGN: 墙上的木牌
|
|
||||||
LEVER: 拉杆
|
|
||||||
STONE_PLATE: 石质压力板
|
|
||||||
IRON_DOOR_BLOCK: 铁门
|
|
||||||
WOOD_PLATE: 木质压力板
|
|
||||||
REDSTONE_ORE: 红石原矿
|
|
||||||
GLOWING_REDSTONE_ORE: 采集中的红石原矿
|
|
||||||
REDSTONE_TORCH_OFF: 红石火把(关闭)
|
|
||||||
REDSTONE_TORCH_ON: 红石火把(打开)
|
|
||||||
STONE_BUTTON: 石按钮
|
|
||||||
SNOW: 雪
|
|
||||||
ICE: 冰
|
|
||||||
SNOW_BLOCK: 雪块
|
|
||||||
CACTUS: 仙人掌
|
|
||||||
CLAY: 粘土
|
|
||||||
SUGAR_CANE_BLOCK: SUGAR_CANE_BLOCK
|
|
||||||
JUKEBOX: 唱片机
|
|
||||||
FENCE: 栅栏
|
|
||||||
PUMPKIN: 南瓜
|
|
||||||
NETHERRACK: 地狱岩
|
|
||||||
SOUL_SAND: 灵魂沙
|
|
||||||
GLOWSTONE: 萤石
|
|
||||||
PORTAL: 传送门
|
|
||||||
JACK_O_LANTERN: 南瓜灯
|
|
||||||
CAKE_BLOCK: 蛋糕
|
|
||||||
DIODE_BLOCK_OFF: DIODE_BLOCK_OFF
|
|
||||||
DIODE_BLOCK_ON: DIODE_BLOCK_ON
|
|
||||||
LOCKED_CHEST: 上锁的箱子
|
|
||||||
STAINED_GLASS: 白色染色玻璃
|
|
||||||
STAINED_GLASS_1: 橙色染色玻璃
|
|
||||||
STAINED_GLASS_2: 品红色染色玻璃
|
|
||||||
STAINED_GLASS_3: 淡蓝色染色玻璃
|
|
||||||
STAINED_GLASS_4: 黄色染色玻璃
|
|
||||||
STAINED_GLASS_5: 黄绿色染色玻璃
|
|
||||||
STAINED_GLASS_6: 粉红色染色玻璃
|
|
||||||
STAINED_GLASS_7: 灰色染色玻璃
|
|
||||||
STAINED_GLASS_8: 淡灰色染色玻璃
|
|
||||||
STAINED_GLASS_9: 青色染色玻璃
|
|
||||||
STAINED_GLASS_10: 紫色染色玻璃
|
|
||||||
STAINED_GLASS_11: 蓝色染色玻璃
|
|
||||||
STAINED_GLASS_12: 棕色染色玻璃
|
|
||||||
STAINED_GLASS_13: 绿色染色玻璃
|
|
||||||
STAINED_GLASS_14: 红色染色玻璃
|
|
||||||
STAINED_GLASS_15: 黑色染色玻璃
|
|
||||||
TRAP_DOOR: 活板门
|
|
||||||
MONSTER_EGGS: 石头刷怪蛋
|
|
||||||
SMOOTH_BRICK: 石砖
|
|
||||||
HUGE_MUSHROOM_1: 蘑菇
|
|
||||||
HUGE_MUSHROOM_2: 蘑菇
|
|
||||||
IRON_FENCE: 铁栅栏
|
|
||||||
THIN_GLASS: 玻璃板
|
|
||||||
MELON_BLOCK: 西瓜方块
|
|
||||||
PUMPKIN_STEM: 南瓜种子
|
|
||||||
MELON_STEM: 西瓜种子
|
|
||||||
VINE: 藤蔓
|
|
||||||
FENCE_GATE: 栅栏门
|
|
||||||
BRICK_STAIRS: 砖楼梯
|
|
||||||
SMOOTH_STAIRS: 石砖楼梯
|
|
||||||
MYCEL: 菌丝
|
|
||||||
WATER_LILY: 睡莲
|
|
||||||
NETHER_BRICK: 地狱砖块
|
|
||||||
NETHER_FENCE: 地狱栅栏
|
|
||||||
NETHER_BRICK_STAIRS: 地狱砖楼梯
|
|
||||||
NETHER_WARTS: 地狱疣
|
|
||||||
ENCHANTMENT_TABLE: 附魔台
|
|
||||||
BREWING_STAND: 酿造台
|
|
||||||
CAULDRON: 炼药锅
|
|
||||||
ENDER_PORTAL: 末地传送门
|
|
||||||
ENDER_PORTAL_FRAME: 末地传送框架
|
|
||||||
ENDER_STONE: 末地石
|
|
||||||
DRAGON_EGG: 龙蛋
|
|
||||||
REDSTONE_LAMP_OFF: 红石灯(关闭)
|
|
||||||
REDSTONE_LAMP_ON: 红石灯(打开)
|
|
||||||
WOOD_DOUBLE_STEP: 橡木台阶(两层)
|
|
||||||
WOOD_STEP: 橡木台阶
|
|
||||||
COCOA: 可可豆
|
|
||||||
SANDSTONE_STAIRS: 沙石台阶
|
|
||||||
EMERALD_ORE: 绿宝石矿石
|
|
||||||
ENDER_CHEST: 末影箱
|
|
||||||
TRIPWIRE_HOOK: 绊线钩
|
|
||||||
TRIPWIRE: 绊线钩
|
|
||||||
EMERALD_BLOCK: 绿宝石块
|
|
||||||
SPRUCE_WOOD_STAIRS: 云杉木楼梯
|
|
||||||
BIRCH_WOOD_STAIRS: 桦木楼梯
|
|
||||||
JUNGLE_WOOD_STAIRS: 丛林木楼梯
|
|
||||||
COMMAND: 命令方块
|
|
||||||
BEACON: 信标
|
|
||||||
COBBLE_WALL: 圆石墙
|
|
||||||
FLOWER_POT: 花盆
|
|
||||||
CARROT: 胡萝卜
|
|
||||||
POTATO: 土豆
|
|
||||||
WOOD_BUTTON: 木按钮
|
|
||||||
SKULL: 头颅
|
|
||||||
ANVIL: 铁毡
|
|
||||||
TRAPPED_CHEST: 陷阱箱
|
|
||||||
GOLD_PLATE: 测重压力板(轻质)
|
|
||||||
IRON_PLATE: 测重压力板(重质)
|
|
||||||
REDSTONE_COMPARATOR_OFF: 红石比较器(关闭)
|
|
||||||
REDSTONE_COMPARATOR_ON: 红石比较器(打开)
|
|
||||||
DAYLIGHT_DETECTOR: 阳光传感器
|
|
||||||
REDSTONE_BLOCK: 红石块
|
|
||||||
QUARTZ_ORE: 下界石英矿石
|
|
||||||
HOPPER: 漏斗
|
|
||||||
QUARTZ_BLOCK: 石英块
|
|
||||||
QUARTZ_STAIRS: 石英楼梯
|
|
||||||
ACTIVATOR_RAIL: 激活铁轨
|
|
||||||
DROPPER: 掉落物
|
|
||||||
STAINED_CLAY: 白色染色粘土
|
|
||||||
STAINED_CLAY_1: 橙色染色粘土
|
|
||||||
STAINED_CLAY_2: 品红色染色粘土
|
|
||||||
STAINED_CLAY_3: 淡蓝色染色粘土
|
|
||||||
STAINED_CLAY_4: 黄色染色粘土
|
|
||||||
STAINED_CLAY_5: 黄绿色染色粘土
|
|
||||||
STAINED_CLAY_6: 粉红色染色粘土
|
|
||||||
STAINED_CLAY_7: 灰色染色粘土
|
|
||||||
STAINED_CLAY_8: 淡灰色染色粘土
|
|
||||||
STAINED_CLAY_9: 青色染色粘土
|
|
||||||
STAINED_CLAY_10: 紫色染色粘土
|
|
||||||
STAINED_CLAY_11: 蓝色染色粘土
|
|
||||||
STAINED_CLAY_12: 棕色染色粘土
|
|
||||||
STAINED_CLAY_13: 绿色染色粘土
|
|
||||||
STAINED_CLAY_14: 红色染色粘土
|
|
||||||
STAINED_CLAY_15: 黑色染色粘土
|
|
||||||
STAINED_GLASS_PANE: 白色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_1: 橙色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_2: 品红色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_3: 淡蓝色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_4: 黄色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_5: 黄绿色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_6: 粉红色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_7: 灰色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_8: 淡灰色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_9: 青色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_10: 紫色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_11: 蓝色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_12: 棕色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_13: 绿色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_14: 红色染色玻璃板
|
|
||||||
STAINED_GLASS_PANE_15: 黑色染色玻璃板
|
|
||||||
LEAVES_2: 合金欢树叶
|
|
||||||
LOG_2: 合金欢木
|
|
||||||
ACACIA_STAIRS: 合金欢楼梯
|
|
||||||
DARK_OAK_STAIRS: 深色橡木楼梯
|
|
||||||
HAY_BLOCK: 干草快
|
|
||||||
CARPET: 白色地毯
|
|
||||||
CARPET_1: 橙色地毯
|
|
||||||
CARPET_2: 品红色地毯
|
|
||||||
CARPET_3: 淡蓝色地毯
|
|
||||||
CARPET_4: 黄色地毯
|
|
||||||
CARPET_5: 黄绿色地毯
|
|
||||||
CARPET_6: 粉红色地毯
|
|
||||||
CARPET_7: 灰色地毯
|
|
||||||
CARPET_8: 淡灰色地毯
|
|
||||||
CARPET_9: 青色地毯
|
|
||||||
CARPET_10: 紫色地毯
|
|
||||||
CARPET_11: 蓝色地毯
|
|
||||||
CARPET_12: 棕色地毯
|
|
||||||
CARPET_13: 绿色地毯
|
|
||||||
CARPET_14: 红色地毯
|
|
||||||
CARPET_15: 黑色地毯
|
|
||||||
HARD_CLAY: 硬化粘土
|
|
||||||
COAL_BLOCK: 煤炭快
|
|
||||||
PACKED_ICE: 浮冰
|
|
||||||
DOUBLE_PLANT: 向日葵
|
|
||||||
IRON_SPADE: 铁楸
|
|
||||||
IRON_PICKAXE: 铁镐
|
|
||||||
IRON_AXE: 铁斧
|
|
||||||
FLINT_AND_STEEL: 打火石
|
|
||||||
APPLE: 苹果
|
|
||||||
BOW: 弓
|
|
||||||
ARROW: 箭
|
|
||||||
COAL: 煤炭
|
|
||||||
DIAMOND: 钻石
|
|
||||||
IRON_INGOT: 铁锭
|
|
||||||
GOLD_INGOT: 金锭
|
|
||||||
IRON_SWORD: 铁剑
|
|
||||||
WOOD_SWORD: 木剑
|
|
||||||
WOOD_SPADE: 木楸
|
|
||||||
WOOD_PICKAXE: 木稿
|
|
||||||
WOOD_AXE: 木斧
|
|
||||||
STONE_SWORD: 石剑
|
|
||||||
STONE_SPADE: 石楸
|
|
||||||
STONE_PICKAXE: 石稿
|
|
||||||
STONE_AXE: 石斧
|
|
||||||
DIAMOND_SWORD: 钻石剑
|
|
||||||
DIAMOND_SPADE: 钻石楸
|
|
||||||
DIAMOND_PICKAXE: 钻石稿
|
|
||||||
DIAMOND_AXE: 钻石斧
|
|
||||||
STICK: 木棍
|
|
||||||
BOWL: 碗
|
|
||||||
MUSHROOM_SOUP: 蘑菇煲
|
|
||||||
GOLD_SWORD: 金剑
|
|
||||||
GOLD_SPADE: 金楸
|
|
||||||
GOLD_PICKAXE: 金稿
|
|
||||||
GOLD_AXE: 金斧
|
|
||||||
GOLD_HOE: 金锄
|
|
||||||
STRING: 线
|
|
||||||
FEATHER: 羽毛
|
|
||||||
SULPHUR: 火药
|
|
||||||
WOOD_HOE: 木锄
|
|
||||||
STONE_HOE: 石锄
|
|
||||||
IRON_HOE: 铁锄
|
|
||||||
DIAMOND_HOE: 钻石锄
|
|
||||||
SEEDS: 种子
|
|
||||||
WHEAT: 小麦
|
|
||||||
BREAD: 面包
|
|
||||||
LEATHER_HELMET: 皮革帽子
|
|
||||||
LEATHER_CHESTPLATE: 皮革外套
|
|
||||||
LEATHER_LEGGINGS: 皮革护腿
|
|
||||||
LEATHER_BOOTS: 皮革靴子
|
|
||||||
CHAINMAIL_HELMET: 锁链帽子
|
|
||||||
CHAINMAIL_CHESTPLATE: 锁链外套
|
|
||||||
CHAINMAIL_LEGGINGS: 锁链护腿
|
|
||||||
CHAINMAIL_BOOTS: 锁链靴子
|
|
||||||
IRON_HELMET: 铁帽子
|
|
||||||
IRON_CHESTPLATE: 铁外套
|
|
||||||
IRON_LEGGINGS: 铁护腿
|
|
||||||
IRON_BOOTS: 铁靴子
|
|
||||||
DIAMOND_HELMET: 钻石帽子
|
|
||||||
DIAMOND_CHESTPLATE: 钻石外套
|
|
||||||
DIAMOND_LEGGINGS: 钻石护腿
|
|
||||||
DIAMOND_BOOTS: 钻石靴子
|
|
||||||
GOLD_HELMET: 金帽子
|
|
||||||
GOLD_CHESTPLATE: 金外套
|
|
||||||
GOLD_LEGGINGS: 金护腿
|
|
||||||
GOLD_BOOTS: 金靴子
|
|
||||||
FLINT: 燧石
|
|
||||||
PORK: 生猪排
|
|
||||||
GRILLED_PORK: 熟猪排
|
|
||||||
PAINTING: 画
|
|
||||||
GOLDEN_APPLE: 金苹果
|
|
||||||
SIGN: 木牌
|
|
||||||
WOOD_DOOR: 木门
|
|
||||||
BUCKET: 桶
|
|
||||||
WATER_BUCKET: 水桶
|
|
||||||
LAVA_BUCKET: 岩浆桶
|
|
||||||
MINECART: 矿车
|
|
||||||
SADDLE: SADDLE
|
|
||||||
IRON_DOOR: 铁门
|
|
||||||
REDSTONE: 红石
|
|
||||||
SNOW_BALL: 雪球
|
|
||||||
BOAT: 船
|
|
||||||
LEATHER: 皮革
|
|
||||||
MILK_BUCKET: 牛奶桶
|
|
||||||
CLAY_BRICK: 红砖
|
|
||||||
CLAY_BALL: 粘土球
|
|
||||||
SUGAR_CANE: 甘蔗
|
|
||||||
PAPER: 纸
|
|
||||||
BOOK: 书
|
|
||||||
SLIME_BALL: 史莱姆球
|
|
||||||
STORAGE_MINECART: 运输矿车
|
|
||||||
POWERED_MINECART: 动力矿车
|
|
||||||
EGG: 鸡蛋
|
|
||||||
COMPASS: 指南针
|
|
||||||
FISHING_ROD: 鱼竿
|
|
||||||
WATCH: 钟
|
|
||||||
GLOWSTONE_DUST: 萤石粉
|
|
||||||
RAW_FISH: 生鱼
|
|
||||||
COOKED_FISH: 熟鱼
|
|
||||||
INK_SACK: 墨囊
|
|
||||||
INK_SACK_1: 玫瑰红
|
|
||||||
INK_SACK_2: 仙人掌绿
|
|
||||||
INK_SACK_3: 可可豆
|
|
||||||
INK_SACK_4: 青金石
|
|
||||||
INK_SACK_5: 紫色染料
|
|
||||||
INK_SACK_6: 青色染料
|
|
||||||
INK_SACK_7: 淡灰色染料
|
|
||||||
INK_SACK_8: 灰色染料
|
|
||||||
INK_SACK_9: 粉色染料
|
|
||||||
INK_SACK_10: 黄绿色染料
|
|
||||||
INK_SACK_11: 蒲公英黄染料
|
|
||||||
INK_SACK_12: 淡蓝色染料
|
|
||||||
INK_SACK_13: 品红色染料
|
|
||||||
INK_SACK_14: 橙色染料
|
|
||||||
INK_SACK_15: 骨粉
|
|
||||||
BONE: 骨粉
|
|
||||||
SUGAR: 糖
|
|
||||||
CAKE: 蛋糕
|
|
||||||
BED: 床
|
|
||||||
DIODE: 红石中继器
|
|
||||||
COOKIE: 曲奇
|
|
||||||
MAP: 地图
|
|
||||||
SHEARS: 剪刀
|
|
||||||
MELON: 西瓜
|
|
||||||
PUMPKIN_SEEDS: 南瓜种子
|
|
||||||
MELON_SEEDS: 西瓜种子
|
|
||||||
RAW_BEEF: 生牛肉
|
|
||||||
COOKED_BEEF: 熟牛肉
|
|
||||||
RAW_CHICKEN: 生鸡肉
|
|
||||||
COOKED_CHICKEN: 熟鸡肉
|
|
||||||
ROTTEN_FLESH: 腐肉
|
|
||||||
ENDER_PEARL: 末影之眼
|
|
||||||
BLAZE_ROD: 烈焰棒
|
|
||||||
GHAST_TEAR: 恶魂之泪
|
|
||||||
GOLD_NUGGET: 金粒
|
|
||||||
NETHER_STALK: 地狱疣
|
|
||||||
POTION: 药水
|
|
||||||
GLASS_BOTTLE: 玻璃瓶
|
|
||||||
SPIDER_EYE: 蜘蛛眼
|
|
||||||
FERMENTED_SPIDER_EYE: 发酵蛛眼
|
|
||||||
BLAZE_POWDER: 烈焰粉
|
|
||||||
MAGMA_CREAM: 岩浆膏
|
|
||||||
BREWING_STAND_ITEM: 酿造台
|
|
||||||
CAULDRON_ITEM: 炼药锅
|
|
||||||
EYE_OF_ENDER: 末影之眼
|
|
||||||
SPECKLED_MELON: 闪烁的西瓜
|
|
||||||
MONSTER_EGG: 刷怪蛋
|
|
||||||
EXP_BOTTLE: 附魔之瓶
|
|
||||||
FIREBALL: 火焰弹
|
|
||||||
BOOK_AND_QUILL: 书和笔
|
|
||||||
WRITTEN_BOOK: 成书
|
|
||||||
EMERALD: 绿宝石
|
|
||||||
ITEM_FRAME: 物品展示框
|
|
||||||
FLOWER_POT_ITEM: 花盆
|
|
||||||
CARROT_ITEM: 胡萝卜
|
|
||||||
POTATO_ITEM: 马铃薯
|
|
||||||
BAKED_POTATO: 烤马铃薯
|
|
||||||
POISONOUS_POTATO: 毒马铃薯
|
|
||||||
EMPTY_MAP: 空地图
|
|
||||||
GOLDEN_CARROT: 金萝卜
|
|
||||||
SKULL_ITEM: 头颅
|
|
||||||
CARROT_STICK: 胡萝卜
|
|
||||||
NETHER_STAR: 下界之星
|
|
||||||
PUMPKIN_PIE: 南瓜派
|
|
||||||
FIREWORK: 烟花
|
|
||||||
FIREWORK_CHARGE: 烟花
|
|
||||||
ENCHANTED_BOOK: 附魔书
|
|
||||||
REDSTONE_COMPARATOR: 红石比较器
|
|
||||||
NETHER_BRICK_ITEM: 地狱砖块
|
|
||||||
QUARTZ: 石英
|
|
||||||
EXPLOSIVE_MINECART: TNT矿车
|
|
||||||
HOPPER_MINECART: 漏斗矿车
|
|
||||||
IRON_BARDING: 铁马凯
|
|
||||||
GOLD_BARDING: 金马凯
|
|
||||||
DIAMOND_BARDING: 钻石马凯
|
|
||||||
LEASH: 栓绳
|
|
||||||
NAME_TAG: 命名牌
|
|
||||||
COMMAND_MINECART: 命令方块
|
|
||||||
GOLD_RECORD: 音乐唱片
|
|
||||||
GREEN_RECORD: 音乐唱片
|
|
||||||
RECORD_3: 音乐唱片
|
|
||||||
RECORD_4: 音乐唱片
|
|
||||||
RECORD_5: 音乐唱片
|
|
||||||
RECORD_6: 音乐唱片
|
|
||||||
RECORD_7: 音乐唱片
|
|
||||||
RECORD_8: 音乐唱片
|
|
||||||
RECORD_9: 音乐唱片
|
|
||||||
RECORD_10: 音乐唱片
|
|
||||||
RECORD_11: 音乐唱片
|
|
||||||
RECORD_12: 音乐唱片
|
|
@ -1,4 +1,4 @@
|
|||||||
Version: 1.2
|
Version: 1.6
|
||||||
|
|
||||||
not-looking-at-shop: '&c没找到快捷商店. 你必须看着那个商店.'
|
not-looking-at-shop: '&c没找到快捷商店. 你必须看着那个商店.'
|
||||||
no-permission: '&4你没有此命令的权限.'
|
no-permission: '&4你没有此命令的权限.'
|
||||||
@ -19,7 +19,8 @@ shop-purchase-cancelled: '&c取消购买.'
|
|||||||
shop-stock-too-low: '&c商店库存仅剩 {0} {1} '
|
shop-stock-too-low: '&c商店库存仅剩 {0} {1} '
|
||||||
you-cant-afford-to-buy: '&c此商品需要 {0}, 但是你只有 {1}'
|
you-cant-afford-to-buy: '&c此商品需要 {0}, 但是你只有 {1}'
|
||||||
negative-amount: '&c警告, 错误的物品数量.'
|
negative-amount: '&c警告, 错误的物品数量.'
|
||||||
player-bought-from-your-store: '&d{0} 购买了 {1} {2} 从你的商店.'
|
player-bought-from-your-store: '&d{0} 从你的商店买走了 {1} 个 {2}.'
|
||||||
|
player-bought-from-your-store-tax: '&d{0} 从你的商店买走了 {1} 个 {2} &c你上缴了 {3} 的税金.'
|
||||||
shop-out-of-stock: '&5你在 {0}, {1}, {2} 的商店, {3} 库存不足了'
|
shop-out-of-stock: '&5你在 {0}, {1}, {2} 的商店, {3} 库存不足了'
|
||||||
shop-has-no-space: '&c商店只能收购 {0} 个 {1} 商品.'
|
shop-has-no-space: '&c商店只能收购 {0} 个 {1} 商品.'
|
||||||
you-dont-have-that-many-items: '&c你只有 {0} {1}.'
|
you-dont-have-that-many-items: '&c你只有 {0} {1}.'
|
||||||
@ -38,6 +39,7 @@ buying-more-than-selling: '&4警告: 你购买的物品超出了商店的库存!
|
|||||||
not-enough-space: '&c你没有足够的空间装 {0} !'
|
not-enough-space: '&c你没有足够的空间装 {0} !'
|
||||||
refill-success: '&a库存补充成功!'
|
refill-success: '&a库存补充成功!'
|
||||||
empty-success: '&a商店清理成功!'
|
empty-success: '&a商店清理成功!'
|
||||||
|
prevent-create: '&c当前世界禁止使用商店插件!'
|
||||||
|
|
||||||
menu:
|
menu:
|
||||||
successful-purchase: '&a商品购买成功:'
|
successful-purchase: '&a商品购买成功:'
|
||||||
@ -53,11 +55,14 @@ menu:
|
|||||||
damage-percent-remaining: '&a耐久剩余: &e{0}.'
|
damage-percent-remaining: '&a耐久剩余: &e{0}.'
|
||||||
this-shop-is-buying: '&a此商店只 &d收购&a 物品.'
|
this-shop-is-buying: '&a此商店只 &d收购&a 物品.'
|
||||||
this-shop-is-selling: '&a此商店只 &b出售&a 商品.'
|
this-shop-is-selling: '&a此商店只 &b出售&a 商品.'
|
||||||
|
sell-tax: '&a你上缴了 &e{0} &a的税金.'
|
||||||
|
sell-tax-self: '&a你拥有这家商店,所以你不用交税.'
|
||||||
|
|
||||||
info:
|
info:
|
||||||
title: '&a当前加载的 &e{0} &a个区块中 共有 &e{1} &a个商店 覆盖 &e{2} &a个世界.'
|
title: '&a当前加载的 &e{0} &a个区块中 共有 &e{1} &a个商店 覆盖 &e{2} &a个世界.'
|
||||||
selling: '&b出售商店&a有 &e{0} &a个.'
|
selling: '&b出售商店&a有 &e{0} &a个.'
|
||||||
buying: '&d收购商店&a有 &e{0} &a个.'
|
buying: '&d收购商店&a有 &e{0} &a个.'
|
||||||
|
unlimited: '&c无限商店&a有 &e{0} &a个.'
|
||||||
double: '&3大箱子商店 &e{0} &a个.'
|
double: '&3大箱子商店 &e{0} &a个.'
|
||||||
canclean: '&a可以用 &b/qs clean &a清理的商店有 &e{0} &a个.'
|
canclean: '&a可以用 &b/qs clean &a清理的商店有 &e{0} &a个.'
|
||||||
|
|
||||||
@ -97,6 +102,6 @@ command:
|
|||||||
remove: '&e移除眼前的商店.'
|
remove: '&e移除眼前的商店.'
|
||||||
|
|
||||||
signs:
|
signs:
|
||||||
selling: '出售数量: {0}'
|
selling: '&b出售数量: &3{0}'
|
||||||
buying: '收购数量: {0}'
|
buying: '&d收购数量: &3{0}'
|
||||||
price: '每件价格: {0}'
|
price: '每件价格: {0}'
|
@ -1,54 +1,60 @@
|
|||||||
name: ${project.artifactId}
|
name: ${project.artifactId}
|
||||||
description: ${project.description}
|
description: ${project.description}
|
||||||
main: ${project.groupId}.${project.artifactId}.${project.artifactId}
|
main: ${project.groupId}.${project.artifactId}.${project.artifactId}
|
||||||
version: ${project.version}
|
version: ${project.version}-git-${env.GIT_COMMIT}
|
||||||
authors: [Netherfoam,Timtower, KaiNoMood,喵♂呜]
|
authors:
|
||||||
softdepend: [Vault]
|
- Netherfoam
|
||||||
website: http://ci.sumcraft.net:8080/job/${project.artifactId}/
|
- Timtower
|
||||||
|
- KaiNoMood
|
||||||
|
- 喵♂呜
|
||||||
|
softdepend:
|
||||||
|
- Vault
|
||||||
|
- WowSuchCleaner
|
||||||
|
website: ${ciManagement.url}
|
||||||
commands:
|
commands:
|
||||||
qs:
|
qs:
|
||||||
description: QuickShop command
|
description: QuickShop 命令
|
||||||
usage: '§c未知的子命令 请输入 §b/qs help §c查看帮助!'
|
usage: §c未知的子命令 请输入 §b/qs help §c查看帮助!
|
||||||
aliases: [quickshop,shop]
|
aliases:
|
||||||
|
- quickshop
|
||||||
|
- shop
|
||||||
permissions:
|
permissions:
|
||||||
quickshop.create.sell:
|
quickshop.create.sell:
|
||||||
description: Allows a player to sell from a shop
|
description: 允许玩家创建出售商店
|
||||||
default: op
|
default: op
|
||||||
quickshop.create.buy:
|
quickshop.create.buy:
|
||||||
description: Allows a player to buy from a shop
|
description: 允许玩家创建收购商店
|
||||||
default: op
|
default: op
|
||||||
quickshop.create.double:
|
quickshop.create.double:
|
||||||
description: Allows a player to create a double shop
|
description: 允许玩家创建双箱商店
|
||||||
default: op
|
default: op
|
||||||
quickshop.use:
|
quickshop.use:
|
||||||
description: Allows a player to buy/sell using other players shops
|
description: 允许玩家在其他商店交易
|
||||||
default: true
|
default: true
|
||||||
quickshop.unlimited:
|
quickshop.unlimited:
|
||||||
description: Allows a Staff Member to use /qs unlimited and make a shop infinite
|
description: 允许玩家使用/qs unlimited创建无限商店
|
||||||
quickshop.bypass.<itemID>:
|
quickshop.bypass.<itemID>:
|
||||||
description: Allows a player to sell <itemID>, even if its blacklisted
|
description: 允许玩家出售 <itemID>, 即使物品在黑名单里
|
||||||
quickshop.other.destroy:
|
quickshop.other.destroy:
|
||||||
description: Allows a Staff Member to destroy other players shops if they are locked in the config
|
description: 允许玩家摧毁其他玩家的商店
|
||||||
quickshop.other.open:
|
quickshop.other.open:
|
||||||
description: Allows a Staff Member to open someone elses shop if they are locked in the config
|
description: 允许玩家打开其他玩家的商店
|
||||||
quickshop.other.price:
|
quickshop.other.price:
|
||||||
description: Allows a Staff Member to change the price of someone elses shop
|
description: 允许玩家修改商店的价格
|
||||||
quickshop.setowner:
|
quickshop.setowner:
|
||||||
description: Allows a Staff Member to change the owner of any shop
|
description: 允许管理员设置商店的所有者
|
||||||
quickshop.find:
|
quickshop.find:
|
||||||
description: Allows a player to locate the nearest shop of a specific item type. Works in a 3 chunk radius.
|
description: 允许玩家查找附近的商店 (限制在3个区块内工作)
|
||||||
default: true
|
default: true
|
||||||
quickshop.refill:
|
quickshop.refill:
|
||||||
description: Allows a Staff Member to refill the shop theyre looking at with the given number of items.
|
description: 允许玩家填满商店库存
|
||||||
default: op
|
default: op
|
||||||
quickshop.empty:
|
quickshop.empty:
|
||||||
description: Allows a Staff Member to empty the shop theyre looking at of all items.
|
description: 允许玩家清空指定商店
|
||||||
default: op
|
default: op
|
||||||
quickshop.debug:
|
quickshop.debug:
|
||||||
description: Enables debug info to console
|
description: 能够从控制台收到调试信息
|
||||||
default: op
|
default: op
|
||||||
quickshop.export:
|
quickshop.export:
|
||||||
description: Allows exporting database to mysql or sqlite
|
description: 允许导出数据到SQLite或者MySQL
|
||||||
default: op
|
default: op
|
Reference in New Issue
Block a user