Last active
June 16, 2019 15:59
-
-
Save WindowDump/76ee68f05b539c970e079d3ff52718d0 to your computer and use it in GitHub Desktop.
thcrap patch configuration randomizer (Python 3.5+)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# thcrap patch configuration randomizer by Window Dump, version 190430 | |
# Changelog | |
# 190430 | |
# * Added more patches to the default blacklist which probably corrupt your scorefiles | |
# 190314-2 | |
# * Don't download files.js - it's managed by thcrap :nmlgcgod: | |
# * If patch.js had to be downloaded, keep it in memory | |
# 190314 | |
# * Use requests to download patch.js for patches that aren't downloaded yet | |
# * Remove _custom launch targets before randomly chosing a game | |
# * Default blacklist | |
# - lang_en dependencies (since they're added by default) | |
# - rEoSD (trashes scorefiles, not nice to happen randomly) | |
# * Prevent exception if a very large number of patches is selected | |
# * Ignore .git directories | |
# * Only remove blacklisted patches that have actually been discovered | |
# 190313-2 | |
# * Use Path.exists() (may result in cross-platform support) | |
# * Use proper encoding settings | |
# 190313 | |
# * Proof of concept | |
# Configuration - edit as desired. An empty Python list is list() or []. | |
# How many random patches to select | |
num_patches = 5 | |
# Include remote patches not yet downloaded (requires requests) | |
download_new_patches = True | |
# Patches to add before and after randomly selected patches | |
# These must not end in a / | |
pre_patches = ['thpatch/lang_en'] | |
post_patches = ['nmlgc/aero'] # You can remove 'nmlgc/aero' if you're not on Windows 7 | |
# Do not randomly select these patches | |
# These must not end in a / | |
blacklist = ['dass7/reosd', | |
'SMB3Memes/LoLKECL', | |
'MoriyaFaith/rEoSD-EX', | |
'MoriyaFaith/rEoSD-EX_alphes', | |
'nmlgc/base_tsa', | |
'nmlgc/base_tasofro', | |
'nmlgc/script_latin', | |
'nmlgc/western_name_order'] | |
# Extra spice: launch a random game | |
launch_random_game = True | |
# End of configuration. | |
from pathlib import Path | |
from random import sample, choice | |
import json | |
import subprocess | |
if download_new_patches: | |
import requests | |
# Modified from scripts/util.py for an authentic thcrap JSON experience | |
json_dump_params = { | |
'ensure_ascii': False, | |
'indent': ' ', | |
'separators': (',', ': '), | |
'sort_keys': True | |
} | |
patches = list() | |
selected = list() | |
def add_patch(patch): | |
"""If the provided patch isn't already added, | |
adds its dependencies to the list of selected patches, | |
then adds this patch. | |
If download_new_patches is True, this will also download the files needed | |
for thcrap if they do not already exist.""" | |
global selected | |
if patch in selected: return | |
# Download the meta files for this patch if needed | |
if download_new_patches and not Path(patch + '/patch.js').exists(): | |
patch_info = download_patch(patch) | |
else: | |
with open(patch + '/patch.js', 'r', encoding='utf-8') as f: | |
patch_info = json.load(f) | |
if 'dependencies' in patch_info: | |
for dependency in patch_info['dependencies']: | |
if '/' not in dependency: # Depends on something in same repo | |
dependency = patch.split('/')[0] + '/' + dependency | |
if dependency not in selected: | |
add_patch(dependency) | |
selected.append(patch) | |
def download_patch(patch): | |
"""Downloads the necessary meta files for this patch, | |
allowing any necessary files to be downloaded by thcrap at launch. | |
Returns a parsed JSON dictionary of patch.js""" | |
Path(patch).mkdir(exist_ok=True) | |
# Get the remote servers | |
repo, target_patch = patch.split('/') | |
with open(repo + '/repo.js', 'r', encoding='utf-8') as f: | |
repo_info = json.load(f) | |
# TODO: Try every server in case one is down, for robustness | |
server = repo_info['servers'][0] | |
# Download, save, and parse patch.js | |
r = requests.get(server + '/' + target_patch + '/patch.js') | |
with open(patch + '/patch.js', 'w', encoding='utf-8') as f: | |
f.write(r.text) | |
return r.json() | |
# Find local repositories, then discover patches based on user preference | |
dirs = Path('.') | |
for repo in [x for x in dirs.iterdir() if x.is_dir()]: | |
if Path(str(repo) + '/repo.js').exists(): # This is actually a repository | |
if download_new_patches: # Parse repo.js for patches | |
with open(str(repo) + '/repo.js', 'r', encoding='utf-8') as f: | |
repo_info = json.load(f) | |
for patch in repo_info['patches'].keys(): | |
patches.append(str(repo) + '/' + patch) | |
else: # Look for locally downloaded patches, ignore .git | |
for patch in [x for x in repo.iterdir() if x.is_dir() and '.git' not in str(x)]: | |
patches.append(str(patch).replace('\\', '/')) # Bill Gates Was Here | |
# Create our patch configuration | |
# Don't randomly choose patches we're adding or don't want | |
for patch in pre_patches: | |
add_patch(patch) | |
patches.remove(patch) | |
for patch in post_patches: | |
patches.remove(patch) | |
for patch in blacklist: | |
if patch in patches: | |
patches.remove(patch) | |
# Choose random patches | |
for patch in sample(patches, min(num_patches, len(patches))): | |
add_patch(patch) | |
for patch in post_patches: | |
add_patch(patch) | |
# Export patch configuration to random.js | |
patch_config = {'console': False, 'dat_dump': False, | |
'patches': [{'archive': x + '/'} for x in selected]} | |
with open('random.js', 'w', encoding='utf-8') as f: | |
json.dump(patch_config, f, **json_dump_params) | |
# Launch a random game if requested | |
if launch_random_game: | |
with open('games.js', 'r', encoding='utf-8') as f: | |
games = json.load(f) | |
target = choice([x for x in games.keys() if '_custom' not in x]) | |
subprocess.run('thcrap_loader "random.js" ' + target) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment