mirror of
https://github.com/libretro/libretro-puzzlescript.git
synced 2026-11-07 03:05:59 -10:00
Add script for downloading puzzlescript games by url.
Add capability to download itch.io puzzlescript games (experimental). Update readme.
This commit is contained in:
1 parent
a35d6715d7
commit
71f0346835
2 files changed
+110
-5
No files matched your search
@@ -8,9 +8,16 @@ PuzzleScript games are usually online at the main PuzzleScript site:
|
||||
https://www.puzzlescript.net/
|
||||
|
||||
To play games in the core, you will need to download the source for the game and save it as a `.pz` file.
|
||||
The normal way to do this is to click the "hack" link on the game to go to the PuzzleScript editor, then
|
||||
The normal way to do this is to click the "hack" or "sourcecode" link on the game to go to the PuzzleScript editor, then
|
||||
copy/paste the entire contents of the program into a file with extension `.pz`.
|
||||
|
||||
There is also a Python utility script in `tools/get_game.py` that can download PuzzleScript game source given a url. Typical
|
||||
use would be:
|
||||
|
||||
python3 tools/get_game.py --url=https://www.puzzlescript.net/play.html?p=2ba817426abc9fcbe9b9980fc4c02519 --output-title=.pz
|
||||
|
||||
This would download and save the file `One_Microban_level.pz`.
|
||||
|
||||
You can also find many games in the Accessible PuzzleScript repository. For these, save the `script.txt` file
|
||||
into a file with extension `.pz`.
|
||||
https://github.com/philschatz/puzzlescript/tree/master/games
|
||||
@@ -74,6 +81,7 @@ content.
|
||||
## Future work
|
||||
|
||||
* Support more platforms for binary releases.
|
||||
* Support [Pattern:Script](https://github.com/ClementSparrow/Pattern-Script/)
|
||||
* Add support for background music.
|
||||
* Add volume level control and other audio options.
|
||||
* Incorporate more accessibility features from: https://github.com/philschatz/puzzlescript
|
||||
@@ -211,15 +219,18 @@ BuildKit build.
|
||||
|
||||
## References
|
||||
|
||||
PuzzleScript project:
|
||||
PuzzleScript project
|
||||
https://github.com/increpare/PuzzleScript
|
||||
|
||||
Accessible PuzzleScript
|
||||
https://github.com/philschatz/puzzlescript
|
||||
|
||||
PuzzleScript Plus:
|
||||
PuzzleScript Plus
|
||||
https://github.com/Auroriax/PuzzleScriptPlus
|
||||
|
||||
Pattern:Script
|
||||
https://github.com/ClementSparrow/Pattern-Script/
|
||||
|
||||
For making the retroarch core, I followed this tutorial:
|
||||
https://web.archive.org/web/20190219134028/http://www.beardypig.com/2016/01/22/emulator-build-along-2/
|
||||
|
||||
@@ -229,8 +240,8 @@ https://github.com/Narkhos/Puzzlescript-Wrapper
|
||||
QuickJS
|
||||
https://bellard.org/quickjs/
|
||||
|
||||
Docs for using V8:
|
||||
Docs for using V8
|
||||
https://v8.dev/docs/
|
||||
|
||||
Linaro toolchain:
|
||||
Linaro toolchain
|
||||
https://releases.linaro.org/components/toolchain/binaries/
|
||||
@@ -0,0 +1,94 @@
|
||||
'''
|
||||
Download a PuzzleScript game
|
||||
|
||||
Given URL to play game on PuzzleScript, this script downloads source and saves to a file.
|
||||
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import codecs
|
||||
import re
|
||||
import requests
|
||||
|
||||
ESCAPE_SEQUENCE_RE = re.compile(r'''
|
||||
( \\U........ # 8-digit hex escapes
|
||||
| \\u.... # 4-digit hex escapes
|
||||
| \\x.. # 2-digit hex escapes
|
||||
| \\[0-7]{1,3} # Octal escapes
|
||||
| \\N\{[^}]+\} # Unicode characters by name
|
||||
| \\[\\'"abfnrtv] # Single-character escapes
|
||||
)''', re.UNICODE | re.VERBOSE)
|
||||
|
||||
def decode_escapes(s):
|
||||
''' Decode Python escape sequences in a string containing unicode '''
|
||||
# Basic problem is that decode with unicode-escape is broken in Python, doesn't work with unicode
|
||||
# So only apply to actual escape parts, which are guaranteed to be just ascii
|
||||
def decode_match(match):
|
||||
return codecs.decode(match.group(0), 'unicode-escape')
|
||||
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
|
||||
|
||||
def find_title(content):
|
||||
lines = content.split('\n')
|
||||
for line in lines:
|
||||
spl = line.split(' ')
|
||||
if spl[0].upper() == 'TITLE':
|
||||
return ' '.join(spl[1:])
|
||||
raise RuntimeError("Could not find title in prelude")
|
||||
|
||||
def convert_dangerous(txt):
|
||||
txt = txt.replace('-', '_')
|
||||
txt = txt.replace(' ', '_')
|
||||
txt = txt.replace("'", '_')
|
||||
return txt
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Download PuzzleScript game source files')
|
||||
parser.add_argument('--url', required=True, help="URL for playing game on PuzzleScript.net or itch.io")
|
||||
parser.add_argument('--output', help="Output filename to save game contents to (if not given will display to stdout)")
|
||||
parser.add_argument('--output-title', help="Save to filename given prefixed with game title")
|
||||
args = parser.parse_args()
|
||||
if "itch.io" in args.url:
|
||||
# For itch.io downloads, first get contents
|
||||
r = requests.get(args.url)
|
||||
# Search for cdn link to game itself
|
||||
m = re.search(r'(https://\S+\.hwcdn.net/\S+/index.html)', r.text)
|
||||
if not m:
|
||||
print('Could not find hwcdn link')
|
||||
exit(-1)
|
||||
# Get contents of cdn link
|
||||
cdn_url = m.group(0)
|
||||
r = requests.get(cdn_url)
|
||||
text = r.content.decode('utf-8')
|
||||
# Regex looks for the sourcecode, inside quotes allowing escapes inside string
|
||||
pat = r'''sourceCode="([^"\\]*(\\.[^"\\]*)*)"'''
|
||||
m = re.search(pat, text)
|
||||
if m is None:
|
||||
# Try minified version
|
||||
mpat = r'''compile\(-1, "([^"\\]*(\\.[^"\\]*)*)"'''
|
||||
m = re.search(mpat, text)
|
||||
if m is None:
|
||||
print("Could not find sourceCode in cdn result")
|
||||
exit(-1)
|
||||
source = m.group(1)
|
||||
# We have the source in escaped form, need to unescape it (allowing unicode)
|
||||
content = decode_escapes(source)
|
||||
else:
|
||||
spl = args.url.split('=')
|
||||
if len(spl) < 2:
|
||||
print("ERROR: Could not parse URL, must be in form: https://www.puzzlescript.net/play.html?p=IDENTIFIER")
|
||||
exit(-1)
|
||||
id = spl[-1]
|
||||
dl_url = f"https://api.github.com/gists/{id}"
|
||||
r = requests.get(dl_url)
|
||||
data = r.json()
|
||||
content = data['files']['script.txt']['content']
|
||||
if args.output_title:
|
||||
title = find_title(content)
|
||||
safe_title = convert_dangerous(title)
|
||||
args.output = f"{safe_title}{args.output_title}"
|
||||
if args.output:
|
||||
with open(args.output, "w") as fout:
|
||||
fout.write(content)
|
||||
print(f"Wrote {len(content)} bytes of output to file: {args.output}")
|
||||
else:
|
||||
print(content)
|
||||
Reference in new issue
Block a user