我目前正在编写一款游戏,其中包含大量的方块放置。 当玩家移动时,玩家下方会设置一条彩色玻璃走道,前有方块,后有方块。
我已经检查过重复放置和玩家是否有足够的移动来实际改变一个方块的距离。
我尝试过使用
sendBlockChange
的方法,但它对性能没有帮助,因为sendBlockChange
必须应用于每个在线玩家,反作弊插件会发疯。
下面我提供了在
moveEvent
期间设置块的代码,并且很乐意在这里提出提高性能的建议。
目前,服务器需要大约 5 GB RAM 才能容纳 3-5 名玩家。
public class MoveListener implements Listener {
@EventHandler
public void onMove(PlayerMoveEvent e) {
Location l = e.getTo();
// if player is below 254 and is inside the arena and the moved at least 1 block
if(e.getFrom().getBlockY()<254
&& YmlMethods.isInArea(e.getPlayer(),e.getPlayer().getLocation())
&& !(e.getFrom().getBlockX() == e.getTo().getBlockX()
&& e.getFrom().getBlockY() == e.getTo().getBlockY()
&& e.getFrom().getBlockZ() == e.getTo().getBlockZ()
)){
// if -135 < yaw <= -45 or 215 < yaw <= 305
if ((l.getYaw() <= -45 && l.getYaw() > -135.0) ||
(l.getYaw() <= 305 && l.getYaw() > 215)) {
setEWArea(-1, 1, l, e.getPlayer());
// if 0 < yaw 45 or -360 < yaw <= -315
} else if ((l.getYaw() <= -305
|| (l.getYaw() > -45 && l.getYaw() <= 0))
|| ((l.getYaw() <= 45 && l.getYaw() >= 0)
|| l.getYaw() > 305)) {
setNSArea(1, 1, l, e.getPlayer());
// if -305 < yaw <= -215 or 45 < yaw <= 135
} else if ((l.getYaw() <= -215 && l.getYaw() > -305)
|| (l.getYaw() <= 135 && l.getYaw() > 45)){
setEWArea(-1, 1, l, e.getPlayer());
// if -135 < yaw <= -45 or 215 < yaw <= 305
} else {
setNSArea(-1, -1, l, e.getPlayer());
}
}
}
private void setNSArea(int x, int z, Location start, Player p) {
// 3x3 area around position
int[] positionsX = {-x, 0, x};
int[] positionsZ = {-z, 0, z};
// stained glass colors
int[] blocks = {14, 4, 9};
// player is looking down, let him fall
if (p.getLocation().getPitch() > 75) {
for (int i = 0; i < positionsX.length; i++) {
for (int pZ : positionsZ) {
setAir(positionsX[i], pZ, start, blocks[i]);
}
}
// player is looking up, let him fly
} else {
for (int i = 0; i < positionsX.length; i++) {
for (int pZ : positionsZ) {
setBlock(positionsX[i], pZ, start, blocks[i]);
}
}
}
}
private void setEWArea(int x, int z, Location start, Player p) {
// 3x3 area around position
int[] positionsX = {-x, 0, x};
int[] positionsZ = {-z, 0, z};
// stained glass colors
int[] blocks = {14, 4, 9};
if (p.getLocation().getPitch() > 75) {
for (int i = 0; i < positionsZ.length; i++) {
for (int pX : positionsX) {
setAir(positionsZ[i], pX, start, blocks[i]);
}
}
} else {
for (int i = 0; i < positionsZ.length; i++) {
for (int pX : positionsX) {
setBlock(positionsZ[i], pX, start, blocks[i]);
}
}
}
}
private void setBlock( int x, int z, Location start, int data) {
// get block below player
Location below = new Location(start.getWorld(), start.getBlockX() + x, start.getBlockY() - 1, start.getBlockZ() + z);
Material block = below.getBlock().getType();
// if block is air, set to stained glass
if (block == Material.AIR) {
below.getBlock().setType(Material.STAINED_GLASS);
BlockState bs = below.getBlock().getState();
bs.setRawData((byte)data);
bs.update();
// and schedule removal
queueBlockRemove(below);
}
}
private void setAir(int x, int z, Location start, int data) {
// get block below player
Location below = new Location(start.getWorld(), start.getBlockX() + x, start.getBlockY() - 1, start.getBlockZ() + z);
// if block is stained glass, set to air
if (below.getBlock().getType() == Material.STAINED_GLASS) {
below.getBlock().setType(Material.AIR);
}
// get block 3 below player
Location threeBelow = new Location(start.getWorld(), start.getBlockX() + x, start.getBlockY() - 3, start.getBlockZ() + z);
Material block = threeBelow.getBlock().getType();
// if block is air, set to stained glass
if (block == Material.AIR) {
threeBelow.getBlock().setType(Material.STAINED_GLASS);
BlockState bs = threeBelow.getBlock().getState();
bs.setRawData((byte)data);
bs.update();
// and schedule removal
queueBlockRemove(threeBelow);
}
}
private void queueBlockRemove(Location remove) {
Bukkit.getScheduler().scheduleSyncDelayedTask(Nyanfighters.getInstance(), () -> remove.getBlock().setType(Material.AIR), 20 * 5);
}
}
注意:有一些代码括号作为注释标记。这些都是扩展,它们是目标,但尚未用于降低性能。
尝试在更新块之间实现较短的等待时间。例如,玩家第一次触发区块更新时,将条目存储在地图中,并键入其 UUID 和当前时间值。然后,下次激活事件时,检查当前时间与上次激活事件之间是否已经经过了一定的时间段。如果指定的时间尚未过去,则不要执行任何操作。即使您将其更改为仍然每秒更新一次,这也会比每次更新更新一次提高 20 倍。