Skip to content

Commit

Permalink
implement 2.1 support for level merger
Browse files Browse the repository at this point in the history
  • Loading branch information
qimiko committed Feb 22, 2020
1 parent 41eda16 commit 7f4676d
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Will also use the following environment variables as settings:
Merges each level, uses first id as the level to take settings from (name, bg, etc)
Will also use the following environment variables as settings:

* `MAIN` - download levels from 2.1
* `EXPORT` - exports level to text file, does not upload (use with `MAIN`)
* `MAIN` - download levels from 2.1 and uploads to 2.1
* `EXPORT` - exports level to text file, does not upload

### Level Downloader

Expand Down
55 changes: 42 additions & 13 deletions levelConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# by zmx
######################################

from argparse import ArgumentError
import objCharts
import re
import levelUtil
Expand All @@ -16,45 +17,73 @@
import os # for error codes
from typing import Dict
from commonTypes import LevelString, RobDict
import robtopCrypto


url: str = "https://absolllute.com/gdps/gdapi/uploadGJLevel19.php"
gameVersion: int = 19
username: str = "21Reupload"


def uploadLevel(levelString: bytes, levelInfo: RobDict) -> int:
def uploadLevel(levelString: LevelString, levelInfo: RobDict,
accUsername: str = username, password: str = None) -> int:
"""
Uploads a level to 1.9 servers
2.1 support sometime, probably not
"""

# 1.9 descriptions aren't base64 encoded, we need to remove illegal
# characters before upload breaks them anyways
desc: str = base64.urlsafe_b64decode(levelInfo["3"]).decode()
desc = re.sub(r"[^A-Za-z0-9\., \$\-\_\.\+\!\*\'()]",
"", desc) # remove anything not url safe
desc: str = levelInfo["3"]
if (gameVersion < 20):
desc = base64.urlsafe_b64decode(desc).decode()
desc = re.sub(r"[^A-Za-z0-9\., \$\-\_\.\+\!\*\'()]",
"", desc) # remove anything not url safe

# some params don't exist
postdata = {
"gjp": '',
"gameVersion": 19,
"userName": "21Reupload",
"unlisted": "1",
"gameVersion": gameVersion,
"udid": "S-hi-people",
"userName": accUsername,
"unlisted": 1,
"levelDesc": desc,
"levelName": levelInfo["2"],
"levelVersion": levelInfo["5"],
"levelLength": levelInfo["15"],
"audioTrack": levelInfo["12"],
"password": 1,
"levelID": 0,
"original": levelInfo["1"],
"songID": levelInfo.get(
"35",
0),
"objects": levelInfo.get(
"45",
0),
"udid": "hi absolute :)"}
"seed2": base64.urlsafe_b64encode(
robtopCrypto.makeSeed(levelString).encode()),
"auto": 0,
"twoPlayer": 0, # going to guess
"ldm": levelInfo.get("40", 0),
"coins": levelInfo.get("37", 0),
"requestedStars": levelInfo.get("39", 0),
"gdw": 0,
"secret": "Wmfd2893gb7"}
postdata["levelString"] = levelString

if gameVersion >= 20:
if not password or not accUsername:
raise ArgumentError()
try:
accID: int = robtopCrypto.loginUser(accUsername, password)
except BaseException:
print("invalid login")
raise Exception()
postdata["gjp"] = robtopCrypto.getGJP(password)
postdata["accountID"] = accID
postdata["userName"] = robtopCrypto.getUsername(accID)

uploadRequest = httpRequest.postRequest(url, postdata)

try:
Expand Down Expand Up @@ -128,8 +157,8 @@ def uploadLevel(levelString: bytes, levelInfo: RobDict) -> int:
sys.exit()

print("Uploading level...")
try:
levelID: int = uploadLevel(encodedLevel, levelInfo)
print(f"Level reuploaded to id: {levelID}")
except BaseException:
print("couldn't reupload level!")
# try:
levelID: int = uploadLevel(LevelString(encodedLevel), levelInfo)
print(f"Level reuploaded to id: {levelID}")
# except BaseException:
print("couldn't reupload level!")
34 changes: 28 additions & 6 deletions levelMerger.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import os
from typing import List, Any
import levelDownloader
from levelConverter import uploadLevel
import levelConverter
from commonTypes import LevelString, RobDict
import saveUtil


def listMerge(list1: List[Any], list2: List[Any]) -> List[Any]:
Expand All @@ -36,6 +37,14 @@ def incrementName(name: str) -> str:
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__":
print("GD Level Merger by zmx")

Expand All @@ -54,8 +63,10 @@ def incrementName(name: str) -> str:
levelDownloader.url = "https://absolllute.com/gdps/\
gdapi/downloadGJLevel19.php"
else:
print("2.1 level download enabled!")

print("2.1 level download/upload enabled!")
levelConverter.url = "http://www.boomlings.com/database/\
uploadGJLevel21.php"
levelConverter.gameVersion = 21

for id in sys.argv[1:]:
try:
Expand Down Expand Up @@ -85,20 +96,31 @@ def incrementName(name: str) -> str:

print(f"Final Object Count: {len(finalLevel)}")

finalLevelStr: str = levelHeader + ";" + (';').join(finalLevel) + ";"
finalLevelStr: LevelString = LevelString(
(levelHeader + ";" + (';').join(finalLevel) + ";").encode())
finalLevelStr = LevelString(saveUtil.encodeLevel(finalLevelStr))

levelInfo["2"] = incrementName(levelInfo["2"])
levelInfo["45"] = str(getObjCount(finalLevelStr))

if os.getenv("EXPORT", "false").lower() == "true":
print("Exporting level...")
with open(levelInfo['2'] + '.txt', 'w') 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 = uploadLevel(LevelString(
finalLevelStr.encode()), levelInfo)
levelID: int = levelConverter.uploadLevel(
finalLevelStr, levelInfo, accUsername, password)
print(f"Level reuploaded to id: {levelID}")
except BaseException:
print("couldn't reupload level!")
71 changes: 71 additions & 0 deletions robtopCrypto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import saveUtil
import hashlib
import base64
from typing import Any, Dict
import httpRequest
import levelUtil


def makeSeed(encoded: bytes) -> str:
"""
seed2 function for robtop games
"""
seed2: str = ""
if len(encoded) < 49:
seed2 = encoded.decode()
else:
seed2 = ""
slot = len(encoded) // 50
for i in range(0, 50):
seed2 += encoded.decode()[slot * i]
return saveUtil.Xor(
hashlib.sha1(
seed2.encode() +
b"xI25fpAapCQg").hexdigest(),
41274)


def getGJP(password: str) -> bytes:
"""
gets gjp from password
"""
return base64.urlsafe_b64encode(saveUtil.Xor(password, 37526).encode())


loginURL: str = "http://www.boomlings.com/database/accounts/loginGJAccount.php"


def loginUser(username: str, password: str) -> int:
"""
logins a user
returns account id
"""
data: Dict[str, Any] = {
"userName": username,
"password": password,
"secret": "Wmfv3899gc9",
"udid": "s12-03912-0391-2039"
}
loginRequest: bytes = httpRequest.postRequest(loginURL, data)
if loginRequest == b"-1":
raise ValueError()

return int(loginRequest.split(b',')[0])


userInfoURL: str = "http://www.boomlings.com/database/getGJUserInfo20.php"


def getUsername(accID: int) -> str:
"""
gets user from account id
"""
data: Dict[str, Any] = {
"targetAccountID": accID,
"secret": "Wmfd2893gb7",
"gameVersion": 21
}
userRequest: bytes = httpRequest.postRequest(userInfoURL, data)
userInfo = levelUtil.parseKeyVarArray(userRequest.decode(), ":")

return userInfo["1"]
12 changes: 5 additions & 7 deletions saveUtil.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import gzip
from typing import Any, Dict, List
from commonTypes import LevelString
from itertools import cycle

# thanks absolute


def Xor(data: Any, key) -> str:
res = []
for i in data:
res.append(i ^ key)
return bytearray(res).decode()
# thanks nekit although he probably stole it from someone else lol
def Xor(data: Any, key: Any) -> str:
return (''.join(chr(ord(x) ^ ord(y))
for (x, y) in zip(data, cycle(str(key)))))


def decodeRobFile(text: str) -> str:
Expand Down

0 comments on commit 7f4676d

Please sign in to comment.