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

Difference between revisions of "WorldEdit/CraftScript"

From Minecraft插件百科
Jump to: navigation, search
(在方块上工作: 翻译部分)
(翻译完成,移除待翻译模板)
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
[[分类:开发教程]]
 
[[分类:开发教程]]
{{模板:待翻译}}
 
  
 
WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作''CraftScripts'',并且这一切都基于JavaScript和你的'''craftscripts/''' 文件. 使用基于WorldEdit写的脚本有这些优点:
 
WorldEdit里的脚本可以让你不用Java和编译你的代码,方便地写一个操控世界的代码。这个脚本在WorldEdit中被称作''CraftScripts'',并且这一切都基于JavaScript和你的'''craftscripts/''' 文件. 使用基于WorldEdit写的脚本有这些优点:
Line 19: 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 31: 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>. 这是因为方块包含各种各样的数据(如箱子方块里面的物品),如果只有方块类型ID的话,很多数据就会被丢失。 <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 41: 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 60: Line 59:
 
</source>
 
</source>
  
如果用户输入的是一个无效的方块会怎么样?会抛出一个异常。并且如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,不再进行下去。
+
如果用户输入的是一个无效的方块的话,将会抛出一个异常。并且,抛出异常后如果你没有去捕捉他,用户就会被提示这个异常,然后这个脚本就会被终止,就不会再进行下去。
  
 
== 配合使用Java包 ==
 
== 配合使用Java包 ==
Line 103: 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);
    }
}