Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
8bc602012e
|
|||
|
e0c34fe700
|
|||
|
cbe9747fd4
|
|||
|
de0104eec8
|
|||
|
c454068715
|
|||
|
d98e1f7478
|
|||
|
c497f64376
|
|||
|
5d43acd9a2
|
|||
|
90a1f0f938
|
|||
|
db52a15888
|
|||
|
71fc272133
|
|||
|
bef656077c
|
|||
|
e94fcf035e
|
|||
|
0abdb50eca
|
+40
-9
@@ -439,12 +439,14 @@ ChatCommandDefinition cc_bank(
|
|||||||
});
|
});
|
||||||
|
|
||||||
static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool is_bb_conversion) {
|
static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool is_bb_conversion) {
|
||||||
// TODO: We could support this in proxy sessions; we'd just have to handle the 61/30 correctly
|
// Allow $savechar in proxy sessions for character migration/testing.
|
||||||
|
// Keep $bbchar blocked in proxy sessions because it writes to BB account slots.
|
||||||
|
if (is_bb_conversion) {
|
||||||
a.check_is_proxy(false);
|
a.check_is_proxy(false);
|
||||||
|
}
|
||||||
a.check_is_game(false);
|
a.check_is_game(false);
|
||||||
|
|
||||||
auto s = a.c->require_server_state();
|
auto s = a.c->require_server_state();
|
||||||
auto l = a.c->require_lobby();
|
|
||||||
|
|
||||||
if (is_bb_conversion && is_ep3(a.c->version())) {
|
if (is_bb_conversion && is_ep3(a.c->version())) {
|
||||||
throw precondition_failed("$C6Episode 3 players\ncannot be converted\nto BB format");
|
throw precondition_failed("$C6Episode 3 players\ncannot be converted\nto BB format");
|
||||||
@@ -481,9 +483,14 @@ static asio::awaitable<void> server_command_bbchar_savechar(const Args& a, bool
|
|||||||
dest_account = a.c->login->account;
|
dest_account = a.c->login->account;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the client isn't BB, request the player info. (If they are BB, the server already has it)
|
// In direct sessions, request player info from the client.
|
||||||
|
// In proxy sessions, don't use the 61/30 request path; use the server-side
|
||||||
|
// character state already tracked for the proxied client.
|
||||||
GetPlayerInfoResult ch;
|
GetPlayerInfoResult ch;
|
||||||
if (a.c->version() == Version::BB_V4) {
|
if ((a.c->version() == Version::BB_V4) || a.c->proxy_session) {
|
||||||
|
if (is_ep3(a.c->version())) {
|
||||||
|
throw precondition_failed("$C6Proxy savechar for\nEpisode 3 is not\nimplemented yet");
|
||||||
|
}
|
||||||
ch.character = a.c->character_file();
|
ch.character = a.c->character_file();
|
||||||
ch.is_full_info = true;
|
ch.is_full_info = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1528,14 +1535,32 @@ ChatCommandDefinition cc_ln(
|
|||||||
ChatCommandDefinition cc_loadchar(
|
ChatCommandDefinition cc_loadchar(
|
||||||
{"$loadchar"},
|
{"$loadchar"},
|
||||||
+[](const Args& a) -> asio::awaitable<void> {
|
+[](const Args& a) -> asio::awaitable<void> {
|
||||||
a.check_is_proxy(false);
|
if (a.c->proxy_session && (a.c->version() == Version::BB_V4)) {
|
||||||
|
throw precondition_failed("$C6This command cannot\nbe used in proxy\nsessions in BB games");
|
||||||
|
}
|
||||||
a.check_is_game(false);
|
a.check_is_game(false);
|
||||||
if (a.check_permissions && a.c->login->account->check_flag(Account::Flag::IS_SHARED_ACCOUNT)) {
|
if (a.check_permissions && a.c->login->account->check_flag(Account::Flag::IS_SHARED_ACCOUNT)) {
|
||||||
throw precondition_failed("$C7This command cannot\nbe used on a shared\naccount");
|
throw precondition_failed("$C7This command cannot\nbe used on a shared\naccount");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s = a.c->require_server_state();
|
auto s = a.c->require_server_state();
|
||||||
auto l = a.c->require_lobby();
|
shared_ptr<Lobby> l;
|
||||||
|
if (a.c->proxy_session) {
|
||||||
|
if (!a.c->proxy_session->is_in_lobby) {
|
||||||
|
throw precondition_failed("$C6This command can\nonly be used from\nthe lobby");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l = a.c->require_lobby();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto send_proxy_lobby_refresh = [&]() {
|
||||||
|
auto temp_l = make_shared<Lobby>(s, 0xFFFFFFFF, false);
|
||||||
|
temp_l->block = 1;
|
||||||
|
temp_l->event = a.c->proxy_session ? a.c->proxy_session->lobby_event : 0;
|
||||||
|
temp_l->leader_id = a.c->lobby_client_id;
|
||||||
|
temp_l->clients.at(a.c->lobby_client_id) = a.c;
|
||||||
|
send_join_lobby(a.c, temp_l);
|
||||||
|
};
|
||||||
|
|
||||||
size_t index = stoull(a.text, nullptr, 0) - 1;
|
size_t index = stoull(a.text, nullptr, 0) - 1;
|
||||||
if (index >= s->num_backup_character_slots) {
|
if (index >= s->num_backup_character_slots) {
|
||||||
@@ -1568,7 +1593,7 @@ ChatCommandDefinition cc_loadchar(
|
|||||||
throw precondition_failed("Can\'t load character\ndata on this game\nversion");
|
throw precondition_failed("Can\'t load character\ndata on this game\nversion");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto send_set_extended_player_info = [&a, &s]<typename CharT>(const CharT& char_file) -> asio::awaitable<void> {
|
auto send_set_extended_player_info = [&a, &s, &send_proxy_lobby_refresh]<typename CharT>(const CharT& char_file) -> asio::awaitable<void> {
|
||||||
co_await prepare_client_for_patches(a.c);
|
co_await prepare_client_for_patches(a.c);
|
||||||
try {
|
try {
|
||||||
auto fn = s->function_code_index->get_patch("SetExtendedPlayerInfo", a.c->specific_version);
|
auto fn = s->function_code_index->get_patch("SetExtendedPlayerInfo", a.c->specific_version);
|
||||||
@@ -1577,6 +1602,8 @@ ChatCommandDefinition cc_loadchar(
|
|||||||
if (l) {
|
if (l) {
|
||||||
send_player_leave_notification(l, a.c->lobby_client_id);
|
send_player_leave_notification(l, a.c->lobby_client_id);
|
||||||
s->send_lobby_join_notifications(l, a.c);
|
s->send_lobby_join_notifications(l, a.c);
|
||||||
|
} else if (a.c->proxy_session) {
|
||||||
|
send_proxy_lobby_refresh();
|
||||||
}
|
}
|
||||||
} catch (const exception& e) {
|
} catch (const exception& e) {
|
||||||
a.c->log.warning_f("Failed to set extended player info: {}", e.what());
|
a.c->log.warning_f("Failed to set extended player info: {}", e.what());
|
||||||
@@ -1611,12 +1638,16 @@ ChatCommandDefinition cc_loadchar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// On v1 and v2, the client will assign its character data from the lobby join command, so it suffices to just
|
// On PC V2 and older DC versions, the client will assign its character data
|
||||||
// resend the join notification.
|
// from the lobby join command, so resend a lobby join notification.
|
||||||
|
if (a.c->proxy_session) {
|
||||||
|
send_proxy_lobby_refresh();
|
||||||
|
} else {
|
||||||
auto s = a.c->require_server_state();
|
auto s = a.c->require_server_state();
|
||||||
send_player_leave_notification(l, a.c->lobby_client_id);
|
send_player_leave_notification(l, a.c->lobby_client_id);
|
||||||
s->send_lobby_join_notifications(l, a.c);
|
s->send_lobby_join_notifications(l, a.c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
co_return;
|
co_return;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public:
|
|||||||
ITEM_DROP_NOTIFICATIONS_1 = 0x0000000400000000,
|
ITEM_DROP_NOTIFICATIONS_1 = 0x0000000400000000,
|
||||||
ITEM_DROP_NOTIFICATIONS_2 = 0x0000000800000000,
|
ITEM_DROP_NOTIFICATIONS_2 = 0x0000000800000000,
|
||||||
HAS_ENEMY_DAMAGE_SYNC_PATCH = 0x0000001000000000, // Must be same as in EnemyDamageSync*.s
|
HAS_ENEMY_DAMAGE_SYNC_PATCH = 0x0000001000000000, // Must be same as in EnemyDamageSync*.s
|
||||||
|
HAS_PSO_PEEPS_XP_PATCH = 0x0000200000000000, // Must be same as in PSO Peeps XP patches
|
||||||
|
|
||||||
// Proxy option flags
|
// Proxy option flags
|
||||||
PROXY_SAVE_FILES = 0x0000002000000000,
|
PROXY_SAVE_FILES = 0x0000002000000000,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ struct RootV2V3V4 {
|
|||||||
/* 08 / 0498 / 0498 / 0608 / 03CE / 04AE */ U32T<BE> unknown_a3; // -> UnknownA3Entry[max(unknown_a2) + 1]
|
/* 08 / 0498 / 0498 / 0608 / 03CE / 04AE */ U32T<BE> unknown_a3; // -> UnknownA3Entry[max(unknown_a2) + 1]
|
||||||
/* 0C / 0510 / 0520 / 06B0 / 0476 / 0556 */ U32T<BE> unknown_a4; // -> uint8_t[NumMags]
|
/* 0C / 0510 / 0520 / 06B0 / 0476 / 0556 */ U32T<BE> unknown_a4; // -> uint8_t[NumMags]
|
||||||
/* 10 / 053C / 054C / 06EC / 04BC / 05AC */ U32T<BE> color_table; // -> ColorEntry[NumColors]
|
/* 10 / 053C / 054C / 06EC / 04BC / 05AC */ U32T<BE> color_table; // -> ColorEntry[NumColors]
|
||||||
/* 14 / / / 077C / 05DC / 06CC */ U32T<BE> evolution_number; // -> uint8_t[NumMags]
|
/* 14 / / / 077C / 05DC / 06CC */ U32T<BE> evolution_number_table; // -> uint8_t[NumMags]
|
||||||
} __packed_ws_be__(RootV2V3V4, 0x18);
|
} __packed_ws_be__(RootV2V3V4, 0x18);
|
||||||
|
|
||||||
struct RootV1 {
|
struct RootV1 {
|
||||||
|
|||||||
@@ -74,7 +74,14 @@ static asio::awaitable<HandlerResult> C_1D(shared_ptr<Client> c, Channel::Messag
|
|||||||
c->ping_start_time = 0;
|
c->ping_start_time = 0;
|
||||||
double ping_ms = static_cast<double>(ping_usecs) / 1000.0;
|
double ping_ms = static_cast<double>(ping_usecs) / 1000.0;
|
||||||
send_text_message_fmt(c->channel, "To proxy: {:g}ms", ping_ms);
|
send_text_message_fmt(c->channel, "To proxy: {:g}ms", ping_ms);
|
||||||
|
co_return HandlerResult::SUPPRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->proxy_session->is_in_game) {
|
||||||
|
c->log.info_f("Forwarding in-game command 1D through proxy");
|
||||||
|
co_return HandlerResult::FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
co_return HandlerResult::SUPPRESS;
|
co_return HandlerResult::SUPPRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-5
@@ -3112,11 +3112,26 @@ static asio::awaitable<void> on_10_proxy_destinations(shared_ptr<Client> c, uint
|
|||||||
send_message_box(c, "$C6No such destination exists.");
|
send_message_box(c, "$C6No such destination exists.");
|
||||||
c->channel->disconnect();
|
c->channel->disconnect();
|
||||||
} else {
|
} else {
|
||||||
// PSO Peeps: boosted GC discs enter through separate frontdoor ports after
|
// PSO Peeps: boosted clients may not enter Vanilla/Hardcore.
|
||||||
// pc_console_detect. Do not allow x5/x10 GC discs into Vanilla.
|
// PC v2 receives boosted BattleParams via the patch server. DC/GC can be
|
||||||
if ((c->listener_port == 9105 || c->listener_port == 9110 ||
|
// boosted either by old boosted-disc listener ports or by the PSO Peeps XP
|
||||||
c->listener_port == 9201 || c->listener_port == 9202) && dest->second == 19203) {
|
// client-function patch, which sets HAS_PSO_PEEPS_XP_PATCH.
|
||||||
send_message_box(c, "$C6Vanilla Ship is not available from boosted discs.\n\n$C7Use the normal disc for Vanilla.");
|
const bool is_vanilla_or_hardcore_dest =
|
||||||
|
(dest->second == 19203 || dest->second == 19230 || dest->second == 19530);
|
||||||
|
const bool is_boosted_disc =
|
||||||
|
(c->listener_port == 9105 || c->listener_port == 9110 ||
|
||||||
|
c->listener_port == 9201 || c->listener_port == 9202 ||
|
||||||
|
c->listener_port == 19105 || c->listener_port == 19110);
|
||||||
|
const bool is_pc_v2_boosted = (c->version() == Version::PC_V2);
|
||||||
|
const bool has_psopeeps_xp_patch =
|
||||||
|
c->check_flag(Client::Flag::HAS_PSO_PEEPS_XP_PATCH);
|
||||||
|
|
||||||
|
if (is_vanilla_or_hardcore_dest &&
|
||||||
|
(is_boosted_disc || is_pc_v2_boosted || has_psopeeps_xp_patch)) {
|
||||||
|
send_message_box(c,
|
||||||
|
"$C6Vanilla and Hardcore are not available\n"
|
||||||
|
"while boosted XP is active.\n\n"
|
||||||
|
"$C7Use Live, Test, or Dev.");
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2487,11 +2487,26 @@ static asio::awaitable<void> on_pick_up_item_generic(
|
|||||||
// TODO: Figure out what the actual max range is; 30 is an overestimate
|
// TODO: Figure out what the actual max range is; 30 is an overestimate
|
||||||
double dist2 = fi->pos.dist2(c->pos);
|
double dist2 = fi->pos.dist2(c->pos);
|
||||||
if (dist2 > 900.0) {
|
if (dist2 > 900.0) {
|
||||||
|
const bool allow_dcv2_falz_pickup_distance_recovery =
|
||||||
|
is_request &&
|
||||||
|
(c->version() == Version::DC_V2) &&
|
||||||
|
(l->episode == Episode::EP1) &&
|
||||||
|
(floor == 0x0E) &&
|
||||||
|
(fi->from_obj == nullptr) &&
|
||||||
|
(fi->from_ene == nullptr) &&
|
||||||
|
fi->visible_to_client(c->lobby_client_id);
|
||||||
|
|
||||||
|
if (allow_dcv2_falz_pickup_distance_recovery) {
|
||||||
|
l->log.warning_f(
|
||||||
|
"DC V2 Falz floor item pickup distance recovery: Player {} picking up {:08X}; dist2={} item_floor={} player_floor={}",
|
||||||
|
client_id, item_id, dist2, static_cast<uint64_t>(floor), static_cast<uint64_t>(c->floor));
|
||||||
|
} else {
|
||||||
l->log.warning_f("Player {} requests to pick up {:08X}, but it is too far away (dist2={})",
|
l->log.warning_f("Player {} requests to pick up {:08X}, but it is too far away (dist2={})",
|
||||||
client_id, item_id, dist2);
|
client_id, item_id, dist2);
|
||||||
l->add_item(floor, fi);
|
l->add_item(floor, fi);
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
p->add_item(fi->data, *s->item_stack_limits(c->version()));
|
p->add_item(fi->data, *s->item_stack_limits(c->version()));
|
||||||
|
|||||||
Reference in New Issue
Block a user