[英]How to use Minecraft's WorldEdit undo stack in a Bukkit mod
I am trying to update blocks in Minecraft within a Bukkit mod and be able to //undo
those changes within Minecraft. 我试图在Bukkit mod中更新Minecraft中的块,并且能够//undo
在Minecraft中//undo
这些更改。 I can change the block but I cannot //undo
the change. 我可以更改块,但我不能//undo
更改。
I must be missing something simple since Google hasn't helped me find a solution. 我一定错过了一些简单的东西,因为谷歌没有帮我找到解决方案。
Here is my mod. 这是我的mod。 It sets a single block from the currently selected region to air. 它将当前所选区域中的单个块设置为空中。 The commented out lines are things I have tried that didn't work for me. 注释掉的行是我尝试过的对我不起作用的东西。
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;
}
}
}
EDIT: Here is what works. 编辑:这是有效的。 Thanks sorifiend for the answer below. 感谢sorifiend以下答案。 To get it to work, I also had to move localSession.remember(editSession)
to after the setBlock call. 为了使它工作,我还必须在setBlock调用之后移动localSession.remember(editSession)
。
@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;
}
}
Now I can select something with WorldEdit, run /setair
to set one of the blocks to air. 现在我可以用WorldEdit选择一些东西,运行/setair
来设置其中一个块。 And //undo
does what you'd expect. 并且//undo
做你期望的事情。
I don't understand why this doesn't work editSession = worldEditPlugin.createEditSession(bukkitPlayer);
我不明白为什么这不起作用editSession = worldEditPlugin.createEditSession(bukkitPlayer);
, however because you have chosen to do it the longer way worldEditPlugin.getWorldEdit().getEditSessionFactory().getEditSession(bukkitPlayer)
you will also need to use: editSession.enableQueue();
但是因为你已经选择了做它更长的路worldEditPlugin.getWorldEdit().getEditSessionFactory().getEditSession(bukkitPlayer)
你还需要使用: editSession.enableQueue();
afterwards. 然后。
The next issue may be in how you are setting the block. 下一个问题可能在于您如何设置块。 Take a quick look at the setBlock
methods in the source code . 快速setBlock
源代码中的setBlock
方法。 there is a number that state: 有一个状态:
/** * 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) {
Note how it says "Set a block, bypassing both history and block re-ordering". 请注意它是如何设置“设置块, 绕过历史记录和阻止重新排序”。
So if you want to remember the block change you are going to need to keep track of it yourself, or use a different setBlock method: 因此,如果您想要记住块更改,您需要自己跟踪它,或使用不同的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)
Note how it says "Sets the block at a position, subject to both history and block re-ordering". 请注意它是如何“将块设置在某个位置,同时受历史记录和块重新排序”。
For example this will set a block to air and will also retain the block history: 例如,这将设置一个空格块,并保留块历史记录:
Pattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState());
editSession.setBlock(minV, pattern);
Now you can use the undo method later on like this: 现在您可以稍后使用undo方法,如下所示:
//use a different EditSession to perform the undo in:
EditSession undoSession = ......;
editSession.undo(undoSession);
Note that the undoSession
should not be the same as the session you are trying to undo. 请注意, undoSession
不应与您尝试撤消的会话相同。
Edit: The source code is currently going through a number of edits/changes for version 1.13 support (The EditSession class was updated 23h ago). 编辑:源代码目前正在进行1.13版支持的编辑/更改(EditSession类在23小时前更新)。 So your WorldEdit library/plugin may need updating before you continue. 因此,在继续之前,您的WorldEdit库/插件可能需要更新。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.