0

所以我正在为 Minecraft 地形操作程序 MCEdit 编写一个过滤器。该过滤器是用 Python 2 编写的(这是 MCEdit 将读取的唯一内容)。MCEdit 通过将变量级别(MCLevel 类型)、框和选项传递给用户定义的函数执行(级别、框、选项)来调用过滤器。您可以在此处找到关于此的文档 >> https://github.com/mcedit/pymclevel

我以前写过多个过滤器,所以我知道它是如何工作的。这是我的代码:

from pymclevel import *
import random

inputs = (("Replace", (0, 1, 255)), ("Of Damage", (0, 0, 15)), ("With", (1, 1, 255)), ("Of Damage ", (0, 0, 15)), ("This Percent of the Time", (50, 0, 100)), ("If it is Beside", (False)), ("Or Diagonal", (False)), ("Exclusively", (False)), ("To", (0, 1, 255)), ("Of Damage  ", (0, 0, 15)))

def getBlock(x, y, z):
    global level
    return (level.blockAt(x, y, z), level.blockDataAt(x, y, z))

def setBlock(x, y, z, block, data):
    global level
    level.setBlockAt(x, y, z, block)
    level.setBlockDataAt(x, y, z, data)

def IsBeside(x, y, z, block, data):
    return (getBlock(x - 1, y, z) == (block, data) or getBlock(x + 1, y, z) == (block, data) or getBlock(x, y - 1, z) == (block, data) or getBlock(x, y + 1, z) == (block, data) or getBlock(x, y, z - 1) == (block, data) or getBlock(x, y, z + 1) == (block, data))

def IsDiagonal(x, y, z, block, data):
    return (getBlock(x - 1, y - 1, z) == (block, data) or getBlock(x - 1, y, z - 1) == (block, data) or getBlock(x, y - 1, z - 1) == (block, data) or getBlock(x + 1, y + 1, z) == (block, data) or getBlock(x + 1, y, z + 1) == (block, data) or getBlock(x, y + 1, z + 1) == (block, data) or getBlock(x + 1, y + 1, z + 1) == (block, data) or getBlock(x - 1, y + 1, z + 1) == (block, data) or getBlock(x + 1, y - 1, z + 1) == (block, data) or getBlock(x + 1, y + 1, z - 1) == (block, data) or getBlock(x - 1, y - 1, z + 1) == (block, data) or getBlock(x - 1, y + 1, z - 1) == (block, data) or getBlock(x + 1, y - 1, z - 1) == (block, data) or getBlock(x - 1, y - 1, z - 1) == (block, data))

def perform(level, box, options):

    Replace = options["Replace"]
    ReplaceData = options["Of Damage"]
    With = options["With"]
    WithData = options["Of Damage "]
    Percent = options["This Percent of the Time"]
    Beside = options["If it is Beside"]
    Diagonal = options["Or Diagonal"]
    Exclusive = options["Exclusively"]
    Check = options["To"]
    CheckData = options["Of Damage  "]

    mark = False

    for x in xrange(box.minx, box.maxx + 1):
        for z in xrange(box.minz, box.maxz + 1):
            for y in xrange(box.miny, box.maxy + 1):
                if random.randint(1, 100) <= Percent and getBlock(x, y, z) == (Replace, ReplaceData):

                    if Beside and not Diagonal and not Exclusive:
                        if IsBeside(x, y, z, Check, CheckData):
                            mark = True

                    elif not Beside and Diagonal and not Exclusive:
                        if IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif Beside and not Diagonal and Exclusive:
                        if IsBeside(x, y, z, Check, CheckData) and not IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif not Beside and Diagonal and Exclusive:
                        if not IsBeside(x, y, z, Check, CheckData) and IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif Beside and Diagonal:
                        if IsBeside(x, y, z, Check, CheckData) and IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    else:
                        mark = True

                    if mark:
                        level.setBlock(x, y, z, With, WithData)
                        mark = False

我的问题是我需要多次调用 getBlock 和 setBlock ,而且很可能该级别将包含大量信息(足以将其复制到函数中需要几秒钟)。通过扩展,这意味着过滤器可以轻松运行数小时,其中大部分时间只是用于复制级别。当然,我不想这样做,而且由于 python 没有按引用传递,而且我无法访问传递给 perform 的原始变量,我只能尝试访问传递给 perform 的 level 的实例其他功能。这就是全局的东西进来的地方,这显然是行不通的。有谁知道在不将 level 作为函数参数传递给 getBlock 和 setBlock 的情况下进行这项工作的方法?我不在乎它是否使用全局,这只是我的想法。

4

1 回答 1

1

您是否运行过这段代码并确认它实际上很慢?Python 不使用按值传递或按引用传递,而是使用按赋值传递进行参数传递。一开始可能很难掌握,但这样做有一些重要的原因。据我所知,在 python 中将非常大的对象传递给函数并不像在 C/C++ 中那样麻烦,因为您不是将对象数据从一个内存位置复制到另一个内存位置,而是将赋值数据。我经常听到它称为“按值传递引用”,这意味着您正在按值传递引用。这很令人困惑,我更喜欢这种解释:Code like a pythonista

如果您想更改被调用者中参数的内容或值,并将这些更改反映在外部范围中,有多种方法可以做到这一点。如果参数总是可变的(例如列表),那么您可以在被调用者中修改它们没有问题,只要您的修改是就地的,例如没有重新分配。如果它们是不可变的,最好的办法是只返回一个已更改对象的元组。您还可以查看 pass-by-assignment 文章中的其他技术(与上面相同的链接)。

希望我没有让你更困惑。:) 祝你好运!

PS 如果您有时间,请像 pythonista 一样阅读其余的代码。这是一个非常快速的阅读和完整的提示,可以让你的 python 编码更顺利。

于 2014-11-30T02:19:07.207 回答