-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathent.py
132 lines (95 loc) · 3.19 KB
/
ent.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
import struct, os
def parse_keyvalue(line):
if line.find("//") != -1:
line = line[:line.find("//")]
quotes = [idx for idx, c in enumerate(line) if c == '"']
if len(quotes) < 4:
return None
key = line[quotes[0]+1 : quotes[1]]
value = line[quotes[2]+1 : quotes[3]]
return (key, value)
def parse_ents(path, ent_text):
ents = []
lineNum = 0
lastBracket = -1
ent = None
for line in ent_text.splitlines():
lineNum += 1
if len(line) < 1 or line[0] == '\n':
continue
if line[0] == '{':
if lastBracket == 0:
print("\n%s.bsp ent data (line %d): Unexpected '{'\n" % (path, lineNum));
continue
lastBracket = 0
ent = {}
elif line[0] == '}':
if lastBracket == 1:
print("\n%s.bsp ent data (line %d): Unexpected '}'\n" % (path, lineNum));
lastBracket = 1
if ent == None:
continue
ents.append(ent)
ent = None
# a new ent can start on the same line as the previous one ends
if line.find("{") != -1:
ent = {}
lastBracket = 0
elif lastBracket == 0 and ent != None: # currently defining an entity
keyvalue = parse_keyvalue(line)
if keyvalue:
ent[keyvalue[0]] = keyvalue[1]
return ents
def load_entities(bsp_path):
with open(bsp_path, mode='rb') as f:
bytes = f.read()
version = struct.unpack("i", bytes[:4])
offset = struct.unpack("i", bytes[4:4+4])[0]
length = struct.unpack("i", bytes[8:8+4])[0]
ent_text = bytes[offset:offset+length].decode("ascii", "ignore")
return parse_ents(bsp_path, ent_text)
print("\nFailed to open %s" % bsp_path)
return None
def get_all_maps(maps_dir):
all_maps = []
for file in os.listdir(maps_dir):
if not file.lower().endswith('.bsp'):
continue
if '@' in file:
continue # ignore old/alternate versions of maps (w00tguy's scmapdb content pool)
all_maps.append(file)
return sorted(all_maps, key=lambda v: v.upper())
maps_dir = "./content_pool/maps"
LIFTABLE_FLAG = 1024
all_maps = get_all_maps(maps_dir)
broken_maps = []
skip_maps = []
with open("mapcycle.txt") as f:
skip_maps = f.read().splitlines()
last_progress_str = ''
for idx, map_name in enumerate(all_maps):
map_path = os.path.join(maps_dir, map_name)
progress_str = "Progress: %s / %s (%s)" % (idx, len(all_maps), map_name)
padded_progress_str = progress_str
if len(progress_str) < len(last_progress_str):
padded_progress_str += ' '*(len(last_progress_str) - len(progress_str))
last_progress_str = progress_str
print(padded_progress_str, end='\r')
if map_name.lower().replace(".bsp", "") in skip_maps:
continue
for ent in load_entities(map_path):
if ('classname' in ent and ('monster_' in ent['classname'])) and 'spawnflags' in ent and int(ent['spawnflags']) & 1 != 0:
broken_maps.append(map_name)
print("\nMATCHED %s" % map_name)
break
'''
for ent in load_entities(map_path):
if 'classname' in ent and ent["classname"] == 'func_pushable':
if 'spawnflags' in ent and int(ent['spawnflags']) & LIFTABLE_FLAG:
broken_maps.append(map_name)
print("\nOH NO %s" % map_name)
break
'''
print("\n\nResults:")
for map in broken_maps:
print(map)