Ответ 1
У меня также была эта проблема, и интернет был не очень полезен. После того, как я наткнулся на эту проблему в течение 3 дней, я смог разобраться с ней или хотя бы получить рабочее решение. Если кто-то хочет добавить дополнительную информацию, пожалуйста. Но вот что я получил.
1) Документация по файлу Unity YAML (они называют это "текстовым файлом сцены", потому что он содержит текст, который читается человеком) - http://docs.unity3d.com/Manual/TextualSceneFormat.html
Это формат, совместимый с YAML 1.1. Поэтому вы можете использовать PyYAML или любую другую библиотеку YAML Python для загрузки объекта 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. Вот документация по этому поводу: http://docs.unity3d.com/Manual/ClassIDReference.html
В принципе, каждый поток определяется как новый класс объекта... соответствующий идентификаторам в этой ссылке. Итак, "GameObject" - "1" и т.д. Строка выглядит так:
--- !u!1 &100000
Итак, "---" определяет новый поток. "! U!" является псевдонимом для "tag: unity3d.com, 2011" , а "& 100000" - это идентификатор файла для этого объекта (внутри этого файла, если что-то ссылается на этот объект, он использует этот идентификатор.... помните, что YAML является node, поэтому идентификатор используется для обозначения соединения node).
Следующая строка - это корень объекта YAML, который является именем класса Unity... example "GameObject" . Поэтому оказывается, что нам действительно не нужно переводить с класса ID на тип Human readable node. Это прямо здесь. Если вам когда-нибудь понадобится его использовать, просто возьмите корень node. И если вам нужно построить объект YAML для Unity, просто держите словарь на основе этой ссылки документации, чтобы перевести "GameObject" на "1" и т.д.
Другая проблема заключается в том, что большинство парней YAML (PyYAML - это тот, который я тестировал) поддерживают только 3 типа объектов YAML:
- Скалярное
- Последовательность
- Отображение
Вы можете определить/расширить пользовательские узлы. Но это сводится к написанию собственного анализатора YAML, потому что вам нужно ОПИСАТЬ, как создается каждый конструктор YAML и выводит. Почему я должен использовать библиотеку, например PyYAML, а затем написать свой собственный синтаксический анализатор для чтения этих пользовательских узлов? Весь смысл использования библиотеки - использовать предыдущую работу и получить всю эту функциональность с первого дня. Я потратил 2 дня, пытаясь создать новый конструктор для каждого идентификатора класса в единстве. Он никогда не работал, и я попал в сорняки, которые пытались правильно построить конструкторы.
ХОРОШИЕ НОВОСТИ/РЕШЕНИЕ:
Оказывается, все узлы Unity, с которыми я когда-либо сталкивался, являются базовыми узлами "Mapping" в YAML. Таким образом, вы можете выбросить пользовательское сопоставление node и просто позволить PyYAML автоматически определять тип node. Оттуда все отлично работает!
В PyYAML вы можете передать файл-объект или строку. Итак, мое решение состояло в том, чтобы написать простой 5-строчный предварительный парсер, чтобы вырезать биты, которые путают PyYAML (биты, которые Unity неправильно синтаксически) и подают эту новую строку в PyYAML.
1) полностью удалите строку 2 или просто проигнорируйте ее:
%TAG !u! tag:unity3d.com,2011:
Нам все равно. Мы знаем, что это файл единства. И тег ничего не делает для нас.
2) Для каждого объявления потока удалите псевдоним тега ( "! u!" ) и удалите идентификатор класса. Оставьте файлID. Пусть PyYAML автоматически определит node как отображение node.
--- !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
Чтобы создать объект PyYAML из файла текстовой сцены Unity, вызовите функцию pre-parser в файле:
import yaml
# This fixes Unity 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 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] )
Надеюсь, что это поможет!
-Vlad
PS. Чтобы ответить на следующую проблему при ее использовании:
Вам также нужно пройти весь каталог проекта и проанализировать все файлы ".meta" для "GUID", который является ссылкой между файлами Unity. Итак, когда вы видите ссылку в файле Unity YAML для чего-то вроде:
m_Materials:
- {fileID: 2100000, guid: 4b191c3a6f88640689fc5ea3ec5bf3a3, type: 2}
Этот файл находится где-то в другом месте. И вы можете повторно открывать это, чтобы узнать какие-либо зависимости.
Я просто разорвал игровой проект и сохранил словарь GUID: Filepath Key: пары значений, с которыми я могу сопоставлять.