-
Notifications
You must be signed in to change notification settings - Fork 1
Initial implementation #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hugglesfox
wants to merge
32
commits into
thoth-tech:main
Choose a base branch
from
hugglesfox:dev
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
db3106b
Add readme
hugglesfox bc9b80e
Add the example game foobar
hugglesfox f5c863d
Change to using a toml based format
hugglesfox 96f62ff
merge branch and tag
hugglesfox 26f80c6
Add clone and build logic
hugglesfox 263fd85
WIP add asteroids
hugglesfox 9667813
Finish initial implementation with asteroids
hugglesfox 7020d6b
Add logging
hugglesfox f58770a
Add dxballgame
hugglesfox 4658013
Add ping pong
hugglesfox f7cd53b
Add github actions
hugglesfox dfc85d1
Fix run statements
hugglesfox 4a2ee46
Fix skm path
hugglesfox 822134c
Configuring CI/CD scripts is annoying
hugglesfox 0d9daa2
Update apt before installing
hugglesfox 224f87c
Fix flipper path
hugglesfox bfb141c
Add apt repo update
hugglesfox 8fca475
Fix arch expression
hugglesfox f0545a6
Change flipper clone path
hugglesfox e047fd6
Add libjsoncpp-dev dependency
hugglesfox bb3e03c
Remove dxballgame
hugglesfox 7443392
Fix C++ library link name
hugglesfox 352576a
Remove json dependency
hugglesfox b4fb56d
switch to g++-arm-linux-gnueabihf
hugglesfox db381b2
Add archive upload
hugglesfox 63efed7
Remove arm build for now
hugglesfox 226f636
Add return code handling for clone, build and archive
hugglesfox c9f636e
Fix archive path
hugglesfox 18b242d
Fix docstring
hugglesfox ebb8ef0
Clean up logging text
hugglesfox 774f0ac
Make path a positional argument
hugglesfox aa9ee95
Add flipper usage instructions
hugglesfox File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| on: [push] | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Install splashkit | ||
| run: | | ||
| sudo apt update | ||
| curl -s https://raw.githubusercontent.com/splashkit/skm/master/install-scripts/skm-install.sh | bash | ||
| ~/.splashkit/skm linux install | ||
| ~/.splashkit/skm global install | ||
|
|
||
| - name: Install dependencies | ||
| run: sudo apt-get install -y dotnet-host g++-arm-linux-gnueabihf | ||
|
|
||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: 3.12 | ||
|
|
||
| - name: Clone flipper repo | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Run flipper | ||
| run: | | ||
| mkdir -p build | ||
| cd build | ||
| python ../flipper.py --path .. | ||
|
|
||
| - name: Upload game archive | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| path: splashkit-games-*.tar.gz | ||
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # Flipper | ||
|
|
||
| The splashkit arcade machine games repository. | ||
|
|
||
| ## Adding a game | ||
|
|
||
| Adding a game is as easy as creating a new [toml](https://toml.io) file which | ||
| contains some details about your game. An example of a basic game is below. | ||
|
|
||
| ```toml | ||
| [meta] | ||
| name = "FooBar" | ||
| description = "Foobar is an amazing strategy game based on fizzbuzz" | ||
| language = "cpp" | ||
|
|
||
| [git] | ||
| repo = "https://github.com/thoth-tech/foobar.git" | ||
| ``` | ||
|
|
||
| The toml file is broken down into 2 parts meta and git. | ||
|
|
||
| ### meta | ||
|
|
||
| The meta section contains metadata about the game. It's fields are as follows. | ||
|
|
||
| - `name` is the name of the game | ||
| - `description` is a short description of the game | ||
| - `language` the language which the game is programmed in. Possible values are | ||
| `cpp` for C++ or `cs` for C#. Python and pascal support coming soon. | ||
|
|
||
| ### git | ||
|
|
||
| The git section contains information about the github repository containing the | ||
| game's source code. | ||
|
|
||
| - `repo` is the url of the game's github repository | ||
|
|
||
| ## Full reference | ||
|
|
||
| The above example is only the minimum required to package a game. Below shows | ||
| all the possible configuration values, however everything which is not stated | ||
| above is considered optional. | ||
|
|
||
| ```toml | ||
| [meta] | ||
| name = "" | ||
| description = "" | ||
| language = "" | ||
|
|
||
| [git] | ||
| repo = "" | ||
| branch = "" # a tag can also be specified | ||
| directory = "" | ||
|
|
||
| # See https://github.com/thoth-tech/ArcadeMenu/blob/master/GAMELISTS.md | ||
| [emulationstation] | ||
| image = "" | ||
| thumbnail = "" | ||
| rating = 0.0 | ||
| releasedate = 1979-05-27T07:32:00 | ||
| developer = "" | ||
| publisher = "" | ||
| genre = "" | ||
| players = 0 | ||
| ``` | ||
|
|
||
| ## FAQ | ||
|
|
||
| > Why toml? | ||
|
|
||
| A toml parser included in Python's standard library, where as a yaml parser | ||
| isn't, and one of my requirements was that the build script should have no | ||
| dependencies other then python and it's standard library. | ||
|
|
||
| ## Usage | ||
|
|
||
| Flipper is designed to be ran in a clean 'build' directory (similar to cmake) | ||
| and therefore takes the path to the repository as a positional argument. This | ||
| would also allow one to seperate the games repository from the flipper source | ||
| if flipper is being used on more repositories then just this one. | ||
|
|
||
| A typical usage would look like the following | ||
|
|
||
| ``` | ||
| $ mkdir build | ||
| $ cd build | ||
| $ ../flipper.py .. | ||
| ``` | ||
|
|
||
| ## Licensing | ||
|
|
||
| By using this project to package your game, you are agreeing that a copy of the | ||
| source code and a binary build of the game will be freely redistributed. | ||
|
|
||
| Please consider licensing your game using an open source license such as GPL, | ||
| MIT, Apache or BSD and including a copy of said licence in your game | ||
| repository. This way we can freely use your game and avoid copyright law | ||
| issues. | ||
|
|
||
| This project and all the game packaging files within (not the contents of the | ||
| games themselves) are licensed under the MIT license unless otherwise stated. | ||
| See LICENSE.txt for more information. |
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| [meta] | ||
| name = "Asteroids" | ||
| language = "cs" | ||
| description = """ | ||
| Asteroids is a top-down single player or co-op shooter that has \ | ||
| you, the player, flying around and surviving an onslaught of rocks, and if you \ | ||
| survive long enough, even bosses!""" | ||
|
|
||
| [git] | ||
| repo = "https://github.com/thoth-tech/Asteroids.git" | ||
|
|
||
| [emulationstation] | ||
| image = "doco/images/img3.png" | ||
| genre = "Multidirectional shooter" | ||
| developer = "Thoth Tech" | ||
| rating = 4.5 |
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| #!/usr/bin/python3 | ||
|
|
||
| import logging | ||
| import argparse | ||
| import os | ||
| import subprocess | ||
| import textwrap | ||
| import tomllib | ||
| import xml.etree.ElementTree as xml | ||
|
|
||
| from datetime import datetime | ||
|
|
||
| ARCHIVE_PATH = f"../splashkit-games-{datetime.now():%Y%m%d-%H%M%S}.tar.gz" | ||
|
|
||
| HOME_PATH = "~" | ||
| GAMES_PATH = "Games" # relative to HOME_PATH | ||
| SYSTEM_PATH = os.path.join(GAMES_PATH, "LaunchScripts") | ||
|
|
||
| CPP_LINK_SPLASHKIT = "-lSplashKit" | ||
|
|
||
| # The verbose flag sets this to None so that stdout will be shown on stdout | ||
| STDOUT = subprocess.DEVNULL | ||
|
|
||
| # The verbose flag sets this to logging.DEBUG | ||
| LOG_LEVEL = logging.INFO | ||
|
|
||
| args = None | ||
| log = logging.getLogger("flipper") | ||
|
|
||
|
|
||
| class Game: | ||
| def __init__(self, config): | ||
| config = tomllib.load(fp) | ||
|
|
||
| self.meta = config["meta"] | ||
| self.git = config["git"] | ||
| self.es = config.get("emulationstation", {}) | ||
|
|
||
| self.log = logging.getLogger(self.meta["name"]) | ||
| self.cloned = False | ||
|
|
||
| def clone(self): | ||
| """Clone the game's source code""" | ||
| clone_path = os.path.join(GAMES_PATH, self.meta["name"]) | ||
|
|
||
| if os.path.isdir(clone_path): | ||
| self.log.warning("Game directory already exists, skipping cloning") | ||
| self.cloned = True | ||
| return | ||
|
|
||
| cmd = ["git", "clone"] | ||
| cmd.append("--depth=1") | ||
|
|
||
| if "branch" in self.git.keys(): | ||
| cmd += ["--branch", self.git["branch"]] | ||
|
|
||
| cmd += [self.git["repo"], clone_path] | ||
|
|
||
| self.log.info(f"Cloning...") | ||
| self.log.debug(" ".join(cmd)) | ||
|
|
||
| clone = subprocess.run(cmd, stdout=STDOUT) | ||
|
|
||
| if clone.returncode != 0: | ||
| self.log.critical("Game failed to clone") | ||
| exit(clone.returncode) | ||
|
|
||
| self.cloned = True | ||
|
|
||
| def build(self): | ||
| """Build the game | ||
|
|
||
| For C++ and C# this creates a bin directory inside the cloned source | ||
| containing the final executable | ||
| """ | ||
| if not self.cloned: | ||
| self.clone() | ||
|
|
||
| build_path = os.path.join( | ||
| GAMES_PATH, self.meta["name"], self.git.get("directory", "") | ||
| ) | ||
|
|
||
| # Create a path to put the compiled binary | ||
| os.makedirs(os.path.join(build_path, "bin"), exist_ok=True) | ||
|
|
||
| cmd = [] | ||
|
|
||
| if self.meta["language"] == "cs": | ||
| cmd += ["dotnet", "publish"] | ||
| cmd += ["--configuration", "release"] | ||
|
|
||
| if args.cs_runtime is not None: | ||
| cmd += ["--runtime", args.cs_runtime] | ||
|
|
||
| cmd += ["-o", "bin"] | ||
| elif self.meta["language"] == "cpp": | ||
| cmd.append(args.cpp_prefix + args.cpp) | ||
| cmd += [ | ||
| source for source in os.listdir(build_path) if source.endswith(".cpp") | ||
| ] | ||
| cmd.append(CPP_LINK_SPLASHKIT) | ||
| cmd += ["-o", "bin/" + self.meta["name"]] | ||
| else: | ||
| self.log.critical( | ||
| f"Unable to build, unknown language {self.meta['language']}" | ||
| ) | ||
| exit(1) | ||
|
|
||
| self.log.info(f"Building {self.meta['name']}...") | ||
| self.log.debug(" ".join(cmd)) | ||
|
|
||
| build = subprocess.run(cmd, cwd=build_path, stdout=STDOUT) | ||
|
|
||
| if build.returncode != 0: | ||
| self.log.critical("Game failed to build") | ||
| exit(build.returncode) | ||
|
|
||
| def generate_run_script(self): | ||
| """Generate a run script for the game""" | ||
| script_path = os.path.join(SYSTEM_PATH, self.meta["name"] + ".sh") | ||
| self.log.info(f"Creating run script at {script_path}") | ||
|
|
||
| script = "" | ||
|
|
||
| if self.meta["language"] == "cs" or self.meta["language"] == "cpp": | ||
| script = f"""\ | ||
| #!/bin/sh | ||
| {os.path.join(HOME_PATH, GAMES_PATH, self.meta['name'], self.git.get('directory', ''), 'bin', self.meta['name'])} | ||
| """ | ||
| else: | ||
| self.log.error( | ||
| f"Unable to create run script, unknown language {self.meta['language']}" | ||
| ) | ||
|
|
||
| os.makedirs(SYSTEM_PATH, exist_ok=True) | ||
|
|
||
| script = textwrap.dedent(script) | ||
| self.log.debug(script) | ||
|
|
||
| with open(script_path, "w+") as fp: | ||
| fp.write(script) | ||
| os.chmod(fp.name, 0o755) | ||
|
|
||
| def es_config(self, gamelist): | ||
| """Append the game's emulation station configuration | ||
|
|
||
| This assumes that the gameList root tag already exist in the given | ||
| element tree | ||
|
|
||
| See https://github.com/thoth-tech/ArcadeMenu/blob/master/GAMELISTS.md | ||
| for the file format | ||
| """ | ||
| game = xml.SubElement(gamelist, "game") | ||
|
|
||
| path = xml.SubElement(game, "path") | ||
| path.text = os.path.join(HOME_PATH, SYSTEM_PATH, self.meta["name"] + ".sh") | ||
|
|
||
| name = xml.SubElement(game, "name") | ||
| name.text = self.meta["name"] | ||
|
|
||
| self.log.info(f"Generating gamelist configuration for {self.meta['name']}") | ||
|
|
||
| if (description := self.meta.get("description")) is not None: | ||
| self.log.debug("Adding description tag") | ||
| desc = xml.SubElement(game, "desc") | ||
| desc.text = description | ||
| else: | ||
| self.log.warning("Game doesn't have a description") | ||
|
|
||
| if (image := self.es.get("image")) is not None: | ||
| self.log.debug("Adding image tag") | ||
| desc = xml.SubElement(game, "image") | ||
| desc.text = os.path.join(self.git.get("directory", ""), image) | ||
| else: | ||
| self.log.warning("Game doesn't have title image") | ||
|
|
||
| for tag, val in self.es.items(): | ||
| if tag == "image": | ||
| continue | ||
|
|
||
| self.log.debug(f"Adding {tag} tag") | ||
| element = xml.SubElement(game, tag) | ||
| element.text = str(val) | ||
|
|
||
|
|
||
| def create_archive(): | ||
| log.info(f"Creating {ARCHIVE_PATH}") | ||
| cmd = ["tar", "czvf", ARCHIVE_PATH, "."] | ||
| log.debug(" ".join(cmd)) | ||
|
|
||
| tar = subprocess.run(cmd, stdout=STDOUT) | ||
|
|
||
| if tar.returncode != 0: | ||
| log.critical("Archive creation failed, run with --verbose for more information") | ||
| exit(tar.returncode) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="splashkit arcade package manager") | ||
|
|
||
| parser.add_argument( | ||
| "--cs-runtime", help="dotnet runtime architecture", default=None | ||
| ) | ||
| parser.add_argument("--cpp-prefix", help="cpp compiler prefix", default="") | ||
| parser.add_argument("--cpp", help="cpp compiler path", default="g++") | ||
| parser.add_argument( | ||
| "--verbose", help="increase output verbosity", action="store_true" | ||
| ) | ||
| parser.add_argument("repo", help="flipper repository path") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| if args.verbose: | ||
| LOG_LEVEL = logging.DEBUG | ||
| STDOUT = None | ||
|
|
||
| logging.basicConfig(level=LOG_LEVEL) | ||
|
|
||
| games = [] | ||
|
|
||
| for file in os.listdir(args.repo): | ||
| if not file.endswith(".toml"): | ||
| continue | ||
|
|
||
| with open(os.repo.join(args.repo, file), "rb") as fp: | ||
| games.append(Game(fp)) | ||
|
|
||
| for game in games: | ||
| game.build() | ||
|
|
||
| for game in games: | ||
| game.generate_run_script() | ||
|
|
||
| gamelist = xml.Element("gameList") | ||
| for game in games: | ||
| game.es_config(gamelist) | ||
|
|
||
| with open(os.repo.join(SYSTEM_PATH, "gamelist.xml"), "wb+") as fp: | ||
| tree = xml.ElementTree(gamelist) | ||
| xml.indent(tree) | ||
| tree.write(fp) | ||
|
|
||
| create_archive() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.