ok now i'm happy

This commit is contained in:
zkldi
2021-06-22 17:07:31 +01:00
parent d384babcc5
commit 2d9680d6a4
11 changed files with 221 additions and 7 deletions
+1 -1
View File
@@ -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.
+103
View File
@@ -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.
+5
View File
@@ -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
+1 -1
View File
@@ -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
+41
View File
@@ -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.
-2
View File
@@ -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.
+1 -1
View File
@@ -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).
*****
+4
View File
@@ -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