0%

Unreal 获取关联资产名单代码片段

摘要

有时候从UE中找到所有关联资产非常不方便.

搞来搞去很麻烦. 找了个时间搞了个py脚本专门输出一个资产关联列表.

人生苦短, CV大法好.

Python 代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# coding=utf-8
# python=3.8

# Script to find Unreal Project assets easily

# How to Use ? Take a selection in AssetContentBrowser then run script with console.

import unreal as unreal; ue = unreal
import subprocess as subprocess
import os as os


# Typing hint
try:
import typing
except Exception as E:
print(E)

def DoWinCopy(inCopy:str) :
"""Copy to windows clipboard"""
subprocess.run(['clip.exe'], input=str(inCopy).strip().encode('utf-16'), check=True)

class SelectionHelper (object) :
"""Help to get current Selection @ World and @ Content"""
__projectContentPath = unreal.Paths.project_content_dir()

@classmethod
def GetSelectedAssets (cls) :
# type: (...) -> list[ue.Object]
return unreal.EditorUtilityLibrary.get_selected_assets()

@classmethod
def GetSelectedActors (cls) :
# type: (...) -> list[ue.Actor]
return unreal.EditorLevelLibrary.get_selected_level_actors()

@classmethod
def GetFullPathByObject (cls, inUObject: ue.Object) -> str :
return unreal.SystemLibrary.get_path_name(inUObject)

@classmethod
def ConvertPackagePathToFilePath (cls, inPackagePath: str) -> str :
"""Convert '/Game/StarterContent/SomeName' to 'Drive:/Project/Content/StarterContent/SomeName'"""
fileSysPath = os.path.join(cls.__projectContentPath,inPackagePath.replace("/Game/",""))
return fileSysPath

@classmethod
def ConvertFilePathToPackagePath (cls, inFilePath: str) -> str :
"""Convert 'Drive:/Project/Content/StarterContent/SomeName(.uasset)' to '/Game/StarterContent/SomeName'"""
return inFilePath.replace("\\","/").replace(".uasset","").replace(cls.__projectContentPath,"/Game/")

class ReferenceHelper (object):
__assetRegistryInstance: ue.AssetRegistry = unreal.AssetRegistryHelpers.get_asset_registry()

__referenceOptions = unreal.AssetRegistryDependencyOptions()
__referenceOptions.include_hard_management_references = True
__referenceOptions.include_hard_package_references = True
__referenceOptions.include_soft_management_references = True
__referenceOptions.include_soft_package_references = True

@classmethod
def GetReferencersPathByPackagePath (cls, inPackagePath: str) :
"""Ref to https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/AssetRegistry.html"""
allReferencersPackage : list[str] = cls.__assetRegistryInstance.get_referencers(inPackagePath,cls.__referenceOptions)
return allReferencersPackage

@classmethod
def GetDependenciesPathByPackagePath (cls, inPackagePath: str) :
"""Ref to https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/AssetRegistry.html"""
allDependenciesPackage : list[str] = cls.__assetRegistryInstance.get_dependencies(inPackagePath,cls.__referenceOptions)
return allDependenciesPackage

@classmethod
def GetAllReferencersPathFromSelectedAssets (cls) :
"""Get all referenced assets path with current selection in AssetContent"""
assets = SelectionHelper.GetSelectedAssets()
assetPaths: set[str] = set()
for asset in assets:
path = unreal.Paths.get_base_filename(asset.get_path_name(),remove_path=False)
assetPaths.add(path)
referencedPaths: list[str] = unreal.EditorAssetLibrary.find_package_referencers_for_asset(path)
assetPaths.update(referencedPaths)
return assetPaths

@classmethod
def GetAllDependenciesPath (cls, assetArray , bDeep=False, maxDeep = 10) :
# type: (typing.Iterable[ue.Object], bool , int) -> set[str]
"""Get all referenced assets path with input array of assets object"""

# NOTE: set is more fast than list !
assetsPath: set[str] = set()

MakeValidPath: typing.Callable[[list[str]], typing.Iterable[str]] = \
lambda inPaths : \
(str(name) if not (str(name).startswith("/Script/") or str(name).startswith("/Engine/")) else None \
for name in inPaths)

def DeepLoop (inAssets: str, deepCount=0):
"""recursion to find all paths"""
if deepCount > maxDeep: return
deepCount+=1
insideAssetsPath:set[str] = set()
insideDependenciesPath: list[str] = cls.GetDependenciesPathByPackagePath(inAssets)
insideAssetsPath.update(MakeValidPath (insideDependenciesPath))
insideAssetsPath.add(inAssets)
insideAssetsPath.discard(None)

# NOTE: Find Path not in assetsPath
for diffAssetsPath in insideAssetsPath:
if not diffAssetsPath in assetsPath:
assetsPath.add(diffAssetsPath)
DeepLoop(diffAssetsPath,deepCount)
assetsPath.update(insideAssetsPath)

for asset in assetArray:
path = unreal.Paths.get_base_filename(asset.get_path_name(),remove_path=False)
DependenciesPath: list[str] = cls.GetDependenciesPathByPackagePath(path)
if isinstance(DependenciesPath, type(None)):
continue
# NOTE: remove all script path
assetsPath.update(MakeValidPath(DependenciesPath))
assetsPath.add(path)
assetsPath.discard(None)
if bDeep:
for subAsset in assetsPath.copy():
DeepLoop(subAsset)

return assetsPath

@classmethod
def GetAllDependenciesPathFromSelectedAssets (cls, bDeep=False, maxDeep = 10) :
"""Get all referenced assets path with current selection in AssetContent"""
assets = SelectionHelper.GetSelectedAssets()
return cls.GetAllDependenciesPath(assets, bDeep, maxDeep)

@classmethod
def GetAllDependenciesPathFromSelectedMeshActors (cls, bDeep=False, maxDeep = 10) :
"""Get all referenced assets path with current selection in AssetContent"""

assets: set[ue.Object] = set()
allActors = SelectionHelper.GetSelectedActors()
for actor in allActors:
staticMeshComponents: list[ue.StaticMeshComponent] = actor.get_components_by_class(ue.StaticMeshComponent)
skeletalMeshComponents: list[ue.SkeletalMeshComponent] = actor.get_components_by_class(ue.SkeletalMeshComponent)
if len(staticMeshComponents) > 0:
for comp in staticMeshComponents:
assets.add(comp.static_mesh)
if len(skeletalMeshComponents) >0 :
for comp in skeletalMeshComponents:
assets.add(comp.skeletal_mesh)

return cls.GetAllDependenciesPath(assets, bDeep, maxDeep)

def RunScript(bViewActor=True,bDoCopy=True):
"""Choose from current ViewportActors or Assets in ContentBrowser"""
method = ReferenceHelper.GetAllDependenciesPathFromSelectedMeshActors \
if bViewActor else ReferenceHelper.GetAllDependenciesPathFromSelectedAssets
result = list(method(bDeep=True,maxDeep=10));result.sort()

# NOTE: Make ContentBrowser sync with current result list
unreal.EditorAssetLibrary.sync_browser_to_objects(result)
# for strName in result : print(strName)
if bDoCopy: DoWinCopy(result)

if __name__ == "__main__":
RunScript(bViewActor=True,bDoCopy=True)

歡迎關注我的其它發布渠道