diff --git a/src/idz/encoder/loadConfig2.ts b/src/idz/encoder/loadConfig2.ts index 0af1d3c..89f4cb7 100644 --- a/src/idz/encoder/loadConfig2.ts +++ b/src/idz/encoder/loadConfig2.ts @@ -1,9 +1,9 @@ import { LoadConfigResponse2 } from "../response/loadConfig2"; export function loadConfig2(res: LoadConfigResponse2) { - const buf = Buffer.alloc(0x230); + const buf = Buffer.alloc(0x0230); - buf.writeInt16LE(0x0065, 0x0000); + buf.writeInt16LE(0x00ac, 0x0000); buf.writeInt8(res.status, 0x0002); return buf; diff --git a/src/idz/handler/_team.ts b/src/idz/handler/_team.ts new file mode 100644 index 0000000..0cdb3d4 --- /dev/null +++ b/src/idz/handler/_team.ts @@ -0,0 +1,27 @@ +import { CreateTeamRequest } from "../request/createTeam"; +import { LoadTeamRequest } from "../request/loadTeam"; +import { CreateTeamResponse } from "../response/createTeam"; +import { LoadTeamResponse } from "../response/loadTeam"; +import { World } from "../world"; + +export function _team( + w: World, + req: CreateTeamRequest | LoadTeamRequest +): CreateTeamResponse | LoadTeamResponse { + const bits = { + name: "ASS GENTLEMEN", + members: [ + { + name: "てすと", + lv: 69, + monthPoints: 1234, + }, + ], + }; + + if (req.type === "create_team_req") { + return { type: "create_team_res", ...bits }; + } else { + return { type: "load_team_res", ...bits }; + } +} diff --git a/src/idz/handler/accountLock.ts b/src/idz/handler/accountLock.ts new file mode 100644 index 0000000..76d883c --- /dev/null +++ b/src/idz/handler/accountLock.ts @@ -0,0 +1,15 @@ +import { AccountLockRequest } from "../request/accountLock"; +import { AccountLockResponse } from "../response/accountLock"; +import { World } from "../world"; + +export function accountLock( + w: World, + req: AccountLockRequest +): AccountLockResponse { + return { + type: "account_lock_res", + field_0018: 1, + field_001A: -1, + field_001C: new Date(Date.now() + 3600000), + }; +} diff --git a/src/idz/handler/accountUnlock.ts b/src/idz/handler/accountUnlock.ts new file mode 100644 index 0000000..eda2559 --- /dev/null +++ b/src/idz/handler/accountUnlock.ts @@ -0,0 +1,13 @@ +import { AccountUnlockRequest } from "../request/accountUnlock"; +import { AccountUnlockResponse } from "../response/accountUnlock"; +import { World } from "../world"; + +export function accountUnlock( + w: World, + req: AccountUnlockRequest +): AccountUnlockResponse { + return { + type: "account_unlock_res", + status: 1, + }; +} diff --git a/src/idz/handler/createProfile.ts b/src/idz/handler/createProfile.ts new file mode 100644 index 0000000..a31fe03 --- /dev/null +++ b/src/idz/handler/createProfile.ts @@ -0,0 +1,13 @@ +import { CreateProfileRequest } from "../request/createProfile"; +import { GenericResponse } from "../response/generic"; +import { World } from "../world"; + +export function createProfile( + w: World, + req: CreateProfileRequest +): GenericResponse { + return { + type: "generic_res", + status: 1, + }; +} diff --git a/src/idz/handler/discoverProfile.ts b/src/idz/handler/discoverProfile.ts new file mode 100644 index 0000000..762c7a9 --- /dev/null +++ b/src/idz/handler/discoverProfile.ts @@ -0,0 +1,13 @@ +import { DiscoverProfileRequest } from "../request/discoverProfile"; +import { DiscoverProfileResponse } from "../response/discoverProfile"; +import { World } from "../world"; + +export function discoverProfile( + w: World, + req: DiscoverProfileRequest +): DiscoverProfileResponse { + return { + type: "discover_profile_res", + result: true, + }; +} diff --git a/src/idz/handler/index.ts b/src/idz/handler/index.ts new file mode 100644 index 0000000..10279c5 --- /dev/null +++ b/src/idz/handler/index.ts @@ -0,0 +1,91 @@ +import { Request } from "../request"; +import { Response } from "../response"; +import { World } from "../world"; +import { accountLock } from "./accountLock"; +import { accountUnlock } from "./accountUnlock"; +import { createProfile } from "./createProfile"; +import { _team } from "./_team"; +import { load2on2 } from "./load2on2"; +import { loadConfig } from "./loadConfig"; +import { loadConfig2 } from "./loadConfig2"; +import { discoverProfile } from "./discoverProfile"; +import { loadGeneralReward } from "./loadGeneralReward"; +import { loadProfile } from "./loadProfile"; +import { loadReward as loadRewardTable } from "./loadRewardTable"; +import { loadServerList } from "./loadServerList"; +import { loadStocker } from "./loadStocker"; +import { saveExpedition } from "./saveExpedition"; +import { updateProvisionalStoreRank } from "./updateProvisionalStoreRank"; +import { saveProfile } from "./saveProfile"; +import { saveSettings } from "./saveSettings"; +import { updateStoryClearNum } from "./updateStoryClearNum"; +import { saveTopic } from "./saveTopic"; + +export function dispatch(w: World, req: Request): Response { + switch (req.type) { + case "account_lock_req": + return accountLock(w, req); + + case "account_unlock_req": + return accountUnlock(w, req); + + case "create_profile_req": + return createProfile(w, req); + + case "create_team_req": + return _team(w, req); + + case "load_2on2_req": + return load2on2(w, req); + + case "load_config_req": + return loadConfig(w, req); + + case "load_config_v2_req": + return loadConfig2(w, req); + + case "discover_profile_req": + return discoverProfile(w, req); + + case "load_general_reward_req": + return loadGeneralReward(w, req); + + case "load_profile_req": + return loadProfile(w, req); + + case "load_reward_table_req": + return loadRewardTable(w, req); + + case "load_server_list_req": + return loadServerList(w, req); + + case "load_stocker_req": + return loadStocker(w, req); + + case "load_team_req": + return _team(w, req); + + case "save_expedition_req": + return saveExpedition(w, req); + + case "update_provisional_store_rank_req": + return updateProvisionalStoreRank(w, req); + + case "save_profile_req": + return saveProfile(w, req); + + case "save_settings_req": + return saveSettings(w, req); + + case "update_story_clear_num_req": + return updateStoryClearNum(w, req); + + case "save_topic_req": + return saveTopic(w, req); + + default: + const exhaustCheck: never = req; + + throw new Error(`Unhandled message ${req["type"]}`); + } +} diff --git a/src/idz/handler/load2on2.ts b/src/idz/handler/load2on2.ts new file mode 100644 index 0000000..cef5a6d --- /dev/null +++ b/src/idz/handler/load2on2.ts @@ -0,0 +1,9 @@ +import { Load2on2Request } from "../request/load2on2"; +import { Load2on2Response } from "../response/load2on2"; +import { World } from "../world"; + +export function load2on2(w: World, req: Load2on2Request): Load2on2Response { + return { + type: "load_2on2_res", + }; +} diff --git a/src/idz/handler/loadConfig.ts b/src/idz/handler/loadConfig.ts new file mode 100644 index 0000000..f6370ff --- /dev/null +++ b/src/idz/handler/loadConfig.ts @@ -0,0 +1,13 @@ +import { LoadConfigRequest } from "../request/loadConfig"; +import { LoadConfigResponse } from "../response/loadConfig"; +import { World } from "../world"; + +export function loadConfig( + w: World, + req: LoadConfigRequest +): LoadConfigResponse { + return { + type: "load_config_res", + status: 1, + }; +} diff --git a/src/idz/handler/loadConfig2.ts b/src/idz/handler/loadConfig2.ts new file mode 100644 index 0000000..ccb46dd --- /dev/null +++ b/src/idz/handler/loadConfig2.ts @@ -0,0 +1,13 @@ +import { LoadConfigRequest2 } from "../request/loadConfig2"; +import { LoadConfigResponse2 } from "../response/loadConfig2"; +import { World } from "../world"; + +export function loadConfig2( + w: World, + req: LoadConfigRequest2 +): LoadConfigResponse2 { + return { + type: "load_config_v2_res", + status: 1, + }; +} diff --git a/src/idz/handler/loadGeneralReward.ts b/src/idz/handler/loadGeneralReward.ts new file mode 100644 index 0000000..6538474 --- /dev/null +++ b/src/idz/handler/loadGeneralReward.ts @@ -0,0 +1,14 @@ +import { LoadGeneralRewardRequest } from "../request/loadGeneralReward"; +import { GenericResponse } from "../response/generic"; +import { World } from "../world"; + +export function loadGeneralReward( + w: World, + req: LoadGeneralRewardRequest +): GenericResponse { + // A non-generic response is also accepted, but why bother + return { + type: "generic_res", + status: 1, // not even checked but let's be consistent + }; +} diff --git a/src/idz/handler/loadProfile.ts b/src/idz/handler/loadProfile.ts new file mode 100644 index 0000000..a156c22 --- /dev/null +++ b/src/idz/handler/loadProfile.ts @@ -0,0 +1,18 @@ +import { LoadProfileRequest } from "../request/loadProfile"; +import { LoadProfileResponse2 } from "../response/loadProfile2"; +import { World } from "../world"; + +export function loadProfile( + w: World, + req: LoadProfileRequest +): LoadProfileResponse2 { + return { + type: "load_profile_v2_res", + name: "てすと", + profileId: 0x11223344, + lv: 69, + fame: 1234, + dpoint: 54321, + teamId: 0x22334455, + }; +} diff --git a/src/idz/handler/loadRewardTable.ts b/src/idz/handler/loadRewardTable.ts new file mode 100644 index 0000000..3c49852 --- /dev/null +++ b/src/idz/handler/loadRewardTable.ts @@ -0,0 +1,12 @@ +import { LoadRewardTableRequest } from "../request/loadRewardTable"; +import { LoadRewardTableResponse } from "../response/loadRewardTable"; +import { World } from "../world"; + +export function loadReward( + w: World, + req: LoadRewardTableRequest +): LoadRewardTableResponse { + return { + type: "load_reward_table_res", + }; +} diff --git a/src/idz/handler/loadServerList.ts b/src/idz/handler/loadServerList.ts new file mode 100644 index 0000000..2ff78b5 --- /dev/null +++ b/src/idz/handler/loadServerList.ts @@ -0,0 +1,52 @@ +import { hostname } from "os"; + +import { LoadServerListRequest } from "../request/loadServerList"; +import { LoadServerListResponse } from "../response/loadServerList"; +import { World } from "../world"; + +export function loadServerList( + w: World, + req: LoadServerListRequest +): LoadServerListResponse { + const myHost = hostname(); + + return { + type: "load_server_list_res", + status: 1, + userDb: { + addr: myHost, + tcp: 10000, + http: 10001, + }, + matchAddr: myHost, + matchPort: { + tcp: 10002, + udpSend: 10003, + udpRecv: 10004, + }, + tagMatchPort: { + tcp: 10005, + udpSend: 10006, + udpRecv: 10007, + }, + event: { + addr: myHost, + tcp: 10008, + }, + screenshot: { + addr: myHost, + tcp: 10009, + }, + pingReturn: myHost, + echo1: { + addr: myHost, + udp: 10010, + }, + echo2: { + addr: myHost, + udp: 10011, + }, + newsUrl: `http://${myHost}:10012/news`, + reportErrorUrl: `http://${myHost}:10013/error`, + }; +} diff --git a/src/idz/handler/loadStocker.ts b/src/idz/handler/loadStocker.ts new file mode 100644 index 0000000..e0efd18 --- /dev/null +++ b/src/idz/handler/loadStocker.ts @@ -0,0 +1,13 @@ +import { LoadStockerRequest } from "../request/loadStocker"; +import { LoadStockerResponse } from "../response/loadStocker"; +import { World } from "../world"; + +export function loadStocker( + w: World, + req: LoadStockerRequest +): LoadStockerResponse { + return { + type: "load_stocker_res", + status: 1, + }; +} diff --git a/src/idz/handler/saveExpedition.ts b/src/idz/handler/saveExpedition.ts new file mode 100644 index 0000000..4ecca5a --- /dev/null +++ b/src/idz/handler/saveExpedition.ts @@ -0,0 +1,20 @@ +import { SaveExpeditionRequest } from "../request/saveExpedition"; +import { GenericResponse } from "../response/generic"; +import { SaveExpeditionResponse } from "../response/saveExpedition"; +import { World } from "../world"; + +export function saveExpedition( + w: World, + req: SaveExpeditionRequest +): GenericResponse | SaveExpeditionResponse { + if (req.field_0004 === 0) { + return { + type: "generic_res", + status: 0, + }; + } else { + return { + type: "save_expedition_res", + }; + } +} diff --git a/src/idz/handler/saveProfile.ts b/src/idz/handler/saveProfile.ts new file mode 100644 index 0000000..823d144 --- /dev/null +++ b/src/idz/handler/saveProfile.ts @@ -0,0 +1,13 @@ +import { SaveProfileRequest } from "../request/saveProfile"; +import { GenericResponse } from "../response/generic"; +import { World } from "../world"; + +export function saveProfile( + w: World, + req: SaveProfileRequest +): GenericResponse { + return { + type: "generic_res", + status: 1, + }; +} diff --git a/src/idz/handler/saveSettings.ts b/src/idz/handler/saveSettings.ts new file mode 100644 index 0000000..a5bc1c8 --- /dev/null +++ b/src/idz/handler/saveSettings.ts @@ -0,0 +1,13 @@ +import { SaveSettingsRequest } from "../request/saveSettings"; +import { GenericResponse } from "../response/generic"; +import { World } from "../world"; + +export function saveSettings( + w: World, + req: SaveSettingsRequest +): GenericResponse { + return { + type: "generic_res", + status: 1, // ignored but whatever + }; +} diff --git a/src/idz/handler/saveTopic.ts b/src/idz/handler/saveTopic.ts new file mode 100644 index 0000000..56ce121 --- /dev/null +++ b/src/idz/handler/saveTopic.ts @@ -0,0 +1,9 @@ +import { SaveTopicRequest } from "../request/saveTopic"; +import { SaveTopicResponse } from "../response/saveTopic"; +import { World } from "../world"; + +export function saveTopic(w: World, req: SaveTopicRequest): SaveTopicResponse { + return { + type: "save_topic_res", + }; +} diff --git a/src/idz/handler/updateProvisionalStoreRank.ts b/src/idz/handler/updateProvisionalStoreRank.ts new file mode 100644 index 0000000..6d703f1 --- /dev/null +++ b/src/idz/handler/updateProvisionalStoreRank.ts @@ -0,0 +1,13 @@ +import { UpdateProvisionalStoreRankRequest } from "../request/updateProvisionalStoreRank"; +import { UpdateProvisionalStoreRankResponse } from "../response/updateProvisionalStoreRank"; +import { World } from "../world"; + +export function updateProvisionalStoreRank( + w: World, + req: UpdateProvisionalStoreRankRequest +): UpdateProvisionalStoreRankResponse { + return { + type: "update_provisional_store_rank_res", + rows: [], + }; +} diff --git a/src/idz/handler/updateStoryClearNum.ts b/src/idz/handler/updateStoryClearNum.ts new file mode 100644 index 0000000..6aa0d2d --- /dev/null +++ b/src/idz/handler/updateStoryClearNum.ts @@ -0,0 +1,12 @@ +import { UpdateStoryClearNumRequest } from "../request/updateStoryClearNum"; +import { UpdateStoryClearNumResponse } from "../response/updateStoryClearNum"; +import { World } from "../world"; + +export function updateStoryClearNum( + w: World, + req: UpdateStoryClearNumRequest +): UpdateStoryClearNumResponse { + return { + type: "update_story_clear_num_res", + }; +} diff --git a/src/idz/index.ts b/src/idz/index.ts index 84b3447..f35a94e 100644 --- a/src/idz/index.ts +++ b/src/idz/index.ts @@ -1,8 +1,10 @@ import { Socket } from "net"; -import { hostname } from "os"; +import { dispatch } from "./handler"; import setup from "./setup"; -import { Response } from "./response"; +import { World } from "./world"; + +const world = new World(); export default async function idz(socket: Socket) { const { input, output } = setup(socket); @@ -11,231 +13,7 @@ export default async function idz(socket: Socket) { try { for await (const req of input) { - let res: Response; - - switch (req.type) { - case "account_lock_req": - res = { - type: "account_lock_res", - field_0018: 1, - field_001A: -1, - field_001C: new Date(Date.now() + 3600000), - }; - - break; - - case "account_unlock_req": - res = { - type: "account_unlock_res", - status: 1, - }; - - break; - - case "create_profile_req": - res = { - type: "generic_res", - status: 1, - }; - - break; - - case "create_team_req": - res = { - type: "create_team_res", - name: "ASS GENTLEMEN", - members: [], - }; - - break; - - case "load_2on2_req": - res = { - type: "load_2on2_res", - }; - - break; - - case "load_config_req": - res = { - type: "load_config_res", - status: 1, - }; - - break; - - case "load_config_v2_req": - res = { - type: "load_config_v2_res", - status: 1, - }; - - break; - - case "discover_profile_req": - res = { - type: "discover_profile_res", - result: true, - }; - - break; - - case "load_general_reward_req": - // A non-generic response is also accepted, but why bother? - res = { - type: "generic_res", - status: 1, // not even checked but let's be consistent - }; - - break; - - case "load_profile_req": - res = { - type: "load_profile_v2_res", - name: "てすと", - profileId: 0x11223344, - lv: 69, - fame: 1234, - dpoint: 54321, - teamId: 0x22334455, - }; - - break; - - case "load_reward_table_req": - res = { - type: "load_reward_table_res", - }; - - break; - - case "load_server_list_req": - const myHost = hostname(); - - res = { - type: "load_server_list_res", - status: 1, - userDb: { - addr: myHost, - tcp: 10000, - http: 10001, - }, - matchAddr: myHost, - matchPort: { - tcp: 10002, - udpSend: 10003, - udpRecv: 10004, - }, - tagMatchPort: { - tcp: 10005, - udpSend: 10006, - udpRecv: 10007, - }, - event: { - addr: myHost, - tcp: 10008, - }, - screenshot: { - addr: myHost, - tcp: 10009, - }, - pingReturn: myHost, - echo1: { - addr: myHost, - udp: 10010, - }, - echo2: { - addr: myHost, - udp: 10011, - }, - newsUrl: `http://${myHost}:10012/news`, - reportErrorUrl: `http://${myHost}:10013/error`, - }; - - break; - - case "load_stocker_req": - res = { - type: "load_stocker_res", - status: 1, - }; - - break; - - case "load_team_req": - res = { - type: "load_team_res", - name: "ASS GENTLEMEN", - members: [ - { - name: "てすと", - lv: 69, - monthPoints: 1234, - }, - ], - }; - - break; - - case "save_expedition_req": - if (req.field_0004 === 0) { - res = { - type: "generic_res", - status: 0, - }; - } else { - res = { - type: "save_expedition_res", - }; - } - - break; - - case "update_provisional_store_rank_req": - res = { - type: "update_provisional_store_rank_res", - rows: [], - }; - - break; - - case "save_profile_req": - res = { - type: "generic_res", - status: 1, - }; - - break; - - case "save_settings_req": - res = { - type: "generic_res", - status: 1, // ignored but whatever - }; - - break; - - case "update_story_clear_num_req": - res = { - type: "update_story_clear_num_res", - }; - - break; - - case "save_topic_req": - res = { - type: "save_topic_res", - }; - - break; - - default: - const exhaustCheck: never = req; - - throw new Error(`Unhandled message ${req["type"]}`); - } - - output.write(res); + output.write(dispatch(world, req)); } } catch (e) { console.log("Idz: Error", e); diff --git a/src/idz/world.ts b/src/idz/world.ts new file mode 100644 index 0000000..ef92ed8 --- /dev/null +++ b/src/idz/world.ts @@ -0,0 +1,3 @@ +export class World { + // Hand out references to some sort of backing store Repository objects here. +}