├── .gitignore
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── proxy.py
├── src
├── commands
│ ├── Interface.ts
│ ├── account.ts
│ ├── alias.json
│ ├── debug.ts
│ ├── exit.ts
│ ├── help.ts
│ ├── kick.ts
│ ├── maintenance.ts
│ └── target.ts
├── db
│ ├── Account.ts
│ ├── Database.ts
│ └── Player.ts
├── http
│ ├── HttpServer.ts
│ ├── cert
│ │ ├── cert.crt
│ │ └── cert.key
│ └── routes
│ │ ├── Handler.ts
│ │ ├── account
│ │ └── risky
│ │ │ └── api
│ │ │ └── check.ts
│ │ ├── combo
│ │ └── box
│ │ │ └── api
│ │ │ └── config
│ │ │ └── sdk
│ │ │ └── combo.ts
│ │ ├── data_abtest_api
│ │ └── config
│ │ │ └── experiment
│ │ │ └── list.ts
│ │ ├── hkrpg
│ │ └── dataUpload.ts
│ │ ├── hkrpg_global
│ │ ├── combo
│ │ │ └── granter
│ │ │ │ ├── api
│ │ │ │ ├── compareProtocolVersion.ts
│ │ │ │ └── getConfig.ts
│ │ │ │ └── login
│ │ │ │ └── v2
│ │ │ │ └── login.ts
│ │ └── mdk
│ │ │ ├── agreement
│ │ │ └── api
│ │ │ │ └── getAgreementInfos.ts
│ │ │ └── shield
│ │ │ └── api
│ │ │ ├── loadConfig.ts
│ │ │ ├── login.ts
│ │ │ └── verify.ts
│ │ ├── query_dispatch.ts
│ │ ├── query_gateway.ts
│ │ └── sdk
│ │ └── dataUpload.ts
├── index.ts
├── server
│ ├── kcp
│ │ ├── Handshake.ts
│ │ ├── Packet.ts
│ │ ├── SRServer.ts
│ │ ├── Session.ts
│ │ └── initial.key
│ └── packets
│ │ ├── ChangeLineupLeaderCsReq.ts
│ │ ├── FinishTalkMissionCsReq.ts
│ │ ├── GetAllLineupDataCsReq.ts
│ │ ├── GetAvatarDataCsReq.ts
│ │ ├── GetBagCsReq.ts
│ │ ├── GetBasicInfoCsReq.ts
│ │ ├── GetChallengeCsReq.ts
│ │ ├── GetChallengeRaidInfoCsReq.ts
│ │ ├── GetCurBattleInfoCsReq.ts
│ │ ├── GetCurLineupDataCsReq.ts
│ │ ├── GetCurSceneInfoCsReq.ts
│ │ ├── GetDialogueEventDataCsReq.ts
│ │ ├── GetExpeditionDataCsReq.ts
│ │ ├── GetFirstTalkNpcCsReq.ts
│ │ ├── GetHeroBasicTypeInfoCsReq.ts
│ │ ├── GetHeroPathCsReq.ts
│ │ ├── GetLevelRewardTakenListCsReq.ts
│ │ ├── GetLoginActivityCsReq.ts
│ │ ├── GetMailCsReq.ts
│ │ ├── GetMazeTimeOfDayCsReq.ts
│ │ ├── GetMissionDataCsReq.ts
│ │ ├── GetMissionEventDataCsReq.ts
│ │ ├── GetMissionStatusCsReq.ts
│ │ ├── GetNpcStatusCsReq.ts
│ │ ├── GetQuestDataCsReq.ts
│ │ ├── GetRogueInfoCsReq.ts
│ │ ├── GetSpringRecoverDataCsReq.ts
│ │ ├── PacketHandler.ts
│ │ ├── PlayerGetTokenCsReq.ts
│ │ ├── PlayerKeepAliveNotify.ts
│ │ ├── PlayerLoginCsReq.ts
│ │ ├── PlayerLogoutCsReq.ts
│ │ ├── SceneEntityMoveCsReq.ts
│ │ └── SyncTimeCsReq.ts
└── util
│ ├── Config.ts
│ ├── Logger.ts
│ ├── ProtoFactory.ts
│ └── stringSimilarity.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 | package-lock.json
44 |
45 | # TypeScript v1 declaration files
46 | typings/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Microbundle cache
58 | .rpt2_cache/
59 | .rts2_cache_cjs/
60 | .rts2_cache_es/
61 | .rts2_cache_umd/
62 |
63 | # Optional REPL history
64 | .node_repl_history
65 |
66 | # Output of 'npm pack'
67 | *.tgz
68 |
69 | # Yarn Integrity file
70 | .yarn-integrity
71 |
72 | # dotenv environment variables file
73 | .env
74 | .env.test
75 |
76 | # parcel-bundler cache (https://parceljs.org/)
77 | .cache
78 |
79 | # Next.js build output
80 | .next
81 |
82 | # Nuxt.js build / generate output
83 | .nuxt
84 | dist
85 |
86 | # Gatsby files
87 | .cache/
88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
89 | # https://nextjs.org/blog/next-9-1#public-directory-support
90 | # public
91 |
92 | # vuepress build output
93 | .vuepress/dist
94 |
95 | # Serverless directories
96 | .serverless/
97 |
98 | # FuseBox cache
99 | .fusebox/
100 |
101 | # DynamoDB Local files
102 | .dynamodb/
103 |
104 | # TernJS port file
105 | .tern-port
106 |
107 | # CrepeSR
108 | config.json
109 | src/data/*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CrepeSR
2 | Fuck MHY
3 |
4 | [Discord](https://discord.gg/sCAC282C)
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "ts-node-dev": "^2.0.0"
4 | },
5 | "scripts": {
6 | "start": "ts-node-dev src/index.ts --respawn --transpile-only"
7 | },
8 | "dependencies": {
9 | "@types/express": "^4.17.13",
10 | "colorts": "^0.1.63",
11 | "dgram": "^1.0.1",
12 | "express": "^4.18.1",
13 | "mongodb": "^4.8.0",
14 | "node-kcp-token": "github:memetrollsxd/node-kcp",
15 | "protobufjs": "^7.0.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/proxy.py:
--------------------------------------------------------------------------------
1 | """MITM script for Star Rail."""
2 | from mitmproxy import http
3 | from mitmproxy import ctx
4 | from mitmproxy.proxy import layer, layers
5 |
6 |
7 | def load(loader):
8 | # ctx.options.web_open_browser = False
9 | # We change the connection strategy to lazy so that next_layer happens before we actually connect upstream.
10 | ctx.options.connection_strategy = "lazy"
11 | ctx.options.upstream_cert = False
12 | ctx.options.ssl_insecure = True
13 |
14 |
15 | def next_layer(nextlayer: layer.NextLayer):
16 | ctx.log(
17 | f"{nextlayer.context=}\n"
18 | f"{nextlayer.data_client()[:70]=}\n"
19 | )
20 | sni = nextlayer.context.client.sni
21 | if nextlayer.context.client.tls and sni and (sni.endswith("yuanshen.com") or sni.endswith("mihoyo.com") or sni.endswith("hoyoverse.com") or sni.endswith("starrails.com")):
22 | ctx.log('sni:' + sni)
23 | nextlayer.context.server.address = ("127.0.0.1", 443)
24 |
25 |
26 | def request(flow: http.HTTPFlow) -> None:
27 | # flow.request.scheme = "http"
28 |
29 | # pretty_host takes the "Host" header of the request into account
30 | if flow.request.pretty_url.startswith('http://log-upload-os.mihoyo.com'):
31 | flow.response = http.Response.make(
32 | 404, # (optional) status code
33 | b"404 not found", # (optional) content
34 | {"Content-Type": "text/html"} # (optional) headers
35 | )
36 | return
--------------------------------------------------------------------------------
/src/commands/Interface.ts:
--------------------------------------------------------------------------------
1 | import { createInterface } from 'readline';
2 | import _alias from './alias.json';
3 | import Logger from '../util/Logger';
4 | import Session from '../server/kcp/Session';
5 |
6 | const c = new Logger("Command", "blue");
7 | const alias: { [key: string]: string } = _alias;
8 |
9 | export class Command {
10 | public readonly name: string;
11 | public readonly args: string[];
12 |
13 | public constructor(public readonly full: string) {
14 | const split = full.split(" ");
15 | this.name = split[0];
16 | this.args = split.slice(1);
17 | }
18 | }
19 |
20 | export default class Interface {
21 | public static readonly rl = createInterface({
22 | input: process.stdin,
23 | output: process.stdout
24 | });
25 |
26 | public static target: Session;
27 |
28 | private constructor() { }
29 |
30 | public static readonly start = () => {
31 | Interface.rl.question("", (_command) => {
32 | if (!_command) {
33 | Interface.start();
34 | return;
35 | }
36 | const cmd = new Command(_command);
37 | import(`./${alias[cmd.name] || cmd.name}`).then(async module => {
38 | await module.default(cmd);
39 | }).catch(err => {
40 | if (err.code == "MODULE_NOT_FOUND") {
41 | c.log(`Command ${cmd.name} not found.`);
42 | return;
43 | }
44 | c.error(err);
45 | });
46 | Interface.start();
47 | });
48 |
49 | Interface.rl.on('close', () => {
50 | console.log('Have a great day!');
51 | process.exit(0);
52 | });
53 | }
54 | }
--------------------------------------------------------------------------------
/src/commands/account.ts:
--------------------------------------------------------------------------------
1 | import Account from "../db/Account";
2 | import Logger from "../util/Logger";
3 | import { Command } from "./Interface";
4 | const c = new Logger("/account", "blue");
5 |
6 | export default async function handle(command: Command) {
7 | switch (command.args[0]) {
8 | case "create":
9 | if (!command.args[1]) {
10 | c.log(`Usage: account create [uid]`);
11 | return;
12 | }
13 | try {
14 | const acc = await Account.create(command.args[1], command.args[2]);
15 | c.log(`Account ${acc.name} with UID ${acc.uid} created.`);
16 | } catch (e) {
17 | c.error(e as Error);
18 | }
19 | break;
20 | case "delete":
21 | if (!command.args[1]) {
22 | c.log(`Usage: account delete `);
23 | return;
24 | }
25 | const acc = await Account.fromUID(command.args[1]);
26 | if (!acc) {
27 | c.error(`Account with UID ${command.args[1]} does not exist.`);
28 | return;
29 | }
30 | Account.delete(command.args[1]);
31 | c.log(`Account ${acc.name} with UID ${acc.uid} deleted successfully.`);
32 | break;
33 | default:
34 | c.log(`Usage: account create [uid]`);
35 | c.log(`Usage: account delete `);
36 | }
37 | }
--------------------------------------------------------------------------------
/src/commands/alias.json:
--------------------------------------------------------------------------------
1 | {
2 | "close": "exit",
3 | "stop": "exit",
4 | "t": "target",
5 | "acc": "account",
6 | "d": "debug",
7 | "?": "help"
8 | }
--------------------------------------------------------------------------------
/src/commands/debug.ts:
--------------------------------------------------------------------------------
1 | import Config from "../util/Config";
2 | import Logger, { VerboseLevel } from "../util/Logger";
3 | import { Command } from "./Interface";
4 | const c = new Logger("/debug", "blue");
5 |
6 | export default async function handle(command: Command) {
7 | if (!command.args[0]) c.log(`VerboseLevel: ${Config.VERBOSE_LEVEL}`);
8 | else {
9 | let level = parseInt(command.args[0]);
10 | if (!level) level = 0;
11 | if (level > 2 || level < 0) {
12 | c.log("Invalid verbose level. Must be between 0 and 2.");
13 | return;
14 | }
15 |
16 | Config.VERBOSE_LEVEL = level as unknown as VerboseLevel;
17 | Logger.VERBOSE_LEVEL = level as unknown as VerboseLevel;
18 | c.log(`VerboseLevel set to ${Config.VERBOSE_LEVEL} (${VerboseLevel[level]})`);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/commands/exit.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../util/Logger";
2 | import { Command } from "./Interface";
3 | const c = new Logger("/exit", "blue");
4 |
5 | export default async function handle(command: Command) {
6 | c.log("Good riddance!");
7 | process.exit(0);
8 | }
--------------------------------------------------------------------------------
/src/commands/help.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../util/Logger";
2 | import { Command } from "./Interface";
3 | import fs from 'fs';
4 | const c = new Logger("/help", "blue");
5 |
6 | export default async function handle(command: Command) {
7 | const cmds = fs.readdirSync(__dirname);
8 | c.log(`${cmds.length} commands available:`)
9 |
10 | cmds.forEach(cmd => {
11 | if (cmd.endsWith(".ts")) {
12 | const cmdName = cmd.replace(/.ts/gm, "");
13 | if (cmdName !== "Interface") c.trail(cmdName);
14 | }
15 | })
16 | }
--------------------------------------------------------------------------------
/src/commands/kick.ts:
--------------------------------------------------------------------------------
1 | import { BlackLimitLevel, PlayerKickOutScNotify, PlayerKickOutScNotify_KickType } from "../data/proto/StarRail";
2 | import SRServer from "../server/kcp/SRServer";
3 | import Logger from "../util/Logger";
4 | import Interface, { Command } from "./Interface";
5 | const c = new Logger("/kick", "blue");
6 |
7 | export default async function handle(command: Command) {
8 | if (!Interface.target) {
9 | c.log("No target specified");
10 | return;
11 | }
12 |
13 | Interface.target.send("PlayerKickOutScNotify", {
14 | kickType: PlayerKickOutScNotify_KickType.KICK_BLACK,
15 | blackInfo: {
16 | limitLevel: BlackLimitLevel.BLACK_LIMIT_LEVEL_ALL,
17 | beginTime: Math.round(Date.now() / 1000),
18 | endTime: Math.round(Date.now() / 1000),
19 | banType: 2
20 | }
21 | } as PlayerKickOutScNotify);
22 |
23 | // SRServer.getInstance().sessions.delete(`${Interface.target.ctx.address}:${Interface.target.ctx.port}`);
24 |
25 | c.log(`Kicked ${Interface.target.account.name}`);
26 | }
--------------------------------------------------------------------------------
/src/commands/maintenance.ts:
--------------------------------------------------------------------------------
1 | import Config from "../util/Config";
2 | import Logger, { VerboseLevel } from "../util/Logger";
3 | import { Command } from "./Interface";
4 | const c = new Logger("/maintenance", "blue");
5 |
6 | export default async function handle(command: Command) {
7 | switch (command.args[0]) {
8 | case "on":
9 | Config.GAMESERVER.MAINTENANCE = true;
10 | if (command.args[1]) Config.GAMESERVER.MAINTENANCE_MSG = command.args.slice(1).join(" ");
11 | c.log("Maintenance mode enabled.");
12 | break;
13 | case "off":
14 | Config.GAMESERVER.MAINTENANCE = false;
15 | c.log("Maintenance mode disabled.");
16 | break;
17 | default:
18 | c.log(`Maintenance mode is ${Config.GAMESERVER.MAINTENANCE ? "enabled" : "disabled"}`);
19 | c.log(`Maintenance message: ${Config.GAMESERVER.MAINTENANCE_MSG}`);
20 | c.log("Usage: /maintenance [on|off] [message]");
21 | break;
22 | }
23 | }
--------------------------------------------------------------------------------
/src/commands/target.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../util/Logger";
2 | import Interface, { Command } from "./Interface";
3 | import findBestMatch from "../util/stringSimilarity";
4 | import SRServer from "../server/kcp/SRServer";
5 | import Session from "../server/kcp/Session";
6 | const c = new Logger("/target", "blue");
7 |
8 | export default async function handle(command: Command) {
9 | const target = command.args[0];
10 | const possibleTargets: {
11 | id: string;
12 | session: Session;
13 | uid: number;
14 | }[] = [];
15 |
16 | SRServer.getInstance().sessions.forEach(client => {
17 | possibleTargets.push({
18 | id: `${client.ctx.address}:${client.ctx.port}`,
19 | uid: Number(client.account.uid),
20 | session: client
21 | });
22 | });
23 |
24 | if (!target) {
25 | c.log("No target specified");
26 | c.log("Possible targets: ");
27 | possibleTargets.forEach(x => c.trail(`${x.id} (UID: ${x.uid})`));
28 | return;
29 | }
30 |
31 | const autoTarget = findBestMatch(target, possibleTargets.map(x => x.id)).bestMatch.target;
32 |
33 | Interface.target = possibleTargets.find(x => x.id === autoTarget)!.session;
34 |
35 | c.log(`Target set to ${autoTarget}`);
36 | }
--------------------------------------------------------------------------------
/src/db/Account.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../util/Logger";
2 | import Database from "./Database";
3 | const c = new Logger("Account");
4 |
5 | interface AccountI {
6 | uid: string | number;
7 | name: string;
8 | token: string;
9 | }
10 |
11 | export default class Account {
12 | private constructor(public readonly uid: string | number, public readonly name: string, public readonly token: string) {
13 |
14 | }
15 |
16 | public static async fromUID(uid: string | number): Promise {
17 | const db = Database.getInstance();
18 | const account = await db.get("accounts", { _id: Number(uid) });
19 | if (!account) return;
20 | return new Account(Number(account._id.toString()), account.name, account.token);
21 | }
22 |
23 | public static async fromToken(token: string): Promise {
24 | const db = Database.getInstance();
25 | const account = await db.get("accounts", { token });
26 | if (!account) return;
27 | return new Account(Number(account._id.toString()), account.name, account.token);
28 | }
29 |
30 | public static async fromUsername(name: string): Promise {
31 | const db = Database.getInstance();
32 | const account = await db.get("accounts", { name });
33 | if (!account) return;
34 | return new Account(Number(account._id.toString()), account.name, account.token);
35 | }
36 |
37 | public static async create(name: string, uid?: string | number): Promise {
38 | const db = Database.getInstance();
39 | let selfAssignedUID = true;
40 | if (!uid) {
41 | uid = Math.round(Math.random() * 50000);
42 | selfAssignedUID = false;
43 | }
44 |
45 | const account = await db.get("accounts", { uid });
46 | if (account) {
47 | if (!selfAssignedUID) {
48 | return await Account.create(name, uid);
49 | } else {
50 | throw new Error(`Account with uid ${uid} already exists.`);
51 | }
52 | }
53 |
54 | const token = generateToken();
55 | await db.set("accounts", { _id: Number(uid), name, token });
56 | return new Account(Number(uid), name, token);
57 | }
58 |
59 | public static async delete(uid: string | number): Promise {
60 | const db = Database.getInstance();
61 | const account = await Account.fromUID(uid);
62 | if (!account) {
63 | throw new Error(`Account with uid ${uid} does not exist.`);
64 | }
65 | await db.delete("accounts", { _id: Number(uid) });
66 | }
67 |
68 | public async save() {
69 | const db = Database.getInstance();
70 | await db.update("accounts", { _id: Number(this.uid) }, this);
71 | }
72 | }
73 |
74 | function generateToken(): string {
75 | let token = "";
76 | for (let i = 0; i < 16; i++) {
77 | token += Math.random().toString(36).substring(2, 15)
78 | }
79 | return token;
80 | }
--------------------------------------------------------------------------------
/src/db/Database.ts:
--------------------------------------------------------------------------------
1 | import { MongoClient } from "mongodb";
2 | import Config from "../util/Config";
3 | import Logger from "../util/Logger";
4 | const c = new Logger("Database");
5 |
6 | export default class Database {
7 | private static instance: Database;
8 | public static client: MongoClient;
9 | private constructor() {
10 | Database.client = new MongoClient(Config.MONGO_URI);
11 | try {
12 | Database.client.connect();
13 | } catch (e) {
14 | c.error(e as Error);
15 | }
16 | }
17 |
18 | public static getInstance(): Database {
19 | if (!Database.instance) {
20 | Database.instance = new Database();
21 | }
22 | return Database.instance;
23 | }
24 |
25 | public async get(collection: string, query?: object) {
26 | try {
27 | const db = await Database.client.db();
28 | const _collection = db.collection(collection);
29 | if (!(await db.listCollections({ name: collection }).toArray()).length) {
30 | c.warn(`Collection ${collection} does not exist. Creating...`);
31 | await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
32 | }
33 | const result = query ? await _collection.findOne(query) : await _collection.findOne();
34 | return result;
35 | } catch (e) {
36 | c.error(e as Error);
37 | return null;
38 | }
39 | }
40 |
41 | public async set(collection: string, payload: any) {
42 | try {
43 | const db = await Database.client.db();
44 | const _collection = db.collection(collection);
45 | if (!(await db.listCollections({ name: collection }).toArray()).length) {
46 | c.warn(`Collection ${collection} does not exist. Creating...`);
47 | await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
48 | }
49 | return await _collection.insertOne(payload);
50 | } catch (e) {
51 | c.error(e as Error);
52 | }
53 | }
54 |
55 | public async delete(collection: string, query: object) {
56 | try {
57 | const db = await Database.client.db();
58 | const _collection = db.collection(collection);
59 | if (!(await db.listCollections({ name: collection }).toArray()).length) {
60 | c.warn(`Collection ${collection} does not exist. Creating...`);
61 | await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
62 | }
63 | return await _collection.deleteOne(query);
64 | } catch (e) {
65 | c.error(e as Error);
66 | }
67 | }
68 |
69 | public async update(collection: string, query: object, payload: object) {
70 | try {
71 | const db = await Database.client.db();
72 | const _collection = db.collection(collection);
73 | if (!(await db.listCollections({ name: collection }).toArray()).length) {
74 | c.warn(`Collection ${collection} does not exist. Creating...`);
75 | await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
76 | }
77 | return await _collection.updateOne(query, { $set: payload }, { upsert: true });
78 | } catch (e) {
79 | c.error(e as Error);
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/src/db/Player.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../util/Logger";
2 | import Account from "./Account";
3 | import Database from "./Database";
4 | const c = new Logger("Player");
5 |
6 | interface PlayerI {
7 | _id: number;
8 | name: string;
9 | token: string;
10 | banned: boolean;
11 | basicInfo: {
12 | nickname: string;
13 | level: number;
14 | exp: number;
15 | stamina: number;
16 | mcoin: number;
17 | hcoin: number;
18 | scoin: number;
19 | worldLevel: number;
20 | }
21 | }
22 |
23 | export default class Player {
24 | private constructor(public db: PlayerI) {
25 |
26 | }
27 |
28 | public static async fromUID(uid: number | string): Promise {
29 | if (typeof uid == "string") uid = Number(uid);
30 | const db = Database.getInstance();
31 | const player = await db.get("players", { _id: uid }) as unknown as PlayerI;
32 | if (!player) return Player.create(uid);
33 | return new Player(player);
34 | }
35 |
36 | public static async fromToken(token: string): Promise {
37 | const db = Database.getInstance();
38 | const plr = await db.get("players", { token }) as unknown as PlayerI;
39 | if (!plr) return Player.fromUID((await Account.fromToken(token))?.uid || Math.round(Math.random() * 50000));
40 |
41 | return new Player(plr);
42 | }
43 |
44 | public static async create(uid: number | string): Promise {
45 | if (typeof uid == "string") uid = Number(uid);
46 | const acc = await Account.fromUID(uid);
47 | if (!acc) {
48 | c.warn(`Account ${uid} not found`);
49 | return;
50 | }
51 | const db = Database.getInstance();
52 |
53 | const dataObj = {
54 | _id: acc.uid,
55 | name: acc.name,
56 | token: acc.token,
57 | banned: false
58 | } as PlayerI
59 |
60 | await db.set("players", dataObj);
61 | return new Player(dataObj);
62 | }
63 |
64 | public async save() {
65 | const db = Database.getInstance();
66 | await db.update("players", { _id: this.db._id } , this.db);
67 | }
68 | }
--------------------------------------------------------------------------------
/src/http/HttpServer.ts:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import https from 'https';
3 | import fs from 'fs';
4 | import { resolve } from 'path';
5 | import Config from '../util/Config';
6 | import Logger, { VerboseLevel } from '../util/Logger';
7 | const c = new Logger("HTTP", "cyan");
8 |
9 | function r(...args: string[]) {
10 | return fs.readFileSync(resolve(__dirname, ...args)).toString();
11 | }
12 |
13 | const HTTPS_CONFIG = {
14 | key: r('./cert/cert.key'),
15 | cert: r('./cert/cert.crt'),
16 | }
17 |
18 | export default class HttpServer {
19 | private readonly server;
20 | private static instance: HttpServer;
21 |
22 | private constructor() {
23 | this.server = express();
24 | this.server.use(express.json());
25 | this.server.route('/*').all((req, res) => {
26 | if (Logger.VERBOSE_LEVEL > VerboseLevel.WARNS) c.log(`${req.method} ${req.url}`);
27 | import(`./routes${req.url.split('?')[0]}`).then(async r => {
28 | await r.default(req, res);
29 | }).catch(err => {
30 | res.send({
31 | code: 0
32 | });
33 | if (err.code === 'MODULE_NOT_FOUND') return;
34 | c.error(err);
35 | });
36 | });
37 | }
38 |
39 | public start(): void {
40 | https.createServer(HTTPS_CONFIG, this.server).listen(Config.HTTP.HTTP_PORT, Config.HTTP.HTTP_PORT);
41 | this.server.listen(80, Config.HTTP.HTTP_HOST, () => {
42 | c.log(`Listening on ${Config.HTTP.HTTP_HOST}:${Config.HTTP.HTTP_PORT}`);
43 | });
44 | }
45 |
46 | public static getInstance(): HttpServer {
47 | if (!HttpServer.instance) {
48 | HttpServer.instance = new HttpServer();
49 | }
50 | return HttpServer.instance;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/http/cert/cert.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIID2TCCAsGgAwIBAgIUO4lg/Dj+kZ9fv+AFxQBrMNUJc9cwDQYJKoZIhvcNAQEL
3 | BQAwVjESMBAGA1UEAwwJbG9jYWxob3N0MQswCQYDVQQGEwJDWTEOMAwGA1UECAwF
4 | Q3JlcGUxDjAMBgNVBAcMBUNyZXBlMRMwEQYDVQQKDApDcmVwZSBJbmMuMB4XDTIx
5 | MTIxMjE2NDY0NloXDTMxMTIxMDE2NDY0NlowVjESMBAGA1UEAwwJbG9jYWxob3N0
6 | MQswCQYDVQQGEwJDWTEOMAwGA1UECAwFQ3JlcGUxDjAMBgNVBAcMBUNyZXBlMRMw
7 | EQYDVQQKDApDcmVwZSBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
8 | AQEAnPFIkkIHKJdmWdUdmwja9qENmnmVL7iSFrgMhBRuZadsD1gYb78liWHH/CT4
9 | 5zmVJ44LiON3DjmCP/gAbFe3epPifB5i6CIh+tolqG8fg9WyyWrP71Z+raaGtlV4
10 | NIyybRJI/9Gjysf4aehpCtEKJf4BAy82lrfBhNhmHf16W65c0NCGMJoB9Wr+wZCd
11 | R6PzcKgWNa33YVfXTD8PiTOU9cLRvRFgwO870f/8jekxVdHggfTdQmVj9rcNet6X
12 | MrWvzUI4LnI2JPyyEpMtlAQnDQ2+aGG5A3GdPPkWeaST+vF6CDCTFkg8Dxw0jQ30
13 | jc0uQv/zz0mFuqvvivgpGSXeuwIDAQABo4GeMIGbMB0GA1UdDgQWBBS8E5THWThf
14 | TVAwTnGez4druLTacDAfBgNVHSMEGDAWgBS8E5THWThfTVAwTnGez4druLTacDAO
15 | BgNVHQ8BAf8EBAMCBaAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16 | MCcGA1UdEQQgMB6CDCoubWlob3lvLmNvbYIOKi55dWFuc2hlbi5jb20wDQYJKoZI
17 | hvcNAQELBQADggEBAIVqx99S1DYtyLqsi15KwTUawShW9iJVsvpk59vK6qbbzuGZ
18 | L72DrRJVTMxodv4WLaiM+te1TsW0WmdrhUYUBfIi+JpB67QB6aWKkOCP8fYq+mWn
19 | Q3vuAEC6KpWH30j+0S58LVV+2iaGVetXYmYDXKoNslyVuJAM4iZSutTZhctO2Fxm
20 | Vicp0fiPq/HJzxsmKHxyFJsgsdV0Dl9ElnlhpH77qxi/nXuUz9YlWZwwQI8KSsKm
21 | sOzTUpSHHHpDocT24Yx73bR3Hd8CJam2bCEOOIIJG7sPx2lhTEJ+sKHDh4jHmRUI
22 | 3rVk5R+x1CcIrAgin+8nH28PhZFdOKs+CYMYGk0=
23 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/src/http/cert/cert.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCc8UiSQgcol2ZZ
3 | 1R2bCNr2oQ2aeZUvuJIWuAyEFG5lp2wPWBhvvyWJYcf8JPjnOZUnjguI43cOOYI/
4 | +ABsV7d6k+J8HmLoIiH62iWobx+D1bLJas/vVn6tpoa2VXg0jLJtEkj/0aPKx/hp
5 | 6GkK0Qol/gEDLzaWt8GE2GYd/XpbrlzQ0IYwmgH1av7BkJ1Ho/NwqBY1rfdhV9dM
6 | Pw+JM5T1wtG9EWDA7zvR//yN6TFV0eCB9N1CZWP2tw163pcyta/NQjgucjYk/LIS
7 | ky2UBCcNDb5oYbkDcZ08+RZ5pJP68XoIMJMWSDwPHDSNDfSNzS5C//PPSYW6q++K
8 | +CkZJd67AgMBAAECggEBAJv3KQC4f3a2Zu+1XBObTEc2rFcsprbi/MN5Km8EAuYg
9 | 6MGi8b3zvrD1rJGGiJj5X6IMhqgGLWXEfw1lP75ruZomZzij1fUNHqm1qyDlNfOF
10 | JoUGEhiu43tc95kx/SB0Bklgl40rYFQAQH23itRGA4jYEVeBzwUfHkEP8QOyyKtc
11 | YKJHa1jCEvE4XHxLqxFC+z7aNmpFonrW8OerVwrDPIkFbXYrC1alzxqMcNBJVeKE
12 | LFFc6EK9ppoPSsm600yac5gOX2ima9JkaYkGKhK25D4NXCd511Ea/TJNctA8IkYA
13 | QB7mCzLHdapRlhSplDwwwgNRzlrkImbqyS2+768ejYkCgYEAzyatfH62cDSDP5e1
14 | oukWI46AqybfIhd9kHzIbIyPjuSb3RvvuxIfNBFjUxRyh+ggCjnRA14HcZzDcGRd
15 | 6VpApq80LQk6mhklKicJNRrcuEvdmj+kRJ+XtSbNZhJVUkNf7nmHCOoJkEwRsblL
16 | kIZCVmfkWAKFjHnCEqH5RHvTbacCgYEAwfObyw0eMD+X23IpyEsCsTKIwIk4Zl8J
17 | iTNnR9yp6B9JdwLSdEWQjhXSltkfmNZ3WXYoyh6kr3jp8d5EqWX1P8JrZBaZikTD
18 | y526kKIvs/I/iW3obOoE6CX6LJEGob8bAPkvu2u37Rghign57W02fYtzJUuqPAoK
19 | b5mtrQ/ycM0CgYBsR8pthgq1Mi3dAt82DeK9qVKGpGYEewTujttxKjQsPEFg3aZ9
20 | Qaa/38rsdYa8ldCRp9EikncPoyLh0ATq4nti5bg/RlC0lipAE3GTqbvwNe/bHiMu
21 | n8F8NpEtJq4ktwUhMbMtLLDdFXY2USY3oIZyhhHtEzxdxpN0i+gxLQzChwKBgQCG
22 | FFztYGIwRKY8hI2x83km+qJjR/l/e8/h03Fg0oF7ALYO2hqXWsf2EcwFkJAxXoIf
23 | jHniUJDU5agFFv0shlmm/Ea1aJI4bhVVG/MvrY+AvMWDwkFdmeJOgoKScKe/BZgr
24 | chi3Xl5GP9pfzUnEAy4aWF7/t3E2FFLml7zi2RVnOQKBgQCYmzwikvHpR+HRiZL9
25 | m0TB6mayGbwQO3xU/naZ1UyCydsRORQnbKaTWSMZgrr7nTAqDhegfUyJXX+uxhGQ
26 | cGu9uLENZWrysXROpMZBhgyNUbDPdO0okIMoJ3kUSocC7L7lpWyZGOxgMwi0a4qK
27 | nV1QDKXsA3oBZn9MJpkuQ81jCw==
28 | -----END PRIVATE KEY-----
--------------------------------------------------------------------------------
/src/http/routes/Handler.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | // Test handler
5 | res.send({
6 | retcode: -1,
7 | message: "Invalid endpoint"
8 | });
9 | }
--------------------------------------------------------------------------------
/src/http/routes/account/risky/api/check.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | // Example request:
4 | // {
5 | // "action_type": "login",
6 | // "api_name": "/shield/api/login",
7 | // "username": "test"
8 | // }
9 |
10 | export default function handle(req: Request, res: Response) {
11 | // Test handler
12 | res.send({
13 | retcode: 0,
14 | message: "OK",
15 | data: {
16 | id: "",
17 | action: "ACTION_NONE",
18 | geetest: null
19 | }
20 | });
21 | }
--------------------------------------------------------------------------------
/src/http/routes/combo/box/api/config/sdk/combo.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | res.send({
5 | data: null,
6 | message: "RetCode_NoConfig",
7 | retcode: 7
8 | });
9 | }
--------------------------------------------------------------------------------
/src/http/routes/data_abtest_api/config/experiment/list.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | res.send({
5 | retcode: 0,
6 | success: true,
7 | message: "",
8 | data: []
9 | });
10 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg/dataUpload.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import Logger, { VerboseLevel } from "../../../util/Logger";
3 | const c = new Logger("dataUpload", "green");
4 |
5 | export default function handle(req: Request, res: Response) {
6 | try {
7 | const content = req.body[0].uploadContent;
8 | if (content.LogStr) {
9 | c.warn(content.LogStr);
10 | if (Logger.VERBOSE_LEVEL == VerboseLevel.ALL) c.trail(content.StackTrace);
11 | }
12 | } catch { }
13 | res.send({ code: 0 });
14 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/combo/granter/api/compareProtocolVersion.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | // Test handler
5 | res.send({
6 | retcode: 0,
7 | message: "OK",
8 | data: {
9 | modified: true,
10 | protocol: {
11 | id: 0,
12 | app_id: 11,
13 | language: "en",
14 | user_proto: "",
15 | priv_proto: "",
16 | major: 1,
17 | minimum: 2,
18 | create_time: "0",
19 | teenager_proto: "",
20 | third_proto: ""
21 | }
22 | }
23 | });
24 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/combo/granter/api/getConfig.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | res.send({
5 | retcode: 0,
6 | message: "OK",
7 | data: {
8 | protocol: true,
9 | qr_enabled: true,
10 | log_level: "INFO",
11 | announce_url: "https://sdk.hoyoverse.com/hkrpg/announcement/index.html?sdk_presentation_style=fullscreen\u0026sdk_screen_transparent=true\u0026auth_appid=announcement\u0026authkey_ver=1\u0026sign_type=2#/",
12 | push_alias_type: 0,
13 | disable_ysdk_guard: true,
14 | enable_announce_pic_popup: true
15 | }
16 | });
17 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/combo/granter/login/v2/login.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | const data = JSON.parse(req.body.data)
5 |
6 | res.send({
7 | retcode: 0,
8 | message: "OK",
9 | data: {
10 | combo_id: 1,
11 | open_id: data.uid,
12 | combo_token: data.token,
13 | data: {
14 | guest: data.guest
15 | },
16 | heartbeat: false,
17 | account_type: 1,
18 | fatigue_remind: null
19 | }
20 | });
21 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/mdk/agreement/api/getAgreementInfos.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | res.send({
5 | retcode: 0,
6 | message: "OK",
7 | data: {
8 | marketing_agreements: []
9 | }
10 | });
11 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/mdk/shield/api/loadConfig.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 |
3 | export default function handle(req: Request, res: Response) {
4 | res.send({
5 | retcode: 0,
6 | message: "OK",
7 | data: {
8 | id: 24,
9 | game_key: "hkrpg_global",
10 | client: "PC",
11 | identity: "I_IDENTITY",
12 | guest: false,
13 | ignore_versions: "",
14 | scene: "S_NORMAL",
15 | name: "崩坏RPG",
16 | disable_regist: true,
17 | enable_email_captcha: false,
18 | thirdparty: [],
19 | disable_mmt: false,
20 | server_guest: true,
21 | thirdparty_ignore: {
22 | fb: "",
23 | tw: ""
24 | },
25 | enable_ps_bind_account: false,
26 | thirdparty_login_configs: {}
27 | }
28 | });
29 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/mdk/shield/api/login.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import Account from "../../../../../../db/Account";
3 | import Logger from "../../../../../../util/Logger";
4 | const c = new Logger("Dispatch");
5 |
6 | // Example request:
7 | // {
8 | // account: "test",
9 | // (RSA)password: "BKWPZjqKfKr6ZKuO40ONwV5JxOi4dg71aeBcxPVK/U+8FM8d5kc5EjLdEXyn6McBvUOL67CmT89eo9jrdwp9xpFexA/C1d9BCxen0NQ+zCrQUkSc6AFD9PYkAmdTNnila5L15SrveQQRtbsDwZeZ9owVH7kyoXuDGUOOA6dc4qE=",
10 | // is_crypto: true
11 | // }
12 |
13 | export default async function handle(req: Request, res: Response) {
14 | const acc = await Account.fromUsername(req.body.account);
15 | const dataObj: any = {
16 | retcode: 0,
17 | message: "OK",
18 | data: {
19 | account: {}
20 | }
21 | }
22 | if (!acc) {
23 | dataObj.retcode = -202;
24 | dataObj.message = "Account not found";
25 | c.warn(`Player ${req.body.account} not found (${req.ip})`);
26 | res.send(dataObj);
27 | } else {
28 | dataObj.data.account = acc;
29 | c.log(`Player ${req.body.account} logged in (${req.ip})`);
30 | res.send(dataObj);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/http/routes/hkrpg_global/mdk/shield/api/verify.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import Account from "../../../../../../db/Account";
3 | import Logger from "../../../../../../util/Logger";
4 | const c = new Logger("Dispatch");
5 | // Example request:
6 | // {"uid":"63884253","token":"ZQmgMdXA1StL9A3aPBUedr8yoiuoLrmV"}
7 |
8 | export default async function handle(req: Request, res: Response) {
9 | const acc = await Account.fromUID(req.body.uid);
10 | const dataObj: any = {
11 | retcode: 0,
12 | message: "OK",
13 | data: {
14 | account: {}
15 | }
16 | }
17 | if (!acc) {
18 | dataObj.retcode = -202;
19 | dataObj.message = "Account not found";
20 | res.send(dataObj);
21 | c.warn(`Player ${req.body.uid} not found (${req.ip})`);
22 | } else {
23 | if (acc.token === req.body.token) {
24 | dataObj.data.account = acc;
25 | c.log(`Player ${req.body.uid} logged in (${req.ip})`);
26 | res.send(dataObj);
27 | } else {
28 | dataObj.retcode = -202;
29 | dataObj.message = "Invalid token";
30 | res.send(dataObj);
31 | }
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/src/http/routes/query_dispatch.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import Config from "../../util/Config";
3 |
4 | interface Region {
5 | dispatch_url: string;
6 | env_type: string;
7 | name: string;
8 | title: string;
9 | }
10 |
11 | export default function handle(req: Request, res: Response) {
12 | const dataObj = {
13 | region_list: [] as Region[],
14 | retcode: 0
15 | }
16 |
17 | Config.DISPATCH.forEach(item => {
18 | dataObj.region_list.push({
19 | dispatch_url: item.DISPATCH_URL,
20 | env_type: "2",
21 | name: item.DISPATCH_NAME,
22 | title: "CrepeSR"
23 | });
24 | });
25 |
26 | res.send(dataObj);
27 | }
--------------------------------------------------------------------------------
/src/http/routes/query_gateway.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import protobuf, { Type } from 'protobufjs';
3 | import { resolve } from 'path';
4 | import Config from "../../util/Config";
5 | import { Gateserver } from "../../data/proto/StarRail";
6 |
7 | export default function handle(req: Request, res: Response) {
8 | const dataObj = Gateserver.fromJSON({
9 | retcode: 0,
10 | msg: "OK",
11 | regionName: "CrepeSR",
12 | ip: Config.GAMESERVER.SERVER_IP,
13 | port: Config.GAMESERVER.SERVER_PORT,
14 | serverDescription: "This is not BingusRail"
15 | });
16 |
17 | if (Config.GAMESERVER.MAINTENANCE) {
18 | dataObj.retcode = 2;
19 | dataObj.msg = Config.GAMESERVER.MAINTENANCE_MSG;
20 | dataObj.stopBeginTime = Date.now();
21 | dataObj.stopEndTime = Date.now() * 2;
22 | }
23 |
24 | let rsp;
25 | try {
26 | rsp = Gateserver.encode(dataObj).finish();
27 | } catch {
28 | rsp = Gateserver.encode(Gateserver.fromJSON({
29 | retcode: 2,
30 | msg: "Internal server error",
31 | stopBeginTime: Date.now(),
32 | stopEndTime: Date.now() * 2,
33 | })).finish();
34 | }
35 | res.send(Buffer.from(rsp).toString('base64'));
36 | }
--------------------------------------------------------------------------------
/src/http/routes/sdk/dataUpload.ts:
--------------------------------------------------------------------------------
1 | import { Request, Response } from "express";
2 | import Logger from "../../../util/Logger";
3 | const c = new Logger("dataUpload", "green");
4 |
5 | export default function handle(req: Request, res: Response) {
6 | res.send({ code: 0 });
7 | }
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @package CrepeSR
3 | * @author Crepe-Inc
4 | * @license AGPL-3.0
5 | */
6 | import Interface from "./commands/Interface";
7 | import HttpServer from "./http/HttpServer";
8 | import SRServer from "./server/kcp/SRServer";
9 | import Logger from "./util/Logger";
10 | import ProtoFactory from "./util/ProtoFactory"
11 |
12 | const c = new Logger("CrepeSR");
13 | c.log(`Starting CrepeSR...`);
14 | ProtoFactory.init();
15 | Interface.start();
16 | HttpServer.getInstance().start();
17 | SRServer.getInstance().start();
--------------------------------------------------------------------------------
/src/server/kcp/Handshake.ts:
--------------------------------------------------------------------------------
1 | export enum HandshakeType {
2 | CONNECT = 1,
3 | DISCONNECT = 2,
4 | SEND_BACK_CONV = 3,
5 | UNKNOWN = 4
6 | }
7 |
8 | export default class Handshake {
9 | private static readonly CONNECT: number[] = [0xff, 0xFFFFFFFF]
10 | private static readonly SEND_BACK_CONV: number[] = [0x145, 0x14514545]
11 | private static readonly DISCONNECT: number[] = [0x194, 0x19419494]
12 |
13 | public readonly conv: number;
14 | public readonly type: number[];
15 | public readonly handshakeType!: HandshakeType;
16 | public readonly token: number;
17 | public readonly data: number;
18 |
19 | public constructor(public readonly bytes: Buffer | HandshakeType) {
20 | if (Buffer.isBuffer(bytes)) {
21 | this.conv = bytes.readUInt32BE(4);
22 | this.token = bytes.readUInt32BE(8);
23 | this.data = bytes.readUInt32BE(12);
24 | this.type = [bytes.readUInt32BE(0), bytes.readUInt32BE(16)];
25 | this.handshakeType = this.decodeType();
26 | } else {
27 | this.conv = 0x69;
28 | this.token = 0x420;
29 | this.data = 0;
30 | this.type = Handshake.SEND_BACK_CONV;
31 | this.handshakeType = HandshakeType.SEND_BACK_CONV;
32 | }
33 | }
34 |
35 | public encode(): Buffer {
36 | const buf = Buffer.alloc(20);
37 | buf.writeUInt32BE(this.type[0]);
38 | buf.writeUInt32BE(this.conv, 4);
39 | buf.writeUInt32BE(this.token, 8);
40 | buf.writeUInt32BE(this.data, 12);
41 | buf.writeUInt32BE(this.type[1], 16);
42 | return buf;
43 | }
44 |
45 | public decodeType(): HandshakeType {
46 | if (this.type[0] == Handshake.CONNECT[0] && this.type[1] == Handshake.CONNECT[1]) {
47 | return HandshakeType.CONNECT;
48 | }
49 | if (this.type[0] == Handshake.SEND_BACK_CONV[0] && this.type[1] == Handshake.SEND_BACK_CONV[1]) {
50 | return HandshakeType.SEND_BACK_CONV
51 | }
52 | if (this.type[0] == Handshake.DISCONNECT[0] && this.type[1] == Handshake.DISCONNECT[1]) {
53 | return HandshakeType.DISCONNECT;
54 | }
55 | return HandshakeType.UNKNOWN;
56 | }
57 | }
--------------------------------------------------------------------------------
/src/server/kcp/Packet.ts:
--------------------------------------------------------------------------------
1 | import Logger, { VerboseLevel } from "../../util/Logger";
2 | import protobuf, { Root } from 'protobufjs';
3 | import { resolve } from 'path';
4 | const c = new Logger("Packet")
5 | export default class Packet {
6 | public readonly cmdid: number;
7 | public readonly data: Buffer;
8 | private static root: Root = Packet.getRoot();
9 | public body: {} = {};
10 |
11 | public constructor(public readonly rawData: Buffer, public readonly protoName: string = "") {
12 | // Remove the header and metadata
13 | const metadataLength = rawData.readUInt16BE(6);
14 | this.data = rawData.subarray(12 + metadataLength, 12 + metadataLength + rawData.readUInt32BE(8));
15 | this.cmdid = this.rawData.readUInt16BE(4);
16 |
17 | this.protoName = this.protoName || CmdID[this.cmdid];
18 | if (this.protoName) {
19 | try {
20 | const Message = Packet.root.lookupTypeOrEnum(this.protoName);
21 | this.body = Message.decode(this.data);
22 | } catch (e) {
23 | c.warn(`Failed to decode ${this.protoName}`);
24 | if (Logger.VERBOSE_LEVEL >= VerboseLevel.ALL) {
25 | c.error(e as Error, false);
26 | }
27 | c.debug(`Data: ${this.data.toString("hex")}`);
28 | }
29 | } else {
30 | c.error(`Unknown packet id ${this.cmdid}`);
31 | }
32 | }
33 |
34 | public static isValid(data: Buffer): boolean {
35 | // Buffer acting fucky so i'll just use good ol' string manipulation
36 | const str = data.toString('hex');
37 | return str.startsWith("01234567") && str.endsWith("89abcdef");
38 | }
39 |
40 | public static encode(name: PacketName, body: {}, customCmdId?: number): Packet | null {
41 | try {
42 | const cmdid = CmdID[name];
43 | const Message = Packet.root.lookupTypeOrEnum(name);
44 |
45 | const data = Buffer.from(Message.encode(body).finish());
46 | const packet = Buffer.allocUnsafe(16 + data.length);
47 | packet.writeUInt32BE(0x1234567);
48 | packet.writeUint16BE(customCmdId || cmdid, 4);
49 | packet.writeUint16BE(0, 6);
50 | packet.writeUint32BE(data.length, 8);
51 | data.copy(packet, 12);
52 | packet.writeUint32BE(0x89abcdef, 12 + data.length);
53 |
54 | return new Packet(packet, name);
55 | } catch (e) {
56 | c.error(e as Error);
57 | return null;
58 | }
59 | }
60 |
61 | private static getRoot(): Root {
62 | try {
63 | // Combined proto file with all definitions
64 | return protobuf.loadSync(resolve(__dirname, `../../data/proto/StarRail.proto`));
65 | } catch (e) {
66 | c.error("Failed to load proto root! Server will not be able to function properly. Please check your data/ folder.");
67 | c.error(e as Error, false);
68 | process.exit(1);
69 | }
70 | }
71 | }
72 |
73 | export type PacketName = keyof typeof CmdID;
74 |
75 | export enum CmdID {
76 | None = 0,
77 | PlayerLoginCsReq = 1,
78 | PlayerLoginScRsp = 2,
79 | PlayerLogoutCsReq = 3,
80 | PlayerLogoutScRsp = 4,
81 | PlayerGetTokenCsReq = 5,
82 | PlayerGetTokenScRsp = 6,
83 | PlayerKeepAliveNotify = 7,
84 | GmTalkScNotify = 8,
85 | PlayerKickOutScNotify = 9,
86 | GmTalkCsReq = 10,
87 | GmTalkScRsp = 11,
88 | ExchangeStaminaCsReq = 14,
89 | ExchangeStaminaScRsp = 15,
90 | GetAuthkeyCsReq = 16,
91 | GetAuthkeyScRsp = 17,
92 | RegionStopScNotify = 18,
93 | AntiAddictScNotify = 19,
94 | SetNicknameCsReq = 20,
95 | SetNicknameScRsp = 21,
96 | GetLevelRewardTakenListCsReq = 22,
97 | GetLevelRewardTakenListScRsp = 23,
98 | GetLevelRewardCsReq = 24,
99 | GetLevelRewardScRsp = 25,
100 | SyncTimeCsReq = 26,
101 | SyncTimeScRsp = 27,
102 | SetLanguageCsReq = 28,
103 | SetLanguageScRsp = 29,
104 | ServerAnnounceNotify = 30,
105 | SetHeroBasicTypeCsReq = 31,
106 | SetHeroBasicTypeScRsp = 32,
107 | GetHeroBasicTypeInfoCsReq = 33,
108 | GetHeroBasicTypeInfoScRsp = 34,
109 | GetHeroPathCsReq = 35,
110 | GetHeroPathScRsp = 36,
111 | HeroPathChangedNotify = 37,
112 | SetGenderCsReq = 38,
113 | SetGenderScRsp = 39,
114 | SetPlayerInfoCsReq = 40,
115 | SetPlayerInfoScRsp = 41,
116 | HeroBasicTypeChangedNotify = 42,
117 | QueryProductInfoCsReq = 43,
118 | QueryProductInfoScRsp = 44,
119 | ClientDownloadDataScNotify = 45,
120 | UpdateFeatureSwitchScNotify = 46,
121 | GetBasicInfoCsReq = 47,
122 | GetBasicInfoScRsp = 48,
123 | DailyRefreshNotify = 49,
124 | PVEBattleResultCsReq = 101,
125 | PVEBattleResultScRsp = 102,
126 | QuitBattleCsReq = 103,
127 | QuitBattleScRsp = 104,
128 | GetCurBattleInfoCsReq = 105,
129 | GetCurBattleInfoScRsp = 106,
130 | SyncClientResVersionCsReq = 107,
131 | SyncClientResVersionScRsp = 108,
132 | QuitBattleScNotify = 109,
133 | GetStageDataCsReq = 201,
134 | GetStageDataScRsp = 202,
135 | StageBeginCsReq = 203,
136 | StageBeginScRsp = 204,
137 | GetAvatarDataCsReq = 301,
138 | GetAvatarDataScRsp = 302,
139 | AvatarExpUpCsReq = 303,
140 | AvatarExpUpScRsp = 304,
141 | UnlockSkilltreeCsReq = 305,
142 | UnlockSkilltreeScRsp = 306,
143 | PromoteAvatarCsReq = 307,
144 | PromoteAvatarScRsp = 308,
145 | DressAvatarCsReq = 309,
146 | DressAvatarScRsp = 310,
147 | TakeOffEquipmentCsReq = 311,
148 | TakeOffEquipmentScRsp = 312,
149 | AddAvatarScNotify = 313,
150 | RankUpAvatarCsReq = 314,
151 | RankUpAvatarScRsp = 315,
152 | DressRelicAvatarCsReq = 316,
153 | DressRelicAvatarScRsp = 317,
154 | TakeOffRelicCsReq = 318,
155 | TakeOffRelicScRsp = 319,
156 | GetWaypointCsReq = 401,
157 | GetWaypointScRsp = 402,
158 | SetCurWaypointCsReq = 403,
159 | SetCurWaypointScRsp = 404,
160 | GetChapterCsReq = 405,
161 | GetChapterScRsp = 406,
162 | WaypointShowNewCsNotify = 407,
163 | TakeChapterRewardCsReq = 408,
164 | TakeChapterRewardScRsp = 409,
165 | GetBagCsReq = 501,
166 | GetBagScRsp = 502,
167 | PromoteEquipmentCsReq = 503,
168 | PromoteEquipmentScRsp = 504,
169 | LockEquipmentCsReq = 505,
170 | LockEquipmentScRsp = 506,
171 | UseItemCsReq = 507,
172 | UseItemScRsp = 508,
173 | RankUpEquipmentCsReq = 509,
174 | RankUpEquipmentScRsp = 510,
175 | ExpUpEquipmentCsReq = 511,
176 | ExpUpEquipmentScRsp = 512,
177 | ComposeItemCsReq = 513,
178 | ComposeItemScRsp = 514,
179 | ExpUpRelicCsReq = 515,
180 | ExpUpRelicScRsp = 516,
181 | LockRelicCsReq = 517,
182 | LockRelicScRsp = 518,
183 | SellItemCsReq = 519,
184 | SellItemScRsp = 520,
185 | RechargeSuccNotify = 521,
186 | PlayerSyncScNotify = 601,
187 | GetStageLineupCsReq = 701,
188 | GetStageLineupScRsp = 702,
189 | GetCurLineupDataCsReq = 703,
190 | GetCurLineupDataScRsp = 704,
191 | JoinLineupCsReq = 705,
192 | JoinLineupScRsp = 706,
193 | QuitLineupCsReq = 707,
194 | QuitLineupScRsp = 708,
195 | SwapLineupCsReq = 709,
196 | SwapLineupScRsp = 710,
197 | SyncLineupNotify = 711,
198 | GetLineupAvatarDataCsReq = 712,
199 | GetLineupAvatarDataScRsp = 713,
200 | ChangeLineupLeaderCsReq = 714,
201 | ChangeLineupLeaderScRsp = 715,
202 | SwitchLineupIndexCsReq = 716,
203 | SwitchLineupIndexScRsp = 717,
204 | SetLineupNameCsReq = 718,
205 | SetLineupNameScRsp = 719,
206 | GetAllLineupDataCsReq = 720,
207 | GetAllLineupDataScRsp = 721,
208 | VirtualLineupDestroyNotify = 722,
209 | GetMailCsReq = 801,
210 | GetMailScRsp = 802,
211 | MarkReadMailCsReq = 803,
212 | MarkReadMailScRsp = 804,
213 | DelMailCsReq = 805,
214 | DelMailScRsp = 806,
215 | TakeMailAttachmentCsReq = 807,
216 | TakeMailAttachmentScRsp = 808,
217 | NewMailScNotify = 809,
218 | GetQuestDataCsReq = 901,
219 | GetQuestDataScRsp = 902,
220 | TakeQuestRewardCsReq = 903,
221 | TakeQuestRewardScRsp = 904,
222 | TakeAchievementLevelRewardCsReq = 905,
223 | TakeAchievementLevelRewardScRsp = 906,
224 | GetMazeCsReq = 1001,
225 | GetMazeScRsp = 1002,
226 | ChooseMazeSeriesCsReq = 1003,
227 | ChooseMazeSeriesScRsp = 1004,
228 | ChooseMazeAbilityCsReq = 1005,
229 | ChooseMazeAbilityScRsp = 1006,
230 | EnterMazeCsReq = 1007,
231 | EnterMazeScRsp = 1008,
232 | MazeBuffScNotify = 1011,
233 | CastMazeSkillCsReq = 1012,
234 | CastMazeSkillScRsp = 1013,
235 | MazePlaneEventScNotify = 1014,
236 | EnterMazeByServerScNotify = 1015,
237 | GetMazeMapInfoCsReq = 1016,
238 | GetMazeMapInfoScRsp = 1017,
239 | GetMazeTimeOfDayCsReq = 1018,
240 | GetMazeTimeOfDayScRsp = 1019,
241 | SetMazeTimeOfDayCsReq = 1020,
242 | SetMazeTimeOfDayScRsp = 1021,
243 | DelMazeTimeOfDayCsReq = 1022,
244 | DelMazeTimeOfDayScRsp = 1023,
245 | ReturnStartAnchorCsReq = 1024,
246 | ReturnStartAnchorScRsp = 1025,
247 | FinishPlotCsReq = 1101,
248 | FinishPlotScRsp = 1102,
249 | GetMissionDataCsReq = 1201,
250 | GetMissionDataScRsp = 1202,
251 | FinishTalkMissionCsReq = 1203,
252 | FinishTalkMissionScRsp = 1204,
253 | MissionRewardScNotify = 1205,
254 | SyncTaskCsReq = 1206,
255 | SyncTaskScRsp = 1207,
256 | DailyTaskDataScNotify = 1208,
257 | TakeDailyTaskExtraRewardCsReq = 1209,
258 | TakeDailyTaskExtraRewardScRsp = 1210,
259 | DailyTaskRewardScNotify = 1211,
260 | MissionGroupWarnScNotify = 1212,
261 | FinishCosumeItemMissionCsReq = 1213,
262 | FinishCosumeItemMissionScRsp = 1214,
263 | GetMissionEventDataCsReq = 1215,
264 | GetMissionEventDataScRsp = 1216,
265 | MissionEventRewardScNotify = 1217,
266 | AcceptMissionEventCsReq = 1218,
267 | AcceptMissionEventScRsp = 1219,
268 | GetMissionStatusCsReq = 1220,
269 | GetMissionStatusScRsp = 1221,
270 | InterruptMissionEventCsReq = 1222,
271 | InterruptMissionEventScRsp = 1223,
272 | SetMissionEventProgressCsReq = 1224,
273 | SetMissionEventProgressScRsp = 1225,
274 | SubMissionRewardScNotify = 1226,
275 | EnterAdventureCsReq = 1301,
276 | EnterAdventureScRsp = 1302,
277 | SceneEntityMoveCsReq = 1401,
278 | SceneEntityMoveScRsp = 1402,
279 | InteractPropCsReq = 1403,
280 | InteractPropScRsp = 1404,
281 | SceneCastSkillCsReq = 1405,
282 | SceneCastSkillScRsp = 1406,
283 | GetCurSceneInfoCsReq = 1407,
284 | GetCurSceneInfoScRsp = 1408,
285 | SceneEntityUpdateScNotify = 1409,
286 | SceneEntityDisappearScNotify = 1410,
287 | SceneEntityMoveScNotify = 1411,
288 | SpringTransferCsReq = 1414,
289 | SpringTransferScRsp = 1415,
290 | UpdateBuffScNotify = 1416,
291 | DelBuffScNotify = 1417,
292 | SpringRefreshCsReq = 1418,
293 | SpringRefreshScRsp = 1419,
294 | LastSpringRefreshTimeNotify = 1420,
295 | ReturnLastTownCsReq = 1421,
296 | ReturnLastTownScRsp = 1422,
297 | SceneEnterStageCsReq = 1423,
298 | SceneEnterStageScRsp = 1424,
299 | EnterSectionCsReq = 1427,
300 | EnterSectionScRsp = 1428,
301 | SetCurInteractEntityCsReq = 1431,
302 | SetCurInteractEntityScRsp = 1432,
303 | RecoverAllLineupCsReq = 1433,
304 | RecoverAllLineupScRsp = 1434,
305 | SavePointsInfoNotify = 1435,
306 | StartCocoonStageCsReq = 1436,
307 | StartCocoonStageScRsp = 1437,
308 | EntityBindPropCsReq = 1438,
309 | EntityBindPropScRsp = 1439,
310 | SetClientPausedCsReq = 1440,
311 | SetClientPausedScRsp = 1441,
312 | UpdateBuffGroupStartScNotify = 1442,
313 | UpdateBuffGroupEndScNotify = 1443,
314 | ActivateFarmElementCsReq = 1445,
315 | ActivateFarmElementScRsp = 1446,
316 | GetSpringRecoverDataCsReq = 1447,
317 | GetSpringRecoverDataScRsp = 1448,
318 | SetSpringRecoverConfigCsReq = 1449,
319 | SetSpringRecoverConfigScRsp = 1450,
320 | SpringRecoverCsReq = 1451,
321 | SpringRecoverScRsp = 1452,
322 | HealPoolInfoNotify = 1453,
323 | SpringRecoverSingleAvatarCsReq = 1454,
324 | SpringRecoverSingleAvatarScRsp = 1455,
325 | GetShopListCsReq = 1501,
326 | GetShopListScRsp = 1502,
327 | BuyGoodsCsReq = 1503,
328 | BuyGoodsScRsp = 1504,
329 | GetTutorialCsReq = 1601,
330 | GetTutorialScRsp = 1602,
331 | GetTutorialGuideCsReq = 1603,
332 | GetTutorialGuideScRsp = 1604,
333 | UnlockTutorialCsReq = 1605,
334 | UnlockTutorialScRsp = 1606,
335 | UnlockTutorialGuideCsReq = 1607,
336 | UnlockTutorialGuideScRsp = 1608,
337 | FinishTutorialCsReq = 1609,
338 | FinishTutorialScRsp = 1610,
339 | FinishTutorialGuideCsReq = 1611,
340 | FinishTutorialGuideScRsp = 1612,
341 | GetChallengeCsReq = 1701,
342 | GetChallengeScRsp = 1702,
343 | StartChallengeCsReq = 1703,
344 | StartChallengeScRsp = 1704,
345 | LeaveChallengeCsReq = 1705,
346 | LeaveChallengeScRsp = 1706,
347 | ChallengeSettleNotify = 1707,
348 | FinishChallengeCsReq = 1708,
349 | FinishChallengeScRsp = 1709,
350 | GetCurChallengeCsReq = 1710,
351 | GetCurChallengeScRsp = 1711,
352 | ChallengeLineupNotify = 1712,
353 | TakeChallengeTargetRewardCsReq = 1713,
354 | TakeChallengeTargetRewardScRsp = 1714,
355 | GetRogueInfoCsReq = 1801,
356 | GetRogueInfoScRsp = 1802,
357 | StartRogueCsReq = 1803,
358 | StartRogueScRsp = 1804,
359 | EnterRogueCsReq = 1805,
360 | EnterRogueScRsp = 1806,
361 | LeaveRogueCsReq = 1807,
362 | LeaveRogueScRsp = 1808,
363 | SyncRogueBuffSelectInfoScNotify = 1809,
364 | SelectRogueBuffCsReq = 1810,
365 | SelectRogueBuffScRsp = 1811,
366 | RollRogueBuffCsReq = 1812,
367 | RollRogueBuffScRsp = 1813,
368 | EnterNextRogueRoomScNotify = 1814,
369 | SyncRogueFinishScNotify = 1815,
370 | PickRogueAvatarCsReq = 1816,
371 | PickRogueAvatarScRsp = 1817,
372 | AddRogueBuffScNotify = 1818,
373 | ReviveRogueAvatarCsReq = 1819,
374 | ReviveRogueAvatarScRsp = 1820,
375 | SaveRogueRecordCsReq = 1821,
376 | SaveRogueRecordScRsp = 1822,
377 | RecoverRogueStaminaCsReq = 1823,
378 | RecoverRogueStaminaScRsp = 1824,
379 | StartRogueChallengeCsReq = 1827,
380 | StartRogueChallengeScRsp = 1828,
381 | LeaveRogueChallengeCsReq = 1829,
382 | LeaveRogueChallengeScRsp = 1830,
383 | SyncRogueChallengeFinishScNotify = 1831,
384 | QuitRogueCsReq = 1832,
385 | QuitRogueScRsp = 1833,
386 | AppraisalRogueStoneCsReq = 1834,
387 | AppraisalRogueStoneScRsp = 1835,
388 | SyncRogueSeasonFinishScNotify = 1836,
389 | SyncRogueInfoChangeScNotify = 1837,
390 | AddRogueExtraBuffScNotify = 1838,
391 | EnterRogueMapRoomCsReq = 1839,
392 | EnterRogueMapRoomScRsp = 1840,
393 | EnterRogueNextLevelCsReq = 1841,
394 | EnterRogueNextLevelScRsp = 1842,
395 | SyncRogueMapRoomScNotify = 1843,
396 | SyncRoguePickAvatarScNotify = 1844,
397 | SetRogueBlessCsReq = 1845,
398 | SetRogueBlessScRsp = 1846,
399 | SyncRogueBlessScNotify = 1847,
400 | GetRogueShopInfoCsReq = 1848,
401 | GetRogueShopInfoScRsp = 1849,
402 | BuyRogueShopBuffCsReq = 1850,
403 | BuyRogueShopBuffScRsp = 1851,
404 | FinishRogueDialogueGroupCsReq = 1852,
405 | FinishRogueDialogueGroupScRsp = 1853,
406 | UnlockRogueRoomCsReq = 1856,
407 | UnlockRogueRoomScRsp = 1857,
408 | GetRogueGachaInfoCsReq = 1858,
409 | GetRogueGachaInfoScRsp = 1859,
410 | SetRogueGachaWishListCsReq = 1860,
411 | SetRogueGachaWishListScRsp = 1861,
412 | DoRogueGachaCsReq = 1862,
413 | DoRogueGachaScRsp = 1863,
414 | SyncRogueGachaRefreshScNotify = 1864,
415 | BuyRogueShopItemCsReq = 1865,
416 | BuyRogueShopItemScRsp = 1866,
417 | GetRogueAppraisalItemInfoCsReq = 1867,
418 | GetRogueAppraisalItemInfoScRsp = 1868,
419 | SyncRogueMiracleGetItemScNotify = 1869,
420 | SyncRogueQuestScNotify = 1870,
421 | GetRogueQuestRewardCsReq = 1871,
422 | GetRogueQuestRewardScRsp = 1872,
423 | GetGachaInfoCsReq = 1901,
424 | GetGachaInfoScRsp = 1902,
425 | DoGachaCsReq = 1903,
426 | DoGachaScRsp = 1904,
427 | GetPrestigeInfoCsReq = 2001,
428 | GetPrestigeInfoScRsp = 2002,
429 | PrestigeInfoChangeNotify = 2003,
430 | TakePrestigeLevelRewardCsReq = 2004,
431 | TakePrestigeLevelRewardScRsp = 2005,
432 | GetNpcTakenRewardCsReq = 2101,
433 | GetNpcTakenRewardScRsp = 2102,
434 | TakeTalkRewardCsReq = 2103,
435 | TakeTalkRewardScRsp = 2104,
436 | GetFirstTalkNpcCsReq = 2105,
437 | GetFirstTalkNpcScRsp = 2106,
438 | FinishFirstTalkNpcCsReq = 2107,
439 | FinishFirstTalkNpcScRsp = 2108,
440 | StartRaidCsReq = 2201,
441 | StartRaidScRsp = 2202,
442 | LeaveRaidCsReq = 2203,
443 | LeaveRaidScRsp = 2204,
444 | RaidInfoNotify = 2205,
445 | GetChallengeRaidInfoCsReq = 2206,
446 | GetChallengeRaidInfoScRsp = 2207,
447 | TakeChallengeRaidRewardCsReq = 2208,
448 | TakeChallengeRaidRewardScRsp = 2209,
449 | ChallengeRaidNotify = 2210,
450 | GetArchiveDataCsReq = 2301,
451 | GetArchiveDataScRsp = 2302,
452 | GetUpdatedArchiveDataCsReq = 2303,
453 | GetUpdatedArchiveDataScRsp = 2304,
454 | GetDialogueEventDataCsReq = 2401,
455 | GetDialogueEventDataScRsp = 2402,
456 | SelectDialogueEventCsReq = 2403,
457 | SelectDialogueEventScRsp = 2404,
458 | SyncDialogueEventDataScNotify = 2405,
459 | GetExpeditionDataCsReq = 2501,
460 | GetExpeditionDataScRsp = 2502,
461 | AcceptExpeditionCsReq = 2503,
462 | AcceptExpeditionScRsp = 2504,
463 | CancelExpeditionCsReq = 2505,
464 | CancelExpeditionScRsp = 2506,
465 | TakeExpeditionRewardCsReq = 2507,
466 | TakeExpeditionRewardScRsp = 2508,
467 | GetLoginActivityCsReq = 2601,
468 | GetLoginActivityScRsp = 2602,
469 | TakeLoginActivityRewardCsReq = 2603,
470 | TakeLoginActivityRewardScRsp = 2604,
471 | GetNpcMessageGroupCsReq = 2701,
472 | GetNpcMessageGroupScRsp = 2702,
473 | GetNpcStatusCsReq = 2703,
474 | GetNpcStatusScRsp = 2704,
475 | FinishItemIdCsReq = 2705,
476 | FinishItemIdScRsp = 2706,
477 | FinishSectionIdCsReq = 2707,
478 | FinishSectionIdScRsp = 2708,
479 | }
480 |
--------------------------------------------------------------------------------
/src/server/kcp/SRServer.ts:
--------------------------------------------------------------------------------
1 | import _KCP from 'node-kcp-token';
2 | import Logger from "../../util/Logger";
3 | import { Socket, createSocket, RemoteInfo } from "dgram";
4 | import Session from "./Session";
5 | import Config from "../../util/Config";
6 | import Handshake, { HandshakeType } from "./Handshake";
7 | const KCP = _KCP.KCP;
8 | const c = new Logger("KCP", "yellow");
9 |
10 | export default class SRServer {
11 | private static instance: SRServer;
12 | public readonly udpSocket: Socket;
13 | public readonly sessions: Map = new Map();
14 |
15 | private constructor() {
16 | this.udpSocket = createSocket("udp4");
17 | }
18 |
19 | public static getInstance(): SRServer {
20 | if (!SRServer.instance) {
21 | SRServer.instance = new SRServer();
22 | }
23 | return SRServer.instance;
24 | }
25 |
26 | public start() {
27 | this.udpSocket.bind(Config.GAMESERVER.SERVER_PORT, "0.0.0.0");
28 |
29 | this.udpSocket.on('listening', () => this.onListening());
30 | this.udpSocket.on('message', (d, i) => this.onMessage(d, i));
31 | this.udpSocket.on('error', (e) => this.onError(e));
32 | }
33 |
34 | private async onMessage(data: Buffer, rinfo: RemoteInfo) {
35 | const client = `${rinfo.address}:${rinfo.port}`;
36 | if (data.byteLength == 20) {
37 | // Hamdshanke
38 | const handshake = new Handshake(data);
39 |
40 | switch (handshake.handshakeType) {
41 | case HandshakeType.CONNECT:
42 | c.log(`${client} connected`);
43 | const rsp = new Handshake(HandshakeType.SEND_BACK_CONV).encode();
44 | this.udpSocket.send(rsp, 0, rsp.byteLength, rinfo.port, rinfo.address);
45 | const kcpobj = new KCP(0x69, 0x420, {
46 | address: rinfo.address,
47 | port: rinfo.port,
48 | family: rinfo.family
49 | });
50 | kcpobj.nodelay(1, 5, 2, 0);
51 | kcpobj.output((d, s, u) => this.output(d, s, u));
52 | kcpobj.wndsize(256, 256);
53 | this.sessions.set(client, new Session(kcpobj, rinfo));
54 | break;
55 | case HandshakeType.DISCONNECT:
56 | c.log(`${client} disconnected`);
57 | this.sessions.delete(client);
58 | break;
59 | default:
60 | c.error(`${client} unknown Handshake: ${data.readUint32BE(0)}`);
61 | }
62 | return;
63 | }
64 |
65 | const session = this.sessions.get(client);
66 | if (!session) return;
67 | session.inputRaw(data);
68 | }
69 |
70 | private output(buf: Buffer, size: number, ctx: { address: string, port: number, family: string }) {
71 | if (!buf) return;
72 | this.udpSocket.send(buf, 0, size, ctx.port, ctx.address);
73 | }
74 |
75 | private async onError(err: Error) {
76 | c.error(err);
77 | }
78 |
79 | private async onListening() {
80 | c.log(`Listening on 0.0.0.0:${Config.GAMESERVER.SERVER_PORT}`);
81 | }
82 | }
--------------------------------------------------------------------------------
/src/server/kcp/Session.ts:
--------------------------------------------------------------------------------
1 | import _KCP from 'node-kcp-token';
2 | import { RemoteInfo } from 'dgram';
3 | import { resolve } from 'path';
4 | import fs from 'fs';
5 | import KCP from 'node-kcp-token';
6 | import Packet, { PacketName } from './Packet';
7 | import Logger, { VerboseLevel } from '../../util/Logger';
8 | import defaultHandler from '../packets/PacketHandler';
9 | import Account from '../../db/Account';
10 | import Player from '../../db/Player';
11 |
12 | function r(...args: string[]) {
13 | return fs.readFileSync(resolve(__dirname, ...args));
14 | }
15 |
16 | export default class Session {
17 | public key: Buffer = r('./initial.key');
18 | public c: Logger;
19 | public account!: Account;
20 | public player!: Player;
21 | public constructor(private readonly kcpobj: KCP.KCP, public readonly ctx: RemoteInfo) {
22 | this.kcpobj = kcpobj;
23 | this.ctx = ctx;
24 | this.c = new Logger(`${this.ctx.address}:${this.ctx.port}`, 'yellow');
25 | this.update();
26 | }
27 |
28 | public inputRaw(data: Buffer) {
29 | this.kcpobj.input(data);
30 | }
31 |
32 | public async update() {
33 | if (!this.kcpobj) {
34 | console.error("wtf kcpobj is undefined");
35 | console.debug(this)
36 | return;
37 | }
38 | const hr = process.hrtime();
39 |
40 | const timestamp = hr[0] * 1000000 + hr[1] / 1000;
41 | this.kcpobj.update(timestamp);
42 |
43 | let recv;
44 | do {
45 | recv = this.kcpobj.recv();
46 | if (!recv) break;
47 |
48 | this.c.debug(`recv ${recv.toString("hex")}`);
49 |
50 | if (Packet.isValid(recv)) {
51 | this.handlePacket(new Packet(recv));
52 | }
53 |
54 | } while (recv)
55 |
56 | setTimeout(() => this.update(), 1);
57 | }
58 |
59 | public async handlePacket(packet: Packet) {
60 | if (Logger.VERBOSE_LEVEL >= VerboseLevel.WARNS) this.c.log(packet.protoName)
61 |
62 | import(`../packets/${packet.protoName}`).then(mod => {
63 | mod.default(this, packet);
64 | }).catch(e => {
65 | if (e.code === 'MODULE_NOT_FOUND') this.c.warn(`Unhandled packet: ${packet.protoName}`);
66 | else this.c.error(e);
67 |
68 | defaultHandler(this, packet);
69 | });
70 | }
71 |
72 | public send(name: PacketName, body: {}) {
73 | const packet = Packet.encode(name, body);
74 | if (!packet) return;
75 | if (Logger.VERBOSE_LEVEL >= VerboseLevel.WARNS) this.c.log(packet.protoName);
76 | this.c.debug(`send ${packet.rawData.toString('hex')}`);
77 | this.kcpobj.send(packet.rawData);
78 | }
79 |
80 | public sendRaw(data: Buffer) {
81 | this.kcpobj.send(data);
82 | }
83 | }
--------------------------------------------------------------------------------
/src/server/kcp/initial.key:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DreamLumine/CrepeSR/b99b1a0b881ff2ee374f9715c6ea8fac9ff55ef1/src/server/kcp/initial.key
--------------------------------------------------------------------------------
/src/server/packets/ChangeLineupLeaderCsReq.ts:
--------------------------------------------------------------------------------
1 | import { ChangeLineupLeaderCsReq, ChangeLineupLeaderScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | const body = packet.body as ChangeLineupLeaderCsReq;
7 |
8 | session.send("ChangeLineupLeaderScRsp", {
9 | retcode: 0,
10 | slot: body.slot
11 | } as ChangeLineupLeaderScRsp);
12 | }
--------------------------------------------------------------------------------
/src/server/packets/FinishTalkMissionCsReq.ts:
--------------------------------------------------------------------------------
1 | import { FinishTalkMissionCsReq, FinishTalkMissionScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | const body = packet.body as FinishTalkMissionCsReq;
7 |
8 | session.send("FinishTalkMissionScRsp", {
9 | retcode: 0,
10 | talkStr: body.talkStr
11 | } as FinishTalkMissionScRsp);
12 | }
--------------------------------------------------------------------------------
/src/server/packets/GetAllLineupDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetAllLineupDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetAllLineupDataScRsp", {
7 | retcode: 0,
8 | lineupList: []
9 | } as unknown as GetAllLineupDataScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetAvatarDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetAvatarDataCsReq, GetAvatarDataScRsp } from "../../data/proto/StarRail";
2 | import AvatarExcelTable from "../../data/excel/AvatarExcelTable.json";
3 | import Packet from "../kcp/Packet";
4 | import Session from "../kcp/Session";
5 |
6 | export default async function handle(session: Session, packet: Packet) {
7 | const body = packet.body as GetAvatarDataCsReq;
8 |
9 | const dataObj = {
10 | retcode: 0,
11 | avatarList: [{
12 | baseAvatarId: 1001,
13 | equipmentUniqueId: 13501,
14 | equipRelicList: [],
15 | exp: 0,
16 | level: 1,
17 | promotion: 1,
18 | rank: 1,
19 | skilltreeList: [],
20 | }],
21 | isAll: body.isGetAll
22 | } as GetAvatarDataScRsp;
23 |
24 | Object.values(AvatarExcelTable).forEach(avatar => {
25 | // dataObj.avatarList.push()
26 | });
27 |
28 | session.send("GetAvatarDataScRsp", dataObj);
29 | }
--------------------------------------------------------------------------------
/src/server/packets/GetBagCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetBagScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetBagScRsp", {
7 | equipmentList: [],
8 | materialList: [],
9 | relicList: [],
10 | retcode: 0,
11 | rogueItemList: [],
12 | waitDelResourceList: []
13 | } as GetBagScRsp);
14 | }
--------------------------------------------------------------------------------
/src/server/packets/GetBasicInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetBasicInfoScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetBasicInfoScRsp", {
7 | curDay: 1,
8 | exchangeTimes: 0,
9 | retcode: 0,
10 | nextRecoverTime: Math.round(new Date().getTime() / 1000) + 100000,
11 | weekCocoonFinishedCount: 0
12 | } as GetBasicInfoScRsp)
13 | }
--------------------------------------------------------------------------------
/src/server/packets/GetChallengeCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetChallengeScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetChallengeScRsp", {
7 | retcode: 0,
8 | challengeList: []
9 | } as GetChallengeScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetChallengeRaidInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetChallengeRaidInfoScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetChallengeRaidInfoScRsp", {
7 | retcode: 0,
8 | challengeRaidList: [],
9 | takenRewardIdList: []
10 | } as GetChallengeRaidInfoScRsp);
11 | }
--------------------------------------------------------------------------------
/src/server/packets/GetCurBattleInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { AvatarType, BattleEndStatus, GetCurBattleInfoScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetCurBattleInfoScRsp", {
7 | retcode: 0,
8 | avatarList: [{
9 | avatarType: AvatarType.AVATAR_FORMAL_TYPE,
10 | id: 1001,
11 | level: 1,
12 | rank: 1,
13 | index: 1,
14 | hp: 100,
15 | sp: 100,
16 | promotion: 1,
17 | }],
18 | stageId: 10000,
19 | logicRandomSeed: 2503,
20 | battleInfo: {},
21 | lastEndStatus: BattleEndStatus.BATTLE_END_WIN,
22 | lastEventId: 0
23 | } as GetCurBattleInfoScRsp);
24 | }
--------------------------------------------------------------------------------
/src/server/packets/GetCurLineupDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { AvatarType, GetCurLineupDataCsReq, GetCurLineupDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetCurLineupDataScRsp", {
7 | retcode: 0,
8 | lineup: {
9 | avatarList: [{
10 | slot: 1,
11 | avatarType: AvatarType.AVATAR_FORMAL_TYPE,
12 | id: 1001,
13 | hp: 100,
14 | sp: 100,
15 | satiety: 100
16 | }],
17 | index: 1,
18 | isVirtual: false,
19 | mp: 100,
20 | name: "lineuprspname",
21 | planeId: 10000,
22 | leaderSlot: 1
23 | }
24 | } as GetCurLineupDataScRsp);
25 | }
--------------------------------------------------------------------------------
/src/server/packets/GetCurSceneInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetCurSceneInfoScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetCurSceneInfoScRsp", {
7 | retcode: 0,
8 | scene: {
9 | planeId: 10000,
10 | floorId: 10000000,
11 | entityList: [],
12 | entityBuffList: [],
13 | entryId: 10001,
14 | envBuffList: [],
15 | gameModeType: 1,
16 | lightenSectionList: []
17 | },
18 | } as unknown as GetCurSceneInfoScRsp);
19 | }
--------------------------------------------------------------------------------
/src/server/packets/GetDialogueEventDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetDialogueEventDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetDialogueEventDataScRsp", {
7 | dialogueEventList: [],
8 | retcode: 0
9 | } as GetDialogueEventDataScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetExpeditionDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetExpeditionDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetExpeditionDataScRsp", {
7 | retcode: 0,
8 | expedtionList: [],
9 | unlockedExpeditionIdList: [],
10 | teamCount: 4
11 | } as GetExpeditionDataScRsp);
12 | }
--------------------------------------------------------------------------------
/src/server/packets/GetFirstTalkNpcCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetFirstTalkNpcScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetFirstTalkNpcScRsp", {
7 | retcode: 0,
8 | } as GetFirstTalkNpcScRsp);
9 | }
--------------------------------------------------------------------------------
/src/server/packets/GetHeroBasicTypeInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { Gender, GetHeroBasicTypeInfoScRsp, HeroBasicType } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetHeroBasicTypeInfoScRsp", {
7 | retcode: 0,
8 | gender: Gender.GenderMan,
9 | basicTypeInfoList: [{
10 | basicType: HeroBasicType.BoyMage,
11 | rank: 1,
12 | skillTreeList: []
13 | }],
14 | curBasicType: HeroBasicType.BoyMage,
15 | heroPathList: [],
16 | isPlayerInfoModified: false,
17 | isGenderModified: false
18 | } as GetHeroBasicTypeInfoScRsp);
19 | }
--------------------------------------------------------------------------------
/src/server/packets/GetHeroPathCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetHeroPathScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetHeroPathScRsp", {
7 | retcode: 0,
8 | heroPathList: []
9 | } as GetHeroPathScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetLevelRewardTakenListCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetLevelRewardTakenListScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetLevelRewardTakenListScRsp", {
7 | retcode: 0,
8 | takenLevelList: []
9 | } as GetLevelRewardTakenListScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetLoginActivityCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetLoginActivityScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetLoginActivityScRsp", {
7 | retcode: 0,
8 | loginActivityList: []
9 | } as GetLoginActivityScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetMailCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetMailScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetMailScRsp", {
7 | retcode: 0,
8 | mailList: [],
9 | noticeMailList: [],
10 | start: 0,
11 | totalNum: 0,
12 | isEnd: false
13 | } as GetMailScRsp);
14 | }
--------------------------------------------------------------------------------
/src/server/packets/GetMazeTimeOfDayCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetMazeTimeOfDayScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetMazeTimeOfDayScRsp", {
7 | retcode: 0,
8 | mazeTimeOfDayMap: {}
9 | } as GetMazeTimeOfDayScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetMissionDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetMissionDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetMissionDataScRsp", {
7 | retcode: 0,
8 | missionList: []
9 | } as unknown as GetMissionDataScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetMissionEventDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetMissionEventDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetMissionEventDataScRsp", {
7 | retcode: 0,
8 | missionEventList: []
9 | } as unknown as GetMissionEventDataScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetMissionStatusCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetMissionStatusCsReq, GetMissionStatusScRsp, MissionStatus } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | const body = packet.body as GetMissionStatusCsReq;
7 |
8 | const dataObj = {
9 | retcode: 0,
10 | finishedMainMissionIdList: [],
11 | missionEventStatusList: [],
12 | subMissionStatusList: [],
13 | unfinishedMainMissionIdList: []
14 | } as GetMissionStatusScRsp;
15 |
16 | body.mainMissionIdList.forEach(id => { dataObj.unfinishedMainMissionIdList.push(id); });
17 |
18 | body.missionEventIdList.forEach(id => {
19 | dataObj.missionEventStatusList.push({
20 | id: id,
21 | progress: 0,
22 | status: MissionStatus.MISSION_DOING
23 | });
24 | });
25 |
26 | body.subMissionIdList.forEach(id => {
27 | dataObj.subMissionStatusList.push({
28 | id: id,
29 | progress: 0,
30 | status: MissionStatus.MISSION_DOING
31 | });
32 | });
33 |
34 | session.send("GetMissionStatusScRsp", dataObj);
35 | }
--------------------------------------------------------------------------------
/src/server/packets/GetNpcStatusCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetNpcStatusScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetNpcStatusScRsp", {
7 | retcode: 0,
8 | messageStatusList: []
9 | } as GetNpcStatusScRsp);
10 | }
--------------------------------------------------------------------------------
/src/server/packets/GetQuestDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetQuestDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetQuestDataScRsp", {
7 | questList: [],
8 | retcode: 0,
9 | takenAchievementLevelList: [],
10 | totalAchievementExp: 1,
11 | } as GetQuestDataScRsp);
12 | }
--------------------------------------------------------------------------------
/src/server/packets/GetRogueInfoCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetRogueInfoScRsp, RogueStatus } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetRogueInfoScRsp", {
7 | retcode: 0,
8 | rogueInfo: {
9 | status: RogueStatus.ROGUE_STATUS_DOING,
10 | rogueCoin: 1,
11 | baseAvatarIdList: [1001],
12 | rogueStamina: 100,
13 | reviveCount: 1,
14 | recoverStaminaCount: 1,
15 | isRecordSaved: true,
16 | beginTime: Math.round(Date.now() / 1000),
17 | endTime: Math.round(Date.now() / 1000) + 3600,
18 | isWin: true,
19 | }
20 | } as GetRogueInfoScRsp);
21 | }
--------------------------------------------------------------------------------
/src/server/packets/GetSpringRecoverDataCsReq.ts:
--------------------------------------------------------------------------------
1 | import { GetSpringRecoverDataScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | session.send("GetSpringRecoverDataScRsp", {
7 | retcode: 0,
8 | healPoolInfo: {
9 | healPool: 0,
10 | refreshTime: 600,
11 | },
12 | springRecoverConfig: {
13 | autoRecoverHp: true,
14 | defaultHp: 100,
15 | avatarPresetHpList: []
16 | }
17 | } as GetSpringRecoverDataScRsp);
18 | }
--------------------------------------------------------------------------------
/src/server/packets/PacketHandler.ts:
--------------------------------------------------------------------------------
1 | import Packet from "../kcp/Packet";
2 | import Session from "../kcp/Session";
3 |
4 | export default async function handle(session: Session, packet: Packet) {
5 | session.c.debug(packet.body);
6 | }
--------------------------------------------------------------------------------
/src/server/packets/PlayerGetTokenCsReq.ts:
--------------------------------------------------------------------------------
1 | import Logger from "../../util/Logger";
2 | import Account from "../../db/Account";
3 | import Packet from "../kcp/Packet";
4 | import Session from "../kcp/Session";
5 | import Player from "../../db/Player";
6 | import { PlayerGetTokenScRsp } from "../../data/proto/StarRail";
7 | const c = new Logger("Dispatch");
8 |
9 | interface PlayerGetTokenCsReq {
10 | channel_id?: number;
11 | account_uid?: string;
12 | token?: string;
13 | uid?: number;
14 | device?: string;
15 | }
16 |
17 | const retWarn = (msg: string) => c.warn(msg);
18 |
19 | export default async function handle(session: Session, packet: Packet) {
20 | const body = packet.body as PlayerGetTokenCsReq;
21 |
22 | let dataObj = {
23 | retcode: 0,
24 | secretKeySeed: 0
25 | } as PlayerGetTokenScRsp;
26 |
27 | const account = await Account.fromToken(body.token || "");
28 | if (!account) retWarn(`Account not found with token ${body.token}`);
29 |
30 | const player = await Player.fromToken(account?.token || "");
31 | if (!player) retWarn(`Player not found with accountToken ${account?.token}`);
32 | if (!player || !account) {
33 | dataObj.retcode = 6;
34 | return;
35 | }
36 | session.account = account;
37 | session.player = player;
38 |
39 | const isTokenValid = player.db.token === body.token;
40 | const isBanned = player.db.banned;
41 | if (isBanned) dataObj.retcode = 1013;
42 | if (!isTokenValid) {
43 | retWarn(`Token invalid (${session.ctx.address}:${session.ctx.port})`);
44 | dataObj.retcode = 1005;
45 | return;
46 | }
47 |
48 | dataObj.uid = player.db._id;
49 | session.send("PlayerGetTokenScRsp", dataObj);
50 | }
--------------------------------------------------------------------------------
/src/server/packets/PlayerKeepAliveNotify.ts:
--------------------------------------------------------------------------------
1 | import Packet from "../kcp/Packet";
2 | import Session from "../kcp/Session";
3 |
4 | export default async function handle(session: Session, packet: Packet) {
5 | // We actually don't need to handle this
6 | }
--------------------------------------------------------------------------------
/src/server/packets/PlayerLoginCsReq.ts:
--------------------------------------------------------------------------------
1 | import { PlayerBasicInfo, PlayerLoginCsReq, PlayerLoginScRsp } from "../../data/proto/StarRail";
2 | import Player from "../../db/Player";
3 | import Packet from "../kcp/Packet";
4 | import Session from "../kcp/Session";
5 |
6 | // { Example body:
7 | // platform: 3,
8 | // deviceUuid: '406d064a8fa3bcb32f1d88df28e600e5a86bbf751658757874371',
9 | // deviceInfo: '{"operatingSystem":"Windows 10 (10.0.19043) 64bit","deviceModel":"B450M DS3H V2 (Gigabyte Technology Co., Ltd.)","graphicsDeviceName":"NVIDIA GeForce GTX 1650","graphicsDeviceType":"Direct3D11","graphicsDeviceVendor":"NVIDIA","graphicsDeviceVersion":"Direct3D 11.0 [level 11.1]","graphicsMemorySize":3962,"processorCount":12,"processorFrequency":3394,"processorType":"AMD Ryzen 5 2600 Six-Core Processor ","systemMemorySize":16335,"DeviceSoC":""}',
10 | // systemInfo: 'Windows 10 (10.0.19043) 64bit',
11 | // clientVersion: 'OSCBWin0.70.0',
12 | // language: 3,
13 | // checkSum_1: 'ff07bc743a394e0ff1c163edc663137d',
14 | // checkSum_2: 'ca590da88620492b921c9b3b4977f1be10',
15 | // resolution: '1920*1080',
16 | // systemLanguage: 'Dutch',
17 | // resVersion: 611127,
18 | // clientTimeZone: '01:00:00'
19 | // }
20 |
21 | export default async function handle(session: Session, packet: Packet) {
22 | const body = packet.body as PlayerLoginCsReq;
23 |
24 | const plr = await Player.fromUID(session.player.db._id)!;
25 | if (!plr!.db.basicInfo) {
26 | plr!.db.basicInfo = {
27 | exp: 0,
28 | level: 1,
29 | hcoin: 0,
30 | mcoin: 0,
31 | nickname: plr!.db.name,
32 | scoin: 0,
33 | stamina: 100,
34 | worldLevel: 1,
35 | }
36 | plr!.save();
37 | }
38 |
39 | session.send("PlayerLoginScRsp", {
40 | basicInfo: plr!.db.basicInfo as PlayerBasicInfo,
41 | isNewPlayer: false,
42 | stamina: 100,
43 | retcode: 0,
44 | isRelay: false,
45 | loginRandom: Number(body.loginRandom),
46 | serverTimestampMs: Math.round(new Date().getTime() / 1000),
47 | } as PlayerLoginScRsp);
48 | }
--------------------------------------------------------------------------------
/src/server/packets/PlayerLogoutCsReq.ts:
--------------------------------------------------------------------------------
1 | import Packet from "../kcp/Packet";
2 | import Session from "../kcp/Session";
3 | import SRServer from "../kcp/SRServer";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | // Remove from session list
7 | SRServer.getInstance().sessions.delete(`${session.ctx.address}:${session.ctx.port}`);
8 | }
--------------------------------------------------------------------------------
/src/server/packets/SceneEntityMoveCsReq.ts:
--------------------------------------------------------------------------------
1 | import { SceneEntityMoveCsReq, SceneEntityMoveScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | const body = packet.body as SceneEntityMoveCsReq;
7 |
8 | session.send("SceneEntityMoveScRsp", {
9 | retcode: 0,
10 | downloadData: undefined,
11 | } as SceneEntityMoveScRsp);
12 | }
--------------------------------------------------------------------------------
/src/server/packets/SyncTimeCsReq.ts:
--------------------------------------------------------------------------------
1 | import { SyncTimeCsReq, SyncTimeScRsp } from "../../data/proto/StarRail";
2 | import Packet from "../kcp/Packet";
3 | import Session from "../kcp/Session";
4 |
5 | export default async function handle(session: Session, packet: Packet) {
6 | const body = packet.body as SyncTimeCsReq;
7 |
8 | session.send("SyncTimeScRsp", {
9 | retcode: 0,
10 | clientTimeMs: body.clientTimeMs,
11 | serverTimeMs: Math.round(new Date().getTime() / 1000)
12 | } as SyncTimeScRsp);
13 | }
--------------------------------------------------------------------------------
/src/util/Config.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { resolve } from 'path';
3 | import { VerboseLevel } from './Logger';
4 |
5 | const DEFAULT_CONFIG = {
6 | // General
7 | VERBOSE_LEVEL: 1,
8 |
9 | // MongoDB
10 | MONGO_URI: "mongodb://localhost:27017/crepesr",
11 |
12 | // HTTP
13 | HTTP: {
14 | HTTP_HOST: "0.0.0.0",
15 | HTTP_PORT: 443
16 | },
17 |
18 | // Dispatch
19 | DISPATCH: [{
20 | DISPATCH_NAME: "CrepeSR",
21 | DISPATCH_URL: "http://localhost/query_gateway"
22 | }],
23 |
24 | // GameServer
25 | GAMESERVER: {
26 | SERVER_IP: "127.0.0.1",
27 | SERVER_PORT: 22102,
28 | MAINTENANCE: false,
29 | MAINTENANCE_MSG: "Server is in maintenance mode."
30 | }
31 | }
32 | type DefaultConfig = typeof DEFAULT_CONFIG;
33 |
34 | function r(...args: string[]) {
35 | return fs.readFileSync(resolve(__dirname, ...args)).toString();
36 | }
37 |
38 | function readConfig(): any {
39 | let config: DefaultConfig;
40 | try {
41 | config = JSON.parse(r('../../config.json'));
42 | // Check if config object.keys is the same as DEFAULT_CONFIG.keys
43 | const missing = Object.keys(DEFAULT_CONFIG).filter(key => !config.hasOwnProperty(key));
44 |
45 | if (missing.length > 0) {
46 | missing.forEach(key => {
47 | // @ts-ignore
48 | config[key] = DEFAULT_CONFIG[key];
49 | });
50 | updateConfig(config);
51 | console.log(`Added missing config keys: ${missing.join(', ')}`);
52 | }
53 | } catch {
54 | console.error("Could not read config file. Creating one for you...");
55 | config = DEFAULT_CONFIG;
56 | updateConfig(config);
57 | }
58 | return config;
59 | }
60 |
61 | function updateConfig(config: any) {
62 | fs.writeFileSync('./config.json', JSON.stringify(config, null, 2));
63 | }
64 |
65 | export default class Config {
66 | public static config = readConfig();
67 | public static VERBOSE_LEVEL: VerboseLevel = Config.config.VERBOSE_LEVEL;
68 | public static MONGO_URI: string = Config.config.MONGO_URI;
69 | public static HTTP: {
70 | HTTP_HOST: string,
71 | HTTP_PORT: number
72 | } = Config.config.HTTP;
73 | public static DISPATCH: {
74 | DISPATCH_NAME: string;
75 | DISPATCH_URL: string;
76 | }[] = Config.config.DISPATCH;
77 | public static GAMESERVER: {
78 | SERVER_IP: string;
79 | SERVER_PORT: number;
80 | MAINTENANCE: boolean;
81 | MAINTENANCE_MSG: string;
82 | } = Config.config.GAMESERVER;
83 |
84 | private constructor() { }
85 | }
--------------------------------------------------------------------------------
/src/util/Logger.ts:
--------------------------------------------------------------------------------
1 | import 'colorts/lib/string';
2 | import Config from './Config';
3 |
4 | export enum VerboseLevel {
5 | NONE = 0, // No logging except for errors
6 | WARNS = 1, // Log warns
7 | ALL = 2, // Warns and (useless) debug
8 | }
9 |
10 | type Color = 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | 'black' | 'italic' | 'bold' | 'underline' | 'strikethrough' | 'inverse' | 'bgRed' | 'bgGreen' | 'bgYellow' | 'bgBlue' | 'bgMagenta' | 'bgCyan' | 'bgWhite' | 'bgBlack' | 'bgGray' | 'bgItalic';
11 |
12 | export default class Logger {
13 | public static VERBOSE_LEVEL: VerboseLevel = Config.VERBOSE_LEVEL || 1;
14 |
15 | constructor(public name: string, public color: Color = 'blue') {
16 | this.name = name;
17 | this.color = color;
18 | }
19 |
20 | private getDate(): string {
21 | return new Date().toLocaleTimeString();
22 | }
23 |
24 | private raw(...args: string[]) {
25 | // @ts-ignore - Element implicitly has an 'any' type because index expression is not of type 'number'
26 | console.log(`[${this.getDate().white.bold}] <${this.name[this.color].bold}>`, ...args);
27 | }
28 |
29 | public log(...args: string[]) {
30 | this.raw(...args);
31 | }
32 |
33 | public trail(...args: any[]) {
34 | console.log(`\t↳ ${args.join(' ').gray}`);
35 | }
36 |
37 | public error(e: Error | string, stack: boolean = true) {
38 | if (typeof e === 'string') e = new Error(e);
39 | console.log(`[${this.getDate().white.bold}] ${`ERROR<${this.name}>`.bgRed.bold}`, e.message);
40 | if (e.stack && stack) this.trail(e.stack);
41 | }
42 |
43 | public warn(...args: string[]) {
44 | if (Logger.VERBOSE_LEVEL < VerboseLevel.WARNS) return;
45 | console.log(`[${this.getDate().white.bold}] ${`WARN<${this.name}>`.bgYellow.bold}`, ...args);
46 | }
47 |
48 | public debug(...args: any) {
49 | if (Logger.VERBOSE_LEVEL < VerboseLevel.ALL) return;
50 | console.log(`[${this.getDate().white.bold}] ${`DEBUG<${this.name}>`.bgBlue.bold}`, ...args);
51 | this.trail(new Error().stack!.split('\n').slice(2).join('\n'));
52 | }
53 | }
--------------------------------------------------------------------------------
/src/util/ProtoFactory.ts:
--------------------------------------------------------------------------------
1 | //ts-proto generated types required, import them here
2 | import * as types from "../data/proto/StarRail";
3 | import protobufjs from "protobufjs";
4 | import { CmdID, PacketName } from "../server/kcp/Packet"
5 | import Logger from "./Logger";
6 | const c = new Logger("ProtoFactory");
7 |
8 | class MessageType {
9 | "encode": (arg0: T) => protobufjs.Writer;
10 | "fromPartial": (arg0: object) => T;
11 | // "decode": (input: protobufjs.Reader | Uint8Array, length?: number)=> T;
12 | // "fromJSON": (object: any)=>T;
13 | // "toJSON": (message: T)=> unknown
14 | //you can add more fields here from the generated types
15 | //fromjson etc...
16 | };
17 |
18 | var messageTypeMap = new Map>();
19 | var messageTypeMapReversed = new Map, PacketName>();
20 |
21 | function send, T>(type: Class, data: T) {
22 | console.log(type.encode(data).finish())
23 | }
24 |
25 |
26 | function isMessageType(pet: MessageType | any): pet is MessageType {
27 | return (>pet).encode !== undefined;
28 | }
29 |
30 |
31 | export default class ProtoFactory {
32 |
33 | // ONLY USE THIS IF YOU'RE DECODING SOMETHING DONT USE IT TO SEND SHIT
34 | // BECAUSE THEN YOU FUCK YOUR TYPECHECKING
35 |
36 | static getType(name: PacketName) {
37 | return messageTypeMap.get(name) as MessageType;
38 | }
39 |
40 | static getName(type: MessageType) {
41 | return messageTypeMapReversed.get(type) as PacketName;
42 | }
43 |
44 | static init() {
45 | //iterate over everything in types and check if they are a MessageType
46 | for (const key of Object.keys(types)) {
47 | let value = types[key as keyof typeof types];
48 | if (isMessageType(value)) {
49 | if (Object.values(CmdID).includes(key)) {
50 | messageTypeMap.set(key as PacketName, value);
51 | messageTypeMapReversed.set(value, key as PacketName);
52 | } else {
53 | // there are some types that are not packets, but are still MessageType
54 | // you can figure out what you want to do with them here
55 | }
56 | }
57 | }
58 |
59 | c.debug(`Initialized with " ${messageTypeMap.size} types`);
60 |
61 | //c.log(this.getName(types.PlayerLoginScRsp))
62 | return;
63 |
64 | //if you want a partial type
65 | send(types.PlayerLoginScRsp, types.PlayerLoginScRsp.fromPartial({
66 | basicInfo: {
67 | exp: 0,
68 | level: 1,
69 | hcoin: 0,
70 | mcoin: 0,
71 | nickname: "test",
72 | scoin: 0,
73 | stamina: 100,
74 | worldLevel: 1,
75 | },
76 | isNewPlayer: true,
77 | stamina: 100,
78 | curTimezone: 1,
79 | serverTimestampMs: Math.round(new Date().getTime() / 1000),
80 | }))
81 | }
82 | }
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/util/stringSimilarity.ts:
--------------------------------------------------------------------------------
1 | export function compareTwoStrings(first: string, second: string) {
2 | first = first.replace(/\s+/g, '')
3 | second = second.replace(/\s+/g, '')
4 |
5 | if (first === second) return 1; // identical or empty
6 | if (first.length < 2 || second.length < 2) return 0; // if either is a 0-letter or 1-letter string
7 |
8 | const firstBigrams = new Map();
9 | for (let i = 0; i < first.length - 1; i++) {
10 | const bigram = first.substring(i, i + 2);
11 | const count = firstBigrams.has(bigram)
12 | ? firstBigrams.get(bigram) + 1
13 | : 1;
14 |
15 | firstBigrams.set(bigram, count);
16 | }
17 |
18 | let intersectionSize = 0;
19 | for (let i = 0; i < second.length - 1; i++) {
20 | const bigram = second.substring(i, i + 2);
21 | const count = firstBigrams.has(bigram)
22 | ? firstBigrams.get(bigram)
23 | : 0;
24 |
25 | if (count > 0) {
26 | firstBigrams.set(bigram, count - 1);
27 | intersectionSize++;
28 | }
29 | }
30 |
31 | return (2.0 * intersectionSize) / (first.length + second.length - 2);
32 | }
33 |
34 | export default function findBestMatch(mainString: string, targetStrings: string[]) {
35 | const ratings = [];
36 | let bestMatchIndex = 0;
37 |
38 | for (let i = 0; i < targetStrings.length; i++) {
39 | const currentTargetString = targetStrings[i];
40 | const currentRating = compareTwoStrings(mainString, currentTargetString)
41 | ratings.push({ target: currentTargetString, rating: currentRating })
42 | if (currentRating > ratings[bestMatchIndex].rating) {
43 | bestMatchIndex = i
44 | }
45 | }
46 |
47 |
48 | const bestMatch = ratings[bestMatchIndex]
49 |
50 | return { ratings: ratings, bestMatch: bestMatch, bestMatchIndex: bestMatchIndex };
51 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Enable incremental compilation */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 |
26 | /* Modules */
27 | "module": "commonjs", /* Specify what module code is generated. */
28 | // "rootDir": "./", /* Specify the root folder within your source files. */
29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36 | "resolveJsonModule": true, /* Enable importing .json files */
37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
38 |
39 | /* JavaScript Support */
40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
43 |
44 | /* Emit */
45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50 | // "outDir": "./", /* Specify an output folder for all emitted files. */
51 | // "removeComments": true, /* Disable emitting comments. */
52 | // "noEmit": true, /* Disable emitting files from a compilation. */
53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61 | // "newLine": "crlf", /* Set the newline character for emitting files. */
62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68 |
69 | /* Interop Constraints */
70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75 |
76 | /* Type Checking */
77 | "strict": true, /* Enable all strict type-checking options. */
78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
96 |
97 | /* Completeness */
98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
100 | }
101 | }
102 |
--------------------------------------------------------------------------------