diff --git a/lib/ProtocolLib-3.6.5-SNAPSHOT.jar b/lib/ProtocolLib-3.6.5-SNAPSHOT.jar
new file mode 100644
index 0000000..ec73d32
Binary files /dev/null and b/lib/ProtocolLib-3.6.5-SNAPSHOT.jar differ
diff --git a/pom.xml b/pom.xml
index 0373556..9a1eef8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,7 +55,8 @@
http://ci.citycraft.cn:8080
DEBUG
- &a修复手动处理无效的问题 使用ProtocolLib序列化物品(&c感谢尘曲修复类库&a)...
+ &a修复手动处理无效的问题
+ 使用ProtocolLib序列化物品(&c感谢尘曲修复类库&a)...
UTF-8
@@ -89,6 +90,13 @@
system
${project.basedir}/lib/WorldEdit.jar
+
+ com.comphenix.protocol
+ ProtocolLib
+ 3.6.5-SNAPSHOT
+ system
+ ${project.basedir}/lib/ProtocolLib-3.6.5-SNAPSHOT.jar
+
cn.citycraft
PluginHelper
diff --git a/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java b/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java
index 38bdd4b..87012e2 100644
--- a/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java
+++ b/src/main/java/org/maxgamer/QuickShop/Config/ConfigManager.java
@@ -7,6 +7,7 @@ import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.maxgamer.QuickShop.QuickShop;
+import org.maxgamer.QuickShop.Shop.FakeItem;
import cn.citycraft.PluginHelper.config.FileConfig;
import cn.citycraft.PluginHelper.tellraw.FancyMessage;
@@ -44,6 +45,8 @@ public class ConfigManager {
private Material superItem = Material.GOLD_AXE;
private double tax = 0;
private final String taxAccount;
+ private boolean fakeItem = false;
+
/**
* A set of players who have been warned
* ("Your shop isn't automatically locked")
@@ -79,6 +82,19 @@ public class ConfigManager {
this.feeForPriceChange = config.getDouble("shop.fee-for-price-change");
this.preventhopper = config.getBoolean("preventhopper");
this.guiTitle = config.getMessage("guititle", guiTitle);
+ this.fakeItem = config.getBoolean("fakeitem", true);
+ if (config.getBoolean("fakeitem", true)) {
+ try {
+ plugin.getLogger().info("启用虚拟悬浮物 尝试启动中...");
+ FakeItem.register(plugin);
+ plugin.getLogger().info("虚拟悬浮物功能测试正常...");
+ fakeItem = true;
+ } catch (final Exception e) {
+ plugin.getLogger().warning("+=========================================");
+ plugin.getLogger().warning("| 警告: 虚拟物品启动失败 使用原版悬浮物品...");
+ plugin.getLogger().warning("+=========================================");
+ }
+ }
if (config.getBoolean("usemagiclib", true)) {
try {
plugin.getLogger().info("启用魔改库 尝试启动中...");
@@ -145,6 +161,10 @@ public class ConfigManager {
return enableMagicLib;
}
+ public boolean isFakeItem() {
+ return fakeItem;
+ }
+
public boolean isLimit() {
return limit;
}
@@ -185,4 +205,8 @@ public class ConfigManager {
this.enableMagicLib = enableMagicLib;
}
+ public void setFakeItem(final boolean fakeItem) {
+ this.fakeItem = fakeItem;
+ }
+
}
diff --git a/src/main/java/org/maxgamer/QuickShop/QuickShop.java b/src/main/java/org/maxgamer/QuickShop/QuickShop.java
index 8e6fd6d..b6686c7 100644
--- a/src/main/java/org/maxgamer/QuickShop/QuickShop.java
+++ b/src/main/java/org/maxgamer/QuickShop/QuickShop.java
@@ -43,6 +43,7 @@ import org.maxgamer.QuickShop.Listeners.ProtectListener;
import org.maxgamer.QuickShop.Listeners.WorldListener;
import org.maxgamer.QuickShop.Listeners.WowSuchCleanerListener;
import org.maxgamer.QuickShop.Shop.ContainerShop;
+import org.maxgamer.QuickShop.Shop.FakeItem;
import org.maxgamer.QuickShop.Shop.Shop;
import org.maxgamer.QuickShop.Shop.ShopManager;
import org.maxgamer.QuickShop.Shop.ShopType;
@@ -295,6 +296,14 @@ public class QuickShop extends JavaPlugin {
// Create the shop manager.
configManager = new ConfigManager(this);
shopManager = new ShopManager(this);
+ if (configManager.isFakeItem()) {
+ if (!FakeItem.isRegistered()) {
+ try {
+ FakeItem.register(this);
+ } catch (final Exception e) {
+ }
+ }
+ }
if (configManager.isLogAction()) {
// Logger Handler
this.logWatcher = new LogWatcher(this, new File(this.getDataFolder(), "qs.log"));
diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java b/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java
index d981adf..f9de264 100644
--- a/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java
+++ b/src/main/java/org/maxgamer/QuickShop/Shop/ContainerShop.java
@@ -23,7 +23,7 @@ import org.maxgamer.QuickShop.Util.MsgUtil;
import org.maxgamer.QuickShop.Util.Util;
public class ContainerShop implements Shop {
- private DisplayItem displayItem;
+ private DisplayItem displayName;
private final ItemStack item;
private final Location loc;
private String owner;
@@ -53,13 +53,17 @@ public class ContainerShop implements Shop {
this.plugin = (QuickShop) Bukkit.getPluginManager().getPlugin("QuickShop");
this.item.setAmount(1);
if (plugin.getConfigManager().isDisplay()) {
- this.displayItem = new DisplayItem(this, this.item);
+ if (plugin.getConfigManager().isFakeItem()) {
+ this.displayName = new FakeItem(this, this.getItem());
+ } else {
+ this.displayName = new NormalItem(this, this.getItem());
+ }
}
this.shopType = ShopType.SELLING;
}
private ContainerShop(final ContainerShop s) {
- this.displayItem = s.displayItem;
+ this.displayName = s.displayName;
this.shopType = s.shopType;
this.item = s.item;
this.loc = s.loc;
@@ -243,7 +247,7 @@ public class ContainerShop implements Shop {
* @return The display item associated with this shop.
*/
public DisplayItem getDisplayItem() {
- return this.displayItem;
+ return this.displayName;
}
/**
@@ -469,7 +473,7 @@ public class ContainerShop implements Shop {
public void onUnload() {
if (this.getDisplayItem() != null) {
this.getDisplayItem().remove();
- this.displayItem = null;
+ this.displayName = null;
}
}
@@ -677,14 +681,18 @@ public class ContainerShop implements Shop {
}
final boolean trans = Util.isTransparent(getLocation().clone().add(0.5, 1.2, 0.5).getBlock().getType());
if (trans && this.getDisplayItem() == null) {
- this.displayItem = new DisplayItem(this, this.getItem());
+ if (plugin.getConfigManager().isFakeItem()) {
+ this.displayName = new FakeItem(this, this.getItem());
+ } else {
+ this.displayName = new NormalItem(this, this.getItem());
+ }
this.getDisplayItem().spawn();
return;
}
if (this.getDisplayItem() != null) {
if (!trans) { // We have a display item in a block... delete it
this.getDisplayItem().remove();
- this.displayItem = null;
+ this.displayName = null;
return;
}
final DisplayItem disItem = this.getDisplayItem();
diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java
index 8bc0149..99f0e94 100644
--- a/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java
+++ b/src/main/java/org/maxgamer/QuickShop/Shop/DisplayItem.java
@@ -1,110 +1,44 @@
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;
+public interface DisplayItem {
/**
- * Creates a new display item.
+ * 获得悬浮物地点
*
- * @param shop
- * The shop (See Shop)
- * @param iStack
- * The item stack to clone properties of the display item from.
+ * @return 获得悬浮地点
*/
- 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);
- }
+ public Location getDisplayLocation();
/**
- * @return Returns the exact location of the display item. (1 above shop
- * block, in the center)
+ * @return {@link Item}
*/
- public Location getDisplayLocation() {
- return this.shop.getLocation().clone().add(0.5, 1.2, 0.5);
- }
+ public Item getItem();
/**
- * Returns the reference to this shops item. Do not modify.
+ * 移除悬浮物
*/
- public Item getItem() {
- return this.item;
- }
+ public void remove();
/**
- * Removes the display item.
+ * 移除多余物品
+ *
+ * @return
*/
- public void remove() {
- if (this.item == null) {
- return;
- }
- this.item.remove();
- }
+ public boolean removeDupe();
/**
- * 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())) {
- e.remove();
- removed = true;
- }
- }
- return removed;
- }
+ public void respawn();
/**
- * 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) {
- }
- }
+ public void spawn();
}
\ No newline at end of file
diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java
new file mode 100644
index 0000000..b97f48e
--- /dev/null
+++ b/src/main/java/org/maxgamer/QuickShop/Shop/FakeItem.java
@@ -0,0 +1,238 @@
+package org.maxgamer.QuickShop.Shop;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.WrappedWatchableObject;
+
+/**
+ * Minecraft 虚拟悬浮物品工具类
+ * 需要depend ProtocolLib
+ *
+ * @author 橙子(chengzi)
+ * @version 1.0.1
+ */
+public class FakeItem implements DisplayItem {
+
+ private static Map> fakes = new HashMap>();
+ private static boolean registered = false;
+ private static int lastId = Integer.MAX_VALUE;
+
+ private final ItemStack itemStack;
+ private final Location location;
+ private final int eid;
+ private boolean created = false;
+
+ 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("The ProtocolLib enable Failed.");
+ }
+ } else {
+ throw new IllegalStateException("The Server Not Found ProtocolLib.");
+ }
+ final PacketAdapter chunkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK) {
+ @Override
+ public void onPacketSending(final PacketEvent event) {
+ 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 fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunkX, chunkZ)));
+ if (fakesInChunk != null) {
+ try {
+ for (final FakeItem fake : fakesInChunk) {
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket());
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getVelocityPacket());
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket());
+ }
+ } catch (final InvocationTargetException e) {
+ }
+ }
+ }
+ };
+ final PacketAdapter chunkBulkPacketListener = new PacketAdapter(plugin, PacketType.Play.Server.MAP_CHUNK_BULK) {
+ @Override
+ public void onPacketSending(final PacketEvent event) {
+ 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 fakesInChunk = fakes.get(getChunkIdentifyString(p.getWorld().getChunkAt(chunksX[i], chunksZ[i])));
+ if (fakesInChunk != null) {
+ try {
+ for (final FakeItem fake : fakesInChunk) {
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getSpawnPacket());
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getVelocityPacket());
+ ProtocolLibrary.getProtocolManager().sendServerPacket(p, fake.getMetadataPacket());
+ }
+ } catch (final InvocationTargetException e) {
+ }
+ }
+ }
+ }
+ };
+
+ ProtocolLibrary.getProtocolManager().addPacketListener(chunkPacketListener);
+ ProtocolLibrary.getProtocolManager().addPacketListener(chunkBulkPacketListener);
+ registered = true;
+ }
+
+ private static String getChunkIdentifyString(final Chunk chunk) {
+ return chunk.getWorld().getName() + "@@" + chunk.getX() + "@@" + chunk.getZ();
+ }
+
+ private static int getFakeEntityId() {
+ return lastId--;
+ }
+
+ private static int getNormalizedDistance(final double value) {
+ return (int) Math.floor(value * 32.0D);
+ }
+
+ public FakeItem(final ContainerShop containerShop, final ItemStack item) {
+ this.itemStack = item;
+ this.location = containerShop.getLocation().add(0.5, 1, 0.5);
+ this.eid = getFakeEntityId();
+ }
+
+ public FakeItem(final ItemStack itemStack, final Location loc) {
+ this.itemStack = itemStack;
+ this.location = loc;
+ this.eid = getFakeEntityId();
+ }
+
+ @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() {
+ destory();
+ create();
+ }
+
+ @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 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 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;
+ }
+
+ private PacketContainer getDestoryPacket() {
+ final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_DESTROY);
+ fakePacket.getIntegers().write(0, 1);
+ fakePacket.getIntegerArrays().write(0, new int[] { eid });
+ return fakePacket;
+ }
+
+ private PacketContainer getMetadataPacket() {
+ final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_METADATA);
+ fakePacket.getIntegers().write(0, eid);
+ final WrappedWatchableObject itemMeta = new WrappedWatchableObject(10, itemStack);
+ final List entityMetaList = new ArrayList(1);
+ entityMetaList.add(itemMeta);
+ fakePacket.getWatchableCollectionModifier().write(0, entityMetaList);
+ return fakePacket;
+ }
+
+ private PacketContainer getSpawnPacket() {
+ final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.SPAWN_ENTITY);
+ fakePacket.getIntegers().write(0, eid);
+ fakePacket.getIntegers().write(1, getNormalizedDistance(location.getX()));
+ fakePacket.getIntegers().write(2, getNormalizedDistance(location.getY()));
+ fakePacket.getIntegers().write(3, getNormalizedDistance(location.getZ()));
+ fakePacket.getIntegers().write(9, 2);
+ return fakePacket;
+ }
+
+ private PacketContainer getVelocityPacket() {
+ final PacketContainer fakePacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_VELOCITY);
+ fakePacket.getIntegers().write(0, eid);
+ return fakePacket;
+ }
+
+}
diff --git a/src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java b/src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java
new file mode 100644
index 0000000..274406e
--- /dev/null
+++ b/src/main/java/org/maxgamer/QuickShop/Shop/NormalItem.java
@@ -0,0 +1,116 @@
+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 NormalItem implements 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 NormalItem(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)
+ */
+ @Override
+ 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.
+ */
+ @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 (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())) {
+ 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 (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) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 5148f69..f263692 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -8,6 +8,8 @@ preventhopper: false
guititle: '&6[&b快捷商店&6]&r'
#启用魔改库支持
usemagiclib: true
+#启用魔改库支持
+fakeitem: true
#税收数量 (decimal) - 例如 税收是0.05 玩家1 在玩家2的商店 购买了 50元的东西,那么,玩家1 减少 50, 玩家2 账户增加(1-0.05)*50, 并且 玩家2税收账户增加 (0.05)*50.
tax: 0.00