• 因近日遭受攻击,百科现已限制新用户的编辑权限,一段时间后成为自动确认用户方可编辑。

Difference between revisions of "WorldEdit/CraftScript"

From Minecraft插件百科
Jump to: navigation, search
(翻译首段)
(翻译完成,移除待翻译模板)
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
[[分类:开发教程]]
 
[[分类:开发教程]]
{{模板:待翻译}}
 
  
WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作''CraftScripts'',并且这一切都基于JavaScript and go into your '''craftscripts/''' 文件. 使用基于WorldEdit写的脚本有这些优点:
+
WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作''CraftScripts'',并且这一切都基于JavaScript和你的'''craftscripts/''' 文件. 使用基于WorldEdit写的脚本有这些优点:
  
 
* 能够与WorldEdit的 undo(撤销)/redo(反撤销) 功能对接
 
* 能够与WorldEdit的 undo(撤销)/redo(反撤销) 功能对接
 
* 能够使用WorldEdit来优化编辑方块的操作
 
* 能够使用WorldEdit来优化编辑方块的操作
* Accept WorldEdit's powerful block type syntax //set sign:3|How|are|you?
+
* 允许使用WorldEdit强大的方块类型语法 //set sign:3|How|are|you?
 
* 能够轻易获取用户选择的区域空间
 
* 能够轻易获取用户选择的区域空间
  
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稳定版本上编写脚本。
此脚本需要通过Mozilla Rhino JavaScript在Java 6 或更高版本上运行。但是,如果WorldEdit的路径下有一个独立的Rhino版本,它会被优先使用。为了最大化的兼容性,请在Rhino的Java稳定版本上编写。
 
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.
 
 
脚本支持在v0.8时曾被移除。在v2.13后,脚本支持被重新加入。然而v0.8或更低的版本的脚本并不能兼容。
 
脚本支持在v0.8时曾被移除。在v2.13后,脚本支持被重新加入。然而v0.8或更低的版本的脚本并不能兼容。
{{warning|请不要运行来自不受信任的来源的脚本。}
+
{{warning|请不要运行来自不受信任的来源的脚本。}}
  
 
请查看 [http://docs.sk89q.com/ WorldEdit的API文档].
 
请查看 [http://docs.sk89q.com/ WorldEdit的API文档].
Line 21: Line 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> 是一个String类型的Java数组
 
* <code>argv</code> 是一个String类型的Java数组
  
Line 33: Line 30:
 
  var sess = context.remember();
 
  var sess = context.remember();
 
</source>
 
</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/>
 
<source lang="java">
 
<source lang="java">
Line 43: Line 40:
 
sess.setBlock(player.getBlockOn(), new BaseBlock(BlockID.CLOTH, 4));</source>
 
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>。
Line 49: Line 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>.
  
 
举个例子:检查参数<br/>
 
举个例子:检查参数<br/>
Line 62: Line 59:
 
</source>
 
</source>
  
如果用户输入的是一个无效的方块会怎么样?会抛出一个异常。并且如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,不再进行下去。
+
如果用户输入的是一个无效的方块的话,将会抛出一个异常。并且,抛出异常后如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,就不会再进行下去。
  
 
== 配合使用Java包 ==
 
== 配合使用Java包 ==
Line 105: Line 102:
 
}</source>
 
}</source>
  
Example: Maze generation script
+
例子: 迷宫生成脚本
 
<source lang="java">
 
<source lang="java">
 
importPackage(Packages.com.sk89q.worldedit);
 
importPackage(Packages.com.sk89q.worldedit);

Latest revision as of 20:50, 15 August 2016


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或更低的版本的脚本并不能兼容。 Warning.png 请不要运行来自不受信任的来源的脚本。

请查看 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);
    }
}