rhythia-api 242.0.0 → 243.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/createBeatmap.ts +57 -39
- package/api/editProfile.ts +4 -67
- package/api/executeAdminOperation.ts +1030 -681
- package/api/getAvatarUploadUrl.ts +90 -85
- package/api/getBeatmapPage.ts +2 -0
- package/api/getBeatmapPageById.ts +2 -0
- package/api/getBeatmaps.ts +110 -197
- package/api/getCollection.ts +44 -31
- package/api/getMapUploadUrl.ts +90 -93
- package/api/getScore.ts +2 -0
- package/api/getVideoUploadUrl.ts +90 -85
- package/api/submitScoreInternal.ts +506 -461
- package/api/updateBeatmapPage.ts +6 -0
- package/beatmap-file-urls.json +29398 -0
- package/handleApi.ts +24 -21
- package/index.ts +121 -112
- package/package.json +4 -2
- package/queries/admin_delete_user.sql +42 -39
- package/queries/admin_remove_all_scores.sql +6 -3
- package/queries/admin_remove_score.sql +107 -0
- package/queries/admin_update_profile.sql +22 -0
- package/queries/get_beatmaps_v2.sql +48 -0
- package/queries/get_top_scores_for_beatmap3.sql +47 -38
- package/queries/profile_update_guards.sql +66 -0
- package/types/database.ts +1525 -1450
- package/utils/beatmapFiles.ts +102 -0
- package/utils/beatmapHash.ts +336 -0
- package/utils/beatmapTopScores.ts +68 -84
- package/utils/getUserBySession.ts +3 -1
- package/utils/profileUpdateValidation.ts +51 -0
- package/utils/redis.ts +24 -0
- package/utils/rhrReplay.ts +122 -0
- package/utils/star-calc/sspmParser.ts +294 -160
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const VERSION_EXTENDED_FIELDS = 20260125;
|
|
2
|
+
const VERSION_FAIL_TIME = 20260222;
|
|
3
|
+
const VERSION_BEATMAP_HASH = 20260517;
|
|
4
|
+
const REPLAY_FRAME_SIZE = 17;
|
|
5
|
+
|
|
6
|
+
export function parseReplaySubmitData(bytes: Buffer) {
|
|
7
|
+
let offset = 0;
|
|
8
|
+
|
|
9
|
+
const ensure = (length: number) => {
|
|
10
|
+
if (offset + length > bytes.length) {
|
|
11
|
+
throw new Error("Invalid replay file");
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const skip = (length: number) => {
|
|
16
|
+
ensure(length);
|
|
17
|
+
offset += length;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const readU8 = () => {
|
|
21
|
+
ensure(1);
|
|
22
|
+
return bytes[offset++];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const readInt32 = () => {
|
|
26
|
+
ensure(4);
|
|
27
|
+
const value = bytes.readInt32LE(offset);
|
|
28
|
+
offset += 4;
|
|
29
|
+
return value;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const readFloat = () => {
|
|
33
|
+
ensure(4);
|
|
34
|
+
const value = bytes.readFloatLE(offset);
|
|
35
|
+
offset += 4;
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const readString = () => {
|
|
40
|
+
let length = 0;
|
|
41
|
+
let shift = 0;
|
|
42
|
+
|
|
43
|
+
while (true) {
|
|
44
|
+
const byte = readU8();
|
|
45
|
+
length += (byte & 0x7f) * 2 ** shift;
|
|
46
|
+
|
|
47
|
+
if ((byte & 0x80) === 0) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
shift += 7;
|
|
52
|
+
if (shift > 35) {
|
|
53
|
+
throw new Error("Invalid replay file");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ensure(length);
|
|
58
|
+
const value = bytes.toString("utf8", offset, offset + length);
|
|
59
|
+
offset += length;
|
|
60
|
+
return value;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const version = readInt32();
|
|
64
|
+
|
|
65
|
+
skip(8);
|
|
66
|
+
readString();
|
|
67
|
+
readString();
|
|
68
|
+
const onlineMapId = readInt32();
|
|
69
|
+
readInt32();
|
|
70
|
+
readString();
|
|
71
|
+
|
|
72
|
+
let mods = "[]";
|
|
73
|
+
let spin = false;
|
|
74
|
+
let speed = 1;
|
|
75
|
+
|
|
76
|
+
if (version >= VERSION_EXTENDED_FIELDS) {
|
|
77
|
+
readU8();
|
|
78
|
+
mods = readString();
|
|
79
|
+
spin = readU8() !== 0;
|
|
80
|
+
speed = readFloat();
|
|
81
|
+
skip(8);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
readFloat();
|
|
85
|
+
const hits = readInt32();
|
|
86
|
+
const misses = readInt32();
|
|
87
|
+
readFloat();
|
|
88
|
+
|
|
89
|
+
let failTime: number | null = null;
|
|
90
|
+
if (version >= VERSION_FAIL_TIME) {
|
|
91
|
+
const value = readInt32();
|
|
92
|
+
failTime = value >= 0 ? value : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const beatmapHash =
|
|
96
|
+
version >= VERSION_BEATMAP_HASH ? readString() || null : null;
|
|
97
|
+
const frameCount = readInt32();
|
|
98
|
+
|
|
99
|
+
if (frameCount < 0) {
|
|
100
|
+
throw new Error("Invalid replay file");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
ensure(frameCount * REPLAY_FRAME_SIZE);
|
|
104
|
+
|
|
105
|
+
const parsedMods = JSON.parse(mods || "[]");
|
|
106
|
+
if (!Array.isArray(parsedMods)) {
|
|
107
|
+
throw new Error("Invalid replay mods");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
beatmapHash,
|
|
112
|
+
onlineMapId,
|
|
113
|
+
misses,
|
|
114
|
+
hits,
|
|
115
|
+
speed,
|
|
116
|
+
mods: parsedMods,
|
|
117
|
+
spin,
|
|
118
|
+
replayBytes: bytes.toString("base64"),
|
|
119
|
+
pauses: null,
|
|
120
|
+
failTime,
|
|
121
|
+
};
|
|
122
|
+
}
|