diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 8c4b5974..50db7814 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -3552,7 +3552,11 @@ static asio::awaitable on_set_entity_set_flag(shared_ptr c, Subcom l->log.info_f("All enemies defeated; setting events with room={:04X} wave_number={:04X} to finished state", room, wave_number); for (auto ev_st : l->map_state->event_states_for_floor_room_wave(c->version(), cmd.floor, room, wave_number)) { + bool already_finished = (ev_st->flags & 0x10); ev_st->flags = (ev_st->flags | 0x18) & (~4); + if (already_finished) { + continue; + } l->log.info_f("Set flags on W-{:03X} to {:04X}", ev_st->w_id, ev_st->flags); const auto& ev_ver = ev_st->super_ev->version(c->version()); @@ -3627,59 +3631,6 @@ static asio::awaitable on_set_entity_set_flag(shared_ptr c, Subcom co_await forward_subcommand_with_entity_id_transcode_t(c, msg); } - -// Dispatch the right per-difficulty DC V2 EXP table when the player has the -// universal EXP shim enabled. The shim's body covers Normal; this corrects to -// the actual loaded difficulty on every set-events trigger. -static asio::awaitable dispatch_dc_v2_exp_patch(shared_ptr c) { - if (c->version() != Version::DC_V2) { - co_return; - } - if (not c->check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL)) { - co_return; - } - if (not c->login || not c->login->account) { - co_return; - } - if (not c->login->account->auto_patches_enabled.count("PsoPeepsV2EXP_enabled")) { - co_return; - } - - auto l = c->require_lobby(); - if (not l->is_game()) { - co_return; - } - - const char* diff_str = nullptr; - switch (l->difficulty) { - case Difficulty::NORMAL: - diff_str = "normal"; - break; - case Difficulty::HARD: - diff_str = "hard"; - break; - case Difficulty::VERY_HARD: - diff_str = "vh"; - break; - case Difficulty::ULTIMATE: - diff_str = "ult"; - break; - default: - co_return; - } - - string key = "PsoPeepsV2EXP_internal_10x_"; - key += diff_str; - - try { - auto server_state = c->require_server_state(); - auto fn = server_state->client_functions->get(key, c->specific_version); - co_await send_function_call(c, fn); - } catch (const out_of_range&) { - c->log.warning_f("DC V2 EXP dispatcher could not find client function {}", key); - } -} - static asio::awaitable on_trigger_set_event(shared_ptr c, SubcommandMessage& msg) { auto l = c->require_lobby(); if (!l->is_game()) { @@ -3698,7 +3649,6 @@ static asio::awaitable on_trigger_set_event(shared_ptr c, Subcomma } forward_subcommand(c, msg); - co_await dispatch_dc_v2_exp_patch(c); } static inline uint32_t bswap32_high16(uint32_t v) { diff --git a/src/SendCommands.cc b/src/SendCommands.cc index c3cbefd0..34a1d7fa 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -772,13 +772,23 @@ static string bb_stream_file_data_for_client(shared_ptr c) { void send_stream_file_index_bb(shared_ptr c) { auto s = c->require_server_state(); - c->log.info_f("PSO Peeps BBZ stream debug: send_stream_file_index_bb called"); + string contents = bb_stream_file_data_for_client(c); + c->log.info_f("BB stream file index: sending {} entries from {} bytes", + s->bb_stream_file->entries.size(), contents.size()); vector entries; - string contents = bb_stream_file_data_for_client(c); + size_t idx = 0; for (const auto& sf_entry : s->bb_stream_file->entries) { - if ((sf_entry.offset > contents.size()) || - (sf_entry.size > (contents.size() - sf_entry.offset))) { + bool offset_past_end = (sf_entry.offset > contents.size()); + bool size_overflows = !offset_past_end && (sf_entry.size > (contents.size() - sf_entry.offset)); + + c->log.info_f( + "PSO Peeps BBZ stream diag: entry[{}] filename={} offset={:08X} size={:08X} contents_size={:08X}{}{}", + idx, sf_entry.filename, sf_entry.offset, sf_entry.size, contents.size(), + offset_past_end ? " OFFSET_PAST_END" : "", + size_overflows ? " SIZE_OVERFLOWS_END" : ""); + + if (offset_past_end || size_overflows) { throw runtime_error("invalid BB stream file entry range"); } @@ -787,25 +797,31 @@ void send_stream_file_index_bb(shared_ptr c) { e.checksum = crc32(contents.data() + sf_entry.offset, e.size); e.offset = sf_entry.offset; e.filename.encode(sf_entry.filename); - + idx++; } + send_command_vt(c, 0x01EB, entries.size(), entries); } void send_stream_file_chunk_bb(shared_ptr c, uint32_t chunk_index) { - auto s = c->require_server_state(); - string contents = bb_stream_file_data_for_client(c); S_StreamFileChunk_BB_02EB chunk_cmd; chunk_cmd.chunk_index = chunk_index; size_t offset = sizeof(chunk_cmd.data) * chunk_index; if (offset > contents.size()) { + c->log.warning_f("BB stream chunk request {} is beyond end of stream data: offset={} size={}", + chunk_index, offset, contents.size()); throw runtime_error("client requested chunk beyond end of stream file"); } + size_t bytes = min(contents.size() - offset, sizeof(chunk_cmd.data)); chunk_cmd.data.assign_range(reinterpret_cast(contents.data() + offset), bytes, 0); + if ((chunk_index < 3) || (bytes < sizeof(chunk_cmd.data))) { + c->log.info_f("BB stream chunk: index={} offset={} bytes={} total={}", + chunk_index, offset, bytes, contents.size()); + } size_t cmd_size = offsetof(S_StreamFileChunk_BB_02EB, data) + bytes; cmd_size = (cmd_size + 3) & ~3;