Let's talk tech. A quick recap on the design ideas we have so far:
- Players start playing LGTM by Forking an/the LGTM repo, since that's the easiest way for us to start the game (two clicks on GitHub's web interface); with later activity requiring the player to create/accept shared repos
- The game backend posts Issues to the player's Fork, with tasks to do. These Issues are essentially "Quests/Missions" in usual game terms, and contain some narrative, and may contain NPCs commenting back and forth to add some realism (or maybe fictional setting to make it interesting)
- The player does the task needed by the issue. Which will primarily involve something requiring the use of a git client or GitHub
- The game backend detects the completed task, and issues new tasks
How do we achieve this?
It's often said that "the best language for the task is the one you know". I think this should really be changed to "the best language for the task is some compromise between what you know, and what you're willing to learn based on possible future and career benefits", but that's not as catchy.
One of the key things we will need is going to be GitHub's API, which allows us to programmatically do many of the above tasks such as posting Issues. While the GitHub API is a set of REST endpoints, it is often a lot easier to use a library that implements these endpoints to save us a lot of time and grief. Having a quick Google for Python libraries, the PyGitHub library seems like the best way to go.
The second thing we need to work with GitHub is a webserver that will respond to webhooks from GitHub itself, which are needed to receive notifications when certain things happen, like someone forks a repo. We'll discuss that in the next post.
Since we are going to need to prepare git repositories, in exactly the state we need them for players to complete the task, we have a few options for this:
- Prepare them beforehand, and just send players a sort of "canned repo".
- Prepare them on-the-fly
There are pros and cons of each
In this option, I would take an/the official LGTM repo (probably the one that the player forked earlier), and on my computer, use the git client and a text editor to manually apply what I want the repo to look like when the player has to do the task, probably in a separate branch. Then the game service can simply make a PR of that branch to the player's fork as part of the setup for a task.
- Easy for me to do
- Every piece of content of the game is available for players to inspect since they need to be on GitHub, in a public repo, to be able to be PR'd (but is this a bad thing?)
In this option, I would have code programmatically make the changes needed to a repo, and then commit it. The game service would effectively be generating the commits needed for the task on-the-fly, using a library such as this one:
- Very flexible, can customize what got committed. Maybe this is useful from a narrative point of view?
- Seems difficult
- Would not work well with a single public repo (works best with multiple private ones)
After some deliberation, it would appear that this option can't be used with the forked public repo, because I would end up generating a new set of game data for every player, solely for the purpose of setting up their repo.
Instead, this option would be ideal in the case where a player has shared a repo with us (or we've created a repo to share with the player) since we could dynamically apply the task commits, and commit it to their repo
So the conclusion here is clear: If we go with the player starting off with the Forked repo, then we will have to go with the "canned repo" approach, that fork will have to contain ALL of the commits necessary for all Tasks that can be played on that fork.
Then, perhaps for later stages of the game, we can move to doing things on-the-fly. If this is the case, then I'm going to icebox this idea for the future to avoid scope creep at this stage. I will focus on the "canned repo" approach in the first version of the game to be released, and revisit it in the next major release that includes all the tasks that happen outside the Forked repo.