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

23 Commits
dev ... master

Author SHA1 Message Date
8edb488ab2 feat: remove wsc listener
Signed-off-by: 502647092 <admin@yumc.pw>
2018-10-04 23:59:35 +08:00
686dc054de update pom.xml 2018-02-05 00:30:18 +08:00
72d3e24b8a fix: 修复低版本兼容问题 2018-02-03 07:11:05 +00:00
0948887e4b Accept Merge Request #10 : 修复java.lang.NoSuchMethod的问题
From -> To: (  17jiong : master   ->   502647092 : master  )

Merge Request: 修复java.lang.NoSuchMethod的问题

Created By: @17jiong
Accepted By: @502647092
URL:https://coding.net/u/502647092/p/QuickShop/git/pull/10
2018-02-03 10:16:27 +08:00
82c2591c9b 修复老版本的服务端没有getStorageContents方法导致报错的问题 2018-02-02 21:38:55 +08:00
a11686a839 fix: 修复部分包未导入 2018-02-01 14:26:48 +08:00
de3fa516e1 feat: 更新版本 2018-02-01 11:00:21 +08:00
2b82a8430d 修复满背包依然可以购买的Bug
玩家背包getContent获取的内容包括了防具栏等
也就是说,即便背包是满的,只要没穿防具就依然可以购买物品
但是因为没有储存空间,导致花了钱,也无法获得该物品
2018-01-31 18:49:19 +08:00
4a18053026 修复不必要的获取离线玩家导致创建大量getProfile线程导致服务端崩溃的问题
[16:32:33] [Paper Watchdog Thread/ERROR]: Current Thread: Craft Scheduler Thread - 14395
[16:32:33] [Paper Watchdog Thread/ERROR]: 	PID: 18215 | Suspended: false | Native: false | State: BLOCKED
[16:32:33] [Paper Watchdog Thread/ERROR]: 	Stack:
[16:32:33] [Paper Watchdog Thread/ERROR]: 		net.minecraft.server.v1_12_R1.UserCache.getProfile(UserCache.java:142)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.bukkit.craftbukkit.v1_12_R1.CraftServer.getOfflinePlayer(CraftServer.java:1352)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:730)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.maxgamer.QuickShop.Util.MsgUtil.lambda$3(MsgUtil.java:170)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.maxgamer.QuickShop.Util.MsgUtil$$Lambda$448/1914437489.run(Unknown Source)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftTask.run(CraftTask.java:58)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:52)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[16:32:33] [Paper Watchdog Thread/ERROR]: 		java.lang.Thread.run(Thread.java:748)
[16:32:33] [Paper Watchdog Thread/ERROR]: ------------------------------
2018-01-31 18:43:23 +08:00
d768f93c6c 修正手误 2018-01-29 04:26:39 +08:00
ccedc8cfea 连接池线程安全修正 2018-01-29 04:24:47 +08:00
7a74e88cd1 让修改价格等行为异步操作数据库 2018-01-29 02:58:21 +08:00
4b41bdff57 异步调用数据库删除方法(BlockBreakEvent触发) 2018-01-29 01:15:51 +08:00
4f3ee83b47 异步保存商店到数据库
由于handleChat已切回主线程,这里需要异步调用
2018-01-29 01:06:12 +08:00
1a624a8384 修复收购商店不触发ShopPurchaseEvent的问题,并且调整触发的时机,避免没钱购买也触发这个事件 2018-01-29 00:31:59 +08:00
1b519fe90f 修复一些奇怪的问题
1. 先取消时间,避免后续抛异常导致事件未被取消
2. AsyncPlayerChatEvent是异步的,在这个事件中的所有操作也是异步执行的,如果不切回同步线程,会导致抛“Entity async add”异常;并且在设置牌子的方法(setSignText)内,会有异步加载区块的风险,导致不可预知的后果
2018-01-29 00:20:04 +08:00
c193f2bc95 update PlayerListener.java 2018-01-29 00:12:47 +08:00
5dd8dd78af 修复一处线程安全问题 2018-01-29 00:10:08 +08:00
e42701f376 修复匹配两个物品是否相同的问题
1. 增加判断Lore信息是否相同
2. 增加判断头颅的Owner是否相同
3. 增加判断成书的标题、内容、作者是否相同
2018-01-29 00:05:03 +08:00
55cd9e386c 删除不必要的监听器 2018-01-28 23:24:01 +08:00
ea61beb719 fix: 修复 1.12 不兼容的问题
Signed-off-by: 502647092 <admin@yumc.pw>
2017-07-29 01:18:27 +08:00
bd2c2aedf9 chore: 更新版本
Signed-off-by: 502647092 <admin@yumc.pw>
2017-06-17 17:48:08 +08:00
664e5c7734 feat: 移除过期无效监听类型
Signed-off-by: 502647092 <admin@yumc.pw>
2017-06-17 17:46:35 +08:00
11 changed files with 850 additions and 678 deletions

33
pom.xml
View File

@ -3,7 +3,7 @@
<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>2.1.1</version> <version>2.3.1</version>
<description>快捷商店重置版本...</description> <description>快捷商店重置版本...</description>
<build> <build>
<finalName>${project.name}</finalName> <finalName>${project.name}</finalName>
@ -50,12 +50,28 @@
</ciManagement> </ciManagement>
<properties> <properties>
<env.GIT_COMMIT>DEBUG</env.GIT_COMMIT> <env.GIT_COMMIT>DEBUG</env.GIT_COMMIT>
<update.description>§a全新版本 §c虚拟悬浮物(橙子提供 对 就是那个汉化COI的逗比)§e7老板修复逗比BUG...</update.description> <update.description>§a全新版本 §c修复大量问题§e(有问题找jiongjiong)...</update.description>
<update.changes> <update.changes>
§b2.3.1 - §cfix: 修复低版本服务端不兼容的问题;
§b2.3.0 - §afeat: 修复大量BUG(感谢jiongjiong提交的PR 下面都是他修复的);
§b - §cfix: 修复不必要的获取离线玩家导致创建大量getProfile线程导致服务端崩溃的问题;
§b - §cfix: 连接池线程安全修正;
§b - §cfix: 让修改价格等行为异步操作数据库;
§b - §cfix: 异步调用数据库删除方法(BlockBreakEvent触发);
§b - §cfix: 异步保存商店到数据库;
§b - §cfix: 修复收购商店不触发ShopPurchaseEvent的问题,并且调整触发的时机,避免没钱购买也触发这个事件;
§b - §cfix: 修复一些奇怪的问题;
§b - §cfix: 修复一处线程安全问题;
§b - §cfix: 修复匹配两个物品是否相同的问题;
§b - §cfix: 删除不必要的监听器
</update.changes>
<update.changelog>
§b2.2.0 - §cfix: 修复 1.12 不兼容的问题;
§b2.1.2 - §e移除过期的监听方法...;
§b2.1.0 - §c修复大箱子刷物品的问题...; §b2.1.0 - §c修复大箱子刷物品的问题...;
§b2.0.1 - §a使用新类库 兼容最新版本...; §b2.0.1 - §a使用新类库 兼容最新版本...;
§b1.9.5 - §a1.10+兼容虚拟悬浮物...; §b1.9.5 - §a1.10+兼容虚拟悬浮物...;
</update.changes> </update.changelog>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
@ -63,14 +79,14 @@
<repositories> <repositories>
<repository> <repository>
<id>yumc-repo</id> <id>yumc-repo</id>
<url>http://repo.yumc.pw/content/groups/public/</url> <url>https://repo.yumc.pw/repository/maven-public/</url>
</repository> </repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<repository> <repository>
<id>jtb</id> <id>jtb</id>
<name>YUMC</name> <name>YUMC</name>
<url>http://repo.yumc.pw/content/repositories/yumcenter/</url> <url>https://repo.yumc.pw/repository/yumcenter/</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<dependencies> <dependencies>
@ -78,12 +94,7 @@
<groupId>pw.yumc</groupId> <groupId>pw.yumc</groupId>
<artifactId>YumCore</artifactId> <artifactId>YumCore</artifactId>
<type>jar</type> <type>jar</type>
<version>1.7</version> <version>[1.8.1,)</version>
</dependency>
<dependency>
<groupId>io.github.Cnly.WowSuchCleaner</groupId>
<artifactId>WowSuchCleaner</artifactId>
<version>1.6.5</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -5,14 +5,18 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties; import java.util.Properties;
public class MySQLCore implements DatabaseCore { public class MySQLCore implements DatabaseCore {
private String url; private String url;
/** The connection properties... user, pass, autoReconnect.. */ /**
* The connection properties... user, pass, autoReconnect..
*/
private Properties info; private Properties info;
private static final int MAX_CONNECTIONS = 8; private static final int MAX_CONNECTIONS = 8;
private static ArrayList<Connection> pool = new ArrayList<>(); private static final List<Connection> POOL = Collections.synchronizedList(new ArrayList<Connection>());
public MySQLCore(String host, String user, String pass, String database, String port) { public MySQLCore(String host, String user, String pass, String database, String port) {
info = new Properties(); info = new Properties();
@ -22,8 +26,7 @@ public class MySQLCore implements DatabaseCore {
info.put("useUnicode", "true"); info.put("useUnicode", "true");
info.put("characterEncoding", "utf8"); info.put("characterEncoding", "utf8");
this.url = "jdbc:mysql://" + host + ":" + port + "/" + database; this.url = "jdbc:mysql://" + host + ":" + port + "/" + database;
for (int i = 0; i < MAX_CONNECTIONS; i++) for (int i = 0; i < MAX_CONNECTIONS; i++) {POOL.add(null);}
pool.add(null);
} }
/** /**
@ -31,9 +34,10 @@ public class MySQLCore implements DatabaseCore {
* *
* @return The database connection * @return The database connection
*/ */
@Override
public Connection getConnection() { public Connection getConnection() {
for (int i = 0; i < MAX_CONNECTIONS; i++) { for (int i = 0; i < MAX_CONNECTIONS; i++) {
Connection connection = pool.get(i); Connection connection = POOL.get(i);
try { try {
// If we have a current connection, fetch it // If we have a current connection, fetch it
if (connection != null && !connection.isClosed()) { if (connection != null && !connection.isClosed()) {
@ -43,7 +47,7 @@ public class MySQLCore implements DatabaseCore {
// Else, it is invalid, so we return another connection. // Else, it is invalid, so we return another connection.
} }
connection = DriverManager.getConnection(this.url, info); connection = DriverManager.getConnection(this.url, info);
pool.set(i, connection); POOL.set(i, connection);
return connection; return connection;
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -1,5 +1,6 @@
package org.maxgamer.QuickShop.Listeners; package org.maxgamer.QuickShop.Listeners;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -7,12 +8,10 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.maxgamer.QuickShop.QuickShop; import org.maxgamer.QuickShop.QuickShop;
/** /**
*
* @author Netherfoam * @author Netherfoam
*
*/ */
public class ChatListener implements Listener { public class ChatListener implements Listener {
QuickShop plugin; private QuickShop plugin;
public ChatListener(final QuickShop plugin) { public ChatListener(final QuickShop plugin) {
this.plugin = plugin; this.plugin = plugin;
@ -23,7 +22,7 @@ public class ChatListener implements Listener {
if (!plugin.getShopManager().getActions().containsKey(e.getPlayer().getName())) { if (!plugin.getShopManager().getActions().containsKey(e.getPlayer().getName())) {
return; return;
} }
plugin.getShopManager().handleChat(e.getPlayer(), e.getMessage());
e.setCancelled(true); e.setCancelled(true);
Bukkit.getScheduler().runTask(plugin, () -> plugin.getShopManager().handleChat(e.getPlayer(), e.getMessage()));
} }
} }

View File

@ -1,6 +1,6 @@
package org.maxgamer.QuickShop.Listeners; package org.maxgamer.QuickShop.Listeners;
import java.util.HashMap; import java.util.Map;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@ -65,7 +65,7 @@ public class PlayerListener implements Listener {
p.openInventory(in); p.openInventory(in);
} }
// Add the new action // Add the new action
final HashMap<String, Info> actions = plugin.getShopManager().getActions(); final Map<String, Info> actions = plugin.getShopManager().getActions();
final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop); final Info info = new Info(shop.getLocation(), ShopAction.BUY, null, null, shop);
actions.put(p.getName(), info); actions.put(p.getName(), info);
} }

View File

@ -1,37 +0,0 @@
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

@ -36,12 +36,10 @@ import org.maxgamer.QuickShop.Economy.EconomyCore;
import org.maxgamer.QuickShop.Economy.Economy_Vault; import org.maxgamer.QuickShop.Economy.Economy_Vault;
import org.maxgamer.QuickShop.Listeners.BlockListener; import org.maxgamer.QuickShop.Listeners.BlockListener;
import org.maxgamer.QuickShop.Listeners.ChatListener; import org.maxgamer.QuickShop.Listeners.ChatListener;
import org.maxgamer.QuickShop.Listeners.ChunkListener;
import org.maxgamer.QuickShop.Listeners.LockListener; import org.maxgamer.QuickShop.Listeners.LockListener;
import org.maxgamer.QuickShop.Listeners.PlayerListener; import org.maxgamer.QuickShop.Listeners.PlayerListener;
import org.maxgamer.QuickShop.Listeners.ProtectListener; import org.maxgamer.QuickShop.Listeners.ProtectListener;
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;
@ -301,16 +299,6 @@ public class QuickShop extends JavaPlugin {
MsgUtil.clean(); MsgUtil.clean();
// Register events // Register events
final PluginManager pm = this.getServer().getPluginManager(); 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 BlockListener(this), this);
pm.registerEvents(new PlayerListener(this), this); pm.registerEvents(new PlayerListener(this), this);
pm.registerEvents(new WorldListener(this), this); pm.registerEvents(new WorldListener(this), this);

View File

@ -195,7 +195,13 @@ public class ContainerShop implements Shop {
final int y = this.getLocation().getBlockY(); final int y = this.getLocation().getBlockY();
final int z = this.getLocation().getBlockZ(); final int z = this.getLocation().getBlockZ();
final String world = this.getLocation().getWorld().getName(); final String world = this.getLocation().getWorld().getName();
plugin.getDB().execute("DELETE FROM shops WHERE x = '" + x + "' AND y = '" + y + "' AND z = '" + z + "' AND world = '" + world + "'"); // Async database execute
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
plugin.getDB().execute("DELETE FROM shops WHERE x = '" + x + "' AND y = '" + y + "' AND z = '" + z + "' AND world = '" + world + "'");
}
});
// Refund if necessary // Refund if necessary
if (plugin.getConfig().getBoolean("shop.refund")) { if (plugin.getConfig().getBoolean("shop.refund")) {
plugin.getEcon().deposit(this.getOwner(), plugin.getConfig().getDouble("shop.cost")); plugin.getEcon().deposit(this.getOwner(), plugin.getConfig().getDouble("shop.cost"));
@ -650,13 +656,22 @@ public class ContainerShop implements Shop {
final String world = this.getLocation().getWorld().getName(); final String world = this.getLocation().getWorld().getName();
final int unlimited = this.isUnlimited() ? 1 : 0; final int unlimited = this.isUnlimited() ? 1 : 0;
final String q = "UPDATE shops SET owner = ?, itemConfig = ?, unlimited = ?, type = ?, price = ? WHERE x = ? AND y = ? and z = ? and world = ?"; final String q = "UPDATE shops SET owner = ?, itemConfig = ?, unlimited = ?, type = ?, price = ? WHERE x = ? AND y = ? and z = ? and world = ?";
try { final String owner = this.getOwner();
plugin.getDB().execute(q, this.getOwner(), Util.serialize(this.getItem()), unlimited, shopType.toID(), this.getPrice(), x, y, z, world); final String item = Util.serialize(this.getItem());
} catch (final Exception e) { double price = this.getPrice();
plugin.getLogger().warning("无法保存商店到数据库!!!"); // Async database execute
plugin.getLogger().warning("错误信息: " + e.getMessage()); plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
e.printStackTrace(); @Override
} public void run() {
try {
plugin.getDB().execute(q, owner, item, unlimited, shopType.toID(), price, x, y, z, world);
} catch (final Exception e) {
plugin.getLogger().warning("无法保存商店到数据库!!!");
plugin.getLogger().warning("错误信息: " + e.getMessage());
e.printStackTrace();
}
}
});
} }
private void checkDisplay() { private void checkDisplay() {

View File

@ -5,7 +5,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
@ -75,24 +74,7 @@ public abstract class FakeItem extends DisplayItem {
} }
} }
}; };
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(chunkPacketListener);
ProtocolLibrary.getProtocolManager().addPacketListener(chunkBulkPacketListener);
registered = true; registered = true;
} }

View File

@ -1,6 +1,18 @@
package org.maxgamer.QuickShop.Shop; package org.maxgamer.QuickShop.Shop;
import org.bukkit.*; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
@ -14,14 +26,9 @@ import org.maxgamer.QuickShop.QuickShop;
import org.maxgamer.QuickShop.Util.MsgUtil; import org.maxgamer.QuickShop.Util.MsgUtil;
import org.maxgamer.QuickShop.Util.Util; import org.maxgamer.QuickShop.Util.Util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
public class ShopManager { public class ShopManager {
private final HashMap<String, Info> actions = new HashMap<>();
private final Map<String, Info> actions = new ConcurrentHashMap<String, Info>();
private final QuickShop plugin; private final QuickShop plugin;
private final HashMap<String, HashMap<ShopChunk, HashMap<Location, Shop>>> shops = new HashMap<>(); private final HashMap<String, HashMap<ShopChunk, HashMap<Location, Shop>>> shops = new HashMap<>();
@ -34,9 +41,9 @@ public class ShopManager {
* shop. * shop.
* *
* @param p * @param p
* The player to check * The player to check
* @param b * @param b
* The block to check * The block to check
* @return True if they're allowed to place a shop there. * @return True if they're allowed to place a shop there.
*/ */
public boolean canBuildShop(final Player p, final Block b, final BlockFace bf) { public boolean canBuildShop(final Player p, final Block b, final BlockFace bf) {
@ -60,7 +67,11 @@ public class ShopManager {
} }
/* 修复其他插件调用产生的报错... */ /* 修复其他插件调用产生的报错... */
try { try {
final PlayerInteractEvent pie = new PlayerInteractEvent(p, Action.RIGHT_CLICK_BLOCK, new ItemStack(Material.AIR), b, bf); // PIE = PlayerInteractEvent - What else? final PlayerInteractEvent pie = new PlayerInteractEvent(p,
Action.RIGHT_CLICK_BLOCK,
new ItemStack(Material.AIR),
b,
bf); // PIE = PlayerInteractEvent - What else?
Bukkit.getPluginManager().callEvent(pie); Bukkit.getPluginManager().callEvent(pie);
pie.getPlayer().closeInventory(); // If the player has chat open, this will close their chat. pie.getPlayer().closeInventory(); // If the player has chat open, this will close their chat.
if (pie.isCancelled()) { return false; } if (pie.isCancelled()) { return false; }
@ -96,26 +107,37 @@ public class ShopManager {
public void createShop(final Shop shop) { public void createShop(final Shop shop) {
final Location loc = shop.getLocation(); final Location loc = shop.getLocation();
final ItemStack item = shop.getItem(); final ItemStack item = shop.getItem();
try { final String serializeItem = Util.serialize(item);
// Write it to the database final String worldName = loc.getWorld().getName();
final String q = "INSERT INTO shops (owner, price, itemConfig, x, y, z, world, unlimited, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; final int x = loc.getBlockX();
plugin.getDB().execute(q, final int y = loc.getBlockY();
shop.getOwner(), final int z = loc.getBlockZ();
shop.getPrice(), // Async database execute
Util.serialize(item), plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
loc.getBlockX(), @Override
loc.getBlockY(), public void run() {
loc.getBlockZ(), try {
loc.getWorld().getName(), // Write it to the database
(shop.isUnlimited() ? 1 : 0), final String q = "INSERT INTO shops (owner, price, itemConfig, x, y, z, world, unlimited, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
shop.getShopType().toID()); plugin.getDB().execute(q,
// Add it to the world shop.getOwner(),
addShop(loc.getWorld().getName(), shop); shop.getPrice(),
} catch (final Exception e) { serializeItem,
plugin.getLogger().warning("无法保存商店到数据库! 下次重启商店将会消失!"); x,
plugin.getLogger().warning("错误信息: " + e.getMessage()); y,
e.printStackTrace(); z,
} worldName,
(shop.isUnlimited() ? 1 : 0),
shop.getShopType().toID());
} catch (final Exception e) {
plugin.getLogger().warning("无法保存商店到数据库! 下次重启商店将会消失!");
plugin.getLogger().warning("错误信息: " + e.getMessage());
e.printStackTrace();
}
}
});
// Add it to the world
addShop(worldName, shop);
} }
public String format(final double d) { public String format(final double d) {
@ -124,9 +146,9 @@ public class ShopManager {
/** /**
* @return Returns the HashMap<Player name, shopInfo>. Info contains what * @return Returns the HashMap<Player name, shopInfo>. Info contains what
* their last question etc was. * their last question etc was.
*/ */
public HashMap<String, Info> getActions() { public Map<String, Info> getActions() {
return this.actions; return this.actions;
} }
@ -138,7 +160,7 @@ public class ShopManager {
* Gets a shop in a specific location * Gets a shop in a specific location
* *
* @param loc * @param loc
* The location to get the shop from * The location to get the shop from
* @return The shop at that location * @return The shop at that location
*/ */
public Shop getShop(final Location loc) { public Shop getShop(final Location loc) {
@ -172,8 +194,8 @@ public class ShopManager {
* Returns a hashmap of Shops * Returns a hashmap of Shops
* *
* @param c * @param c
* The chunk to search. Referencing doesn't matter, only * The chunk to search. Referencing doesn't matter, only
* coordinates and world are used. * coordinates and world are used.
* @return * @return
*/ */
public HashMap<Location, Shop> getShops(final Chunk c) { public HashMap<Location, Shop> getShops(final Chunk c) {
@ -188,8 +210,8 @@ public class ShopManager {
* Returns a hashmap of Chunk -> Shop * Returns a hashmap of Chunk -> Shop
* *
* @param world * @param world
* The name of the world (case sensitive) to get the list of * The name of the world (case sensitive) to get the list of
* shops from * shops from
* @return a hashmap of Chunk -> Shop * @return a hashmap of Chunk -> Shop
*/ */
public HashMap<ShopChunk, HashMap<Location, Shop>> getShops(final String world) { public HashMap<ShopChunk, HashMap<Location, Shop>> getShops(final String world) {
@ -205,10 +227,11 @@ public class ShopManager {
public void handleChat(final Player p, final String msgs) { public void handleChat(final Player p, final String msgs) {
final String message = ChatColor.stripColor(msgs); final String message = ChatColor.stripColor(msgs);
final HashMap<String, Info> actions = getActions(); final Map<String, Info> actions = getActions();
// They wanted to do something. // They wanted to do something.
final Info info = actions.remove(p.getName()); final Info info = actions.remove(p.getName());
if (info == null) { return; // multithreaded means this can happen if (info == null) {
return; // multithreaded means this can happen
} }
/* Creation handling */ /* Creation handling */
if (info.getAction() == ShopAction.CREATE) { if (info.getAction() == ShopAction.CREATE) {
@ -246,9 +269,9 @@ public class ShopManager {
* from the database. Do not use this method to create a shop. * from the database. Do not use this method to create a shop.
* *
* @param world * @param world
* The world the shop is in * The world the shop is in
* @param shop * @param shop
* The shop to load * The shop to load
*/ */
public void loadShop(final String world, final Shop shop) { public void loadShop(final String world, final Shop shop) {
this.addShop(world, shop); this.addShop(world, shop);
@ -259,7 +282,7 @@ public class ShopManager {
* REQUIRES * the world to be loaded * REQUIRES * the world to be loaded
* *
* @param shop * @param shop
* The shop to remove * The shop to remove
*/ */
public void removeShop(final Shop shop) { public void removeShop(final Shop shop) {
final Location loc = shop.getLocation(); final Location loc = shop.getLocation();
@ -277,9 +300,9 @@ public class ShopManager {
* loaded * loaded
* *
* @param world * @param world
* The name of the world * The name of the world
* @param shop * @param shop
* The shop to add * The shop to add
*/ */
private void addShop(final String world, final Shop shop) { private void addShop(final String world, final Shop shop) {
HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops().get(world); HashMap<ShopChunk, HashMap<Location, Shop>> inWorld = this.getShops().get(world);
@ -330,12 +353,21 @@ public class ShopManager {
// Tries to check their balance nicely to see if // Tries to check their balance nicely to see if
// they can afford it. // they can afford it.
if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) { if (plugin.getEcon().getBalance(shop.getOwner()) < amount * shop.getPrice()) {
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you",
format(amount * shop.getPrice()),
format(plugin.getEcon().getBalance(shop.getOwner()))));
return; return;
} }
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled()) {
return; // Cancelled
}
// Check for plugins faking econ.has(amount) // Check for plugins faking econ.has(amount)
if (!plugin.getEcon().withdraw(shop.getOwner(), total)) { if (!plugin.getEcon().withdraw(shop.getOwner(), total)) {
p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(shop.getOwner())))); p.sendMessage(MsgUtil.p("the-owner-cant-afford-to-buy-from-you",
format(amount * shop.getPrice()),
format(plugin.getEcon().getBalance(shop.getOwner()))));
return; return;
} }
if (tax != 0) { if (tax != 0) {
@ -347,7 +379,10 @@ public class ShopManager {
// Notify the owner of the purchase. // Notify the owner of the purchase.
String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName()); String msg = MsgUtil.p("player-sold-to-your-store", p.getName(), "" + amount, shop.getDataName());
if (space == amount) { if (space == amount) {
msg += "\n" + MsgUtil.p("shop-out-of-space", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ()); msg += "\n" + MsgUtil.p("shop-out-of-space",
"" + shop.getLocation().getBlockX(),
"" + shop.getLocation().getBlockY(),
"" + shop.getLocation().getBlockZ());
} }
MsgUtil.send(shop.getOwner(), msg); MsgUtil.send(shop.getOwner(), msg);
} }
@ -409,7 +444,13 @@ public class ShopManager {
createShop(shop); createShop(shop);
p.sendMessage(MsgUtil.p("success-created-shop")); p.sendMessage(MsgUtil.p("success-created-shop"));
final Location loc = shop.getLocation(); final Location loc = shop.getLocation();
plugin.log(String.format("玩家: %s 创建了一个 %s 商店 在 (%s - %s, %s, %s)", p.getName(), shop.getDataName(), loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ())); plugin.log(String.format("玩家: %s 创建了一个 %s 商店 在 (%s - %s, %s, %s)",
p.getName(),
shop.getDataName(),
loc.getWorld().getName(),
loc.getX(),
loc.getY(),
loc.getZ()));
if (!plugin.getConfig().getBoolean("shop.lock")) { if (!plugin.getConfig().getBoolean("shop.lock")) {
// Warn them if they haven't been warned since // Warn them if they haven't been warned since
// reboot // reboot
@ -445,8 +486,7 @@ public class ShopManager {
} }
} }
} }
/* They didn't enter a number. */ /* They didn't enter a number. */ catch (final NumberFormatException ex) {
catch (final NumberFormatException ex) {
p.sendMessage(MsgUtil.p("shop-creation-cancelled")); p.sendMessage(MsgUtil.p("shop-creation-cancelled"));
} }
} }
@ -463,25 +503,30 @@ public class ShopManager {
p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace)); p.sendMessage(MsgUtil.p("not-enough-space", "" + pSpace));
return; return;
} }
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled()) { return; // Cancelled
}
// Money handling // Money handling
if (!p.getName().equals(shop.getOwner())) { if (!p.getName().equals(shop.getOwner())) {
// Check their balance. Works with *most* economy // Check their balance. Works with *most* economy
// plugins* // plugins*
if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) { if (plugin.getEcon().getBalance(p.getName()) < amount * shop.getPrice()) {
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); p.sendMessage(MsgUtil.p("you-cant-afford-to-buy",
format(amount * shop.getPrice()),
format(plugin.getEcon().getBalance(p.getName()))));
return; return;
} }
final ShopPurchaseEvent e = new ShopPurchaseEvent(shop, p, amount);
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled()) {
return; // Cancelled
}
// Don't tax them if they're purchasing from // Don't tax them if they're purchasing from
// themselves. // themselves.
// Do charge an amount of tax though. // Do charge an amount of tax though.
final double tax = plugin.getConfigManager().getTax(); final double tax = plugin.getConfigManager().getTax();
final double total = amount * shop.getPrice(); final double total = amount * shop.getPrice();
if (!plugin.getEcon().withdraw(p.getName(), total)) { if (!plugin.getEcon().withdraw(p.getName(), total)) {
p.sendMessage(MsgUtil.p("you-cant-afford-to-buy", format(amount * shop.getPrice()), format(plugin.getEcon().getBalance(p.getName())))); p.sendMessage(MsgUtil.p("you-cant-afford-to-buy",
format(amount * shop.getPrice()),
format(plugin.getEcon().getBalance(p.getName()))));
return; return;
} }
if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) { if (!shop.isUnlimited() || plugin.getConfig().getBoolean("shop.pay-unlimited-shop-owners")) {
@ -494,13 +539,21 @@ public class ShopManager {
if (plugin.getConfigManager().isShowTax()) { if (plugin.getConfigManager().isShowTax()) {
String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total))); String msg = MsgUtil.p("player-bought-from-your-store-tax", p.getName(), "" + amount, shop.getDataName(), Util.format((tax * total)));
if (stock == amount) { if (stock == amount) {
msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); msg += "\n" + MsgUtil.p("shop-out-of-stock",
"" + shop.getLocation().getBlockX(),
"" + shop.getLocation().getBlockY(),
"" + shop.getLocation().getBlockZ(),
shop.getDataName());
} }
MsgUtil.send(shop.getOwner(), msg); MsgUtil.send(shop.getOwner(), msg);
} else { } else {
String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName()); String msg = MsgUtil.p("player-bought-from-your-store", p.getName(), "" + amount, shop.getDataName());
if (stock == amount) { if (stock == amount) {
msg += "\n" + MsgUtil.p("shop-out-of-stock", "" + shop.getLocation().getBlockX(), "" + shop.getLocation().getBlockY(), "" + shop.getLocation().getBlockZ(), shop.getDataName()); msg += "\n" + MsgUtil.p("shop-out-of-stock",
"" + shop.getLocation().getBlockX(),
"" + shop.getLocation().getBlockY(),
"" + shop.getLocation().getBlockZ(),
shop.getDataName());
} }
MsgUtil.send(shop.getOwner(), msg); MsgUtil.send(shop.getOwner(), msg);
} }
@ -564,7 +617,8 @@ public class ShopManager {
} }
shops = chunks.next().values().iterator(); shops = chunks.next().values().iterator();
} }
if (!shops.hasNext()) { return this.next(); // Skip to the next one (Empty iterator?) if (!shops.hasNext()) {
return this.next(); // Skip to the next one (Empty iterator?)
} }
current = shops.next(); current = shops.next();
return current; return current;

View File

@ -106,7 +106,7 @@ public class MsgUtil {
*/ */
public static void send(final String player, final String message) { public static void send(final String player, final String message) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
final OfflinePlayer p = Bukkit.getOfflinePlayer(player); final Player p = Bukkit.getPlayerExact(player);
if (p == null || !p.isOnline()) { if (p == null || !p.isOnline()) {
LinkedList<String> msgs = player_messages.computeIfAbsent(player, k -> new LinkedList<>()); LinkedList<String> msgs = player_messages.computeIfAbsent(player, k -> new LinkedList<>());
msgs.add(message); msgs.add(message);
@ -166,8 +166,7 @@ public class MsgUtil {
p.sendMessage(""); p.sendMessage("");
p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+"); p.sendMessage(ChatColor.DARK_PURPLE + "+---------------------------------------------------+");
p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information")); p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.shop-information"));
p.sendMessage(ChatColor.DARK_PURPLE + "| " p.sendMessage(ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.owner", shop.getOwner() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : shop.getOwner()));
+ MsgUtil.p("menu.owner", Bukkit.getOfflinePlayer(shop.getOwner()).getName() == null ? (shop.isUnlimited() ? "系统商店" : "未知") : Bukkit.getOfflinePlayer(shop.getOwner()).getName()));
final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName()); final String msg = ChatColor.DARK_PURPLE + "| " + MsgUtil.p("menu.item", shop.getDataName());
sendItemMessage(p, shop.getItem(), msg); sendItemMessage(p, shop.getItem(), msg);
if (Util.isTool(item.getType())) { if (Util.isTool(item.getType())) {

File diff suppressed because it is too large Load Diff