make 04E8 handler match the client's logic

This commit is contained in:
Martin Michelsen
2025-12-05 19:53:09 -08:00
parent a89423e9f5
commit 6291e42ba9
4 changed files with 66 additions and 29 deletions
+1
View File
@@ -913,6 +913,7 @@ void Client::load_all_files() {
string card_filename = this->guild_card_filename();
if (std::filesystem::is_regular_file(card_filename)) {
this->guild_card_data = make_shared<PSOBBGuildCardFile>(phosg::load_object_file<PSOBBGuildCardFile>(card_filename));
this->guild_card_data->delete_duplicates();
this->log.info_f("Loaded Guild Card data from {}", card_filename);
} else {
this->log.info_f("Guild Card file is missing: {}", card_filename);
+28 -29
View File
@@ -3809,10 +3809,8 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x01E8: { // Check guild card file checksum
const auto& cmd = check_size_t<C_GuildCardChecksum_01E8>(msg.data);
uint32_t checksum = gcf->checksum();
c->log.info_f("(Guild card file) Server checksum = {:08X}, client checksum = {:08X}",
checksum, cmd.checksum);
S_GuildCardChecksumResponse_BB_02E8 response = {
(cmd.checksum != checksum), 0};
c->log.info_f("(Guild card file) Server checksum = {:08X}, client checksum = {:08X}", checksum, cmd.checksum);
S_GuildCardChecksumResponse_BB_02E8 response = {(cmd.checksum != checksum), 0};
send_command_t(c, 0x02E8, 0x00000000, response);
break;
}
@@ -3820,13 +3818,14 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
check_size_v(msg.data.size(), 0);
send_guild_card_header_bb(c);
break;
case 0x04E8: { // Add guild card
case 0x04E8: { // Add or replace guild card
auto& new_gc = check_size_t<GuildCardBB>(msg.data);
for (size_t z = 0; z < max_count; z++) {
if (!gcf->entries[z].data.present) {
gcf->entries[z].data = new_gc;
gcf->entries[z].unknown_a1.clear(0);
c->log.info_f("Added guild card {} at position {}", new_gc.guild_card_number, z);
auto& gcf_entry = gcf->entries[z];
if (!gcf_entry.data.present || (gcf_entry.data.guild_card_number == new_gc.guild_card_number)) {
gcf_entry.data = new_gc;
gcf_entry.unknown_a1.clear(0);
c->log.info_f("Added or replaced guild card {} at position {}", new_gc.guild_card_number, z);
should_save = true;
break;
}
@@ -3836,10 +3835,11 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x05E8: { // Delete guild card
auto& cmd = check_size_t<C_DeleteGuildCard_BB_05E8_08E8>(msg.data);
for (size_t z = 0; z < max_count; z++) {
if (gcf->entries[z].data.guild_card_number == cmd.guild_card_number) {
auto& gcf_entry = gcf->entries[z];
if (gcf_entry.data.guild_card_number == cmd.guild_card_number) {
c->log.info_f("Deleted guild card {} at position {}", cmd.guild_card_number, z);
for (z = 0; z < max_count - 1; z++) {
gcf->entries[z] = gcf->entries[z + 1];
gcf_entry = gcf->entries[z + 1];
}
gcf->entries[max_count - 1].clear();
should_save = true;
@@ -3851,8 +3851,9 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x06E8: { // Update guild card
auto& new_gc = check_size_t<GuildCardBB>(msg.data);
for (size_t z = 0; z < max_count; z++) {
if (gcf->entries[z].data.guild_card_number == new_gc.guild_card_number) {
gcf->entries[z].data = new_gc;
auto& gcf_entry = gcf->entries[z];
if (gcf_entry.data.guild_card_number == new_gc.guild_card_number) {
gcf_entry.data = new_gc;
c->log.info_f("Updated guild card {} at position {}", new_gc.guild_card_number, z);
should_save = true;
}
@@ -3866,11 +3867,10 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x07E8: { // Add blocked user
auto& new_gc = check_size_t<GuildCardBB>(msg.data);
for (size_t z = 0; z < max_blocked; z++) {
if (!gcf->blocked[z].present) {
gcf->blocked[z] = new_gc;
auto& gcf_blocked = gcf->blocked[z];
if (!gcf_blocked.present) {
gcf_blocked = new_gc;
c->log.info_f("Added blocked guild card {} at position {}", new_gc.guild_card_number, z);
// Note: The client also sends a C6 command, so we don't have to
// manually sync the actual blocked senders list here
should_save = true;
break;
}
@@ -3880,15 +3880,13 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x08E8: { // Delete blocked user
auto& cmd = check_size_t<C_DeleteGuildCard_BB_05E8_08E8>(msg.data);
for (size_t z = 0; z < max_blocked; z++) {
if (gcf->blocked[z].guild_card_number == cmd.guild_card_number) {
c->log.info_f("Deleted blocked guild card {} at position {}",
cmd.guild_card_number, z);
auto& gcf_blocked = gcf->blocked[z];
if (gcf_blocked.guild_card_number == cmd.guild_card_number) {
c->log.info_f("Deleted blocked guild card {} at position {}", cmd.guild_card_number, z);
for (z = 0; z < max_blocked - 1; z++) {
gcf->blocked[z] = gcf->blocked[z + 1];
gcf_blocked = gcf->blocked[z + 1];
}
gcf->blocked[max_blocked - 1].clear();
// Note: The client also sends a C6 command, so we don't have to
// manually sync the actual blocked senders list here
should_save = true;
break;
}
@@ -3898,8 +3896,9 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
case 0x09E8: { // Write comment
auto& cmd = check_size_t<C_WriteGuildCardComment_BB_09E8>(msg.data);
for (size_t z = 0; z < max_count; z++) {
if (gcf->entries[z].data.guild_card_number == cmd.guild_card_number) {
gcf->entries[z].comment = cmd.comment;
auto& gcf_entry = gcf->entries[z];
if (gcf_entry.data.guild_card_number == cmd.guild_card_number) {
gcf_entry.comment = cmd.comment;
c->log.info_f("Updated comment on guild card {} at position {}", cmd.guild_card_number, z);
should_save = true;
break;
@@ -3912,14 +3911,15 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
size_t index1 = max_count;
size_t index2 = max_count;
for (size_t z = 0; z < max_count; z++) {
if (gcf->entries[z].data.guild_card_number == cmd.guild_card_number1) {
auto& gcf_entry = gcf->entries[z];
if (gcf_entry.data.guild_card_number == cmd.guild_card_number1) {
if (index1 >= max_count) {
index1 = z;
} else {
throw runtime_error("guild card 1 appears multiple times in file");
}
}
if (gcf->entries[z].data.guild_card_number == cmd.guild_card_number2) {
if (gcf_entry.data.guild_card_number == cmd.guild_card_number2) {
if (index2 >= max_count) {
index2 = z;
} else {
@@ -3935,8 +3935,7 @@ static asio::awaitable<void> on_E8_BB(shared_ptr<Client> c, Channel::Message& ms
PSOBBGuildCardFile::Entry displaced_entry = gcf->entries[index1];
gcf->entries[index1] = gcf->entries[index2];
gcf->entries[index2] = displaced_entry;
c->log.info_f("Swapped positions of guild cards {} and {}",
cmd.guild_card_number1, cmd.guild_card_number2);
c->log.info_f("Swapped positions of guild cards {} and {}", cmd.guild_card_number1, cmd.guild_card_number2);
should_save = true;
}
break;
+36
View File
@@ -327,6 +327,42 @@ uint32_t PSOBBGuildCardFile::checksum() const {
return phosg::crc32(this, sizeof(*this));
}
void PSOBBGuildCardFile::delete_duplicates() {
{
unordered_set<uint32_t> seen;
size_t read_index = 0, write_index = 0;
for (read_index = 0; read_index < this->blocked.size(); read_index++) {
const auto& read_blocked = this->blocked[read_index];
if (seen.emplace(read_blocked.guild_card_number).second) {
if (write_index != read_index) {
this->blocked[write_index] = read_blocked;
}
write_index++;
}
}
for (; write_index < this->blocked.size(); write_index++) {
this->blocked[write_index].clear();
}
}
{
unordered_set<uint32_t> seen;
size_t read_index = 0, write_index = 0;
for (read_index = 0; read_index < this->entries.size(); read_index++) {
const auto& read_entry = this->entries[read_index];
if (seen.emplace(read_entry.data.guild_card_number).second) {
if (write_index != read_index) {
this->entries[write_index] = read_entry;
}
write_index++;
}
}
for (; write_index < this->entries.size(); write_index++) {
this->entries[write_index].clear();
}
}
}
PSOBBBaseSystemFile::PSOBBBaseSystemFile() {
// This field is based on 1/1/2000, not 1/1/1970, so adjust appropriately
this->creation_timestamp = (phosg::now() - 946684800000000ULL) / 1000000;
+1
View File
@@ -1045,6 +1045,7 @@ struct PSOBBGuildCardFile {
PSOBBGuildCardFile() = default;
uint32_t checksum() const;
void delete_duplicates();
} __packed_ws__(PSOBBGuildCardFile, 0xD590);
////////////////////////////////////////////////////////////////////////////////