-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
browseprop.py
162 lines (127 loc) · 5.19 KB
/
browseprop.py
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
import sys
from collections import defaultdict
from tkinter import Tk, ttk
from typing import Any, Dict, Optional
import ark.asset
from automate.ark import ArkSteamManager
from ue.loader import AssetNotFound
from ue.paths import find_asset_from_external_path
from ue.properties import FloatProperty, Property, StructProperty
root: Optional[Tk] = None
tree: Optional[ttk.Treeview] = None
assetlist = []
# propertyvalues[propname][index][assetname] = value
propertyvalues: Dict[str, Dict[int, Dict[str, Any]]] = \
defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: None) # type: ignore
))
def create_ui():
global root
# Window
root = Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
root.minsize(width=600, height=400)
root.geometry('1000x800')
def type_name(value):
'''Return the type of a value as a string.'''
return str(type(value).__name__)
def get_value_as_string(value):
if isinstance(value, list):
return f'{len(value)} entries'
if isinstance(value, type):
return value.__name__
if isinstance(value, StructProperty):
return '<struct>'
if isinstance(value, FloatProperty):
return value.rounded
if isinstance(value, Property) or hasattr(value, 'value'):
return get_value_as_string(value.value)
if value is None:
return ''
return str(value)
def find_asset(assetname, loader):
try:
assetname = find_asset_from_external_path(assetname, loader, True)
except AssetNotFound:
print(f'Not found: {assetname}', file=sys.stderr)
sys.exit(404)
return assetname
def load_asset(assetname):
if not assetname.startswith('/Game'):
return
assetname = loader.clean_asset_name(assetname)
asset = loader[assetname]
# Take properties and overrides from each sub-component recursively
for component in ark.asset.findSubComponentExports(asset):
componentname = ark.asset.findExportSourcePackage(component.klass.value)
print(f'Sub-Component: {componentname}')
record_properties(component.properties, '+' + componentname.split('/')[-1])
load_asset(componentname)
# Take properties and overrides from each component recursively
for component in ark.asset.findComponentExports(asset):
record_properties(component.properties, assetname.split('/')[-1])
parentpkg = ark.asset.findExportSourcePackage(component)
print(f'Component: {parentpkg}')
load_asset(parentpkg)
def should_filter_out(prop):
proptype = str(prop.header.type)
if proptype == 'StructProperty':
return True
if proptype == 'ArrayProperty':
return True
if proptype == 'ObjectProperty':
return True
def record_properties(properties, assetname):
if len(properties) < 1:
return
assetlist.append(assetname)
for prop in properties:
if should_filter_out(prop):
continue
value = get_value_as_string(prop)
propertyvalues[str(prop.header.name)][prop.header.index][assetname] = value
def fill_property_grid():
global tree
# Grid-based layout frame
frame = ttk.Frame(root, padding="6 6 6 6")
frame.grid(column=0, row=0, sticky='nsew')
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
# The tree view
tree = ttk.Treeview(frame, columns=['name', 'index'] + assetlist)
tree.grid(column=0, row=0, sticky='nsew')
tree.columnconfigure(0, weight=1)
tree.rowconfigure(0, weight=1)
tree.column('#0', stretch=0, width=0)
tree.column('name', stretch=0, width=320, anchor='e')
tree.column('index', stretch=0, width=36, anchor='c')
tree.heading('name', text='Name')
tree.heading('index', text='Index')
# Simple styling
tree.tag_configure('odd', background='#e0e0e0')
# Scroll bar to control the treeview
vsb = ttk.Scrollbar(frame, orient="vertical", command=tree.yview)
vsb.grid(row=0, column=1, sticky='nse')
tree.configure(yscrollcommand=vsb.set)
for i, assetname in enumerate(assetlist):
smallname = assetname.replace('DinoCharacterStatusComponent', 'DCSC').replace('Character', 'Chr').replace('_BP', '')
tree.heading(i + 2, text=smallname)
tree.column(i + 2, width=60, stretch=1, anchor='c')
odd = False
for propname, propvalues in sorted(propertyvalues.items(), key=lambda p: p[0]):
for index, values in sorted(propvalues.items(), key=lambda p: p[0]):
assetvalues = [values[assetname] or '' for assetname in assetlist]
tree.insert('', 'end', text=propname, values=[propname, index] + assetvalues, tags=('odd' if odd else 'even', ))
odd = not odd
if __name__ == '__main__':
arkman = ArkSteamManager()
loader = arkman.getLoader()
mainasset = sys.argv[1] if len(sys.argv) > 1 else None
create_ui()
assert root
mainasset = find_asset(mainasset, loader)
print(f"Asset: {mainasset}")
root.title(f"Property Browser : {mainasset}")
load_asset(mainasset)
fill_property_grid()
root.mainloop()