我也有這個問題,互聯網是不是非常有幫助。在對付這個問題三天之後,我就能夠把它整理出來......或者至少得到一個可行的解決方案。如果有人想添加更多信息,請做。但這是我得到的。
1)統一的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!」 「標籤:unity3d.com,2011」。
2b)然後繼續使用「!u!」在每個對象流之前的所有地方。但問題是 - 要符合YAML 1.1標準 - 它應該爲每個流實際聲明一個標籤別名(任何時候新對象都以「---」開頭)。在頂部聲明一次,永不再次只對第一個流有效,下一個流對「!!」一無所知,所以它錯誤了。
此外,這個標籤是無用的。它基本上將「tag:unity3d.com,2011」附加到流中的每個條目。我們不關心。我們已經知道這是一個Unity YAML文件。爲什麼混淆數據?
3)對象類型由Unity的Class 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」。所以事實證明,我們實際上並不需要從Class ID轉換爲Human Readable節點類型。它就在那裏。如果您需要使用它,只需取根節點即可。如果你需要爲Unity創建一個YAML對象,那麼只要保留一個基於該文檔鏈接的字典來將「GameObject」翻譯爲「1」等。
另一個問題是大多數YAML解析器(PyYAML是一個我測試)只支持3種類型的YAML對象開箱:
- 標量
- 序列
- 映射
可以定義/定製的延伸節點。但這等於手寫你自己的YAML解析器,因爲你必須定義EXPLICITLY每個YAML構造函數是如何創建的以及輸出的。爲什麼我會使用像PyYAML這樣的庫,然後繼續編寫我自己的解析器來讀取這些自定義節點?使用圖書館的重點是利用以前的工作,並從第一天起就獲得所有功能。我花了2天的時間嘗試爲每個類ID創建一個新的構造函數。它從來沒有工作過,而且我試圖正確地構建構造函數。
好消息/解決方案:
事實證明,所有我曾經碰到迄今爲止團結節點是在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
要創建一個統一文本的場景文件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])
希望有幫助!
-Vlad
PS。回答下一個問題使其可用:
您還需要遍歷整個項目目錄並解析所有「.ID」文件作爲Unity的文件間引用「GUID」。因此,當您在Unity YAML文件中看到類似以下內容的參考時:
m_Materials:
- {fileID: 2100000, guid: 4b191c3a6f88640689fc5ea3ec5bf3a3, type: 2}
該文件位於其他位置。你可以重新打開這個文件來找出任何依賴關係。
我只是通過遊戲項目翻錄並保存了一個GUID字典:Filepath Key:值對,我可以匹配。