mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-30 10:58:07 +03:00
ok now i'm happy
This commit is contained in:
@@ -225,7 +225,7 @@ GET /api/v1/users/zkldi/games/iidx/SP/pbs?search=Verfl
|
||||
`GET /api/v1/users/:userID/games/:game/:playtype/pbs/best`
|
||||
|
||||
This returns the users' best 100 personal bests according
|
||||
to the [Default Rating Algorithm](todo) for this game.
|
||||
to the [Default Rating Algorithm](../../codebase/implementation-details/game-configuration) for this game.
|
||||
|
||||
This is returned in descending sorted order.
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# Goal Document
|
||||
|
||||
Goals are stored in `goals`.
|
||||
|
||||
!!! warning
|
||||
This document describes a goal, but does not describe
|
||||
a user's "subscription" to that goal. For that, see
|
||||
[User Goal Document](./user-goal.md).
|
||||
|
||||
*****
|
||||
|
||||
## Definition
|
||||
|
||||
A base goal document is defined as follows.
|
||||
|
||||
```ts
|
||||
interface BaseGoalDocument {
|
||||
game: Game;
|
||||
playtype: Playtypes[Game];
|
||||
timeAdded: integer;
|
||||
createdBy: integer;
|
||||
title: string;
|
||||
goalID: string;
|
||||
criteria: GoalSingleCriteria | GoalCountCriteria;
|
||||
}
|
||||
```
|
||||
|
||||
| Property | Description |
|
||||
| :: | :: |
|
||||
| `game` | The game this goal is for. |
|
||||
| `playtype` | The playtype this goal is for. Must be a valid playtype for the above game. |
|
||||
| `timeAdded` | The time this goal was added to the database. |
|
||||
| `createdBy` | The ID of the user that originally made this goal. |
|
||||
| `title` | A humanised name for this goal. |
|
||||
| `goalID` | A hash of the criteria and chart set for this goal. Used to de-dupe goals. |
|
||||
|
||||
### Criteria
|
||||
|
||||
Criteria is defined as follows:
|
||||
|
||||
```ts
|
||||
interface GoalCriteria {
|
||||
key: "scoreData.percent" | "scoreData.lampIndex" | "scoreData.gradeIndex" | "scoreData.score";
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface GoalSingleCriteria extends GoalCriteria {
|
||||
mode: "single";
|
||||
}
|
||||
|
||||
interface GoalCountCriteria extends GoalCriteria {
|
||||
mode: "abs" | "proportion";
|
||||
countNum: number;
|
||||
}
|
||||
```
|
||||
|
||||
| Property | Description |
|
||||
| :: | :: |
|
||||
| `key` | Defines the key this goal is for - these correspond to keys in a [Score Document](./score.md). |
|
||||
| `value` | The value this goal must hit in order for it to be achieved. What this value is interpreted as depends on `key`. |
|
||||
| `mode` | If single, this just means the user only has to have one score that meets the above criteria on the defined set of charts. If abs or proportion, the user must hit `countNum` amount of scores on the set of charts (or that percent). |
|
||||
| `countNum` | If mode is abs, this defines an absolute amount of scores the user must get. If proportion, the user must get this percent of the set of charts achieved. |
|
||||
|
||||
### Charts
|
||||
|
||||
The set of charts this goal applies to is added onto the
|
||||
goal document under the `charts` key.
|
||||
|
||||
There are four types of goal.
|
||||
|
||||
```ts
|
||||
interface GoalDocumentSingle extends BaseGoalDocument {
|
||||
charts: {
|
||||
type: "single";
|
||||
data: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface GoalDocumentMulti extends BaseGoalDocument {
|
||||
charts: {
|
||||
type: "multi";
|
||||
data: string[];
|
||||
};
|
||||
}
|
||||
|
||||
interface GoalDocumentFolder extends BaseGoalDocument {
|
||||
charts: {
|
||||
type: "folder";
|
||||
data: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface GoalDocumentAny extends BaseGoalDocument {
|
||||
charts: {
|
||||
type: "any";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
For single and multi, the data field is a chartID, or an
|
||||
array of chartIDs respectively.
|
||||
|
||||
For the folder type, the data field is a folderID.
|
||||
@@ -12,6 +12,11 @@ shape of those documents.
|
||||
involve frequent links to this part of the
|
||||
codebase documentation.
|
||||
|
||||
!!! help
|
||||
This section is a bit sparse, as I don't have the
|
||||
time to populate it all. If you want to contribute
|
||||
to this, please see [Contributing](../contributing.md).
|
||||
|
||||
*****
|
||||
|
||||
## Definition
|
||||
|
||||
@@ -64,7 +64,7 @@ The base score document is structured as follows:
|
||||
| `isPrimary` | Whether this score is was achieved on a "primary" chart or not. You can read more on what a primary chart is [here](../implementation-details/songs-charts.md#isPrimary). |
|
||||
| `highlight` | Whether this individual score was highlighted or not by the user. This is one of the few mutable fields on the score document. |
|
||||
| `comment` | A comment left by the user on this score. If one is not present, it is left as `null`. Comments are capped at 240 characters. |
|
||||
| `scoreID` | A unique identifier for this score. Score IDs are prefixed with `R`. This identifier is derived from the content of the score, and thus can be used to dedupe scores. See [Score IDs](todo). |
|
||||
| `scoreID` | A unique identifier for this score. Score IDs are prefixed with `R`. This identifier is derived from the content of the score, and thus can be used to dedupe scores. See [Score IDs](../implementation-details/score-id.md). |
|
||||
| `importType` | The import type used to import this score. For more on this, see [Import Types](../import/import-types.md) |
|
||||
|
||||
Now, absolutely none of the above fields contain
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# User Goal Document
|
||||
|
||||
The user goal document represents a user's subscription
|
||||
to a goal.
|
||||
|
||||
!!! warning
|
||||
This does not describe the goal or its criteria,
|
||||
for that - see [Goal Document](./goal.md).
|
||||
|
||||
*****
|
||||
|
||||
## Definition
|
||||
|
||||
```ts
|
||||
interface UserGoalDocument {
|
||||
goalID: string;
|
||||
userID: integer;
|
||||
game: Game;
|
||||
playtype: Playtypes[Game];
|
||||
achieved: boolean;
|
||||
timeSet: integer;
|
||||
timeAchieved: integer | null;
|
||||
lastInteraction: integer | null;
|
||||
progress: number | null;
|
||||
progressHuman: string;
|
||||
outOf: number;
|
||||
outOfHuman: string;
|
||||
}
|
||||
```
|
||||
|
||||
| Property | Description |
|
||||
| :: | :: |
|
||||
| `goalID` | This is the goal the user is subscribed to in this document. |
|
||||
| `userID` | This is the user this goal subscription belongs to. |
|
||||
| `game`, `playtype` | These fields are both *technically* redundant. However, for optimisation reasons, they are copied over from the goal document field. |
|
||||
| `achieved` | Whether this goal has been achieved or not. |
|
||||
| `timeSet` | The time the user set this goal. |
|
||||
| `timeAchieved` | The time this user achieved this goal. If the user has not achieved this goal, it is set as `null`. |
|
||||
| `progress` | The user's raw progress towards this goal. This is a number, and should not be displayed to the user. |
|
||||
| `outOf` | The value this goal is out of - this is a number, and should not be displayed to the user. |
|
||||
| `progressHuman`, `outOfHuman` | These are humanised, stringified versions of the above two fields. These convert things like the enum value of lamps to their string equivalents. |
|
||||
@@ -10,8 +10,9 @@ combination, which contains things like the list of
|
||||
lamps for the game.
|
||||
|
||||
!!! help
|
||||
This page is currently unformatted, and is just a reference
|
||||
to the codebase at points.
|
||||
This page is currently unformatted,
|
||||
and is pretty much just a copy-paste of the
|
||||
local configuration files.
|
||||
|
||||
It would be really appreciated if someone formatted
|
||||
the configurations for every game! For the time being,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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](../documents/goal.md)
|
||||
representing the same thing.
|
||||
|
||||
*****
|
||||
|
||||
## Hashing
|
||||
|
||||
To create the Goal ID, we perform a [json stable hash](https://github.com/zkldi/fast-stable-json-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`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
*****
|
||||
|
||||
## Hashing
|
||||
|
||||
The score ID is created by hashing the following template string:
|
||||
|
||||
```ts
|
||||
`${userID}|${chartID}|${dryScore.scoreData.lamp}|${dryScore.scoreData.grade}|${dryScore.scoreData.score}|${dryScore.scoreData.percent}`
|
||||
```
|
||||
|
||||
with SHA256.
|
||||
|
||||
This is then prefixed with `R`, and returned.
|
||||
|
||||
## Why those fields?
|
||||
|
||||
Games do a lot of wacky things. We'd rather not discard
|
||||
non-duplicates, so we're a little more strict than we
|
||||
maybe should be.
|
||||
|
||||
UserID and chartID are so we don't accidentally collide
|
||||
with other user's scores or charts.
|
||||
|
||||
Score and Lamp make sense - since if those change we no
|
||||
longer really have the same score.
|
||||
|
||||
Grade and Percent are the slightly more strict ones. Some
|
||||
games have very strange external grade requirements, such
|
||||
as osu!standard enforcing a Full Combo for an S rank.
|
||||
|
||||
Percent may not correlate with score. This was in anticipation
|
||||
to support BMS's `#RANDOM` instruction - where charts may
|
||||
have a dynamic amount of notes - but I've decided it
|
||||
wasn't worth it. Still, this is left in for futureproofing.
|
||||
@@ -29,8 +29,6 @@ as a result of the import. This is calculated as follows:
|
||||
For every goal matched, we iterate over it and evaluate
|
||||
it using `EvaluateGoalForUser`.
|
||||
|
||||
The details of how this algorithm works (and goals in general work) can be found at [Goals](todo).
|
||||
|
||||
We then need to convert the returns of that function into
|
||||
the expected goal format for ImportDocuments.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This page documents how Sessions are constructed.
|
||||
For a humanised explaination of sessions, see
|
||||
TODO.
|
||||
[this page](../../user/features.md#sessions).
|
||||
|
||||
*****
|
||||
|
||||
|
||||
@@ -95,11 +95,15 @@ nav:
|
||||
- "codebase/implementation-details/songs-charts.md"
|
||||
- "codebase/implementation-details/game-configuration.md"
|
||||
- "codebase/implementation-details/esd.md"
|
||||
- "codebase/implementation-details/score-id.md"
|
||||
- "codebase/implementation-details/goal-id.md"
|
||||
|
||||
- Documents:
|
||||
- "codebase/documents/overview.md"
|
||||
- "codebase/documents/user.md"
|
||||
- "codebase/documents/score.md"
|
||||
- "codebase/documents/goal.md"
|
||||
- "codebase/documents/user-goal.md"
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
|
||||
Reference in New Issue
Block a user