1
0
mirror of https://e.coding.net/circlecloud/QuickShop.git synced 2025-10-02 12:37:27 +00:00

105 Commits
1.4 ... dev

Author SHA1 Message Date
979efda24b fix: 数据统计丢失的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-21 21:34:29 +08:00
5cb710c00f feat: 清理无效代码
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-16 20:37:24 +08:00
20dd524044 fix: 修复悬浮物初始化错误
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-15 10:08:22 +08:00
8916dc0d53 feat: 优化代码
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-15 00:29:54 +08:00
833fe1ac43 feat: 去除调试 优化检测线程
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-10 00:04:53 +08:00
b3995f3b2f fix: 修复悬浮物初始化错误
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-09 21:02:55 +08:00
dec12d75cb fix: 修复虚拟悬浮物 优化初始化流程
Signed-off-by: 502647092 <admin@yumc.pw>
2017-05-08 21:17:45 +08:00
ec2498fc48 feat: 调整虚拟悬浮物
Signed-off-by: 502647092 <admin@yumc.pw>
2017-03-17 17:40:09 +08:00
36dd2ac988 fix: 虚拟悬浮物兼容
Signed-off-by: 502647092 <admin@yumc.pw>
2017-03-13 01:05:46 +08:00
b90049aad7 fix: 修复悬浮物和刷物品的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2017-01-25 13:05:10 +08:00
3c5e4c2cf6 feat: 添加特殊端的错误提示
Signed-off-by: 502647092 <admin@yumc.pw>
2016-12-16 16:39:56 +08:00
49c0b8ecd7 feat: 更新类库 代码优化 添加世界限制
Signed-off-by: 502647092 <admin@yumc.pw>
2016-12-13 19:07:37 +08:00
b110da8f73 fix: 修复爆炸破坏木牌的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2016-11-11 17:44:50 +08:00
16571a6035 feat: 添加阻止世界创建商店 重构命令
Signed-off-by: 502647092 <admin@yumc.pw>
2016-11-11 16:10:00 +08:00
00f6466061 feat: 使用新语言库
Signed-off-by: 502647092 <admin@yumc.pw>
2016-09-27 22:07:06 +08:00
fce1e797b9 feat: 调整名称获取方式
Signed-off-by: 502647092 <admin@yumc.pw>
2016-09-16 16:59:33 +08:00
219bbb5539 feat: 完善1.10的虚拟悬浮物
Signed-off-by: 502647092 <admin@yumc.pw>
2016-09-16 16:35:38 +08:00
9c12bb5f91 fix: 修复悬浮物初始化错误
Signed-off-by: 502647092 <admin@yumc.pw>
2016-09-14 02:15:58 +08:00
0c9a014c13 feat: 使用新类库处理命令 添加1.9+虚拟悬浮物
Signed-off-by: 502647092 <admin@yumc.pw>
2016-09-14 02:05:58 +08:00
db7e6c0f4c feat: 添加项目文件
Signed-off-by: 502647092 <admin@yumc.pw>
2016-08-09 12:09:12 +08:00
923abada16 feat: 移动类库路径
Signed-off-by: 502647092 <admin@yumc.pw>
2016-07-28 19:50:30 +08:00
2131ee1746 feat: 更新类库导入
Signed-off-by: 502647092 <admin@yumc.pw>
2016-07-23 14:37:48 +08:00
9fce7de6b4 feat: 木牌第一行显示配置文件的guititle内容
Signed-off-by: 502647092 <admin@yumc.pw>
2016-07-21 15:33:37 +08:00
b10c601ce7 feat: 修复一个在删除商店时导致的报错
Signed-off-by: 502647092 <admin@yumc.pw>
2016-07-16 11:43:18 +08:00
665d6d77d1 fix: 修复同一个玩家的商店直接漏洞不能传递的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2016-06-10 12:56:38 +08:00
9a5b3cb09f fix: 修复方块更新在1.9的报错
Signed-off-by: 502647092 <admin@yumc.pw>
2016-06-06 20:39:14 +08:00
bbea4b57f8 fix: 修复1.9不能异步操作方块的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2016-06-06 20:32:33 +08:00
e3223aa25f fix: 调整异常抛出 2016-05-11 22:46:51 +08:00
e0de9dbe30 doc: 添加更新说明 2016-04-14 13:44:47 +08:00
6dae73e6b7 fix: 屏蔽未处理的异常 2016-04-14 13:43:25 +08:00
abe7fd3412 fix(ShopManager.java): 修复部分异步执行导致的错误
1.修复异步处理购买事件导致的状态错误
2.修复配置文件部分字段不存在导致的报错
2016-04-04 19:07:26 +08:00
918c329b2c refactor: 清理部分无用方法 2016-04-03 23:58:38 +08:00
c2ac919c40 fix(getOfflinePlayer): 修复getOfflinePlayer卡服问题 2016-03-31 08:56:28 +08:00
44ec03bd30 异步发送商店信息 防止getOfflinePlayer卡服 2016-03-23 23:00:56 +08:00
43c6c7a0ef 添加YUMC源中心信息...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-15 19:46:30 +08:00
c05dd7ea0f 修复获取到Location为null的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-06 20:51:22 +08:00
a0e826f8fc 版本描述分割... 2016-03-06 00:19:05 +08:00
75f21b43f4 更新版本构建...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-06 00:18:03 +08:00
79c5036384 更新依赖...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-06 00:15:06 +08:00
365125674f 修复库文件...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-05 22:22:15 +08:00
671932e34b 更新spigot-api修改版本1.8.4...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-05 20:53:35 +08:00
70ba973a9b 修复部分版本服务器启动失败的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-05 20:51:42 +08:00
ad95e07c94 使用注解处理命令...
Signed-off-by: 502647092 <jtb1@163.com>
2016-03-03 20:56:24 +08:00
a8f0fe2600 更新内容去除换行...
Signed-off-by: 502647092 <jtb1@163.com>
2016-02-19 09:44:26 +08:00
4ab5a1aa67 修复一个NPE错误...
Signed-off-by: 502647092 <jtb1@163.com>
2016-02-19 09:34:48 +08:00
82f6c99c01 修复箱子的标题为Null是产生的报错...
Signed-off-by: 502647092 <jtb1@163.com>
2016-02-14 14:44:20 +08:00
9669c6cc8e 修复PlayerInteractEvent错误参数导致GuiShopManager的报错...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-20 20:54:26 +08:00
764f8a8446 自动判断是否启用虚拟悬浮物...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-17 08:39:10 +08:00
abc81b93ed 修复获取到的Location为Null的错误...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-15 21:22:19 +08:00
f8888f5c9f 修复错误 拦截Error...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-15 01:31:10 +08:00
0284355c87 修复悬浮物消失的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-15 00:30:34 +08:00
f91a647dd8 全新版本 虚拟悬浮物(橙子提供对就是那个汉化COI的逗比)7老板修复逗比BUG...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-15 00:18:19 +08:00
b00e35dc17 格式化代码 修复商店创建BUG(7老板)...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-15 00:05:44 +08:00
062534af1f 修复虚拟物品消除错误...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-14 22:58:40 +08:00
56503fee2b 添加虚拟悬浮物(还有BUG 需要修复)...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-14 19:55:44 +08:00
c6f51981fd 修复手动处理无效的问题 使用ProtocolLib序列化物品 感谢尘曲修复类库 2016-01-13 15:55:08 +08:00
ceeeb5802c 修复扫地大妈返回null时的报错...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-12 13:22:13 +08:00
79ea58412a 完善异步玩家背包检测流程...
Signed-off-by: 502647092 <jtb1@163.com>
2016-01-07 13:53:37 +08:00
86d0eb796e 删除无效模块...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-27 20:02:08 +08:00
1a93f43afe 修复更新检测同步处理导致服务器崩溃...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-26 11:12:37 +08:00
1934b5748c 改名物品扩展显示原版物品名称...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-22 09:35:11 +08:00
2397e33d35 修复异步载入商店信息未刷新的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-18 15:37:08 +08:00
8c26cd6fa4 移动异步载入地点...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-18 09:12:30 +08:00
00349aecae 修改本地化工具载入为异步 妈妈再也不担心卡服啦。。。 2015-12-18 08:51:44 +08:00
62bfb22bec 整理代码 清理无效的return...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-12 11:17:35 +08:00
fba0fbab53 修改非法操作提示...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-09 13:39:20 +08:00
4bb7e63266 修复超级工具修改无法保存数据的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-08 21:57:28 +08:00
56fd3f20ed 补全丢失的词条 修改金额格式化方式...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-07 13:32:58 +08:00
f64af66f09 修复商店所有者设置错误...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-06 22:19:57 +08:00
a6b810e140 修复下载问题...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-06 20:13:27 +08:00
ddb78cf045 添加短命令...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-06 18:01:11 +08:00
c9a527b04a 修复配置文件读取失败的问题...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-06 17:01:41 +08:00
f09901f0b5 修改扫描流程 发现非法物品后扫描玩家背包...
Signed-off-by: 502647092 <jtb1@163.com>
2015-12-06 16:33:24 +08:00
ab54e56821 修改语言文件 调整保存商店信息...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-27 12:04:20 +08:00
8aa88ddfef 添加Tab补全 使用新版PH...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-24 15:31:34 +08:00
2467855766 修复悬浮物刷物品 异步检测装备...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-23 21:00:24 +08:00
a0f4846fd1 修复命令无法修改商店为出售...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-20 14:28:00 +08:00
5fa9ec9142 Merge remote-tracking branch 'origin/master' 2015-11-20 13:20:20 +08:00
a98acb58de 调整汉化文件部分...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-20 13:20:11 +08:00
d5f7f5d429 重载语言配置文件.....
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-18 23:12:31 +08:00
70cba23dc8 更新到1.6.1版本 汉化配置文件...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-18 14:27:13 +08:00
0de3e1a0c7 添加SuperItem的null判断...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-18 12:56:45 +08:00
f2c7c9c2b1 更新LocalUtil 已翻译IC2 和风 NPC 等MOD物品名称...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-14 11:09:45 +08:00
f89f58ba40 紧急更新 修复金斧权限问题...
Signed-off-by: 502647092 <jtb1@163.com>
2015-11-05 11:07:12 +08:00
d8e8678d31 fix item check...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-28 13:13:04 +08:00
b4623befa9 add log create and change shop type...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-28 10:49:00 +08:00
a545a62ef0 chage Config file...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-25 17:54:19 +08:00
31db322e36 fix Owner cna't open gui ...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-25 17:10:39 +08:00
1d951ac2bd fix reload config error and interact action...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-23 16:34:36 +08:00
bcf33b9133 update to 1.5.1...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-23 10:50:22 +08:00
56e0fd8430 catch all error and exception while load magic lib...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-21 14:20:06 +08:00
fa9eead0a9 update pom and add update description...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-21 09:52:15 +08:00
6ed44b3def remove Plugin Metrics...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-21 00:31:36 +08:00
5b6abc1c07 add protect holder and update version to 1.4.4...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-20 18:36:53 +08:00
7d908ff59a update new magic lib...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-18 23:07:34 +08:00
c83ace24c9 fix Owner can't remove shop while gui mode...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-18 14:43:37 +08:00
b409fcc32f fix command permission error...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-18 12:01:28 +08:00
714ce2fa32 add new info unlimited...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-18 11:39:15 +08:00
7f1c37ec4e update priject...
Signed-off-by: j502647092 <jtb1@163.com>
2015-10-17 22:33:18 +08:00
3f781c473c Hook WowSuchListener...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-17 17:54:53 +08:00
5bab17a117 show unlimited numner to chinese...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-17 10:58:06 +08:00
b9a9fe292c modify enable magic library method...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-17 10:47:23 +08:00
efb4e18617 use default jenkins... 2015-10-16 16:08:57 +08:00
f807c054d4 add config usemagiclib...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-16 16:02:48 +08:00
037f5138bb set Default Inventory Title...
Signed-off-by: 502647092 <jtb1@163.com>
2015-10-16 13:11:23 +08:00
65 changed files with 5260 additions and 5637 deletions

2
.gitignore vendored
View File

@ -1,6 +1,4 @@
# Eclipse stuff # Eclipse stuff
/.classpath
/.project
/.settings /.settings
# netbeans # netbeans

Binary file not shown.

Binary file not shown.

195
pom.xml
View File

@ -1,110 +1,89 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<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.1.1</version>
<build> <description>快捷商店重置版本...</description>
<finalName>${project.name}</finalName> <build>
<resources> <finalName>${project.name}</finalName>
<resource> <resources>
<directory>src/main/resources</directory> <resource>
<filtering>true</filtering> <directory>src/main/resources</directory>
</resource> <filtering>true</filtering>
</resources> </resource>
<plugins> </resources>
<plugin> <plugins>
<artifactId>maven-compiler-plugin</artifactId> <plugin>
<version>3.1</version> <groupId>org.apache.maven.plugins</groupId>
<configuration> <artifactId>maven-shade-plugin</artifactId>
<source>1.7</source> <version>2.4.3</version>
<target>1.7</target> <configuration>
</configuration> <createDependencyReducedPom>false</createDependencyReducedPom>
</plugin> <minimizeJar>true</minimizeJar>
<plugin> <artifactSet>
<groupId>org.apache.maven.plugins</groupId> <includes>
<artifactId>maven-shade-plugin</artifactId> <include>pw.yumc:YumCore</include>
<version>2.3</version> </includes>
<configuration> </artifactSet>
<createDependencyReducedPom>false</createDependencyReducedPom> <relocations>
<minimizeJar>true</minimizeJar> <relocation>
<artifactSet> <pattern>pw.yumc.YumCore</pattern>
<includes> <shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern>
<include>cn.citycraft:PluginHelper</include> </relocation>
<include>org.mcstats.*:*</include> </relocations>
</includes> </configuration>
</artifactSet> <executions>
<relocations> <execution>
<relocation> <phase>package</phase>
<pattern>org.mcstats</pattern> <goals>
<shadedPattern>${project.groupId}.${project.artifactId}.mcstats</shadedPattern> <goal>shade</goal>
</relocation> </goals>
<relocation> </execution>
<pattern>cn.citycraft.PluginHelper</pattern> </executions>
<shadedPattern>${project.groupId}.${project.artifactId}</shadedPattern> </plugin>
</relocation> </plugins>
</relocations> </build>
</configuration> <ciManagement>
<executions> <system>Jenkins</system>
<execution> <url>http://ci.yumc.pw/job/${project.artifactId}/</url>
<phase>package</phase> </ciManagement>
<goals> <properties>
<goal>shade</goal> <env.GIT_COMMIT>DEBUG</env.GIT_COMMIT>
</goals> <update.description>§a全新版本 §c虚拟悬浮物(橙子提供 对 就是那个汉化COI的逗比)§e7老板修复逗比BUG...</update.description>
</execution> <update.changes>
</executions> §b2.1.0 - §c修复大箱子刷物品的问题...;
</plugin> §b2.0.1 - §a使用新类库 兼容最新版本...;
</plugins> §b1.9.5 - §a1.10+兼容虚拟悬浮物...;
</build> </update.changes>
<repositories> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<repository> <maven.compiler.source>1.8</maven.compiler.source>
<id>spigot-repo</id> <maven.compiler.target>1.8</maven.compiler.target>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url> </properties>
</repository> <repositories>
<repository> <repository>
<id>sumcraft-repo</id> <id>yumc-repo</id>
<url>http://ci.sumcraft.net:8080/plugin/repository/everything/</url> <url>http://repo.yumc.pw/content/groups/public/</url>
</repository> </repository>
<repository> </repositories>
<id>Plugin Metrics</id> <distributionManagement>
<url>http://repo.mcstats.org/content/repositories/public</url> <repository>
</repository> <id>jtb</id>
</repositories> <name>YUMC</name>
<dependencies> <url>http://repo.yumc.pw/content/repositories/yumcenter/</url>
<dependency> </repository>
<groupId>org.spigotmc</groupId> </distributionManagement>
<artifactId>spigot-api</artifactId> <dependencies>
<type>jar</type> <dependency>
<version>1.8.8-R0.1-SNAPSHOT</version> <groupId>pw.yumc</groupId>
</dependency> <artifactId>YumCore</artifactId>
<dependency> <type>jar</type>
<groupId>net.milkbowl.vault</groupId> <version>1.7</version>
<artifactId>VaultAPI</artifactId> </dependency>
<version>1.5</version> <dependency>
<scope>system</scope> <groupId>io.github.Cnly.WowSuchCleaner</groupId>
<systemPath>${project.basedir}/lib/Vault.jar</systemPath> <artifactId>WowSuchCleaner</artifactId>
</dependency> <version>1.6.5</version>
<dependency> </dependency>
<groupId>com.sk89q</groupId> </dependencies>
<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>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project> </project>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 + "未找到商店!");
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));
hsc.registerCommand(new CommandEmpty(plugin));
hsc.registerCommand(new CommandExport(plugin));
hsc.registerCommand(new CommandFind(plugin));
hsc.registerCommand(new CommandInfo(plugin));
hsc.registerCommand(new CommandPrice(plugin));
hsc.registerCommand(new CommandRefill(plugin));
hsc.registerCommand(new CommandReload(plugin));
hsc.registerCommand(new CommandRemove(plugin));
hsc.registerCommand(new CommandBuy(plugin));
hsc.registerCommand(new CommandSetOwner(plugin));
hsc.registerCommand(new CommandSell(plugin));
hsc.registerCommand(new CommandUnlimited(plugin));
}
@Override @Sort(1)
public void defaultExecute(final CommandSender sender, final Command command, final String label) throws CommandException { @Cmd(aliases = "b", permission = "quickshop.create.buy", executor = Cmd.Executor.PLAYER)
hsc.sendHelp(sender, label); @Help("command.description.buy")
} public void buy(Player player) {
changeShopType(player, ShopType.BUYING);
}
@Override @Sort(7)
public boolean onCommand(final CommandSender sender, final Command cmd, final String label, final String[] args) { @Cmd(aliases = "c", permission = "quickshop.clean")
return hsc.onCommand(sender, cmd, label, args); @Help("command.description.clean")
} public void clean(CommandSender sender) {
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 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
public String parse(final String str) {
return MsgUtil.p(str);
}
@Sort(4)
@Cmd(aliases = "p", minimumArguments = 1, permission = "quickshop.create.changeprice", executor = Cmd.Executor.PLAYER)
@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;
}
} }

View File

@ -1,166 +1,218 @@
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 {
/** Whether debug info should be shown in the console */ private boolean enableMagicLib = false;
protected boolean debug = false; /** Whether debug info should be shown in the console */
/** Whether we should use display items or not */ private final boolean debug = false;
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 we players are charged a fee to change the price on their shop /** Whether or not to limit players shop amounts */
* (To help deter endless undercutting private boolean limit = false;
*/
protected boolean priceChangeRequiresFee = false;
protected boolean shopLock = true;
protected boolean showTax;
/** Whether players are required to sneak to create/buy from a shop */
protected boolean sneak;
/** Whether players are required to sneak to create a shop */
protected boolean sneakCreate;
/** Whether players are required to sneak to trade with a shop */
protected boolean sneakTrade;
protected Material superItem = Material.GOLD_AXE;
protected double tax = 0;
protected String taxAccount;
/** Use SpoutPlugin to get item / block names */
protected boolean useSpout = false;
/**
* A set of players who have been warned
* ("Your shop isn't automatically locked")
*/
protected HashSet<String> warnings = new HashSet<String>();
public ConfigManager(final QuickShop plugin) { private int limitdefault = 0;
final FileConfig config = (FileConfig) plugin.getConfig(); private final HashMap<String, Integer> limits = new HashMap<>();
ConfigurationSection limitCfg = config.getConfigurationSection("limits"); private boolean logAction = true;
if (limitCfg != null) { private boolean preventhopper = false;
this.limit = limitCfg.getBoolean("use", false); /**
this.limitdefault = config.getInt("limits.default"); * Whether we players are charged a fee to change the price on their shop
limitCfg = limitCfg.getConfigurationSection("ranks"); * (To help deter endless undercutting
for (final String key : limitCfg.getKeys(true)) { */
limits.put(key, limitCfg.getInt(key)); private boolean priceChangeRequiresFee = false;
} private boolean shopLock = true;
} private boolean showTax = false;
try { /** Whether players are required to sneak to create/buy from a shop */
this.superItem = Enum.valueOf(Material.class, config.getString("superitem")); private boolean sneak = false;
} catch (final Exception e) { /** Whether players are required to sneak to create a shop */
} private boolean sneakCreate = false;
this.tax = config.getDouble("tax"); /** Whether players are required to sneak to trade with a shop */
this.showTax = config.getBoolean("show-tax"); private boolean sneakTrade = false;
this.taxAccount = config.getString("tax-account"); private Material superItem = Material.GOLD_AXE;
this.logAction = config.getBoolean("log-actions"); private double tax = 0;
this.shopLock = config.getBoolean("shop.lock"); private final String taxAccount;
this.display = config.getBoolean("shop.display-items"); private boolean fakeItem = false;
this.sneak = config.getBoolean("shop.sneak-only"); private List<String> prevent;
this.sneakCreate = config.getBoolean("shop.sneak-to-create"); /**
this.sneakTrade = config.getBoolean("shop.sneak-to-trade"); * A set of players who have been warned
this.priceChangeRequiresFee = config.getBoolean("shop.price-change-requires-fee"); * ("Your shop isn't automatically locked")
this.findDistance = config.getInt("shop.find-distance"); */
this.feeForPriceChange = config.getDouble("shop.fee-for-price-change"); private Set<String> warnings = new HashSet<>();
this.preventhopper = config.getBoolean("preventhopper");
this.guiTitle = config.getMessage("guititle");
}
public double getFeeForPriceChange() { public ConfigManager(final QuickShop plugin) {
return feeForPriceChange; final FileConfig config = (FileConfig) plugin.getConfig();
} ConfigurationSection limitCfg = config.getConfigurationSection("limits");
if (limitCfg != null) {
this.limit = limitCfg.getBoolean("use", false);
this.limitdefault = config.getInt("limits.default");
limitCfg = limitCfg.getConfigurationSection("ranks");
for (final String key : limitCfg.getKeys(true)) {
limits.put(key, limitCfg.getInt(key));
}
}
try {
this.superItem = Material.valueOf(config.getString("superitem"));
} catch (final Exception ignored) {
}
this.tax = config.getDouble("tax");
this.showTax = config.getBoolean("show-tax");
this.taxAccount = config.getString("tax-account");
this.logAction = config.getBoolean("log-actions");
this.shopLock = config.getBoolean("shop.lock");
this.display = config.getBoolean("shop.display-items");
this.sneak = config.getBoolean("shop.sneak-only");
this.sneakCreate = config.getBoolean("shop.sneak-to-create");
this.sneakTrade = config.getBoolean("shop.sneak-to-trade");
this.priceChangeRequiresFee = config.getBoolean("shop.price-change-requires-fee");
this.findDistance = config.getInt("shop.find-distance");
this.feeForPriceChange = config.getDouble("shop.fee-for-price-change");
this.preventhopper = config.getBoolean("preventhopper");
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 int getFindDistance() { public double getFeeForPriceChange() {
return findDistance; return feeForPriceChange;
} }
public String getGuiTitle() { public int getFindDistance() {
return guiTitle; return findDistance;
} }
public int getLimitdefault() { public String getGuiTitle() {
return limitdefault; return guiTitle;
} }
public HashMap<String, Integer> getLimits() { public int getLimitdefault() {
return limits; return limitdefault;
} }
public Material getSuperItem() { public HashMap<String, Integer> getLimits() {
return superItem; return limits;
} }
public double getTax() { public Material getSuperItem() {
return tax; return superItem;
} }
public String getTaxAccount() { public double getTax() {
return taxAccount; return tax;
} }
public HashSet<String> getWarnings() { public String getTaxAccount() {
return warnings; return taxAccount;
} }
public boolean isDebug() { public Set<String> getWarnings() {
return debug; return warnings;
} }
public boolean isDisplay() { public boolean isDebug() {
return display; return debug;
} }
public boolean isLimit() { public boolean isDisplay() {
return limit; return display;
} }
public boolean isLogAction() { public boolean isEnableMagicLib() {
return logAction; return enableMagicLib;
} }
public boolean isPreventHopper() { public boolean isFakeItem() {
return preventhopper; return fakeItem;
} }
public boolean isPriceChangeRequiresFee() { public boolean isLimit() {
return priceChangeRequiresFee; return limit;
} }
public boolean isShopLock() { public boolean isLogAction() {
return shopLock; return logAction;
} }
public boolean isShowTax() { public boolean isPreventHopper() {
return showTax; return preventhopper;
} }
public boolean isSneak() { public boolean isPriceChangeRequiresFee() {
return sneak; return priceChangeRequiresFee;
} }
public boolean isSneakCreate() { public boolean isShopLock() {
return sneakCreate; return shopLock;
} }
public boolean isSneakTrade() { public boolean isShowTax() {
return sneakTrade; return showTax;
} }
public boolean isUseSpout() { public boolean isSneak() {
return useSpout; return sneak;
} }
public boolean isSneakCreate() {
return sneakCreate;
}
public boolean isSneakTrade() {
return sneakTrade;
}
public void setEnableMagicLib(final boolean enableMagicLib) {
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;
}
} }

View File

@ -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();
}
}

View File

@ -6,69 +6,69 @@ import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
public class BufferStatement { public class BufferStatement {
private Object[] values; private Object[] values;
private String query; private String query;
private Exception stacktrace; private Exception stacktrace;
/** /**
* Represents a PreparedStatement in a state before preparing it (E.g. No * Represents a PreparedStatement in a state before preparing it (E.g. No
* file I/O Required) * file I/O Required)
* *
* @param query * @param query
* The query to execute. E.g. INSERT INTO accounts (user, passwd) * The query to execute. E.g. INSERT INTO accounts (user, passwd)
* VALUES (?, ?) * VALUES (?, ?)
* @param values * @param values
* The values to replace <bold>?</bold> with in * The values to replace <bold>?</bold> with in
* <bold>query</bold>. These are in order. * <bold>query</bold>. These are in order.
*/ */
public BufferStatement(String query, Object... values) { public BufferStatement(String query, Object... values) {
this.query = query; this.query = query;
this.values = values; this.values = values;
this.stacktrace = new Exception(); // For error handling this.stacktrace = new Exception(); // For error handling
this.stacktrace.fillInStackTrace(); // We can declare where this this.stacktrace.fillInStackTrace(); // We can declare where this
// statement came from. // statement came from.
} }
/** /**
* Returns a prepared statement using the given connection. Will try to * Returns a prepared statement using the given connection. Will try to
* return an empty statement if something went wrong. If that fails, returns * return an empty statement if something went wrong. If that fails, returns
* null. * null.
* *
* This method escapes everything automatically. * This method escapes everything automatically.
* *
* @param con * @param con
* The connection to prepare this on using * The connection to prepare this on using
* con.prepareStatement(..) * con.prepareStatement(..)
* @return The prepared statement, ready for execution. * @return The prepared statement, ready for execution.
*/ */
public PreparedStatement prepareStatement(Connection con) throws SQLException { public PreparedStatement prepareStatement(Connection con) throws SQLException {
PreparedStatement ps; PreparedStatement ps;
ps = con.prepareStatement(query); ps = con.prepareStatement(query);
for (int i = 1; i <= values.length; i++) { for (int i = 1; i <= values.length; i++) {
ps.setObject(i, values[i - 1]); ps.setObject(i, values[i - 1]);
} }
return ps; return ps;
} }
/** /**
* Used for debugging. This stacktrace is recorded when the statement is * Used for debugging. This stacktrace is recorded when the statement is
* created, so printing it to the screen will provide useful debugging * created, so printing it to the screen will provide useful debugging
* information about where the query came from, if something went wrong * information about where the query came from, if something went wrong
* while executing it. * while executing it.
* *
* @return The stacktrace elements. * @return The stacktrace elements.
*/ */
public StackTraceElement[] getStackTrace() { public StackTraceElement[] getStackTrace() {
return stacktrace.getStackTrace(); return stacktrace.getStackTrace();
} }
/** /**
* @return A string representation of this statement. Returns * @return A string representation of this statement. Returns
* <italic>"Query: " + query + ", values: " + * <italic>"Query: " + query + ", values: " +
* Arrays.toString(values).</italic> * Arrays.toString(values).</italic>
*/ */
@Override @Override
public String toString() { public String toString() {
return "Query: " + query + ", values: " + Arrays.toString(values); return "Query: " + query + ", values: " + Arrays.toString(values);
} }
} }

View File

@ -8,192 +8,191 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
public class Database { public class Database {
private DatabaseCore core; private DatabaseCore core;
/** /**
* Creates a new database and validates its connection. * Creates a new database and validates its connection.
* *
* If the connection is invalid, this will throw a ConnectionException. * If the connection is invalid, this will throw a ConnectionException.
* *
* @param core * @param core
* The core for the database, either MySQL or SQLite. * The core for the database, either MySQL or SQLite.
* @throws ConnectionException * @throws ConnectionException
* If the connection was invalid * If the connection was invalid
*/ */
public Database(DatabaseCore core) throws ConnectionException { public Database(DatabaseCore core) throws ConnectionException {
try { try {
try { try {
if (!core.getConnection().isValid(10)) { if (!core.getConnection().isValid(10)) {
throw new ConnectionException("Database doesn not appear to be valid!"); throw new ConnectionException("Database doesn not appear to be valid!");
} }
} catch (AbstractMethodError e) { } catch (AbstractMethodError e) {
// You don't need to validate this core. // You don't need to validate this core.
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new ConnectionException(e.getMessage()); throw new ConnectionException(e.getMessage());
} }
this.core = core; this.core = core;
} }
/** /**
* Returns the database core object, that this database runs on. * Returns the database core object, that this database runs on.
* *
* @return the database core object, that this database runs on. * @return the database core object, that this database runs on.
*/ */
public DatabaseCore getCore() { public DatabaseCore getCore() {
return core; return core;
} }
/** /**
* Fetches the connection to this database for querying. Try to avoid doing * Fetches the connection to this database for querying. Try to avoid doing
* this in the main thread. * this in the main thread.
* *
* @return Fetches the connection to this database for querying. * @return Fetches the connection to this database for querying.
*/ */
public Connection getConnection() { public Connection getConnection() {
return core.getConnection(); return core.getConnection();
} }
/** /**
* Executes the given statement either immediately, or soon. * Executes the given statement either immediately, or soon.
* *
* @param query * @param query
* The query * The query
* @param objs * @param objs
* The string values for each ? in the given query. * The string values for each ? in the given query.
*/ */
public void execute(String query, Object... objs) { public void execute(String query, Object... objs) {
BufferStatement bs = new BufferStatement(query, objs); BufferStatement bs = new BufferStatement(query, objs);
core.queue(bs); core.queue(bs);
} }
/** /**
* Returns true if the table exists * Returns true if the table exists
* *
* @param table * @param table
* The table to check for * The table to check for
* @return True if the table is found * @return True if the table is found
*/ */
public boolean hasTable(String table) throws SQLException { public boolean hasTable(String table) throws SQLException {
ResultSet rs = getConnection().getMetaData().getTables(null, null, "%", null); ResultSet rs = getConnection().getMetaData().getTables(null, null, "%", null);
while (rs.next()) { while (rs.next()) {
if (table.equalsIgnoreCase(rs.getString("TABLE_NAME"))) { if (table.equalsIgnoreCase(rs.getString("TABLE_NAME"))) {
rs.close(); rs.close();
return true; return true;
} }
} }
rs.close(); rs.close();
return false; return false;
} }
/** /**
* Closes the database * Closes the database
*/ */
public void close() { public void close() {
this.core.close(); this.core.close();
} }
/** /**
* Returns true if the given table has the given column * Returns true if the given table has the given column
* *
* @param table * @param table
* The table * The table
* @param column * @param column
* The column * The column
* @return True if the given table has the given column * @return True if the given table has the given column
* @throws SQLException * @throws SQLException
* If the database isn't connected * If the database isn't connected
*/ */
public boolean hasColumn(String table, String column) throws SQLException { public boolean hasColumn(String table, String column) throws SQLException {
if (!hasTable(table)) if (!hasTable(table))
return false; return false;
String query = "SELECT * FROM " + table + " LIMIT 0,1"; String query = "SELECT * FROM " + table + " LIMIT 0,1";
try { try {
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) { return false;
return false; }
} return false; // Uh, wtf.
return false; // Uh, wtf. }
}
/** /**
* Represents a connection error, generally when the server can't connect to * Represents a connection error, generally when the server can't connect to
* MySQL or something. * MySQL or something.
*/ */
public static class ConnectionException extends Exception { public static class ConnectionException extends Exception {
private static final long serialVersionUID = 8348749992936357317L; private static final long serialVersionUID = 8348749992936357317L;
public ConnectionException(String msg) { public ConnectionException(String msg) {
super(msg); super(msg);
} }
} }
/** /**
* Copies the contents of this database into the given database. Does not * Copies the contents of this database into the given database. Does not
* delete the contents of this database, or change any settings. This may * delete the contents of this database, or change any settings. This may
* take a long time, and will print out progress reports to System.out * take a long time, and will print out progress reports to System.out
* *
* This method does not create the tables in the new database. You need to * This method does not create the tables in the new database. You need to
* do that yourself. * do that yourself.
* *
* @param db * @param db
* The database to copy data to * The database to copy data to
* @throws SQLException * @throws SQLException
* if an error occurs. * if an error occurs.
*/ */
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"));
} }
rs.close(); rs.close();
core.flush(); core.flush();
// For each table // For each table
for (String table : tables) { for (String table : tables) {
if (table.toLowerCase().startsWith("sqlite_autoindex_")) if (table.toLowerCase().startsWith("sqlite_autoindex_"))
continue; continue;
System.out.println("Copying " + table); System.out.println("Copying " + table);
// Wipe the old records // Wipe the old records
db.getConnection().prepareStatement("DELETE FROM " + table).execute(); db.getConnection().prepareStatement("DELETE FROM " + table).execute();
// Fetch all the data from the existing database // Fetch all the data from the existing database
rs = getConnection().prepareStatement("SELECT * FROM " + table).executeQuery(); rs = getConnection().prepareStatement("SELECT * FROM " + table).executeQuery();
int n = 0; int n = 0;
// Build the query // Build the query
String query = "INSERT INTO " + table + " VALUES ("; String query = "INSERT INTO " + table + " VALUES (";
// Append another placeholder for the value // Append another placeholder for the value
query += "?"; query += "?";
for (int i = 2; i <= rs.getMetaData().getColumnCount(); i++) { for (int i = 2; i <= rs.getMetaData().getColumnCount(); i++) {
// Add the rest of the placeholders and values. This is so we // Add the rest of the placeholders and values. This is so we
// have (?, ?, ?) and not (?, ?, ?, ). // have (?, ?, ?) and not (?, ?, ?, ).
query += ", ?"; query += ", ?";
} }
// End the query // End the query
query += ")"; query += ")";
PreparedStatement ps = db.getConnection().prepareStatement(query); PreparedStatement ps = db.getConnection().prepareStatement(query);
while (rs.next()) { while (rs.next()) {
n++; n++;
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
ps.setObject(i, rs.getObject(i)); ps.setObject(i, rs.getObject(i));
} }
ps.addBatch(); ps.addBatch();
if (n % 100 == 0) { if (n % 100 == 0) {
ps.executeBatch(); ps.executeBatch();
System.out.println(n + " records copied..."); System.out.println(n + " records copied...");
} }
} }
ps.executeBatch(); ps.executeBatch();
// Close the resultset of that table // Close the resultset of that table
rs.close(); rs.close();
} }
// Success! // Success!
db.getConnection().close(); db.getConnection().close();
this.getConnection().close(); this.getConnection().close();
} }
} }

View File

@ -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();
} }

View File

@ -5,58 +5,59 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
public class DatabaseHelper { public class DatabaseHelper {
public static void setup(Database db) throws SQLException { public static void setup(Database db) throws SQLException {
if (!db.hasTable("shops")) { if (!db.hasTable("shops")) {
createShopsTable(db); createShopsTable(db);
} }
if (!db.hasTable("messages")) { if (!db.hasTable("messages")) {
createMessagesTable(db); createMessagesTable(db);
} }
checkColumns(db); checkColumns(db);
} }
/** /**
* 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) {
} }
} }
/** /**
* Creates the database table 'shops'. * Creates the database table 'shops'.
* *
* @throws SQLException * @throws SQLException
* If the connection is invalid. * If the connection is invalid.
*/ */
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, "
st.execute(createTable); + "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);
}
/** /**
* Creates the database table 'messages' * Creates the database table 'messages'
* *
* @throws SQLException * @throws SQLException
* If the connection is invalid * If the connection is invalid
*/ */
public static void createMessagesTable(Database db) throws SQLException { public static void createMessagesTable(Database db) throws SQLException {
Statement st = db.getConnection().createStatement(); Statement st = db.getConnection().createStatement();
String createTable = "CREATE TABLE messages (" + "owner TEXT(32) NOT NULL, " + "message TEXT(200) NOT NULL, " + "time BIGINT(32) NOT NULL " + ");"; String createTable = "CREATE TABLE messages (" + "owner TEXT(32) NOT NULL, " + "message TEXT(200) NOT NULL, " + "time BIGINT(32) NOT NULL " + ");";
st.execute(createTable); st.execute(createTable);
} }
} }

View File

@ -8,78 +8,77 @@ import java.util.ArrayList;
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 ArrayList<Connection> pool = new ArrayList<>();
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();
info.put("autoReconnect", "true"); info.put("autoReconnect", "true");
info.put("user", user); info.put("user", user);
info.put("password", pass); info.put("password", pass);
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);
} }
/** /**
* Gets the database connection for executing queries on. * Gets the database connection for executing queries on.
* *
* @return The database connection * @return The database connection
*/ */
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()) {
if (connection.isValid(10)) { if (connection.isValid(10)) {
return connection; return connection;
} }
// 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();
} }
} }
return null; return null;
} }
@Override @Override
public void queue(BufferStatement bs) { public void queue(BufferStatement bs) {
try { try {
Connection con = this.getConnection(); Connection con = this.getConnection();
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();
} }
PreparedStatement ps = bs.prepareStatement(con); PreparedStatement ps = bs.prepareStatement(con);
ps.execute(); ps.execute();
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
return; }
} }
}
@Override @Override
public void close() { public void close() {
// Nothing, because queries are executed immediately for MySQL // Nothing, because queries are executed immediately for MySQL
} }
@Override @Override
public void flush() { public void flush() {
// Nothing, because queries are executed immediately for MySQL // Nothing, because queries are executed immediately for MySQL
} }
} }

View File

@ -9,102 +9,97 @@ import java.sql.SQLException;
import java.util.LinkedList; 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
* Gets the database connection for executing queries on. public void close() {
* flush();
* @return The database connection }
*/
public Connection getConnection() {
try {
// If we have a current connection, fetch it
if (this.connection != null && !this.connection.isClosed()) {
return this.connection;
}
} catch (SQLException e) {
e.printStackTrace();
}
if (this.dbFile.exists()) {
// So we need a new connection
try {
Class.forName("org.sqlite.JDBC");
this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbFile);
return this.connection;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
} else {
// So we need a new file too.
try {
// Create the file
this.dbFile.createNewFile();
// Now we won't need a new file, just a connection.
// This will return that new connection.
return this.getConnection();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
@Override @Override
public void queue(BufferStatement bs) { public void flush() {
synchronized (queue) { while (!queue.isEmpty()) {
queue.add(bs); BufferStatement bs;
} synchronized (queue) {
if (watcher == null || !watcher.isAlive()) { bs = queue.removeFirst();
startWatcher(); }
} synchronized (dbFile) {
} try {
final PreparedStatement ps = bs.prepareStatement(getConnection());
ps.execute();
ps.close();
} catch (final SQLException e) {
e.printStackTrace();
}
}
}
}
@Override /**
public void flush() { * Gets the database connection for executing queries on.
while (queue.isEmpty() == false) { *
BufferStatement bs; * @return The database connection
synchronized (queue) { */
bs = queue.removeFirst(); @Override
} public Connection getConnection() {
synchronized (dbFile) { try {
try { // If we have a current connection, fetch it
PreparedStatement ps = bs.prepareStatement(getConnection()); if (this.connection != null && !this.connection.isClosed()) { return this.connection; }
ps.execute(); } catch (final SQLException e) {
ps.close(); e.printStackTrace();
} catch (SQLException e) { }
e.printStackTrace(); if (this.dbFile.exists()) {
} // So we need a new connection
} try {
} Class.forName("org.sqlite.JDBC");
} this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbFile);
return this.connection;
} catch (final ClassNotFoundException | SQLException e) {
e.printStackTrace();
return null;
}
}
// So we need a new file too.
try {
// Create the file
this.dbFile.createNewFile();
// Now we won't need a new file, just a connection.
// This will return that new connection.
return this.getConnection();
} catch (final IOException e) {
e.printStackTrace();
return null;
}
}
@Override @Override
public void close() { public void queue(final BufferStatement bs) {
flush(); synchronized (queue) {
} queue.add(bs);
}
if (watcher == null || !watcher.isAlive()) {
startWatcher();
}
}
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();
} }
}; };
watcher.start(); watcher.start();
} }
} }

View File

@ -3,117 +3,129 @@ 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();
}
/** /**
* 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.
* *
* @param name * @param name
* The exact (case insensitive) username to give money to * The exact (case insensitive) username to give money to
* @param amount * @param amount
* 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)
*/ */
@Deprecated @Override
public boolean deposit(String name, double amount) { @Deprecated
return core.deposit(name, amount); public boolean deposit(final String name, final double amount) {
} return this.core.deposit(name, amount);
}
/** @Override
* Withdraws a given amount of money from the given username and turns it to public boolean deposit(final UUID name, final double amount) {
* thin air. return this.core.deposit(name, amount);
* }
* @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
*/
@Deprecated
public boolean withdraw(String name, double amount) {
return core.withdraw(name, amount);
}
/** /**
* Transfers the given amount of money from Player1 to Player2 * Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
* * Dollars 5 Cents
* @param from *
* The player who is paying money * @param balance
* @param to * The given number
* The player who is receiving money * @return The balance in human readable text.
* @param amount */
* The amount to transfer @Override
* @return true if success (Payer had enough cash, receiver was able to public String format(final double balance) {
* receive the funds) return this.core.format(balance);
*/ }
@Deprecated
public boolean transfer(String from, String to, double amount) {
return core.transfer(from, to, amount);
}
/** /**
* Fetches the balance of the given account name * Fetches the balance of the given account name
* *
* @param name * @param name
* The name of the account * The name of the account
* @return Their current balance. * @return Their current balance.
*/ */
@Deprecated @Override
public double getBalance(String name) { @Deprecated
return core.getBalance(name); public double getBalance(final String name) {
} return this.core.getBalance(name);
}
/** @Override
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50 public double getBalance(final UUID name) {
* Dollars 5 Cents return this.core.getBalance(name);
* }
* @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 @Deprecated
public String toString() { public boolean has(final String name, final double amount) {
return core.getClass().getName().split("_")[1]; return this.core.getBalance(name) >= amount;
} }
@Override /**
public boolean deposit(UUID name, double amount) { * Checks that this economy is valid. Returns false if it is not valid.
return core.deposit(name,amount); *
} * @return True if this economy will work, false if it will not.
*/
@Override
public boolean isValid() {
return this.core.isValid();
}
@Override @Override
public boolean withdraw(UUID name, double amount) { public String toString() {
return core.withdraw(name, amount); return this.core.getClass().getName().split("_")[1];
} }
@Override /**
public boolean transfer(UUID from, UUID to, double amount) { * Transfers the given amount of money from Player1 to Player2
return core.transfer(from, to, amount); *
} * @param from
* The player who is paying money
* @param to
* The player who is receiving money
* @param amount
* The amount to transfer
* @return true if success (Payer had enough cash, receiver was able to
* receive the funds)
*/
@Override
@Deprecated
public boolean transfer(final String from, final String to, final double amount) {
return this.core.transfer(from, to, amount);
}
@Override @Override
public double getBalance(UUID name) { public boolean transfer(final UUID from, final UUID to, final double amount) {
return core.getBalance(name); return this.core.transfer(from, to, 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
*/
@Override
@Deprecated
public boolean withdraw(final String name, final double amount) {
return this.core.withdraw(name, amount);
}
@Override
public boolean withdraw(final UUID name, final double amount) {
return this.core.withdraw(name, amount);
}
} }

View File

@ -6,122 +6,118 @@ 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.
* *
* @param name * @param name
* The exact (case insensitive) username to give money to * The exact (case insensitive) username to give money to
* @param amount * @param amount
* 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)
*/ */
@Deprecated @Deprecated
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 give money to
* The exact (case insensitive) username to take money from * @param amount
* @param amount * The amount to give them
* The amount to take from them * @return True if success (Should be almost always)
* @return True if success, false if they didn't have enough cash */
*/ public boolean deposit(UUID name, double amount);
@Deprecated
public boolean withdraw(String name, double amount);
/** /**
* Transfers the given amount of money from Player1 to Player2 * Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50
* * Dollars 5 Cents
* @param from *
* The player who is paying money * @param balance
* @param to * The given number
* The player who is receiving money * @return The balance in human readable text.
* @param amount */
* The amount to transfer public String format(double balance);
* @return true if success (Payer had enough cash, receiver was able to
* receive the funds)
*/
@Deprecated
public boolean transfer(String from, String to, double amount);
/** /**
* Fetches the balance of the given account name * Fetches the balance of the given account name
* *
* @param name * @param name
* The name of the account * The name of the account
* @return Their current balance. * @return Their current balance.
*/ */
@Deprecated @Deprecated
public double getBalance(String name); public double getBalance(String name);
/** /**
* Formats the given number... E.g. 50.5 becomes $50.5 Dollars, or 50 * Fetches the balance of the given account name
* Dollars 5 Cents *
* * @param name
* @param balance * The name of the account
* The given number * @return Their current balance.
* @return The balance in human readable text. */
*/ public double getBalance(UUID name);
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 * Checks that this economy is valid. Returns false if it is not valid.
* thin air. *
* * @return True if this economy will work, false if it will not.
* @param name */
* The exact (case insensitive) username to take money from public boolean isValid();
* @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
* *
* @param from * @param from
* The player who is paying money * The player who is paying money
* @param to * @param to
* The player who is receiving money * The player who is receiving money
* @param amount * @param amount
* The amount to transfer * The amount to transfer
* @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)
*/ */
public boolean transfer(UUID from, UUID to, double amount); @Deprecated
public boolean transfer(String from, String to, double amount);
/** /**
* Fetches the balance of the given account name * Transfers the given amount of money from Player1 to Player2
* *
* @param name * @param from
* The name of the account * The player who is paying money
* @return Their current balance. * @param to
*/ * The player who is receiving money
public double getBalance(UUID name); * @param amount
* The amount to transfer
* @return true if success (Payer had enough cash, receiver was able to
* receive the funds)
*/
public boolean transfer(UUID from, UUID to, 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
*/
@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);
} }

View File

@ -9,100 +9,108 @@ import org.bukkit.plugin.RegisteredServiceProvider;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
public class Economy_Vault implements EconomyCore { public class Economy_Vault implements EconomyCore {
private Economy vault; private Economy vault;
public Economy_Vault() { public Economy_Vault() {
setupEconomy(); setupEconomy();
} }
@Override @Override
@Deprecated public String currencyNamePlural() {
public boolean deposit(final String name, final double amount) { return this.vault.currencyNamePlural();
return this.vault.depositPlayer(name, amount).transactionSuccess(); }
}
@Override @Override
public boolean deposit(final UUID name, final double amount) { @Deprecated
final OfflinePlayer p = Bukkit.getOfflinePlayer(name); public boolean deposit(final String name, final double amount) {
return this.vault.depositPlayer(p, amount).transactionSuccess(); return this.vault.depositPlayer(name, amount).transactionSuccess();
} }
@Override @Override
public String format(final double balance) { public boolean deposit(final UUID name, final double amount) {
try { final OfflinePlayer p = Bukkit.getOfflinePlayer(name);
return this.vault.format(balance); return this.vault.depositPlayer(p, amount).transactionSuccess();
} catch (final NumberFormatException e) { }
}
return "" + balance;
}
@Override @Override
@Deprecated public String format(final double balance) {
public double getBalance(final String name) { try {
return this.vault.getBalance(name); return this.vault.format(balance);
} } catch (final NumberFormatException ignored) {
}
return "" + balance;
}
@Override @Override
public double getBalance(final UUID name) { @Deprecated
final OfflinePlayer p = Bukkit.getOfflinePlayer(name); public double getBalance(final String name) {
return this.vault.getBalance(p); return this.vault.getBalance(name);
} }
@Override @Override
public boolean isValid() { public double getBalance(final UUID name) {
return this.vault != null; final OfflinePlayer p = Bukkit.getOfflinePlayer(name);
} return this.vault.getBalance(p);
}
@Override @Override
@Deprecated public boolean isValid() {
public boolean transfer(final String from, final String to, final double amount) { return this.vault != null;
if (this.vault.getBalance(from) >= amount) { }
if (this.vault.withdrawPlayer(from, amount).transactionSuccess()) {
if (!this.vault.depositPlayer(to, amount).transactionSuccess()) {
this.vault.depositPlayer(from, amount);
return false;
}
return true;
}
return false;
}
return false;
}
@Override @Override
public boolean transfer(final UUID from, final UUID to, final double amount) { @Deprecated
final OfflinePlayer pFrom = Bukkit.getOfflinePlayer(from); public boolean transfer(final String from, final String to, final double amount) {
final OfflinePlayer pTo = Bukkit.getOfflinePlayer(to); if (this.vault.getBalance(from) >= amount) {
if (this.vault.getBalance(pFrom) >= amount) { if (this.vault.withdrawPlayer(from, amount).transactionSuccess()) {
if (this.vault.withdrawPlayer(pFrom, amount).transactionSuccess()) { if (!this.vault.depositPlayer(to, amount).transactionSuccess()) {
if (!this.vault.depositPlayer(pTo, amount).transactionSuccess()) { this.vault.depositPlayer(from, amount);
this.vault.depositPlayer(pFrom, amount); return false;
return false; }
} return true;
return true; }
} return false;
return false; }
} return false;
return false; }
}
@Override @Override
@Deprecated public boolean transfer(final UUID from, final UUID to, final double amount) {
public boolean withdraw(final String name, final double amount) { final OfflinePlayer pFrom = Bukkit.getOfflinePlayer(from);
return this.vault.withdrawPlayer(name, amount).transactionSuccess(); final OfflinePlayer pTo = Bukkit.getOfflinePlayer(to);
} if (this.vault.getBalance(pFrom) >= amount) {
if (this.vault.withdrawPlayer(pFrom, amount).transactionSuccess()) {
if (!this.vault.depositPlayer(pTo, amount).transactionSuccess()) {
this.vault.depositPlayer(pFrom, amount);
return false;
}
return true;
}
return false;
}
return false;
}
@Override @Override
public boolean withdraw(final UUID name, final double amount) { @Deprecated
final OfflinePlayer p = Bukkit.getOfflinePlayer(name); public boolean withdraw(final String name, final double amount) {
return this.vault.withdrawPlayer(p, amount).transactionSuccess(); return this.vault.withdrawPlayer(name, amount).transactionSuccess();
} }
private boolean setupEconomy() { @Override
final RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServicesManager().getRegistration(Economy.class); public boolean withdraw(final UUID name, final double amount) {
if (economyProvider != null) { final OfflinePlayer p = Bukkit.getOfflinePlayer(name);
this.vault = (economyProvider.getProvider()); return this.vault.withdrawPlayer(p, amount).transactionSuccess();
} }
return this.vault != null;
} private boolean setupEconomy() {
try {
final RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServicesManager().getRegistration(Economy.class);
if (economyProvider != null) {
vault = (economyProvider.getProvider());
}
} catch (final Exception ignored) {
}
return vault != null;
}
} }

View File

@ -22,102 +22,104 @@ 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;
public BlockListener(final QuickShop plugin) { public BlockListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
/** /**
* Removes chests when they're destroyed. * Removes chests when they're destroyed.
*/ */
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBreak(final BlockBreakEvent e) { public void onBreak(final BlockBreakEvent e) {
final Block b = e.getBlock(); final Block b = e.getBlock();
final Player p = e.getPlayer(); final Player p = e.getPlayer();
// 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
} final ItemStack pinh = p.getItemInHand();
// If they're either survival or the owner, they can break it if (p.getName().equals(shop.getOwner()) || p.getGameMode() == GameMode.SURVIVAL || pinh == null || pinh.getType() == plugin.getConfigManager().getSuperItem()) {
final ItemStack pinh = p.getItemInHand(); // Cancel their current menu... Doesnt cancel other's menu's.
if (p.getName().equals(shop.getOwner()) || p.getGameMode() == GameMode.SURVIVAL || pinh == null || pinh.getType() == plugin.getConfigManager().getSuperItem()) { final Info action = plugin.getShopManager().getActions().get(p.getName());
// Cancel their current menu... Doesnt cancel other's menu's. if (action != null) {
final Info action = plugin.getShopManager().getActions().get(p.getName()); action.setAction(ShopAction.CANCELLED);
if (action != null) { }
action.setAction(ShopAction.CANCELLED); shop.delete();
} p.sendMessage(MsgUtil.p("success-removed-shop"));
shop.delete(); } else {
p.sendMessage(MsgUtil.p("success-removed-shop")); e.setCancelled(true);
} else { p.sendMessage(MsgUtil.p("no-creative-break"));
e.setCancelled(true); }
p.sendMessage(MsgUtil.p("no-creative-break")); } else if (b.getType() == Material.WALL_SIGN) {
return; final Shop shop = getShopNextTo(b.getLocation());
} if (shop == null) { return; }
} else if (b.getType() == Material.WALL_SIGN) { e.setCancelled(true);
final Shop shop = getShopNextTo(b.getLocation()); }
if (shop == null) { }
return;
} else {
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++) {
} Block b = e.blockList().get(i);
for (int i = 0; i < e.blockList().size(); i++) { if (b.getType() == Material.WALL_SIGN) {
final Block b = e.blockList().get(i); b = Util.getAttached(b);
final Shop shop = plugin.getShopManager().getShop(b.getLocation()); }
if (shop != null) { if (b != null) {
shop.delete(); final Shop shop = plugin.getShopManager().getShop(b.getLocation());
} if (shop != null) {
} 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 Block b = e.getBlock();
final BlockState bs = e.getBlock().getState(); final Player p = e.getPlayer();
if (bs instanceof DoubleChest == false) { final Block chest = Util.getSecondHalf(b);
return; if (chest != null) {
} Shop shop = plugin.getShopManager().getShop(chest.getLocation());
final Block b = e.getBlock(); if (shop != null) {
final Player p = e.getPlayer(); if (!p.getName().equals(shop.getOwner())) {
final Block chest = Util.getSecondHalf(b); e.setCancelled(true);
if (chest != null && plugin.getShopManager().getShop(chest.getLocation()) != null && !p.hasPermission("quickshop.create.double")) { p.sendMessage(MsgUtil.p("no-double-chests"));
e.setCancelled(true); return;
p.sendMessage(MsgUtil.p("no-double-chests")); }
} if (!p.hasPermission("quickshop.create.double")) {
} e.setCancelled(true);
p.sendMessage(MsgUtil.p("no-double-chests"));
}
}
}
}
/** /**
* Gets the shop a sign is attached to * Gets the shop a sign is attached to
* *
* @param loc * @param loc
* The location of the sign * The location of the sign
* @return The shop * @return The shop
*/ */
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());
}
} }

View File

@ -12,18 +12,18 @@ import org.maxgamer.QuickShop.QuickShop;
* *
*/ */
public class ChatListener implements Listener { public class ChatListener implements Listener {
QuickShop plugin; QuickShop plugin;
public ChatListener(final QuickShop plugin) { public ChatListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onChat(final AsyncPlayerChatEvent e) { public void onChat(final AsyncPlayerChatEvent e) {
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()); plugin.getShopManager().handleChat(e.getPlayer(), e.getMessage());
e.setCancelled(true); e.setCancelled(true);
} }
} }

View File

@ -12,34 +12,29 @@ 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;
import pw.yumc.YumCore.bukkit.P;
public class ChunkListener implements Listener { public class ChunkListener implements Listener {
private QuickShop plugin; private QuickShop plugin = P.getPlugin();
public ChunkListener(QuickShop plugin) { @EventHandler(priority = EventPriority.HIGHEST)
this.plugin = plugin; public void onChunkLoad(ChunkLoadEvent e) {
} Chunk c = e.getChunk();
if (plugin.getShopManager().getShops() == null) return;
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
if (inChunk == null) return;
for (Shop shop : inChunk.values()) {
shop.onLoad();
}
}
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onChunkLoad(ChunkLoadEvent e) { public void onChunkUnload(ChunkUnloadEvent e) {
Chunk c = e.getChunk(); Chunk c = e.getChunk();
if (plugin.getShopManager().getShops() == null) HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
return; if (inChunk == null) return;
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c); for (Shop shop : inChunk.values()) {
if (inChunk == null) shop.onUnload();
return; }
for (Shop shop : inChunk.values()) { }
shop.onLoad();
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onChunkUnload(ChunkUnloadEvent e) {
Chunk c = e.getChunk();
HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(c);
if (inChunk == null)
return;
for (Shop shop : inChunk.values()) {
shop.onUnload();
}
}
} }

View File

@ -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;
@ -17,135 +20,136 @@ import org.maxgamer.QuickShop.Util.MsgUtil;
import org.maxgamer.QuickShop.Util.Util; import org.maxgamer.QuickShop.Util.Util;
public class LockListener implements Listener { public class LockListener implements Listener {
private final QuickShop plugin; private final QuickShop plugin;
public LockListener(final QuickShop plugin) { public LockListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
/** /**
* Removes chests when they're destroyed. * Removes chests when they're destroyed.
*/ */
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBreak(final BlockBreakEvent e) { public void onBreak(final BlockBreakEvent e) {
Block b = e.getBlock(); Block b = e.getBlock();
final Player p = e.getPlayer(); final Player p = e.getPlayer();
// 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) {
} b = Util.getAttached(b);
} else if (b.getType() == Material.WALL_SIGN) { if (b == null) { return; }
b = Util.getAttached(b); final Shop shop = plugin.getShopManager().getShop(b.getLocation());
if (b == null) { if (shop == null) { return; }
return; e.setCancelled(true);
} }
final Shop shop = plugin.getShopManager().getShop(b.getLocation()); }
if (shop == null) {
return;
} else {
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)) { return; // Interacted with air
if (!Util.canBeShop(b)) { }
return; // Interacted with air Shop shop = plugin.getShopManager().getShop(b.getLocation());
} // Make sure they're not using the non-shop half of a double chest.
Shop shop = plugin.getShopManager().getShop(b.getLocation()); if (!hasSecondHalf(shop, b)) { return; }
// Make sure they're not using the non-shop half of a double chest. if (shop != null && !p.getName().equals(shop.getOwner())) {
if (shop == null) { if (p.hasPermission("quickshop.other.open")) {
b = Util.getSecondHalf(b); p.sendMessage(MsgUtil.p("bypassing-lock"));
if (b == null) { return;
return; }
} p.sendMessage(MsgUtil.p("that-is-locked"));
shop = plugin.getShopManager().getShop(b.getLocation()); e.setCancelled(true);
if (shop == null) { }
return; }
}
}
if (!shop.getOwner().equals(p.getName())) {
if (p.hasPermission("quickshop.other.open")) {
p.sendMessage(MsgUtil.p("bypassing-lock"));
return;
}
p.sendMessage(MsgUtil.p("that-is-locked"));
e.setCancelled(true);
return;
}
}
/** public boolean hasSecondHalf(Shop shop, Block b) {
* Handles shops breaking through explosions if (shop == null) {
*/ b = Util.getSecondHalf(b);
@EventHandler(priority = EventPriority.LOW) if (b == null) { return false; }
public void onExplode(final EntityExplodeEvent e) { shop = plugin.getShopManager().getShop(b.getLocation());
if (e.isCancelled()) { if (shop == null) { return false; }
return; }
} return true;
for (int i = 0; i < e.blockList().size(); i++) { }
final Block b = e.blockList().get(i);
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 shops breaking through explosions
*/ */
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onPlace(final BlockPlaceEvent e) { public void onExplode(final EntityExplodeEvent e) {
final Block b = e.getBlock(); if (e.isCancelled()) { return; }
try { List<Block> removed = new ArrayList<>();
if (b.getType() != Material.HOPPER) { for (int i = 0; i < e.blockList().size(); i++) {
return; Block b = e.blockList().get(i);
} Shop shop = plugin.getShopManager().getShop(b.getLocation());
} catch (final NoSuchFieldError er) { if (shop != null) {
return; // Your server doesn't have hoppers removed.add(b);
} } else if (b.getType() == Material.WALL_SIGN) {
Block c = e.getBlockAgainst(); Block s = Util.getAttached(b);
if (Util.canBeShop(c) == false) { if (s != null) {
return; shop = plugin.getShopManager().getShop(s.getLocation());
} if (shop != null) {
final Player p = e.getPlayer(); removed.add(b);
Shop shop = plugin.getShopManager().getShop(c.getLocation()); }
if (shop == null) { }
c = Util.getSecondHalf(c); }
if (c == null) { }
return; // You didn't place a hopper on a shop. Meh. e.blockList().removeAll(removed);
} else { // for (int i = 0; i < e.blockList().size(); i++) {
shop = plugin.getShopManager().getShop(c.getLocation()); // Block b = e.blockList().get(i);
} // if (b.getType() == Material.WALL_SIGN) {
if (shop == null) { // Block s = Util.getAttached(b);
return; // if (s != null) {
} // final Shop shop = plugin.getShopManager().getShop(s.getLocation());
} // if (shop != null) {
if (p.getName().equals(shop.getOwner()) == false) { // // ToDo: Shouldn't I be decrementing 1 here? Concurrency and all..
if (p.hasPermission("quickshop.other.open")) { // e.blockList().remove(b);
p.sendMessage(MsgUtil.p("bypassing-lock")); // e.blockList().remove(s);
return; // }
} // }
p.sendMessage(MsgUtil.p("that-is-locked")); // }
e.setCancelled(true); // final Shop shop = plugin.getShopManager().getShop(b.getLocation());
return; // if (shop != null) {
} // // ToDo: Shouldn't I be decrementing 1 here? Concurrency and all..
} // e.blockList().remove(b);
// }
// }
}
/**
* Handles hopper placement
*/
@EventHandler(priority = EventPriority.LOW)
public void onPlace(final BlockPlaceEvent e) {
final Block b = e.getBlock();
try {
if (b.getType() != Material.HOPPER) { return; }
} catch (final NoSuchFieldError er) {
return; // Your server doesn't have hoppers
}
Block c = e.getBlockAgainst();
if (!Util.canBeShop(c)) { return; }
final Player p = e.getPlayer();
Shop shop = plugin.getShopManager().getShop(c.getLocation());
if (!hasSecondHalf(shop, b)) { return; }
if (!p.getName().equals(shop.getOwner())) {
if (p.hasPermission("quickshop.other.open")) {
p.sendMessage(MsgUtil.p("bypassing-lock"));
return;
}
p.sendMessage(MsgUtil.p("that-is-locked"));
e.setCancelled(true);
}
}
} }

View File

@ -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;
@ -28,166 +28,159 @@ import org.maxgamer.QuickShop.Util.MsgUtil;
import org.maxgamer.QuickShop.Util.Util; import org.maxgamer.QuickShop.Util.Util;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
private final QuickShop plugin; private final QuickShop plugin;
public PlayerListener(final QuickShop plugin) { public PlayerListener(final QuickShop plugin) {
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, ignoreCancelled = true)
@EventHandler(priority = EventPriority.MONITOR) 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 || p.getGameMode() == GameMode.CREATIVE) { return; }
if (e.getAction() != Action.LEFT_CLICK_BLOCK || (e.getMaterial() == plugin.getConfigManager().getSuperItem() && b.getType() == Material.WALL_SIGN)) { final Location loc = b.getLocation();
return; final ItemStack item = e.getItem();
} // Get the shop
final Location loc = b.getLocation(); Shop shop = plugin.getShopManager().getShop(loc);
final ItemStack item = e.getItem(); // If that wasn't a shop, search nearby shops
// Get the shop if (shop == null && b.getType() == Material.WALL_SIGN) {
Shop shop = plugin.getShopManager().getShop(loc); final Block attached = Util.getAttached(b);
// If that wasn't a shop, search nearby shops if (attached != null) {
if (shop == null && b.getType() == Material.WALL_SIGN) { shop = plugin.getShopManager().getShop(attached.getLocation());
final Block attached = Util.getAttached(b); }
if (attached != null) { }
shop = plugin.getShopManager().getShop(attached.getLocation()); // Purchase handling
} if (shop != null && p.hasPermission("quickshop.use") && (plugin.getConfigManager().isSneakTrade() == p.isSneaking())) {
} shop.onClick();
// Purchase handling // Text menu
if (shop != null && p.hasPermission("quickshop.use") && (plugin.getConfigManager().isSneakTrade() == p.isSneaking())) { MsgUtil.sendShopInfo(p, shop);
shop.onClick(); if (!plugin.getConfigManager().isEnableMagicLib() && b.getType() == Material.WALL_SIGN) {
// Text menu final Inventory in = Bukkit.createInventory(null, 9, plugin.getConfigManager().getGuiTitle());
MsgUtil.sendShopInfo(p, shop); in.setItem(4, shop.getItem());
if (shop.isSelling()) { p.openInventory(in);
p.sendMessage(MsgUtil.p("how-many-buy")); }
} else { // Add the new action
final int items = Util.countItems(p.getInventory(), shop.getItem()); final HashMap<String, Info> actions = plugin.getShopManager().getActions();
p.sendMessage(MsgUtil.p("how-many-sell", items)); final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop);
} actions.put(p.getName(), info);
// Add the new action }
final HashMap<String, Info> actions = plugin.getShopManager().getActions(); // Handles creating shops
final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop); else if (shop == null && item != null && item.getType() != Material.AIR && p.hasPermission("quickshop.create.sell") && Util.canBeShop(b) && p.getGameMode() != GameMode.CREATIVE
actions.put(p.getName(), info); && (plugin.getConfigManager().isSneakCreate() == p.isSneaking())) {
return; if (!plugin.getShopManager().canBuildShop(p, b, e.getBlockFace())) {
} // As of the new checking system, most plugins will tell the
// Handles creating shops // player why they can't create a shop there.
else if (shop == null && item != null && item.getType() != Material.AIR && p.hasPermission("quickshop.create.sell") && Util.canBeShop(b) && p.getGameMode() != GameMode.CREATIVE // So telling them a message would cause spam etc.
&& (plugin.getConfigManager().isSneakCreate() == p.isSneaking())) { return;
if (!plugin.getShopManager().canBuildShop(p, b, e.getBlockFace())) { }
// As of the new checking system, most plugins will tell the if (Util.getSecondHalf(b) != null && !p.hasPermission("quickshop.create.double")) {
// player why they can't create a shop there. p.sendMessage(MsgUtil.p("no-double-chests"));
// So telling them a message would cause spam etc. return;
return; }
} if (Util.isBlacklisted(item.getType()) && !p.hasPermission("quickshop.bypass." + item.getTypeId())) {
if (Util.getSecondHalf(b) != null && !p.hasPermission("quickshop.create.double")) { p.sendMessage(MsgUtil.p("blacklisted-item"));
p.sendMessage(MsgUtil.p("no-double-chests")); return;
return; }
} // Finds out where the sign should be placed for the shop
if (Util.isBlacklisted(item.getType()) && !p.hasPermission("quickshop.bypass." + item.getTypeId())) { Block last = null;
p.sendMessage(MsgUtil.p("blacklisted-item")); final Location from = p.getLocation().clone();
return; from.setY(b.getY());
} from.setPitch(0);
// Finds out where the sign should be placed for the shop final BlockIterator bIt = new BlockIterator(from, 0, 7);
Block last = null; while (bIt.hasNext()) {
final Location from = p.getLocation().clone(); final Block n = bIt.next();
from.setY(b.getY()); if (n.equals(b)) {
from.setPitch(0); break;
final BlockIterator bIt = new BlockIterator(from, 0, 7); }
while (bIt.hasNext()) { last = n;
final Block n = bIt.next(); }
if (n.equals(b)) { // Send creation menu.
break; final Info info = new Info(b.getLocation(), ShopAction.CREATE, e.getItem(), last);
} plugin.getShopManager().getActions().put(p.getName(), info);
last = n; p.sendMessage(MsgUtil.p("how-much-to-trade-for", Util.getName(info.getItem())));
} }
// Send creation menu. }
final Info info = new Info(b.getLocation(), ShopAction.CREATE, e.getItem(), last);
plugin.getShopManager().getActions().put(p.getName(), info);
p.sendMessage(MsgUtil.p("how-much-to-trade-for", Util.getName(info.getItem())));
}
}
@EventHandler @EventHandler
public void onJoin(final PlayerJoinEvent e) { public void onJoin(final PlayerJoinEvent e) {
// Notify the player any messages they were sent // Notify the player any messages they were sent
Bukkit.getScheduler().runTaskLater(QuickShop.instance, new Runnable() { Bukkit.getScheduler().runTaskLater(QuickShop.instance, new Runnable() {
@Override @Override
public void run() { public void run() {
MsgUtil.flush(e.getPlayer()); MsgUtil.flush(e.getPlayer());
} }
}, 60); }, 60);
} }
/** /**
* Waits for a player to move too far from a shop, then cancels the menu. * Waits for a player to move too far from a shop, then cancels the menu.
*/ */
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onMove(final PlayerMoveEvent e) { public void onMove(final PlayerMoveEvent e) {
final Info info = plugin.getShopManager().getActions().get(e.getPlayer().getName()); final Info info = plugin.getShopManager().getActions().get(e.getPlayer().getName());
if (info != null) { if (info != null) {
final Player p = e.getPlayer(); final Player p = e.getPlayer();
final Location loc1 = info.getLocation(); final Location loc1 = info.getLocation();
final Location loc2 = p.getLocation(); final Location loc2 = p.getLocation();
if (loc1.getWorld() != loc2.getWorld() || loc1.distanceSquared(loc2) > 25) { if (loc1.getWorld() != loc2.getWorld() || loc1.distanceSquared(loc2) > 25) {
if (info.getAction() == ShopAction.CREATE) { if (info.getAction() == ShopAction.CREATE) {
p.sendMessage(MsgUtil.p("shop-creation-cancelled")); p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
} else if (info.getAction() == ShopAction.BUY) { } else if (info.getAction() == ShopAction.BUY) {
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; }
} }
} }
}
@EventHandler @EventHandler
public void onPlayerQuit(final PlayerQuitEvent e) { public void onPlayerQuit(final PlayerQuitEvent e) {
// Remove them from the menu // Remove them from the menu
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();
} if (b == null || b.getType() == null) { return; }
final Block b = e.getClickedBlock(); // 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);
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { final Location loc = shop.getLocation();
if (p.hasPermission("quickshop.unlimited")) { String shopmode = "";
shop.setUnlimited(!shop.isUnlimited()); if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
p.sendMessage(MsgUtil.p("command.toggle-unlimited", (shop.isUnlimited() ? "§e无限模式" : "§c有限模式"))); if (p.hasPermission("quickshop.unlimited") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
return; shop.setUnlimited(!shop.isUnlimited());
} shopmode = shop.isUnlimited() ? "§e无限模式" : "§c有限模式";
} else { p.sendMessage(MsgUtil.p("command.toggle-unlimited", shopmode));
if (shop.getShopType() == ShopType.BUYING && p.hasPermission("quickshop.create.sell")) { }
shop.setShopType(ShopType.SELLING); } else {
p.sendMessage(MsgUtil.p("command.now-selling", shop.getDataName())); if (shop.getShopType() == ShopType.BUYING && p.hasPermission("quickshop.create.sell") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
return; shop.setShopType(ShopType.SELLING);
} else if (shop.getShopType() == ShopType.SELLING && p.hasPermission("quickshop.create.buy")) { p.sendMessage(MsgUtil.p("command.now-selling", shop.getDataName()));
shop.setShopType(ShopType.BUYING); shopmode = "出售模式";
p.sendMessage(MsgUtil.p("command.now-buying", shop.getDataName())); } else if (shop.getShopType() == ShopType.SELLING && p.hasPermission("quickshop.create.buy") && (shop.getOwner().equalsIgnoreCase(p.getName()) || p.isOp())) {
return; shop.setShopType(ShopType.BUYING);
} p.sendMessage(MsgUtil.p("command.now-buying", shop.getDataName()));
} shopmode = "收购模式";
shop.setSignText(); }
shop.update(); }
} 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();
@EventHandler(ignoreCancelled = true) shop.update();
public void onTeleport(final PlayerTeleportEvent e) { }
final PlayerMoveEvent me = new PlayerMoveEvent(e.getPlayer(), e.getFrom(), e.getTo()); }
onMove(me); }
}
} }

View File

@ -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,93 +15,147 @@ 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 {
private final QuickShop plugin; private final QuickShop plugin;
public ProtectListener(final QuickShop plugin) { public ProtectListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler public Shop getShop(final Inventory inv) {
public void onInvMove(final InventoryMoveItemEvent e) { if (inv == null) {
final ItemStack ci = e.getItem(); return null;
if (MarkUtil.hasMark(ci)) { }
e.setCancelled(true); InventoryHolder holder = inv.getHolder();
final ItemStack[] items = e.getSource().getContents(); if (holder instanceof DoubleChest) {
for (final ItemStack itemStack : items) { holder = ((DoubleChest) holder).getLeftSide();
if (MarkUtil.hasMark(itemStack)) { }
itemStack.setType(Material.AIR);
}
}
e.getSource().setContents(items);
}
}
@EventHandler if (holder instanceof BlockState) {
public void onInvPickup(final InventoryPickupItemEvent e) { final Block block = ((BlockState) holder).getBlock();
if (!plugin.getConfigManager().isPreventHopper()) { final Shop sp = plugin.getShopManager().getShop(block.getLocation());
return; if (sp != null) {
} return sp;
final ItemStack ci = e.getItem().getItemStack(); }
if (MarkUtil.hasMark(ci)) { }
e.setCancelled(true); return null;
} }
}
@EventHandler @EventHandler
public void onItemClick(final InventoryClickEvent e) { public void onInvMove(final InventoryMoveItemEvent e) {
final Player p = (Player) e.getWhoClicked(); final ItemStack ci = e.getItem();
final ItemStack ci = e.getCurrentItem(); if (MarkUtil.hasMark(ci)) {
final Inventory inv = e.getInventory(); e.setCancelled(true);
final int solt = e.getSlot(); }
if (inv.getType() != InventoryType.PLAYER && inv.getType() != InventoryType.HOPPER) { final Inventory src = e.getSource();
if (inv.getTitle().equalsIgnoreCase(plugin.getConfigManager().getGuiTitle())) { final Inventory me = e.getInitiator();
e.setCancelled(true); final Inventory des = e.getDestination();
p.closeInventory(); final Shop srcshop = getShop(src);
} final Shop meshop = getShop(me);
return; final Shop desshop = getShop(des);
} if (srcshop != null && meshop == null || meshop != null && desshop == null || srcshop != null && srcshop.getOwner() != null && !srcshop.getOwner().equalsIgnoreCase(desshop.getOwner())) {
try { e.setCancelled(true);
if (MarkUtil.hasMark(ci)) { }
inv.setItem(solt, new ItemStack(Material.AIR)); }
Bukkit.broadcastMessage("§6[§b快捷商店§6] §4警告 " + p.getDisplayName() + " §c非法 §d§l获取 " + ci.getItemMeta().getDisplayName() + " §a已清理...");
p.closeInventory();
}
} catch (final Exception ex) {
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler
public void onItemDespawn(final ItemDespawnEvent e) { public void onInvPickup(final InventoryPickupItemEvent e) {
final ItemStack ci = e.getEntity().getItemStack(); if (!plugin.getConfigManager().isPreventHopper()) {
if (MarkUtil.hasMark(ci)) { return;
e.setCancelled(true); }
} final ItemStack ci = e.getItem().getItemStack();
} if (MarkUtil.hasMark(ci)) {
e.setCancelled(true);
}
}
@EventHandler @EventHandler
public void onPlayerHandlerItem(final PlayerItemHeldEvent e) { public void onItemClick(final InventoryClickEvent e) {
final Player p = e.getPlayer(); final Player p = (Player) e.getWhoClicked();
final ItemStack[] cis = p.getInventory().getArmorContents(); final ItemStack ci = e.getCurrentItem();
for (final ItemStack itemStack : cis) { final Inventory inv = e.getInventory();
if (MarkUtil.hasMark(itemStack)) { final int solt = e.getSlot();
Bukkit.broadcastMessage("§6[§b快捷商店§6] §4警告 " + p.getDisplayName() + " §c非法 §e§l穿戴 " + itemStack.getItemMeta().getDisplayName() + " §a已清理..."); if (inv.getType() != InventoryType.PLAYER && inv.getType() != InventoryType.HOPPER) {
itemStack.setType(Material.AIR); if (inv.getTitle() != null && inv.getTitle().equalsIgnoreCase(plugin.getConfigManager().getGuiTitle())) {
} e.setCancelled(true);
} p.closeInventory();
p.getInventory().setArmorContents(cis); }
} return;
}
try {
if (MarkUtil.hasMark(ci)) {
inv.setItem(solt, new ItemStack(Material.AIR));
sendWarning(p, ci, "§d§l获取");
p.closeInventory();
}
} catch (final Exception ignored) {
}
}
@EventHandler @EventHandler
public void onPlayerPickup(final PlayerPickupItemEvent e) { public void onPlayerHandlerItem(final PlayerItemHeldEvent e) {
final ItemStack ci = e.getItem().getItemStack(); Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
if (MarkUtil.hasMark(ci)) { @Override
e.setCancelled(true); public void run() {
} final Player p = e.getPlayer();
} final PlayerInventory inv = p.getInventory();
final ItemStack[] cis = inv.getArmorContents();
for (int i = 0; i < cis.length; i++) {
final ItemStack itemStack = cis[i];
if (MarkUtil.hasMark(itemStack)) {
cis[i] = new ItemStack(Material.AIR);
sendWarning(p, itemStack, "§e§l穿戴");
}
}
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
public void onPlayerPickup(final PlayerPickupItemEvent e) {
final ItemStack ci = e.getItem().getItemStack();
if (MarkUtil.hasMark(ci)) {
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);
}
} }

View File

@ -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,71 +11,72 @@ 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;
public WorldListener(final QuickShop plugin) { public WorldListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler @EventHandler
public void onWorldLoad(final WorldLoadEvent e) { public void onWorldLoad(final WorldLoadEvent e) {
/* /*
* ************************************* * *************************************
* This listener fixes any broken world references. Such as hashmap * This listener fixes any broken world references. Such as hashmap
* lookups will fail, because the World reference is different, but the * lookups will fail, because the World reference is different, but the
* world value is the same. * world value is the same.
* ************************************* * *************************************
*/ */
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()) {
} final HashMap<Location, Shop> inChunk = new HashMap<>(1);
for (final Entry<ShopChunk, HashMap<Location, Shop>> oldInChunk : oldInWorld.entrySet()) { // Put the new chunk were the old chunk was
final HashMap<Location, Shop> inChunk = new HashMap<Location, Shop>(1); inWorld.put(oldInChunk.getKey(), inChunk);
// Put the new chunk were the old chunk was for (final Entry<Location, Shop> entry : oldInChunk.getValue().entrySet()) {
inWorld.put(oldInChunk.getKey(), inChunk); final Shop shop = entry.getValue();
for (final Entry<Location, Shop> entry : oldInChunk.getValue().entrySet()) { shop.getLocation().setWorld(world);
final Shop shop = entry.getValue(); inChunk.put(shop.getLocation(), shop);
shop.getLocation().setWorld(world); }
inChunk.put(shop.getLocation(), shop); }
} // Done - Now we can store the new world dataz!
} plugin.getShopManager().getShops().put(world.getName(), inWorld);
// Done - Now we can store the new world dataz! // This is a workaround, because I don't get parsed chunk events when a
plugin.getShopManager().getShops().put(world.getName(), inWorld); // world first loads....
// This is a workaround, because I don't get parsed chunk events when a // So manually tell all of these shops they're loaded.
// world first loads.... for (final Chunk chunk : world.getLoadedChunks()) {
// So manually tell all of these shops they're loaded. final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(chunk);
for (final Chunk chunk : world.getLoadedChunks()) { if (inChunk == null) {
final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(chunk); continue;
if (inChunk == null) { }
continue; for (final Shop shop : inChunk.values()) {
} shop.onLoad();
for (final Shop shop : inChunk.values()) { }
shop.onLoad(); }
} }
}
}
@EventHandler @EventHandler
public void onWorldUnload(final WorldUnloadEvent e) { public void onWorldUnload(final WorldUnloadEvent e) {
// This is a workaround, because I don't get parsed chunk events when a // This is a workaround, because I don't get parsed chunk events when a
// world unloads, I think... // world unloads, I think...
// So manually tell all of these shops they're unloaded. // So manually tell all of these shops they're unloaded.
for (final Chunk chunk : e.getWorld().getLoadedChunks()) { for (final Chunk chunk : e.getWorld().getLoadedChunks()) {
final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(chunk); final HashMap<Location, Shop> inChunk = plugin.getShopManager().getShops(chunk);
if (inChunk == null) { if (inChunk == null) {
continue; continue;
} }
for (final Shop shop : inChunk.values()) { for (final Shop shop : inChunk.values()) {
shop.onUnload(); shop.onUnload();
} }
} }
} }
} }

View File

@ -0,0 +1,37 @@
package org.maxgamer.QuickShop.Listeners;
import io.github.Cnly.WowSuchCleaner.WowSuchCleaner.ItemPreCleanEvent;
import org.bukkit.entity.Item;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.maxgamer.QuickShop.Util.MarkUtil;
import java.util.ArrayList;
import java.util.List;
public class WowSuchCleanerListener implements Listener {
@EventHandler
public void onWSCClear(final ItemPreCleanEvent e) {
final List<Item> clearList = new ArrayList<>();
final List<ItemStack> aucList = new ArrayList<>();
final List<Item> cleanList = e.getItemsToClean();
final List<ItemStack> acList = e.getItemsToAuction();
if (cleanList != null) {
for (final Item item : cleanList) {
if (MarkUtil.hasMark(item.getItemStack())) {
clearList.add(item);
}
}
e.getItemsToClean().removeAll(clearList);
}
if (acList != null) {
for (final ItemStack itemStack : acList) {
if (MarkUtil.hasMark(itemStack)) {
aucList.add(itemStack);
}
}
e.getItemsToAuction().removeAll(aucList);
}
}
}

View File

@ -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;
@ -42,339 +41,304 @@ 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;
import org.maxgamer.QuickShop.Listeners.WorldListener; import org.maxgamer.QuickShop.Listeners.WorldListener;
import org.maxgamer.QuickShop.Listeners.WowSuchCleanerListener;
import org.maxgamer.QuickShop.Shop.ContainerShop; import org.maxgamer.QuickShop.Shop.ContainerShop;
import org.maxgamer.QuickShop.Shop.Shop; import org.maxgamer.QuickShop.Shop.Shop;
import org.maxgamer.QuickShop.Shop.ShopManager; 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); /** The Config Manager used to read config */
// Listeners - We decide which one to use at runtime private ConfigManager configManager;
private ChatListener chatListener; /** The database for storing all our data for persistence */
private final ChunkListener chunkListener = new ChunkListener(this); private Database database;
/** The Config Manager used to read config */ /** The economy we hook into for transactions */
private ConfigManager configManager; private Economy economy;
public BukkitTask itemWatcherTask;
private LogWatcher logWatcher;
/** The Shop Manager used to store shops */
private ShopManager shopManager;
/** The database for storing all our data for persistence */ /**
private Database database; * Prints debug information if QuickShop is configured to do so.
/** The economy we hook into for transactions */ *
private Economy economy; * @param s
private boolean enableMagicLib; * The string to print.
private BukkitTask itemWatcherTask; */
public void debug(final String s) {
if (!configManager.isDebug()) { return; }
this.getLogger().info(ChatColor.YELLOW + "[Debug] " + s);
}
private LogWatcher logWatcher; @Override
private final PlayerListener playerListener = new PlayerListener(this); public FileConfiguration getConfig() {
private final ProtectListener protectListener = new ProtectListener(this); return config;
/** The Shop Manager used to store shops */ }
private ShopManager shopManager;
private final WorldListener worldListener = new WorldListener(this);
/** public ConfigManager getConfigManager() {
* Prints debug information if QuickShop is configured to do so. return configManager;
* }
* @param s
* The string to print.
*/
public void debug(final String s) {
if (!configManager.isDebug()) {
return;
}
this.getLogger().info(ChatColor.YELLOW + "[Debug] " + s);
}
@Override /**
public FileConfiguration getConfig() { * @return Returns the database handler for queries etc.
return config; */
} public Database getDB() {
return this.database;
}
public ConfigManager getConfigManager() { /**
return configManager; * Returns the economy for moving currency around
} *
* @return The economy for moving currency around
*/
public EconomyCore getEcon() {
return economy;
}
/** public int getShopLimit(final Player p) {
* @return Returns the database handler for queries etc. int max = configManager.getLimitdefault();
*/ for (final Entry<String, Integer> entry : configManager.getLimits().entrySet()) {
public Database getDB() { if (entry.getValue() > max && p.hasPermission(entry.getKey())) {
return this.database; max = entry.getValue();
} }
}
return max;
}
/** /**
* Returns the economy for moving currency around * Returns the ShopManager. This is used for fetching, adding and removing
* * shops.
* @return The economy for moving currency around *
*/ * @return The ShopManager.
public EconomyCore getEcon() { */
return economy; public ShopManager getShopManager() {
} return this.shopManager;
}
/** The plugin metrics from Hidendra */ /**
// public Metrics getMetrics(){ return metrics; } * Tries to load the economy and its core. If this fails, it will try to use
public int getShopLimit(final Player p) { * vault. If that fails, it will return false.
int max = configManager.getLimitdefault(); *
for (final Entry<String, Integer> entry : configManager.getLimits().entrySet()) { * @return true if successful, false if the core is invalid or is not found,
if (entry.getValue() > max && p.hasPermission(entry.getKey())) { * and vault cannot be used.
max = entry.getValue(); */
} public boolean loadEcon() {
} final EconomyCore core = new Economy_Vault();
return max; if (!core.isValid()) {
} getLogger().warning("无法找到经济管理类插件...");
getLogger().warning("卸载插件!!!");
this.getPluginLoader().disablePlugin(this);
return false;
}
this.economy = new Economy(core);
return true;
}
/** public void loadShop() {
* Returns the ShopManager. This is used for fetching, adding and removing /* 从数据库载入商店信息到内存 */
* shops. int count = 0; // 商店个数
* int unload = 0;
* @return The ShopManager. Connection con;
*/ try {
public ShopManager getShopManager() { getLogger().info("开始从数据库载入商店数据...");
return this.shopManager; con = database.getConnection();
} final PreparedStatement ps = con.prepareStatement("SELECT * FROM shops");
final ResultSet rs = ps.executeQuery();
int errors = 0;
while (rs.next()) {
int x = 0;
int y = 0;
int z = 0;
String worldName = null;
try {
x = rs.getInt("x");
y = rs.getInt("y");
z = rs.getInt("z");
worldName = rs.getString("world");
final World world = Bukkit.getWorld(worldName);
final ItemStack item = Util.deserialize(rs.getString("itemConfig"));
final String owner = rs.getString("owner");
final double price = rs.getDouble("price");
final Location loc = new Location(world, x, y, z);
/* Skip invalid shops, if we know of any */
if (world != null && loc.getChunk().isLoaded() && !(loc.getBlock().getState() instanceof InventoryHolder)) {
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);
continue;
}
final int type = rs.getInt("type");
final Shop shop = new ContainerShop(loc, price, item, owner);
shop.setUnlimited(rs.getBoolean("unlimited"));
shop.setShopType(ShopType.fromID(type));
shopManager.loadShop(rs.getString("world"), shop);
if (loc.getWorld() != null && loc.getChunk().isLoaded()) {
shop.onLoad();
}
count++;
} catch (final IllegalStateException e) {
unload++;
} catch (final Exception e) {
errors++;
e.printStackTrace();
getLogger().warning("载入商店数据时发生错误! 商店位置: " + worldName + " (" + x + ", " + y + ", " + z + ")...");
if (errors < 3) {
getLogger().warning("删除错误的商店数据...");
database.execute("DELETE FROM shops WHERE x = ? AND y = ? and z = ? and world = ?", x, y, z, worldName);
} else {
getLogger().warning("过多的错误数据 可能您的数据库文件已损坏! 请检查数据库文件!");
e.printStackTrace();
break;
}
}
}
} catch (final SQLException e) {
getLogger().warning("无法载入商店数据...");
getLogger().warning("错误信息: " + e.getMessage());
e.printStackTrace();
}
getLogger().info("已载入 " + count + " 个商店 剩余 " + unload + " 个商店将在区块载入后加载...");
}
public boolean isEnableMagicLib() { /**
return enableMagicLib; * Logs the given string to qs.log, if QuickShop is configured to do so.
} *
* @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
* Tries to load the economy and its core. If this fails, it will try to use public void onDisable() {
* vault. If that fails, it will return false. if (itemWatcherTask != null) {
* itemWatcherTask.cancel();
* @return true if successful, false if the core is invalid or is not found, }
* and vault cannot be used. if (logWatcher != null) {
*/ logWatcher.task.cancel();
public boolean loadEcon() { logWatcher.close(); // Closes the file
final EconomyCore core = new Economy_Vault(); }
if (!core.isValid()) { /* Remove all display items, and any dupes we can find */
// getLogger().severe("Economy is not valid!"); if (shopManager != null) {
getLogger().warning("无法找到经济管理类插件..."); shopManager.clear();
getLogger().warning("卸载插件!!!"); }
this.getPluginLoader().disablePlugin(this); /* Empty the buffer */
// if(econ.equals("Vault")) if (database != null) {
// getLogger().severe("(Does Vault have an Economy to hook into?!)"); database.close();
return false; try {
} else { database.getConnection().close();
this.economy = new Economy(core); } catch (final SQLException ignored) {
return true; }
} }
} if (configManager != null) {
configManager.getWarnings().clear();
}
}
/** @Override
* Logs the given string to qs.log, if QuickShop is configured to do so. public void onEnable() {
* if (!loadEcon()) { return; }
* @param s Util.initialize();
* The string to log. It will be prefixed with the date and time. // Create the shop manager.
*/ shopManager = new ShopManager(this);
public void log(final String s) { configManager = new ConfigManager(this);
if (this.logWatcher == null) { // Initialize Util
return; if (configManager.isLogAction()) {
} // Logger Handler
final Date date = Calendar.getInstance().getTime(); this.logWatcher = new LogWatcher(this, new File(this.getDataFolder(), "qs.log"));
final Timestamp time = new Timestamp(date.getTime()); logWatcher.task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, this.logWatcher, 150, 150);
this.logWatcher.add("[" + time.toString() + "] " + s); }
} 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();
final Plugin wsc = pm.getPlugin("WowSuchCleaner");
if (wsc != null && wsc.isEnabled()) {
getLogger().info("发现 WowSuchCleaner 插件 开启相关功能...");
try {
Class.forName("io.github.Cnly.WowSuchCleaner.WowSuchCleaner.ItemPreCleanEvent");
pm.registerEvents(new WowSuchCleanerListener(), this);
} catch (final ClassNotFoundException e) {
getLogger().info("WowSuchCleaner 版本过低 可能造成悬浮物上架...");
}
}
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();
@Override if (configManager.getFindDistance() > 100) {
public void onDisable() { getLogger().warning("商店查找半径过大 可能导致服务器Lag! 推荐使用低于 100 的配置!");
if (itemWatcherTask != null) { }
itemWatcherTask.cancel(); this.getLogger().info("载入完成! 版本: " + this.getDescription().getVersion() + " 重制 by 喵♂呜");
} new Statistics();
if (logWatcher != null) { new SubscribeTask();
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 @Override
public void onEnable() { public void onLoad() {
instance = this; instance = this;
if (loadEcon() == false) { config = new FileConfig();
return; MsgUtil.init(this);
} L10N.getItemName(new ItemStack(Material.AIR));
// 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 { /** Reloads QuickShops config */
getLogger().info("尝试启动魔改库..."); @Override
final FancyMessage fm = new FancyMessage("test"); public void reloadConfig() {
fm.then("item").itemTooltip(new ItemStack(Material.DIAMOND_SWORD)); config.reload();
fm.then("link").link("ci.citycraft.cn"); L10N.reload();
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;
Connection con;
try {
getLogger().info("从数据库载入商店数据...");
con = database.getConnection();
final PreparedStatement ps = con.prepareStatement("SELECT * FROM shops");
final ResultSet rs = ps.executeQuery();
int errors = 0;
while (rs.next()) {
int x = 0;
int y = 0;
int z = 0;
String worldName = null;
try {
x = rs.getInt("x");
y = rs.getInt("y");
z = rs.getInt("z");
worldName = rs.getString("world");
final World world = Bukkit.getWorld(worldName);
final ItemStack item = Util.deserialize(rs.getString("itemConfig"));
final String owner = rs.getString("owner");
final double price = rs.getDouble("price");
final Location loc = new Location(world, x, y, z);
/* Skip invalid shops, if we know of any */
if (world != null && loc.getChunk().isLoaded() && (loc.getBlock().getState() instanceof InventoryHolder) == false) {
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);
continue;
}
final int type = rs.getInt("type");
final Shop shop = new ContainerShop(loc, price, item, owner);
shop.setUnlimited(rs.getBoolean("unlimited"));
shop.setShopType(ShopType.fromID(type));
shopManager.loadShop(rs.getString("world"), shop);
if (loc.getWorld() != null && loc.getChunk().isLoaded()) {
shop.onLoad();
}
count++;
} catch (final IllegalStateException e) {
unload++;
} catch (final Exception e) {
errors++;
e.printStackTrace();
getLogger().warning("载入商店数据时发生错误! 商店位置: " + worldName + " (" + x + ", " + y + ", " + z + ")...");
if (errors < 3) {
getLogger().warning("删除错误的商店数据...");
database.execute("DELETE FROM shops WHERE x = ? AND y = ? and z = ? and world = ?", x, y, z, worldName);
} else {
getLogger().warning("过多的错误数据 可能您的数据库文件已损坏! 请检查数据库文件!");
e.printStackTrace();
break;
}
}
}
} catch (final SQLException e) {
getLogger().warning("无法载入商店数据...");
getLogger().warning("错误信息: " + e.getMessage());
e.printStackTrace();
}
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
final QuickShopCommands commandExecutor = new QuickShopCommands(this);
getCommand("qs").setExecutor(commandExecutor);
if (configManager.getFindDistance() > 100) {
getLogger().warning("商店查找半径过大 可能导致服务器Lag! 推荐使用低于 100 的配置!");
}
this.getLogger().info("载入完成! 版本: " + this.getDescription().getVersion() + " 重制 by 喵♂呜");
new VersionChecker(this);
try {
final Metrics metrics = new Metrics(this);
metrics.start();
} catch (final IOException e) {
}
}
@Override
public void onLoad() {
config = new FileConfig(this);
ItemConfig.load(this);
MsgUtil.init(this);
}
/** Reloads QuickShops config */
@Override
public void reloadConfig() {
config.reload();
ItemConfig.reload();
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -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) {
}
}
}

View File

@ -5,94 +5,92 @@ import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class Info { public class Info {
private Location loc; private Location loc;
private ShopAction action; private ShopAction action;
private ItemStack item; private ItemStack item;
private Block last; private Block last;
private Shop shop; private Shop shop;
/** /**
* Stores info for the players last shop interact. * Stores info for the players last shop interact.
* *
* @param loc * @param loc
* 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) {
this.loc = loc; this.loc = loc;
this.action = action; this.action = action;
this.last = last; this.last = last;
if (item != null) if (item != null)
this.item = item.clone(); this.item = item.clone();
} }
/** /**
* Stores info for the players last shop interact. * Stores info for the players last shop interact.
* *
* @param loc * @param loc
* 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
*/ */
public Info(Location loc, ShopAction action, ItemStack item, Block last, Shop shop) { public Info(Location loc, ShopAction action, ItemStack item, Block last, Shop shop) {
this.loc = loc; this.loc = loc;
this.action = action; this.action = action;
this.last = last; this.last = last;
if (item != null) if (item != null)
this.item = item.clone(); this.item = item.clone();
if (shop != null) { if (shop != null) {
this.shop = shop.clone(); this.shop = shop.clone();
} }
} }
public boolean hasChanged(Shop shop) { public boolean hasChanged(Shop shop) {
if (this.shop.isUnlimited() != shop.isUnlimited()) if (this.shop.isUnlimited() != shop.isUnlimited())
return true; return true;
if (this.shop.getShopType() != shop.getShopType()) if (this.shop.getShopType() != shop.getShopType())
return true; return true;
if (!this.shop.getOwner().equals(shop.getOwner())) if (!this.shop.getOwner().equals(shop.getOwner()))
return true; return true;
if (this.shop.getPrice() != shop.getPrice()) if (this.shop.getPrice() != shop.getPrice())
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() {
return this.action; return this.action;
} }
public Location getLocation() { public Location getLocation() {
return this.loc; return this.loc;
} }
/* /*
* public Material getMaterial(){ return this.item.getType(); } public byte * public Material getMaterial(){ return this.item.getType(); } public byte
* getData(){ return this.getData(); } * getData(){ return this.getData(); }
*/ */
public ItemStack getItem() { public ItemStack getItem() {
return this.item; return this.item;
} }
public void setAction(ShopAction action) { public void setAction(ShopAction action) {
this.action = action; this.action = action;
} }
public Block getSignBlock() { public Block getSignBlock() {
return this.last; return this.last;
} }
} }

View 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();
}

View File

@ -0,0 +1,207 @@
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 java.util.UUID;
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) {
}
}
};
final PacketAdapter chunkBulkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK_BULK) {
@Override
public void onPacketSending(final PacketEvent event) {
try {
final PacketContainer packet = event.getPacket();
final Player p = event.getPlayer();
final int[] chunksX = packet.getIntegerArrays().read(0);
final int[] chunksZ = packet.getIntegerArrays().read(1);
for (int i = 0; i < chunksX.length; i++) {
final List<FakeItem> fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunksX[i], chunksZ[i])));
sendChunkPacket(p, fakesInChunk);
}
} catch (final Exception ignored) {
}
}
};
ProtocolLibrary.getProtocolManager().addPacketListener(chunkPacketListener);
ProtocolLibrary.getProtocolManager().addPacketListener(chunkBulkPacketListener);
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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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) {
}
}
}

View File

@ -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();
} }

View File

@ -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()
} }

View File

@ -1,44 +1,43 @@
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;
this.hash = this.x * this.z; // We don't need to use the world's hash, this.hash = this.x * this.z; // We don't need to use the world's hash,
// as these are seperated by world in // as these are seperated by world in
// memory // memory
} }
public int getX() { @Override
return this.x; 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 int getZ() { public String getWorld() {
return this.z; return this.world;
} }
public String getWorld() { public int getX() {
return this.world; return this.x;
} }
@Override public int getZ() {
public boolean equals(Object obj) { return this.z;
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;
} }
} }

View File

@ -6,50 +6,50 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
public class ShopCreateEvent extends Event implements Cancellable { public class ShopCreateEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Shop shop; private Shop shop;
private boolean cancelled; private boolean cancelled;
private Player p; private Player p;
public ShopCreateEvent(Shop shop, Player p) { public ShopCreateEvent(Shop shop, Player p) {
this.shop = shop; this.shop = shop;
this.p = p; this.p = p;
} }
/** /**
* The shop to be created * The shop to be created
* *
* @return The shop to be created * @return The shop to be created
*/ */
public Shop getShop() { public Shop getShop() {
return this.shop; return this.shop;
} }
/** /**
* The player who is creating this shop * The player who is creating this shop
* *
* @return The player who is creating this shop * @return The player who is creating this shop
*/ */
public Player getPlayer() { public Player getPlayer() {
return p; return p;
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return this.cancelled; return this.cancelled;
} }
@Override @Override
public void setCancelled(boolean cancel) { public void setCancelled(boolean cancel) {
this.cancelled = cancel; this.cancelled = cancel;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,50 +12,50 @@ import org.bukkit.event.HandlerList;
* much they wish to trade for. * much they wish to trade for.
*/ */
public class ShopPreCreateEvent extends Event implements Cancellable { public class ShopPreCreateEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private boolean cancelled; private boolean cancelled;
private Player p; private Player p;
private Location loc; private Location loc;
public ShopPreCreateEvent(Player p, Location loc) { public ShopPreCreateEvent(Player p, Location loc) {
this.loc = loc; this.loc = loc;
this.p = p; this.p = p;
} }
/** /**
* The location of the shop that will be created. * The location of the shop that will be created.
* *
* @return The location of the shop that will be created. * @return The location of the shop that will be created.
*/ */
public Location getLocation() { public Location getLocation() {
return loc; return loc;
} }
/** /**
* The player who is creating this shop * The player who is creating this shop
* *
* @return The player who is creating this shop * @return The player who is creating this shop
*/ */
public Player getPlayer() { public Player getPlayer() {
return p; return p;
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return this.cancelled; return this.cancelled;
} }
@Override @Override
public void setCancelled(boolean cancel) { public void setCancelled(boolean cancel) {
this.cancelled = cancel; this.cancelled = cancel;
} }
} }

View File

@ -6,71 +6,71 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
public class ShopPurchaseEvent extends Event implements Cancellable { public class ShopPurchaseEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Shop shop; private Shop shop;
private Player p; private Player p;
private int amount; private int amount;
private boolean cancelled; private boolean cancelled;
/** /**
* Builds a new shop purchase event * Builds a new shop purchase event
* *
* @param shop * @param shop
* The shop bought from * The shop bought from
* @param p * @param p
* The player buying * The player buying
* @param amount * @param amount
* The amount they're buying * The amount they're buying
*/ */
public ShopPurchaseEvent(Shop shop, Player p, int amount) { public ShopPurchaseEvent(Shop shop, Player p, int amount) {
this.shop = shop; this.shop = shop;
this.p = p; this.p = p;
this.amount = amount; this.amount = amount;
} }
/** /**
* The shop used in this event * The shop used in this event
* *
* @return The shop used in this event * @return The shop used in this event
*/ */
public Shop getShop() { public Shop getShop() {
return this.shop; return this.shop;
} }
/** /**
* The player trading with the shop * The player trading with the shop
* *
* @return The player trading with the shop * @return The player trading with the shop
*/ */
public Player getPlayer() { public Player getPlayer() {
return this.p; return this.p;
} }
/** /**
* The amount the purchase was for * The amount the purchase was for
* *
* @return The amount the purchase was for * @return The amount the purchase was for
*/ */
public int getAmount() { public int getAmount() {
return this.amount; return this.amount;
} }
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return this.cancelled; return this.cancelled;
} }
@Override @Override
public void setCancelled(boolean cancel) { public void setCancelled(boolean cancel) {
this.cancelled = cancel; this.cancelled = cancel;
} }
} }

View File

@ -1,26 +1,28 @@
package org.maxgamer.QuickShop.Shop; package org.maxgamer.QuickShop.Shop;
public enum ShopType { public enum ShopType {
SELLING(0), BUYING(1); SELLING(0),
private int id; BUYING(1);
private ShopType(int id){ private int id;
this.id = id;
}
public static ShopType fromID(int id) {
for(ShopType type:ShopType.values()){
if(type.id==id){
return type;
}
}
return null;
}
public static int toID(ShopType shopType) { ShopType(int id) {
return shopType.id; this.id = id;
} }
public int toID() { public static ShopType fromID(int id) {
return id; for (ShopType type : ShopType.values()) {
} if (type.id == id) {
return type;
}
}
return null;
}
public static int toID(ShopType shopType) {
return shopType.id;
}
public int toID() {
return id;
}
} }

View File

@ -4,20 +4,20 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
public class MarkUtil { public class MarkUtil {
static String mark = "§q§s§6[§b快捷商店§6] §c悬浮物品§r "; static String mark = "§q§s§6[§b快捷商店§6] §c悬浮物品§r ";
static int conut = 0; static int conut = 0;
public static void addMark(final ItemStack ci) { public static void addMark(final ItemStack ci) {
final ItemMeta meta = ci.getItemMeta(); final ItemMeta meta = ci.getItemMeta();
meta.setDisplayName(mark + " " + Util.getName(ci) + " " + conut++); meta.setDisplayName(mark + " " + Util.getName(ci) + " " + conut++);
ci.setItemMeta(meta); ci.setItemMeta(meta);
} }
public static boolean hasMark(final ItemStack ci) { public static boolean hasMark(final ItemStack ci) {
try { try {
return ci.getItemMeta().getDisplayName().startsWith(mark); return ci.getItemMeta().getDisplayName().startsWith(mark);
} catch (final Exception e) { } catch (final Exception e) {
return false; return false;
} }
} }
} }

View File

@ -9,194 +9,189 @@ 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;
/** /**
* Deletes any messages that are older than a week in the database, to save * Deletes any messages that are older than a week in the database, to save
* on space. * on space.
*/ */
public static void clean() { public static void clean() {
plugin.getLogger().info("清理超过 一周 的 商店交易记录..."); plugin.getLogger().info("清理超过 一周 的 商店交易记录...");
// 604800,000 msec = 1 week. // 604800,000 msec = 1 week.
final long weekAgo = System.currentTimeMillis() - 604800000; final long weekAgo = System.currentTimeMillis() - 604800000;
plugin.getDB().execute("DELETE FROM messages WHERE time < ?", weekAgo); plugin.getDB().execute("DELETE FROM messages WHERE time < ?", weekAgo);
} }
/** /**
* Empties the queue of messages a player has and sends them to the player. * Empties the queue of messages a player has and sends them to the player.
* *
* @param p * @param p
* 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);
if (msgs != null) { if (msgs != null) {
for (final String msg : msgs) { for (final String msg : msgs) {
p.getPlayer().sendMessage(msg); p.getPlayer().sendMessage(msg);
} }
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);
} }
/** /**
* loads all player purchase messages from the database. * loads all player purchase messages from the database.
*/ */
public static void loadTransactionMessages() { public static void loadTransactionMessages() {
player_messages.clear(); // Delete old messages player_messages.clear(); // Delete old messages
try { try {
final ResultSet rs = plugin.getDB().getConnection().prepareStatement("SELECT * FROM messages").executeQuery(); final ResultSet rs = plugin.getDB().getConnection().prepareStatement("SELECT * FROM messages").executeQuery();
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.add(message);
msgs = new LinkedList<String>(); }
player_messages.put(owner, msgs); } catch (final SQLException e) {
} e.printStackTrace();
msgs.add(message); Log.d("无法从数据库获得玩家的交易记录 跳过...");
} }
} catch (final SQLException e) { }
e.printStackTrace();
System.out.println("无法从数据库获得玩家的交易记录 跳过...");
}
}
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; }
} for (int i = 0; i < args.length; i++) {
if (args == null) { raw = raw.replace("{" + i + "}", args[i] == null ? "null" : args[i].toString());
return raw; }
} return raw;
for (int i = 0; i < args.length; i++) { }
raw = raw.replace("{" + i + "}", args[i] == null ? "null" : args[i].toString());
}
return raw;
}
/** public static void reload() {
* @param player messages.reload();
* The name of the player to message Util.parseColours(messages);
* @param message }
* The message to send them Sends the given player a message if
* they're online. Else, if they're not online, queues it for
* them in the database.
*/
public static void send(final String player, final String message) {
@SuppressWarnings("deprecation")
final OfflinePlayer p = Bukkit.getOfflinePlayer(player);
if (p == null || !p.isOnline()) {
LinkedList<String> msgs = player_messages.get(player);
if (msgs == null) {
msgs = new LinkedList<String>();
player_messages.put(player, msgs);
}
msgs.add(message);
final String q = "INSERT INTO messages (owner, message, time) VALUES (?, ?, ?)";
plugin.getDB().execute(q, player.toString(), message, System.currentTimeMillis());
} else {
p.getPlayer().sendMessage(message);
}
}
public static void sendItemMessage(final Player p, final ItemStack is, final String msg) { /**
try { * @param player
final FancyMessage fm = new FancyMessage(); * The name of the player to message
fm.text(msg).itemTooltip(is).send(p); * @param message
} catch (Exception | NoClassDefFoundError | NoSuchMethodError e) { * The message to send them Sends the given player a message if
p.sendMessage(msg); * they're online. Else, if they're not online, queues it for
} * them in the database.
} */
public static void send(final String player, final String message) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
final OfflinePlayer p = Bukkit.getOfflinePlayer(player);
if (p == null || !p.isOnline()) {
LinkedList<String> msgs = player_messages.computeIfAbsent(player, k -> new LinkedList<>());
msgs.add(message);
final String q = "INSERT INTO messages (owner, message, time) VALUES (?, ?, ?)";
plugin.getDB().execute(q, player, message, System.currentTimeMillis());
} else {
p.getPlayer().sendMessage(message);
}
});
}
public static void sendPurchaseSuccess(final Player p, final Shop shop, final int amount) { public static void sendItemMessage(final Player p, final ItemStack is, final String msg) {
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); try {
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.successful-purchase")); final Tellraw fm = Tellraw.create();
final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item-name-and-price", "" + amount, shop.getDataName(), Util.format((amount * shop.getPrice()))); fm.text(msg).item(is).send(p);
sendItemMessage(p, shop.getItem(), msg); } catch (Exception | NoClassDefFoundError | NoSuchMethodError e) {
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); plugin.getConfigManager().setEnableMagicLib(false);
} p.sendMessage(msg);
}
}
public static void sendSellSuccess(final Player p, final Shop shop, final int amount) { public static void sendPurchaseSuccess(final Player p, final Shop shop, final int amount) {
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.successfully-sold")); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.successful-purchase"));
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item-name-and-price", "" + amount, shop.getDataName(), Util.format((amount * shop.getPrice())))); final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item-name-and-price", "" + amount, shop.getDataName(), Util.format((amount * shop.getPrice())));
if (plugin.getConfig().getBoolean("show-tax")) { sendItemMessage(p, shop.getItem(), msg);
final double tax = plugin.getConfig().getDouble("tax"); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
final double total = amount * shop.getPrice(); }
if (tax != 0) {
if (!p.getName().equals(shop.getOwner())) {
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.sell-tax", "" + Util.format((tax * total))));
} else {
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.sell-tax-self"));
}
}
}
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
}
public static void sendShopInfo(final Player p, final Shop shop) { public static void sendSellSuccess(final Player p, final Shop shop, final int amount) {
sendShopInfo(p, shop, shop.getRemainingStock()); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
} p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.successfully-sold"));
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item-name-and-price", "" + amount, shop.getDataName(), Util.format((amount * shop.getPrice()))));
if (plugin.getConfig().getBoolean("show-tax")) {
final double tax = plugin.getConfig().getDouble("tax");
final double total = amount * shop.getPrice();
if (tax != 0) {
if (!p.getName().equals(shop.getOwner())) {
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.sell-tax", "" + Util.format((tax * total))));
} else {
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.sell-tax-self"));
}
}
}
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
}
@SuppressWarnings("deprecation") public static void sendShopInfo(final Player p, final Shop shop) {
public static void sendShopInfo(final Player p, final Shop shop, final int stock) { sendShopInfo(p, shop, shop.getRemainingStock());
// Potentially faster with an array? }
final ItemStack items = shop.getItem();
p.sendMessage(""); public static void sendShopInfo(final Player p, final Shop shop, final int stock) {
p.sendMessage(""); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); // Potentially faster with an array?
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information")); final ItemStack item = shop.getItem();
p.sendMessage(ChatColor.DARK_PURPLE + "| " p.sendMessage("");
+ MsgUtil.p("menu.owner", Bukkit.getOfflinePlayer(shop.getOwner()).getName() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : Bukkit.getOfflinePlayer(shop.getOwner()).getName())); p.sendMessage("");
final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName()); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
sendItemMessage(p, shop.getItem(), msg); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information"));
if (Util.isTool(items.getType())) { p.sendMessage(ChatColor.DARK_PURPLE + "| "
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.damage-percent-remaining", Util.getToolPercentage(items))); + 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());
if (shop.isSelling()) { sendItemMessage(p, shop.getItem(), msg);
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.stock", "" + stock)); if (Util.isTool(item.getType())) {
} else { p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.damage-percent-remaining", Util.getToolPercentage(item)));
final int space = shop.getRemainingSpace(); }
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.space", "" + space)); if (shop.isSelling()) {
} p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.stock", "" + (stock == 10000 ? "无限" : stock)));
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.price-per", shop.getDataName(), Util.format(shop.getPrice()))); } else {
if (shop.isBuying()) { final int space = shop.getRemainingSpace();
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-buying")); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.space", "" + (space == 10000 ? "无限" : space)));
} else { }
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-selling")); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.price-per", shop.getDataName(), Util.format(shop.getPrice())));
} if (shop.isBuying()) {
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-buying"));
if (!plugin.isEnableMagicLib()) { } else {
final Inventory in = Bukkit.createInventory(null, 9, plugin.getConfigManager().getGuiTitle()); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.this-shop-is-selling"));
in.setItem(4, items); }
p.openInventory(in); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
} if (shop.isSelling()) {
} p.sendMessage(MsgUtil.p("how-many-buy"));
} else {
final int items = Util.countItems(p.getInventory(), shop.getItem());
p.sendMessage(MsgUtil.p("how-many-sell", items));
}
});
}
} }

View File

@ -1,53 +1,16 @@
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;
public class NMS { 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) { private static void rename(final ItemStack iStack) {
try { MarkUtil.addMark(iStack);
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) {
MarkUtil.addMark(iStack);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -17,36 +17,36 @@ import org.maxgamer.QuickShop.Shop.ShopChunk;
* Also deletes invalid items. * Also deletes invalid items.
*/ */
public class ItemWatcher implements Runnable { public class ItemWatcher implements Runnable {
private QuickShop plugin; private QuickShop plugin;
public ItemWatcher(QuickShop plugin) { public ItemWatcher(QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
public void run() { public void run() {
List<Shop> toRemove = new ArrayList<Shop>(1); List<Shop> toRemove = new ArrayList<Shop>(1);
for (Entry<String, HashMap<ShopChunk, HashMap<Location, Shop>>> inWorld : plugin.getShopManager().getShops().entrySet()) { for (Entry<String, HashMap<ShopChunk, HashMap<Location, Shop>>> inWorld : plugin.getShopManager().getShops().entrySet()) {
// This world // This world
World world = Bukkit.getWorld(inWorld.getKey()); World world = Bukkit.getWorld(inWorld.getKey());
if (world == null) if (world == null)
continue; // world not loaded. continue; // world not loaded.
for (Entry<ShopChunk, HashMap<Location, Shop>> inChunk : inWorld.getValue().entrySet()) { for (Entry<ShopChunk, HashMap<Location, Shop>> inChunk : inWorld.getValue().entrySet()) {
if (!world.isChunkLoaded(inChunk.getKey().getX(), inChunk.getKey().getZ())) { if (!world.isChunkLoaded(inChunk.getKey().getX(), inChunk.getKey().getZ())) {
// If the chunk is not loaded, next chunk! // If the chunk is not loaded, next chunk!
continue; continue;
} }
for (Shop shop : inChunk.getValue().values()) { for (Shop shop : inChunk.getValue().values()) {
// Validate the shop. // Validate the shop.
if (!shop.isValid()) { if (!shop.isValid()) {
toRemove.add(shop); toRemove.add(shop);
continue; continue;
} }
} }
} }
} }
// Now we can remove it. // Now we can remove it.
for (Shop shop : toRemove) { for (Shop shop : toRemove) {
shop.delete(); shop.delete();
} }
} }
} }

View File

@ -11,43 +11,43 @@ import org.bukkit.scheduler.BukkitTask;
import org.maxgamer.QuickShop.QuickShop; 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) {
synchronized (logs) { logs.add(s);
for (String s : logs) { }
ps.println(s); }
}
logs.clear();
}
}
public void add(String s) { public void close() {
synchronized (logs) { this.ps.close();
logs.add(s); }
}
}
public void close() { @Override
this.ps.close(); public void run() {
} synchronized (logs) {
for (final String s : logs) {
ps.println(s);
}
logs.clear();
}
}
} }

View File

@ -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

View File

@ -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: 音乐唱片

View File

@ -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}'

View File

@ -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