diff --git a/bun.lock b/bun.lock index bc8d598e9..20e3051de 100644 --- a/bun.lock +++ b/bun.lock @@ -471,7 +471,6 @@ "@types/react-router-dom": "5.1.7", "@types/sql.js": "^1.4.11", "@types/supertest": "2.0.11", - "@types/tap": "^15.0.5", "@typescript-eslint/eslint-plugin": "^4.27.0", "@typescript-eslint/parser": "^4.27.0", "@typescript-eslint/utils": "^8.24.1", @@ -528,12 +527,10 @@ "node-fetch": "2.6.7", "node-html-parser": "^5.3.3", "node-mocks-http": "1.11.0", - "node-sass": "9.0.0", "nodemailer": "7.0.11", "pg": "^8.13.3", "pino": "^10.3.1", "pino-pretty": "^13.1.3", - "prettier": "3.2.5", "pretty-bytes": "5.6.0", "prom-client": "15.1.3", "prudence": "0.10.0", @@ -553,7 +550,6 @@ "sql.js": "^1.14.1", "supertest": "6.2.2", "sync-fetch": "^0.3.1", - "tap": "^15.1.6", "typescript": "^4.3.4", "typescript-eslint": "^8.24.1", "vite": "^8.0.0", diff --git a/old-docs/Justfile b/old-docs/Justfile deleted file mode 100644 index b1d0cfbff..000000000 --- a/old-docs/Justfile +++ /dev/null @@ -1,7 +0,0 @@ -[private] -interactive: - -@cd ../ && just - -# Run just the docs on http://localhost:3001. -start: - mkdocs serve -a 0.0.0.0:3001 \ No newline at end of file diff --git a/old-docs/LICENSE b/old-docs/LICENSE deleted file mode 100644 index ae481f07a..000000000 --- a/old-docs/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 zkldi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/old-docs/README.md b/old-docs/README.md deleted file mode 100644 index 92218a865..000000000 --- a/old-docs/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Tachi-Docs - -This is the documentation for Tachi. - -Our docs are hosted under [https://docs.tachi.ac](https://docs.tachi.ac) - -# Setup - -If you're in a horribly hellish python environment like me (Sorry Sera, you know its true) make sure you use `pip3` - -- `pip install mkdocs` -- `pip install mkdocs-material` -- `mkdocs serve` - -# Contributing - -Fork the repository and PR your changes to `main`. diff --git a/old-docs/docs/api/auth.md b/old-docs/docs/api/auth.md deleted file mode 100644 index c18c29077..000000000 --- a/old-docs/docs/api/auth.md +++ /dev/null @@ -1,61 +0,0 @@ -# API Authorisation - -Certain endpoints on the Tachi API require permissions. -This page covers how to present your permissions to the server, and what those permissions are. - -***** - -## Authorising Requests - -There are two ways to authorise a request. The first one involves API keys. - -### Token Authentication - -To use authentication with a request, you should set a HTTP header of: - -``` -Authorization: Bearer API_KEY -``` - -Where API_KEY is the API key you wish to use. - -### Self-Key Authentication - -The other way to authorise a request is with your session cookie. This **MUST NOT** be used by code, and is instead a way for logged-in users to interact with the API as themselves. - -To use authentication in this way, simply make a request with your `Kamaitachi_SESSION` or -`Bokutachi_SESSION` cookie. - -The reason for this second authentication method is so that, when a user logs in, they can use -the cookie they were set to also interact with the API. - -This type of authentication is referred to as "Self-Key" or "Session-Key" authentication, and it grants special -permissions over API Tokens, such as being able to change your password. - -## Getting Tokens - -You should make a Tachi API Client. With that, you can use [our OAuth2 Flow](../codebase/infrastructure/oauth2.md), -or our [Client File Flow](../codebase/infrastructure/file-flow.md). - -## Permissions - -An API key does not implicitly have permission to do anything on a users behalf for security reasons. -Some endpoints require specific permissions, such as a `score_submit` permission for submitting scores. - -!!! warning - API keys **can not** have their permissions altered once set, a new key must be generated. - -!!! info - Cookie-based authentication always has *all* permissions for the user. - -### Table Of Permissions - -The table of permissions is as follows. - -| Permission | Description | -| :: | :: | -| `submit_score` | Perform requests that could submit scores for the user. | -| `customise_profile` | Perform requests that could modify user info, like their status or about me. | -| `customise_session` | Perform requests that could modify the users sessions, such as changing their names. | -| `customise_score` | Perform requests that could modify a users scores, such as adding a comment. | -| `delete_score` | Perform requests that could delete scores for that user. | diff --git a/old-docs/docs/api/index.md b/old-docs/docs/api/index.md deleted file mode 100644 index dd3587899..000000000 --- a/old-docs/docs/api/index.md +++ /dev/null @@ -1,101 +0,0 @@ -# API Overview - -Tachi exposes a public API which allows programs to interact with Tachi. - -This means you could make your own applications that work off of Tachi's -datasets. - -!!! warning -This documentation assumes some basic programming knowledge, such as how to make -HTTP requests, and how to parse JSON. - -Depending on what variant of Tachi you want to interact with, the API is hosted -on `https://kamai.tachi.ac/api/v1` or `https://boku.tachi.ac/api/v1`. - -!!! note -Some API endpoints are only available on Kamaitachi or Bokutachi. If an -endpoint has this restriction, it will be documented on that endpoints' -page. - ---- - -## Abuse - -The Tachi API is provided under the assumption that it will be used to make -cool things, and used responsibly. - -Abuse of this API will result in your ability to use it being banned. - -The API has a rate limit of 500 requests every minute. This is a very -generous rate limit, and you should not even be close to hitting it. - -If you are in a scenario where you might be hitting even 100 requests a minute consistently, -send an email to `zk@tachi.ac` and let me know what you're up to. Otherwise, I might revoke your tokens for abuse. - -## License - -[Tachi-Server](https://github.com/zkldi/Tachi/tree/main/server) (Where the API is written) is licensed under the [AGPLv3](https://www.gnu.org/licenses/agpl-3.0.en.html). - -To quote GitHub: - -!!! quote -Permissions of this strongest copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights. When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available. - -This is not legal advice. - -## Requests - -Unless otherwise mentioned, all non-GET request properties should be sent to the API in `application/json` form. - -GET request properties should be sent to the API in the Query String. - -Your authentication tokens should be sent in the HTTP `Authorization` header, using `Bearer token` form. - -You should provide this token for every endpoint. Even though not all endpoints -require authentication tokens, they are still used for API analytics. - -## Response - -Unless otherwise mentioned, all responses to the API are in `application/json` form. - -The API has two schemas for JSON responses. - -### Success Response - -As the name implies, the Success Response is returned on a successful request. - -| Property | Type | Description | -| :-----------: | :----------------: | :-------------------------------------------------------------------------------------------: | -| `success` | true | Always true for a successful response. | -| `description` | String | Information about what happened with the request. | -| `body` | Endpoint Dependent | Any data that the endpoint needs to return, such as a user's document from a profile request. | - -The HTTP Status Code for any Success Response will always be of 2XX form. - -### Failed Response - -As the name implies, the Failed Response is returned when a request fails. - -| Property | Type | Description | -| :-----------: | :----: | :-------------------------------------------------: | -| `success` | false | Always false for a failed response. | -| `description` | String | Information about what went wrong with the request. | - -The HTTP Status Code for any Failed Response will always be of either 4XX or 5XX form. - -!!! warning -The `description` property is **NOT** intended for program usage. You should **NEVER** depend -on the output of `description`, as it may be changed at any time for any reason. - -!!! note -Any API request can fail for any reason. You should always account for the -case where the request fails. - -## Footnote - -That should be everything. If you have any questions about the API, you can -contact me at `zk@tachi.ac`. You can also write an issue on the -[Issue Tracker](https://github.com/zkldi/Tachi). I'll get around to either. - -It's entirely possible that I might've made a typo or wrote a poor explaination -of something, so please reach out! diff --git a/old-docs/docs/api/routes/admin.md b/old-docs/docs/api/routes/admin.md deleted file mode 100644 index c70606dc7..000000000 --- a/old-docs/docs/api/routes/admin.md +++ /dev/null @@ -1,224 +0,0 @@ -# Admin Endpoints - -These endpoints are for adminstrator use. As such, they all -require an `authLevel` of at least 3. For more information, see the [UserDocument](../../schemas/user.md). - -***** - -## Change Server Log Level - -`POST /api/v1/admin/change-log-level` - -### Permissions - -- Admin - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `logLevel` | "crit" \| "severe" \| "warn" \| "info" \| "verbose" \| "debug" | The log level to change to. | -| `duration` | Number, Optional | How long to keep this change for in minutes. If not set, defaults to 60 minutes. | -| `noReset` | Boolean, Optional | If true, do not ever reset this log level change. | - -### Response - -Empty Object. - -### Example - -#### Request -``` -POST /api/v1/admin/change-log-level - -{ - duration: 5, - logLevel: "verbose" -} -``` - -#### Response - -Empty Object. - -***** - -## Delete any Score - -This performs all the necessary checks to remove a score document aswell. - -`POST /api/v1/admin/delete-score` - -### Permissions - -- Admin - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `scoreID` | String | The scoreID to delete. | - -### Response - -Empty Object. - -***** - -## Re-run PB processing for every scored user+chart (synchronous). - -`POST /api/v1/admin/recalc-pbs` - -Inserts every distinct `(user_id, chart_id)` from the **`score`** table into **`pb_dirty`**, then **drains** `pb_dirty` and downstream **`session_dirty`** / **`game_profile_dirty`** queues until nothing remains (same batching as the background worker, but the HTTP request waits until idle). Intended when PBs may be out of sync (e.g. after a bad migration). There is **no request body** and no filter-always all distinct pairs that appear on scores. - -### Permissions - -- Admin - -### Parameters - -None (send `{}` if your client requires a body). - -### Response - -Empty object (standard success wrapper with `body`). - -### Example - -#### Request - -``` -POST /api/v1/admin/recalc-pbs -``` - -```js -{} -``` - -#### Response - -```js -{} -``` - -***** - -## Destroy a users GPT Profile and forces a leaderboard recalc. - -`POST /api/v1/admin/destroy-ugpt` - -!!! warning - This is intended to completely remove a users GPT profile. - You should use this **only** if a user has irrevocably screwed - their account. Preferably early on! - -### Permissions - -- Admin - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `userID` | Integer | The user part of the UGPT. | -| `game` | Game | The game part of the UGPT. | -| `playtype` | Playtype | The PT part of the UGPT. Must be for the above game. | - -### Response - -Empty Object. - -### Example - -#### Request -``` -POST /api/v1/admin/destroy-ugpt -``` - -```js -{ - "userID": 1, - "game": "iidx", - "playtype": "DP" -} -``` - -#### Response - -Empty Object. - -***** - -## Destroy a chart and all of its scores. - -`POST /api/v1/admin/destroy-chart` - -### Permissions - -- Admin - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `chartID` | String | The chartID you wish to destroy. | -| `game` | Game | The game this chart belongs to (Necessary for lookups). | - -### Response - -Empty Object. - -### Example - -#### Request -``` -POST /api/v1/admin/destroy-chart -``` -```js -{ - "chartID": "SomeChartID", - "game": "iidx" -} -``` - -#### Response - -Empty Object. - -***** - -## Re-derive all scores site-wide (synchronous). - -`POST /api/v1/admin/recalc` - -Enqueues **every chart** into **`score_rederive`**, then **drains** `score_rederive` and downstream **`pb_dirty`**, **`session_dirty`**, and **`game_profile_dirty`** queues until nothing remains (the request waits until idle). Re-runs `scoreDeriver` and `scoreCalcs` for every score. There is **no request body** and no filter-always all charts. - -### Permissions - -- Admin - -### Parameters - -None (send an empty JSON object `{}` if your client requires a body). - -### Response - -Empty object (standard success wrapper with `body`). - -### Example - -#### Request - -``` -POST /api/v1/admin/recalc -``` - -```js -{} -``` - -#### Response - -```js -{} -``` diff --git a/old-docs/docs/api/routes/api-tokens.md b/old-docs/docs/api/routes/api-tokens.md deleted file mode 100644 index bfefed7e9..000000000 --- a/old-docs/docs/api/routes/api-tokens.md +++ /dev/null @@ -1,92 +0,0 @@ -# API Token Management - -These endpoints relate to managing a users created API Tokens. -These tokens are likely to be generated from an OAuth2 integration, but in the future users may be able to create their own API Keys manually. - -!!! note - All of the below endpoints require [Self Key](../auth.md) level authentication. You cannot interact with these endpoints with Bearer auth. - -***** - -## Retrieve all API Tokens - -`GET /api/v1/users/:userID/api-tokens` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | APIKeyDocument | An array of APIKeyDocuments that belong to this user. | - -### Example - -#### Request -``` -GET /api/v1/users/1/api-tokens -``` - -#### Response -```json -[{ - "identifier": "Fervidex Token", - "token": "foobar", - "permissions": {"submit_score": true}, - "userID": 1, - "fromAPIClient": "FERVIDEX_OA2_CLIENT_ID" -}] -``` - -***** - -## Delete a specific token. - -`DELETE /api/v1/users/:userID/api-token/:token` - -### Parameters - -None. - -### Response - -Empty Object. - -### Example - -#### Request -``` -DELETE /api/v1/users/1/api-token/foobar -``` - -#### Response -```json -{} -``` - -***** - -## Create an API Token - -`POST /api/v1/users/:userID/api-tokens/create` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `permissions` | Array<String> | An array of permissions you wish the key to have. | -| `clientID` | String | Alternatively, you can pass the clientID of an OAuth2 Client. This will select permissions based on what that client wants. | -| `identifier` | String | A humanised identifier for what the string was from. Necessary if using `permissions`. Filled out for you if using `clientID`. - -!!! info - If using ClientID for permissions, the clientID will be pinned to the - token you've created as `fromAPIClient`. You can only have one - API Token per OAuth2 client, and will get a 409 if you repeat the request. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | APITokenDocument | The API Token you created. | diff --git a/old-docs/docs/api/routes/auth.md b/old-docs/docs/api/routes/auth.md deleted file mode 100644 index 4ca883bce..000000000 --- a/old-docs/docs/api/routes/auth.md +++ /dev/null @@ -1,283 +0,0 @@ -# Internal Authentication - -These endpoints relate to internal authentication methods. Read the warning below. - -!!! danger -This is **NOT** for external use. You should **NEVER** -be requesting a username and password from a user. - - Furthermore, interacting with this programmatically - is near-impossible because you need to complete a CAPTCHA. - - Nevertheless, This is documented for completeness' sake. - -!!! warning -All of these endpoints are aggressively rate limited. If you fire a bot at this, you will probably get -your IP blacklisted. Don't do that. - ---- - -## Login with username and password. - -`POST /api/v1/auth/login` - -Logs a user in and returns a session cookie. - -### Parameters - -| Property | Type | Description | -| :---------: | :----: | :---------------------------------------------------------------------------------------: | -| `username` | String | The user's username. This is compared case-insensitively. | -| `!password` | String | The user's password. | -| `captcha` | String | The hCaptcha response token from the client widget; the server verifies it with hCaptcha. | - -!!! info -The `!` prefix is special in that anything with it is assumed to be private and is **always** -ignored by our request logger. - - Without it, we would log passwords! - -### Response - -| Property | Type | Description | -| :------: | :-----: | :--------------------------------------: | -| `userID` | Integer | The ID of the user you authenticated as. | - -| HTTP Header | Description | -| :----------: | :--------------------------------------------------: | -| `Set-Cookie` | Contains a session cookie for future authentication. | - -### Example - -#### Request - -``` -POST /api/v1/auth/login -``` - -```json -{ - "username": "zkldi", - "!password": "my_password", - "captcha": "herebedragons" -} -``` - -#### Response - -```json -{ - "userID": 1 -} -``` - ---- - -## Register a new account. - -`POST /api/v1/auth/register` - -### Parameters - -| Property | Type | Description | -| :----------------------------: | :------------------------------------: | :------------------------------------------------------------------------------------------------------------------: | -| `username` | String | A string between 3 and 20 characters. The first character must be A-Z, _ or -. The other 19 may be A-Z, 0-9, _ or -. | -| `!password` | String | An 8 character or longer string. | -| `!email` | String | Valid email. The `!` prefix keeps this field out of server request logs. | -| `inviteCode` (Kamaitachi Only) | String (Undefined/Unused on Bokutachi) | If on Kamaitachi, this is the user's invitation code. | -| `captcha` | String | The hCaptcha response token from the client widget; the server verifies it with hCaptcha. | - -### Response - -| Property | Type | Description | -| :------: | :-----------------------------------: | :-------------------------------------: | -| `` | [UserDocument](../../schemas/user.md) | The newly-created user's User Document. | - -### Example - -#### Request - -``` -POST /api/v1/auth/register -``` - -```json -{ - "username": "newGuy", - "!password": "my_password", - "captcha": "herebedragons", - "!email": "test@example.com" -} -``` - -#### Response - -```json -{ - "id": 2, - "username": "newGuy", - "usernameLowercase": "newguy", - "socialMedia": { - "discord": null, - "twitter": null, - "github": null, - "steam": null, - "youtube": null, - "twitch": null - }, - "joinDate": 1639628634978, - "lastSeen": 1639628634978, - "about": "I'm a fairly nondescript person.", - "status": null, - "customPfpLocation": null, - "customBannerLocation": null, - "clan": null, - "badges": [], - "authLevel": 1 -} -``` - ---- - -## Verify an email from the code that was sent to it. - -`POST /api/v1/auth/verify-email` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :------------------------------------------: | -| `code` | String | The Code that was sent to the users mailbox. | - -### Response - -Empty Object - -### Example - -#### Request - -``` -{ - "code": "abcdef1234567890" -} -``` - -#### Response - -Empty Object. - ---- - -## Resend a verification email to the requesting user's email address. - -`POST /api/v1/auth/resend-verify-email` - -**Requires Self-Key Level Auth** - -### Parameters - -None, This endpoint reads the requesting user from their session. - -### Response - -Empty object. - -### Example - -N/A - ---- - -## Log Out. - -`POST /api/v1/auth/logout` - -Destroys the current session associated with this cookie. - -### Parameters - -None. - -### Response - -Empty Object. - -### Example - -#### Request - -``` -POST /api/v1/auth/logout -``` - -#### Response - -Nothing. - ---- - -## Create a password reset code and send it to the provided email. - -`POST /api/v1/auth/forgot-password` - -!!! note -This endpoint sends the password reset code pretty-printed to the email, and is **NOT** -returned as part of the HTTP request. - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :-------------------------------------------------------------------------------------------------------------: | -| `!email` | String | A user's email. If the email does not correspond to any accounts, 202 is returned anyway as a security measure. Request logs omit this field. | - -### Response - -Empty Object. The endpoint immediately returns 202 to avoid giving away information about registered emails. - -### Example - -#### Request - -```js -{ - "!email": "zkldiv@gmail.com" -} -``` - -#### Response - -Although the request body returns nothing, `zkldiv@gmail.com` will have recieved an email with -a URL containing the password reset code. - ---- - -## Reset a user's password with a password reset code. - -`POST /api/v1/auth/reset-password` - -### Parameters - -| Property | Type | Description | -| :---------: | :----: | :----------------------------------------------------------------: | -| `code` | String | A password reset code. This is provided in a password reset email. | -| `!password` | String | The password to change to. | - -### Response - -Empty Object. - -### Example - -#### Request - -```js -{ - "code": "1234567890abcdef", - "!password": "zkldi_so_cool", -} -``` - -#### Response - -Empty Object. diff --git a/old-docs/docs/api/routes/clients.md b/old-docs/docs/api/routes/clients.md deleted file mode 100644 index fd2024edf..000000000 --- a/old-docs/docs/api/routes/clients.md +++ /dev/null @@ -1,254 +0,0 @@ -# API Client Management - -These endpoints relate to managing your Tachi API clients, such as creating new ones or deleting them. - -For a detailed explaination on how to use the OAuth2 flow, you can check [Using OAuth2 With Tachi](../../codebase/infrastructure/oauth2.md). - -***** - -!!! warning - All endpoints on this list require [Self Key](./user-integrations.md) level authentication. - - That is to say, it cannot be performed using Bearer tokens, and must be done by the user themselves. - -***** - -## Retrieve all clients you have created. - -`GET /api/v1/clients` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | Array<OAuth2ClientDoc> | All of the OAuth2 clients you have created. | - -### Example - -#### Request -``` -GET /api/v1/clients -``` - -#### Response - -```json -[{ - "name": "My Client", - "clientID": "blah", - "clientSecret": "secret!!", - "requestPermissions": ["customise_profile"], - "author": 1, - "redirectUri": "https://example.com/callback", -}, - // ... -] -``` - -***** - -## Create a new OAuth2 Client - -`POST /api/v1/clients/create` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `name` | String | A string between 3 and 80 characters. The name for this client. | -| `redirectUri` | Optional String (Valid URI) | Must be a HTTP/HTTPS URL, This is where users will be sent to after clicking Yes on the prompt. | -| `webhookUri` | Optional String (Valid URI) | Must be a HTTP/HTTPS URL. Registers this URL as a URL that wants webhook events to be sent to it. Read more about webhooks [here](../webhooks/main.md). | -| `apiKeyFormat` | Optional String | If present, this sets an expected format for the API Key in [Client File Flow](../../codebase/infrastructure/file-flow.md). Must contain %%TACHI_KEY%%. | -| `apiKeyFilename` | Optional String | If present, this sets a filename fir [Client File Flow](../../codebase/infrastructure/file-flow.md). | -| `permissions` | Array<Permissions> | An array of permissions this client requests. You can check all permissions [here](../auth.md). | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | OAuth2ClientDoc | The OAuth2Client you just created. | - -### Example - -#### Request -``` -POST /api/v1/clients/create - -{ - "name": "My Client", - "redirectUri": "https://example.com/callback", - "permissions": ["customise_profile"] -} -``` - -#### Response - -```json -{ - "name": "My Client", - "redirectUri": "https://example.com/callback", - "webhookUri": null, - "requestedPermissions": ["customise_profile"], - "clientID": "foobar", - "clientSecret": "secret_val", - "apiKeyFormat": null, - "apiKeyFilename": null -} -``` - -***** - -## Retrieve information about a client - -`GET /api/v1/clients/:clientID` - -This is used to display information about this client to the user, when they are deciding on whether to authenticate it. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | OAuth2ClientDoc without clientSecret | The client document at this ID. | - -### Example - -#### Request -``` -GET /api/v1/clients/some_client_id -``` - -#### Response -```json -{ - "name": "My Client", - "redirectUri": "https://example.com/callback", - "webhookUri": null, - "requestedPermissions": ["customise_profile"], - "clientID": "foobar", - "clientSecret": "secret_val", - "apiKeyFormat": null, - "apiKeyFilename": null -} -``` - -***** - -## Modify existing client - -`PATCH /api/v1/clients/:clientID` - -### Permissions - -- Must be the owner of this client. - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `name` | String | A string between 3 and 80 characters. | -| `webhookUri` | String | A new webhookUri. | -| `redirectUri` | String | A new redirectUri. | -| `apiKeyFormat` | String | A new apiKeyFormat. | -| `apiKeyFilename` | String | A new apiKeyFilename. | - - -!!! note - If you need to change permissions, you must make another client. - - Also, all the above properties are optional. If not present, they will not be changed. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | OAuth2ClientDoc | The new client document with the patched changes applied. | - -### Example - -#### Request -``` -PATCH /api/v1/clients/some_client_id - -{ - "name": "new name!" -} -``` - -#### Response - -```json -{ - "name": "new name", - "clientID": "some_client_id", - // ... same props as in previous responses -} -``` - -***** - -## Reset your client's secret. - -`POST /api/v1/clients/:clientID/reset-secret` - -!!! warning - This does **NOT** reset api keys created by this client as per OAuth2 spec. - - If you need that functionality, you will need to delete - your client. - -### Permissions - -- Must be the owner of this client. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | OAuth2ClientDoc | The new client document with the new secret. | - -### Example - -#### Request -``` -POST /api/v1/clients/some_client_id/reset-secret -``` - -#### Response -```json -{ - "name": "some client", - "clientID": "some_client_id", - "clientSecret": "FRESHLY_GENERATED_SECRET!", - // ... more props -} -``` - -***** - -## Delete your client. - -`DELETE /api/v1/clients/:clientID` - -### Permissions - -- Must be the owner of this client. - -### Parameters - -None. - -### Response - -Empty Object. diff --git a/old-docs/docs/api/routes/config.md b/old-docs/docs/api/routes/config.md deleted file mode 100644 index e8ecf22f2..000000000 --- a/old-docs/docs/api/routes/config.md +++ /dev/null @@ -1,33 +0,0 @@ -# Config Endpoints - -These endpoints display certain properties about the Tachi [config file](../../codebase/setup/config.md). - -***** - -## Return the value of the BEATORAJA_QUEUE_SIZE - -`GET /api/v1/config/beatoraja-queue-size` - -**Bokutachi Only** - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | Integer | The value in `conf.json5` for BEATORAJA_QUEUE_SIZE. | - - -## Return the value of the USC_QUEUE_SIZE - -`GET /api/v1/config/usc-queue-size` - -**Bokutachi Only** - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | Integer | The value in `conf.json5` for USC_QUEUE_SIZE. | - - - diff --git a/old-docs/docs/api/routes/example.md b/old-docs/docs/api/routes/example.md deleted file mode 100644 index 289b84791..000000000 --- a/old-docs/docs/api/routes/example.md +++ /dev/null @@ -1,113 +0,0 @@ -# Example Endpoint - -_Endpoints will be formatted like this. - These are not real endpoints!_ - ---- - -## Greet a user. - -`GET /api/v1/greet` - -This endpoint greets the user. - -### Permissions - -_If permissions are required, they will be listed here._ - -- example_permission - -### Parameters - -_Parameters are required unless explicitly stated to be optional._ - -!!! note -As mentioned in API Overview, GET parameters are to be sent in the query string, -and all other methods are to have their content in the request body as -`application/json`. - -| Property | Type | Description | -| :-------------------: | :------: | :---------------------------------------: | -| `name` | String | The name of the user to greet. | -| `birthday` (optional) | Presence | Whether it is the user's birthday or not. | - -Not providing required parameters will result in a 400 error. - -### Response - -_Parameters are always present unless stated to be conditional/optional._ - -!!! info -The below properties correspond to keys in the `body` -property of a request. - - This means that the below table corresponds to - ```json - { - "success": true, - "description": "Greeted user.", - "body": { - "greeting": "Hello, zkldi!", - "wasBirthday": false, - } - } - ``` - -| Property | Type | Description | -| :-----------: | :-----: | :-----------------------------------------: | -| `greeting` | String | A greeting for the user. | -| `wasBirthday` | Boolean | Whether today is the users birthday or not. | - -!!! info -Since the above table corresponds to keys in the `body` -property of a request, the special property name -`` refers to the body itself. - - For example: - - | Property | Type | Description | - | :: | :: | :: | - | `` | String | The greeting. | - - Corresponds to: - ```json - { - "success": true, - "description": "Greeted user.", - "body": "Hello, zkldi - } - ``` - -### Example - -#### Request - -``` -GET /greet?name=zkldi -``` - -#### Response - -```json -{ - "greeting": "Hello, zkldi - "wasBirthday": false -} -``` - -!!! warning -The example response is implicitly the `body` key of the API response. -That is to say that, the real response for this request is: - - ```json - { - "success": true, - "description": "Greeted user.", - "body": { - "greeting": "Hello, zkldi - "wasBirthday": false - } - } - ``` - - This is omitted, because it's redundant all of the time. -- That is to say, - You should never depend on parsing the content of `description`. diff --git a/old-docs/docs/api/routes/games.md b/old-docs/docs/api/routes/games.md deleted file mode 100644 index ab77bf097..000000000 --- a/old-docs/docs/api/routes/games.md +++ /dev/null @@ -1,78 +0,0 @@ -# Game Endpoints - -These endpoints cover all games and specific games. For -specific playtypes, see [Game:Playtype Endpoints](./gpt.md). - -***** - -## Retrieve all supported games. - -`GET /api/v1/games` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `supportedGames` | String[] | The list of games this service supports. | -| `configs` | Record<Game, [GameConfig](../../codebase/implementation-details/game-configuration.md)> | Contains a mapping of every supported game to its configuration. | - -### Example - -#### Request -``` -GET /api/v1/games -``` - -#### Response - -```json -{ - "supportedGames": ["iidx", "bms"], - "configs": { - "iidx": { - "name": "beatmania IIDX", - // ... - }, - "bms": { - "name": "BMS", - // ... - } - } -} -``` - -***** - -## Retrieve a specific games' configuration. - -`GET /api/v1/games/:game` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | GameConfig | The configuration for this game. | - -### Example - -#### Request -``` -GET /api/v1/games/iidx -``` - -#### Response - -```json -{ - "name": "beatmania IIDX", - "validPlaytypes": ["SP", "DP"], -} -``` diff --git a/old-docs/docs/api/routes/gpt-targets.md b/old-docs/docs/api/routes/gpt-targets.md deleted file mode 100644 index 6b154a6da..000000000 --- a/old-docs/docs/api/routes/gpt-targets.md +++ /dev/null @@ -1,369 +0,0 @@ -# GPT-Target Endpoints - -These endpoints deal with [targets](../../api/terminology.md) for a Game + Playtype. These are things like searching goals or quests, or retrieving information about a specific ID. - -For user-specific target endpoints, such as subscriptions, see [UGPT-Target Endpoints](./ugpt-targets.md). - ---- - -## Retrieve this game's recently achieved targets - -`GET /api/v1/games/:gameGroup/:playtype/targets/recently-achieved` - -!!! info -This endpoint returns the 100 most recently achieved goal subscriptions, and 50 most recently achieved quest subscriptions. - - A target is not considered recently achieved if it was [instantly achieved](../../codebase/implementation-details/goals-quests.md#instant-indirect-achievements). - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :---------: | :---------------------------: | :-------------------------------------------------------: | -| `goals` | Array<GoalDocument> | The goal documents that were recently achieved. | -| `quests` | Array<QuestDocument> | The quest documents that were recently achieved. | -| `goalSubs` | Array<GoalSubDocument> | User subscriptions to goals that were recently achieved. | -| `questSubs` | Array<QuestSubDocument> | User subscriptions to quests that were recently achieved. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/targets/recently-achieved -``` - -#### Response - -```js -{ - goals: [{ - name: "HARD CLEAR 5.1.1 Another", - goalID: "foo" - // ... other goal props - }], - quests: [{ - name: "Go Beyond Diamond 1", - questID: "bar", - // ... other quest props - }], - goalSubs: [{ - userID: 1, - goalID: "foo", - achieved: true, - // ... other goalsub props - }], - questSubs: [{ - userID: 3, - questID: "bar", - achieved: true, - // ... other quest sub props - }] -} -``` - ---- - -## Retrieve this game's recently interacted-with targets - -`GET /api/v1/games/:gameGroup/:playtype/targets/recently-raised` - -!!! info -This endpoint returns the 100 most recently interacted-with goal subscriptions, and 50 most recently interacted-with quest subscriptions. - - A recently interacted with target subscription is one where `progress` or `outOf` has changed recently. - -!!! warn -This endpoint excludes achieved targets -- targets still get interacted with when achieved, which means a user with a lot of targets will just flood this endpoint with redundant updates on larger imports. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :---------: | :---------------------------: | :--------------------------------------------------------------: | -| `goals` | Array<GoalDocument> | The goal documents that were recently achieved. | -| `quests` | Array<QuestDocument> | The quest documents that were recently achieved. | -| `goalSubs` | Array<GoalSubDocument> | User subscriptions to goals that were recently interacted with. | -| `questSubs` | Array<QuestSubDocument> | User subscriptions to quests that were recently interacted with. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/targets/recently-raised -``` - -#### Response - -```js -{ - goals: [{ - name: "HARD CLEAR 5.1.1 Another", - goalID: "foo" - // ... other goal props - }], - quests: [{ - name: "Go Beyond Diamond 1", - questID: "bar", - // ... other quest props - }], - goalSubs: [{ - userID: 1, - goalID: "foo", - achieved: false, - lastInteraction: 1649438990417, - // ... other goalsub props - }], - questSubs: [{ - userID: 3, - questID: "bar", - achieved: false, - lastInteraction: 1649438990415, - // ... other quest sub props - }] -} -``` - ---- - -## Get the most popular goals for this GPT. - -`GET /api/v1/games/:gameGroup/:playtype/targets/goals/popular` - -### Parameters - -N/A - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------: | :------------------------------------------------------------------------------------------------------------------: | -| `` | Array<GoalDocument & `__subscriptions` > | An array of the 100 most popular goals for this GPT, where `__subscriptions` is how many subscriptions the goal has. | - -### Example - -#### Request - -``` -GET /api/v1/games/:gameGroup/:playtype/targets/goals/popular -``` - -#### Response - -```js -[ - { - name: "HARD CLEAR foo", - // ... - }, - { - name: "AAA foo", - // ... - }, -]; -``` - ---- - -## Retrieve information about a specific goal and its subscribers. - -`GET /api/v1/games/:gameGroup/:playtype/targets/goals/:goalID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------------: | :--------------------------: | :---------------------------------------: | -| `goal` | GoalDocument | The goal document at this ID. | -| `goalSubs` | Array<GoalSubDocument> | All of the subscriptions to this goal. | -| `users` | Array<UserDocument> | All of the users subscribed to this goal. | -| `parentQuests` | Array<QuestDocument> | All of the quests that include this goal. | - ---- - -## Evaluate a goal upon a user. - -`GET /api/v1/games/:gameGroup/:playtype/targets/goals/:goalID/evaluate-for` - -!!! note -This endpoint is notably in a bit of a strange position. It can't go under UGPT because -`UGPT/goals/:goalID` is for goal subscriptions, and overloading the endpoint to be -something like "return the goal subscription or evaluate it if doesn't exist" is ugly. - - As such, it ends up here, but is generally a bit awkward. - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :---------------------------------: | -| `userID` | String | The user to evaluate this goal for. | - -### Response - -| Property | Type | Description | -| :---------------------: | :----------: | :-----------------------------------------------------: | -| `goal` | GoalDocument | The goal document that was evaluated. | -| `user` | UserDocument | The user that this goal was evaluated for. | -| `results.achieved` | Boolean | Whether this user would have this goal achieved or not. | -| `results.progress` | Integer | What this user's progress would be on this goal. | -| `results.progressHuman` | String | A user friendly format for this user's goal progress. | -| `results.outOf` | Integer | What this goal was out of. | -| `results.outOfHuman` | String | A user friendly format for what this goal was out of. | - -!!! info -For more info on `progress`/`outOf`, see [Goals](../../codebase/implementation-details/goals-quests.md#evaluating-a-users-progress). - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/targets/goals/some_goal_id/evaluate-for?userID=zkldi -``` - -#### Response - -```js -{ - user: { - username: "zkldi - id: 1, - // ... - }, - goal: { - goalID: "some_goal_id", - name: "FULL COMBO some chart" - // ... - }, - result: { - achieved: false, - progress: 5, - progressHuman: "EX HARD CLEAR", - outOf: 6, - outOfHuman: "FULL COMBO" - } -} -``` - ---- - -## Search quests for this GPT. - -`GET /api/v1/games/:gameGroup/:playtype/targets/quests` - -!!! note -You might notice that there's no equivalent endpoint for goals. - - Searching goals for a GPT isn't very interesting, since they can be created by anyone at any time. The only reason goals are stored separately to subscriptions are for deduplication purposes and quests. - - As such, searching goals for a GPT is pointless, since technically it should search the set of all possible goals. - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :----------------------: | -| `search` | String | The query to search for. | - -### Response - -| Property | Type | Description | -| :------: | :------------------------: | :--------------------------------------------------: | -| `` | Array<QuestDocument> | All of the quests that matched this search criteria. | - ---- - -## Retrieve information about a specific quest, and who is subscribed to it. - -`GET /api/v1/games/:gameGroup/:playtype/targets/quests/:questID` - -### Parameters - -N/A - -### Response - -| Property | Type | Description | -| :----------------: | :----------------------------: | :-------------------------------------------------: | -| `quest` | QuestDocument | The quest with this questID. | -| `questSubs` | Array<QuestSubDocument> | All of the subscriptions to this quest. | -| `users` | Array<UserDocument> | All of the user's with subscriptions to this quest. | -| `goals` | Array<GoalDocument> | All of the goals in this quest. | -| `parentQuestlines` | Array<QuestlineDocument> | Any questlines that contain this quest. | - ---- - -## Evaluate a quest for a user, even if they aren't subscribed to it. - -`GET /api/v1/games/:gameGroup/:playtype/targets/quests/:questID/evaluate-for` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :--------------------------------------------: | -| `userID` | String | The user you wish to evaluate this quest upon. | - -### Response - -| Property | Type | Description | -| :-----------: | :------------------------------: | :-------------------------------------------------------------------------------: | -| `goals` | Array<GoalDocument> | All of the goals in this quest. | -| `goalResults` | Array<EvaluatedGoalResult> | This user's progress on each individual goal in this quest. | -| `achieved` | Boolean | Whether this user has this quest achieved or not. | -| `progress` | Integer | How many goals this user has achieved in this quest. | -| `outOf` | Integer | How many goals need to be achieved in this quest for it to be marked as achieved. | - -#### EvaluatedGoalResult - -| Property | Type | Description | -| :-------------: | :------------: | :--------------------------------------------------------------------------------------: | -| `goalID` | String | The goal ID that these results are for. | -| `achieved` | Boolean | Whether this goal was achieved or not. | -| `progress` | Number \| Null | How much progress this user made on this goal. Null if no progress was made. | -| `outOf` | Number | What `progress` needs to be greater than or equal to for this goal to count as achieved. | -| `progressHuman` | String | A humanised, pretty-printed progress indicator for this goal. | -| `outOfHuman` | String | A humanised, pretty-printed outOf indicator for this goal. | - ---- - -## Search Questlines - -`GET /api/v1/games/:gameGroup/:playtype/targets/questlines` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :----------------------------------: | -| `search` | String | A name of a questline to search for. | - -### Response - -| Property | Type | Description | -| :------: | :----------------------------: | :------------------------------------------------------------: | -| `` | Array<QuestlineDocument> | An array of QuestlineDocuments, based on the search parameter. | - ---- - -## Retrieve a questline with a specific ID. - -`GET /api/v1/games/:gameGroup/:playtype/targets/questlines/:questlineID` - -### Parameters - -N/A - -### Response - -| Property | Type | Description | -| :---------: | :------------------------: | :-------------------------------------------------: | -| `questline` | QuestlineDocument | The questline document at this ID. | -| `quests` | Array<QuestDocument> | All of the quest documents that belong to this set. | diff --git a/old-docs/docs/api/routes/gpt.md b/old-docs/docs/api/routes/gpt.md deleted file mode 100644 index df5e50f46..000000000 --- a/old-docs/docs/api/routes/gpt.md +++ /dev/null @@ -1,621 +0,0 @@ -# Game:Playtype Endpoints - -These endpoints are for games + their playtypes. -To find out what games are supported by a service -programmatically, you should see [Game Endpoints](./games.md). - ---- - -## Retrieve Game:Playtype Configuration. - -`GET /api/v1/games/:gameGroup/:playtype` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :----------: | :----------------------------------------------: | -| `config` | GamePTConfig | The configuration file for this game + playtype. | - -!!! warning -A GamePTConfig is different to a GameConfig! Read more -[here](../../codebase/implementation-details/game-configuration.md). - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP -``` - -#### Response - -```json -{ - "config": { - "idString": "iidx:SP", - - "percentMax": 100, - - "defaultScoreRatingAlg": "ktRating", - "defaultSessionRatingAlg": "ktRating", - "defaultProfileRatingAlg": "ktRating" - - // ... more props - a lot more props - } -} -``` - ---- - -## Retrieve the player leaderboard. - -`GET /api/v1/games/:gameGroup/:playtype/leaderboard` - -### Parameters - -| Property | Type | Description | -| :--------------: | :----: | :----------------------------------------------------------------------------------------: | -| `alg` (Optional) | String | If present, specifies an alternative algorithm to sort players on, instead of the default. | - -### Response - -| Property | Type | Description | -| :---------: | :------------------------------------------------: | :------------------------------------------------: | -| `gameStats` | Array<GameStats> | The sorted statistics for the leaderboards. | -| `users` | Array<[UserDocument](../../schemas/user.md)> | All of the related users for the above statistics. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/leaderboard -``` - -#### Response - -```json -{ - "gameStats": [ - { - "userID": 1, - "ratings": { - "ktRating": 4 - // ... - } - // ... - } - ], - "users": [ - { - "id": 1, - "username": "zkldi" - } - ] -} -``` - ---- - -## Retrieve a song and its charts. - -`GET /api/v1/games/:gameGroup/:playtype/songs/:songID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :---------------------------------------: | :-----------------------------------------------------------: | -| `song` | [SongDocument](../../schemas/song.md) | The requested song document. | -| `charts` | [ChartDocument](../../schemas/chart.md)[] | All of the charts that belong to this song for this playtype. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/songs/1 -``` - -#### Response - -```json -{ - "song": { - "id": 1, - "title": "5.1.1." - }, - "charts": [ - { - "songID": 1, - "playtype": "SP", - "difficulty": "HYPER" - // ... - }, - { - "songID": 1, - "playtype": "SP", - "difficulty": "ANOTHER" - // ... - } - ] -} -``` - ---- - -## Get popular charts for this game + playtype. - -`GET /api/v1/games/:gameGroup/:playtype/charts` - -### Parameters - -| Property | Type | Description | -| :-----------------: | :----: | :-------------------------: | -| `search` (Optional) | String | A song title to search for. | - -!!! note -If no search parameter is set, then the most popular -100 charts for this game are returned. - - If a search parameter is set, then the most popular - charts that match the search criteria will be returned, - in that order. - -### Response - -| Property | Type | Description | -| :------: | :---------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------: | -| `charts` | Array<[ChartDocument](../../schemas/chart.md) with `__playcount`> | The chart documents that matched this search, or the most popular 100 charts for this game. | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The associated song documents for the charts. | - -!!! info -The `__playcount` property is patched onto the chart -documents returned. This indicates the amount of unique -players that have played this chart. - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/charts?search=AA -``` - -#### Response - -```json -{ - "songs": [ - { - "title": "AA", - "id": 3 - // ... - }, - { - "title": "AA -rebuild-", - "id": 133 - // ... - } - ], - "charts": [ - { - "songID": 3, - "difficulty": "ANOTHER", - "__playcount": 1049 - // ... - }, - { - "songID": 133, - "difficulty": "ANOTHER", - "__playcount": 120 - } - //... - ] -} -``` - ---- - -## Retrieve a chart at a specific ID. - -`GET /api/v1/games/:gameGroup/:playtype/charts/:chartID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :-------------------------------------: | :-----------------------------: | -| `song` | [SongDocument](../../schemas/song.md) | The parent song for this chart. | -| `chart` | [ChartDocument](../../schemas/chart.md) | The requested chart document. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/charts/some_chart_id -``` - -#### Response - -```json -{ - "song": { - "id": 123, - "title": "BLOCKS" - // ... - }, - "chart": { - "chartID": "some_chart_id", - "songID": 123, - "playtype": "SP" - // ... - } -} -``` - ---- - -## Retrieve leaderboards for this chart. - -`GET /api/v1/games/:gameGroup/:playtype/charts/:chartID/pbs` - -### Parameters - -| Property | Type | Description | -| :-----------------------: | :---------------------------------------------------------------------: | :---------: | -| `startRanking` (Optional) | Specify a start point to return 100 pbs from. Defaults to 1. Inclusive. | - -### Response - -| Property | Type | Description | -| :------: | :----------------------------: | :---------------------------------: | -| `pbs` | Array<PBDocument> | The array of pbs sorted by ranking. | -| `users` | The users these PBs belong to. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/charts/some_chart/pbs -``` - -#### Response - -```json -{ - "pbs": [{ - "chartID": "some_chart", - "userID": 1, - "rankingData": { - "rank": 1, - "outOf": 100, - }, - // ... - }, - //... - ], - "users": [{ - "id": 1, - "username": "zkldi - // ... - }, - // ... - ] -} -``` - ---- - -## Search for a user's PB on this chart. - -`GET /api/v1/games/:gameGroup/:playtype/charts/:chartID/pbs/search` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :-------------------------------------: | -| `search` | String | The user whose PB you're searching for. | - -### Response - -Same as `/api/v1/games/:gameGroup/:playtype/charts/:chartID/pbs`. - -### Example - -See Above. - ---- - -## Search a GPT's folders. - -`GET /api/v1/games/:gameGroup/:playtype/folders` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :------------------------------------: | -| `search` | String | A string to search for a given folder. | - -### Response - -| Property | Type | Description | -| :------: | :-------------------------: | :-----------------------------------: | -| `` | Array<FolderDocument> | The folders that matched this search. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/folders?search=12 -``` - -#### Response - -```js -[ - { - name: "beatmania IIDX Level 12", - // ... - }, -]; -``` - ---- - -## Retrieve information on a specific folderID - -`GET /api/v1/games/:gameGroup/:playtype/folders/:folderID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The related song documents for this folder. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The related chart documents for this folder. | -| `folder` | FolderDocument | The folder document at this ID. | - -### Example - -#### Request - -``` -GET /api/v1/games/iidx/SP/folders/some_folder_id -``` - -#### Response - -```js -{ - songs: [{ - id: 123, - title: "Epic Song", - artist: "foo bar", - // ... - }], - charts: [{ - chartID: "foo_bar", - songID: 123, - difficulty: "ANOTHER", - // ... - }], - folder: { - name: "beatmania IIDX Level 12", - folderID: "some_folder_id", - // ... - } -} -``` - ---- - -## Return all the tables for this game - -`GET /api/v1/games/:gameGroup/:playtype/tables` - -!!! note -Unlike the folders endpoint, this one doesn't have a search parameter. This is because we expect -the total table count to stay rather small. - - If this changes in the future, this might become a paginated search like endpoint. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :------------------------: | :-----------------------: | -| `tables` | Array<TableDocument> | Every table for this GPT. | - -### Example - -#### Request - -``` -GET /api/v1/games/bms/7K/tables -``` - -#### Response - -```js -{ - tables: [ - { - name: "Insane", - // ... - }, - { - name: "Overjoy", - // ... - }, - ]; -} -``` - ---- - -## Retrieve folder documents for a specific table. - -`GET /api/v1/games/:gameGroup/:playtype/tables/:tableID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :-------: | :-------------------------: | :--------------------------------: | -| `folders` | Array<FolderDocument> | All of the folders for this table. | -| `table` | TableDocument | The table document at this ID. | - -### Example - -#### Request - -``` -GET /api/v1/games/bms/7K/tableID/insane -``` - -#### Response - -```js -{ - folders: [ - // insane lv1, insane lv2 -- insane lv 25, so on. - ], - table: { - tableID: "insane", - name: "Insane", - // ... - } -} -``` - ---- - -## Retrieve the PB leaderboard for this Game. - -`GET /api/v1/games/:gameGroup/:playtype/pb-leaderboard` - -### Parameters - -| Property | Type | Description | -| :------: | :--------------: | :------------------------------------------------------------------------------------: | -| `alg` | String | An alternative algorithm to use instead of the GPTs default. | -| `limit` | Optional Integer | Optionally, provide a number between 1 and 50 to change the amount of scores returned. | - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :------------------------------------------: | -| `pbs` | Array<PBDocument> | The array of pbs part of the PB leaderboard. | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The array of songs part of the PBs. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts part of the PBs. | -| `users` | Array<[UserDocument](../../schemas/user.md)> | The array of users part of the PBs. | - ---- - -## Get the distribution of players for a provided class. - -`GET /api/v1/games/:gameGroup/:playtype/player-distribution` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :------------------------------------------------------------------------------------: | -| `class` | String | Must be one of the GPTs supported classes, This specifies what distribution to return. | - -### Response - -| Property | Type | Description | -| :------: | :-------------------------------: | :---------------------------------------------------------------------------: | -| `` | Record<ClassValue, integer> | Returns a record of the class value against the amount of people who have it. | - -### Example - -#### Request - -``` -GET /api/v1/games/bms/7K/player-distribution?class=stslDan -``` - -#### Response - -```js -{ - "12": 1, - "11": 5, - "10": 7, - "9": 6, - "8": 4, - // Note that keys will be empty if nobody has them. - "5": 30, - // ... so on -} -``` - -!!! info -You can find the humanised conversions for these classes in the gameConfig for this GPT. - - See [tachi/common](https://github.com/zkldi/Tachi/tree/main/common) for more information. - ---- - -## Retrieve recent class updates from all users on this game. - -`GET /api/v1/games/:gameGroup/:playtype/player-distribution` - -### Parameters - -| Property | Type | Description | -| :------: | :--------------: | :-----------------------------------------------------------------------------------------------------: | -| `limit` | Optional Integer | Optionally, An integer between 1 and 50 can be provided to limit the amount of returns. Defaults to 10. | - -### Response - -| Property | Type | Description | -| :-------: | :------------------------------------------------: | :------------------------------------------: | -| `users` | Array<[UserDocument](../../schemas/user.md)> | Array of the users who achieved the courses. | -| `classes` | Array<ClassAchievementDocument> | Data about the recently achieved classes. | - ---- - -## Retrieve the most recent highlighted scores for this GPT. - -`GET /api/v1/games/:gameGroup/:playtype/scores/highlighted` - -### Parameters - -| Property | Type | Description | -| :------: | :--------------: | :------------------------------------------------------------------------------------------------: | -| `limit` | Optional Integer | Optionally, provide an integer between 1 and 100 to return this amount of scores. Defaults to 100. | - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :---------------------------: | -| `scores` | Array<[ScoreDocument](../../schemas/score.md)> | The highlighted scores. | -| `users` | Array<[UserDocument](../../schemas/user.md)> | The users who own the scores. | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The songs the scores are on. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The charts the scores are on. | diff --git a/old-docs/docs/api/routes/import.md b/old-docs/docs/api/routes/import.md deleted file mode 100644 index 2080f44df..000000000 --- a/old-docs/docs/api/routes/import.md +++ /dev/null @@ -1,293 +0,0 @@ -# Import Scores - -***** - -## Import scores from a file. - -```POST /api/v1/import/file``` - -Perform a score import that depends on a file, such as a .csv import. - -### Permissions - -- `submit_score` - -### Parameters - -This endpoint expects data in `multipart/form-data` form. -This is because we're handling file imports, and is the -appropriate way to send files. - -| Property | Type | Description | -| :: | :: | :: | -| `importType` | String | The ImportType this import is for. This only accepts `file/` [ImportTypes](../../codebase/import/import-types.md). | -| `scoreData` | File | The file to import scores from. | - -| HTTP Header | Description | -| :: | :: | -| `X-User-Intent` (optional) | If this header is "true", the request is assumed to have been sent with 'User Intent'. For more on this, see [Import Types](../../codebase/import/import-types.md) | - -!!! info - It's the responsibility of the API user to use the X-User-Intent - header properly. It should only be used when the user - has explicitly requested this import (i.e. not sent by an automated script). - -### Response - -**Implementation Dependent**. -There are two reponse scenarios for this endpoint, depending on whether the server uses an external score processor or not. - -#### External Score Processor Response - -If an external score processor is being used, **202** is returned as a status code, and you are given the following: - -| Property | Type | Description | -| :: | :: | :: | -| `url` | String | A URL to poll for information about this import, while it's being processed. | -| `importID` | String | The ID of the import currently being processed. | - -#### Internal Score Processor Response - -If score processing is not done externally, the following is returned: - -| Property | Type | Description | -| :: | :: | :: | -| `` | ImportDocument | The import document created as a result of this import. | - -### Example - -#### Request -``` -POST /api/v1/import/file -``` - -``` -// this is not actually a multipart http request example -// as those are huge. - -importType="file/eamusement-iidx-csv" -scoreData= -``` - -#### Response - -```js -{ - "importType": "file/eamusement-iidx-csv", - "idStrings": [ - "iidx:SP" - ], - "scoreIDs": [ - "R6fad5f4947454d8238b45d6a1255d63be4da1130bf91fe9d05df29765a148da8" - ], - "errors": [], - "importID": "bea63277b54a5846bab1fd3a6ce54bfd41276857", - "timeFinished": 1623352263023, - "timeStarted": 1623352260445, - "createdSessions": [ - { - "sessionID": "Qb336d6b1cc0930747f161769a13238a41dce0004", - "type": "Created" - } - ], - "userID": 1, - "classDeltas": [], - "goalInfo": [], - "questInfo": [], - "userIntent": false, // if X-User-Intent was set, this would be true. -} -``` - -**OR** - -```js -{ - url: "https://boku.tachi.ac/api/v1/imports/SOME_IMPORT_ID/poll-status", - importID: "SOME_IMPORT_ID" -} -``` - -***** - -## Synchronise scores up with an API. - -`POST /api/v1/import/from-api` - -This endpoint requests scores from an API to sync up with the requesting user's profile. This can -be performed programmatically, as long as the key has `submit_score` permissions. - -!!! note - The user must configure integration with these services up. - -### Permissions - -- `submit_score` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `importType` | Any Supported API Import Type | The importType this synchronisation is for. | - -### Response - -**Implementation Dependent**. -There are two reponse scenarios for this endpoint, depending on whether the server uses an external score processor or not. - -#### External Score Processor Response - -If an external score processor is being used, **202** is returned as a status code, and you are given the following: - -| Property | Type | Description | -| :: | :: | :: | -| `url` | String | A URL to poll for information about this import, while it's being processed. | -| `importID` | String | The ID of the import currently being processed. | - -#### Internal Score Processor Response - -If score processing is not done externally, the following is returned: - -| Property | Type | Description | -| :: | :: | :: | -| `` | ImportDocument | The import document created as a result of this import. | - -### Example - -#### Request -``` -POST /api/v1/import/from-api - -{ - importType: "api/flo-iidx" -} -``` - - -#### Response - -See previous example. - -***** - -## Force Tachi to reprocess your orphanned scores. - -`POST /api/v1/import/orphans` - - -This endpoint goes through all of the requesting user's [Orphanned Scores](../../codebase/import/orphans.md) and attempts to find them a parent song & chart. - -!!! note - Scores automatically attempt de-orphaning every day at 1 AM UTC on Kamaitachi and Bokutachi, - this endpoint just allows you to force a deorphaning, should you wish to. - -### Permissions - -- submit_score - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `processed` | Integer | The amount of orphans processed. | -| `failed` | Integer | The amount of orphans that did not find a parent chart, and were kept as orphans. | -| `success` | Integer | The amount of orphans that successfully found a parent chart, and were turned into real scores. | -| `removed` | Integer | The amount of orphans removed -- They found a parent chart, but were rejected by the converter for being invalid scores, such as having unsupported options or impossible score values. | - -### Example - -#### Request - -N/A - -#### Response - -```js -{ - "processed": 100, - "failed": 95, - "success": 2, - "removed": 3 -} -``` - -***** - -## List your orphaned scores - -`GET /api/v1/import/orphans` - -Returns rows from `orphan_score` for the authenticated user (scores that failed with SongOrChartNotFound and were persisted for later matching). Newest rows are returned first. - -### Permissions - -- submit_score - -### Query parameters - -| Parameter | Type | Description | -| :: | :: | :: | -| `limit` | Integer (optional) | Page size, 1–100. Default `50`. | -| `after` | String (optional) | Keyset cursor: the `rowID` from the last orphan in the previous page. Omit on the first request. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `orphans` | Array | Each object includes `orphanID`, `rowID`, `importType`, `gameGroup`, `timeInserted` (ms), `message` (nullable), `summary` (nullable, best-effort hint from stored data). | -| `hasMore` | Boolean | Whether another page exists after this one. | - -***** - -## Get one orphaned score (full payload) - -`GET /api/v1/import/orphans/:orphanID` - -Returns a single `orphan_score` row for the authenticated user, including raw `data` and `context` JSON (for debugging unmatched imports). `404` if the row does not exist or belongs to another user. - -### Permissions - -- submit_score - -### Parameters - -| Parameter | Type | Description | -| :: | :: | :: | -| `orphanID` | Path | The orphan’s `orphanID` (same as in `GET /import/orphans` or import errors). | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `orphanID` | String | Stable orphan identifier. | -| `importType` | String | Import type that produced the orphan. | -| `gameGroup` | String | Game group. | -| `timeInserted` | Number | Unix time in ms when the row was stored. | -| `message` | String or null | Stored error / context message. | -| `data` | Object | Raw import datapoint (shape depends on `importType`). | -| `context` | Object | Raw import context. | - -***** - -## Delete one orphaned score - -`DELETE /api/v1/import/orphans/:orphanID` - -Removes a single `orphan_score` row **only if** it belongs to the authenticated user. Use this when you no longer want Tachi to keep or retry a given orphan (for example after a bad import). - -### Permissions - -- submit_score - -### Parameters - -| Parameter | Type | Description | -| :: | :: | :: | -| `orphanID` | Path | The orphan’s `orphanID` (for example from an import error or from `GET /import/orphans`). | - -### Response - -Empty body on success (`success: true`). `404` if no such orphan exists for this user. diff --git a/old-docs/docs/api/routes/imports.md b/old-docs/docs/api/routes/imports.md deleted file mode 100644 index 3c35577ca..000000000 --- a/old-docs/docs/api/routes/imports.md +++ /dev/null @@ -1,124 +0,0 @@ -# Import Document Endpoints - -!!! note - This should not be confused with [Import Endpoints](./import.md). Those are for - importing scores, whereas these endpoints are for Import Document interaction. - -***** - -***** - -## Retrieve an import document and information about it. - -`GET /api/v1/imports/:importID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `scores` | Array<ScoreDocument> | All of the scores imported from this import. | -| `songs` | Array<SongDocument> | All of the songs related to the scores in this import. | -| `charts` | Array<ChartDocument> | All of the charts related to the scores in this import. | -| `sessions` | Array<SessionDocument> | All of the sessions created as a result of this import. **Note that this does not include sessions modified by this import!** | -| `import` | ImportDocument | The Import document you requested. | -| `user` | UserDocument | The user document for the person who made this import. | - -***** - -## Revert an import. - -`POST /api/v1/imports/:importID/revert` - -!!! info - This endpoint is intended to *undo* a faulty import. For example, if you were using - a batch-manual script that somehow went haywire. Normal users should *not* need to - use this, but it is on the UI regardless incase they cause catastrophic failure. - -!!! warning - Reverting an import is equivalent to undoing all of the scores that were imported as - a result of the import. This, however, does not necessitate that classes will be - reverted, such as if the import also declared you as kaiden -- that currently requires - manual moderator intervention. - -### Permissions - -- delete_score -- Must be the owner of this import (Or a server administrator). - -### Parameters - -None. - -### Response - -None. (Empty Object) - -***** - -## Poll an ongoing import - -`GET /api/v1/imports/:importID/poll-status` - -!!! question - The reason we can't directly respond with import info is that `tachi-server` **may** - use a feature called SCORE_IMPORT_WORKERS. This dedicates score processing to separate - processes which communicate back with any parent server. This means that the result of - an import processed on one server may be returned by another. - - This feature is enabled on our instances of `tachi-server` -- Boku and Kamai, which - means you will have to poll this endpoint. - -!!! info - You are intended to poll this endpoint every one second or so. Do it until - `body.importStatus` is "completed". - -!!! tip - `body.progress.description` is human-friendly output, you can render it to - a client on every ping in the case where `body.importStatus` is "ongoing". - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `importStatus` | "completed" \| "ongoing" | If this is equal to completed, the import is finished and the importDocument is returned under `import` . If this is "ongoing", a `progress` key will display information and progress though the import | -| `progress` | `{ description: string }` \| Not Present | If `importStatus` is "ongoing", this will contain a string `description` of where in the import process this import is. | -| `import` | ImportDocument \| Not Present | If `importStatus` is "completed", this will contain the import document that was just inserted into the database. | - -### Example - -#### Request -``` -GET /api/v1/imports/my_import_id/poll-status -``` - -#### Response - -```js -{ - importStatus: "ongoing", - progress: { - description: "Imported 1832 Scores..." - } -} -``` - -Alternatively, - -```js -{ - importStatus: "completed", - import: { - importID: "my_import_id", - scoreIDs: ["foo", "bar"], - // ... more import props - } -} -``` \ No newline at end of file diff --git a/old-docs/docs/api/routes/oauth2.md b/old-docs/docs/api/routes/oauth2.md deleted file mode 100644 index 789270d77..000000000 --- a/old-docs/docs/api/routes/oauth2.md +++ /dev/null @@ -1,101 +0,0 @@ -# OAuth2 Integration - -Tachi provides an OAuth2 API and some other things -so that you can create your own clients and retrieve -user api keys safely. - -For a detailed explaination on how to use the OAuth2 flow, you can check [Using OAuth2 With Tachi](../../codebase/infrastructure/oauth2.md) - -***** - -## Convert Auth Code to API Key - -`POST /api/v1/oauth/token` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `client_id` | String | Your clients ID. | -| `client_secret` | String | Your clients secret. | -| `grant_type` | "authorization_code" | This is the only form of grant_type we currently support. | -| `redirect_uri` | String | The redirect URI your client uses. This must match the one in your client. | -| `code` | String | The intermediate auth code to convert up into an API Key. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | APIKeyDocument | The APIKeyDocument created for your service to use. | - -### Example - -#### Request -``` -POST /api/v1/oauth/token ---- -{ - "client_id": "my_client_id", - "client_secret": "some_secret_value!", - "grant_type": "authorization_code", - "redirect_uri": "https://example.com/callback", - "code": "intermediate_code" -} -``` - -#### Response - -```json -{ - "userID": 1, - "token": "fdbufasbfuarf", - "identifier": "Your_Service Token", - "permissions": { - "customise_profile": true - }, - "fromAPIClient": "my_client_id" -} -``` - -***** - -## Create an intermediate Code - -`POST /api/v1/create-code` - -!!! info - This infers the current user from the session cookie. - - This is *not* meant to be called by external code, and - is instead something for `tachi-client` to use on the oauth confirmation screen. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `code` | String | The intermediate code. | -| `userID` | Integer | The user this code belongs to. | -| `createdOn` | Number | The time in unix milliseconds that this code was created. | - -!!! warning - These codes expire around 30 minutes from their creation. - -### Example - -#### Request -``` -POST /api/v1/oauth/create-code -``` - -#### Response -```json -{ - "code": "foobarbarhsdufh", - "userID": 1, - "createdAt": 111111111111 -} -``` diff --git a/old-docs/docs/api/routes/scores.md b/old-docs/docs/api/routes/scores.md deleted file mode 100644 index a900baf0d..000000000 --- a/old-docs/docs/api/routes/scores.md +++ /dev/null @@ -1,127 +0,0 @@ -# Score Endpoints - -!!! note - Scores are *not* personal bests. For more information - on the distinction, see [PBs and Scores](../../wiki/pbs-scores.md). - -***** - -## Retrieve specific score. - -`GET /api/v1/scores/:scoreID` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `getRelated` | Presence | If present, also return the song and chart for this score document. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `score` | [ScoreDocument](../../schemas/score.md) | The score document with this scoreID. | -| `song` (Conditional) | [SongDocument](../../schemas/song.md) | If `getRelated` is set, then this is the song the score belongs to. | -| `chart` (Conditional) | [ChartDocument](../../schemas/chart.md) | Same as above, but for the chart document. | - -### Example - -#### Request -``` -GET /api/v1/scores/Re7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b -``` - -#### Response - -```json -{ - "score": { - "scoreID": "Re7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b", - "songID": 1, - "chartID": "some_chart_ID" - }, - "song": { - "id": 1, - "title": "5.1.1." - }, - "chart": { - "chartID": "some_chartID", - "songID": 1 - } -} -``` - -***** - -## Modify a score document. - -`PATCH /api/v1/scores/:scoreID` - -### Permissions - -- customise_score -- Must be the owner of this score. - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `comment` (Optional) | Null or String | A string between 1 and 120 characters, or null. If null, the score will have its comment unset. If not, the comment for this score will be set to its contents. If the key is not present, no change will be made. | -| `highlight` (Optional) | Boolean | Whether this score was a highlight or not. If this field is not present, no change will be made to the highlight status. | - -!!! info - Although all of these fields are optional, providing none - of them is a 400 failure. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | [ScoreDocument](../../schemas/score.md) | The new score document. - -### Example - -#### Request -``` -PATCH /api/v1/scores/Re7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b -``` - -```json -{ - "comment": "new comment" -} -``` - -#### Response - -```json -{ - "scoreID": "Re7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b", - "comment": "new comment", - "highlighted": false, - // etc.. -} - -``` - -***** - -## Delete a score. - -`DELETE /api/v1/scores/:scoreID` - -!!! info - Deleting a score will result in profile recalculations and PB updates. - -### Permissions - -- delete_score -- Must be the owner of this score (Or a server administrator). - -### Parameters - -None. - -### Response - -None. (Empty Object) diff --git a/old-docs/docs/api/routes/search.md b/old-docs/docs/api/routes/search.md deleted file mode 100644 index 34f6d83f7..000000000 --- a/old-docs/docs/api/routes/search.md +++ /dev/null @@ -1,52 +0,0 @@ -# Search Endpoints - -***** - -## Search Everything. - -`GET /api/v1/search` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `search` | String | What to search for. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `users` | Array<[UserDocument](../../schemas/user.md)> | The array of users whose usernames look like the search criterion. | -| `songs` | ([SongDocument](../../schemas/song.md) With [__textScore](../../codebase/implementation-details/search.md) and `game`.)[] | An array of songs from all games, with `__textScore` and `game` properties attached. | - -### Example - -#### Request -``` -GET /api/v1/search?search=freedom -``` - -#### Response - -```js -{ - users: [{ - username: "FreedomDiver", - // ... - }], - songs: [{ - title: "FREEDOM", - __textScore: 2, - game: "iidx", - // ... - }, { - title: "FREEDOM DiVE", - __textScore: 1, - game: "bms", - // ... - }] -} -``` - -!!! info - For more details on how searching works, see [Search Implementation](../../codebase/implementation-details/search.md). diff --git a/old-docs/docs/api/routes/sessions.md b/old-docs/docs/api/routes/sessions.md deleted file mode 100644 index 7da6e0242..000000000 --- a/old-docs/docs/api/routes/sessions.md +++ /dev/null @@ -1,118 +0,0 @@ -# Session Endpoints - ---- - -## Get a specific session - -`GET /api/v1/sessions/:sessionID` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :-------: | :--------------------------------------------------: | :-------------------------------------------: | -| `session` | [SessionDocument](../../schemas/session.md) | The session document at this ID. | -| `scores` | Array<[ScoreDocument](../../schemas/score.md)> | The score documents involved in this session. | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The songs these score documents belong to. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The charts these score documents belong to. | -| `user` | [UserDocument](../../schemas/user.md) | The user that made this session. | - -### Example - -#### Request - -``` -GET /api/v1/sessions/Qe7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b -``` - -#### Response - -```js -{ - user: { - id: 1, - username: "zkldi", - // ... - }, - session: { - sessionID: "Qe7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b", - scores: [{ - scoreID: "foo", - // ... - }], - name: "my session", - // ... - }, - scores: [{ - scoreID: "foo", - songID: 1, - chartID: "foo_chartID", - }], - songs: [{ - id: 1, - // ... - }], - charts: [{ - chartID: "foo_chartID", - songID: 1 - // ... - }] -} -``` - ---- - -## Modify a session - -`PATCH /api/v1/sessions/:sessionID` - -### Permissions - -- customise_session -- Must be the owner of this session. - -### Parameters - -| Property | Type | Description | -| :--------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------: | -| `name` (optional) | String | A new name for this session. This must be between 3 and 80 characters. If not present, no update will be made to the session name. | -| `desc` (optional) | String | A new description for this session. This must be between 3 and 120 characters. If not present, no update to the description will be made. | -| `highlight` (optional) | boolean | Whether this session is highlighted or not. If not present, no change will be made to the highlighted status. | - -!!! info -Although all these fields are optional, making a request -without any of them is a 400 error. - -### Response - -| Property | Type | Description | -| :------: | :-----------------------------------------: | :--------------------------------------------: | -| `` | [SessionDocument](../../schemas/session.md) | The new session document, after modifications. | - -### Example - -#### Request - -``` -PATCH /api/v1/sessions/Qe7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b -``` - -```json -{ - "name": "new session name" -} -``` - -#### Response - -```json -{ - "name": "new session name", - "desc": "old session desc", - "highlighted": false - // ... -} -``` diff --git a/old-docs/docs/api/routes/status.md b/old-docs/docs/api/routes/status.md deleted file mode 100644 index d6d0342d7..000000000 --- a/old-docs/docs/api/routes/status.md +++ /dev/null @@ -1,76 +0,0 @@ -# Status Checks - -These endpoints are generally for programmers checking their code works. -They can also be used to check the status of the server. - -***** - -## Check server status. - -```GET /api/v1/status``` - -This endpoint is a status check for the API and the consumer, -It's a good way of sanity checking whether your code works. - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `echo` | String | A string to echo. This is useful for checking whether parameters are sending over properly. | - - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `serverTime` | Integer | The current time of the server in Unix Milliseconds. | -| `startTime` | Integer | The time this server was booted in Unix Milliseconds. | -| `whoami` | Integer \| null | The userID you are authenticated as. If you are not authenticated, this is null. | -| `version` | String | The current version of Tachi-Server running. | -| `permissions` | Array<string> | The permissions this request had. | -| `echo` (Conditional) | String | If an `echo` parameter was provided, this is that exact parameter. | - -### Example - -`GET /api/v1/status?echo=helloworld` - -```json -{ - "serverTime": 1623331110661, - "version": "v2.0.0 (Mysterons)", - "permissions": ["score_submit", "example_permission"], - "echo": "helloworld" -} -``` - -***** - -## Check server status with POST. - -```POST /api/v1/status``` - -This endpoint is identical to `GET /status`, but it responds to POST requests, -and takes the `echo` parameter from the request body. - -This is a good way to check whether your code sends JSON -bodies properly. - -### Example - -```json -POST /api/v1/status -``` -``` -{ - "echo": "hello world" -} -``` - -```json -{ - "serverTime": 1623331110662, - "version": "v2.0.0 (Mysterons)", - "permissions": ["score_submit", "example_permission"], - "echo": "hello world" -} -``` \ No newline at end of file diff --git a/old-docs/docs/api/routes/ugpt-showcase.md b/old-docs/docs/api/routes/ugpt-showcase.md deleted file mode 100644 index 90deb2339..000000000 --- a/old-docs/docs/api/routes/ugpt-showcase.md +++ /dev/null @@ -1,156 +0,0 @@ -# UGPT Stat Showcase - -These endpoints are related to the Statistic Showcase feature. - -***** - -## Evaluate this users set stats - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/showcase` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `projectUser` | Optional, userID | If provided, will *project* another users showcase onto this user, evaluating the same user against the projectedUser's stats. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | Array<StatShowcaseResults> | | - -### Example - -#### Request -``` -GET /api/v1/users/1/games/iidx/SP/showcase -``` - -#### Response -```js -[{ - stat: { - - }, - value: { - value: 123, - }, - related: { - song: { - title: "FREEDOM DIVE", - // ... - }, - chart: { - // some chart stuff.. - }, - // folders: [] if this is a folder(s) stat, then folders are displayed here. - } -}] -``` - -***** - -## Replace a user's stat showcase. - -`PATCH /api/v1/users/:userID/games/:gameGroup/:playtype/showcase` - -### Permissions - -- `customise_profile` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `` | Array<StatDocument> | An array of up to 6 stat documents. | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `` | Array<StatDocument> | The newly updated stat documents. | - -### Example - -#### Request -``` -PATCH /api/v1/users/1/games/iidx/SP/showcase - -[ - { - mode: "chart", - chartID: "some_chart_id", - property: "percent" - } -] -``` - -#### Response -```js -[ - { - mode: "chart", - chartID: "some_chart_id", - property: "percent" - } -] -``` - -***** - -## Evaluate a custom stat on this user. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/showcase/custom` - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `mode` | "folder" \| "chart" | Whether the stat to evaluate is on a folder or a chart. | -| `property` | "grade" \| "lamp" \| "score" \| "percent" or "playcount" if mode is chart. | What property to evaluate on the given criteria. | -| `chartID` | string, if mode === "chart" | If mode is chart, this should contain the relevant chartID. | -| `folderID` | string, if mode === "folder" | If mode is folder, this should contain the relevant folderID. | -| `gte` | number, if mode === "folder" | If mode is folder, this must contain the value the property must be greater than, i.e. lamp >= 6, or percent >= 90 | - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `stat` | StatDocument | The stat you evaluated. | -| `result` | {value: number \| null, outOf?: number } | Contains `value`, which contains the stat's value, or NULL if the mode is chart and the user has not played this chart. If mode is folder, `outOf` contains the total amount of charts in that folder. | -| `related` | {song, chart} or {folders} | If mode is chart, contains the pertinent song and chart. If mode is folder, contains the pertinent folder documents. - -### Example - -#### Request -``` -GET /api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&property=percent&chartID=some_chart_id -``` - -#### Response -```js -{ - stat: { - mode: "chart", - property: "percent", - chartID: "some_chart_id", - }, - result: { - value: 99.12 - }, - related: { - song: { - id: 123, - title: "AA", - artist: "DJ.Amuro", - // ... - }, - chart: { - songID: 123, - difficulty: "ANOTHER", - // ... - } - } -} -``` diff --git a/old-docs/docs/api/routes/ugpt-targets.md b/old-docs/docs/api/routes/ugpt-targets.md deleted file mode 100644 index a0a821a0a..000000000 --- a/old-docs/docs/api/routes/ugpt-targets.md +++ /dev/null @@ -1,148 +0,0 @@ -# UGPT-Target Endpoints - -These endpoints deal with [targets](../../api/terminology.md) for a User, Game and Playtype. These are things like subscribing to a new quest, or reading info about progress on a specific goal. - -For user-specific target endpoints, such as subscriptions, see [UGPT-Target Endpoints](./ugpt-targets.md). - -***** - -***** - -## Retrieve a user's recently achieved targets. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/targets/recently-achieved` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `goalSubs` | Array<GoalSubDocument> | The goal subscriptions that were recently achieved by this user. | -| `goals` | Array<GoalDocument> | The goal documents that were recently achieved (if any). | -| `questSubs` | Array<QuestSubDocument> | The quest subscriptions that were recently achieved by this user. | -| `quest` | Array<QuestDocument> | The quest documents that were recently achieved (if any). | -| `user` | UserDocument | The user you requested this information about. | - -***** - -## Retrieve a user's recently raised targets. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/targets/recently-raised` - -!!! info - Recently raised means that the user recently increased their `progress` on the target. It explicitly excludes achieved goals -- only things that they are getting closer to. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `goalSubs` | Array<GoalSubDocument> | The goal subscriptions that were recently achieved by this user. | -| `goals` | Array<GoalDocument> | The goal documents that were recently achieved (if any). | -| `questSubs` | Array<QuestSubDocument> | The quest subscriptions that were recently achieved by this user. | -| `quest` | Array<QuestDocument> | The quest documents that were recently achieved (if any). | -| `user` | UserDocument | The user you requested this information about. | - -***** - -## Retrieve this user's quest subscriptions. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/targets/quests` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `quests` | Array<QuestDocument> | All of the quests this user is subscribed to. | -| `questSubs` | Array<QuestSubDocument> | All of this user's quest subscriptions. | - -***** - -## Get a user's progress on a specific quest they are subscribed to. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/targets/quests/:questID` - -!!! info - If you're looking to evaluate a quest against a user, without knowing whether they're - subscribed to it or not, you want [GPT/Targets/Quests/Evaluate-For](gpt-targets.md#evaluate-a-quest-for-a-user-even-if-they-arent-subscribed-to-it). - - This endpoint is admittedly in a very strange position, where it overlaps with that `evaluate-for` endpoint quite significantly, but this endpoint is also intended to return the user's `questSub`, so I thought it best to split this into two endpoints. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `questSub` | QuestSubDocument | The user's subscription to this quest. | -| `quest` | QuestDocument | The quest document in question. | -| `goals` | Array<GoalDocument> | The goals involved in this quest. | -| `results` | Array<EvaluatedGoalResult> | The user's progress on each goal in this quest. | - -#### EvaluatedGoalResult - -| Property | Type | Description | -| :: | :: | :: | -| `goalID` | String | The goal ID that these results are for. | -| `achieved` | Boolean | Whether this goal was achieved or not. | -| `progress` | Number \| Null | How much progress this user made on this goal. Null if no progress was made. | -| `outOf` | Number | What `progress` needs to be greater than or equal to for this goal to count as achieved. | -| `progressHuman` | String | A humanised, pretty-printed progress indicator for this goal. | -| `outOfHuman` | String | A humanised, pretty-printed outOf indicator for this goal. | - -***** - -## Subscribe to a quest. - -`PUT /api/v1/users/:userID/games/:gameGroup/:playtype/targets/quests/:questID` - -### Permissions - -- `manage_targets` -- Must be the requesting user. - -### Parameters - -None. (All relevant info is in the URL.) - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `goals` | Array<GpalDocument> | The goals involved in this quest. | -| `quest` | QuestDocument | The quest the user just subscribed to. | -| `goalResults` | Array<EvaluatedGoalResults> | The user's progress on each individual goal in this quest. | -| `questSub` | QuestSubscriptionDocument | The quest subscription this user just created | - -***** - -## Unsubscribe from a quest. - -`DELETE /api/v1/users/:userID/games/:gameGroup/:playtype/targets/quests/:questID` - -### Permissions - -- `manage_targets` -- Must be the requesting user. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `quest` | QuestDocument | The quest you just unsubscribed from. | diff --git a/old-docs/docs/api/routes/user-gamept.md b/old-docs/docs/api/routes/user-gamept.md deleted file mode 100644 index 47fc1aa80..000000000 --- a/old-docs/docs/api/routes/user-gamept.md +++ /dev/null @@ -1,901 +0,0 @@ -# Individual User on Specific Game - -This endpoints are for specific users information on specific game + playtype combinations. - -This scenario appears frequently, and is typically shortened to UGPT. - ---- - -## Get information about a user's plays on a game + playtype. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :---------------: | :------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------: | -| `gameStats` | UserGameStatsDocument | The User's GameStats for this game + playtype. | -| `firstScore` | [ScoreDocument](../../schemas/score.md) or Null | The user's first score for this game + playtype. This is null if the user has no scores with timestamps. | -| `mostRecentScore` | [ScoreDocument](../../schemas/score.md) or Null | The user's most recent score. This is null if the user has no scores with timestamps. | -| `totalScores` | Integer | The total amount of scores this user has. | -| `rankingData` | Record<Rating Algorithm, { ranking: integer, outOf: integer }> | The position of this player on the default leaderboards for this game, and how many players it is out of. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldi/games/iidx/SP -``` - -#### Response - -```js -{ - gameStats: { - userID: 1, - game: "iidx", - playtype: "SP", - ratings: { - ktRating: 15 - }, - classes: { - dan: 14 - } - }, - firstScore: null, - mostRecentScore: null, - totalScores: 5, - rankingData: { - ktRating: { - ranking: 3, - outOf: 18 - } - ktLampRating: { - ranking: 2, - outOf: 18 - }, - BPI: { - ranking: 5, - outOf: 18 - } - } -} -``` - ---- - -## Search a user's personal bests. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/pbs` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :---------------------------------------------------------------------------------------------: | -| `search` | String | Limits the returned scores to those where the corresponding song is most similar to this query. | - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :------------------------------------------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The array of songs this search returned. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts this search returned. | -| `pbs` | Array<PBDocument> | The array of personal bests this search returned. This is limited to 30 returns. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/pbs?search=Verfl -``` - -#### Response - -```js -{ - pbs: [{ - userID: 1, - scoreData: { - score: 123, - // ... - } - }], - songs: [{ - title: "Verflucht", - // ... - }], - charts: [{ - songID: 123, - playtype: "SP", - difficulty: "ANOTHER", - // ... - }, { - songID: 123, - playtype: "SP", - difficulty: "HYPER", - }] -} -``` - -## Get a user's best 100 personal bests. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/pbs/best` - -This returns the users' best 100 personal bests according -to the [Default Rating Algorithm](../../codebase/implementation-details/game-configuration) for this game. - -This is returned in descending sorted order. - -The query parameter `alg` can be used to specify a -different rating algorithm to sort under. - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :-----------------------------------------------------------: | -| `alg` | String | An overriding rating algorithm to use instead of the default. | - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :-----------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The array of songs this search returned. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts this search returned. | -| `pbs` | Array<PBDocument> | The array of personal bests this search returned. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/pbs/best?alg=BPI -``` - -#### Response - -```js -{ - pbs: [{ - userID: 1, - scoreData: { - // ... - }, - calculatedData: { - ktRating: 15, - BPI: 4.4 - } - }, { - userID: 1, - scoreData: { - // ... - }, - calculatedData: { - ktRating: 19, - BPI: 4.2 - } - }], - songs: [{ - title: "Verflucht", - // ... - }, { - title: "AA", - // ... - }], - charts: [{ - songID: 123, - playtype: "SP", - difficulty: "ANOTHER", - // ... - }, { - songID: 14, - playtype: "SP", - difficulty: "ANOTHER", - }] -} -``` - ---- - -## Returns all of a users personal bests. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/pbs/all` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :---------------------------: | -| `pbs` | Array<PBDocument> | All of the users PB Documents | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | All of the relevant songs. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | All of the relevant charts. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/pbs/all -``` - -#### Response - -```js -{ - pbs: [{ - userID: 1, - scoreData: { - score: 123, - // ... - } - }], - songs: [{ - title: "Verflucht", - // ... - }], - charts: [{ - songID: 123, - playtype: "SP", - difficulty: "ANOTHER", - // ... - }, { - songID: 123, - playtype: "SP", - difficulty: "HYPER", - }] -} -``` - ---- - -## Get A User's PB for a given chart. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/pbs/:chartID` - -### Parameters - -| Property | Type | Description | -| :--------------: | :------: | :------------------------------------------------------------------------------------: | -| `getComposition` | Presence | If present, the individual ScoreDocuments that composed this PB will also be returned. | - -### Response - -| Property | Type | Description | -| :--------------------: | :--------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | -| `pb` | PBDocument | The user's PB for this chart. | -| `chart` | [ChartDocument](../../schemas/chart.md) | The chart this PB is on. | -| `scores` (Conditional) | Array<[ScoreDocument](../../schemas/score.md)> | If `getComposition` is present, then this field contains the array of score documents that composed this PB. | - -### Example - -#### Request - -``` -GET /api/v1/users/1/games/iidx/SP/pbs/some_chart_id -``` - -#### Response - -```js -{ - pb: { - chartID: "some_chart_id", - userID: 1, - game: "iidx", - playtype: "SP", - }, - chart: { - chartID: "some_chart_id" - } -} -``` - ---- - -## Search a user's individual scores. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/scores` - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :---------------------------------------------------------------------------------------------: | -| `search` | String | Limits the returned scores to those where the corresponding song is most similar to this query. | - -### Response - -| Property | Type | Description | -| :------: | :-------------------------------------------------------------------: | :----------------------------------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md) with \_\_textScore> | The array of songs this search returned. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts this search returned. | -| `scores` | Array<[ScoreDocument](../../schemas/score.md)> | The array of scores this search returned. This is limited to 30 returns. | - -!!! info -All `songs` returned also have the `__textScore` -property. This property describes how close the query -was to the actual text, and is mostly internal. - - You can read more into the details of this at [Search Implementation](../../codebase/implementation-details/search.md) - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/scores?search=Verfl -``` - -#### Response - -```js -{ - scores: [{ - userID: 1, - scoreData: { - score: 123, - // ... - } - }], - songs: [{ - title: "Verflucht", - // ... - }], - charts: [{ - songID: 123, - playtype: "SP", - difficulty: "ANOTHER", - // ... - }, { - songID: 123, - playtype: "SP", - difficulty: "HYPER", - }] -} -``` - ---- - -## Get a user's most recent 100 scores. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/scores/recent` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :----------------------------------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The array of songs this search returned. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts this search returned. | -| `scores` | Array<[ScoreDocument](../../schemas/score.md)> | The array of scores this search returned. This is limited to 30 returns. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/scores/recent -``` - -#### Response - -```js -{ - scores: [{ - userID: 1, - scoreData: { - score: 123, - // ... - } - }], - songs: [{ - title: "Verflucht", - // ... - }], - charts: [{ - songID: 123, - playtype: "SP", - difficulty: "ANOTHER", - // ... - }, { - songID: 123, - playtype: "SP", - difficulty: "HYPER", - }] -} -``` - ---- - -## Search a user's sessions. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/sessions` - -Searches the names of sessions from a given user. This -does not search session descriptions, nor does it search -song titles of played songs inside sessions. - -### Parameters - -| Property | Type | Description | -| :------: | :----: | :-----------------------------: | -| `search` | String | The session name to search for. | - -### Response - -| Property | Type | Description | -| :------: | :------------------------------------------------------: | :--------------------------------------------: | -| `` | Array<[SessionDocument](../../schemas/session.md)> | The array of sessions that matched this query. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/sessions?search=epic%20session -``` - -#### Response - -```js -[ - { - name: "My Epic Session!!!", - userID: 1, - game: "iidx", - playtype: "SP", - // ... - }, -]; -``` - -## Get a user's best 100 sessions. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/sessions/best` - -Retrieves a user's best 100 sessions according to the -game + playtypes default algorithm. The algorithm can -be overrode with the `alg` query string parameter. - -These are returned in descending order. - -### Parameters - -| Property | Type | Description | -| :--------------: | :----: | :------------------------------------------------------: | -| `alg` (Optional) | String | The name of the algorithm to use instead of the default. | - -### Response - -| Property | Type | Description | -| :------: | :------------------------------------------------------: | :-----------------------------------: | -| `` | Array<[SessionDocument](../../schemas/session.md)> | The array of the users best sessions. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/sessions/best -``` - -#### Response - -!!! info -The default rating algorithm for IIDX:SP is `ktRating`. - -```js -[ - { - userID: 1, - game: "iidx", - playtype: "SP", - calculatedData: { - ktRating: 14, - bpi: 3, - }, - // ... more properties - }, - { - userID: 1, - game: "iidx", - playtype: "SP", - calculatedData: { - ktRating: 13.2, - bpi: 4, - }, - }, -]; -``` - -## Get a user's most recent 100 sessions. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/sessions/recent` - -Retrieves a user's most recent 100 sessions for this game. - -These are returned in descending order according to `timeEnded`. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :------------------------------------------------------: | :------------------------------: | -| `` | Array<[SessionDocument](../../schemas/session.md)> | The array of the users sessions. | - ---- - -## Get a user's most recent session. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/sessions/last` - -!!! info -This endpoint will return 404 if the user has never had a -session for this game. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :-----------------------------------------: | :-----------------------------: | -| `` | [SessionDocument](../../schemas/session.md) | The user's most recent session. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/sessions/last -``` - -#### Response - -```js -{ - "name": "foo", - "desc": "My most recent session", - // ... -} -``` - -## Get a user's most recent 100 highlighted sessions. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/sessions/highlighted` - -Retrieves a user's most recent 100 highlighted sessions for this game. - -These are returned in descending order according to `timeEnded`. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :------------------------------------------------------: | :------------------------------------------: | -| `` | Array<[SessionDocument](../../schemas/session.md)> | The array of the users highlighted sessions. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/sessions/highlighted -``` - -#### Response - -```js -[ - { - userID: 1, - game: "iidx", - playtype: "SP", - calculatedData: { - ktRating: 14, - bpi: 3 - } - highlight: true, - // ... more props - }, -] -``` - ---- - -## Get a user's most played charts. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/most-played` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | -| `songs` | Array<[SongDocument](../../schemas/song.md)> | The array of songs related to the pbs. | -| `charts` | Array<[ChartDocument](../../schemas/chart.md)> | The array of charts related to the pbs. | -| `pbs` | Array<(PBDocument & {\_\_playcount: integer})> | An array of PB documents with the `__playcount` property attached. This property dictates how many times the user has played this chart. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/most-played -``` - -#### Response - -```js -{ - songs: [{ - id: 1, - title: "5.1.1.", - // ... - }, { - id: 2, - title: "GAMBOL", - // ... - }], - charts: [{ - songID: 1, - difficulty: "ANOTHER", - // ... - }, { - songID: 2, - difficulty: "LEGGENDARIA", - // ... - }, { - songID: 1, - difficulty: "HYPER", - }], - pbs: [{ - chartID: "something", - __playcount: 5, - // ... - }, { - chartID: "something_else", - __playcount: 2, - // ... - }, { - chartID: "something_more", - __playcount: 1, - // ... - }] -} -``` - ---- - -## Retrieve a leaderboard around a user. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/leaderboard-adjacent` - -### Parameters - -| Property | Type | Description | -| :------: | :---------------: | :-----------------------------------------------------------------------------------------------------------------: | -| `alg` | String (Optional) | Optionally, you can provide an override algorithm to use for the leaderboards instead of the game+playtype default. | - -### Response - -| Property | Type | Description | -| :----------------: | :------------------------------------------------: | :-------------------------------------------------: | -| `above` | Array<UserGameStats> | Up to 5 users' game stats better than this user. | -| `below` | Array<UserGameStats> | Same as above, but below the user. | -| `users` | Array<[UserDocument](../../schemas/user.md)> | The user documents related to the above statistics. | -| `thisUsersStats` | UserGameStats | The requested user's stats for this GPT. | -| `thisUsersRanking` | {outOf: integer, ranking: integer} | The requested user's ranking for this GPT. | - -### Example - -#### Request - -``` -GET /api/v1/users/zkldimes/iidx/SP/leaderboard-adjacent -``` - -#### Response - -```js -{ - above: [{ - userID: 2, - ratings: { - ktRating: 9 - }, - classes: { - dan: 10 - }, - // ... - }], - below: [{ - userID: 3, - ratings: { - ktRating: 1 - }, - classes: { - dan: 5 - }, - // ... - }], - users: [{ - userID: 2, - username: "sptmgtm", - // ... - }, { - userID: 3, - username: "neil.c", - // ... - }], - thisUsersStats: { - userID: 1, - ratings: { - ktRating: 5 - }, - classes: { - dan: 5 - } - }, - thisUsersRanking: { - ranking: 2, - outOf: 3 - } -} -``` - ---- - -## Retrieve this user's GPT stat history. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/history` - -Every day, a user's game stats are snapshotted and saved. This returns the recent ones. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------: | :-------------------------------------------------------------------------------------------------------------------: | -| `` | Array<UserGameStatsSnapshot> | The most recent (up to) 90 UGS Snapshots, where the first element is the most recent one, and the last is the oldest. | - -### Example - -#### Request - -``` -GET /api/v1/users/1/games/iidx/SP/history -``` - -#### Response - -```js -[ - { - classes: { - dan: 13, - }, - ratings: { - BPI: 5, - ktRating: 3, - ktLampRating: 1, - }, - timestamp: 12312323123123, // most recent - playcount: 500, - ranking: 14, - }, - // and so on.. -]; -``` - ---- - -## Retrieve this user's GPT settings. - -`GET /api/v1/users/:userID/games/:gameGroup/:playtype/settings` - -!!! warning -Unlike most other applications, your settings are completely public. GPT Settings only concern -cosmetic things, like what rating algorithms to prefer. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :------------------: | :----------------------------------: | -| `` | UGPTSettingsDocument | The settings document for this user. | - -### Example - -#### Request - -``` -GET /api/v1/users/1/games/iidx/SP/settings -``` - -#### Response - -```js -{ - preferredScoreAlg: null, - preferredSessionAlg: "BPI", - preferredProfileAlg: null, - stats: [] -} -``` - ---- - -## Modify your UGPT settings. - -`PATCH /api/v1/users/:userID/games/:gameGroup/:playtype/settings` - -!!! note -Although `stats` are part of your settings, they are not modifiable under these endpoints, -instead you should use [UGPT Showcase Endpoints](./ugpt-showcase.md). - -### Permissions - -- `customise_profile` - -### Parameters - -| Property | Type | Description | -| :------: | :--------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------: | -| `` | Partial UGPTSettingsDocument | A UGPTSettingsDocument where all properties are optional. Properties not present will not be modified. Note that `stats` are not modifiable here. | - -### Response - -| Property | Type | Description | -| :------: | :------------------: | :---------------------------: | -| `` | UGPTSettingsDocument | The new UGPTSettingsDocument. | - -### Example - -#### Request - -``` -PATCH /api/v1/users/1/games/iidx/SP/settings - -{ - preferredScoreAlg: "BPI" -} -``` - -#### Response - -```js - -{ - preferredScoreAlg: "BPI", - preferredSessionAlg: "ktRating", - preferredProfileAlg: null, - stats: [] -} -``` diff --git a/old-docs/docs/api/routes/user-integrations.md b/old-docs/docs/api/routes/user-integrations.md deleted file mode 100644 index 27da4910a..000000000 --- a/old-docs/docs/api/routes/user-integrations.md +++ /dev/null @@ -1,110 +0,0 @@ -# User Integrations - -These endpoints are related to a users integrations with external services. - -***** - -## Retrieve whether this user is authenticated with this kaiType. - -`GET /api/v1/users/:userID/integrations/kai/:kaiType` - -**Kamaitachi Only** - -!!! note - A KaiType is either "flo", "min", or "eag". Since these three services - share backends, they all use the same authentication mechanisms, and share - endpoints like this. - -### Permissions - -- Self-key: This request must be made using Cookie authentication, which means it cannot be used with API keys. - -### Response - -| Property | Type | Description | -| :: | :: | :: | -| `authStatus` | boolean | True if the user is authenticated with this kaiType, false if they are not. | - -### Example - -#### Request -``` -GET /api/v1/users/1/integrations/kai/flo -``` - -#### Response - -```js -{ - authStatus: false -} -``` - -***** - -## Revoke this user's authentication with this kaiType - -`DELETE /api/v1/users/:userID/integrations/kai/:kaiType` - - -**Kamaitachi Only** - -!!! note - A KaiType is either "flo", "min", or "eag". Since these three services - share backends, they all use the same authentication mechanisms, and share - endpoints like this. - -### Permissions - -- Self-key: This request must be made using Cookie authentication, which means it cannot be used with API keys. - -### Parameters - -None. - -### Response - -Empty Object. - -***** - -## Update a user's access_token and refresh_token from an intermediate code. - -`POST /api/v1/users/:userID/integrations/kai/:kaiType/oauth2callback` - -**Kamaitachi Only** - -!!! info - This is used as part of an [OAuth2 Flow](https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2). - - The client controls the callback link after authentication with the service, and then POSTs the returned `code` to us. - This part of the flow actually updates the user. - -### Permissions - -- Self-key - -### Parameters - -| Property | Type | Description | -| :: | :: | :: | -| `code` | String | The intermediate code to use to get the access_token and refresh_token. | - -### Response - -Empty object for body. 200 on success, not 200 on failure - status code depending on error. - -### Example - -#### Request -```js -{ - code: "This_Is_An_1nT3rMeDIate_Code" -} -``` - -#### Response - -```js -{} -``` diff --git a/old-docs/docs/api/routes/users.md b/old-docs/docs/api/routes/users.md deleted file mode 100644 index 3c370a68c..000000000 --- a/old-docs/docs/api/routes/users.md +++ /dev/null @@ -1,483 +0,0 @@ -# Users - -These endpoints are related to users in general. - ---- - -## List Users - -`GET /api/v1/users` - -### Parameters - -| Property | Type | Description | -| :-----------------: | :------: | :----------------------------------------------------------------------------------------------------: | -| `online` (Optional) | Presence | If present, this limits the returned users to those that are currently online. | -| `search` (Optional) | String | If present, this endpoint will only return users where this string is contained within their username. | - -### Response - -| Property | Type | Description | -| :------: | :------------------------------------------------: | :------------------------------------: | -| `` | Array<[UserDocument](../../schemas/user.md)> | The array of up to 100 users returned. | - -!!! note -Users are guaranteeably returned in order of when they were `lastSeen`. - -### Example - -#### Request - -``` -GET /api/v1/users -``` - -#### Response - -```js -[ - { - id: 1, - username: "zkldi", - // ... continued - }, -]; -``` - ---- - -## Retrieve user with ID - -`GET /api/v1/users/:userID` - -!!! note -The :userID param has some special functionality, -and any time you see it in these docs, that -functionality is supported. - - You may pass the integer userID for this user - 1. - You may also pass the username - zkldihis is also case-insensitive, so you could pass zklzkldi - You may also pass the special string - `me` - which - will select whatever user you are authenticated as. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :-----------------------------------: | :---------------------------------------: | -| `` | [UserDocument](../../schemas/user.md) | The user this ID/username corresponds to. | - -### Example - -!!! note -`zk` is the username for the user with userID 1. - - it's also the username of the person writing these - docs. Hi! - -#### Request - -``` -GET /api/v1/users/zkldi -OR -GET /api/v1/users/1 -OR -GET /api/v1/users/zkldit's case insensitive!) -OR -GET /api/v1/users/me IF authenticated as userID 1. -``` - -#### Response - -```js -{ - id: 1, - username: "zkldi - // ... so on -} -``` - ---- - -## Modify this user document. - -`PATCH /api/v1/users/:userID` - -### Permissions - -- Self-Key level authentication as this user. - -### Parameters - -| Property | Type | Description | -| :----------------------------------------------------------: | :------------: | :---------------------------------------------------------------------------: | -| `about` | String | An about me. This is rendered as markdown. | -| `status` | String \| Null | The users status. If null, this will be unset. | -| `discord`, `twitter`, `github`, `steam`, `youtube`, `twitch` | String \| Null | Information about this users social media. If null, this field will be unset. | - -### Response - -| Property | Type | Description | -| :------: | :-----------------------------------: | :--------------------------------------------------: | -| `` | [UserDocument](../../schemas/user.md) | The user document with all of those changes applied. | - -### Example - -#### Request - -```js -{ - "about": "#Hello!**I'm zkldi, - "status": "I'm cool!", - "twitter": null, - "steam": "zkldi -} -``` - -#### Response - -```js -{ - "id": 1, - "username": "zkldi - "usernameLowercase": "zkldi - "socialMedia": { - "twitter": null, - "steam": "zkldi - // this property was already here, and not modified by the request. - "discord": "chatbpd", - }, - "about": "#Hello!**I'm zkldi, - "status": "I'm cool!", - // and other user props... -} -``` - ---- - -## Retrieve per-game profiles for a user. - -`GET /api/v1/users/:userID/game-profiles` - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :--------------------------------------------------: | :-----------------------------------------: | -| `` | Array<UserGameStatsDocument & \_\_rankingData> | The array of per-game profile documents (ratings and classes) this user has. | - -!!! info -For UI reasons, the UserGameStatsDocuments here have an additional `__rankingData` property, which contains leaderboard ranking information for this user. - -### Example - -#### Request - -``` -GET /api/v1/users/zkldime-stats -OR -GET /api/v1/users/1/game-profiles -``` - -#### Response - -```js -[ - { - userID: 1, - game: "iidx", - playtype: "SP", - ratings: { - ktRating: 15, - }, - classes: { - dan: 14, - }, - __rankingData: { - ktRating: { - ranking: 15, - outOf: 74, - }, - BPI: { - ranking: 12, - outOf: 74, - }, - }, - }, - { - userID: 1, - game: "gitadora", - playtype: "Dora", - ratings: { - skill: 1404, - }, - classes: { - skillColour: 1, - }, - __rankingData: { - skill: { - ranking: 199, - outOf: 202, - }, - }, - }, -]; -``` - -!!! info -In the event a user has played no games, this will -return an empty array. - ---- - -## Change Profile Picture - -`PUT /api/v1/users/:userID/pfp` - -### Permissions - -- customise_profile -- Must be the owner of this profile. - -### Parameters - -| Property | Type | Description | -| :------: | :---------: | :-----------------------------: | -| `pfp` | JPG, or PNG | The new profile picture to set. | - -!!! note -This endpoint expects multipart form data. - -### Response - -| Property | Type | Description | -| :------: | :----: | :--------------------------------------------------------: | -| `get` | String | This contains the URL to then GET the new profile picture. | - -### Example - -#### Request - -``` -PUT /api/v1/users/1/pfp -``` - -``` -// this is not a real multipart request, as those things -// are huge! -pfp= -``` - -#### Response - -```json -{ - "get": "/api/v1/users/1/pfp" -} -``` - ---- - -## Get a user's profile picture. - -`GET /api/v1/users/:userID/pfp` - -### Parameters - -None. - -### Response - -**Not JSON**. This returns the actual JPG or PNG stored for -this user. - -### Example - -N/A - ---- - -## Unset your profile picture. - -`DELETE /api/v1/users/:userID/pfp` - -!!! note -If you do not have a profile picture set, this will be -a 404 error. - -### Permissions - -- customise_profile -- Must be the owner of this profile. - -### Parameters - -None. - -### Response - -None. - -### Example - -Self-explanatory. - ---- - -## Change Profile Banner - -`PUT /api/v1/users/:userID/banner` - -### Permissions - -- customise_profile -- Must be the owner of this profile. - -### Parameters - -| Property | Type | Description | -| :------: | :---------: | :----------------------------: | -| `banner` | JPG, or PNG | The new profile banner to set. | - -!!! note -This endpoint expects multipart form data. - -### Response - -| Property | Type | Description | -| :------: | :----: | :-------------------------------------------------------: | -| `get` | String | This contains the URL to then GET the new profile banner. | - -### Example - -#### Request - -``` -PUT /api/v1/users/1/banner -``` - -``` -// this is not a real multipart request, as those things -// are huge! -banner= -``` - -#### Response - -```json -{ - "get": "/api/v1/users/1/banner" -} -``` - ---- - -## Get a user's profile banner. - -`GET /api/v1/users/:userID/banner` - -### Parameters - -None. - -### Response - -Not JSON. This returns the actual JPG or PNG stored for -this user. - -### Example - -N/A - ---- - ---- - -## Unset your profile banner. - -`DELETE /api/v1/users/:userID/banner` - -!!! note -If you do not have a profile banner set, this is -a 404 error. - -### Permissions - -- customise_profile -- Must be the owner of this profile. - -### Parameters - -None. - -## Retrieve your notifications - -`GET /api/v1/users/:userID/notifications` - -### Permissions - -- Must be a session-request from the user who owns these notifications. - -!!! note -All of the notification endpoints must be accessed by session-level authentication -from the right requesting user; viz. no api keys can access these endpoints, and -nobody can read another players notifications. - - This isn't really for any security reasons, but more for privacy reasons. It feels - wrong to be able to let others read others notifications. - -### Parameters - -None. - -### Response - -| Property | Type | Description | -| :------: | :-------------------------------: | :----------------------------------------------------------------------------------: | -| `` | Array<NotificationDocument> | An array of all of this users notifications, sorted by most recently recieved first. | - ---- - -## Mark all of your notifications as read. - -`POST /api/v1/users/:userID/notifications/mark-all-read` - -!!! info -This endpoints marks all of a users notifications as read, and is intended for a UI -to invoke this request when they open their inbox. - -### Permissions - -- Must be a session-level request from the user who owns these notifications. - -### Parameters - -None. - -### Response - -None. (Empty Object) - ---- - -## Clear all notifications from your inbox. - -`POST /api/v1/users/:userID/notifications/delete-all` - -### Permissions - -- Must be a session-level request from the user who owns these notifications. - -### Parameters - -None. - -### Response - -None. (Empty Object) diff --git a/old-docs/docs/api/terminology.md b/old-docs/docs/api/terminology.md deleted file mode 100644 index cc7a1c2ea..000000000 --- a/old-docs/docs/api/terminology.md +++ /dev/null @@ -1,20 +0,0 @@ -# Notable Terminology - -Similar to the userland terminology document - Tachi has some internal terminology that you should -be familiar with. - -## GPT - -Refers to "Game + Playtype" - a combination of a game and its playtype (i.e. IIDX SP). - -## UGPT - -Refers to "User on Game + Playtype" - A user's "something" on a game and that playtype. - -## Targets - -Targets are a bucket term for things a user might set as targets to aim for. This term subsumes the following features: - -- Goals -- Quests -- Questlines diff --git a/old-docs/docs/api/webhooks/class-update-v1.md b/old-docs/docs/api/webhooks/class-update-v1.md deleted file mode 100644 index a36b6945a..000000000 --- a/old-docs/docs/api/webhooks/class-update-v1.md +++ /dev/null @@ -1,25 +0,0 @@ -# Event: class-update/v1 - -The content is as follows: - -| Property | Type | Description | -| :: | :: | :: | -| `userID` | Integer | The user ID who had a class update. | -| `set` | Game Class Set | The name of the class set that was updated, such as `genocideDan` or `vfClass`. | -| `game` | Game | The game this class update was for. | -| `playtype` | Playtype | The playtype this class update was for. | -| `old` | Null \| String | The old value for this class. If null, the user had no class here before. | -| `new` | String | The new value for this class. | - -## Example - -```json -{ - "userID": 1, - "set": "dan", - "game": "iidx", - "playtype": "SP", - "old": null, - "new": "CHUUDEN" -} -``` \ No newline at end of file diff --git a/old-docs/docs/api/webhooks/main.md b/old-docs/docs/api/webhooks/main.md deleted file mode 100644 index 897b2ebbf..000000000 --- a/old-docs/docs/api/webhooks/main.md +++ /dev/null @@ -1,33 +0,0 @@ -# About Webhooks - -Tachi supports webhooks. You can set a `webhookUri` as part of your -[Tachi API Client](../routes/clients.md). - -## Usage and Security - -When a given event happens on Tachi, your webhookUri will receive a POST -request with some content and the type of event. - -You **MUST** validate that this request was from Tachi! Otherwise, anyone -could post fake data to your webhook URI and potentially compromise it. - -To secure your webhook implementation, Tachi will send an Authorization header with `Bearer CLIENT_SECRET`. You should check that that value aligns with your client secret. If it doesn't, someone might be trying to perform an attack! - -## Data Format - -Data is sent as follows: - -```json -{ - "type": "EVENT_TYPE", - "content": {} // Content specific to that EVENT_TYPE! -} -``` - -The current Events are: - -| Type | Description | -| :: | :: | -| `class-update/v1` | Fires whenever a user has had a class update positively, such as going from 9th Dan to 10th Dan. | -| `goal-achieved/v1` | Fires whenever a user has achieved a goal. | -| `quest-achieved/v1` | Fires whenever a user has achieved a quest. | diff --git a/old-docs/docs/codebase/batch-manual/direct-manual.md b/old-docs/docs/codebase/batch-manual/direct-manual.md deleted file mode 100644 index 9e79a8183..000000000 --- a/old-docs/docs/codebase/batch-manual/direct-manual.md +++ /dev/null @@ -1,22 +0,0 @@ -# Direct Manual - -Direct Manual is a way of POSTing BATCH-MANUAL content straight to the server. - -In short, this lets you implement your own IRs, with absolutely no input -from me. - -## Flow - -You need to send a POST request to `/ir/direct-manual/import`, with the body -of the request being a batch manual document. - -You can set the `X-User-Intent` Header to true if the import was done with -user-intent (i.e. they clicked a button to fire this request, rather than it -being automated in the background). - -!!! warning - The response from `/ir/direct-manual/import` *MAY* be deferred if the `tachi-server` instance uses score import workers. If this happens **202** will be returned as the status code. You **MUST** then poll the import status to find out what happened to it (such as it failing.) - -## That's it! - -Seriously -- that's it. diff --git a/old-docs/docs/codebase/batch-manual/index.md b/old-docs/docs/codebase/batch-manual/index.md deleted file mode 100644 index d4bf75000..000000000 --- a/old-docs/docs/codebase/batch-manual/index.md +++ /dev/null @@ -1,210 +0,0 @@ -# What is BATCH-MANUAL? - -BATCH-MANUAL is a JSON format that Tachi accepts. -This format can be submitted as [a file](../../api/routes/import.md#import-scores-from-a-file) -using the `file/batch-manual` [Import Type](../import/import-types.md), or it can be submitted as a -[HTTP request body](./direct-manual.md). - -***** - -## Motivation - -Instead of Tachi writing new support for every kind of -possible export, and bothering other service providers -to write exports, we could write a generic format we accept -and then users with a bit of scripting knowledge can import -their own scores. - -This has the additional advantage of allowing extremely -obscure imports, and reduces the workload on Tachi. - -## Format - -The format is incredibly simple JSON. - -It is comprised of two base keys, `meta` and `scores`. - -!!! note - These keys were originally called `head` and `body` in Kamaitachi. You will have to update - existing batch-manual code. - -### Meta - -The `meta` key contains metadata, and looks like this: - -```json -{ - "game": "iidx", - "playtype": "SP", - "service": "foobar" -} -``` - -The fields have the following values: - -| Property | Type | Description | -| :: | :: | :: | -| `game` | Any Game Identifier | The game this import is for. | -| `playtype` | Any Playtype for the above game. | The playtype this import is for. | -| `service` | String | A humanised string to explain where these scores are from. This must be between 2 and 15 characters. | -| `version` (Optional) | String | Optionally, you can specify a version of the game this import is for. This should be used when conflicting versions of songs exist, or when this import is rather old. Most of the time, this does not need to be present. | - -### Scores - -The `scores` property is an array of Batch Manual Scores. An example -score is as follows: - -```json -{ - "score": 500, - "lamp": "HARD CLEAR", - "matchType": "songTitle", - "identifier": "5.1.1.", - "difficulty": "ANOTHER", - "timeAchieved": 1624324467489 -} -``` - -The properties are described as this: - -| Property | Type | Description | -| :: | :: | :: | -| `score` | Number | The score for this, well, score. This should use the default scoring algorithm for this game. | -| `lamp` | Lamp | The lamp for this score. This should be one of the lamps as described in the config for your game + playtype. | -| `percent` (Conditional) | Number | Only appears for `jubeat`. This should be set to the Percent for this score. In jubeat's case, this is your Music Rate. | -| `matchType` | "songTitle" \| "ddrSongHash" \| "tachiSongID" \| "bmsChartHash" \| "inGameID" \| "uscChartHash" | This determines how `identifier` will be used to match your scores' chart with Tachi's database of songs and charts. | -| `identifier` | String | A string that Tachi uses to identify what chart this is for. How this is used depends on the `matchType`. | -| `difficulty` (Conditional) | String | If `matchType` is "tachiSongID", "inGameID", "ddrSongHash" or "songTitle", this field must be present, and describe the difficulty of the chart this score is for. | -| `artist` (Conditional) | String | If `matchType` is "songTitle", this field can be present, and describe the artist name for less equivocal matching. This field is optional for legacy purposes. | -| `timeAchieved` (Optional) | integer \| null | This is *when* the score was achieved in unix milliseconds. This should be provided if possible, as Tachi uses it for a LOT of features. | -| `comment` (Optional) | string \| null | A comment from the user about this score. | -| `judgements` (Optional) | Record<Game Judgement, integer> | This should be a record of the judgements for your game + playtype, and the integer indicating how often they occurred. | -| `optional` (Optional) | See [Game Specific Optional Metrics](../../schemas/score.md#game-specific) | Any optional metrics you wish to provide for this game. | -| `scoreMeta` (Optional) | See [Game Specific Score Meta](../../schemas/score.md#game-specific) | This can be a partial record of various `scoreMeta` props for this game. | - -!!! warning - `identifier` should always be a string. Even if it's something like a numeric ID! Tachi will handle this. - -!!! warning - `timeAchieved` is in **UNIX MILLISECONDS**. Most programming languages use unix seconds. You might have to - multiply your timestamps by 1000. - -#### Match Type - -There are many match types, and they all use identifier -in a different way. - -- songTitle - -As the name implies, this searches for a song whose title -is exactly `identifier`. **THIS IS NOT FUZZY MATCHING**, -and is by far the least reliable way to send scores to -Tachi. This is kept for compatibility purposes with poor quality APIs. - -This match type *necessitates* that `difficulty` be defined -and set to a valid difficulty for this game + playtype. - -This match type can be augmented with a secondary identifier `artist` -which resolves title clashes: - -```json -{ - "score": 500, - "lamp": "HARD CLEAR", - "matchType": "songTitle", - "identifier": "5.1.1.", - "artist": "dj nagureo", - "difficulty": "ANOTHER", - "timeAchieved": 1624324467489 -} -``` - -- tachiSongID - -This uses `identifier` as if it were an integer, to match -songs based on the `id` field of a tachi song. - -This match type *necessitates* that `difficulty` be defined -and set to a valid difficulty for this game + playtype. - -- bmsChartHash - -As the name implies, this looks for the chart hash BMS -uses. This can be either the MD5 hash or the SHA256 hash, -both will match. - -This match type can only be used for BMS. - -- uscChartHash - -This looks for the chart SHA1 that USC uses. As expected, this -can only be used for USC. - -- inGameID - -This uses the in-game-ID for this **SONG**. You, therefore, -**MUST** specify the difficulty for this chart as well. - -This is supported for the following games: - -- IIDX -- Pop'n Music -- Jubeat -- CHUNITHM -- GITADORA -- maimai -- maimai DX -- WACCA -- MUSECA - -- sdvxInGameID - -This uses the in-game-ID for this SDVX song. You must specify -the difficulty for this chart as well. - -The reason SDVX gets its own special `matchType` is because this -matchType supports `difficulty: "ANY_INF"`. This special difficulty -means that it will check for any of `INF/GRV/HVN/VVD/XCD` for this song. - -This is useful for services that store all of those as the same difficulty. - -- ddrSongHash - -This is a 32-character hash used by the official DDR e-amusement website to -identify a song; you must specify the difficulty for this chart as well. - -## Example - -A final example of a simple BATCH MANUAL format -looks like this: - -```json -{ - "meta": { - "game": "iidx", - "playtype": "SP", - "service": "My Service" - }, - "scores": [{ - "score": 500, - "lamp": "HARD CLEAR", - "matchType": "songTitle", - "identifier": "5.1.1.", - "artist": "dj nagureo", - "difficulty": "ANOTHER" - }, { - "score": 123, - "lamp": "FAILED", - "matchType": "tachiSongID", - "identifier": "1", - "difficulty": "HYPER", - "comment": "This score sucked!", - "optional": { - "bp": 5 - }, - "scoreMeta": { - "random": "MIRROR" - } - }] -} -``` diff --git a/old-docs/docs/codebase/implementation-details/details.md b/old-docs/docs/codebase/implementation-details/details.md deleted file mode 100644 index c2d94058f..000000000 --- a/old-docs/docs/codebase/implementation-details/details.md +++ /dev/null @@ -1,7 +0,0 @@ -# About - -As you'd expect, this section contains implementation details. Although the entire -codebase reference is technically about implementation details, this part is -for miscellaneous implementation details that wouldn't fit anywhere else. - -***** diff --git a/old-docs/docs/codebase/implementation-details/game-configuration.md b/old-docs/docs/codebase/implementation-details/game-configuration.md deleted file mode 100644 index 516a5f602..000000000 --- a/old-docs/docs/codebase/implementation-details/game-configuration.md +++ /dev/null @@ -1,22 +0,0 @@ -# Game Configuration - -Tachi has two sets of game configurations. - -The first is on the game level, which contains things -like the humanised name for the game (i.e. `iidx -> beatmania IIDX`). - -The second is for each individual game + playtype -combination, which contains things like the list of -lamps for the game. - -!!! help -This page is unfinished. - - It would be really appreciated if someone formatted - the configurations for every game! For the time being, - the below documentation is just the raw configuration - for each game. Please see [Contributing to Tachi](../../contributing). - ---- - -This documentation is unfinished. It is probably easier for you to [just read the config.ts file](https://github.com/zkldi/Tachi/tree/main/common/src/config/config.ts) diff --git a/old-docs/docs/codebase/implementation-details/goal-id.md b/old-docs/docs/codebase/implementation-details/goal-id.md deleted file mode 100644 index 2443e871d..000000000 --- a/old-docs/docs/codebase/implementation-details/goal-id.md +++ /dev/null @@ -1,18 +0,0 @@ -# Goal ID implementation - -Goal IDs exist to dedupe goals when a user creates -a new goal. For example, if a user wants to create a -HARD CLEAR Mei goal, but one already exists, we should -not insert two [Goal Documents](../../schemas/goal.md) -representing the same thing. - ---- - -## Hashing - -To create the Goal ID, we perform a [JSON stable hash](https://github.com/zkldi/fast-json-stable-hash) on the -`game`, `playtype`, `charts` and `criteria` of this field. - -This enforces that goals are unique on those fields. - -The above hash is then returned, prefixed with `G`. diff --git a/old-docs/docs/codebase/implementation-details/goals-quests.md b/old-docs/docs/codebase/implementation-details/goals-quests.md deleted file mode 100644 index dbbcc47db..000000000 --- a/old-docs/docs/codebase/implementation-details/goals-quests.md +++ /dev/null @@ -1,115 +0,0 @@ -# Goals, Quests, Questlines - -This page covers pretty much everything you need to know about interacting with goals -and quests. - -Although these features are fairly straightforward on the surface, their implementation is a bit complex at points. We'll get to it. - -## What is a Goal? - -A goal is a set of instructions that are evaluated for a player if they are subscribed to it (and it is relevant to their current import, see [Getting Relevant Goals](../import/goals.md)). - -!!! example - An example goal would be something like "AAA 100 charts in the X Folder". - -Users must subscribe to goals for them to be evaluated when they import scores. This is -abstracted away from the user, as the operation to create a goal will automatically subscribe -them to the same goal. - -### Identification - -Goals are identified by a checksum of their instructions. If two users make the goal to "AAA Freedom Dive", the goalID will be the same. - -This allows us to do things like see what goals are popular, and reduce the general duplication on the database. - -## User Subscriptions - -Users may create and subscribe to goals. This is done with the [UGPT Create Goals Endpoint](TODO). If they create a goal that already exists, they are just subscribed to that goal. - -If they create a goal that does not already exist, it is created, and they are subscribed. - -Users may unsubscribe from goals that they no longer care about getting pinged for. - -Subscriptions to goals are stored in a [GoalSubscriptionDocument](../../schemas/goal-sub.md). -This document is uniquely identified by the joining of the `goalID` with the `userID`. - -### Instant Direct Achievements - -If a user creates/subscribes to a goal that they would instantly achieve, they are denied -from adding goal directly. - -### Evaluating A User's Progress - -Goals have two main components in terms of evaluation -- `progress` and `outOf`. If the progress is greater than or equal to the `outOf`, the goal is marked as achieved. - -Both of these values are numbers, and are not intended for human consumption. For example, the goal 'HARD CLEAR Freedom Dive' would be represented by an `outOf` of `6`, which is the internal lampIndex for a BMS HARD CLEAR. - -For human representation, these values are formatted and stored in the Goal Subscription Document as `progressHuman` and `outOfHuman`, respectively. These values are prettified for human users, and leverage game-specific formatting in some cases. - -!!! note - Achieved goals are still calculated -- a user may actually find themselves un-achieving goals in some stranger cases. - - If their goal is something like AAA 10% of a folder, and the folder gets larger, they - may find themselves losing the achieved status on this goal. - -!!! warning - Goal Subscriptions are capped by the MAX_GOAL_SUBSCRIPTIONS [conf.json5](../setup/config.md) property, and defaults to 1000. - -!!! danger - Unsubscribing from goals directly is only possible if they do not have any parent quests. - More on that below. - -## What is a Quest? - -Quests are groups of goals, defined in a structured form, with support for assigning -notes next to goalIDs, and other generally useful stuff. - -Their purpose for users is to give them a quick way to assign a bunch of goals they might care about. - -For example, a dedicated user may make their own "Kaiden Checklist", and create a set of goals -they think are useful for kaidens to aim for. Another user interested in this can just -subscribe to that quest, and all the goals will be managed for them. - -### Identification - -Quests are identified by their `questID`, which is a completely arbitrary string. - -At the moment, users cannot create quests directly, they are hard-defined by the [Database Seeds](../infrastructure/seeds.md). - -### Evaluating a User's Progress - -Similarly to goals, user's can subscribe to quests. - -Quest subscriptions are interesting in that the `progress` factor is always an integer -- how many goals in the quest the user has achieved, and the `outOf` factor is always an integer -- how many goals need to be achieved in the quest for the quest to be marked as achieved. - -Similarly, the `achieved` status on quests is identical to `progress` being greater than or equal to `outOf`. - -### Parenting Goal Subscriptions - -When a quest is subscribed to, all the goals in the quest are also subscribed to. - -When a user is subscribed to a quest, they *must* also be subscribed to all the goals in -that quest. If they aren't, they've desynced with the quest, and that's an awful -user experience. - -As such, Tachi keeps track of all the quests that care about this goal subscription, and users are *prevented from unsubscribing from this goal* while any of their quest subscriptions parent the goal. - -### Instant Indirect Achievements - -Subscribing to a quest *mandates* that all of the goals are assigned. It is not rare for this to mean that you subscribe to goals that are instantly achieved. - -This is fine. If this does happen though, `wasInstantlyAchieved` is set on the goal, and no -webhook event is emitted. - -### Unsubscribing - -For all `goalID`s in the quest, we check if this goal subscription has any other parent quests. - -If this quest was the only reason the goal was assigned (i.e. it wasn't assigned directly, or isn't part of another quest), this quest will be unsubscribed from. - -## Questlines - -Questline are ordered lists of quests. Their purpose is to group quests together -visually in an ordered manner. - -Users *can not* "subscribe" to questlines, but they can use questlines as a utility for subscribing to all the related quests. diff --git a/old-docs/docs/codebase/implementation-details/score-id.md b/old-docs/docs/codebase/implementation-details/score-id.md deleted file mode 100644 index b3bca918a..000000000 --- a/old-docs/docs/codebase/implementation-details/score-id.md +++ /dev/null @@ -1,42 +0,0 @@ -# Score ID implementation - -Score IDs exist to dedupe scores when a user re-submits -the same scores. This happens frequently with `file/` -and `api/` [Import Types](../import/import-types.md), -as they typically resubmit the same scores. - -If a user only got a score once, we don't want to store -it twice. - -Sadly, we can't depend on things like timestamps to assert -whether or whether not we've saw a score before. Many services -alter/tamper their timestamps such that they're unreliable. - -!!! example - E-Amusement IIDX CSVs will change the timestamp of every single - score when a new version comes out to the second the user created - their new account. - -***** - -## Hashing - -The score ID is created by joining the following properties: - -- The `userID` that got this score -- The `chartID` that this score was on -- All [Provided Metrics](todo) for this GPT -- Any [Optional Metrics](todo) that have been marked as `partOfScoreID` - -and then hashing them with SHA256. - -This is then prefixed with `T`, and returned. - -## Clobbering - -Since a scoreID isn't necessarily all of the possible statistics for a score, it's -possible for users to "clobber" their scores, by importing a score without as many -pieces of info (i.e. no judgements), then trying to import that same score with -judgements later will not work, as the scoreID sees it as a duplicate. - -See [Clobbering](todo). diff --git a/old-docs/docs/codebase/implementation-details/search.md b/old-docs/docs/codebase/implementation-details/search.md deleted file mode 100644 index f4de0bbe7..000000000 --- a/old-docs/docs/codebase/implementation-details/search.md +++ /dev/null @@ -1,43 +0,0 @@ -# Search Implementation - -Tachi's search implementation uses MongoDB's $text index. This breaks a query into words -and compares each of them to the provided text fields. - -***** - -## __textScore - -For our code, we mutate the documents we want to return with a special field: `__textScore`. - -This field declares how 'close' the provided query was to the $text fields in this document. - -This is sometimes exposed in the API for sorting reasons. - -!!! bug - MongoDB's $text matching algorithm isn't great for fuzzy matches - It doesn't - like song titles like 'A', as it thinks 'a' is an article, and doesn't match it properly as - a word. - -!!! info - Why not regex for fuzzy matches? - - Regex has performance issues on larger datasets and we - want to avoid it. Most regexes cannot use indexes, and therefore invoke a COLLSCAN, which - we want to avoid. - -## User Searching - -Searching users, on the other hand, has to use regex-based -searching. - -The `$text` method attempts to break things up based on their -words, but that doesn't help with usernames, as they are all -too frequently `XxX_One_Long_Str1ng_xXx`. - -Instead, we use a case insensitive regex - similar to SQL's -`LIKE`. - -This means we do not have a `__textScore` property for this -search to sort on. Instead, we just constrict returns to -around 15, and have the user whittle their search down -better. diff --git a/old-docs/docs/codebase/implementation-details/songs-charts.md b/old-docs/docs/codebase/implementation-details/songs-charts.md deleted file mode 100644 index df729704e..000000000 --- a/old-docs/docs/codebase/implementation-details/songs-charts.md +++ /dev/null @@ -1,121 +0,0 @@ -# Songs And Charts - -Tachi structures its song and chart data in a specific -manner in order to avoid copying properties all over -the place. - -***** - -## Songs - -Songs look like this: - -```json -{ - "title": "5.1.1.", - "artist": "dj nagureo", - "id": 1, - "firstVersion": "0", - "alt-titles": [], - "search-titles": [], - "data": { - "genre": "PIANO AMBIENT" - } -} -``` - -They're relatively small documents, and contain some metadata. - -Depending on the game, the `data` prop will contain -game-specific properties (i.e. not all games have -song genres!) - -Songs, however, don't contain any information about -their *charts*. The charts are what people actually play. - -In short, songs are *just* a collection of metadata that -parents a chart document! - -***** - -## Chart Documents - -Chart Documents **MUST** belong to a song. In the below -chart, `songID` refers to the above song document: - -```json -{ - "chartID": "c2311194e3897ddb5745b1760d2c0141f933e683", - "difficulty": "ANOTHER", - "songID": 1, - "playtype": "SP", - "levelNum": 10, - "level": "10", - "data": { - "inGameID": 1000, - "notecount": 786, - }, - "isPrimary": true, - "versions": [ - "27-omni", - "26-omni", - "27", - "26", - "inf", - "16-cs", - "12-cs", - "10-cs", - "8-cs", - "7-cs", - "bmus" - ] -} -``` - -Songs can have multiple charts, but charts can only have -one song. - -## Primary - -Sometimes, games like to rechart things and release them -under the exact same song. Sometimes, they even do this -under the *exact* same internal songID! - -A 'Primary' chart refers to a chart that is the *current* -variant of that chart for this game. Non-Primary charts -are not eligible for any rating calculations, nor do they -contribute to profile rating. - -To check if a chart is primary or not, the `isPrimary` property -handles that. - -For example: - -```json -{ - "chartID": "103ff8bb004e1a8a005f808c025c3feb", - "difficulty": "ANOTHER", - "songID": 1, - "playtype": "SP", - "levelNum": 5, - "level": "5", - "data": { - "inGameID": 1000, - "notecount": 433 - }, - "isPrimary": false, - "versions": [ - "1" - ] -} -``` - -Notice that the chartID is different, and `isPrimary` -is set to false. - -Even though this chart is "5.1.1 (SP ANOTHER)", it isn't -the primary chart for this songID + playtype + difficulty. - -For the UI, Tachi will hide non-primary charts by default. -Realistically, they only exist to support legacy scores -without having to throw them away when a rechart occurs. diff --git a/old-docs/docs/codebase/import/conv-failures.md b/old-docs/docs/codebase/import/conv-failures.md deleted file mode 100644 index 61c6ad85f..000000000 --- a/old-docs/docs/codebase/import/conv-failures.md +++ /dev/null @@ -1,60 +0,0 @@ -# Converter Failures - -This page contains the list of possible converter fail -states that can be thrown. All of them can be found in -`src/lib/score-import/common/converter-failures.ts`. - -***** - -## SkipScoreFailure - -This is a special case of a failure, in that it isn't -logged or marked as an error in the import. This call -just means we should skip the score. - -An example case of this would be something like the -eamusement IIDX CSV format, which can pass 'empty' scores -for a chart. We would want to skip over those, and they -aren't an error. - -When this is thrown, the score is skipped, and nothing is -imported. - -## SongOrChartNotFoundFailure - -!!! bug - KTData means 'Kamaitachi Data', but this applies to - Bokutachi just as much, it is just a legacy name - holdover. - -This failure means that the score could not match with -anything in the database, such as giving a chartID that -Tachi does not have in its database. - -This failure also takes the current data, importType and -parser context. This is so we can create [Orphan Scores](./orphans.md). - -## Invalid Score Failure - -This score provided invalid data that we cannot process. - -An example of this would be an IIDX score with -1 EX Score. - -## Internal Failure - -This is an internal failure, and thrown when something bad -has occurred on our end. - -The most common case for throwing this is the "Song-Chart" -desync. This occurs when a chart has no parent song (and -a chart must have a parent song.) - -!!! info - This is generally used for states that should never happen, - but we want to handle them nicely anyway. - -## Any Exception - -If any exception is thrown from a converter that is **NOT** -an `instanceof` ConverterFailure, it is treated as an -InternalFailure. diff --git a/old-docs/docs/codebase/import/goals.md b/old-docs/docs/codebase/import/goals.md deleted file mode 100644 index ee5db8163..000000000 --- a/old-docs/docs/codebase/import/goals.md +++ /dev/null @@ -1,38 +0,0 @@ -# Updating Goals - -If a user has goals set, we need to update their -progress on those goals as a result of this import. - -***** - -## Getting Relevant Goals - -In V1 of Tachi, we fetched *all* goals for a user, -and recalculated all of them. - -This was fine for users with some goals, but for users with -lots of goals, it quickly became a huge performance boon. - -To avoid that, Tachi V2 fetches only the "relevant" goals -as a result of the import. This is calculated as follows: - -- Single Goals are matched if their chartID is inside the set of chartIDs affected. - -- Multi Goals are matched if their data contains any chartIDs that were affected. - -- Folder goals are matched if the folder contains any charts inside the set of chartIDs affected. - -## Processing Goals - -For every goal matched, we iterate over it and evaluate -it using `EvaluateGoalForUser`. - -We then need to convert the returns of that function into -the expected goal format for ImportDocuments. - -That means we have to compare the old UserGoal's progress -with the newly returned one. - -If nothing has changed, we return undefined. If something -has changed, we return a `bwrite` key that contains a -MongoDB bulk-write operation to update the UserGoal, and the expected import format of goalID, old, new. diff --git a/old-docs/docs/codebase/import/import-doc-time.md b/old-docs/docs/codebase/import/import-doc-time.md deleted file mode 100644 index debcccdce..000000000 --- a/old-docs/docs/codebase/import/import-doc-time.md +++ /dev/null @@ -1,35 +0,0 @@ -# Import Documents and Import Timings - -The final step of the process is to coalesce all the returns -of the various steps above into one analysable document -and return it. - -***** - -## Logging - -If the import had over 500 scores, we log the import at Info level. This is because those are generally rare, and we -want to know how our performance is doing at a glance. - -If the import has over 1 score, it is logged as verbose. - -Else, the import is logged as debug. - -## Timings - -An internal document - Import Timings - is created by -storing the time each step of the import process took -in milliseconds. - -This is analysed regularly to check for performance -degradation and look for potential optimisations. - -This is also stored in the database. - -## Returns - -The Import Document **is** the return from ScoreImportMain. - -This document contains all the relevant information -about the import and what it has resulted in, and -is also stored in the database under a random ID. diff --git a/old-docs/docs/codebase/import/import-types.md b/old-docs/docs/codebase/import/import-types.md deleted file mode 100644 index 53e070cd6..000000000 --- a/old-docs/docs/codebase/import/import-types.md +++ /dev/null @@ -1,64 +0,0 @@ -# Import Types - -The score import code for Tachi uses 'Import Types' to -determine what kind of code to run on a given import, -and what converter to call (more on that later.) - -***** - -## Format - -An import type is just a string. It is formatted as follows: - -``` -type/name -``` - -## Types - -There are three types. - -| Type | Description | -| :: | :: | -| `file/` | The data is coming from a file, such as one from a multipart form submission. | -| `ir/` | The data is coming from a HTTP Request sent to us. | -| `api/` | The data is being fetched by us from another service through HTTP Requests. | - -## User Intent - -Some imports are performed with user intent, such as -the user going to the Tachi website and uploading -a file and clicking submit. - -Some imports are performed without user intent, i.e. -the user sets up a score hook to automatically import -their scores whenever they get one. The reason for the -distinction is for hiding "automatic" imports from the -users imports page. - -For certain endpoints, the special header `X-User-Intent` -is set to indicate that this was done with User Intent. - -!!! warning - As this is just a convention, you can abuse it, but you - shouldn't, because it's not nice to break things - (and you may be banned). - -## List of Import Types - -| ImportType | Description | Availability | User Intent | -| :: | :: | :: | :: | -| `file/eamusement-iidx-csv` | The E-amusement CSV format for IIDX. This type accepts both Pre-HV and Post-HV formats. | Kamaitachi | Yes | -| `file/batch-manual` | The Tachi BATCH-MANUAL format submitted through a multipart form. | Kamaitachi & Bokutachi | Yes | -| `file/solid-state-squad` | The IIDX XML output by Solid State Squad. | Kamaitachi | Yes | -| `file/pli-iidx-csv` | Same as eamusement's IIDX CSV, but output from PLI. | Kamaitachi | Yes | -| `ir/direct-manual` | The Tachi BATCH-MANUAL format but submitted in a HTTP Request body as `application/json`. | Kamaitachi & Bokutachi | Depends on Header | -| `ir/barbatos` | Barbatos's format submitted in a HTTP Request Body. | Kamaitachi | No | -| `ir/fervidex` | Fervidex's score format submitted in a HTTP Request Body. | Kamaitachi | No | -| `ir/fervidex-static` | Fervidex's profile sync format submitted in a HTTP Request Body. | Kamaitachi | No | -| `ir/usc` | An implementation of the [USCIR](https://uscir.rtfd.io)'s POST /scores endpoint. | Bokutachi | No | -| `ir/beatoraja` | A handler for BokutachiIR's score format. | Bokutachi | No | -| `api/flo-iidx`, `api/eag-iidx` | Both the same IIDX format, but yielded from different APIs with different players. | Kamaitachi | Depends on Calling[^1] | -| `api/flo-sdvx`, `api/eag-sdvx`, `api/min-sdvx`| See above, but for SDVX. | Kamaitachi | Depends on Calling[^1] | - -[^1]: If this is synced manually by the user, I.e. they have called it to be synced, then it is with intent. If it was called for them through automatic synchronisation, then it was not done with user intent. diff --git a/old-docs/docs/codebase/import/importing.md b/old-docs/docs/codebase/import/importing.md deleted file mode 100644 index d51b06206..000000000 --- a/old-docs/docs/codebase/import/importing.md +++ /dev/null @@ -1,108 +0,0 @@ -# Importing DryScores - -This page goes over hydrating a DryScore into a fully -fledged Tachi score, and then goes over how it is imported. - -!!! warning - Performance has been squeezed out of this process - rather aggressively, as such, some of the more - 'obvious' ways to do things have been ignored - for performance gains. - -!!! info - The code that handles this logic is found in - `src/lib/score-import/framework/score-importing/score-importing.ts`. - -***** - -## Return Format - -The `ImportIterableDatapoint` returns -`ImportProcessingInfo` or `null`. The format for the former -can be found in `tachi-common`, and **should be read** before -following this document! - -As a rough outline: -```ts -{ - // whether this import worked or not - success: boolean; - // ScoreImported implies success: true, and all others imply success: false. - type: "ScoreImported" | "SongOrChartNotFound" // ... and more; - // An error message. - message: String | null; - // Some errors return some data about the error, or things like scoreImported returns the score that was imported. - content: see_implementation -} -``` - -## Dealing with converter returns - -As mentioned in [Parsers and Converters](./parse-conv.md), -converters will return a DryScore, and its matching chart -and song on success. - -However, failures are also an expected throw from a -converter function. We handle these throws by logging -them dependent on their severity, and returning -that this score has failed to be imported properly -in the `ImportProcessingInfo` format. - -If the converter was successful, we now have a DryScore, song and chart to work with. - -## Hydration - -Our first step is to turn that DryScore into a 'real score'. - -!!! info - The code for this is found in `HydrateScore`. - -Before anything, we calculated the ScoreID for this score. -This is used to dedupe scores, and is a checksum of -the following properties. - -- userID -- chartID -- lamp -- grade -- score -- percent - -We fill out all the properties that can be calculated -about the score, such as the aptly named `calculatedData`, -and things like `gradeIndex` and `lampIndex`, which are -just the index of the grade/lamp string in the set of grade/lamps. - -Other properties, such as `timeAdded` (the time this data was inserted into the database) can be trivially attached onto the score. - -## Insertion - -Now that we have a real Tachi score, we can insert it into -the database. - -The obvious solution here is something like: -```ts -await db.scores.insert(scoreDocument); -``` - -But this has performance implications for large sets of -scores. - -To solve these performance issues, we use a queue to insert -scores. - -ScoreDocuments are appended to a queue of 500. -If the queue hits 501 scores, the queue is bulk-written to -the database. At the end of hydrating and queueing all scores, the queue is flushed one last time. - -This simple optimisation provides large performance benefits. - -## Final Returns - -Importing each datapoint gives us an `ImportProcessingInfo` -object OR `null`. We want to return only the former, -as `null` is for skipped scores. - -We filter out all the nulls and flush the queue before -returning the array of `ImportProcessingInfo` objects -that were returned from our import process. diff --git a/old-docs/docs/codebase/import/main.md b/old-docs/docs/codebase/import/main.md deleted file mode 100644 index c44ba3084..000000000 --- a/old-docs/docs/codebase/import/main.md +++ /dev/null @@ -1,155 +0,0 @@ -# Score Import Main - -This page refers to the entry point function for a score -import. - -This function can be found at `src/lib/score-import/framework/score-import-main.ts`. - -## Signature - -`ScoreImportMain` takes four arguments and an optional fifth. - -| Argument | Type | Description | -| :: | :: | :: | -| `user` | [UserDocument](../../schemas/user.md) | The user that is making this import request. | -| `userIntent` | boolean | Whether this import was performed with User Intent - See [Import Types](./import-types.md#user-intent) | -| `importType` | ImportType | What kind of import "type" this is. For more on this, see [Import Types](./import-types.md) -| `InputParser` | Function | The parser function to call. For more info, see [Parsing and Converting](./parse-conv.md) -| `providedImportObjects` (Optional) | { logger, importID } | Optionally, a logger and existing importID can be passed here. This is used for scenarios where the logger and importID have already been created before importMain was called. | - -## Import Logger - -For ease of debugging, a logger is passed between most -functions in the score importing process. This logger -contains the context of the currently importing user -and the ImportID. - -## Steps - -To make the process easier to parse, the importing process -is split into multiple steps. These steps may split into -further sub-steps, depending on how much occurs in said -step. - -!!! tip - These steps are also commented inline in - `score-import-main.ts`. - -!!! warning - These steps are only an outline of the process! - - For more information on each specific step, links - are given. - -### Setup - -If `providedImportObjects` is not given, then ScoreImportMain generates a new Logger and an ImportID. - -### Parsing - -This step calls the ParserFunction provided as an argument -to this function. The returns from that are then used -in the below steps. - -- Full Page: [Parsing and Converting](./parse-conv.md) - -### Importing - -We iterate over the `iterable` returned from the Parser Function, -calling the Converter Function for each element. - -Once we have converted the element, we can fill it in -and insert it into the database. - -This process returns an array called the "Import Info". - -This object holds information about the set of charts this -import involved, and the set of scores that were imported. - -- Full Page (Converting): [Parsing and Converting](./parse-conv.md) -- Full Page (Importing): [Importing](./importing.md) - -!!! info - This step does most of the work, and is where a - lot of our complexity lies. - -### Parse Import Info - -The next steps require certain information from our Import Info. - -This step parses that data into some values we have use for, such as the set of chartIDs impacted -by this import. - -- Full Page: [Parsing ImportProcessingInfo](./parse-ipi.md) - -### Sessions - -Now that we have imported the scores and have got -an array of scoreIDs newly created from Parse Import Info, -we can move on to creating sessions from this import. - -- Full Page: [Sessions](./sessions.md) - -### Personal Bests - -This step updates the 'personal bests' for the user. It -iterates over every unique chartID modified in this import -and conjoins the users best scores on the chart into one document. - -This is to have a single document that has the users best -lamp and score, which avoids having to join it together -whenever we want to display a users best score and lamp -at the same time. - -- Full Page: [Personal Bests](./pbs.md) - -### Game Stats - -This step updates the user's Game Stats. - -If this is the users first play on this game, then we create -game stats for them. - -The update is performed by recalculating their statistics -with the new scores inserted. - -!!! info - This section is referred to as UGS sometimes internally. - - This is short for User Game Stats. - -- Full Page: [User Game Stats](./ugs.md) - -### Goals - -This step checks the charts modified in this import and -retrieves all the relevant goals. It then checks -all of these goals for whether their status has -changed or not, and updates them accordingly. - -- Full Page: [Goals](./goals.md) - -### Quests - -Checks the set of goals modified in the previous step, -and gets the relevant quests. This step then re-evaluates all of those quests and -updates accordingly. - -- Full Page: [Quests](./quests.md) - -### Import Document - -Finally, we take all of the returns of the above steps -and combine them into an import document. - -This is inserted to the database, and is also the return -value of this function. - -### Import Timings - -Every step in this process is timed in milliseconds. - -The time each step took is saved alongside the ImportID. - -This is used for internal debugging and degraded performance -checks. diff --git a/old-docs/docs/codebase/import/orphans.md b/old-docs/docs/codebase/import/orphans.md deleted file mode 100644 index 895b4238c..000000000 --- a/old-docs/docs/codebase/import/orphans.md +++ /dev/null @@ -1,33 +0,0 @@ -# Orphan Scores - -SongOrChartNotFoundFailures state that we don't have the data -to understand what chart/song this score is for. - -However, that doesn't necessarily imply we won't have that -data in the future. Orphaned scores are a way of storing -score-like data without a song or chart as a parent. - -Then, when the song and chart are made available, those -scores can be imported as if nothing had changed! - -***** - -## How do they work? - -Orphaned scores store the `data` and `context` from the parser. - -When unorphaning is attempted, the Converter Function is -called with that data and context. - -If it results in a SongOrChartNotFoundFailure, we do nothing. - -If it results in a success, we have a new DryScore we can import. - -!!! info - If another type of failure occurs - i.e. InvalidScoreFailure, - then we remove the orphaned score from the DB. - -!!! note - This is why Converter Functions are completely - static, so we can safely call the same Converter - Function with this data to unorphan scores. diff --git a/old-docs/docs/codebase/import/overview.md b/old-docs/docs/codebase/import/overview.md deleted file mode 100644 index 01e55b4a4..000000000 --- a/old-docs/docs/codebase/import/overview.md +++ /dev/null @@ -1,32 +0,0 @@ -# Score Import Overview - -Score importing in Tachi is *very* complex, and involves -a lot of moving parts. For that reason, the entire process -(and my rationale behind each step) is documented here. - -The code for Score Importing can be found at -`src/lib/score-import`. - -The entry point function is `src/lib/score-import/framework/score-import-main.ts`, and everything else is located nearby. - -***** - -## Folders - -Inside `src/lib/score-import` is two folders, `framework/` -and `import-types`. - -### `framework/` - -The framework folder contains the 'moving parts' of the score importing, -such as processing pbs and inserting scores. - -This folder contains the "entry point" for the importing -mechanism, which is discussed in [Score Import Main](./main.md). - -### `import-types/` - -The Import-Types folder contains the specific parsers -and converter functions for a given ImportType. - -You can read more about import types [here](./import-types.md). diff --git a/old-docs/docs/codebase/import/parse-conv.md b/old-docs/docs/codebase/import/parse-conv.md deleted file mode 100644 index faa737e9c..000000000 --- a/old-docs/docs/codebase/import/parse-conv.md +++ /dev/null @@ -1,324 +0,0 @@ -# Parsing and Converting - -Tachi faces an interesting problem with its score importing -code. We could rewrite our entire score importing process -for every possible import method, or we could try to -factor out the common parts of this process. - -The latter is what we've gone for, but it isn't without -its own traps. - -We face the first obvious problem when it comes to actually -"getting" the scores from a source and turning them into -our format. - -Our source needs to be dynamically set, sometimes we might -be drawing scores from a file, sometimes from a HTTP -request body, sometimes from another API! - -Then, we need to convert the data that document gave us -into a format the rest of our code to understand. - -To solve this problem, Tachi uses two processes, -Parsing and Converting. - -## Outline - -As a rough outline, the parser converts data from -any source into an iterable. - -The iterable is then traversed, and the Converter -is called for every element of the iterable. - -The converter function turns the element into something -the rest of the Tachi import code can work with. - -## Parsing - -Parsing is the job of drawing the data from the source into -an **iterable** (The usage of iterable and **NOT** array will be explained later). - -A parser function is intended to be created *outside* of -score-import-main, which means it can be really whatever -it wants to be, and draw data from whatever source it needs -to. - -!!! warning - Parser functions return more than just an iterable, - but in the interest of introducing complexity slowly - we're going to pretend that they only return an - iterable for now. - -### Implementation - -As an example, let's say we had a CSV being sent to us as a file. - -We could write a parser for that as follows: - -```js -// note: awful example code, this is NOT how to parse a CSV! -function ParserFunction(request) { - let csv = request.file; - - return csv.toString().split("\n"); -} -``` - -This takes the provided file, splits it on newlines, and returns -the array. This meets all our criteria, as it returns -an iterable, but we still have problems. - -Firstly, the calling signature for this involves a `request`. Score Import Main doesn't know of any HTTP requests, as it might not even be triggered by one. - -We could solve this by passing a request object, and -also any other context a parser could possibly need, -but that quickly breaks down when we start needing to -fetch from APIs. - -Instead, we define a ParserFunction is defined to be a function that -takes *one* argument, the Import Logger. - -This means that we actually have to use some -closures in order to call a parser. - -```js -function CreateParser(request) { - return (logger) => { - return request.file.toString().split("\n"); - } -} - -const ParserFunction = CreateParser(request); -``` - -Using closures, we can dynamically create the parser function -and enclose any context it needs to use inside of it. - -This approach allows ScoreImportMain to continue knowing -nothing about where the data is coming from, and -avoids passing lots of initial context, bloating up the -score import function. - -The iterable returned by the parser should be in the -most immediately sensible format. - -!!! info - Parser Functions may be asynchronous. - -### Iterable Vs. Array - -Above, we specifically mentioned that the Parser function -returns an *iterable*. There's a subtle difference here -that allows for significant performance gains when getting -data from a paginated API. - -Let's write an example where we retrieve data from an API. - -```js -function CreateParser() { - return async (logger) => { - let page = 1; - - let array = []; - while (true) { - // pretend this returns some scores - - let res = await fetch("example.com?page=" + page).then(r => r.json()); - - array.push(...res.scores); - - if (!res.moreData) { - break; - } - - page++; - } - - return array; - } -} -``` - -It's not bad, but it has some performance issues if the -user has a lot of scores, by creating a massive array -in memory and *then* passing it. - -We can improve this code significantly using generators. - -```js -function CreateParser() { - return async function* (logger) { - let page = 1; - - while (true) { - let res = await fetch("example.com?page=" + page).then(r => r.json()); - - for (const score of res.scores) { - yield score; - } - - if (!res.moreData) { - break; - } - - page++; - } - } -} -``` - -With generators, this code can now yield each score from -the data returned, instead of having to bubble it up in -one large array. - -### Other Returns - -We mentioned above that parsers return more than -just an iterable. - -In practice, a Parser returns four things in an object. Context, the Game this import is for, the Iterable discussed above and a Class Handler. - -#### `context` - -Some import formats require context to be parsed properly. - -The most obvious example is the IIDX E-Amusement CSV format, which does not declare whether the scores are from -single or double play inside the file. - -To properly interpret a score of, say, 1000 on 5.1.1. ANOTHER, we need to have some context about the score. -That is, we need data that isn't part of the 'score'. - -To solve this, parsers return a `context` object which -contains context for the converter function. - -For IIDX E-Amusement, the parser function could interpret -the playtype from user input, and then return it as context. - -#### `game` - -Sometimes, the game an import is for is not statically -known from the Import Type. This means that the parser -will have to return the `game` this import is for rather -than inferring it. - -An example of a format doing this would be the [BATCH MANUAL](foo) format, -which declares what game the import is for in a header. - -#### `classHandler` - -Sometimes, an import may result in the changing of a users' -classes. This may also sometimes be dependent on data that -is part of the import. - -An example of this would be the Fervidex Static import type, -which passes a set of the users scores, and also passes -their Dans. - -Since dans are part of the user's IIDX classes, we need to -take the information from that request and update classes -accordingly. - -The classHandler returned from the parser should be a callable function -that will update the user's classes dependent on this data. - -!!! info - If no class information is dependent on the content - known by the parser function, then `classHandler` - can be set to null, and it will not be called. - -### Final Example - -With all these other things to return, we can -write a simple example of a parser as follows: - -```js -function CreateIIDXFileParser(request) { - return (logger) => { - let csv = request.file; - - let playtype = request.body.playtype; - - if (playtype !== "SP" && playtype !== "DP") { - // todo: throw error - } - - return { - iterable: csv.toString().split("\n"), - game: "iidx", - context: { - playtype, - }, - classHandler: null, - } - } -} -``` - -## Converters - -let's say we have a parser for SDVX that returns: -```js -[{ - score: 9000000, - lamp: "HARD CLEAR", - timestamp: 1623760037 -}, -// -] -``` - -Our converter has to take every element here and -*convert* it into the form the rest of Tachi can -work with. - -Unlike Parser Functions, Converter Functions are static, -that means that they cannot be dynamically constructed -with closures or similar. - -### Arguments - -Converters are called with these four arguments: - -| Property | Type | Description | -| :: | :: | :: | -| `data` | ParserElement | The given element in the parser's iterable. | -| `context` | ParserContext | The context the parser returned. | -| `importType` | [ImportType](./import-types.md) | The import type this import is for. | -| `logger` | Logger | The import logger. | - -### Returns - -Converter functions are expected to return three values -on success. - -- `dryScore` - -A dry score is a 'partial' real Tachi Score format -with certain properties left blank (because they can be -filled elsewhere). - -In short, the Dry Score is all the properties that can -only be derived from the parser's passed data. - -Other properties, like calculated data are filled out -in a score "hydration" process (hence the name Dry Score). - -- `chart` - -The chart this score is for. - -- `song` - -The song this score is for. - -### Throws - -Converters are also expected to fail. -For this, we have a very specific throw format -that should be thrown whenever a specific error has occurred. - -These are called Failures, and a full list of them can be -found [here](./conv-failures.md). - -If a non-failure is thrown, it is logged as an error and the score is ignored (because crashing the entire -import from an unexpected error is a bad idea.) diff --git a/old-docs/docs/codebase/import/parse-ipi.md b/old-docs/docs/codebase/import/parse-ipi.md deleted file mode 100644 index 469a82f4f..000000000 --- a/old-docs/docs/codebase/import/parse-ipi.md +++ /dev/null @@ -1,32 +0,0 @@ -# Parsing Import Processing Info - -The ImportProcessingInfo array returned from our -importing process is unwieldy to work with. We are interested -in what it has to say, though. - -This step converts that array into data we use -in successive score import steps. - -!!! info - Because the logic for this is essentially just one - loop, it does not get its own file in `score-importing/`. - - Instead, it is defined inside `score-import-main.ts`. - -***** - -## Output - -| Property | Type | Description | -| :: | :: | :: | -| `scoreIDs` | Array<string> | The array of scoreIDs imported as a result of this import. | -| `errors` | Array<{ type, message }> | An array of the failed ImportProcessingInfo's Types and Error Messages. -| `chartIDs` | Set<string> | A set of the chartIDs modified by this import. This is a set to ensure that every chartID here is unique. | -| `scorePlaytypeMap` | Record<Playtype, Array<Score>> | All of the score documents returned filtered into Playtype buckets. - -### What's with ScorePlaytypeMap? - -Some imports may import scores from multiple Playtypes. We -frequently want to only refer to the set of scores modified -under a given playtype (For importing a users game:playtype stats, as an example) -so this is a very useful data structure to have. diff --git a/old-docs/docs/codebase/import/pbs.md b/old-docs/docs/codebase/import/pbs.md deleted file mode 100644 index 7d05da7e3..000000000 --- a/old-docs/docs/codebase/import/pbs.md +++ /dev/null @@ -1,59 +0,0 @@ -# Personal Bests - -Tachi has a lot of scenarios where it needs to reference -a users best score alongside their best lamp. - -This is a standard for most arcade games to conjoin the -best aspects of all your scores, so Tachi needs to -replicate that behaviour. - -However, not all games agree on what aspects to join about -scores. Although in most scenarios we will be joining -a user's best lamp with their best score, there are some -games (like IIDX) which have other statistics that need -to be conjoined. - -***** - -## Calculating Personal Bests - -A user is only allowed one personal best per chart, this -allows us to know what personal bests need to be modified -by looking at the set of chartIDs modified from this import. - -We can iterate over that set and recalculate the users -personal best for each chart. - -Firstly, we select the users score on the chart with the -highest percent, then we select the users score on the -chart with the highest lampIndex. - -We can then join the relevant properties of this -into a PBScore, where the best parts of the lampPB -are unioned with the best part of the scorePB. - -!!! info - A ScorePB refers to a user's best Percent/Score on a chart. - - A PBScore refers to the aforementioned conjoined score - document. - -## Game Specific Things - -Some games require specific conjoining code. The below games -have said exceptional behaviour. - -### SDVX, USC - -VF5 and VF6 depends on the users best lamp and their best score. - -That is, you cannot just select the larger volforce from -the two scores, as HC 9m -> NC 9.1M should have the -volforce of HC 9.1M. - -### IIDX, BMS - -IIDX and BMS have BP. This number is the amount of bads -plus the amount of poors a player made. The lowest non-null -value for this should be selected as that property for the -PBScore. diff --git a/old-docs/docs/codebase/import/quests.md b/old-docs/docs/codebase/import/quests.md deleted file mode 100644 index f441f77f8..000000000 --- a/old-docs/docs/codebase/import/quests.md +++ /dev/null @@ -1,20 +0,0 @@ -# Updating Quests - -We update quests by looking at the set of modified -goalIDs, and check the user's assigned quests to -get those that are affected. - -***** - -## Returns - -We evaluate every quest that contain a goal that has just had it's status change. -For each one we create a bulkwrite operation to update the user's quest -progress. - -If the user has newly achieved a quest, a Webhook Event -is emitted, which could be hooked into by our Discord Bot. - -If the progress has changed at all, the data is -pushed to an array which is then returned. This is -attached onto the Import Document. diff --git a/old-docs/docs/codebase/import/sessions.md b/old-docs/docs/codebase/import/sessions.md deleted file mode 100644 index 27f6b8b0c..000000000 --- a/old-docs/docs/codebase/import/sessions.md +++ /dev/null @@ -1,55 +0,0 @@ -# Sessions - -This page documents how Sessions are constructed. -For a humanised explaination of sessions, see -[this page](../../wiki/features.md#sessions). - -***** - -## Creating New Sessions - -Scores are sorted on the time they were achieved. Scores -without timestamps are discarded from any session processing. - -Scores are then grouped into buckets of two hours, in pseudocode: - -```ts -let lastTimestamp = 0; - -for (score of scores) { - if (score.timestamp > lastTimestamp + TWO_HOURS) { - CloseBucket(); - CreateNewBucketWithThisScore(); - } - else { - AppendToBucket(); - } - - lastTimestamp = score.timestamp; -} -``` - -This means that if there was more than two hours between -any two successive scores, the session is marked as terminated -and a new bucket of scores is created. - -Once we have gotten all the scores we -can create a session from them. We need to generate a random -name (we have some stuff in `src/datasets` for this). - -We also need to calculate statistics for this session, -this is dependent on the game + playtype being used. - -## Appending To Sessions - -If a score within 2 hours of an existing session, -then that score is appended to the session. - -!!! bug - Sessions do not currently conjoin if a user was to - get a score between two sessions such that - there was now less than two hours between the first - sessions last score and the second sessions first score. - - This is so difficult to properly resolve that Tachi simply - makes no attempt to stop it. diff --git a/old-docs/docs/codebase/import/ugs.md b/old-docs/docs/codebase/import/ugs.md deleted file mode 100644 index 663d37cad..000000000 --- a/old-docs/docs/codebase/import/ugs.md +++ /dev/null @@ -1,116 +0,0 @@ -# User Game Stats - -A user has overarching statistics for a game. - -This part of the score importing process updates those -overarching statistics, such as their profile rating -and their classes. - -!!! note - If a user has never played this game + playtype - combination before, a new user game stats - object is saved to the database as a result - of this update. - -***** - -## Format - -A User Game Stats object looks like this: -```ts -{ - userID: string; - game: "iidx" | "bms" // ... so on - playtype: "SP" | "DP" // ... the set of playtypes this game supports. - // A set of continuous statistics about a user. - ratings: { - // A record of numbers with keys determined - // by the game + playtype combination. - // such as: - VF6: number; - // for SDVX and USC. - }, - // A set of discrete statistics about a user. - classes: { - // This typically contains things like dan ranks - // or skill divisions, such as: - dan: 14, - // for IIDX, or - skillColour: 19 - // for gitadora. - - // Note that instead of remembering each number - // for each class, they are defined as constants - // in common/src/constants/game.ts - } -} -``` - -## Ratings - -Ratings are calculated for the given Game + Playtype combination. - -Different combinations will have different statistics, -Gitadora will have a profile skill level, whereas SDVX -would use Profile Volforce. - -All the rating functions for a game are declared -in `src/lib/score-import/framework/user-game-stats/rating.ts`. - -## Classes - -There are two types of classes in Tachi. Static classes -are classes that can always be derived from the data around -them. Things like this are typically discrete buckets -for continuous data, such as Skill Colours in GITADORA. - -The other type of classes are external classes. These -are things like Dans, where the information cannot be -derived from any other data around it, and instead must -be explicitly told to change. - -### Class Handlers - -You may recall that in [Parsers and Converters](./parse-conv.md) it was documented that parsers can return a -ClassHandler. The ClassHandler is intended to handle those -explicit changes. - -For example, let's say we have an import type that tells us: -```js -{ - scores: [{score: 1000, songID: 1, diff: "spa"}], - sp_class: "kaiden" -} -``` - -We could return a classHandler from our parser function -that encloses this updated information, such as: -```ts -function CreateClassHandler(spClass: number): ClassHandler { - return (../../* classHandlers have some args but we dont need them for this example */) => { - return { - dan: spClass - } - } -} -``` - -This returned classHandler is called with 5 arguments -and is expected to return a partial record of the users -classes. This is then merged with the static classes -and returned as the users classes. - -### Static Class Handlers - -Static class handlers are built in, and always called -when a user's game stats is updated. - -## Deltas - -Once a user's classes have been calculated, they are diffed -against the current user's stats. If they have been -increased, then a redis message is sent out, and things -like the Tachi discord bot may choose to echo this -in the discord. - -The deltas are returned to be part of the ImportDocument. \ No newline at end of file diff --git a/old-docs/docs/codebase/index.md b/old-docs/docs/codebase/index.md deleted file mode 100644 index 0628a4803..000000000 --- a/old-docs/docs/codebase/index.md +++ /dev/null @@ -1,43 +0,0 @@ -# Codebase Overview - -This part of the documentation is for the [Tachi-Server](https://github.com/zkldi/Tachi/tree/main/server) codebase. - -## Codebase Documentation vs. Code Documentation - -This is documentation for the **Codebase**. **NOT** documentation for the code. - -The distinction is because we aren't writing a library here - there's no need to document function -signatures or what function calls are meant to do. That can all be done inline because no other -projects depend on our function calls! - -This documentation is more meta-level. Why things are in certain folders, what certain enums -correspond to, how `thing` works, etc. - -## Repos and Licenses - -Tachi is a monorepo, and is made up of many projects. These are: - -- `client/`, Which is a React frontend for Tachi. - -The client and the server are fairly decoupled. Someone could trivially create their own frontend client for Tachi. - -- `server/`, Which is an Express-Typescript backend for Tachi. - -This contains all of our API calls, and interfaces with our database, and powers the actual score import engine. - -- `seeds/`, Which is a git-tracked set of data to be synced with Tachi. - -**This is the source of truth for the songs, charts, and more on the site!** -By submitting PRs to this, you can fix bugs on the website, add new charts, and more. - -- `bot/`, Which is a discord bot frontend for Tachi. - -- `common/`, Which contains common types, utils and functions shared between all other packages. - -This is also published to NPM when it hits production. - -- `docs/`, Which contains Tachi documentation. - -- `sieglinde/`, Which contains our BMS/PMS analysis functions. - -Of these, `server/` and `client/` are licensed under the AGPL3. The `seeds/` are licensed under the unlicense, and everything else is MIT. diff --git a/old-docs/docs/codebase/infrastructure/api-clients.md b/old-docs/docs/codebase/infrastructure/api-clients.md deleted file mode 100644 index 92ba5868f..000000000 --- a/old-docs/docs/codebase/infrastructure/api-clients.md +++ /dev/null @@ -1,15 +0,0 @@ -# Tachi API Clients - -Tachi lets users create API Keys, such that programs can interact with their account on their behalf. These API Keys have permissions and other things. You can read about that [here](../../api/auth.md). - -However, it's common for another programmer to want certain permissions for their client. For example, if I was making a score import hook for Tachi, I would need the `score_submit` permission. - -We could ask users to manually create an API Key, copy it into a config file, and hope that they get the permissions right, or we could set up a nice flow. - -## OAuth2 Flow - -Tachi fully supports OAuth2. When you create a Tachi API Client, you can set a `redirectUri`, which is where your OAuth2 flow will go. You can read about it [here](./oauth2.md). - -## Client File Flow - -Alternatively, if you're just looking for a nice UI for users to create an API Key with the right permissions, check out the [Client File Flow](./file-flow.md). diff --git a/old-docs/docs/codebase/infrastructure/branches.md b/old-docs/docs/codebase/infrastructure/branches.md deleted file mode 100644 index 707f3e51c..000000000 --- a/old-docs/docs/codebase/infrastructure/branches.md +++ /dev/null @@ -1,7 +0,0 @@ -# Branching Model - -`main` is the current release version of `Tachi`, and is automatically deployed into production. - -## How should I PR? - -You should submit your PRs for `main`. diff --git a/old-docs/docs/codebase/infrastructure/database-seeds.md b/old-docs/docs/codebase/infrastructure/database-seeds.md deleted file mode 100644 index c98e325f8..000000000 --- a/old-docs/docs/codebase/infrastructure/database-seeds.md +++ /dev/null @@ -1,24 +0,0 @@ -# Database Seeds - -Tachi tracks the contents of its songs and charts in something called the [Database Seeds](https://github.com/zkldi/Tachi/tree/main/seeds). - -The databases in question aren't (normally) altered by the server code. We essentially overload git and its CI tools to version control parts of our database. - -## What's in the seeds? - -The seeds contain all the [SongDocument](../../schemas/song.md)s and [ChartDocument](../../schemas/chart.md)s for all of the games supported by Tachi. - -They also include all Folder Documents, Table Documents and BMS Course Documents. - -## Synchronisation - -When pushes are made to `main`, our running production servers will automatically update to that new bit of data. - -## Why bother? - -Making all of this data public and easily accessible is one of the best ways to help out other people making rhythm game tools. - -The database seeds are an invaluable resource for other programmers who don't want to scrape data themselves. - -It's also very useful for Tachi. Having charts on a public git repo allows anyone to trivially PR things they know to be wrong. -This level of openness to contribution is great, and has resulted in a lot of good work being done by the community. diff --git a/old-docs/docs/codebase/infrastructure/file-flow.md b/old-docs/docs/codebase/infrastructure/file-flow.md deleted file mode 100644 index ab5207855..000000000 --- a/old-docs/docs/codebase/infrastructure/file-flow.md +++ /dev/null @@ -1,44 +0,0 @@ -# Client File Flow - -While we have an [OAuth2 Flow](./oauth2.md), that requires another webserver. -What if you just want an API key to throw inside a config file? This is a -common use case. - -For this, we have the Client File Flow. This flow is entirely done on our -site, and results in the user downloading a file, or copying a string. - -## Outline - -!!! note - This documentation uses `boku.tachi.ac` as the example site. You should - replace this with the instance of Tachi you're pointing against, if it - is different. - -- You navigate the user to `https://boku.tachi.ac/client-file-flow/YOUR_CLIENT_ID`. -- They are asked if they want to create an API Key for your client. -- If they select yes, an API Key is created for your client, and depending on your client parameters, they get it. - - -## Download Format - -When you create a Tachi API Client, you can select the `File Template` parameter. This will change the format of the key given to the user. - -For example, Let's say you wanted the user to download a `.json` file with -your token. - -You could set a template of something like: - -```json -{ - "tachi-api-token": "%%TACHI_KEY%%", - "someOtherField": "foo" -} -``` - -If the `File Template` is not set, it is just output normally, without any templating. - -The first instance of `%%TACHI_KEY%%` will be replaced with the generated API key. - -The other file parameter you control is the `File Name`. If this is set, the user will be presented with a button that will download the above content. - -If it is not set, the contents of the template are shown in browser, and the user will have to copy-paste the API Key. diff --git a/old-docs/docs/codebase/infrastructure/logging.md b/old-docs/docs/codebase/infrastructure/logging.md deleted file mode 100644 index b9b5740d0..000000000 --- a/old-docs/docs/codebase/infrastructure/logging.md +++ /dev/null @@ -1,185 +0,0 @@ -# Logging - -As mentioned in the [Toolchain](./toolchain), we use -WinstonJS for logging. We use a slightly modified setup -of winston, but the same basic logging principles apply. - -!!! note -If you like my defaults for logging, they can be quickly -invoked with the [Mei](https://github.com/zkldi/mei) wrapper. - ---- - -## Log Levels - -Tachi uses the following log levels, listed in order of -severity. - -### Crit - -```ts -logger.crit("foo"); -``` - -`crit` or Critical is the most severe log level in tachi. - -Calling this means **the process must now completely exit**. - -This fail state is triggered in things like not being able -to connect to a Mongo or Redis instance, where the application -absolutely cannot function anymore and should quit immediately. - -### Severe - -```ts -logger.severe("foo"); -``` - -`severe` is the second most severe log level in tachi. - -Calling this means an error has occurred, and that error implies -it will apply to multiple parts of the codebase. - -This log level is used with things like a Song-Chart -desync -- A chart must have a song as a parent, but if it -doesn't, that's a severe-level error. - -Think of this like an error with wider-reaching implications. - -### Error - -```ts -logger.error("foo"); -``` - -`error` is the third most severe log level in tachi. - -Calling this means an error has occurred, but the impact of -it is limited to the function or general area it was called in. - -Errors may be recovered from or ignored by the code, but generally that should be reserved for `warn`. - -### Warn - -```ts -logger.warn("foo"); -``` - -`warn` indicates that something has gone wrong, but is safely -recoverable from, such as a mathematical function being given NaN unexpectedly, and just returning 0. - -`warn` calls **MUST** be recoverable from, and must not -imply severe damage to the global state of the application. - -### Info - -```ts -logger.info("foo"); -``` - -!!! info -This is the default [LOG_LEVEL](./config) for tachi. - - This means that all the levels below this are - not displayed to the console or stored. - -`info` indicates that something notable has happened. This -should not be used for any errors - instead, it should be -used for notable events, such as a new user signing up. - -### Verbose - -```ts -logger.verbose("foo"); -``` - -`verbose` indicates that something has happened. This is -used for debugging, and is typically only enabled in dev -to find out what has gone wrong. - -### Debug - -```ts -logger.debug("foo"); -``` - -`debug` is the least notable logging level. This is used -exclusively for debugging, and logs typically uninteresting -things like Captcha Requests being sent, or a single score was imported. - -## Logger Usage - -In `src/lib/logger/logger.ts` we define a wrapper around winston -for our logging needs. We use two functions for this. - -The first function is `CreateLogCtx`. This spawns an -instance of the logger with "context". - -This context allows us to keep track of common information -for the logger. - -For file-level logging, you should do: - -```ts -import CreateLogCtx from "~src/lib/logger/logger"; -const logger = CreateLogCtx(__filename); - -logger.info("foo"); -// [src/file.ts] INFO: foo -``` - -!!! info -CreateLogCtx is short for Create Log Context. - -This will spawn an instance of the logger with the context -of the current filename. - -For more specific logging, you should create a logger -and pass it around as an argument to a function. - -This is used in `src/lib/score-import`, as we create a -logger with the user's name and import type as "context". - -```ts -const logger = CreateLogCtx(`${username} ${userID}`); - -logger.info("foo"); -// [zkldi INFO: foo - -SomeOtherFunction(argument1, argument2, logger); -``` - -!!! info -Logger should be the last argument for a function that -takes a logger. - - The only exception to this is if it uses our `fetch` API, - which **MUST** always be the last call. - -If we have an existing logger and want to append context, -we can do that with the `AppendLogCtx` function. - -```ts -const logger = CreateLogCtx("foo"); - -logger.info("hello!"); -// [foo] INFO: hello! - -const logger2 = AppendLogCtx("bar", logger); - -logger2.info("hello!"); -// [foo | bar] INFO: hello! -``` - -## Log Files - -Logs are saved to `${pwd}/logs` in two files. The first -file logs everything above `LOG_LEVEL`. The second file -logs `error` and above calls. - -!!! bug -Unintentional behaviour occurs here if LOG_LEVEL is -above `error` - the main file will not log errors, -but the error file will log errors regardless. - - This may be fixed at some point, but is fairly low priority. diff --git a/old-docs/docs/codebase/infrastructure/oauth2.md b/old-docs/docs/codebase/infrastructure/oauth2.md deleted file mode 100644 index 36512d279..000000000 --- a/old-docs/docs/codebase/infrastructure/oauth2.md +++ /dev/null @@ -1,59 +0,0 @@ -# OAuth2 Flow - -`tachi-server` has a functional implementation of OAuth2, which lets people create clients to request APIKeys from users. - -This is the preferred way of handling authorisation between web applications, as it can be done without the user ever really having to deal with their API keys! - -!!! note - The below steps assume some familiarity with OAuth2. If you are not familiar, I find [this](https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2) to be the best explaination. - -We use an *almost* standard OAuth2 flow, but with the added react-app caveat of POSTing for an intermediate token. If that makes sense to you, you don't need to read this page! - -## Process - -In this scenario, we have two users, user A, who is making a service that integrates with Tachi, and user B, who wants to link integrate their service with their tachi profile. - -!!! info - In this example we will use `boku.tachi.ac` as the Tachi site name. - -- An OAuth2 client is created by user A. - -This client will have the following properties. - -```json -{ - "clientID": "ABCDEF", // this is a random string in practice. - "clientSecret": "GHIJKL", // this is another random string. - "name": "Epic Games", - "author": 1, - "redirectUri": "https://epicgames.example.com/tachi-auth-callback", - "requestedPermissions": ["customise_score"], - "apiKeyFormat": null, // These are for the Client File Flow. - "apiKeyFilename": null, // More on that later. -} -``` - -- User B wants to link their account to this service, and must click on an auth link on Tachi. - -In the `tachi-client`, this link is `https://boku.tachi.ac/oauth/request-auth?clientID={clientID}` - -EpicGames would show this link to the user, and they would click it. - -While on Tachi, they are presented with the option to accept linking with `clientID`, or decline it. - -- If they accept, `tachi-client` will make a POST request to `https://boku.tachi.ac/api/v1/oauth/create-code`, which will create an intermediate authorisation code. - -The user and this authorisation code are then taken to the `redirectUri` defined in the client. In our case, this means they are taken to -`https://epicgames.example.com/tachi-auth-callback?code=SOME_INTERMEDIATE_TOKEN` - -This token **IS NOT** an API Key, but rather an intermediate value that needs to then be converted up. - -EpicGames would now have to take this token and make a POST request to `https://boku.tachi.ac/api/v1/oauth/token`, with their client secret and the intermediate token. - -This POST request will then return the API Key EpicGames wants! The user can then be redirected by EpicGames to wherever they want. - -## The application I want to integrate isn't a web app! - -That's fine. Infact, it's very common for us to integrate with applications -that just want an API token inside a JSON file. For that, we have the -[Client File Flow](./file-flow.md) \ No newline at end of file diff --git a/old-docs/docs/codebase/setup/config.md b/old-docs/docs/codebase/setup/config.md deleted file mode 100644 index e01d5122f..000000000 --- a/old-docs/docs/codebase/setup/config.md +++ /dev/null @@ -1,405 +0,0 @@ -# Configuration Info - -The codebase uses a file called `conf.json5` to handle -various configurable options. It also reads some things from the process environment. - -## What is JSON5? - -JSON5 is an extension of JSON which is better suited -for configuration files. - -You can read more about it [here](https://json5.org/), but -the main benefits for us are as follows: - -- Comments -- No Quoting properties -- Trailing Commas - -## Example Config File - -```js -{ - MONGO_DATABASE_NAME: "testingdb", - CAPTCHA_SECRET_KEY: "something_secret", - SESSION_SECRET: "something_secret", - FLO_API_URL: "https://flo.example.com", - EAG_API_URL: "https://eag.example.com", - MIN_API_URL: "https://min.example.com", - FLO_OAUTH2_INFO: { - CLIENT_ID: "DUMMY_CLIENT_ID", - CLIENT_SECRET: "DUMMY_CLIENT_SECRET", - REDIRECT_URI: "https://example.com", - }, - EAG_OAUTH2_INFO: { - CLIENT_ID: "DUMMY_CLIENT_ID", - CLIENT_SECRET: "DUMMY_CLIENT_SECRET", - REDIRECT_URI: "https://example.com", - }, - ARC_AUTH_TOKEN: "unused", - OUR_URL: "https://example.com", - INVITE_CODE_CONFIG: { - BATCH_SIZE: 2, - INVITE_CAP: 100, - BETA_USER_BONUS: 5, - }, - CDN_CONFIG: { - WEB_LOCATION: "http://localhost:9000/tachi-public", - SAVE_LOCATION: { - TYPE: "S3_BUCKET", - ENDPOINT: "http://tachi-s3:9000", - ACCESS_KEY_ID: "minio", - SECRET_ACCESS_KEY: "password", - BUCKET: "tachi-public", - REGION: "us-east-1", - }, - }, - TACHI_CONFIG: { - TYPE: "omni", - NAME: "Tachi Example Config", - GAMES: [ - "iidx", - "museca", - "maimai", - "sdvx", - "ddr", - "bms", - "chunithm", - "usc", - ], - IMPORT_TYPES: [ - "file/eamusement-iidx-csv", - "file/batch-manual", - "file/solid-state-squad", - "file/pli-iidx-csv", - "ir/direct-manual", - "ir/barbatos", - "ir/fervidex", - "ir/fervidex-static", - "ir/beatoraja", - "ir/usc", - "ir/kshook-sv3c", - "api/eag-iidx", - "api/eag-sdvx", - "api/flo-iidx", - "api/flo-sdvx", - "api/min-sdvx", - ], - }, - LOGGER_CONFIG: { - FILE: false, - CONSOLE: true, - LOG_LEVEL: "info", - }, -} -``` - -!!! warning - **DO NOT BLINDLY COPY THIS CONFIGURATION FILE!** - - Seriously, The `SESSION_SECRET` token MUST not be - public. - -## JSON5 Properties - -All properties are required unless called optional or they have a default. - -### MONGO_DATABASE_NAME - -- Type: String - -What collection to use for your database. - -### CAPTCHA_SECRET_KEY - -- Type: String - -Google gives us a Captcha Secret Key in order for Captcha -to work on our site. - -### SESSION_SECRET - -- Type: String - -This key is used to encrypt Session Cookies. - -!!! warning - If this key is figured out, anyone can log in as - anyone. - - Make sure this is an appropriately long string - generated from a *cryptographically secure* source. - That is, do not just mash your keyboard. - - You can generate secure random strings with something - like [KeePass](https://keepass.info/). - -### FLO_API_URL, EAG_API_URL, MIN_API_URL - -- Type: String - -The URL for the `FLO, EAG or MIN` services. This is used for integration -with the Kamaitachi version of Tachi. - -### FLO/MIN/EAG_OAUTH2_INFO - -- Type: OAuth2Info (Optional) - -If present, these define our OAuth2 Client data for interacting with these services. These are like this like this: -```js -{ - FLO_OAUTH2_INFO: { - CLIENT_ID: "OUR_CLIENT_ID", - CLIENT_SECRET: "OUR_CLIENT_SECRET", - REDIRECT_URI: "https://tachi.example.com" - } -} -``` - -!!! warning - The server will throw a fatal error if you have OAUTH2_INFO set for one service, but not an API_URL. - - Maybe a better solution would be to have the API_URL inside the OAUTH2_INFO. Ah well. - -### CLIENT_DEV_SERVER - -- Type: String -- Default: Null - -If present, and a string, this points to the local dev server for a react app. Having this -option set results in CORS being enabled for *that* specific URL. This is useful for local -development, but should not be used in production. - -### RATE_LIMIT - -- Type: Positive Integer -- Default: 500 - -Determines how many requests an APIKey OR IP can make every minute. - -The default is set to the very generous 500, as it's possible for users to accidentally hit 100 requests/min by refreshing very fast. - -### OAUTH_CLIENT_CAP - -- Type: Positive Integer -- Default: 15 - -The amount of OAuth2Clients one user can create at any one time. Defaults to 15. - -### OPTIONS_ALWAYS_SUCCEEDS - -- Type: Boolean -- Default: false - -If true, all `OPTIONS` requests to the server will return `200`, no matter what. This is a hack used for development CORS. - -### BEATORAJA_QUEUE_SIZE - -- Type: Integer -- Default: 3 - -How many unique players have to have played a chart on the beatoraja IR for it to be de-orphaned. - -!!! note - Note that LR2 scores or database imports do not count towards this total. - -!!! warning - The lowest legal value for this field is 2. - -### OUR_URL - -- Type: String - -Where *this* server is hosted. This is used to -provide callback URLs inside emails. - -### EMAIL_CONFIG - -- Type: EMAIL_CONFIG (required) - -SMTP is always configured. Set: - -- `TACHI_EMAIL_FROM` - `From` header (must match a verified sender when using Postmark). -- `TACHI_EMAIL_HOST`, `TACHI_EMAIL_PORT`, `TACHI_EMAIL_SECURE` (`true` / `false`). -- Optionally `TACHI_EMAIL_AUTH_USER` / `TACHI_EMAIL_AUTH_PASS` for SMTP auth (local Mailpit - typically needs none). -- For Postmark, use host `smtp.postmarkapp.com` (usually port `587` with `TACHI_EMAIL_SECURE=false`) - and set either auth field to your server API token (both username and password are the token for - Postmark SMTP). - -`TRANSPORT_OPS` is derived from these variables and passed to Nodemailer. - -```ts -interface EMAIL_CONFIG { - FROM: string; - TRANSPORT_OPS: any; -} -``` - -### INVITE_CODE_CONFIG - -- Type: INVITE_CODE_CONFIG (Optional) - -Configures how invites are created by Tachi. -If not present, the site will not require invite codes at all. - -`BATCH_SIZE` determines how many invites to create every month, -`INVITE_CAP` determines how many invites a user can have -- ever. -`BETA_USER_BONUS` determines how many additional invites users of Kamaitachi 1 have out of the box. - -```ts -interface INVITE_CODE_CONFIG: { - BATCH_SIZE: integer; - INVITE_CAP: integer; - BETA_USER_BONUS: integer; -}; -``` - -### TACHI_INVITE_ADMIN_INITIAL_INVITE_CODE - -- Type: String (Optional, environment variable only) - -A one-time bootstrap invite code for first-time instance setup. When `INVITE_CODE_CONFIG` is -configured, new instances have a chicken-and-egg problem: registration requires an invite code, -but invite codes can only be created by an existing user. - -Set this environment variable to a long, random secret. The first person to register with this -code - while the `account` table is still empty - becomes the site admin. Once the first admin -exists, the code is no longer accepted. - -### TACHI_CONFIG - -- Type: TACHI_CONFIG - -Configures what the Tachi Server instance supports, and what it's generally doing. - -```ts -interface TACHI_CONFIG: { - NAME: string; - TYPE: "kamai" | "boku" | "omni"; - GAMES: Game[]; - IMPORT_TYPES: ImportTypes[]; -} -``` - -#### NAME - -The name of the server. This is reported at `/api/v1/status`. - -#### TYPE - -What type of tachi-server this is. `kamai` will enable Kamaitachi Only routes, `boku` will enable -Bokutachi only routes, and `omni` will enable both. - -#### GAMES - -What games are supported by this server. For more information, see [Games](../../wiki/games.md). - -#### IMPORT_TYPES - -What importTypes are legal for this server. For more information, see [Import Types](../import/import-types.md). - -### LOGGER_CONFIG - -- Type: LOGGER_CONFIG (Optional) - -Configures how logs are sent around in Tachi. - -```ts -interface LOGGER_CONFIG: { - LOG_LEVEL: "debug" | "verbose" | "info" | "warn" | "error" | "severe" | "crit"; - CONSOLE: boolean; - FILE: boolean; - SEQ_API_KEY: string | undefined; - DISCORD?: { - WEBHOOK_URL: string; - WHO_TO_TAG: string[]; - }; -} -``` - -#### LOG_LEVEL - -What log level to use out of the box. If no LOGGER_CONFIG is provided, defaults to "info". - -#### CONSOLE - -Whether to log to the console or not. If no LOGGER_CONFIG is provided, defaults to true. - -#### FILE - -Whether to log to a log file or not. If no LOGGER_CONFIG is provided, defaults to false. - -#### SEQ_API_KEY - -(Optional) - -If present, this is an API Key for logging to a Seq server, which is set in the process environment. - -If no LOGGER_CONFIG is provided, this is not set. - -#### DISCORD - -(Optional) - -If present, this configures a discord `WEBHOOK_URL` to log info or higher messages to. -`WHO_TO_TAG` is an array of userIDs to tag in the case of a `severe` or `fatal` error. - -If no LOGGER_CONFIG is provided, this is not set. - -### CDN_CONFIG - -- Type: CDN_CONFIG - -Configures the CDN for the Tachi Server. Files are always stored in an S3-compatible bucket (AWS S3, Backblaze, MinIO, etc.). - -For local development with `docker-compose-dev.yml`, run the `tachi-s3` MinIO service and point `SAVE_LOCATION.ENDPOINT` at it (from the `tachi-dev` container, `http://tachi-s3:9000`). Use a `WEB_LOCATION` URL that browsers can load (for example `http://localhost:9000/` when MinIO’s API port is published to the host). - -```ts -interface CDN_CONFIG: { - WEB_LOCATION: string; - SAVE_LOCATION: { - TYPE: "S3_BUCKET"; - ENDPOINT: string; - ACCESS_KEY_ID: string; - SECRET_ACCESS_KEY: string; - BUCKET: string; - KEY_PREFIX?: string; - REGION?: string; - }; -} -``` - -#### WEB_LOCATION - -Configures a URL to redirect users to when returning CDN contents. This could be something like `https://cdn.boku.tachi.ac` or a path-style URL to your bucket on MinIO. - -#### SAVE_LOCATION - -Configures the S3-compatible API endpoint and bucket used for uploads (profile pictures, score import payloads, etc.). - -## Process Environment - -The process environment also contains necessary things for functional Tachi Server running. - -!!! info - These variables are put into the process environment instead of the conf.json5 file because - they're easier to change between docker instances. This Helps us scale and deploy. - -### PORT - -The PORT environment variable specifies what port our express server should listen to. -If not set, this will log a warning and default to 8080. - -### MONGO_URL - -Where our mongoDB instance is. This would be `localhost:27017` if hosting on the same box. -If not set, this will terminate the process with a critical error. - -### SEQ_URL - -Where a Seq instance is. If no `LOGGER_CONFIG.SEQ_API_KEY` was defined, this is fine. If it was, -this will log a warning, and nothing will be sent to Seq. - -### NODE_ENV - -Expected to be either "dev", "production", "staging" or "test". If not set, this will terminate the process. diff --git a/old-docs/docs/codebase/structure/filesystem.md b/old-docs/docs/codebase/structure/filesystem.md deleted file mode 100644 index ec82ba3e4..000000000 --- a/old-docs/docs/codebase/structure/filesystem.md +++ /dev/null @@ -1,130 +0,0 @@ -# File/Folder Organisation - -`tachi-server` has a specific setup of files and folders -to ensure that code is at where it's most sensible. - -!!! note - This documentation is a rough guide for where - to place files if you are writing a new file, - or where to look for certain functionality. - - It is not a comprehensive tutorial for every file - in the repo, as that would be a pain to keep updated. - -***** - -## Top Level - -All of these are at the root level of the project. - -### `/src` - -All of the server TypeScript code goes here. - -### `/js` - -!!! info - This folder is gitignored. - -When compiled, `tsc` will output the JS code here. - -### `/scripts` - -Various scripts for interacting with `tachi-server`, such -as single-use scripts for importing some data, or -frequently used scripts such as updating BMS tables. - -## TypeScript Source Code - -All of these are inside `/src`. - -### `/datasets` - -Some of `tachi-server`'s code interacts with datasets that -aren't worth putting into MongoDB, such as splash text. - -This is mainly for things where we want to randomly select -from the list, and not perform any serious lookups - which -is why it's a good fit for splash text/automatic session names. - -!!! info - Selecting a random element from an entire collection - in MongoDB is relatively expensive, and would quadruple - the time an import takes. - -!!! warning - TypeScript does not support copying over non-code files. - - You can use `cp` in post to move files around, or - place the data in memory, either is fine. - -### `/external` - -Code relating to the "external" applications for `tachi-server`, -such as MongoDB and Redis. - -### `/lib` - -Sets of code for `tachi-server` functionality. This is the -main important part of the codebase for handling things -like score imports, logging, and more. - -### `/server` - -This contains the express application that `tachi-server` -uses in order to be a server. - -This contains our API, IR implementations and a way of -serving our PWA. - -### `/test-utils` - -Tachi's tests need mocks and some specialised code in order -to work well. This folder contains all of those things. - -!!! warning - **NOTHING** from this folder should be ran in production. - -### `/utils` - -Small utilities for interacting with Tachi, such as -functions that retrieve a user given certain params. - -This also contains utilities for handling song/chart -database lookups - such as looking up on BMS hash. - -## Express Server - -All of the below folders are under `/src/server`. - -As mentioned above, Tachi stores the routing for our -APIs and IR implementations here. - -### `/middleware` - -This contains the middleware we use for the server, -such as authentication middleware and such. - -### `/router` - -This contains the actual 'routes' for our server. - -The folders here **MUST** be 1:1 with the endpoints -on the server. For example, the implementation of - -``` -https://boku.tachi.ac/api/v1/foo/bar -``` - -**MUST** be found at `src/server/router/api/v1/foo/bar/router.ts` - -### Router Files - -The only files allowed to declare endpoints are `router.ts` files. - -This allows us to separate functionality from API structure -in cases where an API call needs to do a lot of things. - -## Test Files - -This documentation has been moved to [its own page](./testing.md)! diff --git a/old-docs/docs/codebase/structure/style.md b/old-docs/docs/codebase/structure/style.md deleted file mode 100644 index 18d0e35ee..000000000 --- a/old-docs/docs/codebase/structure/style.md +++ /dev/null @@ -1,10 +0,0 @@ -# Style - -For style, we use a custom tool called [Cadence](https://github.com/CadenceJS/Cadence). - -This is effectively a huge ESLint config with everything I care about enabled. - -It's worth noting that this is an *extremely strict* linter. You are **expected** to have "Format on Save" turned on, in order to use this linter properly. - -!!! info - You can run ESLint in the repo any time with `pnpm lint`. diff --git a/old-docs/docs/codebase/structure/testing.md b/old-docs/docs/codebase/structure/testing.md deleted file mode 100644 index c4256f976..000000000 --- a/old-docs/docs/codebase/structure/testing.md +++ /dev/null @@ -1,58 +0,0 @@ -# Tests - -Tachi makes extensive use of tests to ensure code -is of high quality when its released. - -***** - -## Running Tests - -Tests are ran with [node-tap](https://node-tap.org). - -You can run the server test suite with the following script: - -``` -pnpm test -``` - -This will execute every test, and also perform coverage -analysis. - -!!! bug - Use the workspace Vitest entrypoints (`bun test`, `just test-typescript`, …) rather than running `node` - directly on `.ts` files. Bun invokes Vitest without a separate transpiler for day-to-day runs. - -## Writing Tests - -Tests should be located in the same folder as the file they're testing, and tests should only ever test -exports from one file at a time. - -Tests should call things like `ResetDBState` and `CloseAllConnections` as lifecycle hooks to ensure -the file exits. - -Tests should use the extension `.test.ts`, and keep -the same filename as the file they are testing. - -## Coverage - -Coverage should be kept above 80%. New code should be tested. - -Pull Requests will be rejected if they contain significant -changes that are untested! - -## Single Process TAP - -Since we don't mock our MongoDB install out, we run a real instance of Mongo for our tests, and run against it. - -TAP runs every test file in isolation. This is a good idea normally, as it means state is never shared across files, and nothing bad is generally going to happen. - -*However*, it takes around 2 seconds to connect to the MongoDB server when a new test file is started. These 2 seconds add up over the course of a ~1500 test file suite, and result in tests taking over 15-20 minutes. - -To get around this, we use a Single Process TAP hack, which rolls all of our test files up into one test file. - -The hack part here is **not** an understatement, and it is genuinely rather dirty. **BUT**, it runs in ~40-50 seconds, works the same for coverage, and can just generally be ignored as an abstraction layer. - -As a downside, this makes error messages *way* more cryptic, but for a 20x performance gain, it can be lived with. - -!!! warning - If you are getting failures like "Child test left in suite", one of your test files is *crashing* the entire process, leaving all other tests just dangling. diff --git a/old-docs/docs/contributing/components.md b/old-docs/docs/contributing/components.md deleted file mode 100644 index ab6e91807..000000000 --- a/old-docs/docs/contributing/components.md +++ /dev/null @@ -1,85 +0,0 @@ -# Contribution Guides - -The Tachi repository that you just set up is made up of multiple "components". - -All of them have their own things going on, so this page has all the guides for each specific component. - -## What can I contribute to? - -In order of difficulty, here are the components of Tachi you can contribute to! - -All of these sections summarise a part of Tachi, and end with a link to a guide you can use to -contribute to it. - -### Issue Reports - -You can report issues on the [GitHub](https://github.com/zkldi/Tachi) repository. This requires -_absolutely no programming knowledge_ on your part. All you have to do is write up a nice summary -of the bug. - -!!! note -Although they're called GitHub _issues_, they're actually used for tracking anything. If you've -came up with a cool feature idea, send it over as an issue! `zk` will read and Triage them. - -For more information, read our [Issue Reporting Guide](./components/issues.md). - -### Documentation - -We store our documentation as a series of markdown files in the [Main Repository](https://github.com/zkldi/Tachi). You can find it under the `docs/` folder. - -Writing, maintaining and proofreading the documentation is something that is **severely** neglected -at the moment. Simple things like typo fixes, all the way up to writing new explanations about major features -are **thoroughly** appreciated, as `zk` prioritises maintaining the core of working code. - -If you're interested in this, check out the [Documentation Contribution Guide](./components/documentation.md). - -### Database Seeds - -We use an interesting system for parts of our database. We actually store a game's songs and charts _in_ -our GitHub repository! That means you can: - -- Open the `songs` file for a game. -- Edit a `title` of a song that has a typo. -- Add a couple new songs that were added in the latest update -- Submit your changes back and if they're accepted... -- They automatically synchronise with the site! - -!!! important -This part of Tachi is the most important part for external contributors. -You guys know these games better than `zk` does, and you guys keep an eye on all the updates for your games! - - If people don't add songs/charts to this database, `zk` will **not** keep an eye on the game for you! Someone *has* to pick up the reigns for each game! - - If you want to add/fix songs, charts, folders or tables for your favourite game - **START HERE!** - - Or in general, if you just want to contribute and don't know what to -- **this is the MOST in need of help. Always.** - -Want to get started on contributing to the Database? Check out our [Database Contribution Guide](./components/seeds.md). - -### Server, Client - -The server and client form the powerful _core_ of Tachi. - -The server handles all of our logic -- How do we get scores, where should scores come from, how do we calculate all these stats and way more. - -The client tries to then place a slick UI over that logic and its exposed API. - -!!! warning -Tachi's core is not an amazingly complex beast, but it is _not_ going to be reasonably followable -with not a lot of programming experience. You'll need some background in programming to be able to do almost anything in this area. - - That said, we still have a thorough guide -- It's not *from 0*, but it is *from some programming knowledge*. - -Want to get started on contributing to the Core? Check out our [Core Contribution Guide](./components/core.md). - -We'll cover... - -- Running a local development instance of Tachi. -- How to configure the server with `conf.json5`. -- How our codebase is laid out. -- How to run tests and more! - -## That's it for now! - -Everything else in Tachi isn't seeking external contribution at the moment. So, feel free to check -out one of the above linked guides! diff --git a/old-docs/docs/contributing/components/core.md b/old-docs/docs/contributing/components/core.md deleted file mode 100644 index 6de968319..000000000 --- a/old-docs/docs/contributing/components/core.md +++ /dev/null @@ -1,43 +0,0 @@ -# Client + Server Contribution Guide - -The client and server are the meat and potatoes of Tachi. They handle all of our requests and display our fancy UI. - -Contributing here is a bit more difficult than contributing to the seeds, but it's certainly not impossible! - -Plus, it's good fun to be able to mess around with websites. If you've got something you want to mess around with, you might find it surprisingly easy to do! - -## Pre-Setup - -You must have [Setup a local dev environment](../setup.md) in order to work nicely with the docs! - -## Component Overview - -The content for the client is inside `client/` and the content for the server is inside `server/`. - -The client and server share quite a bit of code. This is inside `common/`. - -To run the client and server, use `just start`. You can hit `Ctrl+C` to stop the server. - -## Editing the Client - -With `just start` running, the client will listen for changes you make, and reload accordingly. You will see your changes reflected on http://localhost:3000. - -## Editing the Server - -Likewise, with `just start` running, the server will listen for changes you make, and reload accordingly. - -!!! warning - Be careful with triggering a server reload. If you do it mid-import you can cause some serious state issues. - - If you suspect that your local state is screwed up, run `just wipe-local-db` to reset - the database. - -## Getting real data - -The client, out of the box, is sort of hard to test because you'll have no scores to display. - -Use `just load-kamai-dataset` or `just load-boku-dataset` to load a *real* dataset from either of the Tachis. - -You'll then need to edit `server/conf.json5` and change `MONGO_DATABASE_NAME` to `"anon-kamai"` or `"anon-boku"`. - -Everyone's passwords are set to `password`, so feel free to log in as anyone, and see real data! diff --git a/old-docs/docs/contributing/components/documentation.md b/old-docs/docs/contributing/components/documentation.md deleted file mode 100644 index 745b18f76..000000000 --- a/old-docs/docs/contributing/components/documentation.md +++ /dev/null @@ -1,45 +0,0 @@ -# Documentation Guide - -The documentation component of Tachi powers the website you're currently viewing. Hi! - -## Pre-Setup - -You must have [Setup a local dev environment](../setup.md) in order to work nicely with the docs! - -## Component Overview - -All of the content for this component is inside the `docs/` folder. - -It contains another folder, inconveniently called `docs/`, which contains all of the markdown files that are our documentation. - -There's another folder called `includes/`, which contains some things that are constantly -referenced throughout the documentation. - -At the top level, there's `mkdocs.yml` which configures how our documentation works later. - -## Software Overview - -We use [MKDocs Material](https://squidfunk.github.io/mkdocs-material/) for our documentation. -It extends markdown a bit to let us add things like admonitions and references. - -Their documentation is **incredibly** good, so check their stuff out there if you want to see what features are available. - -Other than that, our documentation is [markdown](https://www.markdownguide.org/basic-syntax/). If you know how to format a discord message, you know how to write documentation! - -## Running the Documentation - -Use `just docs start` inside Tachi to start up a local documentation viewer on http://localhost:8001. - -This will automatically refresh when you edit anything related to the documentation, so you can quickly see how your stuff goes. - -## A bit about mkdocs.yml - -MKDocs has only one configuration file -- `mkdocs.yml`. This is a [YAML](https://en.wikipedia.org/wiki/YAML) file that configures the documentation we output. - -It also manages the order of pages on the site. **You need to edit this if you're adding new pages! They aren't automatically added!** - -## Contributing Back - -It's just documentation. Make the changes and commit them up, ideally with `docs:` as the commit prefix. - -That is to say: your commit messages should look like `docs: fixed typo in API route`. diff --git a/old-docs/docs/contributing/components/issues.md b/old-docs/docs/contributing/components/issues.md deleted file mode 100644 index a7c72eb49..000000000 --- a/old-docs/docs/contributing/components/issues.md +++ /dev/null @@ -1,30 +0,0 @@ -# GitHub Issues Guide - -This isn't really a Tachi component, but it's important enough to have a guide. - -We use GitHub issues for all of our issue tracking and feature planning, if you're looking to request a feature or report a bug, good etiquette is defined here. - -## Etiquette - -Be nice. - -If you're reporting a bug, **be as explicit as possible**. If something crashed, what were you doing at the time of the crash? Remember that a human has to read your post and attempt to diagnose the issue. - -For the same reasons that you wouldn't go to a doctor and just say "It hurts", you can't just report a software issue as "It's broken". Low effort and ambiguous bug reports will be closed. - -## Large Feature Requests - -If you've came up with an idea for a new large feature, that's awesome! Before you post it though, think it through for a while. -I personally find it very helpful to think on ideas in the shower, but basically anything where you can think about an idea undistracted is useful (like a walk or something). - -This will help you shape up the feature, and makes it easier for maintainers to implement said feature (Especially if it's major). - -Regardless, once you've posted a large feature request, expect there to be discussion in the thread. You should check your emails! - -## Existing Issues - -Search for existing issues before opening a new one. There might already be one open with a similar thing. - -## That's it! - -Don't fret too much about writing perfect issues, but put some effort into them. The development team look at everything that comes through, and will tidy up bits of your issue for you if you make a mistake. diff --git a/old-docs/docs/contributing/components/seeds.md b/old-docs/docs/contributing/components/seeds.md deleted file mode 100644 index e7f53949c..000000000 --- a/old-docs/docs/contributing/components/seeds.md +++ /dev/null @@ -1,138 +0,0 @@ -# Database Seeds Guide - -The database seeds component of Tachi controls the actual data inside the app. - -Changes made in this component are automatically synchronised with the live Tachi database, -it's kind of a cool system, and allows anyone to contribute patches to songs, charts, folders, and more! - -## Pre-Setup - -You must have [Setup a local dev environment](../setup.md) in order to work nicely with the docs! - -## Component Overview - -All of the content for this component is inside the `seeds/` folder. - -It contains the `collections/` folder, which contains JSON files for their respective databases. - -!!! example - `collections/songs-iidx.json` will be synced with the `songs-iidx` collection in the database. - -The other available folder is `scripts/`. -This contains a Typescript package for scripting changes to the database seeds, and also contains a script that tests whether the data in the seeds is valid. -We'll go over this more later. - -## Software Overview - -The collections are all just plain JSON files. - -The scripts are written in either TypeScript or JavaScript. - -## How do I know what a song is meant to look like? - -These are called schemas (or interfaces) and you can find them in two places: - -- The source code. - -You can find the actual interfaces we use inside the common module, it's at `common/src/types.ts`. This contains interface definitions like `SongDocument` which, -expectedly, define what a song is meant to look like. - -- The documentation. - -We also maintain a bit more human readable form for schemas in this documentation, under the [schemas section](../../schemas). - -!!! warning - This may be slightly out of sync with the current content. Please report it if it is! - -## Important Scripts - -After doing **anything** to the collections, such as adding a new item to the database, you **MUST** run `just seeds sort` inside the `scripts/` folder. - -This will deterministically sort the data you put into the collections, making sure that `git` history stays sane (i.e. it only says things that actually changed, changed). - -Before sending any changes, run `just seeds test` to check all your data. If anything you've sent is invalid, it'll be logged in `failed-tests.log`, and the command won't pass. - -This is automatically ran when changes are sent to me, but you should run it yourself before committing anyway! - -!!! info - Your changes won't be synced with the database if they fail the tests. - - If you're confused about why tests are failing, ask in the discord. - -## Rerunners - -Inside the `scripts/` folder is a folder called `rerunners/`. -These scripts are intended to be kept around and re-ran (hence the name). - -You'll find a bunch of useful little utilities here, and there's sadly too many to document. - -It should be obvious what each one does, though. - -If you're looking to add a BMS table to Tachi for an example, you'd look into the rerunner scripts. - -## Single-Use Scripts - -Some scripts we only want to run once, and we don't really need to keep them around. These are saved into the `personal` folder, and will never be tracked by `git`. - -You can make quick hacky scripts here. - -!!! warning - Anything in this folder will *NOT* be shared. Please be generous with what you share, - far too many people have assumed nobody is interested in their scripts, and then lost - the scripts when moving machines! - -## Scripting Changes - -We provide utilities for mutating data inside the collections comfortably inside `scripts/util.js`. The most important one is `MutateCollection`, which, as expected, mutates a collection. - -It takes a collection name (like `songs-iidx.json`) and a callback function that receives the data inside that collection. - -Whatever that callback returns replaces the data in the collection. - -Below are some examples of what you can do with this API. - -=== "Batch Renaming an artist" - ```js - const { MutateCollection } = require("../util"); - - // Let's say all songs made by the artist "Scrimbly" were renamed to - // BEMANI SOUND TEAM "Scrimbly". - MutateCollection("songs-iidx.json", (songs) => { - // for all the songs in songs-iidx.json - for (const song of songs) { - // if the song artist is "Scrimbly" - if (song.artist === "Scrimbly") { - // replace it - song.artist = 'BEMANI SOUND TEAM "Scrimbly"' - } - } - - // return the same piece of data we got, with our mutations applied. - return songs; - }); - ``` - -=== "Adding data" - ```js - const { MutateCollection } = require("../util"); - - MutateCollection("songs-iidx.json", (songs) => { - songs.push({ - // some new song object - }) - - songs.push({ - // another new song object - }) - - // return the same piece of data we got, with our mutations applied. - return songs; - }); - ``` - -For even more examples, see the `rerunners/` folder, as it makes liberal use of this API. - -## Running scripts - -To run a seeds script, type `seeds` and pick your script. This will type out the -command for you. diff --git a/old-docs/docs/contributing/cookbook/bms-tables.md b/old-docs/docs/contributing/cookbook/bms-tables.md deleted file mode 100644 index 92cd722a2..000000000 --- a/old-docs/docs/contributing/cookbook/bms-tables.md +++ /dev/null @@ -1,9 +0,0 @@ -# Adding New BMS Tables - -Adding new BMS tables to Tachi is remarkably simple. - -Firstly, you need to edit `common/src/constants/bms-tables.ts`. Place your new table in the array. - -Now, run the `rerunners/bms-pms/sync-bms-tablefolders.ts` script inside the database seeds. - -Congratulations! You've added support for a BMS table. diff --git a/old-docs/docs/contributing/cookbook/ddr-mdb.md b/old-docs/docs/contributing/cookbook/ddr-mdb.md deleted file mode 100644 index e73b8ac9b..000000000 --- a/old-docs/docs/contributing/cookbook/ddr-mdb.md +++ /dev/null @@ -1,77 +0,0 @@ -# Merging DDR data into seeds - -!!! important - You need to have a working setup of Tachi to use this script. - - For instructions on how to do that, see [Tachi Setup](../setup.md). - -## Using `musicdb.xml` - -We have a script that already exists for parsing a `musicdb.xml` file and merging it with the database seeds. -This is convenient for when you want to provide an update for DDR based off data you have. - -### Importing DDR gamedata - -Navigate to `seeds/scripts/rerunners/ddr`. -The file you're looking to run is `parse-gameData-xml.ts`, but it needs two arguments: - -- `--input`, which is the location of the `musicdb.xml` file you're looking to parse. -- `--version`, what version of the game this music db is from. For a list of versions, see the [DDR Config](../../game-support/games/ddr-SP.md#versions). - -You can run this script by typing `bun parse-gameData-xml.ts --input YOUR_INPUT_HERE --version YOUR_VERSION_HERE` in the terminal. - -For example, if your file is in the same directory as the script, and you're importing from DDR World: -`bun parse-gameData-xml.ts --input ./musicdb.xml --version world` - -!!! warning "Warning" - - If all the difficulties in your XML file are set to `255`, you will need to enter them manually before importing. - Otherwise, the song won't be imported properly, and the difficulties won't show up. - - If the song is also in DDR Konaste, and you have the relevant json file, you can copy the values over. - Alternatively, you can use [RemyWiki](https://remywiki.com/). Look up the song's name, then copy the difficulties manually from the table. - - - Search for your song on RemyWiki. - - Scroll down to "Difficulty & Notecounts", then look for the table containing your game version. - - Manually copy the difficulties from it. - - For example, with [Cheerleader](https://remywiki.com/Cheerleader): - The difficulty in `musicdb.xml` is set to `255 255 255 255 255 0 255 255 255 255`, which is incorrect. - After following these steps, you should end up with `2 6 9 13 15 0 6 9 13 15`. - - Notes: There are 10 numbers, each one corresponding to a level of difficulty. - The first 5 are for SP, and the remaining are for DP. - The difficulty levels range from *BEGINNER*, *BASIC*, *DIFFICULT*, *EXPERT*, to *CHALLENGE*. - Any difficulty above 19 will be ignored, and a difficulty of 0 means that the song does not have it. - The *BEGINNER* field for DP is always set to 0 because it doesn't exist. - -### Updating stepCounts - -Step counts are generated from SSQ files. You're on your own to find them. - -Place all of your SSQ files in the `ssq` folder. The name of each file should correspond to the `basename` of each song, which is a 4~5 characters identifier. -Then, run `bun parse-charts.ts` - - -## Using a JSON file - -We have a script that already exists for parsing a JSON file and merging it with the database seeds. -This is convenient for when you want to provide an update for DDR based off data you have. - -!!! danger "Important" - - JSON files are usually used for Konaste game data, and therefore won't have all arcade songs. - Due to encoding differences, songs may contain Unicode characters in them instead of their actual names. You will have to manually fix this. - Additionally, the basename of existing songs may be edited incorrectly. - Therefore, this option is **not** recommended. - -Navigate to `seeds/scripts/rerunners/ddr`. -The file you're looking to run is `parse-gameData-json.ts`, but it needs two arguments: - -- `--input`, which is the location of the JSON file you're looking to parse. -- `--version`, what version of the game this music db is from. For a list of versions, see the [DDR Config](../../game-support/games/ddr-SP.md#versions). - -You can run this script by typing `bun parse-gameData-json.ts --input YOUR_INPUT_HERE --version YOUR_VERSION_HERE` in the terminal. - -For example, if your file is in the same directory as the script, and you're importing from DDR Konaste: -`bun parse-gameData-json.ts --input ./music.json --version konaste` \ No newline at end of file diff --git a/old-docs/docs/contributing/cookbook/iidx-mdb.md b/old-docs/docs/contributing/cookbook/iidx-mdb.md deleted file mode 100644 index 1ecaf0105..000000000 --- a/old-docs/docs/contributing/cookbook/iidx-mdb.md +++ /dev/null @@ -1,24 +0,0 @@ -# Merging IIDX Data into seeds - -Updating seeds via IIDX data is a complicated endeavour. Luckily, we've automated it with scripts. - -!!! important - You need to have a working setup of Tachi to use this script. - - For instructions on how to do that, see [Tachi Setup](../setup.md). - -## How to use - -You will need `ifstools` in your `$PATH`. You can do this by installing `python3` and then running `pip install ifstools`. - -Navigate to `seeds/scripts/rerunners/iidx/iidx-mdb-parse`. - -Run `bun merge-mdb.ts --help` for information on what arguments are needed. - -Fill out those arguments, and run the script in the terminal. If everything has gone correctly, `charts-iidx.json` and `songs-iidx.json` will be updated accordingly. - -## Blacklisting - -Sometimes, you might want to exclude certain charts from the parser. -Edit `blacklist.txt` accordingly. - diff --git a/old-docs/docs/contributing/cookbook/sdvx-mdb.md b/old-docs/docs/contributing/cookbook/sdvx-mdb.md deleted file mode 100644 index a3021e40c..000000000 --- a/old-docs/docs/contributing/cookbook/sdvx-mdb.md +++ /dev/null @@ -1,20 +0,0 @@ -# Merging a SDVX music_db.xml into seeds - -We have a script that already exists for parsing a `music_db.xml` file and merging it with the database seeds. -This is convenient for when you want to provide an update for SDVX based off data you have. - -!!! important - You need to have a working setup of Tachi to use this script. - - For instructions on how to do that, see [Tachi Setup](../setup.md). - -## How to use - -Navigate to `seeds/scripts/rerunners/sdvx`. - -The file you're looking to run is `merge-mdb.ts`, but it needs two arguments: - -- `--input`, which is the location of the `music_db.xml` file you're looking to parse. -- `--version`, what version of the game this music db is from. For a list of versions, see the [SDVX Config](../../game-support/games/sdvx-Single.md#versions). - -You can run this script by typing `bun merge-mdb.ts --input YOUR_INPUT_HERE --version YOUR_VERSION_HERE` in the terminal. diff --git a/old-docs/docs/contributing/index.md b/old-docs/docs/contributing/index.md deleted file mode 100644 index 1631f61ed..000000000 --- a/old-docs/docs/contributing/index.md +++ /dev/null @@ -1,27 +0,0 @@ -# Contributing Overview - -So, you're interested in contributing to Tachi? Awesome! All help is appreciated. -But, what *can* you contribute, and where can you help out? - -## What does Tachi need? - -Contrary to what you might already think, contributing to Tachi actually has remarkably little to -do with code. - -The primary Tachi maintainer (henceforth referred to as `zk`, because that's their name) -deals with the core of the codebase; things like importing scores, adding new features and most of the UI work -is handled by them. - -Tachi actually doesn't really have a shortage of people who can write good code, and the core of the codebase -feature-wise is maintainable entirely by `zk` comfortably. - -What **isn't** possible to maintain, is the sheer amount of things going on in every game! `zk` -cannot reasonably keep track of all the games we support and everything that's going on in them. - -That's where you step in - people who actually actively *play* games on Tachi! By letting `zk` -know about things going on in your game - and even contributing things yourself - you help make their life easier -and Tachi's support for your favourite game even better! - -## Sounds good. - -Awesome! Start with the [Setup](./setup.md) guide. This will get Tachi running on your local PC, so you can test all your changes. diff --git a/old-docs/docs/contributing/setup.md b/old-docs/docs/contributing/setup.md deleted file mode 100644 index e69e6366f..000000000 --- a/old-docs/docs/contributing/setup.md +++ /dev/null @@ -1,173 +0,0 @@ -# Setting up a Local Development Environment - -Before you can contribute to Tachi, it'll help to have a functional setup on your machine. - -You don't _necessarily_ need to have a working install to contribute - you could easily -make documentation contributions without having anything running on your machine - but -it's extremely helpful to be able to run Tachi's things while working on them. - -## 0. Install the basics - -### VSCode - -We'll need a code editor so we can actually edit Tachi's code. - -Please install [VSCode](https://code.visualstudio.com). -We'll use this as our editor because of it's excellent support for dev containers. - -### Terminal - -You'll also need a terminal to run commands in. For Linux and Mac users, you can just open -a Terminal app. - -However, for Windows users we recommend installing the [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=en-gb&gl=GB). - -With a terminal open you can proceed to the next steps! - -### Git - -You'll need `git` to clone Tachi to your machine. - -=== "Windows" -Install git [from the official website](https://git-scm.com/downloads). - -=== "Ubuntu, Debian" -Open a terminal and type this: -`sh - sudo apt install git - ` - -=== "Arch, Manjaro" -Open a terminal and type this: - - ```sh - sudo pacman -S git - ``` - -=== "MacOS" -Open a terminal and type this: - - ```sh - brew install git - ``` - -## 1. Getting Docker. - -To set everything else up for local development, we'll use [Docker](https://docker.com). - -=== "Windows, WSL Ubuntu" -You should install [Docker Desktop](https://docs.docker.com/desktop/) instead. -Docker doesn't work well inside WSL. - -=== "Debian" -[Please use the official Docker install guide.](https://docs.docker.com/engine/install/debian/) - -=== "Ubuntu" -[Please use the official Docker install guide.](https://docs.docker.com/engine/install/ubuntu/) - -=== "Arch, Manjaro" -Open a terminal and type this: - - ```sh - sudo pacman -S docker docker-compose - ``` - -=== "MacOS" -Open a terminal and type this: - - ```sh - brew install docker docker-compose - ``` - -!!! info -Docker is like a VM[^1]. It runs an entire Linux box to contain your software in, and generally sidesteps the whole "works on some machines" problem. - -## 2. Fork and pull the repo. - -Since you can't just commit straight to someone else's codebase (that would be a massive security issue), you need to make a fork of Tachi - One owned by you! - -Go to [the Tachi repository](https://github.com/zkldi/Tachi) and click the Fork button in the top right (Make sure you're signed in). - -Now, back to the terminal: - -!!! tip -It's good organisation to make a folder on your PC for codestuffs. -If you do that, make sure you open the terminal in that folder, -so your Tachi repo will save there! - -Open a terminal and type the following commands: - -```sh -# This will create a folder called Tachi on your PC. -# It'll create it wherever your terminal is currently open in. -git clone https://github.com/YOUR_GITHUB_USERNAME/Tachi - -# Open this repository in VSCode! -code Tachi -``` - -## 3. Get into the container. - -### What is a container? - -Your personal machine could be running anything. Windows, Mac, Linux, whatever! -Tachi expects to be running on Linux and with specific versions of certain software running. -It's a huge pain to ask _you_ to install that software and manage it yourself. -Plus, subtle differences between Windows and Linux cause problems _all_ the time. - -As such, we work _inside_ a docker container. This is sort of like having a Linux VM with everything set up perfectly for you. -I've spent quite a bit of time making this container user friendly, and it has so many nice things pre-installed for you. - -Perhaps more importantly, the container has everything needed to run Tachi perfectly. Neat! - -### Getting into it - -With `VSCode` open to Tachi, install the [Dev Container](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. - -Then, hit `Ctrl+Shift+P` to view all commands, and run `Dev Containers: Rebuild and Reopen in Container`. - -!!! warning -First time setup can take a very long time. -This depends on the performance of your machine, and whether you're using Windows or not. - - You can click `view log` in the bottom right to see the progress of making the container. - -### Working in the container - -**You want to do ALL your work inside the container.** -Doing thing outside of the container will cause issues or crashes. - -There is a subtle confusing trick here. We now want to use a terminal _inside_ our container. -**Do not use a terminal outside of VSCode now.** - -To open a terminal inside `VSCode`, use `Ctrl+J` to open the bottom panel. -Inside there there should be a `TERMINAL` tab, click that. -There should be a `+` at the top right of the panel. Click that to open a new terminal! - -You should see a message starting with `Welcome to Tachi!`. Inside this shell, you have full access to Tachi and all of its utilities. - -## 4. Authenticate with Github. - -You'll need to authenticate with GitHub before you can actually push changes back -to your repository. - -Type `gh auth login` and follow the instructions. -You should now be properly authenticated! - -## 5. Start Tachi! - -With a terminal open inside the `Tachi` container you just cloned, run `just start`. - -The frontend will be running on `http://localhost:3000`. -The backend listens on `http://localhost:8080`, and the Vite dev server **proxies** `/api` and `/ir` there so the browser talks to the app on port 3000 only (same-origin HTTP, no self-signed certificates). - -!!! tip -Type `just` in the terminal to see other available commands. - -Navigate to http://localhost:3000 and check your Tachi instance! - -## 6. OK, Now what. - -Now that you've got a working version of Tachi running on your local PC, you should go check out the [component-specific contribution guides](./components.md)! - -[^1]: Docker is not actually a VM, it's significantly smarter and does some Linux jail cgroup nonsense. All you need to care about is that we're using it to spawn Linux VMs on your host system. diff --git a/old-docs/docs/game-support/client-impl.md b/old-docs/docs/game-support/client-impl.md deleted file mode 100644 index 70e4b5390..000000000 --- a/old-docs/docs/game-support/client-impl.md +++ /dev/null @@ -1,165 +0,0 @@ -# Client Implementation - -As you probably can expect, the client implementation is entirely frontend-related stuff. - -This includes things like how to render score tables for this GPT, and how to colour -in enums. - -## Where do Client Implementations go? - -Implementations should be written in `client/src/lib/game-implementations.tsx`. - -It's fine to inline implementations here, but feel free to break out into a separate file (See what IIDX does for a reference) if you need to. - -## `enumColours` - -For all the ENUM metrics in this game, give all of their values colours. - -!!! tip - The `COLOUR_SET` global is useful for this, as it provides consistent identity - throughout tachi. - -## `enumIcons` - -What [Font Awesome v5](https://fontawesome.com/v5/search) icon should we use to -represent each enum? - -## `difficultyColours` - -If this game uses fixed difficulties, give each difficulty name a colour here. - -## `classColours` - -Give each class value a colour. These are used to render the class badges. - -## `ratingSystems` - -Although all games have `level` and `levelNum`, some optional properties may be useful here. - -This is an array of functions that take a chart and return information about it. - -These are used to sort charts in tables when the `difficulty` header is used to sort. - -!!! example - The `CreateRatingSys` util is used for this: - - ```ts - [ - CreateRatingSys( - "NC Tier", - "Tierlist Ratings for Normal Clears.", - (c) => c.data.ncTier?.value, - (c) => c.data.ncTier?.text, - (c) => c.data.ncTier?.individualDifference - ), - CreateRatingSys( - "HC Tier", - "Tierlist Ratings for Hard Clears.", - (c) => c.data.hcTier?.value, - (c) => c.data.hcTier?.text, - (c) => c.data.hcTier?.individualDifference - ), - CreateRatingSys( - "EXHC Tier", - "Tierlist Ratings for EX-HARD Clears.", - (c) => c.data.exhcTier?.value, - (c) => c.data.exhcTier?.text, - (c) => c.data.exhcTier?.individualDifference - ), - ] - ``` - -!!! example - ITG also uses this to leverage the sorting abilities of this: we want to sort - things on level, but if the level is the same, we want to break ties on BPM. - - ```ts - [ - CreateRatingSys( - "BPM", - "How fast are the streams in this chart?", - (c) => c.data.streamBPM, - (c) => c.data.streamBPM?.toString() - ), - ] - ``` - -## `scoreHeaders` - -What should the headers be for the score cells when rendering scores for this GPT? - -!!! example - ```ts - [ - ["Score", "Score", NumericSOV((x) => x.scoreData.percent)], - ["Deltas", "Deltas", NumericSOV((x) => x.scoreData.percent)], - ["Lamp", "Lamp", NumericSOV((x) => x.scoreData.enumIndexes.lamp)], - ] - ``` - - will correspond to the headers in the red box - - ![](../images/headers.png) - -## `scoreCoreCells` - -When rendering a score row, how should we render the actual score information cells? - -This function gets `sc`, which is either a score or a PB for this GPT, and `chart`; the chart this score was on. - -!!! important - The amount of cells returned should be **EXACTLY** the same length as the headers. - -!!! example - ```ts - ({ sc }) => ( - <> - - - - - ), - ``` - - will correspond to the cells in these columns. - - ![](../images/cells.png) - -## `ratingCell` - -How should we render the rating cell for this GPT? - -This is a function that takes in the aforementioned `sc` and `chart`, alongside `rating`, which is the currently selected score rating algorithm. - -!!! example - ```ts - ({ sc, chart, rating }) => ( - <> - {rating === "blockRating" ? ( - - - {chart.data.rankedLevel === null - ? "Unranked Chart." - : sc.calculatedData.blockRating === null - ? "Failed" - : sc.calculatedData.blockRating} - - - ) : ( - - )} - - ), - ``` - - will correspond to the cells in this column. - - ![](../images/ratingcell.png) - -## That's it! - -Congrats! If you've done this, the [Server Implementation](./server-impl.md) and the [Common Configuration](./common-config/index.md), you've just added full support for a game to Tachi! Nice job! diff --git a/old-docs/docs/game-support/common-config/index.md b/old-docs/docs/game-support/common-config/index.md deleted file mode 100644 index c328d0864..000000000 --- a/old-docs/docs/game-support/common-config/index.md +++ /dev/null @@ -1,426 +0,0 @@ -# Common Configuration - -This page documents how support for a game is written in `common/`. - -There are two kinds of configs here. - -## Where do configurations go? - -Configurations should be written in `common/src/config/game-support/GAMENAME.ts`. - -Once you have written a config, go to `common/src/config/config.ts` and import it. Mount the game configuration on `GAME_CONFIGS`, and the GPT configuration on `GAME_PT_CONFIGS`. - -## A quick note on Games vs GPTs. - -A game config is configuration for a game. Games in Tachi aren't actually the meaty part of support, instead, games form a kind of "group" for their playtypes. - -For example, in IIDX there are two kinds of playtypes - Single Play and Double Play. Although these are completely separate kinds of games (it wouldn't make sense to share scores between them), they do share songs. - -The game part - in this case `iidx` - defines things that are shared between all of its playtypes - things like what to call the game and what the song documents look like. - -Whereas the game + playtype (typically shortened to GPT) is the part that contains almost all of the actual configuration. This distinction will become more obvious when you see the difference in size between the two configs. - -!!! note - I picked the shorthand `GPT` before ChatGPT et. al. blew up. Ah well. - -## Game Configurations - -Here is an example configuration - taken from our actual implementation of IIDX. - -```ts -export const IIDX_CONF = { - name: "beatmania IIDX", - playtypes: ["SP", "DP"], - songData: z.strictObject({ - genre: z.string(), - displayVersion: z.nullable(z.string()), - }), -} as const satisfies INTERNAL_GAME_CONFIG; -``` - -!!! note - `game` in Tachi is a bit of an unfortunate name. While - intuitively - most people - will think of the game as the important part, `game` in Tachi functions more like - a "grouping" of playtypes. - - Our IIDX game contains two playtypes - SP and DP, these are implemented almost - entirely separately -- SP and DP could have entirely different calculations if they - wanted! - - Things should be grouped together if the songs involved in the game can have - multiple charts across-playtypes. Since songs in IIDX can have SP and DP difficulties, - they share a `game`! - -### `name` - -This is the name for the game that will be displayed to end users. This should be formatted generally how the game formats things. - -### `playtypes` - -The list of playtypes this game supports. For games that only have one playtype (and likely will never have another), "Single" is typically used. - -!!! example - For SDVX, we use `playtypes: ["Single"]`. Since SDVX doesn't normally have any sort of separate playtypes. - -### `songData` - -What game-specific properties should exist on a song? - -This is written as a [Zod](https://github.com/colinhacks/zod) schema, which allows us to simultaneously declare the type of additional data, and how to validate it. - -This game-specific information is stored on the `data` field of a song. - -!!! example - Here's an example IIDX song: - - ```json - { - "altTitles": [], - "artist": "dj nagureo", - "data": { - "displayVersion": "1", - "genre": "PIANO AMBIENT" - }, - "id": 1, - "searchTerms": [], - "title": "5.1.1." - }, - ``` - - Note the `data` field, which allows for game-specific metadata. - -## GPT Configurations - -This is the *real* meat-and-potatoes for implementing something for Tachi. - -Here is our actual implementation for WACCA's Single playtype. - -!!! note - WACCA only has one playtype - "Single". - -```ts -export const WACCA_SINGLE_CONF = { - providedMetrics: { - score: { - type: "INTEGER", - validate: p.isBetween(0, 1_000_000), - formatter: FmtNum, - description: "The score value. This is between 0 and 1 million.", - }, - lamp: { - type: "ENUM", - values: ["FAILED", "CLEAR", "MISSLESS", "FULL COMBO", "ALL MARVELOUS"], - minimumRelevantValue: "CLEAR", - description: "The type of clear this score was.", - }, - }, - - derivedMetrics: { - grade: { - type: "ENUM", - values: [ - "D", - "C", - "B", - "A", - "AA", - "AAA", - "S", - "S+", - "SS", - "SS+", - "SSS", - "SSS+", - "MASTER", - ], - minimumRelevantValue: "S", - description: "The grade this score was.", - }, - }, - - optionalMetrics: { - ...FAST_SLOW_MAXCOMBO, - }, - - defaultMetric: "score", - preferredDefaultEnum: "grade", - - scoreRatingAlgs: { - rate: { - description: "Rating as it's implemented in game.", - }, - }, - profileRatingAlgs: { - naiveRate: { - description: "A naive rating algorithm that just sums your 50 best scores.", - }, - rate: { - description: - "Rating as it's implemented in game, taking 15 scores from the latest version and 35 from all old versions.", - }, - }, - sessionRatingAlgs: { - rate: { description: "The average of your best 10 ratings this session." }, - }, - - defaultScoreRatingAlg: "rate", - defaultProfileRatingAlg: "naiveRate", - defaultSessionRatingAlg: "rate", - - difficulties: { - type: "FIXED", - order: ["NORMAL", "HARD", "EXPERT", "INFERNO"], - shorthand: { - NORMAL: "NRM", - HARD: "HRD", - EXPERT: "EXP", - INFERNO: "INF", - }, - default: "EXPERT", - }, - - classes: { - stageUp: { - type: "PROVIDED", - values: WaccaStageUps, - }, - colour: { - type: "DERIVED", - values: WaccaColours, - }, - }, - - orderedJudgements: ["marvelous", "great", "good", "miss"], - - versions: { - reverse: "REVERSE", - }, - - chartData: z.strictObject({}), - - preferences: z.strictObject({}), - scoreMeta: z.strictObject({ mirror: z.boolean().optional() }), - - supportedMatchTypes: ["songTitle", "tachiSongID"], -} as const satisfies INTERNAL_GAME_PT_CONFIG; -``` - -We'll go over each bit of this. - -## Metrics - -See [Metrics](./metrics.md) and [Metric Groups](./metric-groups.md). - -## `defaultMetric` - -What should the default metric for this GPT be? This is used for chart leaderboards, -and should *ideally* be an `INTEGER` or `DECIMAL` metric. It is not legal for this -to be a `GRAPH` or `NULLABLE_GRAPH` metric, as those are not sanely comparable. - -## `preferredDefaultEnum` - -If the user has no preferences overriding this, what should this GPT default to showing -when showing enum graphs? - -!!! example - ![](../images/../../images/default-enum.png) - - Here, we see that the site has picked lamps by default to show. This is because - the default enum for IIDX is `lamp`. - -!!! note - Users may override this preference in their settings for this GPT. - -## Score, Session, Profile Rating Algorithms - -These are all the exact same idea, but appear in different parts of Tachi. - -All of these define the names of rating algorithms and a description. - -Rating algorithms are functions that return a number or null. This can be used -to implement things like VOLFORCE (SDVX, USC) or tierlist ratings. - -Optionally, a rating algorithm's config may specify a `formatter:` field, which is -a function that transforms the number into a string somehow. If this is not specified, -this will default to a function that rounds the number to two decimal places. - -## Difficulties - -There are two kinds of difficulties available in Tachi. `"FIXED"`, which is a more traditional approach defining a fixed set of possible difficulties for your song (NORMAL, HYPER, ANOTHER, etc.), and `"DYNAMIC"`, which allows any arbitrary string as a difficulty name. - -### Dynamic Difficulties - -Dynamic difficulties are intended for use in games where a song may have any number of possible charts. - -An example of this would be something like `osu!`, where a song may have as many difficulties as it wants, with *any* string as their name. - -### Fixed Difficulties - -For games where songs can only have a certain amount of difficulties (most arcade games) -a fixed config likely makes more sense. - -With a fixed config, you define the `order:` in which these difficulties appear in,a default difficulty to redirect to if the song is selected in the search bar and -optionally, some shorthand (generally for mobile view). - -!!! example - ```ts - difficulties: { - type: "FIXED", - order: ["NORMAL", "HARD", "EXPERT", "INFERNO"], - shorthand: { - NORMAL: "NRM", - HARD: "HRD", - EXPERT: "EXP", - INFERNO: "INF", - }, - default: "EXPERT", - } - ``` - -## Classes - -Classes are enums for profiles. These allow you to store discrete values on a user's -profile. What values are supported are controlled by the `values:` field. -You can use the `ClassValue` helper function to help define values. - -There are two types of classes: - -### "DERIVED" - -In which the value of the class is derived from the user's profile metrics. - -!!! example - A common example of this would be things like `colour` rankings in konami arcade - games. These are cutoffs like `>1500 jubility = ORANGE, >2000 jubility = GREEN`. - -### "PROVIDED" - -In which the value of the class is provided by a score import somehow. - -!!! example - A common example of this would be things like dans. These are not functions - of existing state, and must be stated in an import method. - -!!! note - "DERIVED" classes are allowed to go back down - if the deriving implementation - says the class is now worse, the class the user has will decrease. - - However, "PROVIDED" classes cannot be superceded by worse ones - if the user was - 10th dan and then cleared 3rd dan, their dan will *not* be overwritten. The only - way for a "PROVIDED" class to go down is to contact an admin at the moment. - - Maybe the in the future, users could have the ability to manually wipe their own - classes, in-case they corrupt their profile. - -## `orderedJudgements` - -An ordered list (best to worst) of strings, representing the name of judgements (hit windows) for this GPT. - -## Versions - -See [Versions](./versions.md), as whether your GPT needs this or not requires some assessment. - -## Chart Data - -The `chartData` field allows you to define GPT-specific fields on chart documents. - -For example, in IIDX we *need* to store the `notecount` of a chart somewhere (it's used to calculate `percent` and `grade`). - -The `chartData` field is a [Zod](https://github.com/colinhacks/zod) schema indicating the structure of this additional information. - -!!! example - ```ts - chartData: z.strictObject({ - inGameID: z.number().int().nonnegative(), - clearTier: z.strictObject({ - value: z.number(), - text: z.string(), - individualDifference: z.boolean(), - }).nullable(), - }), - ``` - - declares that a chart for this GPT should look like: - - ```ts - { - "chartID": "5088a4d0e1ee9d0cc2f625934306e45b1a60699b", - "data": { - "inGameID": 1, - "clearTier": { value: 12.5, text: "12C", individualDifference: false } - }, - "difficulty": "ADV", - "isPrimary": true, - "level": "10", - "levelNum": 10, - "playtype": "Single", - "songID": 1, - "versions": ["exceed", "konaste"] - }, - ``` - - Note the GPT-specific properties in the `data` field now. - -## Preferences - -If this GPT should have specific preferences (for BMS, you can set a list of tables you don't want to see, for example), list them here as a Zod schema. - -!!! example - A `preferences` of - - ```ts - preferences: z.strictObject({ showCustomCharts: z.boolean() }) - ``` - - corresponds to a settings document of: - ```ts - [ - { - "userID": 1, - "game": "iidx", - "playtype": "SP", - "preferences": { - "preferredScoreAlg": null, - "preferredSessionAlg": null, - "preferredProfileAlg": null, - "preferredDefaultEnum": null, - "defaultTable": null, - "preferredRanking": null, - "stats": [], - "gameSpecific": { - "showCustomCharts": false - } - }, - "rivals": [] - } - ] - ``` - - Note the `preferences.gameSpecific` part, which holds these game-specific - preferences. - -## Score Metadata - -Sometimes, we want to store stuff about a score that isn't really related to a metric. - -A common example of this would be something like the mods the player was using - were -they using RANDOM, MIRROR, etc? - -!!! note - Score Metadata **DOES NOT** appear on PBs. This metadata is *specific* to the score - itself, and would never make sense to merge. - - If a PB is comprised of a best score using RANDOM, and a best lamp using MIRROR, - what should the PB merge to? It doesn't make any sense as an operation. - -This, similarly, is a Zod schema, and appears on a score documents `scoreMeta` field. - -## Supported Match Types - -This is for [BATCH MANUAL](todo) usage. BATCH MANUAL has to specify a `matchType` - how should it resolve a given identifier? - -Some import methods might want to use in game IDs, hashes of a certain kind, etc. - -For a list of all possible match types, see [Match Types](./match-types.md). - -You should list the available `matchTypes` in this field of the config. diff --git a/old-docs/docs/game-support/common-config/match-types.md b/old-docs/docs/game-support/common-config/match-types.md deleted file mode 100644 index ecc820e7a..000000000 --- a/old-docs/docs/game-support/common-config/match-types.md +++ /dev/null @@ -1,61 +0,0 @@ -# Match Types - -For [BATCH MANUAL](./todo) imports, we need a way of resolving given identifiers -into charts on Tachi. These may be through a variety of methods, such as chart hashes, -in game IDs, etc. - -This is a list of **all** available match types. However, what match types are available -depend on what game you're importing scores for. - -## Identifier Only - -The following match types only need an `identifier` defined. - -### `bmsChartHash` - -Uses `identifier` as an MD5 or SHA25 hash. - -### `itgChartHash` - -Uses `identifier` as a GroovestatsV3 hash. - -### `popnChartHash` - -Uses `identifier` as a SHA256 hash, for pop'n file contents. - -### `uscChartHash` - -Uses `identifier` as a SHA1 hash, since that's what USC uses. - -## Identifier + Difficulty - -These match types need both `identifier` and a `difficulty` defined. - -### `ddrSongHash` - -Looks up on the 32-character song hash for this chart, where the hash is from the official DDR e-amusement website. - -### `inGameID` - -Looks up on the in game ID for this chart. - -### `sdvxInGameID` - -Looks up on the in game ID for this chart, but allows a special difficulty string - `"ANY_INF"` to be passed. - -If `"ANY_INF"` is the difficulty, then that difficulty will try to find a chart with this in game ID where the difficulty is any of INF, GRV, HVN, VVD or XCD. - -### `songTitle` - -Looks up the song on its title or any of its defined `altTitles`. Can also match the artist field of the song if an `artist` property is defined. - -!!! warning - It is generally not recommended to enable this method, as it's particularly error-prone. Scores that can't be unequivocally identified will get rejected. - -### `tachiSongID` - -Looks up the song on Tachi's defined `songID`. - -## Adding a new Match Type - -Does your GPT implementation need its own match type? See [Adding a new match type](./COOKBOOK TODO). \ No newline at end of file diff --git a/old-docs/docs/game-support/common-config/metric-groups.md b/old-docs/docs/game-support/common-config/metric-groups.md deleted file mode 100644 index a903b9b14..000000000 --- a/old-docs/docs/game-support/common-config/metric-groups.md +++ /dev/null @@ -1,102 +0,0 @@ - -# Metric Groups - -Metrics for a GPT are grouped into three categories: - -## Provided Metrics - -These metrics **must** be provided in a score import. These are, in effect, **MANDATORY** metrics. - -These metrics go into the scoreID. - -!!! example - ```ts - providedMetrics: { - score: { - type: "INTEGER", - validate: p.isBetween(0, 1_000_000), - formatter: FmtNum, - description: "The score value. This is between 0 and 1 million.", - }, - lamp: { - type: "ENUM", - values: ["FAILED", "CLEAR", "MISSLESS", "FULL COMBO", "ALL MARVELOUS"], - minimumRelevantValue: "CLEAR", - description: "The type of clear this score was.", - }, - }, - ``` - - Any score import for a GPT like this *must* provide a compliant `score:` and `lamp:` value. - -## Derived Metrics - -These metrics are derived from the provided metrics (and the chart the score was on), but stored on scores for conveniences sake. These will **ALWAYS** be present on a score. - -It may also be the case that this derived form of a metric is the default metric for a game, in which case, we'd definitely want to store it for leaderboards! - -These metrics **DO NOT** go into the scoreID, as they are merely functions of other captured state. - -!!! example - ```ts - derivedMetrics: { - percent: { - type: "DECIMAL", - validate: p.isBetween(0, 100), - formatter: FmtPercent, - description: "EX Score divided by the maximum possible EX Score on this chart.", - }, - grade: { - type: "ENUM", - values: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], - minimumRelevantValue: "A", - description: - "Grades as they are in IIDX. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience.", - }, - }, - ``` - - In IIDX, the derived metrics are `percent` (as it's exScore / maximumEXOnThisChart) - and `grade`, which is also derivable. - - We want to store these values for convenience and displaying on the UI, so we will. - -## Optional Metrics - -Sometimes, we want to store some metrics that not all score imports could provide. For that, we have optional metrics. - -These metrics are defined like any other, but are all allowed to be not-provided by an importer. - -!!! example - ```ts - optionalMetrics: { - bp: { - type: "INTEGER", - validate: p.isPositive, - formatter: FmtScoreNoCommas, - description: "The total bads + poors in this score.", - }, - gauge: { - type: "DECIMAL", - validate: p.isBetween(0, 100), - formatter: FmtPercent, - description: - "The life in percent (between 0 and 100) that was on the gauge at the end of the chart.", - }, - } - ``` - - For IIDX, not all importing methods might know these values, and we don't want to exclude users of those services from being able to import their scores. - - As such, we mark these as optional. - -!!! warning - It's possible, but rare, that an optional metric should be part of the scoreID. - - For these cases, you can mark an optional metric with `partOfScoreID: true`. - This metric will now - as you'd expect - be part of the scoreID. - - We actually use this in SDVX for `exScore`. EX Score might not be available, as it - doesn't necessarily have to be enabled by the user - but if it does exist, we want - to track it properly. That is to say, if the user raises their `exScore` but nothing - else, we should still count that as a new score - despite `exScore` being optional! diff --git a/old-docs/docs/game-support/common-config/metrics.md b/old-docs/docs/game-support/common-config/metrics.md deleted file mode 100644 index dd412eef5..000000000 --- a/old-docs/docs/game-support/common-config/metrics.md +++ /dev/null @@ -1,203 +0,0 @@ -# Metrics - -Metrics are what kind of values we want to track on this GPT's scores. Common things for this are values like `score`, `lamp`, maybe even `grade`. - -A metric definition looks like this: - -```ts -{ - type: "INTEGER", - validate: p.isBetween(0, 100_000), - formatter: FmtNum, - description: "The score value.", -} -``` - -## Metric Types - -We're allowed 5 types of metrics: - -- `DECIMAL` - -This metric is expected to be a decimal. - -!!! example -`ts - percent: { - type: "DECIMAL", - validate: p.isBetween(0, 100), - formatter: FmtPercent, - description: "EX Score divided by the maximum possible EX Score on this chart.", - }, - ` - -- `INTEGER` - -This metric is expected to be a whole number. - -!!! example -`ts - { - type: "INTEGER", - validate: p.isBetween(0, 100_000), - formatter: FmtNum, - description: "The score value.", - } - ` - -- `ENUM` - -This metric is expected to be a string in a provided ordered list of strings. This is used to implement things like `"FAILED", "CLEAR", "FULL COMBO", "PERFECT"` lamps. - -!!! example -`ts - { - type: "ENUM", - values: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - minimumRelevantValue: "EASY CLEAR", - description: "The type of clear this was.", - }, - ` - -- `GRAPH` - -This metric is an array of numbers. - -- `NULLABLE_GRAPH` - -This metric is an array of numbers or null. - -!!! example -`ts - gaugeHistory: { - type: "NULLABLE_GRAPH", - validate: p.isBetween(0, 100), - description: - "A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart.", - }, - ` - - Importantly: something like `[99, 74, 12, null, null, null]` would be legal as a nullable graph. - - This does not mean the field itself is nullable, only the values inside the array! - -## Enum Metrics - -Metrics of type `ENUM` are special in many ways. Most importantly, they don't require -any sort of validation - the input is either a member of `values` or it isn't. - -An ENUM metric looks like this: - -```ts -{ - type: "ENUM", - values: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - minimumRelevantValue: "EASY CLEAR", - description: "The type of clear this was.", -}, -``` - -The order of `values` is extremely important: the first value should be the worst possible value in the metric, and the last value should be the best possible value. - -`minimumRelevantValue` indicates the smallest value in this enum that a user will -ever realistically care about getting. This is used in the UI and other places to -hide useless ENUM values from the user. - -!!! example -![](../../images/min-relevant-value.png) - - Despite the fact this user failed a bunch of stuff this session, the UI won't - show me my new `FAILED` or `ASSIST CLEAR` scores! - -## Integer and Decimal Metrics - -These kinds of metrics, given their more open-ended nature, require some validation. - -### Validation - -There are two kinds of metric validations. If a metric can be validated, it should have -a property called `validate` which returns true on success, and a string representing -an error message on failure: - -!!! example -```ts -{ -type: "INTEGER", -validate: (value) => { -if (value > 100_000) { return "Score cannot be greater than 100k." } - - return true; - }, - formatter: FmtNum, - description: "The score value.", - } - ``` - -!!! note -The type of input is already checked for you. You don't need to check whether your -input is an integer or not if you declare `type: "INTEGER"`. The same goes for -`type: "GRAPH"`, the validator instead runs on each element in the array. - -!!! tip -The reason for this rather strange type signature (`string | true`) is because we -can use our validation library - [Prudence](https://github.com/zkldi/Prudence) - to create validators for us. Instead -of writing out that validation code, we can use `p.isBetween(0, 100_000)`! - -However, it might not be possible to validate a metric without knowing what chart -the score is on. For example, in IIDX the maximum amount of score you can get is -the chart's notecount \* 2. - -Since we don't know what this GPT chart's look like at this time (we haven't defined them yet!) -we instead don't declare a validator and put down `chartDependentMax: true` instead. - -We will have to write the validator later in the server implementation. - -### Formatting - -We also want to format these metrics into a string. For example, a `percent` metric may want to stringify into `92.45%` instead of `92.49938222293842`. -More subtle formatting rules can be defined here too, such as how in Jubeat, scores are -easier to read written like `903,283` instead of `903283`. - -## Graph Metrics - -Graph metrics (`GRAPH` and `NULLABLE_GRAPH`) also have to define a validator, but the validator is called on each element of their respective arrays. - -To validate that all of the values in a graph metric are between 0 and 10, you could -write a validator like: - -```ts -function validate(value: number) { - if (value < 0) return "too small"; - if (value > 10) return "too big"; - return true; -} -``` - -This is remarkably similar to how validators work for `INTEGER` and `DECIMAL` metrics. - -Furthermore, graph metrics can specify a `size` function, which validates the size of -the array too. You can use this to enforce a certain array size (such as exactly 100 entries, or similar). - -## Now what? - -This is how metrics work, but there's more detail in how they're defined in each game's config. - -For example, some metrics (like `grade` for a lot of games) are merely functions of other metrics. Making every import method handle this themselves seems silly. How do we tackle this? This, and more, is answered in [Metric Groups](./metric-groups.md)! diff --git a/old-docs/docs/game-support/common-config/versions.md b/old-docs/docs/game-support/common-config/versions.md deleted file mode 100644 index 08ed8cf0f..000000000 --- a/old-docs/docs/game-support/common-config/versions.md +++ /dev/null @@ -1,32 +0,0 @@ -# Versions - -Versions are a method for us marking charts as being available in a certain "version" of the game. - -The predominant use for this is for arcade games, where new versions of the game generally come out and add/remove charts. - -It's useful for us to know what charts are available in what version for two purposes. - -The first allows us to create folders - users playing on a certain version of a game don't want to see charts they can't play! - -The second is more complex. - -## Disambiguation and `isPrimary` - -Sadly, the real world isn't easy to deal with. It's possible for a chart to exist in -version A of a game, get removed in version B, and then come back in version C with -new, completely different charts. - -**Worse still**, it's possible for that song to use the *exact same* in game ID it used -before. If we use `inGameID` to identify things, now we've got a critical ambiguity! - -Does `inGameID: 1, difficulty: ANOTHER` refer to the version A chart, or the version C one? For games where metrics are chart-dependent, this could be *lethal* to the leaderboards. - -It's much easier to get a good score in IIDX if the chart thinks it has less notes than it actually has! - -To fix this, we also use versions as an identifer for disambiguation. If a score comes -in, it **MAY** pass what version the score was attained on. - -This allows us to immediately disambiguate the previous case. - -If a version is **not** passed in, we assume that the score is for the chart marked as -`isPrimary: true`. Furthermore, seeds tests **enforce** that duplicates on certain IDs expected-to-be-unique cannot be true unless all-but-one-of-them is marked as `isPrimary: false`. diff --git a/old-docs/docs/game-support/games/arcaea-Touch.md b/old-docs/docs/game-support/games/arcaea-Touch.md deleted file mode 100644 index 6b9832d8e..000000000 --- a/old-docs/docs/game-support/games/arcaea-Touch.md +++ /dev/null @@ -1,87 +0,0 @@ -# Arcaea Support - -This game has the internal GPTString of `arcaea:Touch`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 10 million, plus bonus points dependent on how many shiny PUREs you get. | -| `lamp` | "LOST", "EASY CLEAR", "CLEAR", "HARD CLEAR", "FULL RECALL", "PURE MEMORY" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "A", "AA", "EX", "EX+" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `pure` -- `far` -- `lost` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `potential` | Potential as it is implemented in Arcaea. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `naivePotential` | The average of your best 10 potentials this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naivePotential` | The average of your best 30 potential values. This is different to in-game, as it does not take into account your recent scores in any way. | - -## Difficulties - -- `Past` -- `Present` -- `Future` -- `Eternal` -- `Beyond` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `badge` | DERIVED | BLUE, GREEN, ASH_PURPLE, PURPLE, RED, ONE_STAR, TWO_STARS, THREE_STARS -| `courseBanner` | PROVIDED | PHASE_1, PHASE_2, PHASE_3, PHASE_4, PHASE_5, PHASE_6, PHASE_7, PHASE_8, PHASE_9, PHASE_10, PHASE_11, PHASE_12 - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `mobile` | Mobile | -| `switch` | Nintendo Switch | - -## Supported Match Types - -- `inGameStrID` -- `songTitle` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/bms-14K.md b/old-docs/docs/game-support/games/bms-14K.md deleted file mode 100644 index b4f686c55..000000000 --- a/old-docs/docs/game-support/games/bms-14K.md +++ /dev/null @@ -1,98 +0,0 @@ -# BMS (14K) Support - -This game has the internal GPTString of `bms:14K`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in BMS. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `gaugeHistory` | Array<Decimal> | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `gaugeHistoryEasy` | Array<Decimal> | The easy gauge history. | -| `gaugeHistoryGroove` | Array<Decimal> | The groove gauge history. | -| `gaugeHistoryHard` | Array<Decimal> | The hard gauge history. | -| `epg` | Integer | The amount of early PGreats in this score. | -| `egr` | Integer | The amount of early greats in this score. | -| `egd` | Integer | The amount of early goods in this score. | -| `ebd` | Integer | The amount of early bads in this score. | -| `epr` | Integer | The amount of early poors in this score. | -| `lpg` | Integer | The amount of late PGreats in this score. | -| `lgr` | Integer | The amount of late greats in this score. | -| `lgd` | Integer | The amount of late goods in this score. | -| `lbd` | Integer | The amount of late bads in this score. | -| `lpr` | Integer | The amount of late poors in this score. | - -## Judgements - -The following judgements are defined: - -- `pgreat` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | A clearing algorithm that rewards you points based on how difficult an easy clear or hard clear was. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 10 sieglinde ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 20 sieglinde ratings. | - -## Difficulties - -- `CHART` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `genocideDan` | PROVIDED | NORMAL_1, NORMAL_2, NORMAL_3, NORMAL_4, NORMAL_5, NORMAL_6, NORMAL_7, NORMAL_8, NORMAL_9, NORMAL_10, INSANE_1, INSANE_2, INSANE_3, INSANE_4, INSANE_5, INSANE_6, INSANE_7, INSANE_8, INSANE_9, INSANE_10, INSANE_KAIDEN, OVERJOY -| `stslDan` | PROVIDED | SL0, SL1, SL2, SL3, SL4, SL5, SL6, SL7, SL8, SL9, SL10, SL11, SL12 - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `bmsChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/bms-7K.md b/old-docs/docs/game-support/games/bms-7K.md deleted file mode 100644 index 1a0b09763..000000000 --- a/old-docs/docs/game-support/games/bms-7K.md +++ /dev/null @@ -1,101 +0,0 @@ -# BMS (7K) Support - -This game has the internal GPTString of `bms:7K`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in BMS. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `gaugeHistory` | Array<Decimal> | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `gaugeHistoryEasy` | Array<Decimal> | The easy gauge history. | -| `gaugeHistoryGroove` | Array<Decimal> | The groove gauge history. | -| `gaugeHistoryHard` | Array<Decimal> | The hard gauge history. | -| `epg` | Integer | The amount of early PGreats in this score. | -| `egr` | Integer | The amount of early greats in this score. | -| `egd` | Integer | The amount of early goods in this score. | -| `ebd` | Integer | The amount of early bads in this score. | -| `epr` | Integer | The amount of early poors in this score. | -| `lpg` | Integer | The amount of late PGreats in this score. | -| `lgr` | Integer | The amount of late greats in this score. | -| `lgd` | Integer | The amount of late goods in this score. | -| `lbd` | Integer | The amount of late bads in this score. | -| `lpr` | Integer | The amount of late poors in this score. | - -## Judgements - -The following judgements are defined: - -- `pgreat` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | A clearing algorithm that rewards you points based on how difficult an easy clear or hard clear was. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 10 sieglinde ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 20 sieglinde ratings. | - -## Difficulties - -- `CHART` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `genocideDan` | PROVIDED | NORMAL_1, NORMAL_2, NORMAL_3, NORMAL_4, NORMAL_5, NORMAL_6, NORMAL_7, NORMAL_8, NORMAL_9, NORMAL_10, INSANE_1, INSANE_2, INSANE_3, INSANE_4, INSANE_5, INSANE_6, INSANE_7, INSANE_8, INSANE_9, INSANE_10, INSANE_KAIDEN, OVERJOY -| `stslDan` | PROVIDED | SL0, SL1, SL2, SL3, SL4, SL5, SL6, SL7, SL8, SL9, SL10, SL11, SL12, ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8, ST9, ST10, ST11, ST12 -| `newGenerationDan` | PROVIDED | NORMAL_1, NORMAL_2, NORMAL_3, NORMAL_4, NORMAL_5, NORMAL_6, NORMAL_7, NORMAL_8, NORMAL_9, NORMAL_10, INSANE_0, INSANE_1, INSANE_2, INSANE_3, INSANE_4, INSANE_5, INSANE_6, INSANE_7, INSANE_8, INSANE_9, INSANE_10, INSANE_KAIDEN -| `lnDan` | PROVIDED | DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, KAIDEN, OVERJOY, UDON -| `scratchDan` | PROVIDED | KYU_7, KYU_6, KYU_5, KYU_4, KYU_3, KYU_2, KYU_1, DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, KAIDEN - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `bmsChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/chunithm-Single.md b/old-docs/docs/game-support/games/chunithm-Single.md deleted file mode 100644 index c1303c7f6..000000000 --- a/old-docs/docs/game-support/games/chunithm-Single.md +++ /dev/null @@ -1,114 +0,0 @@ -# CHUNITHM Support - -This game has the internal GPTString of `chunithm:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1.01 million. | -| `noteLamp` | "NONE", "FULL COMBO", "ALL JUSTICE", "ALL JUSTICE CRITICAL" | The type of combo this was. | -| `clearLamp` | "FAILED", "CLEAR", "HARD", "BRAVE", "ABSOLUTE", "CATASTROPHY" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `scoreGraph` | Array<Decimal> | The history of the projected score, queried in one-second intervals. | -| `lifeGraph` | Array<Decimal> | Challenge gauge history, queried in one-second intervals. | - -## Judgements - -The following judgements are defined: - -- `jcrit` -- `justice` -- `attack` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `rating` | The rating value of this score. This is identical to the system used in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveRating` | The average of your best 10 ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveRating` | The average of your best 50 ratings. | - -## Difficulties - -- `BASIC` -- `ADVANCED` -- `EXPERT` -- `MASTER` -- `ULTIMA` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | BLUE, GREEN, ORANGE, RED, PURPLE, COPPER, SILVER, GOLD, PLATINUM, RAINBOW, RAINBOW_II, RAINBOW_III, RAINBOW_IV, RAINBOW_EX_I, RAINBOW_EX_II, RAINBOW_EX_III -| `dan` | PROVIDED | DAN_I, DAN_II, DAN_III, DAN_IV, DAN_V, DAN_INFINITE -| `emblem` | PROVIDED | DAN_I, DAN_II, DAN_III, DAN_IV, DAN_V, DAN_INFINITE - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `paradiselost` | PARADISE LOST | -| `new` | NEW | -| `newplus` | NEW PLUS | -| `sun` | SUN | -| `sun-intl` | SUN International | -| `sun-omni` | SUN Omnimix | -| `sunplus` | SUN PLUS | -| `sunplus-intl` | SUN PLUS International | -| `sunplus-omni` | SUN PLUS Omnimix | -| `luminous` | LUMINOUS | -| `luminous-intl` | LUMINOUS International | -| `luminous-omni` | LUMINOUS Omnimix | -| `luminousplus` | LUMINOUS PLUS | -| `luminousplus-intl` | LUMINOUS PLUS International | -| `luminousplus-omni` | LUMINOUS PLUS Omnimix | -| `verse` | VERSE | -| `verse-intl` | VERSE International | -| `verse-omni` | VERSE Omnimix | -| `xverse` | X-VERSE | -| `xverse-intl` | X-VERSE International | -| `xverse-omni` | X-VERSE Omnimix | -| `xversex` | X-VERSE-X | -| `xversex-intl` | X-VERSE-X International | -| `xversex-omni` | X-VERSE-X Omnimix | - -## Supported Match Types - -- `inGameID` -- `songTitle` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/ddr-DP.md b/old-docs/docs/game-support/games/ddr-DP.md deleted file mode 100644 index b58b8d241..000000000 --- a/old-docs/docs/game-support/games/ddr-DP.md +++ /dev/null @@ -1,96 +0,0 @@ -# DDR (DP) Support - -This game has the internal GPTString of `ddr:DP`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1 million. | -| `lamp` | "FAILED", "ASSIST", "CLEAR", "FULL COMBO", "GREAT FULL COMBO", "PERFECT FULL COMBO", "MARVELOUS FULL COMBO", "LIFE4" | The type of clear this user got. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "E", "D", "D+", "C-", "C", "C+", "B-", "B", "B+", "A-", "A", "A+", "AA-", "AA", "AA+", "AAA" | The grade this score was. Note that grades are capped at F if this was a fail. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `flare` | "0", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "EX" | The Flare rank. If no Flare is provided, Flare 0 is chosen by default. | -| `exScore` | Integer | The EXScore value. Marvelous and O.K. judgements are worth 3 points, Perfect judgements are worth 2 points, Great judgements are worth 1 point, and Good and lower judgements are not worth any points. | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `MARVELOUS` -- `PERFECT` -- `GREAT` -- `GOOD` -- `MISS` -- `OK` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Flare Skill as it's implemented in DDR World. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Average of your 10 best Flare Points this session | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Flare Skill as it's implemented in DDR World, taking 30 best flare points from 3 different categories: CLASSIC (DDR 1st~X3 vs 2ndMIX), WHITE (DDR(2013)~DDR A), GOLD (DDR A20~WORLD). | - -## Difficulties - -- `BEGINNER` -- `BASIC` -- `DIFFICULT` -- `EXPERT` -- `CHALLENGE` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `flare` | DERIVED | NONE, NONE+, NONE++, NONE+++, MERCURY, MERCURY+, MERCURY++, MERCURY+++, VENUS, VENUS+, VENUS++, VENUS+++, EARTH, EARTH+, EARTH++, EARTH+++, MARS, MARS+, MARS++, MARS+++, JUPITER, JUPITER+, JUPITER++, JUPITER+++, SATURN, SATURN+, SATURN++, SATURN+++, URANUS, URANUS+, URANUS++, URANUS+++, NEPTUNE, NEPTUNE+, NEPTUNE++, NEPTUNE+++, SUN, SUN+, SUN++, SUN+++, WORLD - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `a` | A | -| `a20` | A20 | -| `a20plus` | A20+ | -| `a3` | A3 | -| `konaste` | Konaste | -| `world` | World | - -## Supported Match Types - -- `inGameID` -- `songTitle` -- `tachiSongID` -- `ddrSongHash` \ No newline at end of file diff --git a/old-docs/docs/game-support/games/ddr-SP.md b/old-docs/docs/game-support/games/ddr-SP.md deleted file mode 100644 index d2c33d8bd..000000000 --- a/old-docs/docs/game-support/games/ddr-SP.md +++ /dev/null @@ -1,96 +0,0 @@ -# DDR (SP) Support - -This game has the internal GPTString of `ddr:SP`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1 million. | -| `lamp` | "FAILED", "ASSIST", "CLEAR", "FULL COMBO", "GREAT FULL COMBO", "PERFECT FULL COMBO", "MARVELOUS FULL COMBO", "LIFE4" | The type of clear this user got. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "E", "D", "D+", "C-", "C", "C+", "B-", "B", "B+", "A-", "A", "A+", "AA-", "AA", "AA+", "AAA" | The grade this score was. Note that grades are capped at F if this was a fail. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `flare` | "0", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "EX" | The Flare rank. If no Flare is provided, Flare 0 is chosen by default. | -| `exScore` | Integer | The EXScore value. Marvelous and O.K. judgements are worth 3 points, Perfect judgements are worth 2 points, Great judgements are worth 1 point, and Good and lower judgements are not worth any points. | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `MARVELOUS` -- `PERFECT` -- `GREAT` -- `GOOD` -- `MISS` -- `OK` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Flare Skill as it's implemented in DDR World. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Average of your 10 best Flare Points this session | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `flareSkill` | Flare Skill as it's implemented in DDR World, taking 30 best flare points from 3 different categories: CLASSIC (DDR 1st~X3 vs 2ndMIX), WHITE (DDR(2013)~DDR A), GOLD (DDR A20~WORLD). | - -## Difficulties - -- `BEGINNER` -- `BASIC` -- `DIFFICULT` -- `EXPERT` -- `CHALLENGE` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `flare` | DERIVED | NONE, NONE+, NONE++, NONE+++, MERCURY, MERCURY+, MERCURY++, MERCURY+++, VENUS, VENUS+, VENUS++, VENUS+++, EARTH, EARTH+, EARTH++, EARTH+++, MARS, MARS+, MARS++, MARS+++, JUPITER, JUPITER+, JUPITER++, JUPITER+++, SATURN, SATURN+, SATURN++, SATURN+++, URANUS, URANUS+, URANUS++, URANUS+++, NEPTUNE, NEPTUNE+, NEPTUNE++, NEPTUNE+++, SUN, SUN+, SUN++, SUN+++, WORLD - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `a` | A | -| `a20` | A20 | -| `a20plus` | A20+ | -| `a3` | A3 | -| `konaste` | Konaste | -| `world` | World | - -## Supported Match Types - -- `inGameID` -- `songTitle` -- `tachiSongID` -- `ddrSongHash` \ No newline at end of file diff --git a/old-docs/docs/game-support/games/gitadora-Dora.md b/old-docs/docs/game-support/games/gitadora-Dora.md deleted file mode 100644 index fdae54a64..000000000 --- a/old-docs/docs/game-support/games/gitadora-Dora.md +++ /dev/null @@ -1,91 +0,0 @@ -# GITADORA (Dora) Support - -This game has the internal GPTString of `gitadora:Dora`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | The percent this score was worth. Sometimes referred to as 'Achievement Rate' in game. This is a value between 0 and 100. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "EXCELLENT" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "C", "B", "A", "S", "SS", "MAX" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `perfect` -- `great` -- `good` -- `ok` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `skill` | Skill Rating as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `skill` | The average of your best 10 skill ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveSkill` | Your best 50 skill levels added together, regardless of whether the chart is HOT or not. | - -## Difficulties - -- `BASIC` -- `ADVANCED` -- `EXTREME` -- `MASTER` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | WHITE, ORANGE, ORANGE_GRD, YELLOW, YELLOW_GRD, GREEN, GREEN_GRD, BLUE, BLUE_GRD, PURPLE, PURPLE_GRD, RED, RED_GRD, BRONZE, SILVER, GOLD, RAINBOW - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `konaste` | Konaste | -| `fuzzUp` | FUZZ-UP | -| `highVoltage` | HIGH-VOLTAGE | -| `nextage` | NEX+AGE | -| `exchain` | EXCHAIN | -| `matixx` | Matixx | - -## Supported Match Types - -- `inGameID` -- `songTitle` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/gitadora-Gita.md b/old-docs/docs/game-support/games/gitadora-Gita.md deleted file mode 100644 index d8ef0aec3..000000000 --- a/old-docs/docs/game-support/games/gitadora-Gita.md +++ /dev/null @@ -1,95 +0,0 @@ -# GITADORA (Gita) Support - -This game has the internal GPTString of `gitadora:Gita`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | The percent this score was worth. Sometimes referred to as 'Achievement Rate' in game. This is a value between 0 and 100. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "EXCELLENT" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "C", "B", "A", "S", "SS", "MAX" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `perfect` -- `great` -- `good` -- `ok` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `skill` | Skill Rating as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `skill` | The average of your best 10 skill ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveSkill` | Your best 50 skill levels added together, regardless of whether the chart is HOT or not. | - -## Difficulties - -- `BASIC` -- `ADVANCED` -- `EXTREME` -- `MASTER` -- `BASS BASIC` -- `BASS ADVANCED` -- `BASS EXTREME` -- `BASS MASTER` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | WHITE, ORANGE, ORANGE_GRD, YELLOW, YELLOW_GRD, GREEN, GREEN_GRD, BLUE, BLUE_GRD, PURPLE, PURPLE_GRD, RED, RED_GRD, BRONZE, SILVER, GOLD, RAINBOW - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `konaste` | Konaste | -| `fuzzUp` | FUZZ-UP | -| `highVoltage` | HIGH-VOLTAGE | -| `nextage` | NEX+AGE | -| `exchain` | EXCHAIN | -| `matixx` | Matixx | - -## Supported Match Types - -- `inGameID` -- `songTitle` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/iidx-DP.md b/old-docs/docs/game-support/games/iidx-DP.md deleted file mode 100644 index b2f8bfa66..000000000 --- a/old-docs/docs/game-support/games/iidx-DP.md +++ /dev/null @@ -1,157 +0,0 @@ -# beatmania IIDX (DP) Support - -This game has the internal GPTString of `iidx:DP`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in IIDX. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `comboBreak` | Integer | The amount of times combo was broken. | -| `gaugeHistory` | Array<Decimal \| null > | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `scoreHistory` | Array<Decimal \| null > | A snapshot of the user's ghost throughout the chart. The values may be null. | -| `gsmEasy` | Array<Decimal \| null > | If GSM is used, this stores the easy gauge history. | -| `gsmNormal` | Array<Decimal \| null > | If GSM is used, this stores the normal gauge history. | -| `gsmHard` | Array<Decimal \| null > | If GSM is used, this stores the hard gauge history. | -| `gsmEXHard` | Array<Decimal \| null > | If GSM is used, this stores the ex-hard gauge history. | - -## Judgements - -The following judgements are defined: - -- `pgreat` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | A rating system that values your clear lamps on charts. Tierlist information is taken into account. | -| `BPI` | A rating system for Kaiden level play. Only applies to 11s and 12s. A BPI of 0 states the score is equal to the Kaiden Average for that chart. A BPI of 100 is equal to the world record. | - -### Session Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | An average of the best 10 ktLampRatings this session. | -| `BPI` | An average of the best 10 BPIs this session. | - -### Profile Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | An average of your best 20 ktLampRatings. | -| `BPI` | An average of your best 20 BPIs. | - -## Difficulties - -- `NORMAL` -- `HYPER` -- `ANOTHER` -- `LEGGENDARIA` -- `All Scratch NORMAL` -- `All Scratch HYPER` -- `All Scratch ANOTHER` -- `All Scratch LEGGENDARIA` -- `Kichiku NORMAL` -- `Kichiku HYPER` -- `Kichiku ANOTHER` -- `Kichiku LEGGENDARIA` -- `Kiraku NORMAL` -- `Kiraku HYPER` -- `Kiraku ANOTHER` -- `Kiraku LEGGENDARIA` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `dan` | PROVIDED | KYU_7, KYU_6, KYU_5, KYU_4, KYU_3, KYU_2, KYU_1, DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, CHUUDEN, KAIDEN - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `20` | tricoro | -| `21` | SPADA | -| `22` | PENDUAL | -| `23` | copula | -| `24` | SINOBUZ | -| `25` | CANNON BALLERS | -| `26` | ROOTAGE | -| `27` | HEROIC VERSE | -| `28` | BISTROVER | -| `29` | CastHour | -| `30` | Resident | -| `31` | Epolis | -| `32` | Pinky Crush | -| `33` | Sparkle Shower | -| `3-cs` | 3rd Style CS | -| `4-cs` | 4th Style CS | -| `5-cs` | 5th Style CS | -| `6-cs` | 6th Style CS | -| `7-cs` | 7th Style CS | -| `8-cs` | 8th Style CS | -| `9-cs` | 9th Style CS | -| `10-cs` | 10th Style CS | -| `11-cs` | IIDX RED CS | -| `12-cs` | HAPPY SKY CS | -| `13-cs` | DISTORTED CS | -| `14-cs` | GOLD CS | -| `15-cs` | DJ TROOPERS CS | -| `16-cs` | EMPRESS CS | -| `26-omni` | ROOTAGE Omnimix | -| `27-omni` | HEROIC VERSE Omnimix | -| `28-omni` | BISTROVER Omnimix | -| `29-omni` | CastHour Omnimix | -| `30-omni` | Resident Omnimix | -| `31-omni` | Epolis Omnimix | -| `32-omni` | Pinky Crush Omnimix | -| `27-2dxtra` | HEROIC VERSE 2dxtra | -| `28-2dxtra` | BISTROVER 2dxtra | -| `30-2dxtra` | RESIDENT 2dxtra | -| `31-2dxtra` | Epolis 2dxtra | -| `bmus` | BEATMANIA US | -| `inf` | INFINITAS | - -## Supported Match Types - -- `inGameID` -- `tachiSongID` -- `songTitle` diff --git a/old-docs/docs/game-support/games/iidx-SP.md b/old-docs/docs/game-support/games/iidx-SP.md deleted file mode 100644 index f221726e8..000000000 --- a/old-docs/docs/game-support/games/iidx-SP.md +++ /dev/null @@ -1,157 +0,0 @@ -# beatmania IIDX (SP) Support - -This game has the internal GPTString of `iidx:SP`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in IIDX. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `comboBreak` | Integer | The amount of times combo was broken. | -| `gaugeHistory` | Array<Decimal \| null > | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `scoreHistory` | Array<Decimal \| null > | A snapshot of the user's ghost throughout the chart. The values may be null. | -| `gsmEasy` | Array<Decimal \| null > | If GSM is used, this stores the easy gauge history. | -| `gsmNormal` | Array<Decimal \| null > | If GSM is used, this stores the normal gauge history. | -| `gsmHard` | Array<Decimal \| null > | If GSM is used, this stores the hard gauge history. | -| `gsmEXHard` | Array<Decimal \| null > | If GSM is used, this stores the ex-hard gauge history. | - -## Judgements - -The following judgements are defined: - -- `pgreat` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | A rating system that values your clear lamps on charts. Tierlist information is taken into account. | -| `BPI` | A rating system for Kaiden level play. Only applies to 11s and 12s. A BPI of 0 states the score is equal to the Kaiden Average for that chart. A BPI of 100 is equal to the world record. | - -### Session Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | An average of the best 10 ktLampRatings this session. | -| `BPI` | An average of the best 10 BPIs this session. | - -### Profile Rating Algorithms - -The default rating algorithm is `ktLampRating`. - -| Name | Description | -| :: | :: | -| `ktLampRating` | An average of your best 20 ktLampRatings. | -| `BPI` | An average of your best 20 BPIs. | - -## Difficulties - -- `NORMAL` -- `HYPER` -- `ANOTHER` -- `LEGGENDARIA` -- `All Scratch NORMAL` -- `All Scratch HYPER` -- `All Scratch ANOTHER` -- `All Scratch LEGGENDARIA` -- `Kichiku NORMAL` -- `Kichiku HYPER` -- `Kichiku ANOTHER` -- `Kichiku LEGGENDARIA` -- `Kiraku NORMAL` -- `Kiraku HYPER` -- `Kiraku ANOTHER` -- `Kiraku LEGGENDARIA` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `dan` | PROVIDED | KYU_7, KYU_6, KYU_5, KYU_4, KYU_3, KYU_2, KYU_1, DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, CHUUDEN, KAIDEN - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `20` | tricoro | -| `21` | SPADA | -| `22` | PENDUAL | -| `23` | copula | -| `24` | SINOBUZ | -| `25` | CANNON BALLERS | -| `26` | ROOTAGE | -| `27` | HEROIC VERSE | -| `28` | BISTROVER | -| `29` | CastHour | -| `30` | Resident | -| `31` | Epolis | -| `32` | Pinky Crush | -| `33` | Sparkle Shower | -| `3-cs` | 3rd Style CS | -| `4-cs` | 4th Style CS | -| `5-cs` | 5th Style CS | -| `6-cs` | 6th Style CS | -| `7-cs` | 7th Style CS | -| `8-cs` | 8th Style CS | -| `9-cs` | 9th Style CS | -| `10-cs` | 10th Style CS | -| `11-cs` | IIDX RED CS | -| `12-cs` | HAPPY SKY CS | -| `13-cs` | DISTORTED CS | -| `14-cs` | GOLD CS | -| `15-cs` | DJ TROOPERS CS | -| `16-cs` | EMPRESS CS | -| `26-omni` | ROOTAGE Omnimix | -| `27-omni` | HEROIC VERSE Omnimix | -| `28-omni` | BISTROVER Omnimix | -| `29-omni` | CastHour Omnimix | -| `30-omni` | Resident Omnimix | -| `31-omni` | Epolis Omnimix | -| `32-omni` | Pinky Crush Omnimix | -| `27-2dxtra` | HEROIC VERSE 2dxtra | -| `28-2dxtra` | BISTROVER 2dxtra | -| `30-2dxtra` | RESIDENT 2dxtra | -| `31-2dxtra` | Epolis 2dxtra | -| `bmus` | BEATMANIA US | -| `inf` | INFINITAS | - -## Supported Match Types - -- `inGameID` -- `tachiSongID` -- `songTitle` diff --git a/old-docs/docs/game-support/games/itg-Stamina.md b/old-docs/docs/game-support/games/itg-Stamina.md deleted file mode 100644 index 6e96ed2fb..000000000 --- a/old-docs/docs/game-support/games/itg-Stamina.md +++ /dev/null @@ -1,86 +0,0 @@ -# ITG Support - -This game has the internal GPTString of `itg:Stamina`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `scorePercent` | Decimal | The % value this score was worth. This is a number between 0 and 100. Note that negative %s, although existing in ITG, are not supported. | -| `survivedPercent` | Decimal | How far this user survived through the chart. For clears, this should be 100, if the user got halfway through, this should be 50, etc. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "FULL EXCELLENT COMBO", "QUAD", "QUINT" | The type of clear this user got. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "D", "C", "B", "A", "S", "★", "★★", "★★★", "★★★★" | The grade this score was. Note that grades are capped at F if this was a fail. | -| `finalPercent` | Decimal | A combination of `survivedPercent` and `scorePercent`. This metric is `survivedPercent` if the player didn't clear the chart. Otherwise, it's their `scorePercent` + 100. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `lifebarHistory` | Array<Decimal> | A snapshot of how much life the player had throughout the chart. | - -## Judgements - -The following judgements are defined: - -- `fantastic+` -- `fantastic` -- `excellent` -- `great` -- `decent` -- `wayoff` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -The default rating algorithm is `blockRating`. - -| Name | Description | -| :: | :: | -| `blockRating` | How much this clear is worth. | -| `fastest32` | The fastest BPM this score streamed 32 measures straight for. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `blockRating` | An average of your best 5 block levels cleared this session. | - -### Profile Rating Algorithms - -The default rating algorithm is `highestBlock`. - -| Name | Description | -| :: | :: | -| `highestBlock` | The highest block level this player has cleared. | -| `fastest32` | The fastest BPM this user has streamed 32 unbroken measures at. | - -## Difficulties - -This game uses dynamic difficulties. A difficulty name may be any string, provided `songID` + `playtype` + `difficulty` is unique. - -## Classes - -| Name | Type | Values | -| :: | :: | :: | - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `itgChartHash` diff --git a/old-docs/docs/game-support/games/jubeat-Single.md b/old-docs/docs/game-support/games/jubeat-Single.md deleted file mode 100644 index cb158e183..000000000 --- a/old-docs/docs/game-support/games/jubeat-Single.md +++ /dev/null @@ -1,103 +0,0 @@ -# jubeat Support - -This game has the internal GPTString of `jubeat:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1 million. | -| `musicRate` | Decimal | The music rate for this score. This is between 0 and 100 on normal difficulties, and 0 and 120 for hard-mode difficulties. This should be submitted to one decimal place. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "EXCELLENT" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "E", "D", "C", "B", "A", "S", "SS", "SSS", "EXC" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `musicBar` | Array<Decimal> | A snapshot of how well the player did in each part of the song | - -## Judgements - -The following judgements are defined: - -- `perfect` -- `great` -- `good` -- `poor` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `jubility` | Jubility as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `jubility` | The average of your best 10 jubilities this session. | - -### Profile Rating Algorithms - -The default rating algorithm is `jubility`. - -| Name | Description | -| :: | :: | -| `jubility` | Your profile jubility. This takes your best 30 scores on PICK UP songs, and your best 30 elsewhere. | -| `naiveJubility` | A naive version of jubility which just adds together your best 60 scores. | - -## Difficulties - -- `BSC` -- `ADV` -- `EXT` -- `HARD BSC` -- `HARD ADV` -- `HARD EXT` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | BLACK, YELLOW_GREEN, GREEN, LIGHT_BLUE, BLUE, VIOLET, PURPLE, PINK, ORANGE, GOLD - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `jubeat` | jubeat | -| `ripples` | ripples | -| `knit` | knit | -| `copious` | copious | -| `saucer` | saucer | -| `prop` | prop | -| `qubell` | Qubell | -| `clan` | clan | -| `festo` | festo | -| `festo-omni` | festo Omnimix | -| `ave` | Ave. | -| `beyond` | beyond the Ave. | - -## Supported Match Types - -- `inGameID` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/maimai-Single.md b/old-docs/docs/game-support/games/maimai-Single.md deleted file mode 100644 index 0955ad033..000000000 --- a/old-docs/docs/game-support/games/maimai-Single.md +++ /dev/null @@ -1,89 +0,0 @@ -# maimai Support - -This game has the internal GPTString of `maimai:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | The percent this score was worth. Sometimes called 'rate' in game. This is upper-bounded by how many BREAK notes the chart has. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "ALL PERFECT", "ALL PERFECT+" | The type of clear this score was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `perfect` -- `great` -- `good` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | Rating as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | The average of your best 10 ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveRate` | An average of your 30 best ratings. This is different from the rating in-game, as that is song-based and takes into account recent scores. | - -## Difficulties - -- `Easy` -- `Basic` -- `Advanced` -- `Expert` -- `Master` -- `Re:Master` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | WHITE, BLUE, GREEN, YELLOW, RED, PURPLE, BRONZE, SILVER, GOLD, RAINBOW -| `dan` | PROVIDED | DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, KAIDEN, SHINDAN_1, SHINDAN_2, SHINDAN_3, SHINDAN_4, SHINDAN_5, SHINDAN_6, SHINDAN_7, SHINDAN_8, SHINDAN_9, SHINDAN_10, SHINKAIDEN - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `finale` | FiNALE | - -## Supported Match Types - -- `songTitle` -- `tachiSongID` -- `inGameID` -- `inGameStrID` diff --git a/old-docs/docs/game-support/games/maimaidx-Single.md b/old-docs/docs/game-support/games/maimaidx-Single.md deleted file mode 100644 index bbfd7a118..000000000 --- a/old-docs/docs/game-support/games/maimaidx-Single.md +++ /dev/null @@ -1,107 +0,0 @@ -# maimai DX Support - -This game has the internal GPTString of `maimaidx:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `percent` | Decimal | The percent this score was worth. Sometimes called 'rate' in game. This is between 0 and 101. | -| `lamp` | "FAILED", "CLEAR", "FULL COMBO", "FULL COMBO+", "ALL PERFECT", "ALL PERFECT+" | The type of clear this score was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `percentGraph` | Array<Decimal \| null > | The history of the projected achievement, queried in one-second intervals. | -| `lifeGraph` | Array<Decimal \| null > | Life count history, queried in one-second intervals. | - -## Judgements - -The following judgements are defined: - -- `pcrit` -- `perfect` -- `great` -- `good` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | Rating as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | The average of your best 10 ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveRate` | A naive rating algorithm that just sums your 50 best scores. | - -## Difficulties - -- `Basic` -- `Advanced` -- `Expert` -- `Master` -- `Re:Master` -- `DX Basic` -- `DX Advanced` -- `DX Expert` -- `DX Master` -- `DX Re:Master` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | WHITE, BLUE, GREEN, YELLOW, RED, PURPLE, BRONZE, SILVER, GOLD, PLATINUM, RAINBOW -| `dan` | PROVIDED | DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, SHINDAN_1, SHINDAN_2, SHINDAN_3, SHINDAN_4, SHINDAN_5, SHINDAN_6, SHINDAN_7, SHINDAN_8, SHINDAN_9, SHINDAN_10, SHINKAIDEN, URAKAIDEN -| `matchingClass` | PROVIDED | B5, B4, B3, B2, B1, A5, A5, A4, A3, A2, A1, S5, S4, S3, S2, S1, SS5, SS4, SS3, SS2, SS1, SSS5, SSS4, SSS3, SSS2, SSS1, LEGEND - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `universeplus` | UNiVERSE PLUS | -| `festival` | FESTiVAL | -| `festivalplus` | FESTiVAL PLUS | -| `buddies` | BUDDiES | -| `buddies-omni` | BUDDiES Omnimix | -| `buddiesplus` | BUDDiES PLUS | -| `buddiesplus-omni` | BUDDiES PLUS Omnimix | -| `prism` | PRiSM | -| `prism-omni` | PRiSM Omnimix | -| `prismplus` | PRiSM PLUS | -| `prismplus-omni` | PRiSM PLUS Omnimix | -| `circle` | CiRCLE | - -## Supported Match Types - -- `songTitle` -- `tachiSongID` -- `inGameID` diff --git a/old-docs/docs/game-support/games/museca-Single.md b/old-docs/docs/game-support/games/museca-Single.md deleted file mode 100644 index 53aaf81a2..000000000 --- a/old-docs/docs/game-support/games/museca-Single.md +++ /dev/null @@ -1,83 +0,0 @@ -# MÚSECA Support - -This game has the internal GPTString of `museca:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1 million. | -| `lamp` | "FAILED", "CLEAR", "CONNECT ALL", "PERFECT CONNECT ALL" | The type of clear this score was. **Note:** we define a CLEAR as being >= 800k, and FAILED as anything less. We do not respect MUSECA's story mode for clear/failed types. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "没", "拙", "凡", "佳", "良", "優", "秀", "傑", "傑G" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `critical` -- `near` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `curatorSkill` | Curator Skill as it's implemented in-game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `curatorSkill` | The average of your best 10 Curator skills this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `curatorSkill` | The sum of your best 20 Curator Skills. This is identical to how it's calculated in-game. | - -## Difficulties - -- `Green` -- `Yellow` -- `Red` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `1.5` | 1 + 1/2 | -| `1.5-b` | 1 + 1/2 Rev. B | - -## Supported Match Types - -- `songTitle` -- `tachiSongID` -- `inGameID` diff --git a/old-docs/docs/game-support/games/ongeki-Single.md b/old-docs/docs/game-support/games/ongeki-Single.md deleted file mode 100644 index d5dc25983..000000000 --- a/old-docs/docs/game-support/games/ongeki-Single.md +++ /dev/null @@ -1,134 +0,0 @@ -# O.N.G.E.K.I. Support - -This game has the internal GPTString of `ongeki:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | Known in-game as 'Technical Score'. It ranges between 0 and 1,010,000, where notes are worth 950,000, and bells 60,000. | -| `noteLamp` | "LOSS", "CLEAR", "FULL COMBO", "ALL BREAK", "ALL BREAK+" | The primary lamp. A clear is a draw or a win in-game. | -| `bellLamp` | "NONE", "FULL BELL" | Tracks whether all bells in the chart have been collected. | -| `platinumScore` | Integer | The Platinum Score value. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "SS", "SSS", "SSS+" | The grade this score was. | -| `platinumStars` | The number of platinum stars of this score | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The number of non-critical mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The number of non-critical mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `damage` | Integer | The number of damage ticks received. | -| `bellCount` | Integer | The number of bells collected. | -| `totalBellCount` | Integer | The maximum number of bells that could have been obtained at the time of the play's end. | -| `scoreGraph` | Array<Decimal \| null > | The history of the projected score, queried in one-second intervals. | -| `platinumGraph` | Array<Decimal \| null > | The Platinum Score history, queried in one-second intervals. | -| `bellGraph` | Array<Decimal \| null > | The history of the number of bells missed, queried in one-second intervals. | -| `lifeGraph` | Array<Decimal \| null > | The life gauge history, queried in one-second intervals. | - -## Judgements - -The following judgements are defined: - -- `cbreak` (critical break) -- `break` (red/regular break) -- `hit` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -The default rating algorithm is `rating`. - -| Name | Description | -| :: | :: | -| `rating` | A rating value of this score, capping at +2.0 at SSS+. This is identical to the system used in bright MEMORY and earlier versions. | -| `scoreRating` | A rating value of this score, capping at +2.7 at 1,010,000. This is identical to the system used in Re:Fresh. | -| `starRating` | A rating value of this score, based on stars derived from Platinum Score. This is identical to the system used in Re:Fresh. | -### Session Rating Algorithms - -The default rating algorithm is `naiveRating`. - -| Name | Description | -| :: | :: | -| `naiveRating` | The average of your best 10 classic ratings this session. | -| `naiveScoreRating` | The average of your best 10 score ratings this session. | -| `starRating` | The average of your best 10 star ratings this session. | - -### Profile Rating Algorithms - -The default rating algorithm is `naiveRating`. - -| Name | Description | -| :: | :: | -| `naiveRating` | The average of your best 45 classic ratings. This is a simpler variant of the rating algorithm used in bright MEMORY and earlier versions, without distinguishing between new and old charts, and without taking recent scores into account. | -| `naiveRatingRefresh` | A weighted sum of the average of your best 60 score ratings, and your best 50 star ratings. This is a simpler variant of the rating algorithm used in Re:Fresh, without distinguishing between new and old charts. | -| `scoreRating` | The average of your best 60 score ratings. | -| `starRating` | The average of your best 50 star ratings. | - -## Difficulties - -- `BASIC` -- `ADVANCED` -- `EXPERT` -- `MASTER` -- `LUNATIC` -- `Re:MASTER` - -The `LUNATIC`/`Re:MASTER` split is transparent; your import script must assume every "white" chart is `LUNATIC`. - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `colour` | DERIVED | BLUE, GREEN, ORANGE, RED, PURPLE, COPPER, SILVER, GOLD, PLATINUM, RAINBOW, RAINBOW_SHINY, RAINBOW_EX, RAINBOW_EX_TRUE - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `brightMemory2Omni` | bright MEMORY Act.II Omnimix | -| `brightMemory3` | bright MEMORY Act.III | -| `brightMemory3Omni` | bright MEMORY Act.III Omnimix | -| `refresh` | Re:Fresh | -| `refreshOmni` | Re:Fresh Omnimix | - -## Supported Match Types - -- `songTitle` -- `tachiSongID` – deprecated; don't use this -- `inGameID` - -### Song Title Matching -There are several songs with non-unique names: - -- Singularity (technoplanet) `inGameID: 391` -- Singularity (ETIA.「Arcaea」) `inGameID: 454` -- Singularity (SEGA SOUND STAFF「セガNET麻雀 MJ」) `inGameID: 516` - -- Hand in Hand (livetune) `inGameID: 380` -- Hand in Hand (ユーフィリア(CV:高橋 李依)「アンジュ・ヴィエルジュ」) `inGameID: 212` - -- Perfect_Shining!! LUNATIC 0 (Loctest chart) `inGameID: 8003` -- Perfect_Shining!! LUNATIC 13+ (Re:Master) `inGameID: 8091` - -Most of these conflicts can be resolved by providing the `artist` field; the only exception is Perfect Shining, which uniquely has two LUNATIC charts and has to be matched by `inGameID`. -There are numerous songs with non-unique names (e.g. Singularity, Singularity, Singularity and Xingularity), but this can be resolved by providing the `artist` field. The only exception is Perfect Shining!!, which uniquely has two LUNATIC charts and has to be matched by `inGameID`: - -- LUNATIC 0 (Loctest chart) `inGameID: 8003` -- Re:MASTER 13+ `inGameID: 8091` diff --git a/old-docs/docs/game-support/games/pms-Controller.md b/old-docs/docs/game-support/games/pms-Controller.md deleted file mode 100644 index 0d9161bf0..000000000 --- a/old-docs/docs/game-support/games/pms-Controller.md +++ /dev/null @@ -1,97 +0,0 @@ -# PMS (Controller) Support - -This game has the internal GPTString of `pms:Controller`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in IIDX. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `gaugeHistory` | Array<Decimal> | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `gaugeHistoryEasy` | Array<Decimal> | The easy gauge history. | -| `gaugeHistoryGroove` | Array<Decimal> | The groove gauge history. | -| `gaugeHistoryHard` | Array<Decimal> | The hard gauge history. | -| `epg` | Integer | The amount of early PGreats in this score. | -| `egr` | Integer | The amount of early greats in this score. | -| `egd` | Integer | The amount of early goods in this score. | -| `ebd` | Integer | The amount of early bads in this score. | -| `epr` | Integer | The amount of early poors in this score. | -| `lpg` | Integer | The amount of late PGreats in this score. | -| `lgr` | Integer | The amount of late greats in this score. | -| `lgd` | Integer | The amount of late goods in this score. | -| `lbd` | Integer | The amount of late bads in this score. | -| `lpr` | Integer | The amount of late poors in this score. | - -## Judgements - -The following judgements are defined: - -- `cool` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | A clearing algorithm that rewards you points based on how difficult an easy clear or hard clear was. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 10 sieglinde ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 20 sieglinde ratings. | - -## Difficulties - -- `CHART` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `dan` | PROVIDED | INSANE_1, INSANE_2, INSANE_3, INSANE_4, INSANE_5, INSANE_6, INSANE_7, INSANE_8, INSANE_9, INSANE_10, INSANE_KAIDEN, OVERJOY, UNDEFINED - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `bmsChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/pms-Keyboard.md b/old-docs/docs/game-support/games/pms-Keyboard.md deleted file mode 100644 index 6addbb02b..000000000 --- a/old-docs/docs/game-support/games/pms-Keyboard.md +++ /dev/null @@ -1,97 +0,0 @@ -# PMS (Keyboard) Support - -This game has the internal GPTString of `pms:Keyboard`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | EX Score. This should be between 0 and the maximum possible EX on this chart. | -| `lamp` | "NO PLAY", "FAILED", "ASSIST CLEAR", "EASY CLEAR", "CLEAR", "HARD CLEAR", "EX HARD CLEAR", "FULL COMBO" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX" | Grades as they are in IIDX. We also add MAX- (94.44...%) and MAX (100%) as their own grades for convenience. | -| `percent` | Decimal | EX Score divided by the maximum possible EX Score on this chart. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `bp` | Integer | The total bads + poors in this score. | -| `gauge` | Decimal | The life in percent (between 0 and 100) that was on the gauge at the end of the chart. | -| `gaugeHistory` | Array<Decimal> | A snapshot of the gauge percent throughout the chart. The values should be null from the point the user dies until the end of the chart. | -| `gaugeHistoryEasy` | Array<Decimal> | The easy gauge history. | -| `gaugeHistoryGroove` | Array<Decimal> | The groove gauge history. | -| `gaugeHistoryHard` | Array<Decimal> | The hard gauge history. | -| `epg` | Integer | The amount of early PGreats in this score. | -| `egr` | Integer | The amount of early greats in this score. | -| `egd` | Integer | The amount of early goods in this score. | -| `ebd` | Integer | The amount of early bads in this score. | -| `epr` | Integer | The amount of early poors in this score. | -| `lpg` | Integer | The amount of late PGreats in this score. | -| `lgr` | Integer | The amount of late greats in this score. | -| `lgd` | Integer | The amount of late goods in this score. | -| `lbd` | Integer | The amount of late bads in this score. | -| `lpr` | Integer | The amount of late poors in this score. | - -## Judgements - -The following judgements are defined: - -- `cool` -- `great` -- `good` -- `bad` -- `poor` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | A clearing algorithm that rewards you points based on how difficult an easy clear or hard clear was. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 10 sieglinde ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `sieglinde` | The average of your best 20 sieglinde ratings. | - -## Difficulties - -- `CHART` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `dan` | PROVIDED | INSANE_1, INSANE_2, INSANE_3, INSANE_4, INSANE_5, INSANE_6, INSANE_7, INSANE_8, INSANE_9, INSANE_10, INSANE_KAIDEN, OVERJOY, UNDEFINED - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `bmsChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/popn-9B.md b/old-docs/docs/game-support/games/popn-9B.md deleted file mode 100644 index 4ba1fe7ee..000000000 --- a/old-docs/docs/game-support/games/popn-9B.md +++ /dev/null @@ -1,89 +0,0 @@ -# pop'n music Support - -This game has the internal GPTString of `popn:9B`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. | -| `clearMedal` | "failedCircle", "failedDiamond", "failedStar", "easyClear", "clearCircle", "clearDiamond", "clearStar", "fullComboCircle", "fullComboDiamond", "fullComboStar", "perfect" | The clear medal for this score. This is a superset of lamps. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `lamp` | "FAILED", "EASY CLEAR", "CLEAR", "FULL COMBO", "PERFECT" | The lamp for this score. This is a subset of clearMedals, and is - as a result - derived from them. We keep both around as lamps are better for grouping up scores. | -| `grade` | "E", "D", "C", "B", "A", "AA", "AAA", "S" | The grade this score was worth. Note that scores are capped at a grade of A if they are a fail, regardless of how good the score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `gauge` | Decimal | The gauge value this score had at the end. This is a value between 0 and 100. | - -## Judgements - -The following judgements are defined: - -- `cool` -- `great` -- `good` -- `bad` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `classPoints` | Class Points as they're implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `classPoints` | The average of your best 10 class points this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveClassPoints` | A naive average of your best 20 scores. This is different to in game class points, as that is affected by recent scores, and not just your best scores. | - -## Difficulties - -- `Easy` -- `Normal` -- `Hyper` -- `EX` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `class` | DERIVED | KITTY, STUDENT, DELINQUENT, DETECTIVE, IDOL, GENERAL, HERMIT, GOD - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `peace` | peace | -| `kaimei` | Kaimei Riddles | -| `unilab` | Unilab | - -## Supported Match Types - -- `inGameID` -- `tachiSongID` -- `popnChartHash` diff --git a/old-docs/docs/game-support/games/sdvx-Single.md b/old-docs/docs/game-support/games/sdvx-Single.md deleted file mode 100644 index 089ee03c3..000000000 --- a/old-docs/docs/game-support/games/sdvx-Single.md +++ /dev/null @@ -1,99 +0,0 @@ -# SOUND VOLTEX Support - -This game has the internal GPTString of `sdvx:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 10 million. | -| `lamp` | "FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN" | The type of clear this was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S", "PUC" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `exScore` | Integer | The EXScore value. This is part of the scoreID, and is optional -- this metric did not exist before SDVX6, and is still optional. | -| `gauge` | Decimal | The amount of life in the gauge at the end of this chart. | - -## Judgements - -The following judgements are defined: - -- `critical` -- `near` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | VOLFORCE as it is implemented in SDVX6. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `ProfileVF6` | The average of your best 10 VF6s this session, multiplied to be on the same scale as profile VOLFORCE. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | Your best 50 VF6 values added together. | - -## Difficulties - -- `NOV` -- `ADV` -- `EXH` -- `INF` -- `GRV` -- `HVN` -- `VVD` -- `XCD` -- `MXM` -- `ULT` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `dan` | PROVIDED | DAN_1, DAN_2, DAN_3, DAN_4, DAN_5, DAN_6, DAN_7, DAN_8, DAN_9, DAN_10, DAN_11, INF -| `vfClass` | DERIVED | SIENNA_I, SIENNA_II, SIENNA_III, SIENNA_IV, COBALT_I, COBALT_II, COBALT_III, COBALT_IV, DANDELION_I, DANDELION_II, DANDELION_III, DANDELION_IV, CYAN_I, CYAN_II, CYAN_III, CYAN_IV, SCARLET_I, SCARLET_II, SCARLET_III, SCARLET_IV, CORAL_I, CORAL_II, CORAL_III, CORAL_IV, ARGENTO_I, ARGENTO_II, ARGENTO_III, ARGENTO_IV, ELDORA_I, ELDORA_II, ELDORA_III, ELDORA_IV, CRIMSON_I, CRIMSON_II, CRIMSON_III, CRIMSON_IV, IMPERIAL_I, IMPERIAL_II, IMPERIAL_III, IMPERIAL_IV - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `booth` | BOOTH | -| `inf` | infinite infection | -| `gw` | GRAVITY WARS | -| `heaven` | HEAVENLY HAVEN | -| `vivid` | VIVID WAVE | -| `exceed` | EXCEED GEAR | -| `konaste` | Konaste | - -## Supported Match Types - -- `sdvxInGameID` -- `songTitle` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/usc-Controller.md b/old-docs/docs/game-support/games/usc-Controller.md deleted file mode 100644 index f7d2b0d41..000000000 --- a/old-docs/docs/game-support/games/usc-Controller.md +++ /dev/null @@ -1,82 +0,0 @@ -# USC (Controller) Support - -This game has the internal GPTString of `usc:Controller`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 10 million. | -| `lamp` | "FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN" | The type of clear this score was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S", "PUC" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `gauge` | Decimal | The amount of life in the gauge when this chart finished. This is between 0 and 100. | - -## Judgements - -The following judgements are defined: - -- `critical` -- `near` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | VOLFORCE as it is implemented in SDVX6. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `ProfileVF6` | The average of your best 10 VF6s this session, multiplied to be on the same scale as profile VOLFORCE. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | Your best 50 VF6 values added together. | - -## Difficulties - -- `NOV` -- `ADV` -- `EXH` -- `INF` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `vfClass` | DERIVED | SIENNA_I, SIENNA_II, SIENNA_III, SIENNA_IV, COBALT_I, COBALT_II, COBALT_III, COBALT_IV, DANDELION_I, DANDELION_II, DANDELION_III, DANDELION_IV, CYAN_I, CYAN_II, CYAN_III, CYAN_IV, SCARLET_I, SCARLET_II, SCARLET_III, SCARLET_IV, CORAL_I, CORAL_II, CORAL_III, CORAL_IV, ARGENTO_I, ARGENTO_II, ARGENTO_III, ARGENTO_IV, ELDORA_I, ELDORA_II, ELDORA_III, ELDORA_IV, CRIMSON_I, CRIMSON_II, CRIMSON_III, CRIMSON_IV, IMPERIAL_I, IMPERIAL_II, IMPERIAL_III, IMPERIAL_IV - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `uscChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/usc-Keyboard.md b/old-docs/docs/game-support/games/usc-Keyboard.md deleted file mode 100644 index dab5c609f..000000000 --- a/old-docs/docs/game-support/games/usc-Keyboard.md +++ /dev/null @@ -1,82 +0,0 @@ -# USC (Keyboard/Other) Support - -This game has the internal GPTString of `usc:Keyboard`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 10 million. | -| `lamp` | "FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN" | The type of clear this score was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S", "PUC" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | -| `gauge` | Decimal | The amount of life in the gauge when this chart finished. This is between 0 and 100. | - -## Judgements - -The following judgements are defined: - -- `critical` -- `near` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | VOLFORCE as it is implemented in SDVX6. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `ProfileVF6` | The average of your best 10 VF6s this session, multiplied to be on the same scale as profile VOLFORCE. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `VF6` | Your best 50 VF6 values added together. | - -## Difficulties - -- `NOV` -- `ADV` -- `EXH` -- `INF` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `vfClass` | DERIVED | SIENNA_I, SIENNA_II, SIENNA_III, SIENNA_IV, COBALT_I, COBALT_II, COBALT_III, COBALT_IV, DANDELION_I, DANDELION_II, DANDELION_III, DANDELION_IV, CYAN_I, CYAN_II, CYAN_III, CYAN_IV, SCARLET_I, SCARLET_II, SCARLET_III, SCARLET_IV, CORAL_I, CORAL_II, CORAL_III, CORAL_IV, ARGENTO_I, ARGENTO_II, ARGENTO_III, ARGENTO_IV, ELDORA_I, ELDORA_II, ELDORA_III, ELDORA_IV, CRIMSON_I, CRIMSON_II, CRIMSON_III, CRIMSON_IV, IMPERIAL_I, IMPERIAL_II, IMPERIAL_III, IMPERIAL_IV - -## Versions - -This game has no versions, and presumably doesn't need to disambiguate its IDs. - -## Supported Match Types - -- `uscChartHash` -- `tachiSongID` diff --git a/old-docs/docs/game-support/games/wacca-Single.md b/old-docs/docs/game-support/games/wacca-Single.md deleted file mode 100644 index 24b3bb1bd..000000000 --- a/old-docs/docs/game-support/games/wacca-Single.md +++ /dev/null @@ -1,87 +0,0 @@ -# WACCA Support - -This game has the internal GPTString of `wacca:Single`. - -!!! note - For information on what each section means, please see [Common Config](../common-config/index.md). - -## Metrics - -For more information on what metrics are and how they work, see [TODO]! - -### Provided Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `score` | Integer | The score value. This is between 0 and 1 million. | -| `lamp` | "FAILED", "CLEAR", "MISSLESS", "FULL COMBO", "ALL MARVELOUS" | The type of clear this score was. | - -### Derived Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `grade` | "D", "C", "B", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+", "MASTER" | The grade this score was. | - -### Optional Metrics - -| Metric Name | Type | Description | -| :: | :: | :: | -| `fast` | Integer | The amount of mistakes in this score that were a result of hitting early. | -| `slow` | Integer | The amount of mistakes in this score that were a result of hitting late. | -| `maxCombo` | Integer | The largest combo in this score. | - -## Judgements - -The following judgements are defined: - -- `marvelous` -- `great` -- `good` -- `miss` - -## Rating Algorithms - -### Score Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | Rating as it's implemented in game. | - -### Session Rating Algorithms - -| Name | Description | -| :: | :: | -| `rate` | The average of your best 10 ratings this session. | - -### Profile Rating Algorithms - -| Name | Description | -| :: | :: | -| `naiveRate` | A naive rating algorithm that just sums your 50 best scores. | - -## Difficulties - -- `NORMAL` -- `HARD` -- `EXPERT` -- `INFERNO` - -## Classes - -| Name | Type | Values | -| :: | :: | :: | -| `stageUp` | PROVIDED | I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV -| `colour` | DERIVED | ASH, NAVY, YELLOW, RED, PURPLE, BLUE, SILVER, GOLD, RAINBOW - -## Versions - -| ID | Pretty Name | -| :: | :: | -| `reverse` | REVERSE | -| `plus` | PLUS | - -## Supported Match Types - -- `songTitle` -- `tachiSongID` -- `inGameID` \ No newline at end of file diff --git a/old-docs/docs/game-support/index.md b/old-docs/docs/game-support/index.md deleted file mode 100644 index d0ceee6a7..000000000 --- a/old-docs/docs/game-support/index.md +++ /dev/null @@ -1,26 +0,0 @@ -# Game Support - -Tachi is a *modular* score tracker. What that means is that you can define your own -support for games in Tachi, and as long as the module is loaded, that support will -be enabled on this Tachi instance. - -## What games are supported? - -See 'Game Information' in the sidebar for a list of all supported games and their configurations. - -## How do I write support for a game? - -Adding support for a game requires configuration in three places and a loading of `seeds`. - -You will need to: - -- [Create a configuration in common](./common-config/index.md). -- [Implement it in the server](./server-impl.md). -- [Implement it in the client](./client-impl.md). -- [Load songs, charts, folders, etc.](./seeds.md). - -For more information on how to write each module and what they contain, click on the specific item. - -## How do I enable that support? - -In your `server`'s `conf.json5` file, add the game to `TACHI_CONFIG.GAMES`. This will enable this module. diff --git a/old-docs/docs/game-support/seeds.md b/old-docs/docs/game-support/seeds.md deleted file mode 100644 index 2076686b7..000000000 --- a/old-docs/docs/game-support/seeds.md +++ /dev/null @@ -1,98 +0,0 @@ -# Adding Seeds - -With a [Common Configuration](./common-config/index.md) defined, we know what the songs and charts for this game should look like. - -Lets load them into the database seeds. - -## Quick Primer - -The database seeds are a folder in the monorepo: `seeds/collections`, which contain JSON files. - -These JSON files contain the state of a lot of our databases that need to be loaded. When changes are made to these seeds and committed to the main repository, a script will automatically apply those changes to the database. - -!!! info - For local usage, you can use `pnpm sync-database-local` in the terminal to sync - the database with your local seeds. - -## Adding songs and charts - -If they don't already exist, create new files for `songs-GAMENAME.json` and `charts-GAMENAME.json`. Place `[]` inside those files, as they should be arrays. - -It's left as an exercise for the reader to source the song and chart data for their game. You will likely need to write your own scripts. - -Once you've gotten that data, you need to convert it into Tachi's song/chart format. - -## Writing the files - -You can modify the JSON files however you want. It really doesn't matter. However, there is a `seeds/scripts/` folder with a bunch of scripts you can use -to ease this process. - -For things you only want to run a single time, place the script in the `seeds/scripts/personal` folder. -For things you want to keep around, place the script in the `seeds/rerunners` folder. Simple. - -The file `util.js` contains a bunch of miscellaneous utils for helping out, like `CreateChartID` or `MutateCollection`. - -## What do songs and charts look like? - -A song in Tachi looks like this: - -```json -{ - "altTitles": [], - "artist": "dj nagureo", - "data": { - // the things you defined in GAME_CONFIG.songData go here - }, - "id": 1, - "searchTerms": [], - "title": "5.1.1." -}, -``` - -For information on what each of these properties mean, see [Song Document](../schemas/song.md). - -A chart in Tachi looks like this: - -```json -{ - // This is a randomly generated 20 byte string. - // The utility function `CreateChartID` should be used. - "chartID": "70b80da02a2037d556026b412c386b2fd1e57dbd", - - "data": { - // this should be what you defined in GPT_CONFIG.chartData. - }, - - // If your difficulties are "FIXED", this should be one of the expected difficulties. - // Otherwise, any string goes here. - "difficulty": "Green", - - "level": "3", - "levelNum": 3, - - // this should be one of the playtypes for your game. - "playtype": "Single", - "songID": 1, - - // This should be an array of the versions this chart appears in. - // For more information, see Common Config's Versions documentation. - "versions": [ - "1.5", - "1.5-b" - ], - // See Common Config's Versions documentation. - "isPrimary": true -} -``` - -## Tables and Folders - -You'll probably want to create at least one table and some folders for your game. - -There are various utilities for this, like `scripts/rerunners/add-level-version-folders.js` for creating a traditional "Level 1, Level 2, Level 3" kind of table. - -## Loading the seeds - -Once you've modified the database seeds, test them with `pnpm test` inside the `seeds/scripts` folder. This will check a bunch of properties about the songs and charts you just made. - -If they fail, read why and make appropriate changes. If they pass, move to the root of the Tachi repository and run `pnpm sync-database-local`. This will load the changes into your MongoDB instance. diff --git a/old-docs/docs/game-support/server-impl.md b/old-docs/docs/game-support/server-impl.md deleted file mode 100644 index 0a18ced15..000000000 --- a/old-docs/docs/game-support/server-impl.md +++ /dev/null @@ -1,154 +0,0 @@ -# Implementing on the Server - -Now that we've got a config defined in `common/` for a GPT, we need to implement -parts of it on the server. - -## Where do Server Implementations go? - -Implementations should be written in `server/src/game-implementations/games/GAMENAME.ts`. - -Once you have written a config, go to `server/src/game-implementations/game-implementations.ts` and import it. Mount the game configuration on `GPT_SERVER_IMPLEMENTATIONS`. - -## `chartSpecificValidators` - -Any metrics you declared as being `chartSpecificMax: true` in the config need -an implementation here. You can declare a function that takes in the metric's value -and the chart the score is on and validate accordingly. - -These functions should return a string on error, and true on success. This is aligned -with how [Prudence](https://github.com/zkldi/Prudence) works, so you can re-use prudence -functions here. - -!!! example -```ts -musicRate: (rate, chart) => { -switch (chart.difficulty) { -case "BSC": -case "ADV": -case "EXT": -return p.isBetween(0, 100)(rate); - - case "HARD BSC": - case "HARD ADV": - case "HARD EXT": - return p.isBetween(0, 120)(rate); - } - }, - ``` - -## `scoreDeriver` - -Any derived metrics you declared are produced by a single function -`(scoreData, chart) => derivedMetrics` that returns all derived fields at once. - -!!! example -```ts -(scoreData, chart) => ({ - percent: (100 * scoreData.score) / (chart.data.notecount * 2), - grade: GetGrade(G, scoreData.score), -}); -``` - -## `scoreCalcs`, `sessionCalcs`, `profileCalcs` - -For any `{score, session, profile}RatingAlgs` you defined, implement them here. - -## `classDerivers` - -For all the classes you declared with `type: "DERIVED"`, implement the derivers here. - -## `goalCriteriaFormatters` - -When creating a goal on a metric, how should we format the title? - -``` -Get a score of 1234 on 5.1.1 SP ANOTHER -^^^^^^^^^^^^^^^^^^^^^^ -this bit -``` - -## `goalOutOfFormatters` - -When creating a goal on a metric, how should we format the "outOf" part? - -``` -HARD CLEAR/FULL COMBO - ^^^^^^^^ - this bit -``` - -## `goalProgressFormatters` - -How should we format the progress of this goal? - -``` -HARD CLEAR/FULL COMBO - ^^^^^^^^ - this bit -``` - -## `pbMergeFunctions` - -How should we combine scores into one PB? There is an _extraordinarily_ useful helper -function for this called `CreatePBMergeFor`. - -The way PBs are merged works like a chain: the first score is the best score this user -has on this chart for the `defaultMetric` declared in the config. Then, every -merge function defined in this pipeline is ran on the score and mutates the original. - -Eventually, you have a fully merged PB document. - -The below code defines a PB merger that gets the largest lamp. It will then run the -final function with the base score and the score it just fetched. - -In the event it doesn't find a score (i.e. the user has no scores with `optional.bp`) -the function will simply not be called. - -```ts -[ - CreatePBMergeFor("largest", "enumIndexes.lamp", "Best Lamp", (base, lamp) => { - base.scoreData.lamp = lamp.scoreData.lamp; - - base.scoreData.optional.gsmEasy = lamp.scoreData.optional.gsmEasy; - base.scoreData.optional.gsmNormal = lamp.scoreData.optional.gsmNormal; - base.scoreData.optional.gsmHard = lamp.scoreData.optional.gsmHard; - base.scoreData.optional.gsmEXHard = lamp.scoreData.optional.gsmEXHard; - - base.scoreData.optional.gauge = lamp.scoreData.optional.gauge; - base.scoreData.optional.gaugeHistory = lamp.scoreData.optional.gaugeHistory; - - base.scoreData.optional.comboBreak = lamp.scoreData.optional.comboBreak; - }), - CreatePBMergeFor("smallest", "optional.bp", "Lowest BP", (base, bp) => { - base.scoreData.optional.bp = bp.scoreData.optional.bp; - }), -]; -``` - -## `defaultMergeRefName` - -As mentioned above, the chain of PB functions starts by plucking the best score this -user has on this chart under the `defaultMetric`. What should we call that score? - -!!! example -For IIDX, this is "Best Score". For something like GITADORA, which only has percent, -this might be called "Best Percent". - -## `scoreValidators` - -Out of the box, Tachi will assume complete independence of all variables in a score. -However, this is often not the case, and there are certain things you expect to be true -between the metrics of a score. - -For example, you shouldn't be able to submit a `PERFECT ULTIMATE CHAIN` if your score -isn't 10 million - the two imply each other! - -In this part of the server implementation, you may specify as many validation functions -as you like. These assert relations between the fields on a score, and allow you -to restrict certain things. - -Like real life, passing judgements subjects you to more scrutiny -- getting a `FULL COMBO` with misses should likely fail a validation function. - -## That's it! - -The only thing left is to define the [Client Implementation](./client-impl.md)! diff --git a/old-docs/docs/images/advanced-search.png b/old-docs/docs/images/advanced-search.png deleted file mode 100644 index cafb1d796..000000000 Binary files a/old-docs/docs/images/advanced-search.png and /dev/null differ diff --git a/old-docs/docs/images/basic-search.png b/old-docs/docs/images/basic-search.png deleted file mode 100644 index 24d2fd14c..000000000 Binary files a/old-docs/docs/images/basic-search.png and /dev/null differ diff --git a/old-docs/docs/images/cells.png b/old-docs/docs/images/cells.png deleted file mode 100644 index e782c2fba..000000000 Binary files a/old-docs/docs/images/cells.png and /dev/null differ diff --git a/old-docs/docs/images/default-enum.png b/old-docs/docs/images/default-enum.png deleted file mode 100644 index bdb40ef44..000000000 Binary files a/old-docs/docs/images/default-enum.png and /dev/null differ diff --git a/old-docs/docs/images/headers.png b/old-docs/docs/images/headers.png deleted file mode 100644 index e2887b64f..000000000 Binary files a/old-docs/docs/images/headers.png and /dev/null differ diff --git a/old-docs/docs/images/min-relevant-value.png b/old-docs/docs/images/min-relevant-value.png deleted file mode 100644 index 907ea440c..000000000 Binary files a/old-docs/docs/images/min-relevant-value.png and /dev/null differ diff --git a/old-docs/docs/images/ratingcell.png b/old-docs/docs/images/ratingcell.png deleted file mode 100644 index 81c410e67..000000000 Binary files a/old-docs/docs/images/ratingcell.png and /dev/null differ diff --git a/old-docs/docs/images/title-search.png b/old-docs/docs/images/title-search.png deleted file mode 100644 index cc04aced9..000000000 Binary files a/old-docs/docs/images/title-search.png and /dev/null differ diff --git a/old-docs/docs/index.md b/old-docs/docs/index.md deleted file mode 100644 index 9ef664d2b..000000000 --- a/old-docs/docs/index.md +++ /dev/null @@ -1,71 +0,0 @@ -# Tachi Documentation - -This site serves as the documentation for Tachi. - -Tachi is a fully-open rhythm game score tracking engine, and is the name of the codebase that powers -both [Bokutachi](https://boku.tachi.ac) and [Kamaitachi](https://kamai.tachi.ac). - -!!! help -Tachi is **fully open**. The core is almost exclusively maintained by [one person](https://github.com/zkldi). -However, we support nearly twenty games and playtypes now. Said one person cannot reasonably keep up -with all the new things coming out in those games. - - If you care about a game you play a lot, and want to help out Tachi, there are loads of ways you can contribute - and ease the load on the primary maintainer! - - Because Tachi is fully open source, if you want a feature, bug-fix, or new content added to your game, - you can *become a contributor* or *report to someone who will contribute!* - - We maintain a **comprehensive** [contribution guide](./contributing), which is accessible - to even people who have never wrote a line of code in their life. If you want to improve Tachi, and maybe even - nab some development skills yourself (or look good on a CV!), check it out. I've put a lot of effort into it. - -## About This Documentation - -This is the documentation for _all_ of Tachi. It - like Tachi - is primarily maintained by one -person, and as such, some things may be slightly outdated, wrong, or generally just ill-maintained. - -!!! info -If you're confused about anything, ask in your Tachi instance's discord! -We have a remarkably helpful community of developers and contributors, who should be able to help you out. - -Apologies in advance! If you find a problem in the documentation, you can freely contribute a fix -to it. See the [Contribution Guide](./contributing)! - -## User Wiki - -This is for end user reference, such as score importing tutorials, documentation on tachi's -statistics. It requires no programming knowledge, and is mostly used as a wiki-like reference. - -View it [here](./wiki). - ---- - -## Programmer References - -These sections are for experienced programmers who want to see documentation on how -Tachi's components work internally and externally. - -### Contributor Reference - -If you're looking to contribute to Tachi, check out the [Contribution Guide](./contributing). - -### API Reference - -This is for people who want to make things with Tachi's API, and assumes basic knowledge of -APIs and how they work. - -View it [here](./api). - -### Codebase Reference - -This is for people who want further documentation for `Tachi`'s codebase. -This is mainly full of high-level architectural documentation. - -View it [here](./codebase). - -## Acknowledgements - -This documentation is built on top of the beautiful [Material MKDocs](https://squidfunk.github.io/mkdocs-material) theme. - ---8<-- "includes/abbreviations.md" diff --git a/old-docs/docs/wiki/features.md b/old-docs/docs/wiki/features.md deleted file mode 100644 index fc55b2c34..000000000 --- a/old-docs/docs/wiki/features.md +++ /dev/null @@ -1,234 +0,0 @@ -# Feature List - -This page lists all of the features Tachi has. -Some games may utilise these better than others. - -***** - -## Sessions - -Sessions are a feature in Tachi that group up your -scores depending on *when* they were achieved. - -Sessions are meant to mimic the colloquial use of -the term - Players typically refer to their scores -as being part of a session, so why don't we show -their scores in that fashion aswell? - -### What is a session? - -A session is a group of scores that all happened -around the same time. - -When you get a new score (and don't have a session nearby), -a session is automatically created! -Then, if you get a score within two hours of that last score, -that score is added to the session - this will repeat -until eventually you spend more than two hours between -your score and the last score. - -In practice, the only time you're spending more than -two hours between a score is when you're either not playing -anymore, or taking a significant enough break that you're -probably no longer warm. - -!!! info - The reason we use the two-hour rule instead of just - splitting on a day is that not everyone lives in the - same timezone, and their session may get unexpectedly - split in two! - -### Why bother? - -Since players use the term "sessions" so frequently, it -makes sense to let them view scores how they already -think about them. - -Advantages of sessions also include being able to name and -categorise them - so you can search back on them in the -future. - -You can also share a single link to your finished session, -instead of having to squish all your great scores into one -long twitter thread! - -Another small advantages include statistics - we can -calculate your "ability" that session, and graph it -over time - so you can see your real time improvement! - -### What if I play multiple games? - -**Sessions can only store scores of the same game and playtype**. - -That is, if you have an IIDX SP session "ongoing", and get -an IIDX DP score - you will have two sessions ongoing at -the same time! - -Your IIDX DP score will **not** be added to your SP session. - -!!! note - For home players, this is likely to not ever be an - issue, but for arcade players - where people typically - throw a couple credits into different games every day, - it can become a problem! - -### What does this performance statistic mean? - -You can read all about session statistics [here](./stats/tachi.md#session-ratings). - -### Summary - -That's it for sessions! As a quick summary: - -- Sessions group your scores based on when they've happened. -- Sessions are easy to share with other players. -- Sessions are a nice way of displaying all the scores you did! - -***** - -## Goals - -!!! note - This feature goes hand-in-hand with [Quests](#quests). - -Goals are a built-in way of setting targets for yourself. - -A lot of the time, people have goals they're aiming for in -rhythm games, but at the moment, people generally have to -keep said goals in their head. - -Tachi lets you set and track your own goals - so you don't -have to remember them! - -### Advantages - -With your goals set and stored, we can see other users with -similar goals - which might give you good ideas for other -goals to aim for. - -You can also be automatically notified when a goal is -achieved, or when you've made some progress towards it. - -If you've ever been in the middle of a session and not -known what to play, you could always look at your list of -goals and try to check off some older ones, too! - -### What kind of goals can I set? - -There are two different parameters that control a goal. - -#### Criteria - -The criteria determines what our goal actually is. - -You can set goals for Lamps, Grades, Percents and score. - -!!! example - Get 950'000 on FREEDOM DiVE. - - SS FREEDOM DiVE. - - Clear FREEDOM DiVE - - Get 95% on FREEDOM DiVE. - -We can also control *how many* scores need to match the -given criteria. This makes more sense when goals apply -to more than one chart. - -!!! example - AAA 50 Charts in the Level 12 folder. - - FULL COMBO 10% of the Level 11 folder. - - Clear either FREEDOM DiVE or Blue Zenith. - -#### Charts - -You can also control what charts your goal applies to. - -The most simple option is to only select one chart. - -!!! example - Full Combo xi - FREEDOM DiVE (FOUR DIMENSIONS) - -You can also select multiple, fixed charts. - -!!! example - Full Combo xi - FREEDOM DiVE or NOMA - BRAIN POWER. - - Get 95% on 2 of the following, FREEDOM DiVE, Elemental Creation, BRAIN POWER or Blue Zenith. - -Alternatively, you can set goals on folders! - -!!! example - Full combo any chart in the Level 12 folder. - - Clear 50% of the Level 12 folder. - - AAA 100 charts in the Level 12 folder. - -### Summary - -That's it for goals! As a quick summary: - -- Goals can be set for charts or folders! -- You can set goals for any of the game's metrics (score, percent, etc.). -- You can share your goals with other users, and see what your rivals have set! - -This is nice, but there's something missing... - -## Quests - -As mentioned above, Goals were designed to go hand-in-hand -with this feature. - -### Issues with Just Goals. - -The main issue with goals on their own is that we're not -good at setting our own goals. - -What if someone doesn't *really* know what they should be -aiming for, or is just lazy and doesn't like setting goals? - -In general, we're bad at setting our own goals. How can -we fix that? - -### What are Quests? - -Quests are **pre-made groups of goals**. As an example, -we might bundle together some goals aimed at SOUND VOLTEX -11 dan players. You can then subscribe to that quest, -and all those goals will be merged with your list of goals! - -This solves the problem of having to set and manage *loads* -of goals on your own - since other people can come up with -and debate good goals for your skill level, and you can -just seamlessly integrate them with your play! - -### Who makes the Quests? - -The community! People are free to create their own -quests and share them. - -### Why are they called Quests? - -Quests work as - well - quests! - -They're achievable, just like goals, which means the -quest creator can set criteria. - -A basic example would be counting the quest as -achieved when you've achieved *all* of the goals in that -quest. - -More advanced options include achieving X goals inside a -quest, or X% of the goals inside a quest. - -### Summary - -That's all for quests! As a quick summary: - -- Since quests are achievables, you'll be automatically notified when you tick another quest off! -- You can also see other user's quests and their progress. -- Quests reduce the pain of having to set your goals yourself! diff --git a/old-docs/docs/wiki/filter-directives.md b/old-docs/docs/wiki/filter-directives.md deleted file mode 100644 index e7c0f7af7..000000000 --- a/old-docs/docs/wiki/filter-directives.md +++ /dev/null @@ -1,93 +0,0 @@ -# What Are Filter Directives? - -Filter Directives are a fancy way of *filtering* rows inside a table. - -They provide an advanced toolkit for users to whittle down what they -actually want to see! - -!!! tip - You can tell if a field supports filter directives if it has a lightning - bolt next to it. You can mouse over and click on the lightning bolt for - more information about what filter directives are available! - -## Simple Example - -In the below examples, let's assume we're talking about a table of a users -scores. - -By default, the filter bar loosely searches every column in the table. So if -you search for `AA`, You will get a list of all the scores that were on a song -that contains `AA` (such as `AA -rebuild-`) and all of the scores that have the grade -`AA` (OR `AAA`, as it's a loose match!). - -!!! example - ![](../images/basic-search.png) - Note the inclusion of AAAs and AAs? That's because it tries to match with as much as it can, as loosely as it can! - -This isn't always what we want, though! What if I wanted to see only scores -on the song `AA`? - -That's where Filter Directives come in. We can search for that using: - -``` -title=AA -``` - -Simple enough, right! - -!!! example - ![](../images/title-search.png) - Now, it only loosely matches on the title! - -Now, depending on *where* you actually are, different filter directives are -available. The above example makes sense for filtering scores, but makes *no* -sense for filtering a table of users! - -!!! tip - You can *always* find out what directives are available by clicking the - lightning bolt next to the field. - -## Advanced Example - -Before, we mentioned that this was a *powerful* toolkit for filtering rows -in a table. The above example is fairly mundane, though. What else can we do? - -By default, a directive performs a loose match on that value, but we can -change that behaviour! - -| Name | Example | What it does. | -| :: | :: | :: | -| Normal | `title=AA` | Matches any title that contains "AA". | -| Exact | `title==AA` | Matches any title that is *exactly* AA. | -| Not | `title!=AA` | Matches any title that does not contain AA. | -| Less Than | `percent<50` | Matches any percent that is less than 50. | -| Less Than Equal | `percent<=50` | Matches any percent that is less than or equal to 50. | -| Greater Than | `percent>50` | Matches any percent that is greater than 50. | -| Greater Than Equal | `percent>=50` | Matches any percent that is greater than or equal to 50. | - - - -## Other Things - -You can use multiple directives in one filter! - -`title==AA percent>50` - Find all scores on AA where the percent is greater than 50. - -Multiple directives are separated by spaces. However, if you need to use a -space inside a value, you should quote it, like this: - -`title="FREEDOM DiVE" percent>50`. - -!!! tip - If you need quotes *inside* that, you should escape them, like this: - - `artist="A Tribe Called \"Quest\"" percent>50` - - However, it is likely you will never need to use this. diff --git a/old-docs/docs/wiki/games.md b/old-docs/docs/wiki/games.md deleted file mode 100644 index 8c816e00b..000000000 --- a/old-docs/docs/wiki/games.md +++ /dev/null @@ -1,69 +0,0 @@ -# Games - -Tachi supports multiple games at the same time. It does -this using Games and Playtypes. - -***** - -## What's a playtype? - -A playtype is a 'sub game' for a given game. For example, -DDR has two 'playtypes', one where the player plays on 4 -panels, and one where the player plays on 8 panels. - -For DDR, these are referred to as SP and DP - corresponding -to Single Play and Double Play. - -Games **MUST** have playtypes, even if the game only has -one practical playtype! - -For this scenario, the playtype `Single` is used, so for -something like SDVX, it would be SDVX Single. - -### Why? - -Playtypes are for separating different scores on the same -game, we don't want to get a user's DP scores mixed with -their SP scores as, for all intents and purposes, they are -completely separate games that need completely different -skills! - -As for why games **MUST** have playtypes, it's generally -for futureproofing, and it works nicely with the codebase. - -For games that don't *really* have multiple playtypes, this -fact is hidden in the UI, but might still poke up in URLs. - -## What games and playtypes are supported? - -### Kamaitachi - -The following games are supported on [Kamaitachi](https://kamai.tachi.ac). - -| Name | Internal Name | Playtypes | -| :: | :: | :: | -| beatmania IIDX | `iidx` | `SP`, `DP` | -| CHUNITHM | `chunithm` | `Single` | -| MÚSECA | `museca` | `Single` | -| SOUND VOLTEX | `sdvx` | `Single` | -| WACCA | `wacca` | `Single` | -| pop'n music | `popn` | `9B`[^1] | -| jubeat | `jubeat` | `Single` | -| GITADORA | `gitadora` | `Gita`, `Dora` | -| maimai DX | `maimaidx` | `Single` | -| maimai | `maimai` | `Single` | -| O.N.G.E.K.I. | `ongeki` | `Single` | -| Dance Dance Revolution | `ddr` | `SP`, `DP` | - -### Bokutachi - -The following games are supported on [Bokutachi](https://boku.tachi.ac). - -| Name | Internal Name | Playtypes | -| :: | :: | :: | -| BMS | `bms` | `7K`, `14K` | -| unnamed_sdvx_clone | `usc` | `Controller` `Keyboard`[^2] | -| PMS | `pms` | `Controller`, `Keyboard`[^2] | - -[^1]: Pop'n *had* some other playtypes, namely a 5-Button mode, but it seems to be removed now. 9B is used instead of single here for futureproofing. -[^2]: This use of playtypes is a small hack to make separate leaderboards for keyboard and controller players. The split is necessary because the two input mechanisms are *very* different at high levels, but there are still a lot of keyboard players. It's a compromise! \ No newline at end of file diff --git a/old-docs/docs/wiki/index.md b/old-docs/docs/wiki/index.md deleted file mode 100644 index b45b08812..000000000 --- a/old-docs/docs/wiki/index.md +++ /dev/null @@ -1,68 +0,0 @@ -# About - -This part of the documentation is for end users, and can -be treated like a Wiki for Tachi information. - -As such, nothing here will require programming knowledge, -but it might help. - ---- - -## What is Tachi? - -Tachi refers to the code that powers both Kamaitachi and -Bokutachi. - -### What's Bokutachi? - -Bokutachi is an instance of Tachi designed for Home simulators, such as BMS or USC. - -### What's Kamaitachi? - -Kamaitachi is an instance of Tachi designed for Arcade -games, such as beatmania IIDX or Sound Voltex. - -### Why are they separate? - -Kamaitachi is a private score tracker, and Bokutachi is not. - -## What is the point of Tachi? - -Tachi is a score tracker and analyser for various rhythm -games. It was designed out of a dislike for existing websites -that display your scores. I think that scores are integral -to the rhythm game experience, and that displaying them -properly is _just_ as important. - -The benefits of Tachi include features like [Sessions](./features.md#sessions), which break your scores up into -groups of when they were played, and [Goals](./features.md#goals) which let you set automatically updating targets for yourself! - -There are way more features that Tachi has, and you can -read about all of them [here](./features.md). - -## Do I have to be good to use Tachi? - -There's a prevailing notion that analysing scores in depth -is only for 'pro' players (or likewise). - -In reality, it doesn't matter how good you are (or aren't), -being able to see your progress and analyse your scores -in more detail will help you pick out strengths and weaknesses in your skills as a player. - -You do not need to be a 'pro' at all to benefit from -Tachi's analytics! - -## Are there rules? - -Yes. - -You should familiarise yourself with the rules before -using any distribution of Tachi. - -The rules can be found [here](./rules.md). - -## I have a bug report or feature request. - -Please reach out on discord or [GitHub Issues](https://github.com/zkldi/Tachi)! - ---8<-- "includes/abbreviations.md" diff --git a/old-docs/docs/wiki/lamps.md b/old-docs/docs/wiki/lamps.md deleted file mode 100644 index 801eb3c86..000000000 --- a/old-docs/docs/wiki/lamps.md +++ /dev/null @@ -1,29 +0,0 @@ -# What are Lamps? - -Lamps are a term borrowed mainly from Arcade rhythm games. - -Their name is derived from the visual implementation in -IIDX and DDR, where a lamp would light up a specific -colour depending on how you cleared the chart. - -A synonym for this that might make more sense is "clear type", and some games use this name internally. - -***** - -## Examples - -In most games, you have a "FULL COMBO", which means you -didn't miss. That would be a different lamp to a "CLEAR", -which would generally refer to clearing the chart normally. - -Another common lamp is "FAILED", which is exactly what -you think it would be. - -## Why Bother? - -Some players like to go for lamps, especially in games like BMS -and IIDX, where scoring and lamping[^1] are fairly separate skills. -Keeping track of your lamps is important for a lot of games, and generally -a cool thing! - -[^1]: Lamping is the colloquial term for 'going for lamps' rather than going for score. \ No newline at end of file diff --git a/old-docs/docs/wiki/pbs-scores.md b/old-docs/docs/wiki/pbs-scores.md deleted file mode 100644 index db5e63fb4..000000000 --- a/old-docs/docs/wiki/pbs-scores.md +++ /dev/null @@ -1,33 +0,0 @@ -# What's the difference between a PB and a Score? - -A PB is all of your best scores on that chart joined together. - -In most games, this means joining your best score with your best lamp. - -!!! note - Some games have some additional properties - like BP in IIDX and BMS - that - also need to be joined. - -## Why bother? - -It would *suck* if you could overwrite good scores with slightly worse ones, -and people would **NEVER** agree on what the primary metric for a games was. - -If you got a better lamp on a chart in BMS, and it ruined your existing *sick* -score, that would be terrible! - -!!! example - As an example, consider the following scores. - - | Score | Lamp | - | :: | :: | - | 5000 | CLEAR | - | 4000 | HARD CLEAR | - - Your PB on this chart would then therefore be: - - | Score | Lamp | - | :: | :: | - | 5000 | HARD CLEAR| - - As it joins the best score with the best lamp! diff --git a/old-docs/docs/wiki/rules.md b/old-docs/docs/wiki/rules.md deleted file mode 100644 index 5ffc956de..000000000 --- a/old-docs/docs/wiki/rules.md +++ /dev/null @@ -1,103 +0,0 @@ -# Tachi Rules - -To ensure that the score tracker stays accurate, -and everyone has a nice time, Tachi enforces some -rules. - -## R1: You **MUST NOT** deliberately fake score submissions to Tachi. - -The punishment for this is an instant, permanent -IP ban. - -Accidentally making a mistake in score submission (somehow) -that results in invalid scores ending up on your profile -is OK, but if they repeatedly happen in your favour, you -may be warned. - -!!! warning - Cheating on Tachi is very easy. With a basic - amount of programming knowledge you could fake - scores. - - There is no anti-cheat in this regard, and this - is deliberately so. - - As such, this rule is enforced **incredibly** strictly. - - You do not get a second chance. If you fake scores, you - revoke all access to the tracker. - -## R2: You **MUST NOT** play on invalid input devices. - -Games on Tachi have specific requirements for what kind of -setups are 'legitimate'. That means that you **MUST NOT** -submit scores on input devices that aren't fair for -that game, such as playing pop'n on a keyboard. - -This is to keep everyone on a level playing field. - -The valid input devices are listed below. - -### Kamaitachi - -| Game | Devices | Justifications | -| :: | :: | :: | -| beatmania IIDX | Cabinet or any beatmania IIDX controller | Keyboard is not marked as legitimate for beatmania IIDX play (such as on INFINITAS). | -| CHUNITHM | Cabinet or any AC-size CHUNITHM controller | *AC-size* means the controller should fit a 32-inch monitor. Keyboard is not allowed. | -| MÚSECA | Cabinet | | -| SOUND VOLTEX | Cabinet or any AC-size SDVX controller | Keyboard is not allowed, as it is significantly different from controller play. Pocket Voltexes are not allowed either, as they are similarly different. | -| WACCA | Cabinet | | -| pop'n music | Cabinet or any AC-size pop'n controller | Keyboard is not allowed, and neither are smaller-sized pop'n controllers, as they give significant advantages (such as on lively). | -| jubeat | Cabinet or any AC-size jubeat controller | | -| GITADORA (Gita) | Any *reasonable* guitar | That just means no keyboard play, really.[^1] | -| GITADORA (Dora) | Any *reasonable* drum kit | There are lots of drum kits. Use common-sense. Keyboard is not allowed for obvious reasons. | -| maimai DX | Cabinet or any AC-size washing machine | | -| maimai | Cabinet | | -| O.N.G.E.K.I. | Cabinet or any AC-like controller | The controller must match the AC layout (WADs have to be vertical and so on) but it does *not* need to be 1:1 to scale (though it should be as close as possible). Keyboard is not allowed. -| DDR | Any *reasonable* Pad | There are lots of DDR pads, as long as it has four panels and you have to step on it, it's probably fine. Keyboard is not allowed for obvious reasons. | - -### Bokutachi - -| Game | Devices | Justifications | -| :: | :: | :: | -| BMS (7K) | Anything | Do whatever. | -| BMS (14K) | Anything | Do Whatever. | -| unnamed_sdvx_clone (Controller) | Any arcade-size controller | The controller leaderboards are **exclusively** for arcade **SIZE** controllers. **POCKET VOLTEXES DO NOT COUNT AS ARCADE SIZE CONTROLLERS.** | -| unnamed_sdvx_clone (Keyboard/Other) | Keyboard | The keyboard leaderboards are **exclusively** for keyboard players. You must not play on these leaderboards with a controller! | -| PMS (Controller) | Any arcade-size controller | The controller leaderboards are **exclusively** for arcade **SIZE** controllers. **MINI POP'N CONTROLLERS DO NOT COUNT AS ARCADE SIZE CONTROLLERS.** | -| PMS (Keyboard) | Keyboard | The keyboard leaderboards are **exclusively** for keyboard players. You must not play on these leaderboards with a controller! | - - -!!! info - As always though, exercise some common sense. I'm not going to whitelist controllers on here, because that's asking for trouble. Use your head as for whether something is fair or not, and if you're not certain still, ask in the discord. - -## R3: You are only allowed one account. - -Do not make multiple accounts, we track account IPs and it -lets us know. This is to keep the leaderboards fair -and avoid one player from taking up multiple spaces. - -## R4: Keep things appropriate - -Don't set your profile picture or banner or whatnot to something inappropriate. - -Kids use this website to track their scores too! Don't be a creep. - -Similarly, try and keep session names and about me's and whatnot appropriate. - -In general, just don't be an ass. - -## R5: Use Common Sense. - -This list of rules isn't exhaustive, and staff reserve the -right to ban you at any time for any reason. You should use -common sense. - -Finding loopholes in the above rules, or not-explicitly -excluded things does not mean that you can do it. - -For example, the previous rule did not explicitly exclude -setting your profile picture to a GIF designed to invoke -epileptic seizures, but common sense tells you you shouldn't do that. - -[^1]: Gitadora AC guitars have a significantly heavier strum bar than things like Guitar Hero Guitars. I don't play Gita enough to know whether this is a fair comparison or not. If it isn't, let me know. diff --git a/old-docs/docs/wiki/score-oddities.md b/old-docs/docs/wiki/score-oddities.md deleted file mode 100644 index b392a36ca..000000000 --- a/old-docs/docs/wiki/score-oddities.md +++ /dev/null @@ -1,90 +0,0 @@ -# Score Oddities - -Writing a score tracker is easy. Dealing with 20 years of questionable score storage habits is not. - -Here's a collection of weird things that have reared their head. If you've been -linked here, it's to warn you about this. - -## LR2 Auto Scratch Easy Clear - -Before ASSIST CLEAR was a dedicated clear type in IIDX, AutoScr would degrade -the score back down to an EASY CLEAR. This is fine normally, as the score would -also have a BP of -1 or NULL. You could easily tell when a score was AutoScr -and correct it. - -However. If you then get **ANY SCORE** on the chart without Auto Scratch, your -BP will be set to a normal value, rather than -1 or NULL. This means that... - -``` -EASY CLEAR, BP -1 -then... -FAILED, BP: 140 -becomes -EASY CLEAR, BP: 140 -``` - -And there's no longer any way to determine the score was auto scratched! - -## Beatoraja + LR2 DP Random - -Beatoraja and LR2 only store the left hand random. They completely ignore -the right hand one and never store or send it anywhere. - -## E-Amusement IIDX Resets (0EX Lamps) - -E-Amusement resets scores for IIDX every version. This would be fine under a normal interpretation of 'resets score', but the emphasis here is on the word *score*, not *reset*. - -E-Amusement IIDX Score Resets only reset your EX Score, you actually get to keep your lamp. -For exported E-Amusement CSVs, this means that you submit scores with 0EX, but with lamps. -For sanities sake, scores with 0EX are rejected so that you don't accidentally flood the server with fake scores because... - -## E-Amusement IIDX Resets (Timestamps) - -The timestamp for all your scores is also changed to the point when you first carded in on -the new version of the game, meaning that if you were to import all those 0EX scores, you -would create a session of every single chart you've ever lamped at that exact moment. - -## E-Amusement IIDX Timestamps - -Timestamps in E-Amusement IIDX CSVs are also only on a per-song basis, rather than a per-chart basis. -If you play V (Another) and V (Hyper) in the same session, the data in the CSV says that you -played both of those charts at the same time (since all charts of V have to share a timestamp). - -## Legacy LEGGENDARIA Formats (IIDX) - -From IIDX 21 to IIDX 26, Leggendarias were not their own difficulty. Instead they were -just anothers with the special quantifier that the song title ended in † or †LEGGENDARIA exactly. -To handle this, Tachi will automatically convert song titles ending in † or †LEGGENDARIA -into their original form, changing the difficulty from ANOTHER to LEGGENDARIA. - -!!! note - This only applies to legacy imports -- This has been fixed since IIDX 27 (2019). - -## Deduplication False Positives (All Games) - -Tachi identifies scores using a `scoreID`. This is calculated from some properties on the score, such as who got it (`userID`) and the various metrics for this game (`score`, `percent`, `lamp`, etc.) - -`scoreID`s are *unique* across all of Tachi. The motivation for this is to avoid score duplication. - -!!! example - Let's say you imported your local score database, which has some scores in it. - You then get some more scores, and import your local score database. - - What you *want* to happen here is that your new scores get imported and the old ones are just ignored. - - Therefore, we need a way of recognising that a score has already been imported, and ignore - it. - -To deduplicate scores, we compare scoreIDs. This works in all scenarios, and avoiding score duplication is a good thing. *However*, it has a false positive in exactly one scenario. - -**If you get the same score twice, only one of them will be imported**. - -There is no way to distinguish between a user getting a score twice, and a user getting a score once and importing it twice (therefore being deduplicated). - -### Why not simply check the timestamp? - -You can't check the score timestamp. Games like LR2 do not store timestamps, games like E-Amusement lie about their timestamps and generally clobber them. PLI infamously lied about almost all their timestamps to hide what players were playing, etc. - -Similarly, scores are sometimes duplicated across services -- someone might import their FLO scores to EAG using their integration. Those timestamps also get clobbered. - -It is safer to be right all the time on deduplication and sacrifice this case. diff --git a/old-docs/includes/abbreviations.md b/old-docs/includes/abbreviations.md deleted file mode 100644 index b26a00e27..000000000 --- a/old-docs/includes/abbreviations.md +++ /dev/null @@ -1,3 +0,0 @@ -*[Monorepo]: When code for many different projects is stored in the same repository. -*[BMS]: Be-Music Source -*[USC]: unnamed_sdvx_clone \ No newline at end of file diff --git a/old-docs/includes/mathjax.js b/old-docs/includes/mathjax.js deleted file mode 100644 index 385b5215c..000000000 --- a/old-docs/includes/mathjax.js +++ /dev/null @@ -1,16 +0,0 @@ -window.MathJax = { - tex: { - inlineMath: [["\\(", "\\)"]], - displayMath: [["\\[", "\\]"]], - processEscapes: true, - processEnvironments: true, - }, - options: { - ignoreHtmlClass: ".*|", - processHtmlClass: "arithmatex", - }, -}; - -document$.subscribe(() => { - MathJax.typesetPromise(); -}); diff --git a/old-docs/mkdocs.yml b/old-docs/mkdocs.yml deleted file mode 100644 index da15a4980..000000000 --- a/old-docs/mkdocs.yml +++ /dev/null @@ -1,196 +0,0 @@ -site_name: Tachi Documentation -site_description: Documentation for Kamaitachi, Bokutachi and related things. -site_author: zkldi -site_url: https://docs.tachi.ac - -watch: - - "docs/" - - "mkdocs.yml" - -theme: - name: material - features: - - navigation.instant - - navigation.tabs - palette: - - scheme: slate - primary: deep purple - accent: deep purple - toggle: - icon: material/weather-sunny - name: Switch to light mode - - scheme: default - primary: deep purple - accent: deep purple - toggle: - icon: material/weather-night - name: Switch to dark mode - -nav: - - Getting Started: - - "index.md" - - Contributing: - - "contributing/index.md" - - "contributing/setup.md" - - "contributing/components.md" - - Component-Specific Guides: - - "contributing/components/issues.md" - - "contributing/components/documentation.md" - - "contributing/components/seeds.md" - - "contributing/components/core.md" - - - Cookbook: - - "contributing/cookbook/iidx-mdb.md" - - "contributing/cookbook/sdvx-mdb.md" - - "contributing/cookbook/ddr-mdb.md" - - "contributing/cookbook/bms-tables.md" - - - Supporting New Games: - - "game-support/index.md" - - - Common Config: - - "game-support/common-config/index.md" - - "game-support/common-config/metrics.md" - - "game-support/common-config/metric-groups.md" - - "game-support/common-config/match-types.md" - - "game-support/common-config/versions.md" - - - "game-support/server-impl.md" - - "game-support/client-impl.md" - - "game-support/seeds.md" - - - Game Information: - - "game-support/games/iidx-SP.md" - - "game-support/games/iidx-DP.md" - - "game-support/games/museca-Single.md" - - "game-support/games/chunithm-Single.md" - - "game-support/games/bms-7K.md" - - "game-support/games/bms-14K.md" - - "game-support/games/gitadora-Gita.md" - - "game-support/games/gitadora-Dora.md" - - "game-support/games/jubeat-Single.md" - - "game-support/games/maimai-Single.md" - - "game-support/games/maimaidx-Single.md" - - "game-support/games/popn-9B.md" - - "game-support/games/sdvx-Single.md" - - "game-support/games/usc-Controller.md" - - "game-support/games/usc-Keyboard.md" - - "game-support/games/wacca-Single.md" - - "game-support/games/pms-Controller.md" - - "game-support/games/pms-Keyboard.md" - - "game-support/games/itg-Stamina.md" - - "game-support/games/arcaea-Touch.md" - - "game-support/games/ongeki-Single.md" - - "game-support/games/ddr-SP.md" - - "game-support/games/ddr-DP.md" - - - Wiki: - - "wiki/index.md" - - "wiki/rules.md" - - "wiki/games.md" - - "wiki/features.md" - - "wiki/pbs-scores.md" - - "wiki/filter-directives.md" - - "wiki/lamps.md" - - "wiki/score-oddities.md" - - - API Reference: - - "api/index.md" - - "api/auth.md" - - "api/terminology.md" - - - Endpoints: - - "api/routes/example.md" - - "api/routes/status.md" - - "api/routes/import.md" - - "api/routes/auth.md" - - "api/routes/users.md" - - "api/routes/user-gamept.md" - - "api/routes/user-integrations.md" - - "api/routes/sessions.md" - - "api/routes/scores.md" - - "api/routes/search.md" - - "api/routes/games.md" - - "api/routes/gpt.md" - - "api/routes/admin.md" - - "api/routes/ugpt-showcase.md" - - "api/routes/api-tokens.md" - - "api/routes/oauth2.md" - - "api/routes/clients.md" - - "api/routes/config.md" - - "api/routes/imports.md" - - "api/routes/gpt-targets.md" - - "api/routes/ugpt-targets.md" - - - Webhooks: - - "api/webhooks/main.md" - - "api/webhooks/class-update-v1.md" - - - Codebase Reference: - - "codebase/index.md" - - - Setup: - - "codebase/setup/config.md" - - - Infrastructure: - - "codebase/infrastructure/logging.md" - - "codebase/infrastructure/branches.md" - - "codebase/infrastructure/database-seeds.md" - - - OAuth2: - - "codebase/infrastructure/api-clients.md" - - "codebase/infrastructure/oauth2.md" - - "codebase/infrastructure/file-flow.md" - - - Structure: - - "codebase/structure/style.md" - - "codebase/structure/filesystem.md" - - "codebase/structure/testing.md" - - - BATCH-MANUAL: - - "codebase/batch-manual/index.md" - - "codebase/batch-manual/direct-manual.md" - - - Score Importing: - - "codebase/import/overview.md" - - "codebase/import/main.md" - - "codebase/import/import-types.md" - - "codebase/import/parse-conv.md" - - "codebase/import/conv-failures.md" - - "codebase/import/importing.md" - - "codebase/import/orphans.md" - - "codebase/import/parse-ipi.md" - - "codebase/import/sessions.md" - - "codebase/import/pbs.md" - - "codebase/import/ugs.md" - - "codebase/import/goals.md" - - "codebase/import/quests.md" - - "codebase/import/import-doc-time.md" - - - Implementation Details: - - "codebase/implementation-details/details.md" - - "codebase/implementation-details/search.md" - - "codebase/implementation-details/songs-charts.md" - - "codebase/implementation-details/game-configuration.md" - - "codebase/implementation-details/score-id.md" - - "codebase/implementation-details/goal-id.md" - - "codebase/implementation-details/goals-quests.md" - -markdown_extensions: - - admonition - - pymdownx.highlight - - pymdownx.superfences - - abbr - - pymdownx.snippets - - footnotes - - toc: - toc_depth: 2 - permalink: true - - pymdownx.arithmatex: - generic: true - - pymdownx.tabbed: - alternate_style: true - -extra_javascript: - - https://polyfill.io/v3/polyfill.min.js?features=es6 - - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js diff --git a/old-docs/requirements.txt b/old-docs/requirements.txt deleted file mode 100644 index 898468cb1..000000000 --- a/old-docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -mkdocs-material \ No newline at end of file diff --git a/package.json b/package.json index de1a1d087..3c538301f 100644 --- a/package.json +++ b/package.json @@ -135,12 +135,10 @@ "node-fetch": "2.6.7", "node-html-parser": "^5.3.3", "node-mocks-http": "1.11.0", - "node-sass": "9.0.0", "nodemailer": "7.0.11", "pg": "^8.13.3", "pino": "^10.3.1", "pino-pretty": "^13.1.3", - "prettier": "3.2.5", "pretty-bytes": "5.6.0", "prom-client": "15.1.3", "prudence": "0.10.0", @@ -165,8 +163,6 @@ "vite-plugin-html": "^3.2.0", "vitest": "~3.2.0", "zod": "^4.3.6", - "@types/tap": "^15.0.5", - "tap": "^15.1.6", "@types/istanbul-lib-coverage": "^2.0.6", "istanbul-lib-coverage": "^3.2.2", "@codemirror/lang-sql": "^6.10.0", diff --git a/typescript/bot/src/slash-commands/commands/roles.ts b/typescript/bot/src/slash-commands/commands/roles.ts deleted file mode 100644 index 1c06beda2..000000000 --- a/typescript/bot/src/slash-commands/commands/roles.ts +++ /dev/null @@ -1,155 +0,0 @@ -import type { GameGroup } from "tachi-common"; - -import { Env } from "#config"; -import { log } from "#utils/log"; -import { SlashCommandBuilder, type SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import { GuildMember } from "discord.js"; - -import type { SlashCommand } from "../types"; - -import { IsGameGroupKey } from "../../utils/predicates"; - -/** Discord allows at most 25 string choices per option. */ -export const SELF_ASSIGN_ROLE_CHOICE_LIMIT = 25; - -/** - * Stable sorted GameGroup keys capped for slash choices + list of omitted keys after the cutoff. - * - * Exported for tests. - */ -export function selfAssignableSlashChoiceKeys( - map: Partial>, - limit = SELF_ASSIGN_ROLE_CHOICE_LIMIT, -): { - keysIncluded: readonly GameGroup[]; - keysOmitted: readonly GameGroup[]; -} { - const sorted = (Object.keys(map) as GameGroup[]).sort((a, b) => a.localeCompare(b)); - const keysIncluded = sorted.slice(0, limit); - const keysOmitted = sorted.slice(limit); - - return { - keysIncluded, - keysOmitted, - }; -} - -function attachRoleChoiceOption(sub: SlashCommandSubcommandBuilder, choices: [string, string][]) { - return sub.addStringOption((opt) => - opt - .setName("role") - .setRequired(true) - .setDescription("Which game group ping role.") - .addChoices(choices), - ); -} - -/** Returns slash command `/roles`, or null if there is nothing to expose. */ -export function getRolesSlashCommand(): SlashCommand | null { - const map = Env.DISCORD_GAME_ROLES; - if (Object.keys(map).length === 0) { - return null; - } - - const { keysIncluded, keysOmitted } = selfAssignableSlashChoiceKeys(map); - if (keysOmitted.length > 0) { - log.warn( - { - total: keysIncluded.length + keysOmitted.length, - limit: SELF_ASSIGN_ROLE_CHOICE_LIMIT, - ignoredKeys: [...keysOmitted], - }, - `DISCORD_GAME_ROLES exposes more GameGroups than Discord's slash choice limit; only the first ${SELF_ASSIGN_ROLE_CHOICE_LIMIT} (alphabetical) appear in \`/roles\`.`, - ); - } - - const choiceTuples: [string, string][] = keysIncluded.map((k) => [k, k]); - - const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("roles") - .setDescription("Add or remove self-assignable Discord roles.") - .addSubcommand((sub) => - attachRoleChoiceOption( - sub.setName("add").setDescription("Grant yourself one of these roles."), - choiceTuples, - ), - ) - .addSubcommand((sub) => - attachRoleChoiceOption( - sub - .setName("remove") - .setDescription("Remove one of these roles from yourself."), - choiceTuples, - ), - ) - .toJSON(), - exec: async (interaction) => { - if (!(interaction.member instanceof GuildMember)) { - return `This command can only be used in a server.`; - } - - const subcommand = interaction.options.getSubcommand(true); - const choiceKey = interaction.options.getString("role", true); - - if (!IsGameGroupKey(choiceKey)) { - return `That selection is not a configured game group.`; - } - - const gameGroup = choiceKey; - const roleId = map[gameGroup]; - - if (!roleId) { - return `That game group role is no longer configured. Ask a moderator to refresh the bot's configuration.`; - } - - if (subcommand === "add") { - if (interaction.member.roles.cache.has(roleId)) { - return `You already have that role.`; - } - - try { - await interaction.member.roles.add(roleId); - } catch (err) { - log.error({ err, roleId }, "Failed to add self-assign Discord role."); - - return discordRoleOpFailureMessage(err, "grant"); - } - - return `Added role for **${gameGroup}**.`; - } - - if (subcommand === "remove") { - if (!interaction.member.roles.cache.has(roleId)) { - return `You do not have that role.`; - } - - try { - await interaction.member.roles.remove(roleId); - } catch (err) { - log.error({ err, roleId }, "Failed to remove self-assign Discord role."); - - return discordRoleOpFailureMessage(err, "remove"); - } - - return `Removed role for **${gameGroup}**.`; - } - - return `Unsupported subcommand.`; - }, - }; - - return command; -} - -function discordRoleOpFailureMessage(err: unknown, verb: "grant" | "remove"): string { - const snippet = - err && - typeof err === "object" && - "message" in err && - typeof (err as { message: unknown }).message === "string" - ? (err as { message: string }).message - : String(err); - - return `Discord could not ${verb} that role (${snippet}). If this keeps failing, ensure the bot's role sits above those roles and has Manage Roles.`; -} diff --git a/typescript/bot/src/utils/arg-parsers.ts b/typescript/bot/src/utils/arg-parsers.ts deleted file mode 100644 index 7522406c0..000000000 --- a/typescript/bot/src/utils/arg-parsers.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { CommandInteraction } from "discord.js"; -import type { PrivDiscordUserMap } from "tachi-db"; - -import { IsValidGame, type UserDocument, type V3Game } from "tachi-common"; - -import type { Emittable } from "../slash-commands/types"; - -import { GetUserInfo } from "./api-requests"; - -/** - * Utility parser for getting the game and requesting user, since this is - * a common pattern in the bot. - */ -export async function GetGameAndUser( - interaction: CommandInteraction, - requestingUser: PrivDiscordUserMap, -): Promise< - { content: { game: V3Game; userDoc: UserDocument }; error: null } | { error: Emittable } -> { - const userID = interaction.options.getString("other_user") ?? requestingUser.user_id.toString(); - - if (!/^[a-zA-Z0-9_-]{0,20}$/u.test(userID)) { - return { error: `Invalid userID. Can't query this!` }; - } - - let userDoc; - - try { - userDoc = await GetUserInfo(userID); - } catch { - return { error: `This user does not exist.` }; - } - - const game = interaction.options.getString("game", true); - - if (!IsValidGame(game)) { - return { error: `Invalid game: ${game}.` }; - } - - return { error: null, content: { userDoc, game } }; -} diff --git a/typescript/bot/src/utils/options.ts b/typescript/bot/src/utils/options.ts deleted file mode 100644 index 6c4bf8799..000000000 --- a/typescript/bot/src/utils/options.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { SlashCommandStringOption } from "@discordjs/builders"; - -import { FormatGame, GetGameGroupConfig } from "tachi-common"; - -import { ServerConfig } from "../config"; - -/** - * Game options. Frequently used by things that might need - * game specific listening. - */ -const GameChoices: Array<[string, string]> = []; - -for (const gameGroup of ServerConfig.GAME_GROUPS) { - const gameGroupConfig = GetGameGroupConfig(gameGroup); - - for (const game of gameGroupConfig.games) { - GameChoices.push([FormatGame(game), game]); - } -} - -export const GameOptions = (str: SlashCommandStringOption) => - str.setName("game").setDescription("Pick the relevant game.").addChoices(GameChoices); - -export function MakeRequired(fn: (str: SlashCommandStringOption) => SlashCommandStringOption) { - return (str: SlashCommandStringOption) => fn(str).setRequired(true); -} - -export const OtherUserOption = (str: SlashCommandStringOption) => - str.setName("other_user").setDescription("Optionally, check this info out for another user."); diff --git a/typescript/client/src/app/pages/LandingPage.tsx b/typescript/client/src/app/pages/LandingPage.tsx deleted file mode 100644 index 9c4e2bcbb..000000000 --- a/typescript/client/src/app/pages/LandingPage.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { Footer } from "#components/layout/footer/Footer"; -import Divider from "#components/util/Divider"; -import LinkButton from "#components/util/LinkButton"; -import { TachiConfig } from "#lib/config"; -import { ToCDNURL } from "#util/api"; -import { DEFAULT_GAME_BANNER_REL_PATH } from "#util/game-group-banner-counts"; -import React from "react"; - -// This page is currently unused, -// It's alright, but hey, we could do more. -export default function LandingPage() { - return ( - <> - {/* */} - {/*
*/} -
-
-
-
-
-
-
-
-
-
- {TachiConfig.NAME} -
-
- {TachiConfig.NAME} -
-
-
-

- A Supercharged Score Tracker -

-
-
-
-
-
-
- -
-
-
- - - - - foo - - - foo - -
- But hey, this all sounds a bit formal. Let's be honest, if you're a - rhythm gamer, you probably don't need to be sold on this like it's a - startup :P. -
- - Register? - -
-
-
-
-
-