java - 如何在 Bukkit 模组中使用 Minecraft 的 WorldEdit 撤消堆栈
问题描述
我正在尝试在 Bukkit mod 中更新 Minecraft 中的块,并能够//undo
在 Minecraft 中进行这些更改。我可以改变块,但我不能//undo
改变。
由于谷歌没有帮助我找到解决方案,我一定错过了一些简单的东西。
这是我的模组。它将当前选定区域的单个块设置为空气。注释掉的行是我尝试过的对我不起作用的东西。
public class Main extends JavaPlugin implements Listener
{
// ... //
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
{
if (command.getName().equalsIgnoreCase("setair"))
{
org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) sender;
WorldEditPlugin worldEditPlugin = null;
worldEditPlugin = (WorldEditPlugin) Bukkit.getServer().getPluginManager().getPlugin("WorldEdit");
if(worldEditPlugin == null){
bukkitPlayer.sendMessage("Error: WorldEdit is null.");
}
else
{
com.sk89q.worldedit.bukkit.selections.Selection s = worldEditPlugin.getSelection(bukkitPlayer);
com.sk89q.worldedit.LocalSession localSession = worldEditPlugin.getSession(bukkitPlayer);
com.sk89q.worldedit.world.World localWorld = localSession.getSelectionWorld();
com.sk89q.worldedit.bukkit.BukkitPlayer wrappedPlayer = worldEditPlugin.wrapPlayer(bukkitPlayer);
com.sk89q.worldedit.LocalPlayer localPlayer = wrappedPlayer;
//com.sk89q.worldedit.world.World localWorld2 = localPlayer.getWorld();
com.sk89q.worldedit.EditSession editSession = worldEditPlugin.getWorldEdit().getEditSessionFactory().getEditSession(localWorld, -1, localPlayer);
//com.sk89q.worldedit.EditSession editSession = worldEditPlugin.createEditSession(bukkitPlayer);
//localSession.remember(editSession);
Vector minV = s.getNativeMinimumPoint();
try {
editSession.setBlock(minV, new com.sk89q.worldedit.blocks.BaseBlock(0,0));
} catch (MaxChangedBlocksException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//try {
// localWorld.setBlock(minV, new com.sk89q.worldedit.blocks.BaseBlock(0,0));
//} catch (WorldEditException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
localSession.getRegionSelector(localWorld).learnChanges();
localSession.getRegionSelector(localWorld).explainRegionAdjust(localPlayer, localSession);
bukkitPlayer.performCommand("tellraw @p \"Done setair\"");
}
return true;
}
}
}
编辑:这是有效的。感谢sorifiend在下面的回答。为了让它工作,我还必须localSession.remember(editSession)
在 setBlock 调用之后移动。
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
{
if (command.getName().equalsIgnoreCase("setair"))
{
org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) sender;
WorldEditPlugin worldEditPlugin = null;
worldEditPlugin = (WorldEditPlugin) Bukkit.getServer().getPluginManager().getPlugin("WorldEdit");
if(worldEditPlugin == null){
bukkitPlayer.sendMessage("Error: WorldEdit is null.");
}
else
{
com.sk89q.worldedit.bukkit.selections.Selection s = worldEditPlugin.getSelection(bukkitPlayer);
com.sk89q.worldedit.LocalSession localSession = worldEditPlugin.getSession(bukkitPlayer);
com.sk89q.worldedit.EditSession editSession = worldEditPlugin.createEditSession(bukkitPlayer);
Vector minV = s.getNativeMinimumPoint();
try {
editSession.setBlock(minV, new com.sk89q.worldedit.blocks.BaseBlock(0,0));
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
localSession.remember(editSession);
bukkitPlayer.performCommand("tellraw @p \"Done setair\"");
}
return true;
}
}
现在我可以用 WorldEdit 选择一些东西,运行/setair
以将其中一个块设置为空气。并//undo
做你所期望的。
解决方案
我不明白为什么这不起作用editSession = worldEditPlugin.createEditSession(bukkitPlayer);
,但是因为您选择了更长的方式worldEditPlugin.getWorldEdit().getEditSessionFactory().getEditSession(bukkitPlayer)
,您还需要使用:editSession.enableQueue();
之后。
下一个问题可能是您如何设置块。快速查看源代码setBlock
中的方法。有一个数字表明:
/** * Set a block, bypassing history but still utilizing block re-ordering. * * @param position the position to set the block at * @param block the block * @return whether the block changed */ public boolean setBlock(Vector position, BlockStateHolder block) {
请注意它是如何说“设置一个块,绕过历史记录和块重新排序”的。
因此,如果您想记住块更改,您需要自己跟踪它,或者使用不同的 setBlock 方法:
/** * Sets the block at a position, subject to both history and block re-ordering. * * @param position the position * @param pattern a pattern to use * @return Whether the block changed -- not entirely dependable * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public boolean setBlock(Vector position, Pattern pattern)
请注意它是如何说“将块设置在一个位置,受历史记录和块重新排序的影响”。
例如,这会将一个块设置为空,并将保留块历史:
Pattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState());
editSession.setBlock(minV, pattern);
现在您可以像这样稍后使用 undo 方法:
//use a different EditSession to perform the undo in:
EditSession undoSession = ......;
editSession.undo(undoSession);
请注意,undoSession
不应与您尝试撤消的会话相同。
编辑:源代码目前正在为 1.13 版支持进行一些编辑/更改(EditSession 类在 23 小时前更新)。因此,在继续之前,您的 WorldEdit 库/插件可能需要更新。
推荐阅读
- java - 无论如何,使用 rs.next() 加载 java 数组都会引发空指针错误。用控制台检查
- r - data.table 未正确过滤
- oauth-2.0 - “MalformedResponse:由于语音响应为空,无法将 Dialogflow 响应解析为 AppResponse”在 OAuth 帐户链接流程中
- python - 无头浏览器与 Youtube 一起使用
- javascript - Flow 中的联合数组类型。类型 A 中缺少属性,但类型 B 中存在
- angular - goBack 路由后重新加载选项卡视图(Ionic 4)
- ember.js - Ember:从导入的 mixin 中覆盖属性?
- python - 登录后将用户带到新页面的Tkinter登录页面?
- python - 根据关联值将值连接到多列
- python - Keras evaluate() 和 predict() 结果太离谱了