https://github.com/panel-attack/panel-updater
An experimental updater for Panel Attack
https://github.com/panel-attack/panel-updater
Last synced: 6 months ago
JSON representation
An experimental updater for Panel Attack
- Host: GitHub
- URL: https://github.com/panel-attack/panel-updater
- Owner: panel-attack
- License: zlib
- Created: 2024-04-22T19:43:03.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-12-19T23:58:03.000Z (about 1 year ago)
- Last Synced: 2025-03-22T13:44:10.957Z (11 months ago)
- Language: Lua
- Size: 351 KB
- Stars: 1
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
~~A somewhat generic updater for love games without dependencies, mostly intended for games with an open/free license.~~
The updater for the game Panel Attack. You can probably adapt it for other love games relatively easily.
Some of the options may seem impractical, alien and overly specific for how bad of a solution they present.
They were (at least partially) implemented to serve the predecessor of this tool without having to change the server side of things in the same go in order to let users migrate to the new updater at their own pace.
# Configuration
## releaseStreams.json
Configure `releaseStreams.json` to decide which different release streams exist, from which source they update and how they are versioned.
The `default` key specifies which release stream the updater should try to use in case the currently active release stream somehow has nothing available locally nor remotely.
```Json
{
"releaseStreams":
[
{
"name":"releaseStream1",
"versioningType":"semantic",
"serverEndPoint":
{
"type":"github",
"repository":"love2d/love"
}
},
{
"name":"releaseStream2",
"versioningType": "timestamp",
"serverEndPoint":
{
"type": "filesystem",
"url": "http://example.com/updates/",
"prefix":"example-"
}
}
],
"default": "releaseStream2"
}
```
### name
For name, choose whatever so long as you avoid duplicates, these function as the unique identifier!
### versioningType
For versioningType there are currently 2 supported settings.
#### semantic
For semantic versioning, `major.minor.patch-prereleasestring+metadata`.
Your semantic version must specify at least `major.minor`.
If you wish to utilize prerelease and metadata, you must specify the full `major.minor.patch` before it, e.g. `1.0-alpha` is not valid but `1.0.0-alpha` is.
#### timestamp
For versioning in a custom datetime format suitable to be used in file names, `yyyy-MM-dd_hh-mm-ss`.
Locally this will be converted to a timestamp using `os.time`.
### serverEndPoint
This is a set of options that may differ in details depending on the selected type.
#### github
The github server end point looks for versions via the github api for releases.
To determine the final url a field `repository` has to be supplied in the format `githubUser/repositoryName`.
When using github as the endpoint, the name (not the tag!) of the release is used as string representation of the version.
#### filesystem
This was implemented against the standard html presentation of a readable directory on a nginx webserver but may work on other websites as well.
The body of the response to a GET request on the requested `url` will be matched with `'href="' .. prefix .. "[^%s%.].love"` and all matches will be interpreted as versions.
The part inbetween that is getting matched by `[^%s%.]` is used as the string representation of the version.
## launch.json
Stores the user's current starting configuration.
### activeReleaseStream
This has to refer to the unique name of one of the release streams specified in releaseStreams.json.
### activeVersion
Specifies the version the user currently has selected in the string representation of that release stream's versioning type.
If not present, the user uses the latest version of the release stream.
The idea here is to allow users to specifically select older versions they may have installed, effectively allowing them to opt out of updates or selecting an older version.
In the current iteration, downloading a new version as part of the startup always causes the new version to be set as the active version.
# Usage
Set the identity of the updater to the identity of the game so they share their save directory.
Edit `releaseStreams.json` to suit your needs.
In `config.json` configure only the `activeReleaseStream` to the one you wish your players to start with as a fallback, do not configure `activeVersion`.
Zip, rename and possibly fuse the updater for release as usual.
In general it is advisable to embed a fallback version.
## Switching release streams
After determining the startup version, the updater restarts from scratch and loads up with the conf of the game.
Before doing so it sets the `GAME_UPDATER` and `GAME_UPDATER_STATES`.
As the restart is indeed a full restart, if you wish to make release stream switching available in your game, you need to call `GAME_UPDATER:init()` to have the updater read its configurations and installed versions. You can then use functions as defined in `updater/gameUpdater.lua` to retrieve information about remote and installed versions.
The updater uses love threads so if you do anything online related, you should make sure to call `update` on the updater as otherwise it will never update with the results of the threads.
## Embedding a fallback version
In case of your players not having internet access the first time they open your game, they should have a version available for offline use, even if it is outdated.
To embed a version of your game, create a directory with the name of the active release stream chosen in your `config.json` at the top level.
Inside this directory, create another directory that holds the minimum possible version for the release stream's versioning type. For semantic versioning this would be `0.0.0-norelease` or similar, for timestamp it would be `0`.
Put your .love or .zip file inside the folder.
The updater will identify this embedded version as the base version for the release stream and download the most recent version to start in its stead if it can find one on first startup. If an update is not successful, it will boot with the embedded version.
Usually you will want to embed a fallback version for the release stream you use as your default fallback as the embedded version is the only one that cannot be removed.
## Making an informed decision on externalstorage on Android
The updater basically launching the game in itself and aiming to provide control over updates and release stream choice in the game itself means that both the updater and the game **need** to use the same save directory.
Normally that is the standard but on Android this can be compromised through having diverging `externalstorage` settings.
Due to that it is basically impossible to change your mind on this setting later on without explicitly asking your users to redownload the updater with a new setting (and that still does not migrate their data to the new save directory!).
Regardless of which setting you choose, the files will be relatively inaccessible for writing, however, with `externalstorage` set to `true` it is quite a bit easier for users to at least read them.
# Distribution
## love-build
This project's `build.lua` is a config file for use with [love-build](https://github.com/ellraiser/love-build).
## Supporting unsecured http
The used [https library](https://github.com/love2d/lua-https) depends on OS specific implementations and thus extra steps have to be taken, specifically on Mac OS X, to allow requests to unsecured endpoints.
The respective implementation defaults the `NSExceptionAllowsInsecureHTTPLoads` key responsible for toggling the behaviour to `false`, making requests to unsecured http servers fail with status code 0.
After packaging the project with love-build, the resulting artifact for Mac can be unzipped and the pseudo-xml `Contents/Info.plist` can be supplied with domain specific exceptions for this behaviour, e.g.:
```Xml
NSAppTransportSecurity
NSExceptionDomains
yourdomain.com
NSExceptionAllowsInsecureHTTPLoads
```
After rezipping, unsecured http requests against that domain will work, additional configuration options can be found in [Apple's documentation](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW44).