• 欢迎来到Minecraft插件百科!
  • 对百科编辑一脸懵逼?帮助:快速入门带您快速熟悉百科编辑!
  • 因近日遭受攻击,百科现已限制编辑,有意编辑请加入插件百科企鹅群:223812289

WorldEdit/CraftScript:修订间差异

来自Minecraft插件百科
跳转到导航 跳转到搜索
(翻译完成,移除待翻译模板)
 
(未显示4个用户的20个中间版本)
第1行: 第1行:
{{模板:待翻译}}
[[分类:开发教程]]


Scripting in WorldEdit allows you to write world manipulation code without having to learn Java or compile your code. Scripts, called ''CraftScripts'' in WorldEdit, and are written in JavaScript and go into your '''craftscripts/''' directory. The advantages of writing scripts with WorldEdit are:
WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作''CraftScripts'',并且这一切都基于JavaScript和你的'''craftscripts/''' 文件. 使用基于WorldEdit写的脚本有这些优点:


* Hook right into WorldEdit's undo/redo system
* 能够与WorldEdit的 undo(撤销)/redo(反撤销) 功能对接
* Use WorldEdit's block place prioritization
* 能够使用WorldEdit来优化编辑方块的操作
* Accept WorldEdit's powerful block type syntax //set sign:3|How|are|you?
* 允许使用WorldEdit强大的方块类型语法 //set sign:3|How|are|you?
* Get the region selected by the user
* 能够轻易获取用户选择的区域空间


The Mozilla Rhino JavaScript engine bundled with Java 6 and above is used to evaluate the scripts. However, if an independent version of Rhino is found in WorldEdit's classpath, it will be used instead. For maximum portability, write scripts for Java's built-in version of Rhino.  
此脚本需要通过Mozilla Rhino JavaScript在Java 6 或更高版本上运行。但是,如果WorldEdit的路径下有一个独立的Rhino版本,它会被优先使用。为了最大化的兼容性,请在Rhino的Java稳定版本上编写脚本。
脚本支持在v0.8时曾被移除。在v2.13后,脚本支持被重新加入。然而v0.8或更低的版本的脚本并不能兼容。
{{warning|请不要运行来自不受信任的来源的脚本。}}


Scripting support was re-added in v2.13 after having been removed in v0.8. However, scripts written for v0.8 and below are not compatible.
请查看 [http://docs.sk89q.com/ WorldEdit的API文档].
 
{{warning|Do not run scripts from untrusted sources.}}
 
Check out [http://docs.sk89q.com/ WorldEdit's API documentation].


== 介绍 ==
== 介绍 ==
第20行: 第18行:
脚本有以下在他们的命名空间中的三个变量:
脚本有以下在他们的命名空间中的三个变量:


* <code>context</code> is an instance of [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html CraftScriptContext]
* <code>context</code> 是一个 [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html CraftScriptContext] 的实例。
* <code>player</code> is a copy of the player, an instance of [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/LocalPlayer.html LocalPlayer]
* <code>player</code> 是一个玩家的附件,是 [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/LocalPlayer.html LocalPlayer] 的实例。
* <code>argv</code> is a Java array of arguments as strings
* <code>argv</code> 是一个String类型的Java数组


想要运行一个脚本,请使用指令 /cs YourScript.js
想要运行一个脚本,请使用指令 /cs YourScript.js
第28行: 第26行:
== 在方块上工作 ==
== 在方块上工作 ==


在WorldEdit中所有的方块编辑操作都基于一个 <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/EditSession.html EditSession]</code>. This object handles history and block placement order all automatically. To get an edit session for your own script, use:
在WorldEdit中所有的方块编辑操作都基于一个 <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/EditSession.html EditSession]</code>. 这个对象会自动处理历史和方块放置的顺序。为了得到你自己的脚本的一个编辑样本,请使用:
 
<source lang="java">
  var sess = context.remember();
  var sess = context.remember();
 
</source>
任何时候你调用这个方法,你都会得到一个新的 <code>EditSession</code>, 所以一定要保持一个左右。要设置一个方块,而不是给一个方块的物品ID。你给一个<code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/BaseBlock.html BaseBlock]</code>. The reason is that blocks contain data (and in some cases, complex data like chest contents), and if only block types were passed around, a lot of data would be lost. <code>BaseBlock</code> is an independent representation of a block; it doesn't know where it is in the world. That means that you can pass a <code>BaseBlock</code> around everywhere and reuse it. <code>BaseBlock</code>s remember block type and block data. For more complex blocks such as signs and chests, you will use a <code>BaseBlock</code> derivative such as <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/SignBlock.html SignBlock]</code>.
任何时候你调用这个方法,你都会得到一个新的 <code>EditSession</code>, 所以一定要保持一个左右。要设置一个方块,而不是给一个方块的物品ID。你给一个<code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/BaseBlock.html BaseBlock]</code>. 这是因为方块包含各种各样的数据(如箱子方块里面的物品),如果只有方块类型ID的话,很多数据就会被丢失。 <code>BaseBlock</code> 与block是独立的,他并不能获取得到对象所在的世界。这意味着你可以传递一个<code>BaseBlock</code> 到任何地方并重复使用他。 <code>BaseBlock</code>们记录着方块种类和数据。对于一些复杂的方块,比如说告示牌和箱子,你可以使用<code>BaseBlock</code> 就像这样<code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/SignBlock.html SignBlock]</code>.


举个例子:<br/>
举个例子:<br/>
Setting a cloth block with color value 4
设置一个带有4号颜色的羊毛方块
<br/>
<br/>
<pre>
<source lang="java">
importPackage(Packages.com.sk89q.worldedit.blocks);
importPackage(Packages.com.sk89q.worldedit.blocks);
var sess = context.remember();
var sess = context.remember();
sess.setBlock(player.getBlockOn(), new BaseBlock(BlockID.CLOTH, 4));</pre>}}
sess.setBlock(player.getBlockOn(), new BaseBlock(BlockID.CLOTH, 4));</source>


Note that because <code>BaseBlock</code> is in the ''com.sk89q.worldedit.blocks'' namespace, it had to be imported first. <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/BlockID.html BlockID]</code> has a list of block types. The first argument for <code>setBlock()</code> is a <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/Vector.html Vector]</code> indicating the position in the world.
标记这个是因为 <code>BaseBlock</code> 是在''com.sk89q.worldedit.blocks'' 的命名空间,它必须被引入先. <code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/blocks/BlockID.html BlockID]</code> 有一个方块类型的列表. <code>setBlock()</code>方法的第一个参数是一个表示在一个世界的位置的<code>[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/Vector.html Vector]</code>


想要得到方块,使用基于<code>EditSession</code>的<code>getBlock()</code>函数。你将也能得到一个<code>BaseBlock</code>。
想要得到方块,使用基于<code>EditSession</code>的<code>getBlock()</code>函数。你将也能得到一个<code>BaseBlock</code>。
第48行: 第46行:
== 处理参数 ==
== 处理参数 ==


Arguments are passed in under the <code>argv</code> variable. 如果你需要去检查用户提供的参数是不是正确的,你可以用 <code>CraftScriptContext.[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#checkArgs%28int,%20int,%20java.lang.String%29 checkArgs]()</code>.
Arguments由<code>argv</code>变量传递。如果你需要去检查用户提供的参数是不是正确的,你可以用 <code>CraftScriptContext.[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#checkArgs%28int,%20int,%20java.lang.String%29 checkArgs]()</code>.


举个例子:Checking arguments<br/>
举个例子:检查参数<br/>
<pre>context.checkArgs(1, 3, "<block> [width] [height]");</pre>
<source lang="java">context.checkArgs(1, 3, "<block> [width] [height]");</source>


如果你要去处理一个方块名字使其成为<code>BaseBlock</code>, 你可以使用 <code>CraftScriptContext.[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#getBlock%28java.lang.String%29 getBlock]()</code>. That method checks the block blacklist, however. If you need a block for, for example, replacing, you can ignore the blacklist by [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#getBlock%28java.lang.String,%20boolean%29 adding a boolean "true" for a third parameter].
如果你要去处理一个方块名字使其成为<code>BaseBlock</code>, 你可以使用 <code>CraftScriptContext.[http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#getBlock%28java.lang.String%29 getBlock]()</code>. 这个方法可以检查方块黑名单, however. 如果你需要一个方块去, 比如说, 替换, 你可以 ignore the blacklist by [http://docs.sk89q.com/worldedit/apidocs/com/sk89q/worldedit/scripting/CraftScriptContext.html#getBlock%28java.lang.String,%20boolean%29 adding a boolean "true" for a third parameter].


举个例子:Getting the passed in block<br/>
举个例子:Getting the passed in block<br/>
<pre>
<source lang="java">
context.checkArgs(1, 3, "<block> [width] [height]");
context.checkArgs(1, 3, "<block> [width] [height]");
var block = context.getBlock(argv[1]);
var block = context.getBlock(argv[1]);
</pre>
</source>


What happens if the user inputs an invalid block? An exception will be raised and if you don't catch it, the user will be informed about their error and your script will be halted.
如果用户输入的是一个无效的方块的话,将会抛出一个异常。并且,抛出异常后如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,就不会再进行下去。


== Working with Java packages ==
== 配合使用Java包 ==


To import a java package, you can use the following syntax:
你可以通过使用以下的语法来引入一个Java包:


  importPackage(Packages.package.name.here);
  importPackage(Packages.package.name.here);


Tip: The "Packages." prefix is not required if you installed Mozilla's Rhino library, but to keep portability with the default bundle of Rhino in Java, it is recommended that you use it.
注意:如果你安装了Mozilla's Rhino库,则不需要"Packages."前缀,但为了保持在默认的Java Rhino上运行的稳定性,"Packages."前缀是推荐的。
 
当安装了以后,你可以使用所有Java的扩展库,以及所有WorldEdit的类。
You have access to all of Java's vast library as it is installed. WorldEdit's classes are also fully available.


== 例程 ==
== 例程 ==


例子:设置附近的发射器装满箭
例子:设置附近的发射器装满箭
<pre>
<source lang="java">
importPackage(Packages.com.sk89q.worldedit.blocks);
importPackage(Packages.com.sk89q.worldedit.blocks);


第103行: 第100行:
         }
         }
     }
     }
}</pre>
}</source>


Example: Maze generation script
例子: 迷宫生成脚本
<pre>
<source lang="java">
importPackage(Packages.com.sk89q.worldedit);
importPackage(Packages.com.sk89q.worldedit);
importPackage(Packages.com.sk89q.worldedit.blocks);
importPackage(Packages.com.sk89q.worldedit.blocks);
第208行: 第205行:
         sess.setBlock(origin.add(x * 2 - 1, 1, y * 2 - 1), block);
         sess.setBlock(origin.add(x * 2 - 1, 1, y * 2 - 1), block);
     }
     }
}</pre>
}</source>

2016年8月15日 (一) 12:50的最新版本


WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作CraftScripts,并且这一切都基于JavaScript和你的craftscripts/ 文件. 使用基于WorldEdit写的脚本有这些优点:

  • 能够与WorldEdit的 undo(撤销)/redo(反撤销) 功能对接
  • 能够使用WorldEdit来优化编辑方块的操作
  • 允许使用WorldEdit强大的方块类型语法 //set sign:3|How|are|you?
  • 能够轻易获取用户选择的区域空间

此脚本需要通过Mozilla Rhino JavaScript在Java 6 或更高版本上运行。但是,如果WorldEdit的路径下有一个独立的Rhino版本,它会被优先使用。为了最大化的兼容性,请在Rhino的Java稳定版本上编写脚本。 脚本支持在v0.8时曾被移除。在v2.13后,脚本支持被重新加入。然而v0.8或更低的版本的脚本并不能兼容。 请不要运行来自不受信任的来源的脚本。

请查看 WorldEdit的API文档.

介绍

脚本有以下在他们的命名空间中的三个变量:

  • context 是一个 CraftScriptContext 的实例。
  • player 是一个玩家的附件,是 LocalPlayer 的实例。
  • argv 是一个String类型的Java数组

想要运行一个脚本,请使用指令 /cs YourScript.js

在方块上工作

在WorldEdit中所有的方块编辑操作都基于一个 EditSession. 这个对象会自动处理历史和方块放置的顺序。为了得到你自己的脚本的一个编辑样本,请使用:

 var sess = context.remember();

任何时候你调用这个方法,你都会得到一个新的 EditSession, 所以一定要保持一个左右。要设置一个方块,而不是给一个方块的物品ID。你给一个BaseBlock. 这是因为方块包含各种各样的数据(如箱子方块里面的物品),如果只有方块类型ID的话,很多数据就会被丢失。 BaseBlock 与block是独立的,他并不能获取得到对象所在的世界。这意味着你可以传递一个BaseBlock 到任何地方并重复使用他。 BaseBlock们记录着方块种类和数据。对于一些复杂的方块,比如说告示牌和箱子,你可以使用BaseBlock 就像这样SignBlock.

举个例子:
设置一个带有4号颜色的羊毛方块

importPackage(Packages.com.sk89q.worldedit.blocks);
var sess = context.remember();
sess.setBlock(player.getBlockOn(), new BaseBlock(BlockID.CLOTH, 4));

标记这个是因为 BaseBlock 是在com.sk89q.worldedit.blocks 的命名空间,它必须被引入先. BlockID 有一个方块类型的列表. setBlock()方法的第一个参数是一个表示在一个世界的位置的Vector

想要得到方块,使用基于EditSessiongetBlock()函数。你将也能得到一个BaseBlock

处理参数

Arguments由argv变量传递。如果你需要去检查用户提供的参数是不是正确的,你可以用 CraftScriptContext.checkArgs().

举个例子:检查参数

context.checkArgs(1, 3, "<block> [width] [height]");

如果你要去处理一个方块名字使其成为BaseBlock, 你可以使用 CraftScriptContext.getBlock(). 这个方法可以检查方块黑名单, however. 如果你需要一个方块去, 比如说, 替换, 你可以 ignore the blacklist by adding a boolean "true" for a third parameter.

举个例子:Getting the passed in block

context.checkArgs(1, 3, "<block> [width] [height]");
var block = context.getBlock(argv[1]);

如果用户输入的是一个无效的方块的话,将会抛出一个异常。并且,抛出异常后如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,就不会再进行下去。

配合使用Java包

你可以通过使用以下的语法来引入一个Java包:

importPackage(Packages.package.name.here);

注意:如果你安装了Mozilla's Rhino库,则不需要"Packages."前缀,但为了保持在默认的Java Rhino上运行的稳定性,"Packages."前缀是推荐的。 当安装了以后,你可以使用所有Java的扩展库,以及所有WorldEdit的类。

例程

例子:设置附近的发射器装满箭

importPackage(Packages.com.sk89q.worldedit.blocks);

var session = context.remember();
var origin = player.getPosition();

var arrows = new BaseItemStack(262, 64);

var items = [arrows, arrows, arrows,
             arrows, arrows, arrows,
             arrows, arrows, arrows]

for (var x = -4; x <= 4; x++) {
    for (var y = -4; y <= 4; y++) {
        for (var z = -4; z <= 4; z++) {
            var pt = origin.add(x, y, z);
            var id = session.getBlockType(pt);
            
            if (id == BlockID.DISPENSER) {
                var block = session.getBlock(pt);
                block.setItems(items);
                session.setBlock(pt, block);
                
                player.print("Arrows set @ " + pt);
            }
        }
    }
}

例子: 迷宫生成脚本

importPackage(Packages.com.sk89q.worldedit);
importPackage(Packages.com.sk89q.worldedit.blocks);

context.checkArgs(1, 3, "<block> [width] [height]");

var sess = context.remember();

// This may throw an exception that is caught by the script processor
var block = context.getBlock(argv[1]);
var w = argv.length > 2 ? parseInt(argv[2]) : 5;
var h = argv.length > 3 ? parseInt(argv[3]) : 5;

function id(x, y) {
    return y * (w + 1) + x;
}

function $x(i) {
    return i % (w + 1);
}

function $y(i) {
    return Math.floor(i / (w + 1));
}

function shuffle(arr) {
    var i = arr.length;
    if (i == 0) return false;
    while (--i) {
        var j = Math.floor(Math.random() * (i + 1));
        var tempi = arr[i];
        var tempj = arr[j];
        arr[i] = tempj;
        arr[j] = tempi;
    }
}

var stack = [];
var visited = {};
var noWallLeft = new Array(w * h);
var noWallAbove = new Array(w * h);
var current = 0;

stack.push(id(0, 0))

while (stack.length > 0) {
    var cell = stack.pop();
    var x = $x(cell), y = $y(cell);
    visited[cell] = true;
    
    var neighbors = []
    
    if (x > 0) neighbors.push(id(x - 1, y));
    if (x < w - 1) neighbors.push(id(x + 1, y));
    if (y > 0) neighbors.push(id(x, y - 1));
    if (y < h - 1) neighbors.push(id(x, y + 1));
    
    shuffle(neighbors);
    
    while (neighbors.length > 0) {
        var neighbor = neighbors.pop();
        var nx = $x(neighbor), ny = $y(neighbor);
        
        if (visited[neighbor] != true) {
            stack.push(cell);
            
            if (y == ny) {
                if (nx < x) {
                    noWallLeft[cell] = true;
                } else {
                    noWallLeft[neighbor] = true;
                }
            } else {
                if (ny < y) {
                    noWallAbove[cell] = true;
                } else {
                    noWallAbove[neighbor] = true;
                }
            }
            
            stack.push(neighbor);
            break;
        }
    }
}

var origin = player.getBlockIn();

for (var y = 0; y <= h; y++) {
    for (var x = 0; x <= w; x++) {
        var cell = id(x, y)
        if (!noWallLeft[cell] && y < h) {
            sess.setBlock(origin.add(x * 2 - 1, 0, y * 2), block);
            sess.setBlock(origin.add(x * 2 - 1, 1, y * 2), block);
        }
        if (!noWallAbove[cell] && x < w) {
            sess.setBlock(origin.add(x * 2, 0, y * 2 - 1), block);
            sess.setBlock(origin.add(x * 2, 1, y * 2 - 1), block);
        }
        sess.setBlock(origin.add(x * 2 - 1, 0, y * 2 - 1), block);
        sess.setBlock(origin.add(x * 2 - 1, 1, y * 2 - 1), block);
    }
}