V4 Components: Game Library Service

We already have those. Maybe I’m not understanding what you’re saying here, because we’ve always had those.

But we can’t search on them.

Which kind of bring up the point… What is the point of having the various data elements? Why are they important? What can we do with them?

You can. Why do you think you can’t?

All of this metadata will be available through the library API. So… you could do anything you want with it, but only if the fields you want are present. The use I intend to put it to first is generating all the module pages on the site.

Formatted as TOML, you might have this:

[game]
title = "Paths of Glory"
publisher = "GMT Games"
year = 1999
number_of_players = 2
tags = [ "WWI", "strategic", "card driven", "point to point" ]

I’ve collapsed all of the tag-like fields in to tags. I’m not convinced that length is a field we should keep. Maybe we should have the endpoints of the player range represented individually (though it would make it impossible to represent the allowed numbers of players for any oddball games which have gaps in their ranges…).

We should probably have a title_sortkey field, for handling titles that do not sort strictly alphabetically (e.g., anything starting with “A”, “An”, “The”).

If I go to the Modules section of the website, there is no generic (or advanced) search option. Instead, you have the ability to sort by a limited # of options - Number of Players, Publisher, Game Series, etc.

So if I wanted to say search on the following 2 examples, I can’t…

  1. Module Maintainer = Korval
  2. Game Designer = Craig Besinque AND Era = WW2

(these btw are both real examples I have wanted in the current system)

Having more sort options would be great, but having a search capability for modules would also be great. That seems to be where we are heading for V4…

You can do 1 with the search function in the wiki:

https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1

You can do 2 similarly, but you won’t get any results because game designers aren’t listed presently.

Some fields which are specific to modules, not to games:

For a particular module file:

  • name
  • version
  • authors
  • required Vassal version
  • description

(I’m not including size here because that’s not something you set, but is rather a property derived from the file.)

For all the versions of a module collectively:

  • notes
  • repository URL
  • homepage URL

I’m envisioning some of these as optional.

1 Like

Wow!! I would never have guessed that, nor would I have a clue where to start looking to see how to do it.

Not really, that returns any module page that contains the text ‘Korval’, whether that is maintainer, contributor or Player, or the module ‘Korval at War’. You get there in the end, but it’s not really a maintainer search as such.

We will want any metatdata we define to be individually searchable.

I’ve collapsed all of the tag-like fields in to tags.

I have no problem in collapsing all the tags into one list, as long as it is easy to view and select from the existing tags in a logical way when you are registering the modile. IMO, having ‘mechanism’ and ‘category’ tags mixed in together makes it more difficult to find what you are looking for. However. Module registration is a relatively infrequent process, so maybe that isn’t such an issue.

1 Like

The search field is available from the hamburger menu in the upper right.

From a Library perspective I would love to be able to have multiple tags within our defined classes. Some games are made by publisher A - reimplemented by publisher B etc…
BGG does this, unfortunately we cannot at this time.

It leads back to the original website chaos of X number of pages for the same game because module designers feel their module is different because of who actually published the game or their take on design

I know my thoughts here are kind of a side track to the meta data capture for V4 modules in future, but it is (and should be) part and parcel with our site at same time…

Everyone has very valid points to consider imo - Its a difficult problem to solve

1 Like

Below I will post a sketch of a Game Library Service API. Not everything is filled in yet. Comments welcome.

Module Library API Reference (Draft)

Reference

All paths relative to /api/v1.

Description

GET /projects

Get a list of projects.

Parameters
  • q Limit results to projects containing the query term.
  • tag Limit results to projects so tagged.
  • prefix Limit results to projects starting with the given prefix.
  • owner Limit results to projects having the given owner.
  • seek Key for pagination.
Returns
{
  "projects": [
    { },
    ...
  ],
  "meta": {
    "prev_page": "",
    "next_page": "",
    "total": 1234
  }
}

GET /projects/{proj_id}

Get current metadata for project proj_id.

Returns
{
  "id": "",
  "name": "",
  "description": "",
  "revision": 2,
  "created_at": "2023-08-12T17:10:29.188970+00:00",
  "modified_at": "2023-08-13T23:54:10.578320+00:00",
  "modified_by": "",
  "tags": [],
  "readme_path": "",
  "game": {
    "title": "",
    "title_sort_key": "",
    "publisher": "",
    "year": ""
  },
  "owners": ["alice", "bob"],
  "packages": [
    {
      "id": "",
      "name": "",
      "description": ""
      "versions": [
        {
          "number": "1.2.3",
          "dl_path": "",
          "type": "",
          "checksum": "",
          "size": 123456,
          "published_at": "2023-08-13T23:54:10.578320+00:00",
          "published_by": "",
          "requires": "",
          "authors": ["alice", "bob"]
        }
      ]
    }
  ]
}

PUT /projects/{proj_id}

Update metadata for project proj_id. Creates project proj_id if it does not yet exist.

Requires auth token. Logged in user must be in the owners list for a preexisting project.

Payload
{
  // TBD
}
Returns
{
  // TBD
}

GET /projects/{proj_id}/{revision}

Get metadata for project proj_id at revision.

Returns

See GET /projects/{proj_id} for the return format.

GET /projects/{proj_id}/owners

Get the list of owners for project proj_id.

Returns
{
  "users": ["alice", "bob"]
}

PUT /projects/{proj_id}/owners

Add owners for project proj_id.

Requires auth token. Logged in user must be in the owners list.

Payload
{
  "users": ["alice", "bob"] 
}

DELETE /projects/{proj_id}/owners

Remove owners from project proj_id.

Requires auth token. Logged in user must be in the owners list.

Payload
{
  "users": ["alice", "bob"] 
}

GET /projects/{proj_id}/players

Get the list of players for project proj_id.

Returns
{
  "users": ["alice", "bob"]
}

PUT /projects/{proj_id}/players

Add player for project proj_id.

Requires auth token. Logged in user must be the player to add.

Payload
{
  "user": "alice" 
}

DELETE /projects/{proj_id}/players

Remove player from project proj_id.

Requires auth token. Logged in user must be the player to remove.

Payload
{
  "user": "alice" 
}

GET /projects/{proj_id}/packages/{pkg_name}

Download current version of pkg_name. May be a redirect.

GET /projects/{proj_id}/packages/{pkg_name}/{version}

Download version of pkg_name. May be a redirect.

PUT /projects/{proj_id}/packages/{pkg_name}/{version}

Publish version of pkg_name. Fails if version already exists.

Requires auth token. Logged in user must be in the owners list.

Payload
{
   // TBD
}

GET /projects/{proj_id}/readme

Get the project readme for the current revision of proj_id. The readme is formatted as Markdown.

GET /projects/{proj_id}/readme/{revision}

Get the project readme for revision revision of proj_id. The readme is formatted as Markdown.

GET /projects/{proj_id}/images/{img_name}

PUT /projects/{proj_id}/images/{img_name}

Requires auth token. Logged in user must be in the owners list.

GET /tags

Parameters
  • prefix
Returns
{
  // TBD
}

GET /games

Parameters
  • prefix
Returns
{
  // TBD
}

GET /tags

Parameters
  • prefix
Returns
{
  // TBD
}

POST /login

Log in. (Possibly this should not be here, but in a user management service instead.)

Payload
{
  "username": "skroob",
  "passwrod": "12345"
}
Returns
{
  "token": "abcdefg..."
}

The token must be sent in an Authorization header for any requests requiring authroization:

Authorization: Bearer abcdefg...

GET /users

Get list of users. (This is needed by any frontend which will do autocomplete. Possibly this should not be here, but in a user management service instead.) Should support pagination.

Requires auth token.

Parameters
  • prefix
Returns
{
  "users": ["alice", "bob"]
}
1 Like

Looking good.

It will be good to lock in some sensible terminology as we go along.

So, my read is that a Project is roughly equivalent to a what we see in a Module Page currently. A Package is an individually versioned sub-component of the Project.

I’m guessing these will be individual files like the ‘Module’ (whatever that ends up being), version history and other associated documentation. An older LTS version of the Project main module might be stored as a separate Package while a newer version is being developed.

Do we want to keep using Module to refer to the thing that contains the game implementation? It’s a good word, I like it.

What are games? Is that a list of Games that the Project is implementing? Thoughts on how we maintain a unique list of these? I would suggest BGG game Id’s? Their TOS allow us to harvest their game DB for this sort of thing, no point in re-inventing the wheel. We can potentially do Ajax-style auto-complete lookups on game names etc.

A couple of comments:

  1. I like the term “module.” (One huge beef I have w/ Microsoft is how they keep changing the UI… (usually dumbing it down))

  2. Suggest add “game_designer” as a tag

  3. Probably out of scope for this discussion, but suggest consider 2-factor authentication for module/library actions (add, modify, delete). A common commercial paradigm is to send a security code to your registered email…

My comment on the game library service is that it is a great start to something that will really help VASSAL.

One design comment is to consider providing some useful links in the reply body that will save the client and the server from repeatedly accessing related information.

For example, a client accesses the projects endpoint which provides 5 owners and 50 players. Now the client assembles a request to access the 5 users and another request to get the 50 players. Also the notification requires some game information, so another request to the games or tags end point.

Obviously, getting all this information requires work from the client and the server and there is a balance somewhere in between too much client work, too much server work, and too much information over the wire. However sometimes, the information is easily available on the server side and much quicker than multiple requests/responses and encodes/decodes.

Another way to look at this is “how many useful next-step links do you want to provide the consumer”? This idea is part of the idea of a RESTful service, which might help generate more clients or might be too much.

Just food for thought. This web interface as-is is a major step-up in VASSAL customer service.

We’ve made significant progress on the GLS component since I started working on it seriously in October. There’s a nearly usable prototype here:

The short-term goal is to use the GLS to replace the current game library in the wiki. To that end, I’ve concurrently been working on a new game library frontend which uses the GLS:

I am aiming for these to be ready for use in March, but that is an aspiration, not a promise.

1 Like