-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlevelMerger.py
203 lines (163 loc) · 6.36 KB
/
levelMerger.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#######################################
# merges two+ levels
# for the creators, i guess
# uploads to servers automatically and unlisted
# by zmx
######################################
import sys
from typing import List, Any
import levelDownloader
import levelConverter
from commonTypes import LevelString, RobDict
import saveUtil
from pathlib import Path
def listMerge(list1: List[Any], list2: List[Any],
remove_duplicate=True) -> List[Any]:
"""
Merges two lists, keeping order and removing duplicates between two lists
(while not removing duplicates in the first)
from https://stackoverflow.com/a/1319355 lol
"""
resulting_list: List[Any] = list(list1)
if remove_duplicate:
resulting_list.extend(x for x in list2 if x not in resulting_list)
else:
resulting_list.extend(x for x in list2)
return resulting_list
def incrementName(name: str) -> str:
"""
fun little function, increments level names
"""
if name[-1].isnumeric() and len(name) > 20:
newInt: int = int(name[-1]) + 1
return name[:-1] + str(newInt)
else:
return name + " 2"
def getObjCount(levelString: LevelString) -> int:
"""
Gets object count for a level
"""
objects = levelString.split(b';')
return len(objects[1:-1])
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description="GD Level Merger", epilog="hi ~zmx")
base_group = parser.add_mutually_exclusive_group(required=True)
base_group.add_argument(
"--base-id", help="base id to get attributes from", type=int)
# base file is not supported until i figure out a better format ~ zmx
#base_group.add_argument(
# "--base-file", help="base files to get attributes from")
parser.add_argument("--ids", help="ids to merge", nargs="+", type=int)
parser.add_argument("--files", help="files to merge", nargs="+")
parser.add_argument(
"--main", help="use 2.1 servers for download and upload",
action="store_true")
parser.add_argument(
"--export", help="export level to file, skip upload",
action="store_true")
parser.add_argument(
"--allow-collisions", help="keep collisions while merging",
action="store_true")
args = parser.parse_args()
levels: List[List[str]] = []
levelHeader: str = ""
levelInfo: RobDict = RobDict({})
if not args.main:
levelDownloader.url = "https://absolllute.com/gdps/\
gdapi/downloadGJLevel19.php"
else:
print("2.1 level download/upload enabled!")
levelConverter.url = "http://www.boomlings.com/database/\
uploadGJLevel21.php"
levelConverter.gameVersion = 21
# supporting multiple types is weird
# this is the id levels downloading stuff
download_list = []
if args.base_id:
download_list.append(args.base_id)
if args.ids:
download_list.extend(args.ids)
for id in download_list:
try:
levelString, curLevelInfo = levelDownloader.downloadLevel(
int(id)) # i promise this isn't dangerous
print(f"Downloaded level `{curLevelInfo['2']}`")
levelObjects = levelString.decode().split(';')
curLevelHeader = levelObjects.pop(0)
levels.append(levelObjects)
if args.base_id and id == args.base_id:
levelInfo = curLevelInfo
print(f"Using info from `{levelInfo['2']}`")
levelHeader = curLevelHeader
except:
print(f"Please specfiy a valid id - {id} is broken!")
sys.exit()
open_list = []
# if args.base_file:
# open_list.append(args.base_file)
args.base_file = ""
if args.files:
open_list.extend(args.files)
for file in open_list:
try:
current_string = ""
with open(file, "r") as opened_file:
current_string = opened_file.read()
print(f"read file {file}")
levelObjects = current_string.split(';')
curLevelHeader = levelObjects.pop(0)
levels.append(levelObjects)
if file == args.base_file:
print(f"Using info from {file}")
levelInfo['2'] = Path(file).stem
# we'll just assume the last level added is base level. unless this is multithreaded
# dirty way to get header too
levelHeader = levels[-1].split(";")[0]
except:
print(f"invalid file `{file}`` provided!")
sys.exit()
finalLevel = List[List[str]]
finalLevel = levels[0]
allow_collisions = False
if args.allow_collisions:
print("collisions enabled!")
allow_collisions = True
for pos, objects in enumerate(levels[1:]):
print(f"Merging level {pos + 2} to level 1")
finalLevel = listMerge(finalLevel, objects[:-1],
not allow_collisions)
# last object is ;, keep that outta here
print(f"Final Object Count: {len(finalLevel)}")
finalLevelStr: LevelString = LevelString(
(levelHeader + ";" + (';').join(finalLevel) + ";").encode())
finalLevelStr = LevelString(saveUtil.encodeLevel(finalLevelStr))
levelInfo["2"] = incrementName(levelInfo["2"])
levelInfo["45"] = str(getObjCount(finalLevelStr))
if args.export:
print("Exporting level...")
with open(levelInfo['2'] + '.txt', 'wb') as lvlFile:
lvlFile.write(finalLevelStr)
sys.exit()
if levelConverter.gameVersion >= 20:
import getpass
accUsername: str = input("Username: ")
password: str = getpass.getpass("User password: ")
else:
accUsername = ""
password = ""
print("Uploading level...")
try:
levelID: int = levelConverter.uploadLevel(
finalLevelStr, levelInfo,
accUsername=accUsername, password=password)
print(f"Level reuploaded to id: {levelID}")
except levelConverter.LevelUploadError as upload_error:
print(f"Could not upload level with code {upload_error.enum}")
if upload_error.enum == -1:
print("This likely means that you are being rate limited. \n\
If you're uploading to a server based on cvolton's GMDPrivateServer, \
you can only upload a level once every minute.")
except Exception as err:
print(f"Uploading level failed with error:\n{err}")