implement GC Ep1&2 trial edition
This commit is contained in:
@@ -51,6 +51,9 @@ struct Client {
|
|||||||
ENCRYPTED_SEND_FUNCTION_CALL = 0x0800,
|
ENCRYPTED_SEND_FUNCTION_CALL = 0x0800,
|
||||||
// Client supports send_function_call but does not actually run the code
|
// Client supports send_function_call but does not actually run the code
|
||||||
SEND_FUNCTION_CALL_CHECKSUM_ONLY = 0x1000,
|
SEND_FUNCTION_CALL_CHECKSUM_ONLY = 0x1000,
|
||||||
|
// Client is GC Trial Edition, and therefore uses V2 encryption instead of
|
||||||
|
// V3, and doesn't support some commands
|
||||||
|
GC_TRIAL_EDITION = 0x2000,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
|||||||
+34
-21
@@ -376,8 +376,10 @@ struct C_LegacyLogin_BB_04 {
|
|||||||
// 05 = Server down for maintenance (108)
|
// 05 = Server down for maintenance (108)
|
||||||
// 06 = Incorrect password (127)
|
// 06 = Incorrect password (127)
|
||||||
// Any other nonzero value = Generic failure (101)
|
// Any other nonzero value = Generic failure (101)
|
||||||
// The client config field in this command is only used by V3 clients. newserv
|
// The client config field in this command is ignored by pre-V3 clients as well
|
||||||
// sends it anyway to clients on earlier versions, but they ignore it.
|
// as Episodes 1&2 Trial Edition. All other V3 clients save it as opaque data to
|
||||||
|
// be returned in a 9E or 9F command later. newserv sends the client config
|
||||||
|
// anyway to clients that ignore it.
|
||||||
// Client will respond with a 96 command, but only the first time it receives
|
// Client will respond with a 96 command, but only the first time it receives
|
||||||
// this command - for later 04 commands, the client will still update its client
|
// this command - for later 04 commands, the client will still update its client
|
||||||
// config but will not respond. Changing the security data at any time seems ok,
|
// config but will not respond. Changing the security data at any time seems ok,
|
||||||
@@ -433,8 +435,8 @@ struct S_MenuEntry {
|
|||||||
le_uint16_t flags; // should be 0x0F04
|
le_uint16_t flags; // should be 0x0F04
|
||||||
ptext<CharT, EntryLength> text;
|
ptext<CharT, EntryLength> text;
|
||||||
};
|
};
|
||||||
struct S_MenuEntry_PC_BB_07_1F : S_MenuEntry<char16_t, 17> { };
|
struct S_MenuEntry_PC_BB_07_1F : S_MenuEntry<char16_t, 0x11> { };
|
||||||
struct S_MenuEntry_DC_V3_07_1F : S_MenuEntry<char, 18> { };
|
struct S_MenuEntry_DC_V3_07_1F : S_MenuEntry<char, 0x12> { };
|
||||||
|
|
||||||
// 08 (C->S): Request game list
|
// 08 (C->S): Request game list
|
||||||
// No arguments
|
// No arguments
|
||||||
@@ -578,8 +580,9 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 {
|
|||||||
// All commands after this command will be encrypted with PSO V2 encryption on
|
// All commands after this command will be encrypted with PSO V2 encryption on
|
||||||
// PC, or PSO V3 encryption on V3.
|
// PC, or PSO V3 encryption on V3.
|
||||||
// V3 clients will respond with a DB command the first time they receive a 17
|
// V3 clients will respond with a DB command the first time they receive a 17
|
||||||
// command in any online session; after the first time, they will respond with a
|
// command in any online session, with the exception of Episodes 1&2 trial
|
||||||
// 9E. Non-V3 clients will respond with a 9D.
|
// edition (which responds with a 9A). After the first time, V3 clients will
|
||||||
|
// respond with a 9E. Non-V3 clients will respond with a 9D.
|
||||||
// The copyright field in the structure must contain the following text:
|
// The copyright field in the structure must contain the following text:
|
||||||
// "DreamCast Port Map. Copyright SEGA Enterprises. 1999"
|
// "DreamCast Port Map. Copyright SEGA Enterprises. 1999"
|
||||||
|
|
||||||
@@ -1307,8 +1310,9 @@ struct C_Register_BB_9C {
|
|||||||
// displayed if the header.flag field is zero. If header.flag is nonzero, the
|
// displayed if the header.flag field is zero. If header.flag is nonzero, the
|
||||||
// client proceeds with the login procedure by sending a 9D/9E.
|
// client proceeds with the login procedure by sending a 9D/9E.
|
||||||
|
|
||||||
// 9D (C->S): Log in without client config (PC)
|
// 9D (C->S): Log in without client config (PC/GC)
|
||||||
// Not used on V3 - the client sends 9E instead.
|
// Not used on most versions of V3 - the client sends 9E instead. The one
|
||||||
|
// type of PSO V3 that uses 9D is the Trial Edition of Episodes 1&2.
|
||||||
// The extended version of this command is sent if the client has not yet
|
// The extended version of this command is sent if the client has not yet
|
||||||
// received an 04 (in which case the extended fields are blank) or if the client
|
// received an 04 (in which case the extended fields are blank) or if the client
|
||||||
// selected the Meet User option, in which case it specifies the requested lobby
|
// selected the Meet User option, in which case it specifies the requested lobby
|
||||||
@@ -1322,7 +1326,7 @@ struct C_Login_MeetUserExtension {
|
|||||||
ptext<CharT, 0x20> target_player_name;
|
ptext<CharT, 0x20> target_player_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct C_Login_PC_9D {
|
struct C_Login_PC_GC_9D {
|
||||||
le_uint32_t player_tag; // 0x00010000 if guild card is set (via 04)
|
le_uint32_t player_tag; // 0x00010000 if guild card is set (via 04)
|
||||||
le_uint32_t guild_card_number; // 0xFFFFFFFF if not set
|
le_uint32_t guild_card_number; // 0xFFFFFFFF if not set
|
||||||
le_uint64_t unused;
|
le_uint64_t unused;
|
||||||
@@ -1338,7 +1342,7 @@ struct C_Login_PC_9D {
|
|||||||
ptext<char, 0x30> access_key2; // On XB, this is the XBL user ID
|
ptext<char, 0x30> access_key2; // On XB, this is the XBL user ID
|
||||||
ptext<char, 0x10> name;
|
ptext<char, 0x10> name;
|
||||||
};
|
};
|
||||||
struct C_LoginExtended_PC_9D : C_Login_PC_9D {
|
struct C_LoginExtended_PC_GC_9D : C_Login_PC_GC_9D {
|
||||||
C_Login_MeetUserExtension<char16_t> extension;
|
C_Login_MeetUserExtension<char16_t> extension;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1346,7 +1350,7 @@ struct C_LoginExtended_PC_9D : C_Login_PC_9D {
|
|||||||
// The extended version of this command is used in the same circumstances as
|
// The extended version of this command is used in the same circumstances as
|
||||||
// when PSO PC uses the extended version of the 9D command.
|
// when PSO PC uses the extended version of the 9D command.
|
||||||
|
|
||||||
struct C_Login_GC_9E : C_Login_PC_9D {
|
struct C_Login_GC_9E : C_Login_PC_GC_9D {
|
||||||
union ClientConfigFields {
|
union ClientConfigFields {
|
||||||
ClientConfig cfg;
|
ClientConfig cfg;
|
||||||
parray<uint8_t, 0x20> data;
|
parray<uint8_t, 0x20> data;
|
||||||
@@ -1383,6 +1387,8 @@ struct C_LoginExtended_BB_9E {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 9F (S->C): Request client config / security data (V3/BB)
|
// 9F (S->C): Request client config / security data (V3/BB)
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition, nor any
|
||||||
|
// pre-V3 PSO versions.
|
||||||
// No arguments
|
// No arguments
|
||||||
|
|
||||||
// 9F (C->S): Client config / security data response (V3/BB)
|
// 9F (C->S): Client config / security data response (V3/BB)
|
||||||
@@ -1476,6 +1482,8 @@ struct S_QuestMenuEntry_BB_A2_A4 : S_QuestMenuEntry<char16_t, 0x7A> { };
|
|||||||
// specific to that quest. The structure here represents the only instance I've
|
// specific to that quest. The structure here represents the only instance I've
|
||||||
// seen so far.
|
// seen so far.
|
||||||
// The server will respond with an AB command.
|
// The server will respond with an AB command.
|
||||||
|
// This command is likely never sent by PSO GC Episodes 1&2 Trial Edition,
|
||||||
|
// because the following command (AB) is definitely not valid on that version.
|
||||||
|
|
||||||
struct C_UpdateQuestStatistics_AA {
|
struct C_UpdateQuestStatistics_AA {
|
||||||
le_uint16_t quest_internal_id;
|
le_uint16_t quest_internal_id;
|
||||||
@@ -1489,6 +1497,7 @@ struct C_UpdateQuestStatistics_AA {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// AB (S->C): Confirm update quest statistics
|
// AB (S->C): Confirm update quest statistics
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition.
|
||||||
// TODO: Does this command have a different meaning in Episode 3? Is it used at
|
// TODO: Does this command have a different meaning in Episode 3? Is it used at
|
||||||
// all there, or is the handler an undeleted vestige from Episodes 1&2?
|
// all there, or is the handler an undeleted vestige from Episodes 1&2?
|
||||||
|
|
||||||
@@ -1508,6 +1517,7 @@ struct S_ConfirmUpdateQuestStatistics_AB {
|
|||||||
// which starts the quest for all players at (approximately) the same time.
|
// which starts the quest for all players at (approximately) the same time.
|
||||||
// Sending this command to a GC client when it is not waiting to start a quest
|
// Sending this command to a GC client when it is not waiting to start a quest
|
||||||
// will cause it to crash.
|
// will cause it to crash.
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition.
|
||||||
|
|
||||||
// AD: Invalid command
|
// AD: Invalid command
|
||||||
// AE: Invalid command
|
// AE: Invalid command
|
||||||
@@ -1939,6 +1949,7 @@ struct C_GBAGameRequest_V3_D7 {
|
|||||||
|
|
||||||
// D7 (S->C): Unknown (V3/BB)
|
// D7 (S->C): Unknown (V3/BB)
|
||||||
// No arguments
|
// No arguments
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition.
|
||||||
// On PSO V3, this command does... something. The command isn't *completely*
|
// On PSO V3, this command does... something. The command isn't *completely*
|
||||||
// ignored: it sets a global state variable, but it's not clear what that
|
// ignored: it sets a global state variable, but it's not clear what that
|
||||||
// variable does. That variable is also set when a D7 is sent by the client, so
|
// variable does. That variable is also set when a D7 is sent by the client, so
|
||||||
@@ -1950,6 +1961,7 @@ struct C_GBAGameRequest_V3_D7 {
|
|||||||
// The server should respond with a D8 command (described below).
|
// The server should respond with a D8 command (described below).
|
||||||
|
|
||||||
// D8 (S->C): Info board contents (V3/BB)
|
// D8 (S->C): Info board contents (V3/BB)
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition.
|
||||||
|
|
||||||
// Command is a list of these; header.flag is the entry count. There should be
|
// Command is a list of these; header.flag is the entry count. There should be
|
||||||
// one entry for each player in the current lobby/game.
|
// one entry for each player in the current lobby/game.
|
||||||
@@ -1967,6 +1979,7 @@ struct S_InfoBoardEntry_V3_D8 : S_InfoBoardEntry_D8<char> { };
|
|||||||
|
|
||||||
// DA (S->C): Change lobby event (V3/BB)
|
// DA (S->C): Change lobby event (V3/BB)
|
||||||
// header.flag = new event number; no other arguments.
|
// header.flag = new event number; no other arguments.
|
||||||
|
// This command is not valid on PSO GC Episodes 1&2 Trial Edition.
|
||||||
|
|
||||||
// DB (C->S): Verify license (V3/BB)
|
// DB (C->S): Verify license (V3/BB)
|
||||||
// Server should respond with a 9A command.
|
// Server should respond with a 9A command.
|
||||||
@@ -3007,10 +3020,10 @@ struct G_EnemyDropItemRequest_6x60 {
|
|||||||
// 68: Telepipe/Ryuker
|
// 68: Telepipe/Ryuker
|
||||||
// 69: Unknown (supported; game only)
|
// 69: Unknown (supported; game only)
|
||||||
// 6A: Unknown (supported; game only; not valid on Episode 3)
|
// 6A: Unknown (supported; game only; not valid on Episode 3)
|
||||||
// 6B: Unknown (used while loading into game)
|
// 6B: Sync enemy state (used while loading into game)
|
||||||
// 6C: Unknown (used while loading into game)
|
// 6C: Sync object state (used while loading into game)
|
||||||
// 6D: Unknown (used while loading into game)
|
// 6D: Sync item state (used while loading into game)
|
||||||
// 6E: Unknown (used while loading into game)
|
// 6E: Sync flag state (used while loading into game)
|
||||||
// 6F: Unknown (used while loading into game)
|
// 6F: Unknown (used while loading into game)
|
||||||
// 70: Unknown (used while loading into game)
|
// 70: Unknown (used while loading into game)
|
||||||
// 71: Unknown (used while loading into game)
|
// 71: Unknown (used while loading into game)
|
||||||
@@ -3087,12 +3100,12 @@ struct G_BoxItemDropRequest_6xA2 {
|
|||||||
// AA: Episode 2 boss actions (not valid on PC or Episode 3)
|
// AA: Episode 2 boss actions (not valid on PC or Episode 3)
|
||||||
// AB: Create lobby chair (not valid on PC)
|
// AB: Create lobby chair (not valid on PC)
|
||||||
// AC: Unknown (not valid on PC)
|
// AC: Unknown (not valid on PC)
|
||||||
// AD: Unknown (not valid on PC or Episode 3)
|
// AD: Unknown (not valid on PC, Episode 3, or GC Trial Edition)
|
||||||
// AE: Set chair state? (sent by existing clients at join time; not valid on PC)
|
// AE: Set chair state? (sent by existing clients at join time; not valid on PC or GC Trial Edition)
|
||||||
// AF: Turn in lobby chair (not valid on PC)
|
// AF: Turn in lobby chair (not valid on PC or GC Trial Edition)
|
||||||
// B0: Move in lobby chair (not valid on PC)
|
// B0: Move in lobby chair (not valid on PC or GC Trial Edition)
|
||||||
// B1: Unknown (not valid on PC)
|
// B1: Unknown (not valid on PC or GC Trial Edition)
|
||||||
// B2: Unknown (not valid on PC)
|
// B2: Unknown (not valid on PC or GC Trial Edition)
|
||||||
// B3: Unknown (Episode 3 only)
|
// B3: Unknown (Episode 3 only)
|
||||||
// B4: Unknown (Episode 3 only)
|
// B4: Unknown (Episode 3 only)
|
||||||
// B5: Episode 3 game setup menu state sync
|
// B5: Episode 3 game setup menu state sync
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ static HandlerResult process_server_pc_v3_patch_02_17(shared_ptr<ServerState> s,
|
|||||||
return HandlerResult::Type::SUPPRESS;
|
return HandlerResult::Type::SUPPRESS;
|
||||||
|
|
||||||
} else if (session.version == GameVersion::PC) {
|
} else if (session.version == GameVersion::PC) {
|
||||||
C_Login_PC_9D cmd;
|
C_Login_PC_GC_9D cmd;
|
||||||
if (session.remote_guild_card_number == 0) {
|
if (session.remote_guild_card_number == 0) {
|
||||||
cmd.player_tag = 0xFFFF0000;
|
cmd.player_tag = 0xFFFF0000;
|
||||||
cmd.guild_card_number = 0xFFFFFFFF;
|
cmd.guild_card_number = 0xFFFFFFFF;
|
||||||
|
|||||||
+2
-2
@@ -269,8 +269,8 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
|
|||||||
if (command != 0x9D) {
|
if (command != 0x9D) {
|
||||||
throw runtime_error("command is not 9D");
|
throw runtime_error("command is not 9D");
|
||||||
}
|
}
|
||||||
const auto& cmd = check_size_t<C_Login_PC_9D>(
|
const auto& cmd = check_size_t<C_Login_PC_GC_9D>(
|
||||||
data, sizeof(C_Login_PC_9D), sizeof(C_LoginExtended_PC_9D));
|
data, sizeof(C_Login_PC_GC_9D), sizeof(C_LoginExtended_PC_GC_9D));
|
||||||
license = session->server->state->license_manager->verify_pc(
|
license = session->server->state->license_manager->verify_pc(
|
||||||
stoul(cmd.serial_number, nullptr, 16), cmd.access_key);
|
stoul(cmd.serial_number, nullptr, 16), cmd.access_key);
|
||||||
sub_version = cmd.sub_version;
|
sub_version = cmd.sub_version;
|
||||||
|
|||||||
+25
-10
@@ -76,6 +76,9 @@ void process_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ServerBehavior::LOGIN_SERVER_GC_TRIAL_EDITION:
|
||||||
|
c->flags |= Client::Flag::GC_TRIAL_EDITION;
|
||||||
|
[[fallthrough]];
|
||||||
case ServerBehavior::LOGIN_SERVER:
|
case ServerBehavior::LOGIN_SERVER:
|
||||||
send_server_init(s, c, true, false);
|
send_server_init(s, c, true, false);
|
||||||
if (s->pre_lobby_event) {
|
if (s->pre_lobby_event) {
|
||||||
@@ -85,6 +88,11 @@ void process_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c)
|
|||||||
|
|
||||||
case ServerBehavior::PATCH_SERVER_BB:
|
case ServerBehavior::PATCH_SERVER_BB:
|
||||||
c->flags |= Client::Flag::BB_PATCH;
|
c->flags |= Client::Flag::BB_PATCH;
|
||||||
|
send_server_init(s, c, false, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerBehavior::LOBBY_SERVER_GC_TRIAL_EDITION:
|
||||||
|
c->flags |= Client::Flag::GC_TRIAL_EDITION;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ServerBehavior::PATCH_SERVER_PC:
|
case ServerBehavior::PATCH_SERVER_PC:
|
||||||
case ServerBehavior::DATA_SERVER_BB:
|
case ServerBehavior::DATA_SERVER_BB:
|
||||||
@@ -319,12 +327,12 @@ void process_login_d_e_pc_v3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
// The client sends extra unused data the first time it sends these commands,
|
// The client sends extra unused data the first time it sends these commands,
|
||||||
// hence the odd check_size calls here
|
// hence the odd check_size calls here
|
||||||
|
|
||||||
const C_Login_PC_9D* base_cmd;
|
const C_Login_PC_GC_9D* base_cmd;
|
||||||
if (command == 0x9D) {
|
if (command == 0x9D) {
|
||||||
base_cmd = &check_size_t<C_Login_PC_9D>(data,
|
base_cmd = &check_size_t<C_Login_PC_GC_9D>(data,
|
||||||
sizeof(C_Login_PC_9D), sizeof(C_LoginExtended_PC_9D));
|
sizeof(C_Login_PC_GC_9D), sizeof(C_LoginExtended_PC_GC_9D));
|
||||||
if (base_cmd->is_extended) {
|
if (base_cmd->is_extended) {
|
||||||
const auto& cmd = check_size_t<C_LoginExtended_PC_9D>(data);
|
const auto& cmd = check_size_t<C_LoginExtended_PC_GC_9D>(data);
|
||||||
if (cmd.extension.menu_id == MenuID::LOBBY) {
|
if (cmd.extension.menu_id == MenuID::LOBBY) {
|
||||||
c->preferred_lobby_id = cmd.extension.preferred_lobby_id;
|
c->preferred_lobby_id = cmd.extension.preferred_lobby_id;
|
||||||
}
|
}
|
||||||
@@ -1119,12 +1127,15 @@ void process_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
send_quest_file(l->clients[x], dat_basename + ".dat", dat_basename,
|
send_quest_file(l->clients[x], dat_basename + ".dat", dat_basename,
|
||||||
*dat_contents, QuestFileType::ONLINE);
|
*dat_contents, QuestFileType::ONLINE);
|
||||||
|
|
||||||
// There is no such thing as command AC on PSO PC - quests just start
|
// There is no such thing as command AC on PSO V2 - quests just start
|
||||||
// immediately when they're done downloading. There are also no chunk
|
// immediately when they're done downloading. (This is also the case
|
||||||
// acknowledgements (C->S 13 commands) like there are on GC. So, for
|
// on V3 Trial Edition.) There are also no chunk acknowledgements
|
||||||
// PC clients, we can just not set the loading flag, since we never
|
// (C->S 13 commands) like there are on GC. So, for PC/Trial clients,
|
||||||
// need to check/clear it later.
|
// we can just not set the loading flag, since we never need to
|
||||||
if (l->clients[x]->version != GameVersion::PC) {
|
// check/clear it later.
|
||||||
|
if ((l->clients[x]->version != GameVersion::DC) &&
|
||||||
|
(l->clients[x]->version != GameVersion::PC) &&
|
||||||
|
!(l->clients[x]->flags & Client::Flag::GC_TRIAL_EDITION)) {
|
||||||
l->clients[x]->flags |= Client::Flag::LOADING_QUEST;
|
l->clients[x]->flags |= Client::Flag::LOADING_QUEST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1407,6 +1418,10 @@ void process_update_quest_statistics(shared_ptr<ServerState> s,
|
|||||||
shared_ptr<Client> c, uint16_t, uint32_t, const string& data) { // AA
|
shared_ptr<Client> c, uint16_t, uint32_t, const string& data) { // AA
|
||||||
const auto& cmd = check_size_t<C_UpdateQuestStatistics_AA>(data);
|
const auto& cmd = check_size_t<C_UpdateQuestStatistics_AA>(data);
|
||||||
|
|
||||||
|
if (c->flags & Client::Flag::GC_TRIAL_EDITION) {
|
||||||
|
throw runtime_error("trial edition client sent update quest stats command");
|
||||||
|
}
|
||||||
|
|
||||||
auto l = s->find_lobby(c->lobby_id);
|
auto l = s->find_lobby(c->lobby_id);
|
||||||
if (!l || !l->is_game() || !l->loading_quest.get() ||
|
if (!l || !l->is_game() || !l->loading_quest.get() ||
|
||||||
(l->loading_quest->internal_id != cmd.quest_internal_id)) {
|
(l->loading_quest->internal_id != cmd.quest_internal_id)) {
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ void ReplaySession::check_for_password(shared_ptr<const Event> ev) const {
|
|||||||
check_ak(cmd.access_key);
|
check_ak(cmd.access_key);
|
||||||
check_pw(cmd.password);
|
check_pw(cmd.password);
|
||||||
} else if (header.command == 0x9D) {
|
} else if (header.command == 0x9D) {
|
||||||
const auto& cmd = check_size_t<C_Login_PC_9D>(cmd_data, cmd_size,
|
const auto& cmd = check_size_t<C_Login_PC_GC_9D>(cmd_data, cmd_size,
|
||||||
sizeof(C_Login_PC_9D), sizeof(C_LoginExtended_PC_9D));
|
sizeof(C_Login_PC_GC_9D), sizeof(C_LoginExtended_PC_GC_9D));
|
||||||
check_ak(cmd.access_key);
|
check_ak(cmd.access_key);
|
||||||
check_ak(cmd.access_key2);
|
check_ak(cmd.access_key2);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-9
@@ -104,8 +104,7 @@ S_ServerInit_DC_PC_V3_02_17_91_9B prepare_server_init_contents_dc_pc_v3(
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_server_init_dc_pc_v3(shared_ptr<Client> c,
|
void send_server_init_dc_pc_v3(shared_ptr<Client> c, bool initial_connection) {
|
||||||
bool initial_connection) {
|
|
||||||
uint8_t command = initial_connection ? 0x17 : 0x02;
|
uint8_t command = initial_connection ? 0x17 : 0x02;
|
||||||
uint32_t server_key = random_object<uint32_t>();
|
uint32_t server_key = random_object<uint32_t>();
|
||||||
uint32_t client_key = random_object<uint32_t>();
|
uint32_t client_key = random_object<uint32_t>();
|
||||||
@@ -122,8 +121,13 @@ void send_server_init_dc_pc_v3(shared_ptr<Client> c,
|
|||||||
break;
|
break;
|
||||||
case GameVersion::GC:
|
case GameVersion::GC:
|
||||||
case GameVersion::XB:
|
case GameVersion::XB:
|
||||||
c->channel.crypt_out.reset(new PSOV3Encryption(server_key));
|
if (c->flags & Client::Flag::GC_TRIAL_EDITION) {
|
||||||
c->channel.crypt_in.reset(new PSOV3Encryption(client_key));
|
c->channel.crypt_out.reset(new PSOV2Encryption(server_key));
|
||||||
|
c->channel.crypt_in.reset(new PSOV2Encryption(client_key));
|
||||||
|
} else {
|
||||||
|
c->channel.crypt_out.reset(new PSOV3Encryption(server_key));
|
||||||
|
c->channel.crypt_in.reset(new PSOV3Encryption(client_key));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw invalid_argument("incorrect client version");
|
throw invalid_argument("incorrect client version");
|
||||||
@@ -1584,12 +1588,13 @@ void send_server_time(shared_ptr<Client> c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void send_change_event(shared_ptr<Client> c, uint8_t new_event) {
|
void send_change_event(shared_ptr<Client> c, uint8_t new_event) {
|
||||||
// THis command isn't supported on versions before V3
|
// This command isn't supported on versions before V3, nor on Trial Edition.
|
||||||
if ((c->version == GameVersion::GC) ||
|
if ((c->version == GameVersion::DC) ||
|
||||||
(c->version == GameVersion::XB) ||
|
(c->version == GameVersion::PC) ||
|
||||||
(c->version == GameVersion::BB)) {
|
(c->flags & Client::Flag::GC_TRIAL_EDITION)) {
|
||||||
send_command(c, 0xDA, new_event);
|
return;
|
||||||
}
|
}
|
||||||
|
send_command(c, 0xDA, new_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_change_event(shared_ptr<Lobby> l, uint8_t new_event) {
|
void send_change_event(shared_ptr<Lobby> l, uint8_t new_event) {
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ uint16_t flags_for_version(GameVersion version, int64_t sub_version) {
|
|||||||
return Client::Flag::NO_MESSAGE_BOX_CLOSE_CONFIRMATION |
|
return Client::Flag::NO_MESSAGE_BOX_CLOSE_CONFIRMATION |
|
||||||
Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY;
|
Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY;
|
||||||
|
|
||||||
|
// TODO: GC Ep1&2 trial edition uses sub_version 0x30, but also uses PSO V2
|
||||||
|
// encryption! Find a way to tell that version apart from the others before
|
||||||
|
// starting encryption (hopefully it connects on a port not shared by other
|
||||||
|
// versions).
|
||||||
case 0x30: // GC Ep1&2 JP v1.02, at least one version of PSO XB
|
case 0x30: // GC Ep1&2 JP v1.02, at least one version of PSO XB
|
||||||
case 0x31: // GC Ep1&2 US v1.00, GC US v1.01, GC EU v1.00, GC JP v1.00
|
case 0x31: // GC Ep1&2 US v1.00, GC US v1.01, GC EU v1.00, GC JP v1.00
|
||||||
case 0x34: // GC Ep1&2 JP v1.03
|
case 0x34: // GC Ep1&2 JP v1.03
|
||||||
@@ -114,8 +118,12 @@ const char* name_for_server_behavior(ServerBehavior behavior) {
|
|||||||
return "split_reconnect";
|
return "split_reconnect";
|
||||||
case ServerBehavior::LOGIN_SERVER:
|
case ServerBehavior::LOGIN_SERVER:
|
||||||
return "login_server";
|
return "login_server";
|
||||||
|
case ServerBehavior::LOGIN_SERVER_GC_TRIAL_EDITION:
|
||||||
|
return "login_server_gcte";
|
||||||
case ServerBehavior::LOBBY_SERVER:
|
case ServerBehavior::LOBBY_SERVER:
|
||||||
return "lobby_server";
|
return "lobby_server";
|
||||||
|
case ServerBehavior::LOBBY_SERVER_GC_TRIAL_EDITION:
|
||||||
|
return "lobby_server_gcte";
|
||||||
case ServerBehavior::DATA_SERVER_BB:
|
case ServerBehavior::DATA_SERVER_BB:
|
||||||
return "data_server_bb";
|
return "data_server_bb";
|
||||||
case ServerBehavior::PATCH_SERVER_PC:
|
case ServerBehavior::PATCH_SERVER_PC:
|
||||||
@@ -134,8 +142,12 @@ ServerBehavior server_behavior_for_name(const char* name) {
|
|||||||
return ServerBehavior::SPLIT_RECONNECT;
|
return ServerBehavior::SPLIT_RECONNECT;
|
||||||
} else if (!strcasecmp(name, "login_server") || !strcasecmp(name, "login")) {
|
} else if (!strcasecmp(name, "login_server") || !strcasecmp(name, "login")) {
|
||||||
return ServerBehavior::LOGIN_SERVER;
|
return ServerBehavior::LOGIN_SERVER;
|
||||||
|
} else if (!strcasecmp(name, "login_server_gcte") || !strcasecmp(name, "login_gcte")) {
|
||||||
|
return ServerBehavior::LOGIN_SERVER_GC_TRIAL_EDITION;
|
||||||
} else if (!strcasecmp(name, "lobby_server") || !strcasecmp(name, "lobby")) {
|
} else if (!strcasecmp(name, "lobby_server") || !strcasecmp(name, "lobby")) {
|
||||||
return ServerBehavior::LOBBY_SERVER;
|
return ServerBehavior::LOBBY_SERVER;
|
||||||
|
} else if (!strcasecmp(name, "lobby_server_gcte") || !strcasecmp(name, "lobby_gcte")) {
|
||||||
|
return ServerBehavior::LOBBY_SERVER_GC_TRIAL_EDITION;
|
||||||
} else if (!strcasecmp(name, "data_server_bb") || !strcasecmp(name, "data_server") || !strcasecmp(name, "data")) {
|
} else if (!strcasecmp(name, "data_server_bb") || !strcasecmp(name, "data_server") || !strcasecmp(name, "data")) {
|
||||||
return ServerBehavior::DATA_SERVER_BB;
|
return ServerBehavior::DATA_SERVER_BB;
|
||||||
} else if (!strcasecmp(name, "patch_server_pc") || !strcasecmp(name, "patch_pc")) {
|
} else if (!strcasecmp(name, "patch_server_pc") || !strcasecmp(name, "patch_pc")) {
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ enum class GameVersion {
|
|||||||
enum class ServerBehavior {
|
enum class ServerBehavior {
|
||||||
SPLIT_RECONNECT = 0,
|
SPLIT_RECONNECT = 0,
|
||||||
LOGIN_SERVER,
|
LOGIN_SERVER,
|
||||||
|
LOGIN_SERVER_GC_TRIAL_EDITION,
|
||||||
LOBBY_SERVER,
|
LOBBY_SERVER,
|
||||||
|
LOBBY_SERVER_GC_TRIAL_EDITION,
|
||||||
DATA_SERVER_BB,
|
DATA_SERVER_BB,
|
||||||
PATCH_SERVER_PC,
|
PATCH_SERVER_PC,
|
||||||
PATCH_SERVER_BB,
|
PATCH_SERVER_BB,
|
||||||
|
|||||||
@@ -23,14 +23,19 @@
|
|||||||
|
|
||||||
// Various versions of PSO hardcode these ports in the clients. Don't change
|
// Various versions of PSO hardcode these ports in the clients. Don't change
|
||||||
// these unless you don't want to support certain versions of PSO.
|
// these unless you don't want to support certain versions of PSO.
|
||||||
|
// TODO: GC Episodes 1&2 Trial Edition also uses port 9000, but a real
|
||||||
|
// version of PSO uses that port too. Figure out a way to differentiate
|
||||||
|
// between the two versions.
|
||||||
"gc-jp10": [9000, "gc", "login_server"],
|
"gc-jp10": [9000, "gc", "login_server"],
|
||||||
"gc-jp11": [9001, "gc", "login_server"],
|
"gc-jp11": [9001, "gc", "login_server"],
|
||||||
"gc-jpte": [9002, "gc", "login_server"],
|
"gc-jp3te": [9002, "gc", "login_server"],
|
||||||
"gc-jp3": [9003, "gc", "login_server"],
|
"gc-jp3": [9003, "gc", "login_server"],
|
||||||
|
"gc-us12t1": [9064, "gc", "login_server_gcte"],
|
||||||
"gc-us10": [9100, "pc", "split_reconnect"],
|
"gc-us10": [9100, "pc", "split_reconnect"],
|
||||||
"gc-us3": [9103, "gc", "login_server"],
|
"gc-us3": [9103, "gc", "login_server"],
|
||||||
"gc-eu10": [9200, "gc", "login_server"],
|
"gc-eu10": [9200, "gc", "login_server"],
|
||||||
"gc-eu11": [9201, "gc", "login_server"],
|
"gc-eu11": [9201, "gc", "login_server"],
|
||||||
|
"gc-us12t2": [9202, "gc", "login_server_gcte"],
|
||||||
"gc-eu3": [9203, "gc", "login_server"],
|
"gc-eu3": [9203, "gc", "login_server"],
|
||||||
"pc-login": [9300, "pc", "login_server"],
|
"pc-login": [9300, "pc", "login_server"],
|
||||||
"pc-patch": [10000, "patch", "patch_server_pc"],
|
"pc-patch": [10000, "patch", "patch_server_pc"],
|
||||||
@@ -60,10 +65,12 @@
|
|||||||
"gc-lobby": [9421, "gc", "lobby_server"],
|
"gc-lobby": [9421, "gc", "lobby_server"],
|
||||||
"bb-lobby": [9422, "bb", "lobby_server"],
|
"bb-lobby": [9422, "bb", "lobby_server"],
|
||||||
"xb-lobby": [9423, "xb", "lobby_server"],
|
"xb-lobby": [9423, "xb", "lobby_server"],
|
||||||
|
"gct-lobby": [9424, "gc", "lobby_server_gcte"],
|
||||||
"pc-proxy": [9520, "pc", "proxy_server"],
|
"pc-proxy": [9520, "pc", "proxy_server"],
|
||||||
"gc-proxy": [9521, "gc", "proxy_server"],
|
"gc-proxy": [9521, "gc", "proxy_server"],
|
||||||
"bb-proxy": [9522, "bb", "proxy_server"],
|
"bb-proxy": [9522, "bb", "proxy_server"],
|
||||||
"xb-proxy": [9523, "xb", "proxy_server"],
|
"xb-proxy": [9523, "xb", "proxy_server"],
|
||||||
|
// TODO: Implement proxy server for GC Trial Edition
|
||||||
"bb-data1": [12004, "bb", "data_server_bb"],
|
"bb-data1": [12004, "bb", "data_server_bb"],
|
||||||
"bb-data2": [12005, "bb", "data_server_bb"],
|
"bb-data2": [12005, "bb", "data_server_bb"],
|
||||||
},
|
},
|
||||||
|
|||||||
+6
-1
@@ -19,12 +19,14 @@
|
|||||||
"PortConfiguration": {
|
"PortConfiguration": {
|
||||||
"gc-jp10": [9000, "gc", "login_server"],
|
"gc-jp10": [9000, "gc", "login_server"],
|
||||||
"gc-jp11": [9001, "gc", "login_server"],
|
"gc-jp11": [9001, "gc", "login_server"],
|
||||||
"gc-jpte": [9002, "gc", "login_server"],
|
"gc-jp3te": [9002, "gc", "login_server"],
|
||||||
"gc-jp3": [9003, "gc", "login_server"],
|
"gc-jp3": [9003, "gc", "login_server"],
|
||||||
|
"gc-us12t1": [9064, "gc", "login_server_gcte"],
|
||||||
"gc-us10": [9100, "pc", "split_reconnect"],
|
"gc-us10": [9100, "pc", "split_reconnect"],
|
||||||
"gc-us3": [9103, "gc", "login_server"],
|
"gc-us3": [9103, "gc", "login_server"],
|
||||||
"gc-eu10": [9200, "gc", "login_server"],
|
"gc-eu10": [9200, "gc", "login_server"],
|
||||||
"gc-eu11": [9201, "gc", "login_server"],
|
"gc-eu11": [9201, "gc", "login_server"],
|
||||||
|
"gc-us12t2": [9202, "gc", "login_server_gcte"],
|
||||||
"gc-eu3": [9203, "gc", "login_server"],
|
"gc-eu3": [9203, "gc", "login_server"],
|
||||||
"pc-login": [9300, "pc", "login_server"],
|
"pc-login": [9300, "pc", "login_server"],
|
||||||
"pc-patch": [10000, "patch", "patch_server_pc"],
|
"pc-patch": [10000, "patch", "patch_server_pc"],
|
||||||
@@ -38,9 +40,12 @@
|
|||||||
"pc-lobby": [9420, "pc", "lobby_server"],
|
"pc-lobby": [9420, "pc", "lobby_server"],
|
||||||
"gc-lobby": [9421, "gc", "lobby_server"],
|
"gc-lobby": [9421, "gc", "lobby_server"],
|
||||||
"bb-lobby": [9422, "bb", "lobby_server"],
|
"bb-lobby": [9422, "bb", "lobby_server"],
|
||||||
|
"xb-lobby": [9423, "xb", "lobby_server"],
|
||||||
|
"gct-lobby": [9424, "gc", "lobby_server_gcte"],
|
||||||
"pc-proxy": [9520, "pc", "proxy_server"],
|
"pc-proxy": [9520, "pc", "proxy_server"],
|
||||||
"gc-proxy": [9521, "gc", "proxy_server"],
|
"gc-proxy": [9521, "gc", "proxy_server"],
|
||||||
"bb-proxy": [9522, "bb", "proxy_server"],
|
"bb-proxy": [9522, "bb", "proxy_server"],
|
||||||
|
"xb-proxy": [9523, "xb", "proxy_server"],
|
||||||
},
|
},
|
||||||
|
|
||||||
"ProxyDestinations-GC": {
|
"ProxyDestinations-GC": {
|
||||||
|
|||||||
Reference in New Issue
Block a user