├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── README.md ├── initpki ├── package-lock.json ├── package.json ├── pki ├── billing.key ├── billing.pub ├── ca.crt ├── ca.key ├── ca.pem ├── server.key └── server.pem ├── schema ├── init │ ├── aime.sql │ ├── cm.sql │ ├── idz.sql │ ├── meta.sql │ └── util.sql └── migrate │ ├── M0007-aime-simplify-player.sql │ ├── M0008-cm-initial-deploy.sql │ ├── M0009-idz-aura.sql │ ├── M0010-cm-user-duel-list.sql │ ├── M0011-cm-user-course.sql │ ├── M0012-cm-user-course-fix.sql │ ├── M0013-cm-user-duel-list-fix.sql │ ├── M0014-cm-user-charge.sql │ ├── M0015-cm-user-recent-rating.sql │ ├── M0016-idz-profile-version.sql │ ├── M0017-idz-v2-support.sql │ └── M0018-idz-auto-team-fix.sql ├── src ├── aimedb │ ├── decoder.test.ts │ ├── decoder.ts │ ├── encoder.ts │ ├── frame.ts │ ├── handler.ts │ ├── index.ts │ ├── pipeline.ts │ ├── repo.ts │ ├── request.ts │ ├── response.ts │ └── sql.ts ├── allnet.ts ├── billing.ts ├── checkdb.ts ├── chunithm │ ├── handler │ │ ├── _util.ts │ │ ├── gameLogin.ts │ │ ├── gameLogout.ts │ │ ├── getGameCharge.ts │ │ ├── getGameEvent.ts │ │ ├── getGameIdlist.ts │ │ ├── getGameMessage.ts │ │ ├── getGameRanking.ts │ │ ├── getGameSale.ts │ │ ├── getGameSetting.ts │ │ ├── getUserActivity.ts │ │ ├── getUserCharacter.ts │ │ ├── getUserCharge.ts │ │ ├── getUserCourse.ts │ │ ├── getUserData.ts │ │ ├── getUserDataEx.ts │ │ ├── getUserDuel.ts │ │ ├── getUserFavoriteMusic.ts │ │ ├── getUserItem.ts │ │ ├── getUserMap.ts │ │ ├── getUserMusic.ts │ │ ├── getUserOption.ts │ │ ├── getUserOptionEx.ts │ │ ├── getUserPreview.ts │ │ ├── getUserRecentRating.ts │ │ ├── getUserRegion.ts │ │ ├── index.ts │ │ ├── upsertClientBookkeeping.ts │ │ ├── upsertClientDevelop.ts │ │ ├── upsertClientError.ts │ │ ├── upsertClientSetting.ts │ │ ├── upsertClientTestmode.ts │ │ ├── upsertUserAll.ts │ │ └── upsertUserChargelogApi.ts │ ├── index.ts │ ├── model │ │ ├── gameCharge.ts │ │ ├── gameEvent.ts │ │ ├── gameMessage.ts │ │ ├── gameRanking.ts │ │ ├── gameSale.ts │ │ ├── userActivity.ts │ │ ├── userCharacter.ts │ │ ├── userCharge.ts │ │ ├── userCourse.ts │ │ ├── userData.ts │ │ ├── userDataEx.ts │ │ ├── userDuelList.ts │ │ ├── userGameOption.ts │ │ ├── userGameOptionEx.ts │ │ ├── userItem.ts │ │ ├── userMap.ts │ │ ├── userMusic.ts │ │ ├── userPlaylog.ts │ │ ├── userRecentRating.ts │ │ └── userRegion.ts │ ├── proto │ │ ├── base.ts │ │ ├── gameCharge.ts │ │ ├── gameEvent.ts │ │ ├── gameMessage.ts │ │ ├── gameRanking.ts │ │ ├── gameSale.ts │ │ ├── userActivity.ts │ │ ├── userCharacter.ts │ │ ├── userCharge.ts │ │ ├── userCourse.ts │ │ ├── userData.ts │ │ ├── userDataEx.ts │ │ ├── userDuelList.ts │ │ ├── userGameOption.ts │ │ ├── userGameOptionEx.ts │ │ ├── userItem.ts │ │ ├── userMap.ts │ │ ├── userMusic.ts │ │ ├── userPlaylog.ts │ │ ├── userRecentRating.ts │ │ └── userRegion.ts │ ├── repo │ │ ├── _defs.ts │ │ ├── index.ts │ │ ├── userActivity.ts │ │ ├── userCharacter.ts │ │ ├── userCharge.ts │ │ ├── userCourse.ts │ │ ├── userData.ts │ │ ├── userDataEx.ts │ │ ├── userDuelList.ts │ │ ├── userGameOption.ts │ │ ├── userGameOptionEx.ts │ │ ├── userItem.ts │ │ ├── userMap.ts │ │ ├── userMusic.ts │ │ ├── userPlaylog.ts │ │ └── userRecentRating.ts │ ├── request │ │ ├── gameLogin.ts │ │ ├── gameLogout.ts │ │ ├── getGameCharge.ts │ │ ├── getGameEvent.ts │ │ ├── getGameIdlist.ts │ │ ├── getGameMessage.ts │ │ ├── getGameRanking.ts │ │ ├── getGameSale.ts │ │ ├── getGameSetting.ts │ │ ├── getUserActivity.ts │ │ ├── getUserCharacter.ts │ │ ├── getUserCharge.ts │ │ ├── getUserCourse.ts │ │ ├── getUserData.ts │ │ ├── getUserDataEx.ts │ │ ├── getUserDuel.ts │ │ ├── getUserFavoriteMusic.ts │ │ ├── getUserItem.ts │ │ ├── getUserMap.ts │ │ ├── getUserMusic.ts │ │ ├── getUserOption.ts │ │ ├── getUserOptionEx.ts │ │ ├── getUserPreview.ts │ │ ├── getUserRecentRating.ts │ │ ├── getUserRegion.ts │ │ ├── upsertClientBookkeeping.ts │ │ ├── upsertClientDevelop.ts │ │ ├── upsertClientError.ts │ │ ├── upsertClientSetting.ts │ │ ├── upsertClientTestmode.ts │ │ ├── upsertUserAll.ts │ │ └── upsertUserChargelogApi.ts │ ├── response │ │ ├── gameLogin.ts │ │ ├── gameLogout.ts │ │ ├── getGameCharge.ts │ │ ├── getGameEvent.ts │ │ ├── getGameIdlist.ts │ │ ├── getGameMessage.ts │ │ ├── getGameRanking.ts │ │ ├── getGameSale.ts │ │ ├── getGameSetting.ts │ │ ├── getUserActivity.ts │ │ ├── getUserCharacter.ts │ │ ├── getUserCharge.ts │ │ ├── getUserCourse.ts │ │ ├── getUserData.ts │ │ ├── getUserDataEx.ts │ │ ├── getUserDuel.ts │ │ ├── getUserFavoriteMusic.ts │ │ ├── getUserItem.ts │ │ ├── getUserMap.ts │ │ ├── getUserMusic.ts │ │ ├── getUserOption.ts │ │ ├── getUserOptionEx.ts │ │ ├── getUserPreview.ts │ │ ├── getUserRecentRating.ts │ │ ├── getUserRegion.ts │ │ ├── upsertClientBookkeeping.ts │ │ ├── upsertClientDevelop.ts │ │ ├── upsertClientError.ts │ │ ├── upsertClientSetting.ts │ │ ├── upsertClientTestmode.ts │ │ ├── upsertUserAll.ts │ │ └── upsertUserChargelogApi.ts │ ├── rpc.ts │ ├── sql │ │ ├── _factory.ts │ │ ├── index.ts │ │ ├── userActivity.ts │ │ ├── userCharacter.ts │ │ ├── userCharge.ts │ │ ├── userCourse.ts │ │ ├── userData.ts │ │ ├── userDataEx.ts │ │ ├── userDuelList.ts │ │ ├── userGameOption.ts │ │ ├── userGameOptionEx.ts │ │ ├── userItem.ts │ │ ├── userMap.ts │ │ ├── userMusic.ts │ │ ├── userPlaylog.ts │ │ └── userRecentRating.ts │ └── static │ │ ├── charge.ts │ │ └── event.ts ├── diva │ ├── gameInit.ts │ └── index.ts ├── idz │ ├── common │ │ ├── aes.ts │ │ ├── bigint.ts │ │ ├── index.ts │ │ └── setup.ts │ ├── ping.ts │ ├── userdb │ │ ├── decoder │ │ │ ├── _bitmap.ts │ │ │ ├── _car.ts │ │ │ ├── _chara.ts │ │ │ ├── _mission.ts │ │ │ ├── checkTeamName.ts │ │ │ ├── createAutoTeam.ts │ │ │ ├── createProfile.ts │ │ │ ├── createTeam.ts │ │ │ ├── discoverProfile.ts │ │ │ ├── index.ts │ │ │ ├── load2on2.ts │ │ │ ├── loadConfig.ts │ │ │ ├── loadEventInfo.ts │ │ │ ├── loadGacha.ts │ │ │ ├── loadGarage.ts │ │ │ ├── loadGeneralReward.ts │ │ │ ├── loadGhost.ts │ │ │ ├── loadProfile.ts │ │ │ ├── loadRewardTable.ts │ │ │ ├── loadServerList.ts │ │ │ ├── loadStocker.ts │ │ │ ├── loadTeam.ts │ │ │ ├── loadTeamRanking.ts │ │ │ ├── loadTopTen1.ts │ │ │ ├── loadTopTen2.ts │ │ │ ├── lockGarage.ts │ │ │ ├── lockProfile.ts │ │ │ ├── lockProfileExtend.ts │ │ │ ├── saveExpedition.ts │ │ │ ├── saveGarage.ts │ │ │ ├── saveNewCar.ts │ │ │ ├── saveProfile2.ts │ │ │ ├── saveProfile3.ts │ │ │ ├── saveProfile4.ts │ │ │ ├── saveSettings.ts │ │ │ ├── saveStocker.ts │ │ │ ├── saveTeamBanner.ts │ │ │ ├── saveTimeAttack.ts │ │ │ ├── saveTopic.ts │ │ │ ├── unknownA.ts │ │ │ ├── unlockProfile.ts │ │ │ ├── updateExpedition.ts │ │ │ ├── updateProvisionalStoreRank.ts │ │ │ ├── updateResult.ts │ │ │ ├── updateStoryClearNum.ts │ │ │ ├── updateTeamLeader.ts │ │ │ ├── updateTeamMember.ts │ │ │ ├── updateTeamPoints.ts │ │ │ ├── updateUiReport.ts │ │ │ └── updateUserLog.ts │ │ ├── encoder │ │ │ ├── _bitmap.ts │ │ │ ├── _car.ts │ │ │ ├── _chara.ts │ │ │ ├── _mission.ts │ │ │ ├── _team.ts │ │ │ ├── checkTeamName.ts │ │ │ ├── createProfile.ts │ │ │ ├── createTeam.ts │ │ │ ├── discoverProfile.ts │ │ │ ├── generic.ts │ │ │ ├── index.ts │ │ │ ├── load2on2.ts │ │ │ ├── loadConfig.ts │ │ │ ├── loadEventInfo.ts │ │ │ ├── loadGacha.ts │ │ │ ├── loadGarage.ts │ │ │ ├── loadGeneralReward.ts │ │ │ ├── loadGhost.ts │ │ │ ├── loadProfile1.ts │ │ │ ├── loadProfile2.ts │ │ │ ├── loadProfile3.ts │ │ │ ├── loadProfile4.ts │ │ │ ├── loadRewardTable.ts │ │ │ ├── loadServerList.ts │ │ │ ├── loadStocker.ts │ │ │ ├── loadTeamRanking.ts │ │ │ ├── loadTopTen1.ts │ │ │ ├── loadTopTen2.ts │ │ │ ├── lockProfile.ts │ │ │ ├── lockProfileExtend.ts │ │ │ ├── saveExpedition.ts │ │ │ ├── saveGarage.ts │ │ │ ├── saveNewCar.ts │ │ │ ├── saveTimeAttack.ts │ │ │ ├── saveTopic.ts │ │ │ ├── unlockProfile.ts │ │ │ ├── updateExpedition.ts │ │ │ ├── updateProvisionalStoreRank.ts │ │ │ ├── updateStoryClearNum.ts │ │ │ ├── updateTeamLeader.ts │ │ │ └── updateTeamMember.ts │ │ ├── handler │ │ │ ├── _team.ts │ │ │ ├── checkTeamName.ts │ │ │ ├── createAutoTeam.ts │ │ │ ├── createProfile.ts │ │ │ ├── createTeam.ts │ │ │ ├── discoverProfile.ts │ │ │ ├── index.ts │ │ │ ├── load2on2.ts │ │ │ ├── loadConfig.ts │ │ │ ├── loadEventInfo.ts │ │ │ ├── loadGacha.ts │ │ │ ├── loadGarage.ts │ │ │ ├── loadGeneralReward.ts │ │ │ ├── loadGhost.ts │ │ │ ├── loadProfile.ts │ │ │ ├── loadRewardTable.ts │ │ │ ├── loadServerList.ts │ │ │ ├── loadStocker.ts │ │ │ ├── loadTeam.ts │ │ │ ├── loadTeamRanking.ts │ │ │ ├── loadTopTen.ts │ │ │ ├── lockGarage.ts │ │ │ ├── lockProfile.ts │ │ │ ├── lockProfileExtend.ts │ │ │ ├── saveExpedition.ts │ │ │ ├── saveGarage.ts │ │ │ ├── saveNewCar.ts │ │ │ ├── saveProfile.ts │ │ │ ├── saveSettings.ts │ │ │ ├── saveStocker.ts │ │ │ ├── saveTeamBanner.ts │ │ │ ├── saveTimeAttack.ts │ │ │ ├── saveTopic.ts │ │ │ ├── unknownA.ts │ │ │ ├── unlockProfile.ts │ │ │ ├── updateExpedition.ts │ │ │ ├── updateProvisionalStoreRank.ts │ │ │ ├── updateResult.ts │ │ │ ├── updateStoryClearNum.ts │ │ │ ├── updateTeamLeader.ts │ │ │ ├── updateTeamMember.ts │ │ │ ├── updateTeamPoints.ts │ │ │ ├── updateUiReport.ts │ │ │ └── updateUserLog.ts │ │ ├── index.ts │ │ ├── model │ │ │ ├── base.ts │ │ │ ├── car.ts │ │ │ ├── chara.ts │ │ │ ├── index.ts │ │ │ ├── mission.ts │ │ │ ├── profile.ts │ │ │ ├── settings.ts │ │ │ ├── stamps.ts │ │ │ ├── story.ts │ │ │ ├── team.ts │ │ │ ├── tickets.ts │ │ │ ├── timeAttack.ts │ │ │ ├── unlocks.ts │ │ │ └── weeklyMissions.ts │ │ ├── repo.ts │ │ ├── request │ │ │ ├── checkTeamName.ts │ │ │ ├── createAutoTeam.ts │ │ │ ├── createProfile.ts │ │ │ ├── createTeam.ts │ │ │ ├── discoverProfile.ts │ │ │ ├── index.ts │ │ │ ├── load2on2.ts │ │ │ ├── loadConfig.ts │ │ │ ├── loadEventInfo.ts │ │ │ ├── loadGacha.ts │ │ │ ├── loadGarage.ts │ │ │ ├── loadGeneralReward.ts │ │ │ ├── loadGhost.ts │ │ │ ├── loadProfile.ts │ │ │ ├── loadRewardTable.ts │ │ │ ├── loadServerList.ts │ │ │ ├── loadStocker.ts │ │ │ ├── loadTeam.ts │ │ │ ├── loadTeamRanking.ts │ │ │ ├── loadTopTen.ts │ │ │ ├── lockGarage.ts │ │ │ ├── lockProfile.ts │ │ │ ├── lockProfileExtend.ts │ │ │ ├── saveExpedition.ts │ │ │ ├── saveGarage.ts │ │ │ ├── saveNewCar.ts │ │ │ ├── saveProfile.ts │ │ │ ├── saveSettings.ts │ │ │ ├── saveStocker.ts │ │ │ ├── saveTeamBanner.ts │ │ │ ├── saveTimeAttack.ts │ │ │ ├── saveTopic.ts │ │ │ ├── unknownA.ts │ │ │ ├── unlockProfile.ts │ │ │ ├── updateExpedition.ts │ │ │ ├── updateProvisionalStoreRank.ts │ │ │ ├── updateResult.ts │ │ │ ├── updateStoryClearNum.ts │ │ │ ├── updateTeamLeader.ts │ │ │ ├── updateTeamMember.ts │ │ │ ├── updateTeamPoints.ts │ │ │ ├── updateUiReport.ts │ │ │ └── updateUserLog.ts │ │ ├── response │ │ │ ├── _team.ts │ │ │ ├── checkTeamName.ts │ │ │ ├── createAutoTeam.ts │ │ │ ├── createProfile.ts │ │ │ ├── createTeam.ts │ │ │ ├── discoverProfile.ts │ │ │ ├── generic.ts │ │ │ ├── index.ts │ │ │ ├── load2on2.ts │ │ │ ├── loadConfig.ts │ │ │ ├── loadEventInfo.ts │ │ │ ├── loadGacha.ts │ │ │ ├── loadGarage.ts │ │ │ ├── loadGeneralReward.ts │ │ │ ├── loadGeneralReward1.ts │ │ │ ├── loadGeneralReward2.ts │ │ │ ├── loadGhost.ts │ │ │ ├── loadProfile.ts │ │ │ ├── loadRewardTable.ts │ │ │ ├── loadServerList.ts │ │ │ ├── loadStocker.ts │ │ │ ├── loadTeam.ts │ │ │ ├── loadTeamRanking.ts │ │ │ ├── loadTopTen.ts │ │ │ ├── lockProfile.ts │ │ │ ├── lockProfileExtend.ts │ │ │ ├── saveExpedition.ts │ │ │ ├── saveGarage.ts │ │ │ ├── saveNewCar.ts │ │ │ ├── saveTimeAttack.ts │ │ │ ├── saveTopic.ts │ │ │ ├── unlockProfile.ts │ │ │ ├── updateExpedition.ts │ │ │ ├── updateProvisionalStoreRank.ts │ │ │ ├── updateStoryClearNum.ts │ │ │ ├── updateTeamLeader.ts │ │ │ └── updateTeamMember.ts │ │ └── sql │ │ │ ├── backgrounds.ts │ │ │ ├── car.ts │ │ │ ├── chara.ts │ │ │ ├── coursePlays.ts │ │ │ ├── index.ts │ │ │ ├── missions.ts │ │ │ ├── myChara.ts │ │ │ ├── profile.ts │ │ │ ├── settings.ts │ │ │ ├── stamps.ts │ │ │ ├── story.ts │ │ │ ├── team.ts │ │ │ ├── teamAuto.ts │ │ │ ├── teamMember.ts │ │ │ ├── teamReservation.ts │ │ │ ├── tickets.ts │ │ │ ├── timeAttack.ts │ │ │ ├── titles.ts │ │ │ ├── unlocks.ts │ │ │ └── weeklyMissions.ts │ └── util │ │ └── bin.ts ├── index.ts ├── model.ts ├── sql │ ├── api.ts │ ├── index.ts │ ├── sqlite.test.ts │ ├── sqlite.ts │ └── util.ts ├── switchboard.ts └── util │ └── stream │ ├── index.ts │ ├── reader.ts │ ├── stream.ts │ ├── types.ts │ └── writer.ts ├── start.bat ├── tsconfig.json └── types ├── sql-bricks-postgres └── index.d.ts └── sql-bricks └── index.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | max_line_length = 79 11 | 12 | [*.md] 13 | indent_size = 2 14 | 15 | [*.sql] 16 | indent_size = 4 17 | 18 | [*.ts] 19 | indent_size = 2 20 | 21 | [*.json] 22 | indent_size = 2 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | data/ 3 | node_modules/ 4 | .env 5 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: node:12-buster 2 | 3 | cache: 4 | paths: 5 | - node_modules/ 6 | 7 | stages: 8 | - build 9 | 10 | do_build: 11 | stage: build 12 | script: 13 | - npm install 14 | - npm run build 15 | - npm test 16 | 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "EditorConfig.EditorConfig", 4 | "esbenp.prettier-vscode", 5 | "mikestead.dotenv" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.rulers": [79], 4 | "typescript.tsdk": "node_modules/typescript/lib", 5 | "[typescript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiniMe 2 | 3 | A simple self-hosted ALLNET/AiMe server written in TypeScript, running on Node.js, that stores its data in an SQLite database. 4 | -------------------------------------------------------------------------------- /pki/billing.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAML2GPUuzv2N4bYC 3 | xtc5bZSzolHFWdCUbP+whjr3K98FOLnYeoi7mtUSUUYOW8wIqy6WM3c4c0Bp7FcQ 4 | LnZ0zWMm1TfLGHZzZmk5n7Iv6HDPr3ehDgbWLnOpRrVqZDxpAGD2vQb4p2DW4I2x 5 | GUqnqDa++C8dH/0lXqE6cqwGXNGtAgMBAAECgYEAizgPhG4Dk55QkpeTBDfXH3vT 6 | Ko9B3qdO2ptkjxDX/C8PXe7POXq2SvcEoIE6Xg3Gp8LMR5NBAbth8J32f9JSov3P 7 | SiGCGno4k2i2s3jRuVg76FGLDsZH/N1dt4h78VnW0VlInwaM6bQv3zp0u8rXVk/P 8 | wpYh9AGmquBJS3VYUcECQQD0PDRe28SrhollygGZSO321rYbYhoTIstDXZWyQ/y/ 9 | PWKNwNHcYTHIVGmTrJx2AJUyr1tJhwjiOwlsI5Y1Q4/9AkEAzFpFPcs1r/xgSFxB 10 | eYrcNseWYbVajtVxG9t57sayaEQbH2UMNA2vqSYK/nU6oJhj5eLRIsPHlA5ZbIiZ 11 | rvc/cQJAKS0RQ0DX+ncXKQMSm+4wuGHgl+NFNB60mCnp+AEAVpmZyP5OI1J7myOo 12 | HQ6H3lkgzkfEIzRR6ho773BcfaRjXQJAfS4nEE11G9ML4AezjBLGB0CIHF6NlMWn 13 | PhtaPCy3iSt/OeIacaCYpJNLVMjXGx1+xIoG9rbbgRSxLs0W55lJ4QJBALOUVcNw 14 | GKEJdxhIkA8iuUlEyGpKluAgHUNOOKvC3ogRoB0OyH+If/9o8wWDfxgexgM0zGBc 15 | u178W9XDW+IijDA= 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /pki/billing.pub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Soyandroid/minime/86c7ae272d2c6ca50474175677bf1f693e000ca7/pki/billing.pub -------------------------------------------------------------------------------- /pki/ca.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Soyandroid/minime/86c7ae272d2c6ca50474175677bf1f693e000ca7/pki/ca.crt -------------------------------------------------------------------------------- /pki/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICtDCCAZwCAQAwDQYJKoZIhvcNAQELBQAwJTEQMA4GA1UEAwwHRHVtbXlDQTER 3 | MA8GA1UECgwIRHVtbXlQS0kwIBcNMTgxMDE1MTkzMDUxWhgPMjExODEwMTUxOTMw 4 | NTFaMBkxFzAVBgNVBAMMDmliLm5hb21pbmV0LmpwMIIBIjANBgkqhkiG9w0BAQEF 5 | AAOCAQ8AMIIBCgKCAQEA4Ncb4/CS7eJw6q0UDhswsrNGw9lXRkZ0P02At3s4NMIW 6 | G0EQ+21HZDUJtSnjTpY/Mq/JI899LMCGOulH8PNqhh9EI7Jm0jky69dwfStaIHdd 7 | WjMRK71Z8bTQTpLsLcyi/mW9Q/fY78V9LntHSLAXLqI3psqM+ojW1O1kjbWyBXkB 8 | a/jJWboxyL9B4++jGMmQKjathdzrtUnblZMPgHKJfCs034iCN/Im2XD/iDYCumL5 9 | 6ya8Ww2fjV8LFznoNMv72e4XNodZOcE9xMVqMjA/2751ayk53kH8DiPbOLN6QeqN 10 | YRnlBkYT76SdtPhRjhPCyEcwRIsQypfNkxutw1aDCQIDAQABMA0GCSqGSIb3DQEB 11 | CwUAA4IBAQANOqFqjnGf80vvwYEkUsfOWp8rNVat+8rdXl0BShGBXiDItzMOU79K 12 | YkPObniQ5RLBMhrvqlCsSk0Np+ZgvV12J4Wtmf/znLa5ZKyeI4N1FCefU9cl4xpB 13 | 08Fv8YWbYV7SMNr54ZkURdho4FVR1pAnpuittpAEjMT4R4ubbOH8UEbMTbVgxXdn 14 | 086IAlfsYn0gnOlf76RkJFLe4UlWaZB75SaaXnNavBPN9iFnqXLckg6tsFUJnNMC 15 | esq5aHQ9sXWs4oKpJi8SXxt/zNRmgTnQK2ONM38NeZpLmlWPkyNxzsRNlYWo+kWP 16 | C98jVFe1+3K88ISk0DSN4XOQQnrIvn68 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /schema/init/aime.sql: -------------------------------------------------------------------------------- 1 | create table "aime_player" ( 2 | "id" integer primary key not null, 3 | "ext_id" integer not null, 4 | "luid" text not null, 5 | "register_time" timestamp not null, 6 | "access_time" timestamp not null, 7 | constraint "aime_player_ext_id_uq" unique ("ext_id"), 8 | constraint "aime_player_luid_uq" unique ("luid") 9 | ); 10 | -------------------------------------------------------------------------------- /schema/init/meta.sql: -------------------------------------------------------------------------------- 1 | create table "meta" ("schemaver" integer not null); 2 | -------------------------------------------------------------------------------- /schema/migrate/M0007-aime-simplify-player.sql: -------------------------------------------------------------------------------- 1 | -- Can't add NOT NULL or UNIQUE constraints as we'd like to. Fortunately we 2 | -- haven't released anything yet so there aren't really any DBs with live 3 | -- data out there in the wild. 4 | 5 | -- (Can't drop and recreate the table either btw because "aime_player" is 6 | -- transitively referenced by _literally everything_). 7 | 8 | alter table "aime_player" add column "luid" text; 9 | alter table "aime_player" add column "access_time" text; 10 | 11 | update "aime_player" as "p" 12 | set "luid" = ( 13 | select "c"."nfc_id" 14 | from "aime_card" as "c" 15 | where "c"."player_id" = "p"."id" 16 | ), 17 | "access_time" = ( 18 | select "c"."access_time" 19 | from "aime_card" as "c" 20 | where "c"."player_id" = "p"."id" 21 | ); 22 | 23 | drop table "aime_card"; 24 | 25 | -- These were never used. Re-create them if they become necessary. 26 | drop table "aime_machine"; 27 | drop table "aime_shop"; 28 | -------------------------------------------------------------------------------- /schema/migrate/M0009-idz-aura.sql: -------------------------------------------------------------------------------- 1 | -- This adds the required columns to save player aura settings and unlocks 2 | -- Default values are set according to what the game expects 3 | 4 | alter table "idz_settings" add column "aura" integer NOT NULL DEFAULT '0'; 5 | alter table "idz_unlocks" add column "auras" integer NOT NULL DEFAULT '1'; -------------------------------------------------------------------------------- /schema/migrate/M0010-cm-user-duel-list.sql: -------------------------------------------------------------------------------- 1 | create table "cm_user_duel_list" ( 2 | "id" integer primary key not null, 3 | "profile_id" integer not null 4 | references "cm_user_data"("id") 5 | on delete cascade, 6 | "duel_id" integer not null, 7 | "progress" integer not null, 8 | "point" integer not null, 9 | "is_clear" boolean not null, 10 | "last_play_date" text not null, 11 | "param1" integer not null, 12 | "param2" integer not null, 13 | "param3" integer not null, 14 | "param4" integer not null, 15 | constraint "cm_user_duel_list_uq" unique ("profile_id", "duel_id") 16 | ); 17 | -------------------------------------------------------------------------------- /schema/migrate/M0011-cm-user-course.sql: -------------------------------------------------------------------------------- 1 | create table "cm_user_course" ( 2 | "id" integer primary key not null, 3 | "profile_id" integer not null 4 | references "cm_user_data"("id") 5 | on delete cascade, 6 | "course_id" integer not null, 7 | "class_id" integer not null, 8 | "play_count" integer not null, 9 | "score_max" integer not null, 10 | "is_full_combo" text not null, 11 | "is_all_justice" text not null, 12 | "is_success" text not null, 13 | "score_rank" integer not null, 14 | "event_id" integer not null, 15 | "last_play_date" text not null, 16 | "param1" integer not null, 17 | "param2" integer not null, 18 | "param3" integer not null, 19 | "param4" integer not null, 20 | "is_clear" text not null, 21 | constraint "cm_user_course_uq" unique ("profile_id", "course_id") 22 | ); 23 | -------------------------------------------------------------------------------- /schema/migrate/M0012-cm-user-course-fix.sql: -------------------------------------------------------------------------------- 1 | -- This was not present in new DBs initialized to schema version 11. 2 | create table if not exists "cm_user_course" ( 3 | "id" integer primary key not null, 4 | "profile_id" integer not null 5 | references "cm_user_data"("id") 6 | on delete cascade, 7 | "course_id" integer not null, 8 | "class_id" integer not null, 9 | "play_count" integer not null, 10 | "score_max" integer not null, 11 | "is_full_combo" text not null, 12 | "is_all_justice" text not null, 13 | "is_success" text not null, 14 | "score_rank" integer not null, 15 | "event_id" integer not null, 16 | "last_play_date" text not null, 17 | "param1" integer not null, 18 | "param2" integer not null, 19 | "param3" integer not null, 20 | "param4" integer not null, 21 | "is_clear" text not null, 22 | constraint "cm_user_course_uq" unique ("profile_id", "course_id") 23 | ); 24 | -------------------------------------------------------------------------------- /schema/migrate/M0013-cm-user-duel-list-fix.sql: -------------------------------------------------------------------------------- 1 | -- This was also not present in the db init scripts... 2 | create table if not exists "cm_user_duel_list" ( 3 | "id" integer primary key not null, 4 | "profile_id" integer not null 5 | references "cm_user_data"("id") 6 | on delete cascade, 7 | "duel_id" integer not null, 8 | "progress" integer not null, 9 | "point" integer not null, 10 | "is_clear" boolean not null, 11 | "last_play_date" text not null, 12 | "param1" integer not null, 13 | "param2" integer not null, 14 | "param3" integer not null, 15 | "param4" integer not null, 16 | constraint "cm_user_duel_list_uq" unique ("profile_id", "duel_id") 17 | ); 18 | -------------------------------------------------------------------------------- /schema/migrate/M0014-cm-user-charge.sql: -------------------------------------------------------------------------------- 1 | create table if not exists "cm_user_charge" ( 2 | "id" integer primary key not null, 3 | "profile_id" integer not null 4 | references "cm_user_data"("id") 5 | on delete cascade, 6 | "charge_id" integer not null, 7 | "stock" integer not null, 8 | "purchase_date" text not null, 9 | "valid_date" text not null, 10 | "param1" integer not null, 11 | "param2" integer not null, 12 | "param_date" text not null, 13 | constraint "cm_user_charge_uq" unique ("profile_id", "charge_id") 14 | ); 15 | -------------------------------------------------------------------------------- /schema/migrate/M0018-idz-auto-team-fix.sql: -------------------------------------------------------------------------------- 1 | create table "new_idz_team_auto" ( 2 | "id" integer primary key not null 3 | references "idz_team"("id") 4 | on delete cascade, 5 | "serial_no" integer not null, 6 | "name_idx" integer not null 7 | ); 8 | 9 | insert into "new_idz_team_auto" 10 | select "id", "serial_no", "name_idx" from "idz_team_auto"; 11 | 12 | drop table "idz_team_auto"; 13 | alter table "new_idz_team_auto" rename to "idz_team_auto"; 14 | -------------------------------------------------------------------------------- /src/aimedb/frame.ts: -------------------------------------------------------------------------------- 1 | import logger from "debug"; 2 | import { Transform } from "stream"; 3 | 4 | const debug = logger("app:aimedb:frame"); 5 | 6 | export class Deframer extends Transform { 7 | private state: Buffer; 8 | 9 | constructor(options) { 10 | super({ 11 | readableObjectMode: true, 12 | ...options, 13 | }); 14 | 15 | this.state = Buffer.alloc(0); 16 | } 17 | 18 | _transform(chunk, encoding, callback) { 19 | this.state = Buffer.concat([this.state, chunk]); 20 | 21 | if (this.state.length < 8) { 22 | return; 23 | } 24 | 25 | const magic = this.state.readUInt16LE(0x0000); 26 | 27 | if (magic != 0xa13e) { 28 | return callback(new Error(`Invalid magic (decimal ${magic})`)); 29 | } 30 | 31 | const len = this.state.readUInt16LE(0x0006); 32 | 33 | if (this.state.length < len) { 34 | return; 35 | } 36 | 37 | const frame = this.state.slice(0, len); 38 | 39 | if (debug.enabled) { 40 | debug("Recv %s", frame.toString("hex")); 41 | } 42 | 43 | this.state = this.state.slice(len); 44 | 45 | return callback(null, frame); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/aimedb/index.ts: -------------------------------------------------------------------------------- 1 | import logger from "debug"; 2 | import { Socket } from "net"; 3 | 4 | import { dispatch } from "./handler"; 5 | import { setup } from "./pipeline"; 6 | import { DataSource } from "../sql/api"; 7 | import { SqlRepositories } from "./sql"; 8 | 9 | const debug = logger("app:aimedb:session"); 10 | 11 | export default function aimedb(db: DataSource) { 12 | return async function(socket: Socket) { 13 | debug("Connection opened"); 14 | 15 | const { input, output } = setup(socket); 16 | 17 | for await (const obj of input) { 18 | try { 19 | const now = new Date(); 20 | const req = obj; 21 | const res = await db.transaction(txn => 22 | dispatch(new SqlRepositories(txn), req, now) 23 | ); 24 | 25 | if (res === undefined) { 26 | debug("Closing connection"); 27 | 28 | break; 29 | } 30 | 31 | output.write(res); 32 | } catch (e) { 33 | if (debug.enabled) { 34 | debug("Connection error: %s", e.stack); 35 | } 36 | 37 | break; 38 | } 39 | } 40 | 41 | debug("Connection closed"); 42 | socket.end(); 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/aimedb/pipeline.ts: -------------------------------------------------------------------------------- 1 | import { createCipheriv, createDecipheriv } from "crypto"; 2 | import { Socket } from "net"; 3 | import * as stream from "stream"; 4 | import { promisify } from "util"; 5 | 6 | import { Decoder } from "./decoder"; 7 | import { Deframer } from "./frame"; 8 | import { Encoder } from "./encoder"; 9 | import { AimeRequest } from "./request"; 10 | import { AimeResponse } from "./response"; 11 | 12 | const K = Buffer.from("Copyright(C)SEGA", "utf8"); 13 | const pipeline = promisify(stream.pipeline); 14 | 15 | export interface Session { 16 | input: AsyncIterable; 17 | output: { 18 | write(res: AimeResponse): void; 19 | }; 20 | } 21 | 22 | function doNothing() {} 23 | 24 | export function setup(socket: Socket): Session { 25 | const input = new Decoder(); 26 | 27 | pipeline( 28 | socket, 29 | createDecipheriv("aes-128-ecb", K, null).setAutoPadding(false), 30 | new Deframer({}), 31 | input 32 | ).catch(doNothing); 33 | 34 | const output = new Encoder(); 35 | 36 | pipeline( 37 | output, 38 | createCipheriv("aes-128-ecb", K, null).setAutoPadding(false), 39 | socket 40 | ).catch(doNothing); 41 | 42 | return { input, output }; 43 | } 44 | -------------------------------------------------------------------------------- /src/aimedb/repo.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../model"; 2 | 3 | export interface CardRepository { 4 | lookup(luid: string, now: Date): Promise; 5 | 6 | register(luid: string, now: Date): Promise; 7 | } 8 | 9 | export interface Repositories { 10 | cards(): CardRepository; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/handler/_util.ts: -------------------------------------------------------------------------------- 1 | // Make the names explicit so that we don't get the order mixed up 2 | interface Params { 3 | maxCount: number; 4 | nextIndex: number; 5 | } 6 | 7 | export function paginationCookie(items: T[], params: Params) { 8 | if (items.length < params.maxCount) { 9 | return "-1"; 10 | } else { 11 | return (params.nextIndex + params.maxCount).toString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/chunithm/handler/gameLogin.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GameLoginRequest } from "../request/gameLogin"; 3 | import { GameLoginResponse } from "../response/gameLogin"; 4 | 5 | export default async function gameLogin( 6 | rep: Repositories, 7 | req: GameLoginRequest 8 | ): Promise { 9 | return { returnCode: "1" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/handler/gameLogout.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GameLogoutRequest } from "../request/gameLogout"; 3 | import { GameLogoutResponse } from "../response/gameLogout"; 4 | 5 | export default async function gameLogout( 6 | rep: Repositories, 7 | req: GameLogoutRequest 8 | ): Promise { 9 | return { returnCode: "1" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameCharge.ts: -------------------------------------------------------------------------------- 1 | import { GameChargeJson } from "../proto/gameCharge"; 2 | import { Repositories } from "../repo"; 3 | import { GetGameChargeRequest } from "../request/getGameCharge"; 4 | import { GetGameChargeResponse } from "../response/getGameCharge"; 5 | import { CHARGE_IDS } from "../static/charge"; 6 | 7 | export default async function getGameCharge( 8 | rep: Repositories, 9 | req: GetGameChargeRequest 10 | ): Promise { 11 | const gameChargeList: GameChargeJson[] = []; 12 | 13 | for (const [i, charge] of CHARGE_IDS.entries()) { 14 | gameChargeList.push({ 15 | chargeId: charge.id.toString(), 16 | orderId: (i+1).toString(), 17 | price: charge.price.toString(), 18 | salePrice: charge.salePrice.toString(), 19 | startDate: "2017-12-05 07:00:00.0", 20 | endDate: "2029-12-31 23:59:59.0", 21 | saleStartDate: "2017-12-05 07:00:00.0", 22 | saleEndDate: "2030-12-31 23:59:59.0" 23 | }); 24 | } 25 | 26 | return { 27 | length: gameChargeList.length.toString(), 28 | gameChargeList, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameEvent.ts: -------------------------------------------------------------------------------- 1 | import { GameEventJson } from "../proto/gameEvent"; 2 | import { Repositories } from "../repo"; 3 | import { GetGameEventRequest } from "../request/getGameEvent"; 4 | import { GetGameEventResponse } from "../response/getGameEvent"; 5 | import { EVENT_IDS } from "../static/event"; 6 | 7 | export default async function getGameEvent( 8 | rep: Repositories, 9 | req: GetGameEventRequest 10 | ): Promise { 11 | const gameEventList: GameEventJson[] = []; 12 | 13 | for (const id of EVENT_IDS) { 14 | gameEventList.push({ 15 | type: req.type, 16 | id: id.toString(), 17 | startDate: "2017-12-05 07:00:00.0", 18 | endDate: "2099-12-31 00:00:00.0", 19 | }); 20 | } 21 | 22 | return { 23 | type: req.type, 24 | length: gameEventList.length.toString(), 25 | gameEventList, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameIdlist.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetGameIdlistRequest } from "../request/getGameIdlist"; 3 | import { GetGameIdlistResponse } from "../response/getGameIdlist"; 4 | 5 | export default async function getGameIdlist( 6 | rep: Repositories, 7 | req: GetGameIdlistRequest 8 | ): Promise { 9 | return { 10 | type: req.type, 11 | length: "0", 12 | gameIdlistList: [], 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameMessage.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetGameMessageRequest } from "../request/getGameMessage"; 3 | import { GetGameMessageResponse } from "../response/getGameMessage"; 4 | 5 | export default async function getGameMessage( 6 | rep: Repositories, 7 | req: GetGameMessageRequest 8 | ): Promise { 9 | return { 10 | type: req.type, 11 | length: "0", 12 | gameMessageList: [], 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameRanking.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetGameRankingRequest } from "../request/getGameRanking"; 3 | import { GetGameRankingResponse } from "../response/getGameRanking"; 4 | 5 | export default async function getGameRanking( 6 | rep: Repositories, 7 | req: GetGameRankingRequest 8 | ): Promise { 9 | return { 10 | type: req.type, 11 | gameRankingList: [], 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameSale.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetGameSaleRequest } from "../request/getGameSale"; 3 | import { GetGameSaleResponse } from "../response/getGameSale"; 4 | 5 | export default async function getGameSale( 6 | rep: Repositories, 7 | req: GetGameSaleRequest 8 | ): Promise { 9 | return { 10 | type: req.type, 11 | length: "0", 12 | gameSaleList: [], 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/handler/getGameSetting.ts: -------------------------------------------------------------------------------- 1 | import { writeDate } from "../proto/base"; 2 | import { Repositories } from "../repo"; 3 | import { GetGameSettingRequest } from "../request/getGameSetting"; 4 | import { GetGameSettingResponse } from "../response/getGameSetting"; 5 | 6 | export default async function getGameSetting( 7 | rep: Repositories, 8 | req: GetGameSettingRequest 9 | ): Promise { 10 | const rebootStartTime = new Date(); 11 | rebootStartTime.setHours(rebootStartTime.getHours() - 3); 12 | 13 | const rebootEndTime = new Date(); 14 | rebootEndTime.setHours(rebootEndTime.getHours() - 2); 15 | 16 | return { 17 | gameSetting: { 18 | dataVersion: "1", 19 | isMaintenance: "false", 20 | requestInterval: "10", 21 | rebootStartTime: writeDate(rebootStartTime), 22 | rebootEndTime: writeDate(rebootEndTime), 23 | isBackgroundDistribute: "false", 24 | maxCountCharacter: "300", 25 | maxCountItem: "300", 26 | maxCountMusic: "100", 27 | }, 28 | isDumpUpload: "false", 29 | isAou: "true", 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserActivity.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserActivity } from "../proto/userActivity"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserActivityRequest } from "../request/getUserActivity"; 5 | import { GetUserActivityResponse } from "../response/getUserActivity"; 6 | 7 | export default async function getUserActivity( 8 | rep: Repositories, 9 | req: GetUserActivityRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | const kind = parseInt(req.kind); 13 | 14 | const profileId = await rep.userData().lookup(aimeId); 15 | const items = await rep.userActivity().load(profileId, kind); 16 | 17 | return { 18 | userId: req.userId, 19 | length: items.length.toString(), 20 | kind: kind.toString(), 21 | userActivityList: items.map(writeUserActivity), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserCharacter.ts: -------------------------------------------------------------------------------- 1 | import { paginationCookie } from "./_util"; 2 | import { readAimeId } from "../proto/base"; 3 | import { writeUserCharacter } from "../proto/userCharacter"; 4 | import { Repositories } from "../repo"; 5 | import { GetUserCharacterRequest } from "../request/getUserCharacter"; 6 | import { GetUserCharacterResponse } from "../response/getUserCharacter"; 7 | 8 | export default async function getUserCharacter( 9 | rep: Repositories, 10 | req: GetUserCharacterRequest 11 | ): Promise { 12 | const aimeId = readAimeId(req.userId); 13 | const maxCount = parseInt(req.maxCount); 14 | const nextIndex = parseInt(req.nextIndex); 15 | 16 | const profileId = await rep.userData().lookup(aimeId); 17 | const items = await rep 18 | .userCharacter() 19 | .load(profileId, { limit: maxCount, offset: nextIndex }); 20 | 21 | return { 22 | userId: req.userId, 23 | length: items.length.toString(), 24 | nextIndex: paginationCookie(items, { maxCount, nextIndex }), 25 | userCharacterList: items.map(writeUserCharacter), 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserCharge.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserCharge } from "../proto/userCharge"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserChargeRequest } from "../request/getUserCharge"; 5 | import { GetUserChargeResponse } from "../response/getUserCharge"; 6 | 7 | export default async function getUserCharge( 8 | rep: Repositories, 9 | req: GetUserChargeRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const items = await rep.userCharge().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | length: items.length.toString(), 19 | userChargeList: items.map(writeUserCharge), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserCourse.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetUserCourseRequest } from "../request/getUserCourse"; 3 | import { GetUserCourseResponse } from "../response/getUserCourse"; 4 | import { readAimeId } from "../proto/base"; 5 | import { paginationCookie } from "./_util"; 6 | import { writeUserCourse } from "../proto/userCourse"; 7 | 8 | export default async function getUserCourse( 9 | rep: Repositories, 10 | req: GetUserCourseRequest 11 | ): Promise { 12 | const aimeId = readAimeId(req.userId); 13 | const maxCount = parseInt(req.maxCount); 14 | const nextIndex = parseInt(req.nextIndex); 15 | 16 | const profileId = await rep.userData().lookup(aimeId); 17 | const items = await rep 18 | .userCourse() 19 | .load(profileId, { limit: maxCount, offset: nextIndex }); 20 | 21 | return { 22 | userId: req.userId, 23 | length: items.length.toString(), 24 | nextIndex: paginationCookie(items, { maxCount, nextIndex }), 25 | userCourseList: items.map(writeUserCourse) 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserData.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserData } from "../proto/userData"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserDataRequest } from "../request/getUserData"; 5 | import { GetUserDataResponse } from "../response/getUserData"; 6 | 7 | export default async function getUserData( 8 | rep: Repositories, 9 | req: GetUserDataRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const userData = await rep.userData().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | userData: writeUserData(userData), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserDataEx.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserDataEx } from "../proto/userDataEx"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserDataExRequest } from "../request/getUserDataEx"; 5 | import { GetUserDataExResponse } from "../response/getUserDataEx"; 6 | 7 | export default async function getUserDataEx( 8 | rep: Repositories, 9 | req: GetUserDataExRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const userDataEx = await rep.userDataEx().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | userDataEx: writeUserDataEx(userDataEx), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserDuel.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetUserDuelRequest } from "../request/getUserDuel"; 3 | import { GetUserDuelResponse } from "../response/getUserDuel"; 4 | import { readAimeId } from "../proto/base"; 5 | import { writeUserDuelList } from "../proto/userDuelList"; 6 | 7 | export default async function getUserDuel( 8 | rep: Repositories, 9 | req: GetUserDuelRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | // Get all duel entities if the client specifies to. 13 | const duelId = req.isAllDuel ? undefined : parseInt(req.duelId); 14 | 15 | const profileId = await rep.userData().lookup(aimeId); 16 | const items = await rep.userDuelList().load(profileId, duelId); 17 | 18 | return { 19 | userId: req.userId, 20 | length: items.length.toString(), 21 | userDuelList: items.map(writeUserDuelList), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserFavoriteMusic.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetUserFavoriteMusicRequest } from "../request/getUserFavoriteMusic"; 3 | import { GetUserFavoriteMusicResponse } from "../response/getUserFavoriteMusic"; 4 | import { readAimeId } from "../proto/base"; 5 | 6 | export default async function getUserFavoriteMusic( 7 | rep: Repositories, 8 | req: GetUserFavoriteMusicRequest 9 | ): Promise { 10 | const aimeId = readAimeId(req.userId); 11 | 12 | const profileId = await rep.userData().lookup(aimeId); 13 | 14 | /* 15 | * `Chunithm Amazon Plus` does not appear to save a favorites list and there 16 | * is no user-accessible favorites function from what I can tell. 17 | */ 18 | return { 19 | userId: req.userId, 20 | length: "0", 21 | userFavoriteMusicList: [], 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserMap.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserMap } from "../proto/userMap"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserMapRequest } from "../request/getUserMap"; 5 | import { GetUserMapResponse } from "../response/getUserMap"; 6 | 7 | export default async function getUserMap( 8 | rep: Repositories, 9 | req: GetUserMapRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const items = await rep.userMap().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | length: items.length.toString(), 19 | userMapList: items.map(writeUserMap), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserOption.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserGameOption } from "../proto/userGameOption"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserOptionRequest } from "../request/getUserOption"; 5 | import { GetUserOptionResponse } from "../response/getUserOption"; 6 | 7 | export default async function getUserOption( 8 | rep: Repositories, 9 | req: GetUserOptionRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const userGameOption = await rep.userGameOption().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | userGameOption: writeUserGameOption(userGameOption), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserOptionEx.ts: -------------------------------------------------------------------------------- 1 | import { readAimeId } from "../proto/base"; 2 | import { writeUserGameOptionEx } from "../proto/userGameOptionEx"; 3 | import { Repositories } from "../repo"; 4 | import { GetUserOptionExRequest } from "../request/getUserOptionEx"; 5 | import { GetUserOptionExResponse } from "../response/getUserOptionEx"; 6 | 7 | export default async function getUserOptionEx( 8 | rep: Repositories, 9 | req: GetUserOptionExRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | const userGameOptionEx = await rep.userGameOptionEx().load(profileId); 15 | 16 | return { 17 | userId: req.userId, 18 | userGameOptionEx: writeUserGameOptionEx(userGameOptionEx), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserRecentRating.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetUserRecentRatingRequest } from "../request/getUserRecentRating"; 3 | import { GetUserRecentRatingResponse } from "../response/getUserRecentRating"; 4 | import { readAimeId } from "../proto/base"; 5 | import { writeUserRecentRating } from "../proto/userRecentRating"; 6 | 7 | export default async function getUserRecentRating( 8 | rep: Repositories, 9 | req: GetUserRecentRatingRequest 10 | ): Promise { 11 | const aimeId = readAimeId(req.userId); 12 | 13 | const profileId = await rep.userData().lookup(aimeId); 14 | // Return recent 30 plays to calculate rating 15 | const items = await rep.userRecentRating().load(profileId); 16 | 17 | return { 18 | userId: req.userId, 19 | length: items.length.toString(), 20 | userRecentRatingList: items.map(writeUserRecentRating), 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/chunithm/handler/getUserRegion.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { GetUserRegionRequest } from "../request/getUserRegion"; 3 | import { GetUserRegionResponse } from "../response/getUserRegion"; 4 | 5 | export default async function getUserRegion( 6 | rep: Repositories, 7 | req: GetUserRegionRequest 8 | ): Promise { 9 | return { 10 | userId: req.userId, 11 | length: "0", 12 | userRegionList: [ 13 | // Doesn't get saved 14 | ], 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertClientBookkeeping.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertClientBookkeepingRequest } from "../request/upsertClientBookkeeping"; 3 | import { UpsertClientBookkeepingResponse } from "../response/upsertClientBookkeeping"; 4 | 5 | export default async function upsertClientBookkeeping( 6 | rep: Repositories, 7 | req: UpsertClientBookkeepingRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertClientDevelop.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertClientDevelopRequest } from "../request/upsertClientDevelop"; 3 | import { UpsertClientDevelopResponse } from "../response/upsertClientDevelop"; 4 | 5 | export default async function upsertClientDevelop( 6 | rep: Repositories, 7 | req: UpsertClientDevelopRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertClientError.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertClientErrorRequest } from "../request/upsertClientError"; 3 | import { UpsertClientErrorResponse } from "../response/upsertClientError"; 4 | 5 | export default async function upsertClientError( 6 | rep: Repositories, 7 | req: UpsertClientErrorRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertClientSetting.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertClientSettingRequest } from "../request/upsertClientSetting"; 3 | import { UpsertClientSettingResponse } from "../response/upsertClientSetting"; 4 | 5 | export default async function upsertClientSetting( 6 | rep: Repositories, 7 | req: UpsertClientSettingRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertClientTestmode.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertClientTestmodeRequest } from "../request/upsertClientTestmode"; 3 | import { UpsertClientTestmodeResponse } from "../response/upsertClientTestmode"; 4 | 5 | export default async function upsertClientTestmode( 6 | rep: Repositories, 7 | req: UpsertClientTestmodeRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/handler/upsertUserChargelogApi.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { UpsertUserChargelogApiRequest } from "../request/upsertUserChargelogApi"; 3 | import { UpsertUserChargelogApiResponse } from "../response/upsertUserChargelogApi"; 4 | 5 | export default async function UpsertUserChargelogApi( 6 | rep: Repositories, 7 | req: UpsertUserChargelogApiRequest 8 | ): Promise { 9 | return { 10 | returnCode: "1", 11 | }; 12 | } -------------------------------------------------------------------------------- /src/chunithm/index.ts: -------------------------------------------------------------------------------- 1 | import chunithm from "./handler"; 2 | export default chunithm; 3 | -------------------------------------------------------------------------------- /src/chunithm/model/gameCharge.ts: -------------------------------------------------------------------------------- 1 | export interface GameChargeItem { 2 | orderId: number; 3 | chargeId: number; 4 | price: number; 5 | startDate: Date; 6 | endDate: Date; 7 | salePrice: number; 8 | saleStartDate: Date; 9 | saleEndDate: Date; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/model/gameEvent.ts: -------------------------------------------------------------------------------- 1 | export interface GameEventItem { 2 | type: number; 3 | id: number; 4 | startDate: Date; 5 | endDate: Date; 6 | } 7 | -------------------------------------------------------------------------------- /src/chunithm/model/gameMessage.ts: -------------------------------------------------------------------------------- 1 | export interface GameMessageItem { 2 | type: number; 3 | id: number; 4 | message: string; 5 | startDate: Date; 6 | endDate: Date; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/model/gameRanking.ts: -------------------------------------------------------------------------------- 1 | export interface GameRankingItem { 2 | id: bigint; 3 | point: bigint; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/model/gameSale.ts: -------------------------------------------------------------------------------- 1 | export interface GameSaleItem { 2 | orderId: number; 3 | type: number; 4 | id: number; 5 | rate: number; 6 | startDate: Date; 7 | endDate: Date; 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/model/userActivity.ts: -------------------------------------------------------------------------------- 1 | export interface UserActivityItem { 2 | kind: number; 3 | activityId: number; // This is just called "id" in the JSON! 4 | sortNumber: number; 5 | param1: number; 6 | param2: number; 7 | param3: number; 8 | param4: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/chunithm/model/userCharacter.ts: -------------------------------------------------------------------------------- 1 | export interface UserCharacterItem { 2 | characterId: number; 3 | playCount: number; 4 | level: number; 5 | skillId: number; 6 | friendshipExp: number; 7 | isValid: boolean; 8 | isNewMark: boolean; 9 | param1: number; 10 | param2: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/model/userCharge.ts: -------------------------------------------------------------------------------- 1 | export interface UserChargeItem { 2 | chargeId: number; 3 | stock: number; 4 | purchaseDate: Date; 5 | validDate: Date; 6 | param1: number; 7 | param2: number; 8 | paramDate: Date; 9 | } 10 | -------------------------------------------------------------------------------- /src/chunithm/model/userCourse.ts: -------------------------------------------------------------------------------- 1 | export interface UserCourseItem { 2 | courseId: number; 3 | classId: number; 4 | playCount: number; 5 | scoreMax: number; 6 | isFullCombo: boolean; 7 | isAllJustice: boolean; 8 | isSuccess: boolean; 9 | scoreRank: number; 10 | eventId: number; 11 | lastPlayDate: Date; 12 | param1: number; 13 | param2: number; 14 | param3: number; 15 | param4: number; 16 | isClear: boolean; 17 | } 18 | -------------------------------------------------------------------------------- /src/chunithm/model/userDataEx.ts: -------------------------------------------------------------------------------- 1 | export interface UserDataExItem { 2 | compatibleCmVersion: string; 3 | medal: number; 4 | mapIconId: number; 5 | voiceId: number; 6 | ext1: number; 7 | ext2: number; 8 | ext3: number; 9 | ext4: number; 10 | ext5: number; 11 | ext6: number; 12 | ext7: number; 13 | ext8: number; 14 | ext9: number; 15 | ext10: number; 16 | ext11: number; 17 | ext12: number; 18 | ext13: number; 19 | ext14: number; 20 | ext15: number; 21 | ext16: number; 22 | ext17: number; 23 | ext18: number; 24 | ext19: number; 25 | ext20: number; 26 | extStr1: string; 27 | extStr2: string; 28 | extStr3: string; 29 | extStr4: string; 30 | extStr5: string; 31 | extLong1: bigint; 32 | extLong2: bigint; 33 | extLong3: bigint; 34 | extLong4: bigint; 35 | extLong5: bigint; 36 | } 37 | -------------------------------------------------------------------------------- /src/chunithm/model/userDuelList.ts: -------------------------------------------------------------------------------- 1 | export interface UserDuelListItem { 2 | duelId: number; 3 | progress: number; 4 | point: number; 5 | isClear: boolean; 6 | lastPlayDate: Date; 7 | param1: number; 8 | param2: number; 9 | param3: number; 10 | param4: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/model/userGameOption.ts: -------------------------------------------------------------------------------- 1 | export interface UserGameOptionItem { 2 | bgInfo: number; 3 | fieldColor: number; 4 | guideSound: number; 5 | soundEffect: number; 6 | guideLine: number; 7 | speed: number; 8 | optionSet: number; 9 | matching: number; 10 | judgePos: number; 11 | rating: number; 12 | judgeJustice: number; 13 | judgeAttack: number; 14 | headphone: number; 15 | playerLevel: number; 16 | successTap: number; 17 | successExTap: number; 18 | successSlideHold: number; 19 | successAir: number; 20 | successFlick: number; 21 | successSkill: number; 22 | successTapTimbre: number; 23 | privacy: number; 24 | } 25 | -------------------------------------------------------------------------------- /src/chunithm/model/userGameOptionEx.ts: -------------------------------------------------------------------------------- 1 | export interface UserGameOptionExItem { 2 | ext1: number; 3 | ext2: number; 4 | ext3: number; 5 | ext4: number; 6 | ext5: number; 7 | ext6: number; 8 | ext7: number; 9 | ext8: number; 10 | ext9: number; 11 | ext10: number; 12 | ext11: number; 13 | ext12: number; 14 | ext13: number; 15 | ext14: number; 16 | ext15: number; 17 | ext16: number; 18 | ext17: number; 19 | ext18: number; 20 | ext19: number; 21 | ext20: number; 22 | } 23 | -------------------------------------------------------------------------------- /src/chunithm/model/userItem.ts: -------------------------------------------------------------------------------- 1 | export interface UserItemItem { 2 | itemKind: number; 3 | itemId: number; 4 | stock: number; 5 | isValid: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /src/chunithm/model/userMap.ts: -------------------------------------------------------------------------------- 1 | export interface UserMapItem { 2 | mapId: number; 3 | position: number; 4 | isClear: boolean; 5 | areaId: number; 6 | routeNumber: number; 7 | eventId: number; 8 | rate: number; 9 | statusCount: number; 10 | isValid: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/model/userMusic.ts: -------------------------------------------------------------------------------- 1 | export interface UserMusicDetailItem { 2 | musicId: number; 3 | level: number; 4 | playCount: number; 5 | scoreMax: number; 6 | resRequestCount: number; 7 | resAcceptCount: number; 8 | resSuccessCount: number; 9 | missCount: number; 10 | maxComboCount: number; 11 | isFullCombo: boolean; 12 | isAllJustice: boolean; 13 | isSuccess: boolean; 14 | fullChain: number; 15 | maxChain: number; 16 | scoreRank: number; 17 | isLock: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/chunithm/model/userRecentRating.ts: -------------------------------------------------------------------------------- 1 | export interface UserRecentRatingItem { 2 | musicId: number; 3 | difficultId: number; 4 | romVersionCode: number; 5 | score: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/chunithm/model/userRegion.ts: -------------------------------------------------------------------------------- 1 | export interface UserRegionItem { 2 | regionId: number; 3 | playCount: number; 4 | created: Date; 5 | } 6 | -------------------------------------------------------------------------------- /src/chunithm/proto/gameCharge.ts: -------------------------------------------------------------------------------- 1 | import { Crush, writeObject } from "./base"; 2 | import { GameChargeItem } from "../model/gameCharge"; 3 | 4 | export type GameChargeJson = Crush; 5 | 6 | export function writeGameCharge(obj: GameChargeItem): GameChargeJson { 7 | return writeObject(obj); 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/proto/gameEvent.ts: -------------------------------------------------------------------------------- 1 | import { Crush, writeObject } from "./base"; 2 | import { GameEventItem } from "../model/gameEvent"; 3 | 4 | export type GameEventJson = Crush; 5 | 6 | export function writeGameEvent(obj: GameEventItem): GameEventJson { 7 | return writeObject(obj); 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/proto/gameMessage.ts: -------------------------------------------------------------------------------- 1 | import { Crush, writeObject } from "./base"; 2 | import { GameMessageItem } from "../model/gameMessage"; 3 | 4 | export type GameMessageJson = Crush; 5 | 6 | export function writeGameMessage(obj: GameMessageItem): GameMessageJson { 7 | return writeObject(obj); 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/proto/gameRanking.ts: -------------------------------------------------------------------------------- 1 | import { Crush, writeObject } from "./base"; 2 | import { GameRankingItem } from "../model/gameRanking"; 3 | 4 | export type GameRankingJson = Crush; 5 | 6 | export function writeGameRanking(obj: GameRankingItem): GameRankingJson { 7 | return writeObject(obj); 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/proto/gameSale.ts: -------------------------------------------------------------------------------- 1 | import { Crush, writeObject } from "./base"; 2 | import { GameSaleItem } from "../model/gameSale"; 3 | 4 | export type GameSaleJson = Crush; 5 | 6 | export function writeGameSale(obj: GameSaleItem): GameSaleJson { 7 | return writeObject(obj); 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/proto/userCharacter.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readBoolean, writeObject } from "./base"; 2 | import { UserCharacterItem } from "../model/userCharacter"; 3 | 4 | export type UserCharacterJson = Crush; 5 | 6 | export function readUserCharacter(json: UserCharacterJson): UserCharacterItem { 7 | return { 8 | characterId: parseInt(json.characterId), 9 | playCount: parseInt(json.playCount), 10 | level: parseInt(json.level), 11 | skillId: parseInt(json.skillId), 12 | friendshipExp: parseInt(json.friendshipExp), 13 | isValid: readBoolean(json.isValid), 14 | isNewMark: readBoolean(json.isNewMark), 15 | param1: parseInt(json.param1), 16 | param2: parseInt(json.param2), 17 | }; 18 | } 19 | 20 | export function writeUserCharacter(obj: UserCharacterItem): UserCharacterJson { 21 | return writeObject(obj); 22 | } 23 | -------------------------------------------------------------------------------- /src/chunithm/proto/userCharge.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readDate, writeObject } from "./base"; 2 | import { UserChargeItem } from "../model/userCharge"; 3 | 4 | export type UserChargeJson = Crush; 5 | 6 | export function readUserCharge(json: UserChargeJson): UserChargeItem { 7 | return { 8 | chargeId: parseInt(json.chargeId), 9 | stock: parseInt(json.stock), 10 | purchaseDate: readDate(json.purchaseDate), 11 | validDate: readDate(json.validDate), 12 | param1: parseInt(json.param1), 13 | param2: parseInt(json.param2), 14 | paramDate: readDate(json.paramDate), 15 | }; 16 | } 17 | 18 | export function writeUserCharge(obj: UserChargeItem): UserChargeJson { 19 | return writeObject(obj); 20 | } 21 | -------------------------------------------------------------------------------- /src/chunithm/proto/userCourse.ts: -------------------------------------------------------------------------------- 1 | import { UserCourseItem } from "../model/userCourse"; 2 | import { Crush, readBoolean, readDate, writeObject } from "./base"; 3 | 4 | export type UserCourseJson = Crush; 5 | 6 | export function readUserCourse(json: UserCourseJson): UserCourseItem { 7 | return { 8 | classId: parseInt(json.classId), 9 | courseId: parseInt(json.courseId), 10 | eventId: parseInt(json.eventId), 11 | isAllJustice: readBoolean(json.isAllJustice), 12 | isClear: readBoolean(json.isClear), 13 | isFullCombo: readBoolean(json.isFullCombo), 14 | isSuccess: readBoolean(json.isSuccess), 15 | lastPlayDate: readDate(json.lastPlayDate), 16 | param1: parseInt(json.param1), 17 | param2: parseInt(json.param2), 18 | param3: parseInt(json.param3), 19 | param4: parseInt(json.param4), 20 | playCount: parseInt(json.playCount), 21 | scoreMax: parseInt(json.scoreMax), 22 | scoreRank: parseInt(json.scoreRank) 23 | } 24 | } 25 | 26 | export function writeUserCourse(obj: UserCourseItem): UserCourseJson { 27 | return writeObject(obj); 28 | } 29 | -------------------------------------------------------------------------------- /src/chunithm/proto/userDuelList.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readBoolean, readDate, writeObject } from "./base"; 2 | import { UserDuelListItem } from "../model/userDuelList"; 3 | 4 | export type UserDuelListJson = Crush; 5 | 6 | export function readUserDuelList( 7 | json: UserDuelListJson 8 | ): UserDuelListItem { 9 | return { 10 | duelId: parseInt(json.duelId), 11 | progress: parseInt(json.progress), 12 | point: parseInt(json.point), 13 | isClear: readBoolean(json.isClear), 14 | lastPlayDate: readDate(json.lastPlayDate), 15 | param1: parseInt(json.param1), 16 | param2: parseInt(json.param2), 17 | param3: parseInt(json.param3), 18 | param4: parseInt(json.param4), 19 | }; 20 | } 21 | 22 | export function writeUserDuelList( 23 | obj: UserDuelListItem 24 | ): UserDuelListJson { 25 | return writeObject(obj); 26 | } 27 | -------------------------------------------------------------------------------- /src/chunithm/proto/userItem.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readBoolean, writeObject } from "./base"; 2 | import { UserItemItem } from "../model/userItem"; 3 | 4 | export type UserItemJson = Crush; 5 | 6 | export function readUserItem(json: UserItemJson): UserItemItem { 7 | return { 8 | itemKind: parseInt(json.itemKind), 9 | itemId: parseInt(json.itemId), 10 | stock: parseInt(json.stock), 11 | isValid: readBoolean(json.isValid), 12 | }; 13 | } 14 | 15 | export function writeUserItem(obj: UserItemItem): UserItemJson { 16 | return writeObject(obj); 17 | } 18 | -------------------------------------------------------------------------------- /src/chunithm/proto/userMap.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readBoolean, writeObject } from "./base"; 2 | import { UserMapItem } from "../model/userMap"; 3 | 4 | export type UserMapJson = Crush; 5 | 6 | export function readUserMap(json: UserMapJson): UserMapItem { 7 | return { 8 | mapId: parseInt(json.mapId), 9 | position: parseInt(json.position), 10 | isClear: readBoolean(json.isClear), 11 | areaId: parseInt(json.areaId), 12 | routeNumber: parseInt(json.routeNumber), 13 | eventId: parseInt(json.eventId), 14 | rate: parseInt(json.rate), 15 | statusCount: parseInt(json.statusCount), 16 | isValid: readBoolean(json.isValid), 17 | }; 18 | } 19 | 20 | export function writeUserMap(obj: UserMapItem): UserMapJson { 21 | return writeObject(obj); 22 | } 23 | -------------------------------------------------------------------------------- /src/chunithm/proto/userRecentRating.ts: -------------------------------------------------------------------------------- 1 | import { UserPlaylogItem } from "./../model/userPlaylog"; 2 | import { Crush, writeObject } from "./base"; 3 | import { UserRecentRatingItem } from "../model/userRecentRating"; 4 | 5 | export type UserRecentRatingJson = Crush; 6 | 7 | export function readUserRecentRating( 8 | json: UserRecentRatingJson 9 | ): UserRecentRatingItem { 10 | return { 11 | musicId: parseInt(json.musicId), 12 | difficultId: parseInt(json.difficultId), 13 | romVersionCode: parseInt(json.romVersionCode), 14 | score: parseInt(json.score), 15 | }; 16 | } 17 | 18 | export function writeUserRecentRating( 19 | obj: UserRecentRatingItem 20 | ): UserRecentRatingJson { 21 | return writeObject(obj); 22 | } 23 | -------------------------------------------------------------------------------- /src/chunithm/proto/userRegion.ts: -------------------------------------------------------------------------------- 1 | import { Crush, readDate, writeObject } from "./base"; 2 | import { UserRegionItem } from "../model/userRegion"; 3 | 4 | export type UserRegionJson = Crush; 5 | 6 | export function readUserRegion(json: UserRegionJson): UserRegionItem { 7 | return { 8 | regionId: parseInt(json.regionId), 9 | playCount: parseInt(json.playCount), 10 | created: readDate(json.created), 11 | }; 12 | } 13 | 14 | export function writeUserRegion(obj: UserRegionItem): UserRegionJson { 15 | return writeObject(obj); 16 | } 17 | -------------------------------------------------------------------------------- /src/chunithm/repo/_defs.ts: -------------------------------------------------------------------------------- 1 | import { UserDataItem } from "../model/userData"; 2 | import { Id } from "../../model"; 3 | 4 | export interface Page { 5 | offset: number; 6 | limit: number; 7 | } 8 | 9 | export interface Repository { 10 | save(profileId: Id, obj: T): Promise; 11 | } 12 | 13 | export interface Repository1 extends Repository { 14 | load(profileId: Id): Promise; 15 | } 16 | 17 | export interface RepositoryN extends Repository { 18 | load(profileId: Id, page?: Page): Promise; 19 | } 20 | -------------------------------------------------------------------------------- /src/chunithm/repo/userActivity.ts: -------------------------------------------------------------------------------- 1 | import { UserActivityItem } from "../model/userActivity"; 2 | import { UserDataItem } from "../model/userData"; 3 | import { Id } from "../../model"; 4 | 5 | export interface UserActivityRepository { 6 | load(profileId: Id, kind: number): Promise; 7 | 8 | save(profileId: Id, obj: UserActivityItem): Promise; 9 | } 10 | -------------------------------------------------------------------------------- /src/chunithm/repo/userCharacter.ts: -------------------------------------------------------------------------------- 1 | import { RepositoryN } from "./_defs"; 2 | import { UserCharacterItem } from "../model/userCharacter"; 3 | import { UserDataItem } from "../model/userData"; 4 | import { Id } from "../../model"; 5 | 6 | export interface UserCharacterRepository 7 | extends RepositoryN { 8 | loadOne( 9 | profileId: Id, 10 | characterId: number 11 | ): Promise; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/repo/userCharge.ts: -------------------------------------------------------------------------------- 1 | import { UserChargeItem } from "../model/userCharge"; 2 | import { RepositoryN } from "./_defs"; 3 | 4 | export type UserChargeRepository = RepositoryN; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userCourse.ts: -------------------------------------------------------------------------------- 1 | import { UserCourseItem } from "../model/userCourse"; 2 | import { RepositoryN } from "./_defs"; 3 | 4 | export type UserCourseRepository = RepositoryN; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userData.ts: -------------------------------------------------------------------------------- 1 | import { UserDataItem } from "../model/userData"; 2 | import { AimeId, Id } from "../../model"; 3 | 4 | export interface UserDataRepository { 5 | load(profileId: Id): Promise; 6 | 7 | lookup(aimeId: AimeId): Promise>; 8 | 9 | save(aimeId: AimeId, obj: UserDataItem): Promise>; 10 | 11 | tryLookup(aimeId: AimeId): Promise | undefined>; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/repo/userDataEx.ts: -------------------------------------------------------------------------------- 1 | import { Repository1 } from "./_defs"; 2 | import { UserDataExItem } from "../model/userDataEx"; 3 | 4 | export type UserDataExRepository = Repository1; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userDuelList.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "./_defs"; 2 | import { UserDataItem } from "../model/userData"; 3 | import { UserDuelListItem } from "../model/userDuelList"; 4 | import { Id } from "../../model"; 5 | 6 | export interface UserDuelListRepository { 7 | load( 8 | profileId: Id, 9 | duelId?: number, 10 | ): Promise; 11 | 12 | save(profileId: Id, obj: UserDuelListItem): Promise; 13 | } 14 | -------------------------------------------------------------------------------- /src/chunithm/repo/userGameOption.ts: -------------------------------------------------------------------------------- 1 | import { Repository1 } from "./_defs"; 2 | import { UserGameOptionItem } from "../model/userGameOption"; 3 | 4 | export type UserGameOptionRepository = Repository1; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userGameOptionEx.ts: -------------------------------------------------------------------------------- 1 | import { Repository1 } from "./_defs"; 2 | import { UserGameOptionExItem } from "../model/userGameOptionEx"; 3 | 4 | export type UserGameOptionExRepository = Repository1; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userItem.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "./_defs"; 2 | import { UserDataItem } from "../model/userData"; 3 | import { UserItemItem } from "../model/userItem"; 4 | import { Id } from "../../model"; 5 | 6 | export interface UserItemRepository { 7 | load( 8 | profileId: Id, 9 | itemKind: number, 10 | page: Page 11 | ): Promise; 12 | 13 | save(profileId: Id, obj: UserItemItem): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/repo/userMap.ts: -------------------------------------------------------------------------------- 1 | import { RepositoryN } from "./_defs"; 2 | import { UserMapItem } from "../model/userMap"; 3 | 4 | export type UserMapRepository = RepositoryN; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userMusic.ts: -------------------------------------------------------------------------------- 1 | import { RepositoryN } from "./_defs"; 2 | import { UserMusicDetailItem } from "../model/userMusic"; 3 | 4 | export type UserMusicRepository = RepositoryN; 5 | -------------------------------------------------------------------------------- /src/chunithm/repo/userPlaylog.ts: -------------------------------------------------------------------------------- 1 | import { UserDataItem } from "../model/userData"; 2 | import { UserPlaylogItem } from "../model/userPlaylog"; 3 | import { Id } from "../../model"; 4 | 5 | export interface UserPlaylogRepository { 6 | // This seems to only be used internally by SEGA for analytics, but the data 7 | // is nice to have. 8 | 9 | save(profileId: Id, obj: UserPlaylogItem): Promise; 10 | loadLatest(profileId: Id, size: number): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/repo/userRecentRating.ts: -------------------------------------------------------------------------------- 1 | import { UserDataItem } from "../model/userData"; 2 | import { UserRecentRatingItem } from "../model/userRecentRating"; 3 | import { Id } from "../../model"; 4 | 5 | export interface UserRecentRatingRepository { 6 | load(profileId: Id): Promise; 7 | 8 | save( 9 | profileId: Id, 10 | objs: UserRecentRatingItem[] 11 | ): Promise; 12 | } 13 | -------------------------------------------------------------------------------- /src/chunithm/request/gameLogin.ts: -------------------------------------------------------------------------------- 1 | export interface GameLoginRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/gameLogout.ts: -------------------------------------------------------------------------------- 1 | export interface GameLogoutRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameCharge.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameChargeRequest { 2 | /** Boolean */ 3 | isAllSale: "string"; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameEvent.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameEventRequest { 2 | // FIXME 3 | type: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameIdlist.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameIdlistRequest { 2 | /** Integer */ 3 | type: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameMessage.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameMessageRequest { 2 | /** Integer */ 3 | type: string; 4 | 5 | /** Boolean */ 6 | isAllMessage: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameRanking.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameRankingRequest { 2 | /** Long */ 3 | type: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameSale.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameSaleRequest { 2 | /** Integer */ 3 | type: string; 4 | 5 | /** Boolean */ 6 | isAllSale: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getGameSetting.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameSettingRequest { 2 | /** Base-10 ALLNet location ID */ 3 | placeId: string; 4 | 5 | /** Keychip ID */ 6 | clientId: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserActivity.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserActivityRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer, filter on `UserActivityItem.kind`. */ 6 | kind: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserCharacter.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserCharacterRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer, pagination cookie. Initially zero. */ 6 | nextIndex: string; 7 | 8 | /** Integer, max page size. Taken from GetGameSettingResponse. */ 9 | maxCount: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserCharge.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserChargeRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserCourse.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserCourseRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer, pagination cookie. Initially zero. */ 6 | nextIndex: string; 7 | 8 | /** 9 | * Integer, max page size. NOT configured from GetGameSetting as of 1.30.00, 10 | * but instead hardcoded to 50. Still, don't assume that will always be the 11 | * case. 12 | */ 13 | maxCount: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserData.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserDataRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserDataEx.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserDataExRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Boolean */ 6 | isAdmin: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserDuel.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserDuelRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer */ 6 | duelId: string; 7 | 8 | /** Boolean */ 9 | isAllDuel: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserFavoriteMusic.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserFavoriteMusicRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserItem.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserItemRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** 6 | * Long. 7 | * 8 | * This is an odd amalgam of what ought to be two separate `kind` and 9 | * `nextIndex` parameters. Divide by 10 billion to separate them out. 10 | * The quotient is the `kind` that the client wants you to return, the 11 | * remainder is the effective `nextIndex` pagination cookie which comes into 12 | * play if more than `maxCount` items of this type are available. Presumably 13 | * returning a result set of size `maxCount` will cause another request to 14 | * be issued in order to retrieve the next page. See response documentation 15 | * for further details. 16 | * 17 | * @see GetUserItemResponse 18 | */ 19 | nextIndex: string; 20 | 21 | /** Integer, max page size. Taken from GetGameSettingResponse. */ 22 | maxCount: string; 23 | } 24 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserMap.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserMapRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Boolean */ 6 | isAllMap: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserMusic.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserMusicRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer, pagination cookie. Initially zero. */ 6 | nextIndex: string; 7 | 8 | /** Integer, max page size. Taken from GetGameSettingResponse. */ 9 | maxCount: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserOption.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserOptionRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserOptionEx.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserOptionExRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Boolean */ 6 | isAdmin: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserPreview.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserPreviewRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | segaIdAuthKey: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserRecentRating.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserRecentRatingRequest { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/request/getUserRegion.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserRegionRequest { 2 | // FIXME 3 | 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertClientBookkeeping.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientBookkeepingRequest { 2 | // FIXME 3 | } 4 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertClientDevelop.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientDevelopRequest { 2 | // FIXME 3 | } 4 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertClientError.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientErrorRequest { 2 | // FIXME 3 | } 4 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertClientSetting.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientSettingRequest { 2 | clientSetting: { 3 | /* Base-10 ALLNet location ID */ 4 | placeId: string; 5 | 6 | /** Keychip ID */ 7 | clientId: string; 8 | 9 | /** ALLNet place name */ 10 | placeName: string; 11 | 12 | /** ALLNet "region0" */ 13 | regionId: string; 14 | 15 | /** ALLNet "region_name0" */ 16 | regionName: string; 17 | 18 | /** ALLNet "allnet_id" string */ 19 | allNetId: string; 20 | 21 | /** sic. AMEX DS EEPROM ID */ 22 | bordId: string; 23 | 24 | /** Data version of the form "1.30.00" */ 25 | romVersion: string; 26 | 27 | /** Data version of the form "1.30.00" */ 28 | dataVersion: string; 29 | 30 | /** Integer */ 31 | dumpFileNum: string; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertClientTestmode.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientTestmodeRequest { 2 | clientTestmode: { 3 | /* Base-10 ALLNet location ID */ 4 | placeId: string; 5 | 6 | /** Keychip ID */ 7 | clientId: string; 8 | 9 | /** Date "YYYY-MM-DD hh:mm:ss" */ 10 | updateDate: string; 11 | 12 | /** Boolean */ 13 | isDelivery: string; 14 | 15 | /** Integer */ 16 | groupId: string; 17 | 18 | /** Integer */ 19 | groupRole: string; 20 | 21 | /** Integer */ 22 | continueMode: string; 23 | 24 | /** Integer */ 25 | selectMusicTime: string; 26 | 27 | /** Integer */ 28 | advertiseVolume: string; 29 | 30 | /** Integer */ 31 | eventMode: string; 32 | 33 | /** Integer */ 34 | eventMusicNum: string; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/chunithm/request/upsertUserChargelogApi.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertUserChargelogApiRequest { 2 | userId: string; 3 | 4 | userChargelog: { 5 | chargeId: string, 6 | price: string, 7 | purchaseDate: Date, 8 | playCount: string, 9 | playerRating: string, 10 | placeId: string, 11 | regionId: string, 12 | clientId: string 13 | }; 14 | 15 | userCharge: { 16 | chargeId: string, 17 | stock: string, 18 | purchaseDate: Date, 19 | validDate: Date, 20 | param1: string, 21 | param2: string, 22 | paramDate: Date 23 | }; 24 | } -------------------------------------------------------------------------------- /src/chunithm/response/gameLogin.ts: -------------------------------------------------------------------------------- 1 | export interface GameLoginResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/gameLogout.ts: -------------------------------------------------------------------------------- 1 | export interface GameLogoutResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameCharge.ts: -------------------------------------------------------------------------------- 1 | import { GameChargeJson } from "../proto/gameCharge"; 2 | 3 | export interface GetGameChargeResponse { 4 | /** Integer */ 5 | length: string; 6 | 7 | /** TBD */ 8 | gameChargeList: GameChargeJson[]; 9 | } 10 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameEvent.ts: -------------------------------------------------------------------------------- 1 | import { GameEventJson } from "../proto/gameEvent"; 2 | 3 | export interface GetGameEventResponse { 4 | /** Integer */ 5 | type: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | gameEventList: GameEventJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameIdlist.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameIdlistResponse { 2 | /** Integer */ 3 | type: string; 4 | 5 | /** Integer */ 6 | length: string; 7 | 8 | /** Format TBD */ 9 | gameIdlistList: []; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameMessage.ts: -------------------------------------------------------------------------------- 1 | import { GameMessageJson } from "../proto/gameMessage"; 2 | 3 | export interface GetGameMessageResponse { 4 | /** Integer */ 5 | type: string; 6 | 7 | /** Integer */ 8 | length: string; 9 | 10 | gameMessageList: GameMessageJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameRanking.ts: -------------------------------------------------------------------------------- 1 | import { GameRankingJson } from "../proto/gameRanking"; 2 | 3 | export interface GetGameRankingResponse { 4 | /** Long */ 5 | type: string; 6 | 7 | // No length parameter..? 8 | 9 | gameRankingList: GameRankingJson[]; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameSale.ts: -------------------------------------------------------------------------------- 1 | import { GameSaleJson } from "../proto/gameSale"; 2 | 3 | export interface GetGameSaleResponse { 4 | /** Integer */ 5 | type: string; 6 | 7 | /** Integer */ 8 | length: string; 9 | 10 | gameSaleList: GameSaleJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getGameSetting.ts: -------------------------------------------------------------------------------- 1 | export interface GetGameSettingResponse { 2 | gameSetting: { 3 | /** ROM version string e.g. "1.30.00" */ 4 | dataVersion: string; 5 | 6 | isMaintenance: string; 7 | 8 | requestInterval: string; 9 | 10 | rebootStartTime: string; 11 | 12 | rebootEndTime: string; 13 | 14 | /** Boolean */ 15 | isBackgroundDistribute: string; 16 | 17 | /** Integer, pagination granularity for GetUserCharacter */ 18 | maxCountCharacter: string; 19 | 20 | /** Integer, pagination granularity for GetUserJson */ 21 | maxCountItem: string; 22 | 23 | /** Integer, pagination granularity for GetUserMusic */ 24 | maxCountMusic: string; 25 | }; 26 | 27 | /** Boolean */ 28 | isDumpUpload: string; 29 | 30 | /** Boolean */ 31 | isAou: string; 32 | } 33 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserActivity.ts: -------------------------------------------------------------------------------- 1 | import { UserActivityJson } from "../proto/userActivity"; 2 | 3 | export interface GetUserActivityResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | /** Integer, round-trip from request */ 11 | kind: string; 12 | 13 | userActivityList: UserActivityJson[]; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserCharacter.ts: -------------------------------------------------------------------------------- 1 | import { UserCharacterJson } from "../proto/userCharacter"; 2 | 3 | export interface GetUserCharacterResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | /** 11 | * Integer, pagination cookie. Sent back in next request if 12 | * `length === maxCount`. 13 | */ 14 | nextIndex: string; 15 | 16 | userCharacterList: UserCharacterJson[]; 17 | } 18 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserCharge.ts: -------------------------------------------------------------------------------- 1 | import { UserChargeJson } from "../proto/userCharge"; 2 | 3 | export interface GetUserChargeResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | userChargeList: UserChargeJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserCourse.ts: -------------------------------------------------------------------------------- 1 | import { UserCourseJson } from "../proto/userCourse"; 2 | 3 | export interface GetUserCourseResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | /** Integer, pagination cookie */ 11 | nextIndex: string; 12 | 13 | userCourseList: UserCourseJson[]; 14 | } 15 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserData.ts: -------------------------------------------------------------------------------- 1 | import { UserDataJson } from "../proto/userData"; 2 | 3 | export interface GetUserDataResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | userData: UserDataJson; 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserDataEx.ts: -------------------------------------------------------------------------------- 1 | import { UserDataExJson } from "../proto/userDataEx"; 2 | 3 | export interface GetUserDataExResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | userDataEx: UserDataExJson; 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserDuel.ts: -------------------------------------------------------------------------------- 1 | import { UserDuelListJson } from "../proto/userDuelList"; 2 | 3 | export interface GetUserDuelResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | /** 11 | * List of duel entities, either all duel entities associated with `userId` 12 | * or single requested by `duelId` in request. 13 | */ 14 | userDuelList: UserDuelListJson[]; 15 | } 16 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserFavoriteMusic.ts: -------------------------------------------------------------------------------- 1 | export interface GetUserFavoriteMusicResponse { 2 | /** Integer, AiMe ID */ 3 | userId: string; 4 | 5 | /** Integer, number of results returned */ 6 | length: string; 7 | 8 | /** TBD */ 9 | userFavoriteMusicList: []; 10 | } 11 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserMap.ts: -------------------------------------------------------------------------------- 1 | import { UserMapJson } from "../proto/userMap"; 2 | 3 | export interface GetUserMapResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | userMapList: UserMapJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserMusic.ts: -------------------------------------------------------------------------------- 1 | import { UserMusicJson } from "../proto/userMusic"; 2 | 3 | export interface GetUserMusicResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** 8 | * Integer, number of top-level `UserMusicJson` objects returned (each of 9 | * which will, in turn, contain one or more "detail" objects). 10 | */ 11 | length: string; 12 | 13 | /** Integer, pagination cookie */ 14 | nextIndex: string; 15 | 16 | /** 17 | * List of `UserMusicDetailJson` objects grouped by `musicId` into 18 | * `UserMusicJson` objects. 19 | **/ 20 | userMusicList: UserMusicJson[]; 21 | } 22 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserOption.ts: -------------------------------------------------------------------------------- 1 | import { UserGameOptionJson } from "../proto/userGameOption"; 2 | 3 | export interface GetUserOptionResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | userGameOption: UserGameOptionJson; 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserOptionEx.ts: -------------------------------------------------------------------------------- 1 | import { UserGameOptionExJson } from "../proto/userGameOptionEx"; 2 | 3 | export interface GetUserOptionExResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | userGameOptionEx: UserGameOptionExJson; 8 | } 9 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserRecentRating.ts: -------------------------------------------------------------------------------- 1 | import { UserRecentRatingJson } from "../proto/userRecentRating"; 2 | 3 | export interface GetUserRecentRatingResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | userRecentRatingList: UserRecentRatingJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/getUserRegion.ts: -------------------------------------------------------------------------------- 1 | import { UserRegionJson } from "../proto/userRegion"; 2 | 3 | export interface GetUserRegionResponse { 4 | /** Integer, AiMe ID */ 5 | userId: string; 6 | 7 | /** Integer, number of results returned */ 8 | length: string; 9 | 10 | userRegionList: UserRegionJson[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertClientBookkeeping.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientBookkeepingResponse { 2 | returnCode: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertClientDevelop.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientDevelopResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertClientError.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientErrorResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertClientSetting.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientSettingResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertClientTestmode.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertClientTestmodeResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertUserAll.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertUserAllResponse { 2 | /** Integer */ 3 | returnCode: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/chunithm/response/upsertUserChargelogApi.ts: -------------------------------------------------------------------------------- 1 | export interface UpsertUserChargelogApiResponse { 2 | returnCode: string; 3 | } -------------------------------------------------------------------------------- /src/chunithm/rpc.ts: -------------------------------------------------------------------------------- 1 | import { RequestHandler } from "express"; 2 | 3 | import { Repositories } from "./repo"; 4 | 5 | /** 6 | * An async function that is supplied with an implementation of the 7 | * `Repositories` instance and uses it to transform a JSON request into a 8 | * JSON response. 9 | */ 10 | export type RpcHandler = (rep: Repositories, reqObj: Q) => Promise; 11 | 12 | /** 13 | * This describes a piece of router-like Express middleware that provides the 14 | * connective tissue between an HTTP request scope and the life cycle of an 15 | * implementation of the `Repositories` persistent data storage interface. Call 16 | * `rpc()` to declare async JSON RPC handlers, then once that's fully prepared 17 | * you can pass the implementation of this type to Express. 18 | */ 19 | export type RpcWrapper = RequestHandler & { 20 | rpc: (path: string, handler: RpcHandler) => RpcWrapper; 21 | }; 22 | -------------------------------------------------------------------------------- /src/chunithm/static/charge.ts: -------------------------------------------------------------------------------- 1 | export const CHARGE_IDS = Object.freeze([ 2 | { 3 | id: 2310, //World's End ticket x5 4 | price: 1, 5 | salePrice: 1, 6 | }, 7 | { 8 | id: 2060, //4x bonus ticket 9 | price: 1, 10 | salePrice: 1, 11 | }, 12 | { 13 | id: 2230, //6 songs premium ticket 14 | price: 2, 15 | salePrice: 2, 16 | }, 17 | ]); -------------------------------------------------------------------------------- /src/diva/gameInit.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | 3 | export default function gameInit(req: Request, res: Response) { 4 | const { cmd, req_id } = req.body; 5 | 6 | res.send({ 7 | cmd, 8 | req_id, 9 | stat: 1, 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/common/bigint.ts: -------------------------------------------------------------------------------- 1 | export function readBigInt(buf: Buffer) { 2 | let result = 0n; 3 | 4 | for (let i = 0; i < buf.length; i++) { 5 | const shift = 8n * BigInt(i); 6 | const byte = buf.readUInt8(i); 7 | 8 | result |= BigInt(byte) << shift; 9 | } 10 | 11 | return result; 12 | } 13 | 14 | export function writeBigInt(n: bigint, length: number) { 15 | const result = Buffer.alloc(length); 16 | 17 | for (let i = 0; i < length; i++) { 18 | const shift = 8n * BigInt(i); 19 | const byte = (n >> shift) & 0xffn; 20 | 21 | result[i] = Number(byte); 22 | } 23 | 24 | return result; 25 | } 26 | 27 | // i pick the one implementation language that doesn't have this built in 28 | 29 | export function modPow(b: bigint, e: bigint, m: bigint) { 30 | // https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method 31 | 32 | let result = 1n; 33 | 34 | b = b % m; 35 | 36 | while (e > 0n) { 37 | if ((e & 1n) === 1n) { 38 | result = (result * b) % m; 39 | } 40 | 41 | e = e >> 1n; 42 | b = (b * b) % m; 43 | } 44 | 45 | return result; 46 | } 47 | -------------------------------------------------------------------------------- /src/idz/common/index.ts: -------------------------------------------------------------------------------- 1 | import setup from "./setup"; 2 | 3 | export { BLOCK_SIZE } from "./aes"; 4 | export { ClientHello } from "./setup"; 5 | export default setup; 6 | -------------------------------------------------------------------------------- /src/idz/ping.ts: -------------------------------------------------------------------------------- 1 | import logger from "debug"; 2 | import { createSocket } from "dgram"; 3 | 4 | const debug = logger("app:idz:ping"); 5 | 6 | export default function createPing(port: number, host: string) { 7 | const socket = createSocket("udp4"); 8 | 9 | socket.bind(port, host); 10 | socket.on("message", (msg, rinfo) => { 11 | debug("Ping from %s:%s", rinfo.address, rinfo.port); 12 | socket.send(msg, rinfo.port, rinfo.address); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/_bitmap.ts: -------------------------------------------------------------------------------- 1 | export function bitmap(buf: Buffer): Set { 2 | const result = new Set(); 3 | 4 | for (let byteNo = 0; byteNo < buf.length; byteNo++) { 5 | const byte = buf.readUInt8(byteNo); 6 | 7 | for (let bitNo = 0; bitNo < 8; bitNo++) { 8 | if (byte & (1 << bitNo)) { 9 | result.add((8 * byteNo + bitNo) as T); 10 | } 11 | } 12 | } 13 | 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/_car.ts: -------------------------------------------------------------------------------- 1 | import { Car, CarSelector } from "../model/car"; 2 | 3 | export function car(buf: Buffer): Car { 4 | const field_04: number[] = []; 5 | 6 | for (let i = 0; i < 32; i++) { 7 | field_04.push(buf.readUInt16LE(0x0004 + 2 * i)); 8 | } 9 | 10 | return { 11 | field_00: buf.readUInt16LE(0x0000), 12 | field_02: buf.readUInt16LE(0x0002), 13 | field_04, 14 | selector: buf.readUInt16LE(0x0044) as CarSelector, 15 | field_46: buf.readUInt16LE(0x0046), 16 | field_48: buf.readUInt16LE(0x0048), 17 | field_4a: buf.readUInt16LE(0x004a), 18 | field_4c: buf.readUInt32LE(0x004c), 19 | field_50_lo: buf.readUInt32LE(0x0050), 20 | field_50_hi: buf.readUInt32LE(0x0054), 21 | field_58: buf.readUInt16LE(0x0058), 22 | field_5a: buf.readUInt8(0x005a), 23 | field_5b: buf.readUInt8(0x005b), 24 | field_5c: buf.readUInt16LE(0x005c), 25 | field_5e: buf.readUInt16LE(0x005e), 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/_chara.ts: -------------------------------------------------------------------------------- 1 | import { BackgroundCode, TitleCode } from "../model/base"; 2 | import { Chara } from "../model/chara"; 3 | 4 | export function chara(buf: Buffer): Chara { 5 | return { 6 | gender: buf.readUInt16LE(0x00) === 0 ? "male" : "female", 7 | field_02: buf.readUInt16LE(0x02), 8 | field_04: buf.readUInt16LE(0x04), 9 | field_06: buf.readUInt16LE(0x06), 10 | field_08: buf.readUInt16LE(0x08), 11 | field_0a: buf.readUInt16LE(0x0a), 12 | field_0c: buf.readUInt16LE(0x0c), 13 | field_0e: buf.readUInt16LE(0x0e), 14 | title: buf.readUInt16LE(0x10) as TitleCode, // Swapped on load 15 | background: buf.readUInt16LE(0x12) as BackgroundCode, // Swapped on load 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/_mission.ts: -------------------------------------------------------------------------------- 1 | import { MissionGrid } from "../model/mission"; 2 | 3 | export function mission(buf: Buffer): MissionGrid[] { 4 | const grids = new Array(); 5 | 6 | for (let gridNo = 0; gridNo < 5; gridNo++) { 7 | const grid: MissionGrid = { cells: [] }; 8 | 9 | for (let cellNo = 0; cellNo < 9; cellNo++) { 10 | let cell = 0; 11 | let mask = 1 << cellNo; 12 | 13 | for (let sliceNo = 0; sliceNo < 3; sliceNo++) { 14 | const slice = buf.readUInt16LE(0x0c * sliceNo + 0x02 * gridNo); 15 | 16 | if (slice & mask) { 17 | cell |= 1 << sliceNo; 18 | } 19 | } 20 | 21 | grid.cells.push(cell); 22 | } 23 | 24 | grids.push(grid); 25 | } 26 | 27 | return grids; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/checkTeamName.ts: -------------------------------------------------------------------------------- 1 | import { CheckTeamNameRequest } from "../request/checkTeamName"; 2 | 3 | checkTeamName1.msgCode = 0x00a2; 4 | checkTeamName1.msgLen = 0x0040; 5 | 6 | export function checkTeamName1(buf: Buffer): CheckTeamNameRequest { 7 | return { type: "check_team_name_req" }; 8 | } 9 | 10 | checkTeamName2.msgCode = 0x0097; 11 | checkTeamName2.msgLen = 0x0040; 12 | 13 | export function checkTeamName2(buf: Buffer): CheckTeamNameRequest { 14 | return { type: "check_team_name_req" }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/createAutoTeam.ts: -------------------------------------------------------------------------------- 1 | import { CreateAutoTeamRequest } from "../request/createAutoTeam"; 2 | import { AimeId } from "../../../model"; 3 | 4 | createAutoTeam1.msgCode = 0x007b; 5 | createAutoTeam1.msgLen = 0x0010; 6 | 7 | export function createAutoTeam1(buf: Buffer): CreateAutoTeamRequest { 8 | return { 9 | type: "create_auto_team_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | version: 1, 12 | field_0008: buf.readUInt32LE(0x0008), 13 | field_000C: buf.readUInt8(0x000c), 14 | }; 15 | } 16 | 17 | createAutoTeam2.msgCode = 0x0077; 18 | createAutoTeam2.msgLen = 0x0010; 19 | 20 | export function createAutoTeam2(buf: Buffer): CreateAutoTeamRequest { 21 | return { 22 | type: "create_auto_team_req", 23 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 24 | version: 2, 25 | field_0008: buf.readUInt32LE(0x0008), 26 | field_000C: buf.readUInt8(0x000c), 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/discoverProfile.ts: -------------------------------------------------------------------------------- 1 | import { DiscoverProfileRequest } from "../request/discoverProfile"; 2 | import { AimeId } from "../../../model"; 3 | 4 | discoverProfile1.msgCode = 0x006b; 5 | discoverProfile1.msgLen = 0x0010; 6 | 7 | export function discoverProfile1(buf: Buffer): DiscoverProfileRequest { 8 | return { 9 | type: "discover_profile_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | version: 1, 12 | }; 13 | } 14 | 15 | discoverProfile2.msgCode = 0x0067; 16 | discoverProfile2.msgLen = 0x0010; 17 | 18 | export function discoverProfile2(buf: Buffer): DiscoverProfileRequest { 19 | return { 20 | type: "discover_profile_req", 21 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 22 | version: 2, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadConfig.ts: -------------------------------------------------------------------------------- 1 | import { LoadConfigRequestA, LoadConfigRequestB } from "../request/loadConfig"; 2 | 3 | loadConfigA_1.msgCode = 0x0004; 4 | loadConfigA_1.msgLen = 0x0050; 5 | 6 | export function loadConfigA_1(): LoadConfigRequestA { 7 | return { type: "load_config_A_req" }; 8 | } 9 | 10 | loadConfigB_1.msgCode = 0x00ab; 11 | loadConfigB_1.msgLen = 0x0010; 12 | 13 | export function loadConfigB_1(): LoadConfigRequestB { 14 | return { type: "load_config_B_req" }; 15 | } 16 | 17 | loadConfigA_2.msgCode = 0x0004; 18 | loadConfigA_2.msgLen = 0x0050; 19 | 20 | export function loadConfigA_2(): LoadConfigRequestA { 21 | return { type: "load_config_A_req" }; 22 | } 23 | 24 | loadConfigB_2.msgCode = 0x00a0; 25 | loadConfigB_2.msgLen = 0x0010; 26 | 27 | export function loadConfigB_2(): LoadConfigRequestB { 28 | return { type: "load_config_B_req" }; 29 | } 30 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadEventInfo.ts: -------------------------------------------------------------------------------- 1 | import { LoadEventInfoRequest } from "../request/loadEventInfo"; 2 | import { AimeId } from "../../../model"; 3 | 4 | loadEventInfo1.msgCode = 0x00be; 5 | loadEventInfo1.msgLen = 0x0010; 6 | 7 | export function loadEventInfo1(buf: Buffer): LoadEventInfoRequest { 8 | return { 9 | type: "load_event_info_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | }; 12 | } 13 | 14 | loadEventInfo2.msgCode = 0x00ac; 15 | loadEventInfo2.msgLen = 0x0010; 16 | 17 | export function loadEventInfo2(buf: Buffer): LoadEventInfoRequest { 18 | return { 19 | type: "load_event_info_req", 20 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadGacha.ts: -------------------------------------------------------------------------------- 1 | import { LoadGachaRequest } from "../request/loadGacha"; 2 | import { AimeId } from "../../../model"; 3 | 4 | loadGacha1.msgCode = 0x00c1; 5 | loadGacha1.msgLen = 0x0010; 6 | 7 | export function loadGacha1(buf: Buffer): LoadGachaRequest { 8 | return { 9 | type: "load_gacha_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | }; 12 | } 13 | 14 | loadGacha2.msgCode = 0x00af; 15 | loadGacha2.msgLen = 0x0010; 16 | 17 | export function loadGacha2(buf: Buffer): LoadGachaRequest { 18 | return { 19 | type: "load_gacha_req", 20 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadGarage.ts: -------------------------------------------------------------------------------- 1 | import { LoadGarageRequest } from "../request/loadGarage"; 2 | import { AimeId } from "../../../model"; 3 | 4 | loadGarage1.msgCode = 0x0090; 5 | loadGarage1.msgLen = 0x0010; 6 | 7 | export function loadGarage1(buf: Buffer): LoadGarageRequest { 8 | return { 9 | type: "load_garage_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | version: 1, 12 | fetchOffset: buf.readUInt8(0x0008), 13 | field_000A: buf.readUInt16LE(0x000a), 14 | }; 15 | } 16 | 17 | loadGarage2.msgCode = 0x0087; 18 | loadGarage2.msgLen = 0x0010; 19 | 20 | export function loadGarage2(buf: Buffer): LoadGarageRequest { 21 | return { 22 | type: "load_garage_req", 23 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 24 | version: 2, 25 | fetchOffset: buf.readUInt8(0x0008), 26 | field_000A: buf.readUInt16LE(0x000a), 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadGeneralReward.ts: -------------------------------------------------------------------------------- 1 | import { LoadGeneralRewardRequest } from "../request/loadGeneralReward"; 2 | import { AimeId } from "../../../model"; 3 | 4 | loadGeneralReward1.msgCode = 0x009c; 5 | loadGeneralReward1.msgLen = 0x0010; 6 | 7 | export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest { 8 | return { 9 | type: "load_general_reward_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | }; 12 | } 13 | 14 | loadGeneralReward2.msgCode = 0x093b; 15 | loadGeneralReward2.msgLen = 0x0010; 16 | 17 | export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest { 18 | return { 19 | type: "load_general_reward_req", 20 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 21 | }; 22 | } 23 | 24 | loadGeneralReward3.msgCode = 0x013b; 25 | loadGeneralReward3.msgLen = 0x0010; 26 | 27 | export function loadGeneralReward3(buf: Buffer): LoadGeneralRewardRequest { 28 | return { 29 | type: "load_general_reward_req", 30 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadGhost.ts: -------------------------------------------------------------------------------- 1 | import { LoadGhostRequest } from "../request/loadGhost"; 2 | 3 | loadGhost1.msgCode = 0x00a0; 4 | loadGhost1.msgLen = 0x0010; 5 | 6 | export function loadGhost1(buf: Buffer): LoadGhostRequest { 7 | return { 8 | type: "load_ghost_req", 9 | field_0002: buf.readUInt16LE(0x0002), 10 | field_0004: buf.readUInt16LE(0x0004), 11 | field_0008: buf.readUInt32LE(0x0008), 12 | field_000C: buf.readUInt16LE(0x000c), 13 | field_000E: buf.readUInt16LE(0x000e), 14 | }; 15 | } 16 | 17 | loadGhost2.msgCode = 0x0095; 18 | loadGhost2.msgLen = 0x0010; 19 | 20 | export function loadGhost2(buf: Buffer): LoadGhostRequest { 21 | return { 22 | type: "load_ghost_req", 23 | field_0002: buf.readUInt16LE(0x0002), 24 | field_0004: buf.readUInt16LE(0x0004), 25 | field_0008: buf.readUInt32LE(0x0008), 26 | field_000C: buf.readUInt16LE(0x000c), 27 | field_000E: buf.readUInt16LE(0x000e), 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadProfile.ts: -------------------------------------------------------------------------------- 1 | import { LoadProfileRequest } from "../request/loadProfile"; 2 | import { AimeId } from "../../../model"; 3 | import { readAsciiStr } from "../../util/bin"; 4 | 5 | loadProfile2.msgCode = 0x0067; 6 | loadProfile2.msgLen = 0x0020; 7 | 8 | export function loadProfile2(buf: Buffer): LoadProfileRequest { 9 | return { 10 | type: "load_profile_req", 11 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 12 | version: 1, 13 | luid: readAsciiStr(buf, 0x0008, 0x0020), 14 | }; 15 | } 16 | 17 | loadProfile3.msgCode = 0x012f; 18 | loadProfile3.msgLen = 0x0020; 19 | 20 | export function loadProfile3(buf: Buffer): LoadProfileRequest { 21 | return { 22 | type: "load_profile_req", 23 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 24 | version: 1, 25 | luid: readAsciiStr(buf, 0x0008, 0x0020), 26 | }; 27 | } 28 | 29 | loadProfile4.msgCode = 0x012f; 30 | loadProfile4.msgLen = 0x0020; 31 | 32 | export function loadProfile4(buf: Buffer): LoadProfileRequest { 33 | return { 34 | type: "load_profile_req", 35 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 36 | version: 2, 37 | luid: readAsciiStr(buf, 0x0008, 0x0020), 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadRewardTable.ts: -------------------------------------------------------------------------------- 1 | import { LoadRewardTableRequest } from "../request/loadRewardTable"; 2 | 3 | loadRewardTable1.msgCode = 0x0086; 4 | loadRewardTable1.msgLen = 0x0010; 5 | 6 | export function loadRewardTable1(): LoadRewardTableRequest { 7 | return { 8 | type: "load_reward_table_req", 9 | }; 10 | } 11 | 12 | loadRewardTable2.msgCode = 0x007f; 13 | loadRewardTable2.msgLen = 0x0010; 14 | 15 | export function loadRewardTable2(): LoadRewardTableRequest { 16 | return { 17 | type: "load_reward_table_req", 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadServerList.ts: -------------------------------------------------------------------------------- 1 | import { LoadServerListRequest } from "../request/loadServerList"; 2 | 3 | loadServerList.msgCode = 0x0006; 4 | loadServerList.msgLen = 0x0020; 5 | 6 | export function loadServerList(): LoadServerListRequest { 7 | return { type: "load_server_list_req" }; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadStocker.ts: -------------------------------------------------------------------------------- 1 | import { LoadStockerRequest } from "../request/loadStocker"; 2 | import { AimeId } from "../../../model"; 3 | 4 | loadStocker1.msgCode = 0x00a7; 5 | loadStocker1.msgLen = 0x0010; 6 | 7 | export function loadStocker1(buf: Buffer): LoadStockerRequest { 8 | return { 9 | type: "load_stocker_req", 10 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 11 | version: 1, 12 | }; 13 | } 14 | 15 | loadStocker2.msgCode = 0x009c; 16 | loadStocker2.msgLen = 0x0010; 17 | 18 | export function loadStocker2(buf: Buffer): LoadStockerRequest { 19 | return { 20 | type: "load_stocker_req", 21 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 22 | version: 2, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadTeam.ts: -------------------------------------------------------------------------------- 1 | import { LoadTeamRequest } from "../request/loadTeam"; 2 | import { ExtId } from "../model/base"; 3 | import { Team } from "../model/team"; 4 | 5 | loadTeam1.msgCode = 0x0077; 6 | loadTeam1.msgLen = 0x0010; 7 | 8 | export function loadTeam1(buf: Buffer): LoadTeamRequest { 9 | const extId = buf.readUInt32LE(0x0008); 10 | 11 | return { 12 | type: "load_team_req", 13 | aimeId: buf.readUInt32LE(0x0004), 14 | version: 1, 15 | teamExtId: extId !== 0xffffffff ? (extId as ExtId) : undefined, 16 | }; 17 | } 18 | 19 | loadTeam2.msgCode = 0x0073; 20 | loadTeam2.msgLen = 0x0010; 21 | 22 | export function loadTeam2(buf: Buffer): LoadTeamRequest { 23 | const extId = buf.readUInt32LE(0x0008); 24 | 25 | return { 26 | type: "load_team_req", 27 | aimeId: buf.readUInt32LE(0x0004), 28 | version: 2, 29 | teamExtId: extId !== 0xffffffff ? (extId as ExtId) : undefined, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/loadTeamRanking.ts: -------------------------------------------------------------------------------- 1 | import { LoadTeamRankingRequest } from "../request/loadTeamRanking"; 2 | 3 | loadTeamRanking1.msgCode = 0x00b9; 4 | loadTeamRanking1.msgLen = 0x0010; 5 | 6 | export function loadTeamRanking1(buf: Buffer): LoadTeamRankingRequest { 7 | return { 8 | type: "load_team_ranking_req", 9 | }; 10 | } 11 | 12 | // unused? Not sure where this came from. 13 | loadTeamRanking2.msgCode = 0x00a7; 14 | loadTeamRanking2.msgLen = 0x0010; 15 | 16 | export function loadTeamRanking2(buf: Buffer): LoadTeamRankingRequest { 17 | return { 18 | type: "load_team_ranking_req", 19 | }; 20 | } 21 | 22 | // not sure what the difference is... 23 | 24 | loadTeamRanking3.msgCode = 0x00bb; 25 | loadTeamRanking3.msgLen = 0x0010; 26 | 27 | export function loadTeamRanking3(buf: Buffer): LoadTeamRankingRequest { 28 | return { 29 | type: "load_team_ranking_req", 30 | }; 31 | } 32 | 33 | loadTeamRanking4.msgCode = 0x00a9; 34 | loadTeamRanking4.msgLen = 0x0010; 35 | 36 | export function loadTeamRanking4(buf: Buffer): LoadTeamRankingRequest { 37 | return { 38 | type: "load_team_ranking_req", 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/lockGarage.ts: -------------------------------------------------------------------------------- 1 | import { LockGarageRequest } from "../request/lockGarage"; 2 | 3 | lockGarage1.msgCode = 0x00a9; 4 | lockGarage1.msgLen = 0x0010; 5 | 6 | export function lockGarage1(buf: Buffer): LockGarageRequest { 7 | return { 8 | type: "lock_garage_request", 9 | field_0004: buf.readUInt32LE(0x0004), 10 | }; 11 | } 12 | 13 | lockGarage2.msgCode = 0x009e; 14 | lockGarage2.msgLen = 0x0010; 15 | 16 | export function lockGarage2(buf: Buffer): LockGarageRequest { 17 | return { 18 | type: "lock_garage_request", 19 | field_0004: buf.readUInt32LE(0x0004), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/lockProfile.ts: -------------------------------------------------------------------------------- 1 | import { readAsciiStr } from "../../util/bin"; 2 | import { LockProfileRequest } from "../request/lockProfile"; 3 | 4 | lockProfile1.msgCode = 0x0069; 5 | lockProfile1.msgLen = 0x0020; 6 | 7 | export function lockProfile1(buf: Buffer): LockProfileRequest { 8 | return { 9 | type: "lock_profile_req", 10 | aimeId: buf.readUInt32LE(0x0004), 11 | pcbId: readAsciiStr(buf, 0x0008, 0x0018), 12 | field_0018: buf.readUInt16LE(0x0018), 13 | }; 14 | } 15 | 16 | lockProfile2.msgCode = 0x0065; 17 | lockProfile2.msgLen = 0x0020; 18 | 19 | export function lockProfile2(buf: Buffer): LockProfileRequest { 20 | return { 21 | type: "lock_profile_req", 22 | aimeId: buf.readUInt32LE(0x0004), 23 | pcbId: readAsciiStr(buf, 0x0008, 0x0018), 24 | field_0018: buf.readUInt16LE(0x0018), 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/lockProfileExtend.ts: -------------------------------------------------------------------------------- 1 | import { LockProfileExtendRequest } from "../request/lockProfileExtend"; 2 | import { AimeId } from "../../../model"; 3 | import { readAsciiStr } from "../../util/bin"; 4 | 5 | lockProfileExtend1.msgCode = 0x006d; 6 | lockProfileExtend1.msgLen = 0x0020; 7 | 8 | export function lockProfileExtend1(buf: Buffer): LockProfileExtendRequest { 9 | return { 10 | type: "lock_profile_extend_req", 11 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 12 | luid: readAsciiStr(buf, 0x0008, 0x0020), 13 | }; 14 | } 15 | 16 | lockProfileExtend2.msgCode = 0x0069; 17 | lockProfileExtend2.msgLen = 0x0020; 18 | 19 | export function lockProfileExtend2(buf: Buffer): LockProfileExtendRequest { 20 | return { 21 | type: "lock_profile_extend_req", 22 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 23 | luid: buf.slice(0x0008, buf.indexOf("\0")).toString("ascii"), 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/saveExpedition.ts: -------------------------------------------------------------------------------- 1 | import { SaveExpeditionRequest } from "../request/saveExpedition"; 2 | 3 | saveExpedition1.msgCode = 0x008c; 4 | saveExpedition1.msgLen = 0x0010; 5 | 6 | export function saveExpedition1(buf: Buffer): SaveExpeditionRequest { 7 | return { 8 | type: "save_expedition_req", 9 | field_0004: buf.readUInt32LE(0x0004), 10 | }; 11 | } 12 | 13 | saveExpedition2.msgCode = 0x013f; 14 | saveExpedition2.msgLen = 0x0010; 15 | 16 | export function saveExpedition2(buf: Buffer): SaveExpeditionRequest { 17 | return { 18 | type: "save_expedition_req", 19 | field_0004: buf.readUInt32LE(0x0004), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/saveNewCar.ts: -------------------------------------------------------------------------------- 1 | import { car } from "./_car"; 2 | import { SaveNewCarRequest } from "../request/saveNewCar"; 3 | import { readAsciiStr } from "../../util/bin"; 4 | import { AimeId } from "../../../model"; 5 | 6 | saveNewCar1.msgCode = 0x0079; 7 | saveNewCar1.msgLen = 0x0090; 8 | 9 | export function saveNewCar1(buf: Buffer): SaveNewCarRequest { 10 | return { 11 | type: "save_new_car_req", 12 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 13 | version: 1, 14 | luid: readAsciiStr(buf, 0x0008, 0x001e), 15 | car: car(buf.slice(0x0020, 0x0080)), 16 | field_0080: buf.readUInt32LE(0x0080), 17 | }; 18 | } 19 | 20 | saveNewCar2.msgCode = 0x0075; 21 | saveNewCar2.msgLen = 0x0090; 22 | 23 | export function saveNewCar2(buf: Buffer): SaveNewCarRequest { 24 | return { 25 | type: "save_new_car_req", 26 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 27 | version: 2, 28 | luid: readAsciiStr(buf, 0x0008, 0x001e), 29 | car: car(buf.slice(0x0020, 0x0080)), 30 | field_0080: buf.readUInt32LE(0x0080), 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/saveTeamBanner.ts: -------------------------------------------------------------------------------- 1 | import { SaveTeamBannerRequest } from "../request/saveTeamBanner"; 2 | import { ExtId } from "../model/base"; 3 | import { Team } from "../model/team"; 4 | 5 | saveTeamBanner1.msgCode = 0x0089; 6 | saveTeamBanner1.msgLen = 0x0010; 7 | 8 | export function saveTeamBanner1(buf: Buffer): SaveTeamBannerRequest { 9 | return { 10 | type: "save_team_banner_req", 11 | teamExtId: buf.readUInt32LE(0x0004) as ExtId, 12 | version: 1, 13 | nameBg: buf.readUInt32LE(0x0008), 14 | nameFx: buf.readUInt32LE(0x000c), 15 | }; 16 | } 17 | 18 | saveTeamBanner2.msgCode = 0x0082; 19 | saveTeamBanner2.msgLen = 0x0010; 20 | 21 | export function saveTeamBanner2(buf: Buffer): SaveTeamBannerRequest { 22 | return { 23 | type: "save_team_banner_req", 24 | teamExtId: buf.readUInt32LE(0x0004) as ExtId, 25 | version: 2, 26 | nameBg: buf.readUInt32LE(0x0008), 27 | nameFx: buf.readUInt32LE(0x000c), 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/saveTopic.ts: -------------------------------------------------------------------------------- 1 | import { SaveTopicRequest } from "../request/saveTopic"; 2 | 3 | saveTopic1.msgCode = 0x009a; 4 | saveTopic1.msgLen = 0x0010; 5 | 6 | export function saveTopic1(buf: Buffer): SaveTopicRequest { 7 | const aimeId = buf.readUInt32LE(0x0004); 8 | 9 | return { 10 | type: "save_topic_req", 11 | aimeId: aimeId !== 0xffffffff ? aimeId : undefined, 12 | }; 13 | } 14 | 15 | saveTopic2.msgCode = 0x0091; 16 | saveTopic2.msgLen = 0x0010; 17 | 18 | export function saveTopic2(buf: Buffer): SaveTopicRequest { 19 | const aimeId = buf.readUInt32LE(0x0004); 20 | 21 | return { 22 | type: "save_topic_req", 23 | aimeId: aimeId !== 0xffffffff ? aimeId : undefined, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/unknownA.ts: -------------------------------------------------------------------------------- 1 | import { UnknownRequestA } from "../request/unknownA"; 2 | 3 | unknownA_1.msgCode = 0x00ad; 4 | unknownA_1.msgLen = 0x0620; 5 | 6 | export function unknownA_1(buf: Buffer): UnknownRequestA { 7 | return { type: "unknown_A_req" }; 8 | } 9 | 10 | unknownA_2.msgCode = 0x00a2; 11 | unknownA_2.msgLen = 0x0620; 12 | 13 | export function unknownA_2(buf: Buffer): UnknownRequestA { 14 | return { type: "unknown_A_req" }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/unlockProfile.ts: -------------------------------------------------------------------------------- 1 | import { UnlockProfileRequest } from "../request/unlockProfile"; 2 | 3 | unlockProfile1.msgCode = 0x006f; 4 | unlockProfile1.msgLen = 0x0020; 5 | 6 | export function unlockProfile1(buf: Buffer): UnlockProfileRequest { 7 | return { 8 | type: "unlock_profile_req", 9 | aimeId: buf.readUInt32LE(0x0004), 10 | pcbId: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"), 11 | }; 12 | } 13 | 14 | unlockProfile2.msgCode = 0x006b; 15 | unlockProfile2.msgLen = 0x0020; 16 | 17 | export function unlockProfile2(buf: Buffer): UnlockProfileRequest { 18 | return { 19 | type: "unlock_profile_req", 20 | aimeId: buf.readUInt32LE(0x0004), 21 | pcbId: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateExpedition.ts: -------------------------------------------------------------------------------- 1 | import { UpdateExpeditionRequest } from "../request/updateExpedition"; 2 | 3 | updateExpedition.msgCode = 0x013F; 4 | updateExpedition.msgLen = 0x0010; 5 | 6 | export function updateExpedition( 7 | buf: Buffer 8 | ): UpdateExpeditionRequest { 9 | return { 10 | type: "update_expedition_req", 11 | expeditionRequestType: buf.readUInt32LE(0x0004), 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateProvisionalStoreRank.ts: -------------------------------------------------------------------------------- 1 | import { UpdateProvisionalStoreRankRequest } from "../request/updateProvisionalStoreRank"; 2 | 3 | updateProvisionalStoreRank1.msgCode = 0x0082; 4 | updateProvisionalStoreRank1.msgLen = 0x0010; 5 | 6 | export function updateProvisionalStoreRank1( 7 | buf: Buffer 8 | ): UpdateProvisionalStoreRankRequest { 9 | return { 10 | type: "update_provisional_store_rank_req", 11 | aimeId: buf.readUInt32LE(0x0004), 12 | }; 13 | } 14 | 15 | updateProvisionalStoreRank2.msgCode = 0x007c; 16 | updateProvisionalStoreRank2.msgLen = 0x0010; 17 | 18 | export function updateProvisionalStoreRank2( 19 | buf: Buffer 20 | ): UpdateProvisionalStoreRankRequest { 21 | return { 22 | type: "update_provisional_store_rank_req", 23 | aimeId: buf.readUInt32LE(0x0004), 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateResult.ts: -------------------------------------------------------------------------------- 1 | import { UpdateResultRequest } from "../request/updateResult"; 2 | 3 | updateResult.msgCode = 0x00cc; 4 | updateResult.msgLen = 0x0030; 5 | 6 | export function updateResult(buf: Buffer): UpdateResultRequest { 7 | return { 8 | type: "update_result_req", 9 | field_0002: buf.readUInt16LE(0x0002), 10 | field_0004: buf.readUInt32LE(0x0004), 11 | field_0008: buf.readUInt32LE(0x0008), 12 | field_000C: buf.readUInt32LE(0x000c), 13 | field_0010: buf.readUInt32LE(0x0010), 14 | field_0014: buf.readUInt16LE(0x0014), 15 | field_0016: buf.readUInt16LE(0x0016), 16 | field_0018: buf.readUInt8(0x0018), 17 | field_0019: buf.readUInt8(0x0019), 18 | field_001A: buf.readUInt8(0x001a), 19 | field_001C: buf.readUInt16LE(0x001c), 20 | field_0020: buf.readUInt32LE(0x0020), 21 | field_0024: buf.readUInt8(0x0024), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateStoryClearNum.ts: -------------------------------------------------------------------------------- 1 | import { UpdateStoryClearNumRequest } from "../request/updateStoryClearNum"; 2 | 3 | updateStoryClearNum1.msgCode = 0x007f; 4 | updateStoryClearNum1.msgLen = 0x0010; 5 | 6 | export function updateStoryClearNum1(buf: Buffer): UpdateStoryClearNumRequest { 7 | return { 8 | type: "update_story_clear_num_req", 9 | }; 10 | } 11 | 12 | updateStoryClearNum2.msgCode = 0x097f; 13 | updateStoryClearNum2.msgLen = 0x0010; 14 | 15 | export function updateStoryClearNum2(buf: Buffer): UpdateStoryClearNumRequest { 16 | return { 17 | type: "update_story_clear_num_req", 18 | }; 19 | } 20 | 21 | updateStoryClearNum3.msgCode = 0x013d; 22 | updateStoryClearNum3.msgLen = 0x0010; 23 | 24 | export function updateStoryClearNum3(buf: Buffer): UpdateStoryClearNumRequest { 25 | return { 26 | type: "update_story_clear_num_req", 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateTeamLeader.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { UpdateTeamLeaderRequest } from "../request/updateTeamLeader"; 4 | import { AimeId } from "../../../model"; 5 | import { readAsciiStr } from "../../util/bin"; 6 | 7 | updateTeamLeader1.msgCode = 0x008a; 8 | updateTeamLeader1.msgLen = 0x0020; 9 | 10 | export function updateTeamLeader1(buf: Buffer): UpdateTeamLeaderRequest { 11 | return { 12 | type: "update_team_leader_req", 13 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 14 | version: 1, 15 | teamExtId: buf.readUInt32LE(0x0008) as ExtId, 16 | field_000C: readAsciiStr(buf, 0x000c, 0x0020), 17 | }; 18 | } 19 | 20 | updateTeamLeader2.msgCode = 0x0083; 21 | updateTeamLeader2.msgLen = 0x0020; 22 | 23 | export function updateTeamLeader2(buf: Buffer): UpdateTeamLeaderRequest { 24 | return { 25 | type: "update_team_leader_req", 26 | aimeId: buf.readUInt32LE(0x0004) as AimeId, 27 | version: 2, 28 | teamExtId: buf.readUInt32LE(0x0008) as ExtId, 29 | field_000C: readAsciiStr(buf, 0x000c, 0x0020), 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateTeamMember.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { UpdateTeamMemberRequest } from "../request/updateTeamMember"; 4 | import { AimeId } from "../../../model"; 5 | 6 | updateTeamMember1.msgCode = 0x0073; 7 | updateTeamMember1.msgLen = 0x0010; 8 | 9 | export function updateTeamMember1(buf: Buffer): UpdateTeamMemberRequest { 10 | return { 11 | type: "update_team_member_req", 12 | action: buf.readUInt8(0x0004) === 0 ? "add" : "remove", 13 | aimeId: buf.readUInt32LE(0x0008) as AimeId, 14 | version: 1, 15 | teamExtId: buf.readUInt32LE(0x000c) as ExtId, 16 | }; 17 | } 18 | 19 | updateTeamMember2.msgCode = 0x006f; 20 | updateTeamMember2.msgLen = 0x0010; 21 | 22 | export function updateTeamMember2(buf: Buffer): UpdateTeamMemberRequest { 23 | return { 24 | type: "update_team_member_req", 25 | action: buf.readUInt8(0x0004) === 0 ? "add" : "remove", 26 | aimeId: buf.readUInt32LE(0x0008) as AimeId, 27 | version: 2, 28 | teamExtId: buf.readUInt32LE(0x000c) as ExtId, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateTeamPoints.ts: -------------------------------------------------------------------------------- 1 | import { UpdateTeamPointsRequest } from "../request/updateTeamPoints"; 2 | 3 | updateTeamPoints1.msgCode = 0x0081; 4 | updateTeamPoints1.msgLen = 0x0010; 5 | 6 | export function updateTeamPoints1(buf: Buffer): UpdateTeamPointsRequest { 7 | return { 8 | type: "update_team_points_req", 9 | field_0004: buf.readUInt32LE(0x0004), 10 | field_0008: buf.readUInt32LE(0x0008), 11 | }; 12 | } 13 | 14 | updateTeamPoints2.msgCode = 0x007b; 15 | updateTeamPoints2.msgLen = 0x0010; 16 | 17 | export function updateTeamPoints2(buf: Buffer): UpdateTeamPointsRequest { 18 | return { 19 | type: "update_team_points_req", 20 | field_0004: buf.readUInt32LE(0x0004), 21 | field_0008: buf.readUInt32LE(0x0008), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateUiReport.ts: -------------------------------------------------------------------------------- 1 | import { UpdateUiReportRequest } from "../request/updateUiReport"; 2 | 3 | updateUiReport1.msgCode = 0x0084; 4 | updateUiReport1.msgLen = 0x0410; 5 | 6 | export function updateUiReport1(buf: Buffer): UpdateUiReportRequest { 7 | return { 8 | type: "update_ui_report_req", 9 | field_02: buf.readUInt16LE(0x0002), 10 | field_04: buf.readUInt16LE(0x0004), 11 | }; 12 | } 13 | 14 | updateUiReport2.msgCode = 0x007e; 15 | updateUiReport2.msgLen = 0x0410; 16 | 17 | export function updateUiReport2(buf: Buffer): UpdateUiReportRequest { 18 | return { 19 | type: "update_ui_report_req", 20 | field_02: buf.readUInt16LE(0x0002), 21 | field_04: buf.readUInt16LE(0x0004), 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/idz/userdb/decoder/updateUserLog.ts: -------------------------------------------------------------------------------- 1 | import { UpdateUserLogRequest } from "../request/updateUserLog"; 2 | 3 | updateUserLog1.msgCode = 0x00bd; 4 | updateUserLog1.msgLen = 0x0050; 5 | 6 | export function updateUserLog1(buf: Buffer): UpdateUserLogRequest { 7 | return { type: "update_user_log_req" }; 8 | } 9 | 10 | updateUserLog2.msgCode = 0x00ab; 11 | updateUserLog2.msgLen = 0x0050; 12 | 13 | export function updateUserLog2(buf: Buffer): UpdateUserLogRequest { 14 | return { type: "update_user_log_req" }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/_bitmap.ts: -------------------------------------------------------------------------------- 1 | export function encodeBitmap(items: Set, nbytes: number): Buffer { 2 | const buf = Buffer.alloc(nbytes); 3 | 4 | for (const item of items) { 5 | const byte = (item / 8) | 0; 6 | const bit = item % 8; 7 | 8 | buf.writeUInt8(buf.readUInt8(byte) | (1 << bit), byte); 9 | } 10 | 11 | return buf; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/_car.ts: -------------------------------------------------------------------------------- 1 | import { Car } from "../model/car"; 2 | 3 | export function encodeCar(car: Car): Buffer { 4 | const buf = Buffer.alloc(0x0060); 5 | 6 | buf.writeUInt16LE(car.field_00, 0x0000); 7 | buf.writeUInt16LE(car.field_02, 0x0002); 8 | 9 | for (let i = 0; i < 32; i++) { 10 | buf.writeUInt16LE( 11 | i < car.field_04.length ? car.field_04[i] : 0xff00, 12 | 0x0004 + 2 * i 13 | ); 14 | } 15 | 16 | buf.writeUInt16LE(car.selector, 0x0044); 17 | buf.writeUInt16LE(car.field_46, 0x0046); 18 | buf.writeUInt16LE(car.field_48, 0x0048); 19 | buf.writeUInt16LE(car.field_4a, 0x004a); 20 | buf.writeUInt32LE(car.field_4c, 0x004c); 21 | buf.writeUInt32LE(car.field_50_lo, 0x0050); 22 | buf.writeUInt32LE(car.field_50_hi, 0x0054); 23 | buf.writeUInt16LE(car.field_58, 0x0058); 24 | buf.writeUInt8(car.field_5a, 0x005a); 25 | buf.writeUInt8(car.field_5b, 0x005b); 26 | buf.writeUInt16LE(car.field_5c, 0x005c); 27 | buf.writeUInt16LE(car.field_5e, 0x005e); 28 | 29 | return buf; 30 | } 31 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/_mission.ts: -------------------------------------------------------------------------------- 1 | import { MissionGrid } from "../model/mission"; 2 | 3 | export function encodeMission(grids: MissionGrid[]): Buffer { 4 | const buf = Buffer.alloc(0x24); 5 | 6 | for (let gridNo = 0; gridNo < grids.length; gridNo++) { 7 | const grid = grids[gridNo]; 8 | const slices = [0, 0, 0]; 9 | 10 | for (let cellNo = 0; cellNo < 9 && cellNo < grid.cells.length; cellNo++) { 11 | const value = grid.cells[cellNo]; 12 | 13 | for (let sliceNo = 0; sliceNo < 3; sliceNo++) { 14 | if (value & (1 << sliceNo)) { 15 | slices[sliceNo] |= 1 << cellNo; 16 | } 17 | } 18 | } 19 | 20 | for (let sliceNo = 0; sliceNo < 3; sliceNo++) { 21 | buf.writeUInt16LE(slices[sliceNo], 0x0c * sliceNo + 0x02 * gridNo); 22 | } 23 | } 24 | 25 | return buf; 26 | } 27 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/checkTeamName.ts: -------------------------------------------------------------------------------- 1 | import { CheckTeamNameResponse } from "../response/checkTeamName"; 2 | 3 | export function checkTeamName1(res: CheckTeamNameResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x00a3, 0x0000); 7 | buf.writeUInt32LE(res.status, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function checkTeamName2(res: CheckTeamNameResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x0098, 0x0000); 16 | buf.writeUInt32LE(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/createProfile.ts: -------------------------------------------------------------------------------- 1 | import { CreateProfileResponse } from "../response/createProfile"; 2 | 3 | export function createProfile1(res: CreateProfileResponse) { 4 | const buf = Buffer.alloc(0x0020); 5 | 6 | // Shares message type code with the "generic" response 7 | buf.writeInt16LE(0x0001, 0x0000); 8 | buf.writeInt32LE(res.aimeId, 0x0004); 9 | 10 | return buf; 11 | } 12 | 13 | export function createProfile2(res: CreateProfileResponse) { 14 | const buf = Buffer.alloc(0x0030); 15 | 16 | buf.writeInt16LE(0x0001, 0x0000); 17 | buf.writeInt32LE(res.aimeId, 0x0008); 18 | 19 | return buf; 20 | } 21 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/createTeam.ts: -------------------------------------------------------------------------------- 1 | import { CreateTeamResponse } from "../response/createTeam"; 2 | 3 | export function createTeam1(res: CreateTeamResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x0072, 0x0000); 7 | buf.writeUInt32LE(res.status, 0x0004); 8 | buf.writeUInt32LE(res.teamExtId, 0x0008); 9 | 10 | return buf; 11 | } 12 | 13 | export function createTeam2(res: CreateTeamResponse): Buffer { 14 | const buf = Buffer.alloc(0x0010); 15 | 16 | buf.writeUInt16LE(0x006e, 0x0000); 17 | buf.writeUInt32LE(res.status, 0x0004); 18 | buf.writeUInt32LE(res.teamExtId, 0x0008); 19 | 20 | return buf; 21 | } 22 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/discoverProfile.ts: -------------------------------------------------------------------------------- 1 | import { DiscoverProfileResponse } from "../response/discoverProfile"; 2 | 3 | export function discoverProfile1(res: DiscoverProfileResponse) { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeInt16LE(0x006c, 0x0000); 7 | buf.writeInt8(res.exists ? 1 : 0, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function discoverProfile2(res: DiscoverProfileResponse) { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeInt16LE(0x0068, 0x0000); 16 | buf.writeInt8(res.exists ? 1 : 0, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/generic.ts: -------------------------------------------------------------------------------- 1 | import { GenericResponse } from "../response/generic"; 2 | 3 | export function generic1(res: GenericResponse) { 4 | const buf = Buffer.alloc(0x0020); 5 | 6 | buf.writeInt16LE(0x0001, 0x0000); 7 | buf.writeInt32LE(res.status || 0, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function generic2(res: GenericResponse) { 13 | const buf = Buffer.alloc(0x0030); 14 | 15 | buf.writeInt16LE(0x0001, 0x0000); 16 | buf.writeInt32LE(res.status || 0, 0x0004); 17 | 18 | // write the AIME ID for createProfile in 2.12, kinda awkward but whatever. 19 | buf.writeInt32LE(res.status || 0, 0x0008); 20 | 21 | return buf; 22 | } 23 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/load2on2.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Load2on2InfoResponse, 3 | Load2on2RankingPointsResponse, 4 | } from "../response/load2on2"; 5 | 6 | export function load2on2RankingPoints1( 7 | res: Load2on2RankingPointsResponse 8 | ): Buffer { 9 | const buf = Buffer.alloc(0x04c0); 10 | 11 | buf.writeInt16LE(0x00b1, 0x0000); 12 | 13 | return buf; 14 | } 15 | 16 | export function load2on2Info1(res: Load2on2InfoResponse): Buffer { 17 | const buf = Buffer.alloc(0x04c0); 18 | 19 | buf.writeInt16LE(0x0133, 0x0000); 20 | 21 | return buf; 22 | } 23 | 24 | export function load2on2RankingPoints2( 25 | res: Load2on2RankingPointsResponse 26 | ): Buffer { 27 | const buf = Buffer.alloc(0x1290); 28 | 29 | buf.writeInt16LE(0x00a4, 0x0000); 30 | 31 | return buf; 32 | } 33 | 34 | export function load2on2Info2(res: Load2on2InfoResponse): Buffer { 35 | const buf = Buffer.alloc(0x0540); 36 | 37 | buf.writeInt16LE(0x0133, 0x0000); 38 | 39 | return buf; 40 | } 41 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadConfig.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LoadConfigResponseA, 3 | LoadConfigResponseB, 4 | } from "../response/loadConfig"; 5 | 6 | export function loadConfigA_1(res: LoadConfigResponseA) { 7 | const buf = Buffer.alloc(0x01a0); 8 | 9 | buf.writeInt16LE(0x0005, 0x0000); 10 | buf.writeInt8(res.status, 0x0002); 11 | buf.writeUInt16LE(res.serverVersion, 0x0016); 12 | 13 | return buf; 14 | } 15 | 16 | export function loadConfigB_1(res: LoadConfigResponseB) { 17 | const buf = Buffer.alloc(0x0230); 18 | 19 | buf.writeInt16LE(0x00ac, 0x0000); 20 | buf.writeInt8(res.status, 0x0002); 21 | 22 | return buf; 23 | } 24 | 25 | export function loadConfigA_2(res: LoadConfigResponseA) { 26 | const buf = Buffer.alloc(0x05e0); 27 | 28 | buf.writeInt16LE(0x0005, 0x0000); 29 | buf.writeInt8(res.status, 0x0002); 30 | buf.writeUInt16LE(res.serverVersion, 0x0016); 31 | 32 | return buf; 33 | } 34 | 35 | export function loadConfigB_2(res: LoadConfigResponseB) { 36 | const buf = Buffer.alloc(0x0240); 37 | 38 | buf.writeInt16LE(0x00a1, 0x0000); 39 | buf.writeInt8(res.status, 0x0002); 40 | 41 | return buf; 42 | } 43 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadEventInfo.ts: -------------------------------------------------------------------------------- 1 | import { LoadEventInfoResponse } from "../response/loadEventInfo"; 2 | 3 | export function loadEventInfo1(res: LoadEventInfoResponse): Buffer { 4 | const buf = Buffer.alloc(0x01b0); 5 | 6 | buf.writeUInt16LE(0x00bf, 0x0000); 7 | 8 | return buf; 9 | } 10 | 11 | export function loadEventInfo2(res: LoadEventInfoResponse): Buffer { 12 | const buf = Buffer.alloc(0x01b0); 13 | 14 | buf.writeUInt16LE(0x00ad, 0x0000); 15 | 16 | return buf; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadGacha.ts: -------------------------------------------------------------------------------- 1 | import { LoadGachaResponse } from "../response/loadGacha"; 2 | 3 | export function loadGacha1(res: LoadGachaResponse): Buffer { 4 | const buf = Buffer.alloc(0x0090); 5 | 6 | buf.writeUInt16LE(0x00c2, 0x0000); 7 | buf.writeUInt8(res.awardedToday ? 0x01 : 0x00, 0x0002); 8 | 9 | return buf; 10 | } 11 | 12 | export function loadGacha2(res: LoadGachaResponse): Buffer { 13 | const buf = Buffer.alloc(0x0090); 14 | 15 | buf.writeUInt16LE(0x00b0, 0x0000); 16 | buf.writeUInt8(res.awardedToday ? 0x01 : 0x00, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadGarage.ts: -------------------------------------------------------------------------------- 1 | import { encodeCar } from "./_car"; 2 | import { LoadGarageResponse } from "../response/loadGarage"; 3 | 4 | export function loadGarage1(res: LoadGarageResponse): Buffer { 5 | const buf = Buffer.alloc(0x03d0); 6 | 7 | buf.writeUInt16LE(0x0091, 0x0000); 8 | buf.writeUInt16LE(res.cars.length, 0x0002); 9 | 10 | for (let i = 0; i < res.cars.length; i++) { 11 | encodeCar(res.cars[i]).copy(buf, 0x0004 + 0x0060 * i); 12 | } 13 | 14 | return buf; 15 | } 16 | 17 | export function loadGarage2(res: LoadGarageResponse): Buffer { 18 | const buf = Buffer.alloc(0x0420); 19 | 20 | buf.writeUInt16LE(0x0088, 0x0000); 21 | buf.writeUInt16LE(res.cars.length, 0x0004); 22 | 23 | for (let i = 0; i < res.cars.length; i++) { 24 | encodeCar(res.cars[i]).copy(buf, 0x0008 + 0x0068 * i); 25 | } 26 | 27 | return buf; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadGeneralReward.ts: -------------------------------------------------------------------------------- 1 | import { LoadGeneralRewardResponse } from "../response/loadGeneralReward"; 2 | import { writeSjisStr } from "../../util/bin"; 3 | 4 | export function loadGeneralReward(res: LoadGeneralRewardResponse) { 5 | const buf = Buffer.alloc(0x0330); 6 | 7 | buf.writeInt16LE(0x009d, 0x0000); 8 | 9 | // Traversal code shat out by MSVC uses shifted pointers and neither the 10 | // beginning nor the end of each entry in this array gets read, so the true 11 | // start of the array and offsets of each item's fields are still uncertain. 12 | 13 | for (let i = 0; i < 10 && i < res.items.length; i++) { 14 | const item = res.items[i]; 15 | const base = 0x04 + 0x50 * i; 16 | 17 | writeSjisStr(buf, base + 0x04, base + 0x2c, item.field_04); 18 | buf.writeUInt32LE(item.field_2C, base + 0x2c); 19 | buf.writeUInt8(item.field_38, base + 0x38); 20 | buf.writeUInt8(item.field_39, base + 0x39); 21 | 22 | for (let j = 0; j < 4 && j < item.field_3C.length; j++) { 23 | buf.writeUInt32LE(item.field_3C[j], base + 0x3c + 4 * j); 24 | } 25 | } 26 | 27 | return buf; 28 | } 29 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadProfile1.ts: -------------------------------------------------------------------------------- 1 | import { LoadProfileResponse } from "../response/loadProfile"; 2 | 3 | // Sending this causes an error in v1.21, so it is currently unmapped and 4 | // unimplemented. 5 | 6 | export function loadProfile1(res: LoadProfileResponse) { 7 | const buf = Buffer.alloc(0x0c60); 8 | 9 | buf.writeInt16LE(0x0064, 0x0000); 10 | 11 | return buf; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadRewardTable.ts: -------------------------------------------------------------------------------- 1 | import { LoadRewardTableResponse } from "../response/loadRewardTable"; 2 | 3 | export function loadRewardTable1(res: LoadRewardTableResponse) { 4 | const buf = Buffer.alloc(0x01c0); 5 | 6 | buf.writeInt16LE(0x0087, 0x0000); 7 | 8 | return buf; 9 | } 10 | 11 | export function loadRewardTable2(res: LoadRewardTableResponse) { 12 | const buf = Buffer.alloc(0x01c0); 13 | 14 | buf.writeInt16LE(0x0080, 0x0000); 15 | 16 | return buf; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadStocker.ts: -------------------------------------------------------------------------------- 1 | import { encodeBitmap } from "./_bitmap"; 2 | import { LoadStockerResponse } from "../response/loadStocker"; 3 | 4 | export function loadStocker1(res: LoadStockerResponse) { 5 | const buf = Buffer.alloc(0x00a0); 6 | 7 | buf.writeInt16LE(0x00a8, 0x0000); 8 | buf.writeUInt8(res.status, 0x0002); 9 | encodeBitmap(res.backgrounds, 0x24).copy(buf, 0x0003); 10 | 11 | return buf; 12 | } 13 | 14 | export function loadStocker2(res: LoadStockerResponse) { 15 | const buf = Buffer.alloc(0x00a0); 16 | 17 | buf.writeInt16LE(0x009d, 0x0000); 18 | buf.writeUInt8(res.status, 0x0004); 19 | encodeBitmap(res.backgrounds, 0x2c).copy(buf, 0x0005); 20 | encodeBitmap(res.myChara, 0x98).copy(buf, 0x0031); 21 | 22 | return buf; 23 | } 24 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/loadTeamRanking.ts: -------------------------------------------------------------------------------- 1 | import { LoadTeamRankingResponse } from "../response/loadTeamRanking"; 2 | 3 | export function loadTeamRanking1(res: LoadTeamRankingResponse): Buffer { 4 | const buf = Buffer.alloc(0x0ba0); 5 | 6 | buf.writeUInt16LE(0x00ba, 0x0000); 7 | // Row stride is 0x94 8 | 9 | return buf; 10 | } 11 | 12 | export function loadTeamRanking2(res: LoadTeamRankingResponse): Buffer { 13 | const buf = Buffer.alloc(0x0ba0); 14 | 15 | buf.writeUInt16LE(0x00a8, 0x0000); 16 | 17 | return buf; 18 | } 19 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/lockProfile.ts: -------------------------------------------------------------------------------- 1 | import { LockProfileResponse } from "../response/lockProfile"; 2 | 3 | const statusCodes = { 4 | locked: 0x0000, 5 | unlocked: 0x0001, 6 | obsolete: 0x0002, 7 | }; 8 | 9 | export function lockProfile1(res: LockProfileResponse) { 10 | const buf = Buffer.alloc(0x0020); 11 | 12 | buf.writeInt16LE(0x006a, 0x0000); 13 | buf.writeInt8(statusCodes[res.status], 0x0018); 14 | buf.writeInt16LE(res.field_001A, 0x001a); 15 | buf.writeInt32LE(res.lockExpiry.getTime() / 1000, 0x001c); 16 | 17 | return buf; 18 | } 19 | 20 | export function lockProfile2(res: LockProfileResponse) { 21 | const buf = Buffer.alloc(0x0020); 22 | 23 | buf.writeInt16LE(0x0066, 0x0000); 24 | buf.writeInt8(statusCodes[res.status], 0x0018); 25 | buf.writeInt16LE(res.field_001A, 0x001a); 26 | buf.writeInt32LE(res.lockExpiry.getTime() / 1000, 0x001c); 27 | 28 | return buf; 29 | } 30 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/lockProfileExtend.ts: -------------------------------------------------------------------------------- 1 | import { LockProfileExtendResponse } from "../response/lockProfileExtend"; 2 | 3 | export function lockProfileExtend1(res: LockProfileExtendResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x006e, 0x0000); 7 | buf.writeUInt8(res.status, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function lockProfileExtend2(res: LockProfileExtendResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x006a, 0x0000); 16 | buf.writeUInt8(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/saveExpedition.ts: -------------------------------------------------------------------------------- 1 | import { SaveExpeditionResponse } from "../response/saveExpedition"; 2 | 3 | export function saveExpedition1(res: SaveExpeditionResponse): Buffer { 4 | // in awe of the size of this lad 5 | const buf = Buffer.alloc(0x17c0); 6 | 7 | buf.writeInt16LE(0x008d, 0x0000); 8 | 9 | return buf; 10 | } 11 | 12 | export function saveExpedition2(res: SaveExpeditionResponse): Buffer { 13 | // absolute unit 14 | const buf = Buffer.alloc(0x18ac); 15 | 16 | buf.writeUInt16LE(0x0140, 0x0000); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/saveGarage.ts: -------------------------------------------------------------------------------- 1 | import { SaveGarageResponse } from "../response/saveGarage"; 2 | 3 | export function saveGarage1(res: SaveGarageResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x008f, 0x0000); 7 | buf.writeUInt16LE(res.status, 0x0002); 8 | 9 | return buf; 10 | } 11 | 12 | export function saveGarage2(res: SaveGarageResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x0086, 0x0000); 16 | buf.writeUInt16LE(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/saveNewCar.ts: -------------------------------------------------------------------------------- 1 | import { SaveNewCarResponse } from "../response/saveNewCar"; 2 | 3 | export function saveNewCar1(res: SaveNewCarResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x007a, 0x0000); 7 | buf.writeUInt8(res.status, 0x0002); 8 | 9 | return buf; 10 | } 11 | 12 | export function saveNewCar2(res: SaveNewCarResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x0076, 0x0000); 16 | buf.writeUInt8(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/saveTimeAttack.ts: -------------------------------------------------------------------------------- 1 | import { SaveTimeAttackResponse } from "../response/saveTimeAttack"; 2 | 3 | export function saveTimeAttack1(res: SaveTimeAttackResponse): Buffer { 4 | const buf = Buffer.alloc(0x00b0); 5 | 6 | buf.writeUInt16LE(0x00ce, 0x0000); 7 | 8 | return buf; 9 | } 10 | 11 | export function saveTimeAttack2(res: SaveTimeAttackResponse): Buffer { 12 | const buf = Buffer.alloc(0x00f0); 13 | 14 | buf.writeUInt16LE(0x00cd, 0x0000); 15 | 16 | return buf; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/saveTopic.ts: -------------------------------------------------------------------------------- 1 | import { SaveTopicResponse } from "../response/saveTopic"; 2 | 3 | export function saveTopic1(res: SaveTopicResponse) { 4 | const buf = Buffer.alloc(0x05d0); 5 | 6 | buf.writeInt16LE(0x009b, 0x0000); 7 | 8 | return buf; 9 | } 10 | 11 | export function saveTopic2(res: SaveTopicResponse) { 12 | const buf = Buffer.alloc(0x05d0); 13 | 14 | buf.writeInt16LE(0x0092, 0x0000); 15 | 16 | return buf; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/unlockProfile.ts: -------------------------------------------------------------------------------- 1 | import { UnlockProfileResponse } from "../response/unlockProfile"; 2 | 3 | export function unlockProfile1(res: UnlockProfileResponse) { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeInt16LE(0x0070, 0x0000); 7 | buf.writeInt8(res.status, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function unlockProfile2(res: UnlockProfileResponse) { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeInt16LE(0x006c, 0x0000); 16 | buf.writeInt8(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/updateExpedition.ts: -------------------------------------------------------------------------------- 1 | import { UpdateExpeditionResponse } from "../response/updateExpedition"; 2 | 3 | export function updateExpedition(res: UpdateExpeditionResponse) { 4 | let buf: Buffer; 5 | 6 | if (res.expeditionType == 0) { 7 | buf = Buffer.alloc(0x0040); 8 | buf.writeInt16LE(1, 0x0000); 9 | } else { 10 | buf = Buffer.alloc(0x19f0); 11 | buf.writeInt16LE(0x0140, 0x0000); 12 | // Experiments used to live here, removed because they're a not-really 13 | // working mess. Hopefully, one day there will be beautiful code 14 | // here, that works and makes people happy. One day. 15 | } 16 | 17 | return buf; 18 | } 19 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/updateStoryClearNum.ts: -------------------------------------------------------------------------------- 1 | import { UpdateStoryClearNumResponse } from "../response/updateStoryClearNum"; 2 | 3 | export function updateStoryClearNum1( 4 | res: UpdateStoryClearNumResponse 5 | ): Buffer { 6 | const buf = Buffer.alloc(0x0220); 7 | 8 | buf.writeInt16LE(0x0080, 0x0000); 9 | 10 | return buf; 11 | } 12 | 13 | export function updateStoryClearNum2( 14 | res: UpdateStoryClearNumResponse 15 | ): Buffer { 16 | const buf = Buffer.alloc(0x04f0); 17 | 18 | buf.writeInt16LE(0x013e, 0x0000); 19 | 20 | return buf; 21 | } 22 | 23 | export function updateStoryClearNum3( 24 | res: UpdateStoryClearNumResponse 25 | ): Buffer { 26 | const buf = Buffer.alloc(0x0510); 27 | 28 | buf.writeInt16LE(0x013e, 0x0000); 29 | 30 | return buf; 31 | } 32 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/updateTeamLeader.ts: -------------------------------------------------------------------------------- 1 | import { UpdateTeamLeaderResponse } from "../response/updateTeamLeader"; 2 | 3 | export function updateTeamLeader1(res: UpdateTeamLeaderResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x008b, 0x0000); 7 | buf.writeUInt32LE(res.status, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function updateTeamLeader2(res: UpdateTeamLeaderResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x0084, 0x0000); 16 | buf.writeUInt32LE(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/encoder/updateTeamMember.ts: -------------------------------------------------------------------------------- 1 | import { UpdateTeamMemberResponse } from "../response/updateTeamMember"; 2 | 3 | export function updateTeamMember1(res: UpdateTeamMemberResponse): Buffer { 4 | const buf = Buffer.alloc(0x0010); 5 | 6 | buf.writeUInt16LE(0x0074, 0x0000); 7 | buf.writeUInt32LE(res.status, 0x0004); 8 | 9 | return buf; 10 | } 11 | 12 | export function updateTeamMember2(res: UpdateTeamMemberResponse): Buffer { 13 | const buf = Buffer.alloc(0x0010); 14 | 15 | buf.writeUInt16LE(0x0070, 0x0000); 16 | buf.writeUInt32LE(res.status, 0x0004); 17 | 18 | return buf; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/_team.ts: -------------------------------------------------------------------------------- 1 | import { Team } from "../model/team"; 2 | import { Repositories } from "../repo"; 3 | import { Id } from "../../../model"; 4 | 5 | // Bleh. This factorization is kind of messy. 6 | 7 | export async function _fixupPrevTeam( 8 | w: Repositories, 9 | prevTeamId: Id | undefined 10 | ): Promise { 11 | if (prevTeamId === undefined) { 12 | return; 13 | } 14 | 15 | const remaining = await w.teamMembers().loadRoster(prevTeamId); 16 | 17 | if (remaining.length === 0) { 18 | // Last member left, GC previous team 19 | 20 | await w.teams().delete(prevTeamId); 21 | } else if (remaining.find(member => member.leader) === undefined) { 22 | // Leader left, appoint new leader by seniority 23 | 24 | remaining.sort((x, y) => x.joinTime.getTime() - y.joinTime.getTime()); 25 | 26 | // (need to look up new leader's db id from aime id. ick) 27 | 28 | const newLeader = remaining[remaining.length - 1]; 29 | const newLeaderId = await w 30 | .profile() 31 | .find(newLeader.profile.aimeId, newLeader.profile.version); 32 | 33 | await w.teamMembers().makeLeader(prevTeamId, newLeaderId); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/checkTeamName.ts: -------------------------------------------------------------------------------- 1 | import { CheckTeamNameRequest } from "../request/checkTeamName"; 2 | import { CheckTeamNameResponse } from "../response/checkTeamName"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function checkTeamName( 6 | w: Repositories, 7 | req: CheckTeamNameRequest 8 | ): CheckTeamNameResponse { 9 | return { 10 | type: "check_team_name_res", 11 | status: 0, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/createTeam.ts: -------------------------------------------------------------------------------- 1 | import { _fixupPrevTeam } from "./_team"; 2 | import { CreateTeamRequest } from "../request/createTeam"; 3 | import { CreateTeamResponse } from "../response/createTeam"; 4 | import { Repositories } from "../repo"; 5 | 6 | export async function createTeam( 7 | w: Repositories, 8 | req: CreateTeamRequest 9 | ): Promise { 10 | const profileId = await w.profile().find(req.aimeId, req.version); 11 | const prevTeamId = await w.teamMembers().findTeam(profileId); 12 | const now = new Date(); 13 | 14 | // Create the new team... 15 | 16 | const teamSpec = { 17 | name: req.teamName, 18 | version: req.version, 19 | nameBg: req.nameBg, 20 | nameFx: 0, 21 | registerTime: now, 22 | }; 23 | 24 | const [teamId, teamExtId] = await w.teams().create(teamSpec); 25 | 26 | await w.teamMembers().join(teamId, profileId, now); 27 | await w.teamMembers().makeLeader(teamId, profileId); 28 | await _fixupPrevTeam(w, prevTeamId); 29 | 30 | return { 31 | type: "create_team_res", 32 | status: 0, 33 | teamExtId, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/discoverProfile.ts: -------------------------------------------------------------------------------- 1 | import { DiscoverProfileRequest } from "../request/discoverProfile"; 2 | import { DiscoverProfileResponse } from "../response/discoverProfile"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function discoverProfile( 6 | w: Repositories, 7 | req: DiscoverProfileRequest 8 | ): Promise { 9 | const profileId = await w.profile().peek(req.aimeId, req.version); 10 | 11 | return { 12 | type: "discover_profile_res", 13 | exists: profileId !== undefined, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/load2on2.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Load2on2InfoRequest, 3 | Load2on2RankingPointsRequest, 4 | } from "../request/load2on2"; 5 | import { 6 | Load2on2InfoResponse, 7 | Load2on2RankingPointsResponse, 8 | } from "../response/load2on2"; 9 | import { Repositories } from "../repo"; 10 | 11 | export function load2on2Info( 12 | w: Repositories, 13 | req: Load2on2InfoRequest 14 | ): Load2on2InfoResponse { 15 | return { 16 | type: "load_2on2_info_res", 17 | }; 18 | } 19 | 20 | export function load2on2RankingPoints( 21 | w: Repositories, 22 | req: Load2on2RankingPointsRequest 23 | ): Load2on2RankingPointsResponse { 24 | return { 25 | type: "load_2on2_ranking_points_res", 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadConfig.ts: -------------------------------------------------------------------------------- 1 | import { LoadConfigRequestA, LoadConfigRequestB } from "../request/loadConfig"; 2 | import { 3 | LoadConfigResponseA, 4 | LoadConfigResponseB, 5 | } from "../response/loadConfig"; 6 | import { Repositories } from "../repo"; 7 | import { ClientHello } from "../../common"; 8 | 9 | export function loadConfig1( 10 | w: Repositories, 11 | req: LoadConfigRequestA, 12 | clientHello: ClientHello 13 | ): LoadConfigResponseA { 14 | return { 15 | type: "load_config_A_res", 16 | status: 1, 17 | 18 | // Only advertise up to v210 for now, advertising v230 to the v230 client 19 | // will activate a bunch of stuff that's currently broken. 20 | serverVersion: Math.min(parseInt(clientHello.protocol), 210), 21 | }; 22 | } 23 | 24 | export function loadConfig2( 25 | w: Repositories, 26 | req: LoadConfigRequestB 27 | ): LoadConfigResponseB { 28 | return { 29 | type: "load_config_B_res", 30 | status: 1, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadEventInfo.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { LoadEventInfoRequest } from "../request/loadEventInfo"; 3 | import { LoadEventInfoResponse } from "../response/loadEventInfo"; 4 | 5 | export function loadEventInfo( 6 | w: Repositories, 7 | req: LoadEventInfoRequest 8 | ): LoadEventInfoResponse { 9 | return { 10 | type: "load_event_info_res", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadGacha.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { LoadGachaRequest } from "../request/loadGacha"; 3 | import { LoadGachaResponse } from "../response/loadGacha"; 4 | 5 | export function loadGacha( 6 | w: Repositories, 7 | req: LoadGachaRequest 8 | ): LoadGachaResponse { 9 | return { 10 | type: "load_gacha_res", 11 | awardedToday: true, // Disable for now, not even mapped out yet. 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadGarage.ts: -------------------------------------------------------------------------------- 1 | import { LoadGarageRequest } from "../request/loadGarage"; 2 | import { LoadGarageResponse } from "../response/loadGarage"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function loadGarage( 6 | w: Repositories, 7 | req: LoadGarageRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | 11 | return { 12 | type: "load_garage_res", 13 | cars: await w.car().loadCars(profileId, 10, req.fetchOffset), 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadGeneralReward.ts: -------------------------------------------------------------------------------- 1 | import { LoadGeneralRewardRequest } from "../request/loadGeneralReward"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function loadGeneralReward( 6 | w: Repositories, 7 | req: LoadGeneralRewardRequest 8 | ): GenericResponse { 9 | // A version-specific response is also accepted. Format TBD. 10 | return { type: "generic_res" }; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadGhost.ts: -------------------------------------------------------------------------------- 1 | import { LoadGhostRequest } from "../request/loadGhost"; 2 | import { LoadGhostResponse } from "../response/loadGhost"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function loadGhost( 6 | w: Repositories, 7 | req: LoadGhostRequest 8 | ): LoadGhostResponse { 9 | return { type: "load_ghost_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadRewardTable.ts: -------------------------------------------------------------------------------- 1 | import { LoadRewardTableRequest } from "../request/loadRewardTable"; 2 | import { LoadRewardTableResponse } from "../response/loadRewardTable"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function loadReward( 6 | w: Repositories, 7 | req: LoadRewardTableRequest 8 | ): LoadRewardTableResponse { 9 | return { 10 | type: "load_reward_table_res", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadStocker.ts: -------------------------------------------------------------------------------- 1 | import { LoadStockerRequest } from "../request/loadStocker"; 2 | import { LoadStockerResponse } from "../response/loadStocker"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function loadStocker( 6 | w: Repositories, 7 | req: LoadStockerRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | const backgrounds = await w.backgrounds().loadAll(profileId); 11 | const myChara = await w.myChara().loadAll(profileId); 12 | 13 | return { 14 | type: "load_stocker_res", 15 | status: 1, 16 | backgrounds, 17 | myChara, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadTeam.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { LoadTeamRequest } from "../request/loadTeam"; 4 | import { LoadTeamResponse } from "../response/loadTeam"; 5 | import { Repositories } from "../repo"; 6 | 7 | export async function loadTeam( 8 | w: Repositories, 9 | req: LoadTeamRequest 10 | ): Promise { 11 | if (req.teamExtId === undefined) { 12 | // Even if a profile does not belong to a team, a team must still be loaded 13 | // (and then ignored by the client). 14 | 15 | return { 16 | type: "load_team_res", 17 | team: { 18 | extId: 0 as ExtId, 19 | version: req.version, 20 | name: "", 21 | nameBg: 0, 22 | nameFx: 0, 23 | registerTime: new Date(0), 24 | }, 25 | members: [], 26 | }; 27 | } 28 | 29 | const teamId = await w.teams().find(req.teamExtId, req.version); 30 | 31 | return { 32 | type: "load_team_res", 33 | team: await w.teams().load(teamId), 34 | members: await w.teamMembers().loadRoster(teamId), 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/loadTeamRanking.ts: -------------------------------------------------------------------------------- 1 | import { LoadTeamRankingRequest } from "../request/loadTeamRanking"; 2 | import { LoadTeamRankingResponse } from "../response/loadTeamRanking"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function loadTeamRanking( 6 | w: Repositories, 7 | req: LoadTeamRankingRequest 8 | ): LoadTeamRankingResponse { 9 | return { 10 | type: "load_team_ranking_res", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/lockGarage.ts: -------------------------------------------------------------------------------- 1 | import { LockGarageRequest } from "../request/lockGarage"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function lockGarage( 6 | w: Repositories, 7 | req: LockGarageRequest 8 | ): GenericResponse { 9 | return { type: "generic_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/lockProfile.ts: -------------------------------------------------------------------------------- 1 | import { LockProfileRequest } from "../request/lockProfile"; 2 | import { LockProfileResponse } from "../response/lockProfile"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function lockProfile( 6 | w: Repositories, 7 | req: LockProfileRequest 8 | ): LockProfileResponse { 9 | return { 10 | type: "lock_profile_res", 11 | status: "unlocked", 12 | field_001A: -1, 13 | lockExpiry: new Date(Date.now() + 3600000), 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/lockProfileExtend.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { LockProfileExtendRequest } from "../request/lockProfileExtend"; 3 | import { LockProfileExtendResponse } from "../response/lockProfileExtend"; 4 | 5 | export function lockProfileExtend( 6 | w: Repositories, 7 | req: LockProfileExtendRequest 8 | ): LockProfileExtendResponse { 9 | return { 10 | type: "lock_profile_extend_res", 11 | status: 1, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveExpedition.ts: -------------------------------------------------------------------------------- 1 | import { SaveExpeditionRequest } from "../request/saveExpedition"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { SaveExpeditionResponse } from "../response/saveExpedition"; 4 | import { Repositories } from "../repo"; 5 | 6 | export function saveExpedition( 7 | w: Repositories, 8 | req: SaveExpeditionRequest 9 | ): GenericResponse | SaveExpeditionResponse { 10 | if (req.field_0004 === 0) { 11 | return { 12 | type: "generic_res", 13 | status: 0, 14 | }; 15 | } else { 16 | return { 17 | type: "save_expedition_res", 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveGarage.ts: -------------------------------------------------------------------------------- 1 | import { SaveGarageRequest } from "../request/saveGarage"; 2 | import { SaveGarageResponse } from "../response/saveGarage"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function saveGarage( 6 | w: Repositories, 7 | req: SaveGarageRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | 11 | await w.car().saveCar(profileId, req.car); 12 | 13 | return { 14 | type: "save_garage_res", 15 | status: 0, // Zero means success for this particular message -.- 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveNewCar.ts: -------------------------------------------------------------------------------- 1 | import { SaveNewCarRequest } from "../request/saveNewCar"; 2 | import { SaveNewCarResponse } from "../response/saveNewCar"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function saveNewCar( 6 | w: Repositories, 7 | req: SaveNewCarRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | 11 | await w.car().saveCar(profileId, req.car); 12 | 13 | return { 14 | type: "save_new_car_res", 15 | status: 0, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveSettings.ts: -------------------------------------------------------------------------------- 1 | import { SaveSettingsRequest } from "../request/saveSettings"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function saveSettings( 6 | w: Repositories, 7 | req: SaveSettingsRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | 11 | await w.settings().save(profileId, req.settings); 12 | 13 | return { type: "generic_res" }; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveStocker.ts: -------------------------------------------------------------------------------- 1 | import { SaveStockerRequest } from "../request/saveStocker"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function saveStocker( 6 | w: Repositories, 7 | req: SaveStockerRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | 11 | await Promise.all([ 12 | w.backgrounds().saveAll(profileId, req.backgrounds), 13 | w.chara().save(profileId, req.chara), 14 | w.car().saveSelection(profileId, req.selectedCar), 15 | req.myChara && w.myChara().saveAll(profileId, req.myChara), 16 | req.selectedStamps && 17 | w.stamps().saveSelection(profileId, req.selectedStamps), 18 | req.stamps && w.stamps().saveAll(profileId, req.stamps), 19 | ]); 20 | 21 | return { type: "generic_res" }; 22 | } 23 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveTeamBanner.ts: -------------------------------------------------------------------------------- 1 | import { Repositories } from "../repo"; 2 | import { SaveTeamBannerRequest } from "../request/saveTeamBanner"; 3 | import { GenericResponse } from "../response/generic"; 4 | 5 | export async function saveTeamBanner( 6 | w: Repositories, 7 | req: SaveTeamBannerRequest 8 | ): Promise { 9 | const teamId = await w.teams().find(req.teamExtId, req.version); 10 | const orig = await w.teams().load(teamId); 11 | 12 | await w.teams().save(teamId, { 13 | ...orig, 14 | nameBg: req.nameBg, 15 | nameFx: req.nameFx, 16 | }); 17 | 18 | return { 19 | type: "generic_res", 20 | status: 0, // ignored 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveTimeAttack.ts: -------------------------------------------------------------------------------- 1 | import { SaveTimeAttackRequest } from "../request/saveTimeAttack"; 2 | import { SaveTimeAttackResponse } from "../response/saveTimeAttack"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function saveTimeAttack( 6 | w: Repositories, 7 | req: SaveTimeAttackRequest 8 | ): Promise { 9 | // Non time-attack credits still call this method, but they pass some 10 | // bullshit payload that we need to ignore. 11 | 12 | if (req.payload.totalTime > 0) { 13 | // Override client time since we might be doing some maintenance window 14 | // avoidance time warping stuff 15 | 16 | const now = new Date(); 17 | const profileId = await w.profile().find(req.aimeId, req.version); 18 | 19 | await w.timeAttack().save(profileId, { ...req.payload, timestamp: now }); 20 | } 21 | 22 | return { 23 | type: "save_time_attack_res", 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/saveTopic.ts: -------------------------------------------------------------------------------- 1 | import { SaveTopicRequest } from "../request/saveTopic"; 2 | import { SaveTopicResponse } from "../response/saveTopic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function saveTopic( 6 | w: Repositories, 7 | req: SaveTopicRequest 8 | ): SaveTopicResponse { 9 | return { 10 | type: "save_topic_res", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/unknownA.ts: -------------------------------------------------------------------------------- 1 | import { UnknownRequestA } from "../request/unknownA"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function unknownA( 6 | w: Repositories, 7 | req: UnknownRequestA 8 | ): GenericResponse { 9 | return { type: "generic_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/unlockProfile.ts: -------------------------------------------------------------------------------- 1 | import { UnlockProfileRequest } from "../request/unlockProfile"; 2 | import { UnlockProfileResponse } from "../response/unlockProfile"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function unlockProfile( 6 | w: Repositories, 7 | req: UnlockProfileRequest 8 | ): UnlockProfileResponse { 9 | return { 10 | type: "unlock_profile_res", 11 | status: 1, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateExpedition.ts: -------------------------------------------------------------------------------- 1 | import { UpdateExpeditionRequest } from "../request/updateExpedition"; 2 | import { UpdateExpeditionResponse } from "../response/updateExpedition"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function updateExpedition( 6 | w: Repositories, 7 | req: UpdateExpeditionRequest 8 | ): Promise { 9 | 10 | return { 11 | type: "update_expedition_res", 12 | expeditionType: req.expeditionRequestType, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateProvisionalStoreRank.ts: -------------------------------------------------------------------------------- 1 | import { UpdateProvisionalStoreRankRequest } from "../request/updateProvisionalStoreRank"; 2 | import { UpdateProvisionalStoreRankResponse } from "../response/updateProvisionalStoreRank"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function updateProvisionalStoreRank( 6 | w: Repositories, 7 | req: UpdateProvisionalStoreRankRequest 8 | ): UpdateProvisionalStoreRankResponse { 9 | return { 10 | type: "update_provisional_store_rank_res", 11 | rows: [], 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateResult.ts: -------------------------------------------------------------------------------- 1 | import { UpdateResultRequest } from "../request/updateResult"; 2 | import { GenericResponse } from "../response/generic"; 3 | 4 | export function updateResult(req: UpdateResultRequest): GenericResponse { 5 | // Apparently field_000C in this supposedly-generic response matters here?! 6 | return { type: "generic_res" }; 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateStoryClearNum.ts: -------------------------------------------------------------------------------- 1 | import { UpdateStoryClearNumRequest } from "../request/updateStoryClearNum"; 2 | import { UpdateStoryClearNumResponse } from "../response/updateStoryClearNum"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function updateStoryClearNum( 6 | w: Repositories, 7 | req: UpdateStoryClearNumRequest 8 | ): UpdateStoryClearNumResponse { 9 | return { 10 | type: "update_story_clear_num_res", 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateTeamLeader.ts: -------------------------------------------------------------------------------- 1 | import { UpdateTeamLeaderRequest } from "../request/updateTeamLeader"; 2 | import { UpdateTeamLeaderResponse } from "../response/updateTeamLeader"; 3 | import { Repositories } from "../repo"; 4 | 5 | export async function updateTeamLeader( 6 | w: Repositories, 7 | req: UpdateTeamLeaderRequest 8 | ): Promise { 9 | const profileId = await w.profile().find(req.aimeId, req.version); 10 | const teamId = await w.teams().find(req.teamExtId, req.version); 11 | 12 | await w.teamMembers().makeLeader(teamId, profileId); 13 | 14 | return { 15 | type: "update_team_leader_res", 16 | status: 0, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateTeamMember.ts: -------------------------------------------------------------------------------- 1 | import { _fixupPrevTeam } from "./_team"; 2 | import { UpdateTeamMemberRequest } from "../request/updateTeamMember"; 3 | import { UpdateTeamMemberResponse } from "../response/updateTeamMember"; 4 | import { Repositories } from "../repo"; 5 | 6 | export async function updateTeamMember( 7 | w: Repositories, 8 | req: UpdateTeamMemberRequest 9 | ): Promise { 10 | const now = new Date(); 11 | const profileId = await w.profile().find(req.aimeId, req.version); 12 | const teamId = await w.teams().find(req.teamExtId, req.version); 13 | 14 | switch (req.action) { 15 | case "add": 16 | const prevTeamId = await w.teamMembers().findTeam(profileId); 17 | 18 | await w.teamMembers().join(teamId, profileId, now); 19 | await _fixupPrevTeam(w, prevTeamId); 20 | 21 | break; 22 | 23 | case "remove": 24 | // TODO store expulsion flag in db 25 | await w.teamMembers().leave(teamId, profileId); 26 | 27 | break; 28 | 29 | default: 30 | throw new Error("???"); 31 | } 32 | 33 | return { 34 | type: "update_team_member_res", 35 | status: 0, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateTeamPoints.ts: -------------------------------------------------------------------------------- 1 | import { UpdateTeamPointsRequest } from "../request/updateTeamPoints"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function updateTeamPoints( 6 | w: Repositories, 7 | req: UpdateTeamPointsRequest 8 | ): GenericResponse { 9 | return { type: "generic_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateUiReport.ts: -------------------------------------------------------------------------------- 1 | import { UpdateUiReportRequest } from "../request/updateUiReport"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function updateUiReport( 6 | w: Repositories, 7 | req: UpdateUiReportRequest 8 | ): GenericResponse { 9 | return { type: "generic_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/handler/updateUserLog.ts: -------------------------------------------------------------------------------- 1 | import { UpdateUserLogRequest } from "../request/updateUserLog"; 2 | import { GenericResponse } from "../response/generic"; 3 | import { Repositories } from "../repo"; 4 | 5 | export function updateUserLog( 6 | w: Repositories, 7 | req: UpdateUserLogRequest 8 | ): GenericResponse { 9 | return { type: "generic_res" }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/index.ts: -------------------------------------------------------------------------------- 1 | import logger from "debug"; 2 | import { Socket } from "net"; 3 | 4 | import readRequestStream from "./decoder"; 5 | import writeResponse from "./encoder"; 6 | import { dispatch } from "./handler"; 7 | import setup from "../common"; 8 | import { DataSource } from "../../sql"; 9 | import { SqlRepositories } from "./sql"; 10 | 11 | const debug = logger("app:idz:userdb"); 12 | 13 | export default function idz(db: DataSource) { 14 | return async function(socket: Socket) { 15 | debug("Connection established"); 16 | 17 | try { 18 | const { clientHello, aesStream } = await setup(socket); 19 | 20 | debug("Handshake OK", clientHello); 21 | 22 | for await (const req of readRequestStream(clientHello, aesStream)) { 23 | const res = await db.transaction(txn => 24 | dispatch(new SqlRepositories(txn), req, clientHello) 25 | ); 26 | 27 | await aesStream.write(writeResponse(res, clientHello)); 28 | } 29 | } catch (error) { 30 | if (debug.enabled) { 31 | debug("Error: %s", error.stack); 32 | } 33 | } 34 | 35 | debug("Connection closed"); 36 | 37 | socket.end(); 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/idz/userdb/model/base.ts: -------------------------------------------------------------------------------- 1 | // Quasi-nominative "brands". These double-underscore properties never actually 2 | // exist at run time, we just pretend they do. 3 | 4 | export type BackgroundCode = number & { __brand: "backgroundCode" }; 5 | export type CourseNo = number & { __brand: "courseNo" }; 6 | export type ExtId = number & { __extId: T }; 7 | export type MyCharaCode = number & { __brand: "myCharaCode" }; 8 | export type RouteNo = number & { __brand: "routeNo" }; 9 | export type StampCode = number & { __brand: "stampCode" }; 10 | export type TitleCode = number & { __brand: "titleCode" }; 11 | -------------------------------------------------------------------------------- /src/idz/userdb/model/car.ts: -------------------------------------------------------------------------------- 1 | // See base.ts for information about branding. 2 | export type CarSelector = number & { __brand: "car_selector" }; 3 | 4 | export interface Car { 5 | field_00: number; 6 | field_02: number; 7 | field_04: number[]; 8 | selector: CarSelector; 9 | field_46: number; 10 | field_48: number; 11 | field_4a: number; 12 | field_4c: number; 13 | field_50_lo: number; 14 | field_50_hi: number; 15 | field_58: number; 16 | field_5a: number; 17 | field_5b: number; 18 | field_5c: number; 19 | field_5e: number; 20 | } 21 | -------------------------------------------------------------------------------- /src/idz/userdb/model/chara.ts: -------------------------------------------------------------------------------- 1 | import { BackgroundCode, TitleCode } from "./base"; 2 | 3 | export type Gender = "male" | "female"; 4 | 5 | export interface Chara { 6 | gender: Gender; 7 | field_02: number; 8 | field_04: number; 9 | field_06: number; 10 | field_08: number; 11 | field_0a: number; 12 | field_0c: number; 13 | field_0e: number; 14 | title: TitleCode; 15 | background: BackgroundCode; 16 | } 17 | -------------------------------------------------------------------------------- /src/idz/userdb/model/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | BackgroundCode, 3 | CourseNo, 4 | ExtId, 5 | MyCharaCode, 6 | RouteNo, 7 | StampCode, 8 | TitleCode, 9 | } from "./base"; 10 | export { Car, CarSelector } from "./car"; 11 | export { Chara } from "./chara"; 12 | export { MissionState, MissionGrid } from "./mission"; 13 | export { Profile } from "./profile"; 14 | export { Settings } from "./settings"; 15 | export { SelectedStamps } from "./stamps"; 16 | export { Story } from "./story"; 17 | export { Team, TeamAuto, TeamMember } from "./team"; 18 | export { Tickets } from "./tickets"; 19 | export { TimeAttackScore } from "./timeAttack"; 20 | export { Unlocks } from "./unlocks"; 21 | export { WeeklyMissions } from "./weeklyMissions"; 22 | -------------------------------------------------------------------------------- /src/idz/userdb/model/mission.ts: -------------------------------------------------------------------------------- 1 | export interface MissionGrid { 2 | cells: number[]; 3 | } 4 | 5 | export interface MissionState { 6 | team: MissionGrid[]; 7 | solo: MissionGrid[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/model/profile.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface Profile { 4 | aimeId: AimeId; 5 | version: number; 6 | name: string; 7 | lv: number; 8 | exp: number; 9 | fame: number; 10 | dpoint: number; 11 | mileage: number; 12 | accessTime: Date; 13 | registerTime: Date; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/model/settings.ts: -------------------------------------------------------------------------------- 1 | export interface Settings { 2 | music: number; 3 | pack: number; 4 | aura: number; 5 | paperCup: number; 6 | gauges: number; 7 | drivingStyle: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/model/stamps.ts: -------------------------------------------------------------------------------- 1 | import { StampCode } from "./base"; 2 | 3 | export interface SelectedStamps { 4 | stamp01: StampCode; 5 | stamp02: StampCode; 6 | stamp03: StampCode; 7 | stamp04: StampCode; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/model/story.ts: -------------------------------------------------------------------------------- 1 | export interface StoryCell { 2 | a: number; 3 | b: number; 4 | c: number; 5 | } 6 | 7 | export interface StoryRow { 8 | cells: Map; 9 | } 10 | 11 | export interface Story { 12 | x: number; 13 | y: number; 14 | rows: Map; 15 | } 16 | -------------------------------------------------------------------------------- /src/idz/userdb/model/team.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "./base"; 2 | import { Chara } from "./chara"; 3 | import { Profile } from "./profile"; 4 | 5 | export interface Team { 6 | extId: ExtId; 7 | version: number; 8 | name: string; 9 | nameBg: number; 10 | nameFx: number; 11 | registerTime: Date; 12 | } 13 | 14 | export interface TeamAuto { 15 | serialNo: number; 16 | nameIdx: number; 17 | } 18 | 19 | export interface TeamMember { 20 | profile: Profile; 21 | chara: Chara; 22 | leader: boolean; 23 | joinTime: Date; 24 | } 25 | -------------------------------------------------------------------------------- /src/idz/userdb/model/tickets.ts: -------------------------------------------------------------------------------- 1 | export interface Tickets { 2 | freeCar?: { 3 | validFrom: Date; 4 | // Valid To cannot be controlled, it is always 14 days after issue date. 5 | }; 6 | freeContinue?: { 7 | validFrom: Date; 8 | validTo: Date; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/model/timeAttack.ts: -------------------------------------------------------------------------------- 1 | import { RouteNo } from "./base"; 2 | import { CarSelector } from "./car"; 3 | 4 | export interface TimeAttackScore { 5 | routeNo: RouteNo; 6 | timestamp: Date; 7 | flags: number; 8 | totalTime: number; 9 | sectionTimes: number[]; 10 | grade: number; 11 | carSelector: CarSelector; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/model/unlocks.ts: -------------------------------------------------------------------------------- 1 | export interface Unlocks { 2 | auras: number; 3 | cup: number; 4 | gauges: number; 5 | music: number; 6 | 7 | // Doesn't really fit anywhere but let's put it here for now. This field is 8 | // an odd one, still not entirely sure what its purpose and semantics are, 9 | // but if we don't save it then the unlock notification for the music track 10 | // THE TOP (unlocked at 300km mileage) pops up at the start of every credit 11 | // even if its music unlock bit is set and round-tripped. 12 | 13 | lastMileageReward: number; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/model/weeklyMissions.ts: -------------------------------------------------------------------------------- 1 | export interface WeeklyMissions { 2 | weeklyReset: Date; 3 | weeklyMissionLeft: number; 4 | weeklyProgressLeft: number; 5 | weeklyParamsLeft: number; 6 | weeklyMissionRight: number; 7 | weeklyProgressRight: number; 8 | weeklyParamsRight: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/idz/userdb/request/checkTeamName.ts: -------------------------------------------------------------------------------- 1 | export interface CheckTeamNameRequest { 2 | type: "check_team_name_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/createAutoTeam.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface CreateAutoTeamRequest { 4 | type: "create_auto_team_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | field_0008: number; 8 | field_000C: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/idz/userdb/request/createProfile.ts: -------------------------------------------------------------------------------- 1 | import { Car } from "../model/car"; 2 | import { Chara } from "../model/chara"; 3 | import { AimeId } from "../../../model"; 4 | 5 | export interface CreateProfileRequest { 6 | type: "create_profile_req"; 7 | aimeId: AimeId; 8 | version: number; 9 | luid: string; 10 | name: string; 11 | field_0034: number; 12 | car: Car; 13 | chara: Chara; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/request/createTeam.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface CreateTeamRequest { 4 | type: "create_team_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | teamName: string; // len 0x20 8 | field_0028: number; // u16 9 | field_002C: number; // u32 (but only holds a u8) 10 | nameBg: number; // u8 11 | field_0032: number; // u16 12 | prevTeamId: number; // u32 13 | pcbId: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/idz/userdb/request/discoverProfile.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface DiscoverProfileRequest { 4 | type: "discover_profile_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/request/load2on2.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { AimeId } from "../../../model"; 4 | 5 | export interface Load2on2InfoRequest { 6 | type: "load_2on2_info_req"; 7 | field_0002: number; 8 | aimeId: AimeId; 9 | teamId: ExtId; 10 | } 11 | 12 | export interface Load2on2RankingPointsRequest { 13 | type: "load_2on2_ranking_points_req"; 14 | field_0002: number; 15 | aimeId: AimeId; 16 | teamId: ExtId; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadConfig.ts: -------------------------------------------------------------------------------- 1 | export interface LoadConfigRequestA { 2 | type: "load_config_A_req"; 3 | } 4 | 5 | export interface LoadConfigRequestB { 6 | type: "load_config_B_req"; 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadEventInfo.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadEventInfoRequest { 4 | type: "load_event_info_req"; 5 | aimeId: AimeId; 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadGacha.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadGachaRequest { 4 | type: "load_gacha_req"; 5 | aimeId: AimeId; 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadGarage.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadGarageRequest { 4 | type: "load_garage_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | fetchOffset: number; 8 | field_000A: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadGeneralReward.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadGeneralRewardRequest { 4 | type: "load_general_reward_req"; 5 | aimeId: AimeId; 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadGhost.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGhostRequest { 2 | type: "load_ghost_req"; 3 | field_0002: number; // u16 4 | field_0004: number; // u16 5 | field_0008: number; // u32 6 | field_000C: number; // u16 7 | field_000E: number; // u16 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadProfile.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadProfileRequest { 4 | type: "load_profile_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | luid: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadRewardTable.ts: -------------------------------------------------------------------------------- 1 | export interface LoadRewardTableRequest { 2 | type: "load_reward_table_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadServerList.ts: -------------------------------------------------------------------------------- 1 | export interface LoadServerListRequest { 2 | type: "load_server_list_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadStocker.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LoadStockerRequest { 4 | type: "load_stocker_req"; 5 | aimeId: AimeId; 6 | version: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadTeam.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | 4 | export interface LoadTeamRequest { 5 | type: "load_team_req"; 6 | aimeId: number; 7 | version: number; 8 | teamExtId?: ExtId; 9 | } 10 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadTeamRanking.ts: -------------------------------------------------------------------------------- 1 | export interface LoadTeamRankingRequest { 2 | type: "load_team_ranking_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/loadTopTen.ts: -------------------------------------------------------------------------------- 1 | import { ExtId, RouteNo } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { AimeId } from "../../../model"; 4 | 5 | export interface LoadTopTenRequestSelector { 6 | routeNo: RouteNo; 7 | minTimestamp: Date; 8 | } 9 | 10 | export interface LoadTopTenRequest { 11 | type: "load_top_ten_req"; 12 | version: number; 13 | field_2: number; 14 | selectors: LoadTopTenRequestSelector[]; 15 | field_C4: number; 16 | field_C5: number; 17 | field_C6: number; 18 | aimeId?: AimeId; 19 | teamId?: ExtId; 20 | } 21 | -------------------------------------------------------------------------------- /src/idz/userdb/request/lockGarage.ts: -------------------------------------------------------------------------------- 1 | export interface LockGarageRequest { 2 | type: "lock_garage_request"; 3 | field_0004: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/request/lockProfile.ts: -------------------------------------------------------------------------------- 1 | export interface LockProfileRequest { 2 | type: "lock_profile_req"; 3 | aimeId: number; 4 | pcbId: string; 5 | field_0018: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/request/lockProfileExtend.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface LockProfileExtendRequest { 4 | type: "lock_profile_extend_req"; 5 | aimeId: AimeId; 6 | luid: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveExpedition.ts: -------------------------------------------------------------------------------- 1 | export interface SaveExpeditionRequest { 2 | type: "save_expedition_req"; 3 | field_0004: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveGarage.ts: -------------------------------------------------------------------------------- 1 | import { Car } from "../model/car"; 2 | import { AimeId } from "../../../model"; 3 | 4 | export interface SaveGarageRequest { 5 | type: "save_garage_req"; 6 | version: number; 7 | aimeId: AimeId; 8 | car: Car; 9 | field_0068: number[]; 10 | field_0080: number; 11 | field_0081: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveNewCar.ts: -------------------------------------------------------------------------------- 1 | import { Car } from "../model/car"; 2 | import { AimeId } from "../../../model"; 3 | 4 | export interface SaveNewCarRequest { 5 | type: "save_new_car_req"; 6 | aimeId: AimeId; 7 | version: number; 8 | luid: string; 9 | car: Car; 10 | field_0080: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveProfile.ts: -------------------------------------------------------------------------------- 1 | import { BackgroundCode, CourseNo, StampCode, TitleCode } from "../model/base"; 2 | import { Car } from "../model/car"; 3 | import { MissionState } from "../model/mission"; 4 | import { Settings } from "../model/settings"; 5 | import { SelectedStamps } from "../model/stamps"; 6 | import { Story } from "../model/story"; 7 | import { Tickets } from "../model/tickets"; 8 | import { Unlocks } from "../model/unlocks"; 9 | import { WeeklyMissions } from "../model/weeklyMissions"; 10 | import { AimeId } from "../../../model"; 11 | 12 | export interface SaveProfileRequest { 13 | type: "save_profile_req"; 14 | aimeId: AimeId; 15 | version: number; 16 | lv: number; 17 | exp: number; 18 | fame: number; 19 | dpoint: number; 20 | mileage: number; 21 | title: TitleCode; 22 | titles: Set; 23 | background: BackgroundCode; 24 | coursePlays: Map; 25 | missions: MissionState; 26 | car: Car; 27 | story: Story; 28 | unlocks: Unlocks; 29 | tickets: Tickets; 30 | settings: Settings; 31 | selectedStamps?: SelectedStamps; 32 | stamps?: Set; 33 | weeklyMissions?: WeeklyMissions; 34 | } 35 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveSettings.ts: -------------------------------------------------------------------------------- 1 | import { Settings } from "../model/settings"; 2 | import { AimeId } from "../../../model"; 3 | 4 | export interface SaveSettingsRequest { 5 | type: "save_settings_req"; 6 | aimeId: AimeId; 7 | version: number; 8 | dpoint: number; // ?? why 9 | settings: Settings; 10 | field_0010: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveStocker.ts: -------------------------------------------------------------------------------- 1 | import { BackgroundCode, MyCharaCode, StampCode } from "../model/base"; 2 | import { CarSelector } from "../model/car"; 3 | import { Chara } from "../model/chara"; 4 | import { SelectedStamps } from "../model/stamps"; 5 | import { AimeId } from "../../../model"; 6 | 7 | export interface SaveStockerRequest { 8 | type: "save_stocker_req"; 9 | aimeId: AimeId; 10 | version: number; 11 | selectedCar: CarSelector; 12 | backgrounds: Set; 13 | chara: Chara; 14 | myChara?: Set; 15 | selectedStamps?: SelectedStamps; 16 | stamps?: Set; 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveTeamBanner.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | 4 | export interface SaveTeamBannerRequest { 5 | type: "save_team_banner_req"; 6 | teamExtId: ExtId; 7 | version: number; 8 | nameBg: number; 9 | nameFx: number; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveTimeAttack.ts: -------------------------------------------------------------------------------- 1 | import { TimeAttackScore } from "../model/timeAttack"; 2 | import { AimeId } from "../../../model"; 3 | 4 | export interface SaveTimeAttackRequest { 5 | type: "save_time_attack_req"; 6 | aimeId: AimeId; 7 | version: number; 8 | dayNight: number; 9 | payload: TimeAttackScore; 10 | field_0002: number; // u16, always 1 11 | field_0008: number; // u32 12 | field_0012: number; // u8 13 | field_0015: number; // u8 14 | field_005D: number; // u8 15 | field_005E: number; // u16 16 | field_0060: number; // u16 17 | } 18 | -------------------------------------------------------------------------------- /src/idz/userdb/request/saveTopic.ts: -------------------------------------------------------------------------------- 1 | export interface SaveTopicRequest { 2 | type: "save_topic_req"; 3 | aimeId?: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/request/unknownA.ts: -------------------------------------------------------------------------------- 1 | export interface UnknownRequestA { 2 | type: "unknown_A_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/unlockProfile.ts: -------------------------------------------------------------------------------- 1 | export interface UnlockProfileRequest { 2 | type: "unlock_profile_req"; 3 | aimeId: number; 4 | pcbId: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateExpedition.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateExpeditionRequest { 2 | type: "update_expedition_req"; 3 | expeditionRequestType: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateProvisionalStoreRank.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateProvisionalStoreRankRequest { 2 | type: "update_provisional_store_rank_req"; 3 | aimeId: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateResult.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateResultRequest { 2 | type: "update_result_req"; 3 | field_0002: number; 4 | field_0004: number; 5 | field_0008: number; 6 | field_000C: number; 7 | field_0010: number; 8 | field_0014: number; 9 | field_0016: number; 10 | field_0018: number; 11 | field_0019: number; 12 | field_001A: number; 13 | field_001C: number; 14 | field_0020: number; 15 | field_0024: number; 16 | } 17 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateStoryClearNum.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateStoryClearNumRequest { 2 | type: "update_story_clear_num_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateTeamLeader.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { AimeId } from "../../../model"; 4 | 5 | export interface UpdateTeamLeaderRequest { 6 | type: "update_team_leader_req"; 7 | aimeId: AimeId; 8 | version: number; 9 | teamExtId: ExtId; 10 | field_000C: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateTeamMember.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | import { AimeId } from "../../../model"; 4 | 5 | export interface UpdateTeamMemberRequest { 6 | type: "update_team_member_req"; 7 | action: "add" | "remove"; 8 | aimeId: AimeId; 9 | version: number; 10 | teamExtId: ExtId; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateTeamPoints.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateTeamPointsRequest { 2 | type: "update_team_points_req"; 3 | field_0004: number; 4 | field_0008: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateUiReport.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUiReportRequest { 2 | type: "update_ui_report_req"; 3 | field_02: number; 4 | field_04: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/request/updateUserLog.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUserLogRequest { 2 | type: "update_user_log_req"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/response/_team.ts: -------------------------------------------------------------------------------- 1 | import { Team, TeamMember } from "../model/team"; 2 | 3 | export interface BaseTeamResponse { 4 | team: Team; 5 | members: TeamMember[]; 6 | // giga TODO 7 | } 8 | -------------------------------------------------------------------------------- /src/idz/userdb/response/checkTeamName.ts: -------------------------------------------------------------------------------- 1 | export interface CheckTeamNameResponse { 2 | type: "check_team_name_res"; 3 | status: number; // Anything other than 4 is success 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/createAutoTeam.ts: -------------------------------------------------------------------------------- 1 | import { BaseTeamResponse } from "./_team"; 2 | 3 | export interface CreateAutoTeamResponse extends BaseTeamResponse { 4 | type: "create_auto_team_res"; 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/response/createProfile.ts: -------------------------------------------------------------------------------- 1 | import { AimeId } from "../../../model"; 2 | 3 | export interface CreateProfileResponse { 4 | type: "create_profile_res"; 5 | aimeId: AimeId; 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/response/createTeam.ts: -------------------------------------------------------------------------------- 1 | import { ExtId } from "../model/base"; 2 | import { Team } from "../model/team"; 3 | 4 | export interface CreateTeamResponse { 5 | type: "create_team_res"; 6 | status: number; // 0 is success, 1 is failure 7 | teamExtId: ExtId; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/response/discoverProfile.ts: -------------------------------------------------------------------------------- 1 | export interface DiscoverProfileResponse { 2 | type: "discover_profile_res"; 3 | exists: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/generic.ts: -------------------------------------------------------------------------------- 1 | export interface GenericResponse { 2 | type: "generic_res"; 3 | status?: number; 4 | // a bunch of other stuff here! total size is 0x20 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/response/load2on2.ts: -------------------------------------------------------------------------------- 1 | export interface Load2on2InfoResponse { 2 | type: "load_2on2_info_res"; 3 | // TODO? 4 | } 5 | 6 | export interface Load2on2RankingPointsResponse { 7 | type: "load_2on2_ranking_points_res"; 8 | // TODO? 9 | } 10 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadConfig.ts: -------------------------------------------------------------------------------- 1 | export interface LoadConfigResponseA { 2 | type: "load_config_A_res"; 3 | status: number; 4 | serverVersion: number; 5 | } 6 | 7 | export interface LoadConfigResponseB { 8 | type: "load_config_B_res"; 9 | status: number; 10 | } 11 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadEventInfo.ts: -------------------------------------------------------------------------------- 1 | export interface LoadEventInfoResponse { 2 | type: "load_event_info_res"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGacha.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGachaResponse { 2 | type: "load_gacha_res"; 3 | awardedToday: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGarage.ts: -------------------------------------------------------------------------------- 1 | import { Car } from "../model/car"; 2 | 3 | export interface LoadGarageResponse { 4 | type: "load_garage_res"; 5 | cars: Car[]; // max 10 6 | } 7 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGeneralReward.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGeneralRewardItem { 2 | field_04: string; // 40 chars max 3 | field_2C: number; // payload? 4 | field_38: number; // u8 5 | field_39: number; // u8 6 | field_3C: number[]; // u32 * 4 7 | } 8 | 9 | export interface LoadGeneralRewardResponse { 10 | type: "load_general_reward_res"; 11 | items: LoadGeneralRewardItem[]; 12 | } 13 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGeneralReward1.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGeneralRewardItem { 2 | field_04: string; // 40 chars max 3 | field_2C: number; // payload? 4 | field_38: number; // u8 5 | field_39: number; // u8 6 | field_3C: number[]; // u32 * 4 7 | } 8 | 9 | export interface LoadGeneralRewardResponse1 { 10 | type: "load_general_reward_res"; 11 | format: 1; 12 | items: LoadGeneralRewardItem[]; 13 | } 14 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGeneralReward2.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGeneralRewardResponse2 { 2 | type: "load_general_reward_res"; 3 | format: 2; 4 | // TBD 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadGhost.ts: -------------------------------------------------------------------------------- 1 | export interface LoadGhostResponse { 2 | type: "load_ghost_res"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadRewardTable.ts: -------------------------------------------------------------------------------- 1 | export interface LoadRewardTableResponse { 2 | type: "load_reward_table_res"; 3 | // TODO 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadServerList.ts: -------------------------------------------------------------------------------- 1 | export interface LoadServerListResponse { 2 | type: "load_server_list_res"; 3 | status: number; 4 | userDb: { 5 | addr: string; 6 | tcp: number; 7 | http: number; 8 | }; 9 | matchAddr: string; 10 | matchPort: { 11 | tcp: number; 12 | udpSend: number; 13 | udpRecv: number; 14 | }; 15 | tagMatchPort: { 16 | tcp: number; 17 | udpSend: number; 18 | udpRecv: number; 19 | }; 20 | event: { 21 | addr: string; 22 | tcp: number; 23 | }; 24 | screenshot: { 25 | addr: string; 26 | tcp: number; 27 | }; 28 | pingReturn: string; 29 | echo1: { 30 | addr: string; 31 | udp: number; 32 | }; 33 | echo2: { 34 | addr: string; 35 | udp: number; 36 | }; 37 | newsUrl: string; 38 | reportErrorUrl: string; 39 | } 40 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadStocker.ts: -------------------------------------------------------------------------------- 1 | import { BackgroundCode, MyCharaCode } from "../model/base"; 2 | 3 | export interface LoadStockerResponse { 4 | type: "load_stocker_res"; 5 | status: number; 6 | backgrounds: Set; 7 | myChara: Set; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadTeam.ts: -------------------------------------------------------------------------------- 1 | import { BaseTeamResponse } from "./_team"; 2 | 3 | export interface LoadTeamResponse extends BaseTeamResponse { 4 | type: "load_team_res"; 5 | } 6 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadTeamRanking.ts: -------------------------------------------------------------------------------- 1 | export interface LoadTeamRankingResponse { 2 | type: "load_team_ranking_res"; 3 | // TODO 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/loadTopTen.ts: -------------------------------------------------------------------------------- 1 | import { RouteNo } from "../model/base"; 2 | import { TimeAttackScore } from "../model/timeAttack"; 3 | 4 | export interface LoadTopTenResponseRow { 5 | field_00: number; 6 | field_0E: boolean; 7 | field_0F: boolean; 8 | field_10: number; 9 | driverName: string; 10 | shopName: string; 11 | team: { 12 | name: string; 13 | nameBg: number; 14 | nameFx: number; 15 | }; 16 | field_7C: number; 17 | field_7D: number; 18 | ta: TimeAttackScore; 19 | } 20 | 21 | export interface LoadTopTenResponseCourse { 22 | routeNo: RouteNo; 23 | field_02: number; 24 | rows: LoadTopTenResponseRow[]; 25 | } 26 | 27 | export interface LoadTopTenResponseTrailer { 28 | // Something team related... 29 | yearMonth: number; 30 | courseId: number; 31 | isNight: boolean; 32 | totalMsec: number; 33 | name: string; 34 | } 35 | 36 | export interface LoadTopTenResponse { 37 | type: "load_top_ten_res"; 38 | courseCount: number; 39 | courses: LoadTopTenResponseCourse[]; 40 | trailers: LoadTopTenResponseTrailer[]; 41 | } 42 | -------------------------------------------------------------------------------- /src/idz/userdb/response/lockProfile.ts: -------------------------------------------------------------------------------- 1 | export type LockAccountStatus = "locked" | "unlocked" | "obsolete"; 2 | 3 | export interface LockProfileResponse { 4 | type: "lock_profile_res"; 5 | status: LockAccountStatus; 6 | field_001A: number; 7 | lockExpiry: Date; 8 | } 9 | -------------------------------------------------------------------------------- /src/idz/userdb/response/lockProfileExtend.ts: -------------------------------------------------------------------------------- 1 | export interface LockProfileExtendResponse { 2 | type: "lock_profile_extend_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/saveExpedition.ts: -------------------------------------------------------------------------------- 1 | export interface SaveExpeditionResponse { 2 | type: "save_expedition_res"; 3 | // tera TODO 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/saveGarage.ts: -------------------------------------------------------------------------------- 1 | export interface SaveGarageResponse { 2 | type: "save_garage_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/saveNewCar.ts: -------------------------------------------------------------------------------- 1 | export interface SaveNewCarResponse { 2 | type: "save_new_car_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/saveTimeAttack.ts: -------------------------------------------------------------------------------- 1 | export interface SaveTimeAttackResponse { 2 | type: "save_time_attack_res"; 3 | } 4 | -------------------------------------------------------------------------------- /src/idz/userdb/response/saveTopic.ts: -------------------------------------------------------------------------------- 1 | export interface SaveTopicResponse { 2 | type: "save_topic_res"; 3 | // mega TODO 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/unlockProfile.ts: -------------------------------------------------------------------------------- 1 | export interface UnlockProfileResponse { 2 | type: "unlock_profile_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/updateExpedition.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateExpeditionResponse { 2 | type: "update_expedition_res"; 3 | expeditionType: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/updateProvisionalStoreRank.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateProvisionalStoreRankResponseRow { 2 | field_0000: number; 3 | field_0004: number; 4 | field_0010: string; 5 | field_003B: string; 6 | } 7 | 8 | export interface UpdateProvisionalStoreRankResponse { 9 | type: "update_provisional_store_rank_res"; 10 | rows: UpdateProvisionalStoreRankResponseRow[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/idz/userdb/response/updateStoryClearNum.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateStoryClearNumResponse { 2 | type: "update_story_clear_num_res"; 3 | // TODO, looks like a table of 9 * 10 u32 fields 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/updateTeamLeader.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateTeamLeaderResponse { 2 | type: "update_team_leader_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/idz/userdb/response/updateTeamMember.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateTeamMemberResponse { 2 | type: "update_team_member_res"; 3 | status: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/model.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes } from "crypto"; 2 | 3 | /** 4 | * An internal database id. 5 | * 6 | * We don't have any say over the protocols that we are implementing, and we 7 | * would also like our internal data store to adhere to a consistent set of 8 | * design principles. This type defines a fully opaque primary key data type 9 | * for database records which should not be exposed to external clients under 10 | * normal circumstances. Clients outside the SQL DB (or other persistent data 11 | * storage) driver should make no assumptions about its structure or actual 12 | * underlying data type. 13 | * 14 | * Database entities presented to external clients must be identified using 15 | * alternative external identifiers in formats that are acceptable to those 16 | * external systems. 17 | */ 18 | export type Id = string & { __type: T }; 19 | 20 | export type AimeId = number & { __aimeId: null }; 21 | 22 | /** Generate a random 32-bit ID for use in external protocol messages */ 23 | export function generateExtId(): number { 24 | const buf = randomBytes(4); 25 | 26 | buf[0] &= 0x7f; // Force number to be non-negative 27 | 28 | return buf.readUInt32BE(0); 29 | } 30 | -------------------------------------------------------------------------------- /src/sql/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api"; 2 | export * from "./sqlite"; 3 | -------------------------------------------------------------------------------- /src/sql/sqlite.test.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from "./api"; 2 | import { openSqlite } from "./sqlite"; 3 | 4 | async function violateFk(txn: Transaction) { 5 | await txn.raw("create table foo (id number primary key)"); 6 | await txn.raw("create table bar (foo_id integer references foo(id))"); 7 | await txn.raw("insert into bar (foo_id) values (1)"); 8 | } 9 | 10 | test("FK enforcement", async () => { 11 | const db = openSqlite(":memory:"); 12 | const promise = db.transaction(violateFk); 13 | 14 | expect(promise).rejects.toMatchObject({ 15 | message: "FOREIGN KEY constraint failed", 16 | }); 17 | }); 18 | 19 | test("FK violation detection", async () => { 20 | const db = openSqlite(":memory:"); 21 | const promise = db.maintenance(violateFk); 22 | 23 | expect(promise).rejects.toMatchObject({ 24 | fkViolations: [ 25 | { 26 | fkid: BigInt(0), 27 | parent: "foo", 28 | rowid: BigInt(1), 29 | table: "bar", 30 | }, 31 | ], 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/util/stream/index.ts: -------------------------------------------------------------------------------- 1 | import IoByteStream from "./stream"; 2 | 3 | export * from "./types"; 4 | export default IoByteStream; 5 | -------------------------------------------------------------------------------- /src/util/stream/stream.ts: -------------------------------------------------------------------------------- 1 | import { Duplex } from "stream"; 2 | 3 | import makeReader from "./reader"; 4 | import { ByteStream } from "./types"; 5 | import makeWriter from "./writer"; 6 | 7 | export default class IoByteStream implements ByteStream { 8 | private _stm?: Duplex; 9 | private readonly _read: (nbytes: number) => Promise; 10 | private readonly _write: (buf: Buffer) => Promise; 11 | 12 | constructor(stm: Duplex) { 13 | this._stm = stm; 14 | this._read = makeReader(stm); 15 | this._write = makeWriter(stm); 16 | } 17 | 18 | close() { 19 | if (this._stm !== undefined) { 20 | this._stm.destroy(); 21 | } 22 | 23 | this._stm = undefined; 24 | } 25 | 26 | read(nbytes: number): Promise { 27 | if (this._stm === undefined) { 28 | throw new Error("Stream is closed"); 29 | } 30 | 31 | return this._read(nbytes); 32 | } 33 | 34 | write(buf: Buffer): Promise { 35 | if (this._stm === undefined) { 36 | throw new Error("Stream is closed"); 37 | } 38 | 39 | return this._write(buf); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/util/stream/types.ts: -------------------------------------------------------------------------------- 1 | export interface ReadableByteStream { 2 | close(): void; 3 | 4 | read(nbytes: number): Promise; 5 | } 6 | 7 | export interface WritableByteStream { 8 | close(): void; 9 | 10 | write(buf: Buffer): Promise; 11 | } 12 | 13 | export type ByteStream = ReadableByteStream & WritableByteStream; 14 | -------------------------------------------------------------------------------- /src/util/stream/writer.ts: -------------------------------------------------------------------------------- 1 | import { Writable } from "stream"; 2 | 3 | export default function makeWriter(stm: Writable) { 4 | let busy = false; 5 | 6 | return function write(buf: Buffer): Promise { 7 | return new Promise((resolve, reject) => { 8 | if (busy) { 9 | return reject(new Error("Already writing")); 10 | } 11 | 12 | busy = true; 13 | 14 | stm.write(buf, error => { 15 | busy = false; 16 | 17 | if (error !== undefined) { 18 | reject(error); 19 | } else { 20 | resolve(); 21 | } 22 | }); 23 | }); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | pushd %~dp0 4 | 5 | where /q node 6 | if errorlevel 1 ( 7 | echo NodeJS does not appear to be installed. 8 | echo Please install the latest LTS version from https://nodejs.org/ 9 | 10 | goto end 11 | ) 12 | 13 | where /q npm 14 | if errorlevel 1 ( 15 | echo The npm command does not appear to be available. 16 | echo Please ensure that npm was installed during NodeJS setup. 17 | 18 | goto end 19 | ) 20 | 21 | if not exist node_modules ( 22 | echo The server's dependencies will now be installed. 23 | echo This process requires an internet connection and may take some time. 24 | echo. 25 | 26 | pause 27 | call npm install 28 | 29 | if errorlevel 1 ( 30 | if exist bin rmdir /q /s bin 31 | if exist node_modules rmdir /q /s node_modules 32 | 33 | echo Installation failed. Cannot continue. 34 | 35 | goto end 36 | ) 37 | 38 | echo Installation successful, launching server. 39 | echo. 40 | ) 41 | 42 | rem Project Diva requires TLSv1.0 43 | 44 | set DEBUG=app:* 45 | node --tls-min-v1.0 .\bin\index.js 46 | 47 | :end 48 | echo. 49 | pause 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "lib": ["es2017", "esnext.asynciterable"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "outDir": "./bin/", 8 | "strictNullChecks": true, 9 | "target": "esnext", 10 | "typeRoots": ["./node_modules/@types", "./types"] 11 | }, 12 | "include": ["./src/"], 13 | "exclude": ["./src/**/*.test.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /types/sql-bricks-postgres/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "sql-bricks-postgres" { 2 | import * as sql from "sql-bricks"; 3 | export * from "sql-bricks"; 4 | 5 | interface OnConflictClause { 6 | doNothing(): sql.Statement; 7 | 8 | doUpdate(colNames: string[]): sql.Statement; 9 | } 10 | 11 | interface LimitClause extends sql.SelectStatement { 12 | offset(value: number): sql.SelectStatement; 13 | } 14 | 15 | export interface PgInsertStatement extends sql.InsertStatement { 16 | onConflict(...colNames: string[]): OnConflictClause; 17 | } 18 | 19 | export interface PgSelectStatement extends sql.SelectStatement { 20 | limit(value: number): LimitClause; 21 | } 22 | 23 | export interface PgSqlBricksFn extends sql.SqlBricksFn { 24 | insert(tbl?: string, ...values: any[]): PgInsertStatement; 25 | 26 | select(...columns: Array): PgSelectStatement; 27 | select(columns: string[] | sql.SelectStatement[]): PgSelectStatement; 28 | } 29 | 30 | const PgSqlBricks: PgSqlBricksFn; 31 | export default PgSqlBricks; 32 | } 33 | --------------------------------------------------------------------------------