gpt4 book ai didi

python - PyYAML 和不寻常的标签

转载 作者:太空狗 更新时间:2023-10-29 17:58:48 26 4
gpt4 key购买 nike

我正在开发一个使用 Unity3D 游戏引擎的项目。对于某些管道要求,最好能够使用 Python 从外部工具更新某些文件。 Unity 的 meta 和 anim 文件在 YAML 中,所以我认为使用 PyYAML 就足够了。

问题是 Unity 的格式使用自定义属性,我不确定如何使用它们,因为所有示例都显示了 Python 和 Ruby 使用的更常见的标签。

以下是文件的顶行:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
...

当我尝试读取文件时,出现此错误:
could not determine a constructor for the tag 'tag:unity3d.com,2011:74'

现在在查看所有其他问题后,这个标签方案似乎与那些问题和答案不一样。例如这个文件使用“!u!”我无法弄清楚它的含义或类似的东西会如何表现(我疯狂的未受过教育的猜测说它看起来像别名或命名空间)。

我可以做一个黑客的方式并去掉标签,但这不是尝试这样做的理想方法。我正在寻求解决方案的帮助,该解决方案将正确处理标签并允许我以保留正确格式的方式解析和编码数据。

谢谢,
-R

最佳答案

我也有这个问题,而且互联网不是很有帮助。在我对这个问题猛烈抨击 3 天之后,我能够解决它……或者至少得到一个可行的解决方案。如果有人想添加更多信息,请做。但这是我得到的。

1) Unity 的 YAML 文件格式的文档(他们称之为“文本场景文件”,因为它包含人类可读的文本)- http://docs.unity3d.com/Manual/TextualSceneFormat.html

它是一种符合 YAML 1.1 的格式。因此,您应该能够使用 PyYAML 或任何其他 Python YAML 库来加载 YAML 对象。

好的,太好了。但它不起作用。每个 YAML 库都有这个文件的问题。

2) 文件格式不正确。事实证明,Unity 文件存在一些语法问题,导致 YAML 解析器出错。具体来说:

2a) 在顶部,它使用 %TAG 指令为字符串“unity3d.com,2011”创建别名。看起来像:

%TAG !u! tag:unity3d.com,2011:

这意味着在您看到“!u!”的任何地方,将其替换为“tag:unity3d.com,2011”。

2b) 然后继续使用“!u!”在每个对象流之前到处都是。但问题是——要符合 YAML 1.1——它实际上应该为每个流声明一个标签别名(任何时候新对象以“---”开头)。在顶部声明一次并且不再声明它只对第一个流有效,而下一个流对“!u!”一无所知,所以它出错了。

此外,这个标签是无用的。它基本上将“tag:unity3d.com,2011”附加到流中的每个条目。我们不关心的。我们已经知道它是一个 Unity YAML 文件。为什么要弄乱数据?

3) 对象类型由 Unity 的类 ID 给出。这是有关的文档:
http://docs.unity3d.com/Manual/ClassIDReference.html

基本上,每个流都被定义为一个新的对象类……对应于该链接中的 ID。所以“游戏对象”是“1”,等等。该行如下所示:
--- !u!1 &100000

所以“---”定义了一个新的流。 “!你!”是“tag:unity3d.com,2011”的别名,“&100000”是这个对象的文件ID(在这个文件中,如果有东西引用这个对象,它使用这个ID....记住YAML是一个节点-基于表示,因此 ID 用于表示节点连接)。

下一行是 YAML 对象的根,它恰好是 Unity 类的名称...例如“GameObject”。所以事实证明我们实际上并不需要从类 ID 转换为人类可读的节点类型。它就在那里。如果您需要使用它,只需使用根节点即可。如果您需要为 Unity 构建一个 YAML 对象,只需根据该文档链接保留一个字典,将“GameObject”转换为“1”等。

另一个问题是大多数 YAML 解析器(PyYAML 是我测试过的)只支持 3 种类型的 YAML 对象:
  • 标量
  • 序列
  • 制图

  • 您可以定义/扩展自定义节点。但这相当于手动编写您自己的 YAML 解析器,因为您必须明确定义每个 YAML 构造函数的创建和输出方式。为什么我要使用像 PyYAML 这样的库,然后继续编写自己的解析器来读取这些自定义节点?使用库的全部意义在于利用以前的工作并从第一天起获得所有功能。我花了 2 天的时间尝试为每个类 ID 统一创建一个新的构造函数。它从未奏效,我陷入了试图正确构建构造函数的杂草中。

    好消息/解决方案:

    事实证明,到目前为止我遇到的所有 Unity 节点都是 YAML 中的基本“映射”节点。所以你可以扔掉自定义节点映射,让 PyYAML 自动检测节点类型。从那里开始,一切都很好!

    在 PyYAML 中,您可以传递文件对象或字符串。因此,我的解决方案是编写一个简单的 5 行预解析器来去除混淆 PyYAML 的位(Unity 语法错误的位)并将这个新字符串提供给 PyYAML。

    1) 完全删除第 2 行,或者直接忽略它:
    %TAG !u! tag:unity3d.com,2011:

    我们不在乎。我们知道这是一个统一文件。标签对我们没有任何作用。

    2) 对于每个流声明,删除标签别名 ("!u!") 并删除类 ID。保留文件 ID。让 PyYAML 将节点自动检测为 Mapping 节点。
    --- !u!1 &100000

    变成……
    --- &100000

    3)其余的,按原样输出。

    预解析器的代码如下所示:
    def removeUnityTagAlias(filepath):
    """
    Name: removeUnityTagAlias()

    Description: Loads a file object from a Unity textual scene file, which is in a pseudo YAML style, and strips the
    parts that are not YAML 1.1 compliant. Then returns a string as a stream, which can be passed to PyYAML.
    Essentially removes the "!u!" tag directive, class type and the "&" file ID directive. PyYAML seems to handle
    rest just fine after that.

    Returns: String (YAML stream as string)


    """
    result = str()
    sourceFile = open(filepath, 'r')

    for lineNumber,line in enumerate( sourceFile.readlines() ):
    if line.startswith('--- !u!'):
    result += '--- ' + line.split(' ')[2] + '\n' # remove the tag, but keep file ID
    else:
    # Just copy the contents...
    result += line

    sourceFile.close()

    return result

    要从 Unity 文本场景文件创建 PyYAML 对象,请对该文件调用预解析器函数:
    import yaml

    # This fixes Unity's YAML %TAG alias issue.
    fileToLoad = '/Users/vlad.dumitrascu/<SOME_PROJECT>/Client/Assets/Gear/MeleeWeapons/SomeAsset_test.prefab'

    UnityStreamNoTags = removeUnityTagAlias(fileToLoad)

    ListOfNodes = list()

    for data in yaml.load_all(UnityStreamNoTags):
    ListOfNodes.append( data )

    # Example, print each object's name and type
    for node in ListOfNodes:
    if 'm_Name' in node[ node.keys()[0] ]:
    print( 'Name: ' + node[ node.keys()[0] ]['m_Name'] + ' NodeType: ' + node.keys()[0] )
    else:
    print( 'Name: ' + 'No Name Attribute' + ' NodeType: ' + node.keys()[0] )

    希望有帮助!

    -弗拉德

    附注。回答下一个问题,使其可用:

    您还需要遍历整个项目目录并解析“GUID”的所有“.meta”文件,这是 Unity 的文件间引用。因此,当您在 Unity YAML 文件中看到类似以下内容的引用时:
    m_Materials:
    - {fileID: 2100000, guid: 4b191c3a6f88640689fc5ea3ec5bf3a3, type: 2}

    该文件在其他地方。您可以递归地打开它以找出任何依赖项。

    我刚刚翻阅了游戏项目并保存了一个 GUID:Filepath Key:Value 对的字典,我可以与之匹配。

    关于python - PyYAML 和不寻常的标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21473076/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com