为什么函数safeBreak()在Call 1中按预期执行,但在Call 2或Call 2.1中没有执行?
我正在使用我的Minecraft Bukkit插件ToolBelt。
我的插件中的一个工具(PickHax)允许玩家在持有定义的材料时删除一个块(默认为DIAMOND_PICKAXE)。为了提供对提供区域保护(如WorldGuard)和日志记录(如HawkEye)的其他插件的最广泛支持,我制作并调用了BlockBreakEvent。以下是执行此操作的代码:
protected boolean safeBreak(Block target, Player subject, boolean applyPhysics) {
BlockBreakEvent canBreak = new BlockBreakEvent(target,subject);
server.getPluginManager().callEvent(canBreak);
if(!canBreak.isCancelled())
target.setTypeId(0, applyPhysics);
return !canBreak.isCancelled();
}
使用ToolBelt的当前版本(0.1),这非常有效,如果播放器没有该服务器区域(WorldGuard)的权限,则不会删除块。我只需将目标Block设置为event.getClickedBlock()
,将主题Player设置为event.getPlayer()
,将物理布尔值设置为true
,如果它们左键单击,{ {1}}如果他们右键点击。这是0.1版本中的调用:
致电1
false
我目前正在开发支持范围块删除的新版本。根据用户是否正在蹲伏并具有范围权限节点,目标阻止由safeBreak(target,event.getPlayer(),physics);
或event.getClickedBlock()
设置。除了一种情况外,这种方法很好。
subject.getTargetBlock(null,25)
(LEFT_CLICK_AIR),那么他们就会看到更改。true
(RIGHT_CLICK_AIR),那么他们会不看到一个区块更新客户端。如果他们注销并重新开启,则更改是可见的,因此更改确实发生在服务器端。为了缓解这个问题,我尝试使用false
,它应该向用户发送虚假的块更改,而不是以任何方式修改服务器。有了这个,用户总能看到他们做了什么。因此新代码:
致电2
subject.sendBlockChange()
但是,出于某种原因,仅运行if(safeBreak(target,event.getPlayer(),physics))
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
和运行safeBreak()
之间的更改使得区域保护(WorldGuard)不受尊重。用户从WorldGuard获取打印输出仍然警告他们没有构建权,但是bock仍然被打破。
如果if(safeBreak()) sendBlockChange()
的描述并不准确,它实际上并没有以任何方式改变世界,我也尝试过“无害”的打印消息
致电2.1
.sendBlockChange()
当我运行Call 2.1时,如果我在一个我有权打破块的区域,我会得到“错误仍然存在?”消息,但是当我在禁区时,我没有。这意味着if(safeBreak(target,event.getPlayer(),physics))
subject.sendMessage("Error still present?");
返回正确的值,如果我应该打破一个块,但不知何故仍然打破了块。另外,因为它没有调用2的safeBreak()
,所以我再次遇到案例3问题。
致电3
.sendBlockChange()
现在代码除了检查if(safeBreak(target,event.getPlayer(),physics)) {}
的返回值之外没有任何操作,但它仍然在限制区域中打破了块。我切换到了Call 1,它没有打破禁区内的区块。
这让我回到原来的问题。我可以重新编译ToolBelt.jar,唯一的区别是Call 1 vs Call 2并可靠地重现问题。如果调用1已就绪,则会遵循区域支持,但案例3不会更新客户端。如果调用2已到位,则客户端始终获取块更新,但是他们可以删除任何区域中的块。
我可以通过不允许案例3(在范围内没有物理移除)和使用调用1来解决问题,但是我不想牺牲工具的能力。当Call 1没有问题时,有没有人知道为什么Call 2和Call 2.1不能与区域一起工作?
感兴趣的文档链接:
Block:表示一个块。这是一个活动对象,世界上任何给定位置只能存在一个Block。
Player:表示已连接或未连接的播放器
.isCanceled():获取此事件的取消状态。取消的事件不会在服务器中执行,但仍会传递给其他插件
.sendBlockChange():发送一个块更改。这为某个位置的用户伪造了一个块更改包。这实际上不会以任何方式改变世界。
答案 0 :(得分:3)
这个问题的水平比我发布的要高。很抱歉没有包含足够的数据。最初的案例1调用是:
if(isUseEvent())
safeBreak(target,event.getPlayer(),physics);
else {
target.setTypeId(0,physics);
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
案例2调用是
if(isUseEvent())
if(safeBreak(target,event.getPlayer(),physics))
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
else {
target.setTypeId(0,physics);
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
但是,因为我没有将if(safeBreak()) doStuff;
包裹在{}中,所以它意味着else排列了最内层的if()
语句。因此,正确的格式将显示:
if(isUseEvent())
if(safeBreak(target,event.getPlayer(),physics))
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
else {
target.setTypeId(0,physics);
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
这可以通过不采用愚蠢的快捷方式并正确包装我的if() {doStuff;}
if(isUseEvent()) {
if(safeBreak(target,event.getPlayer(),physics)) {
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
}else {
target.setTypeId(0,physics);
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
答案 1 :(得分:0)
检查l-value对生成l值的代码没有影响。这意味着if语句的“then”部分中的代码可能是罪魁祸首。
根据您正在集成的第三方代码的设计方式,异常等内容可能会导致类似回滚的行为。
尝试在if块中使用简单的语句(而不是“无害的打印消息”),您应该能够自己验证:
if(safeBreak(target,event.getPlayer(),physics))
{
}