fix play time field and marked utf16 fields

This commit is contained in:
Martin Michelsen
2024-02-19 20:57:42 -08:00
parent f2f1007cee
commit cd77fae4e3
16 changed files with 79 additions and 87 deletions
+1 -3
View File
@@ -1126,9 +1126,7 @@ static void server_command_edit(shared_ptr<Client> c, const std::string& args) {
}
} else if (tokens.at(0) == "name") {
vector<string> orig_tokens = split(args, ' ');
string name = ((p->inventory.language == 0) ? "\tE" : "\tJ") + orig_tokens.at(1);
p->disp.name.clear();
p->disp.name.encode(name, p->inventory.language);
p->disp.name.encode(orig_tokens.at(1), p->inventory.language);
} else if (tokens.at(0) == "npc") {
if (tokens.at(1) == "none") {
p->disp.visual.extra_model = 0;
+2 -3
View File
@@ -815,7 +815,7 @@ void Client::load_all_files() {
files_manager->set_character(this->character_filename(), this->character_data);
this->character_data->inventory = nsc_data.inventory;
this->character_data->disp = nsc_data.disp;
this->character_data->play_time_seconds = nsc_data.disp.play_time;
this->character_data->play_time_seconds = 0;
this->character_data->unknown_a2 = nsc_data.unknown_a2;
this->character_data->quest_flags = nsc_data.quest_flags;
this->character_data->death_count = nsc_data.death_count;
@@ -929,8 +929,7 @@ void Client::save_character_file() {
// off each time we save. I'm lazy, so insert shrug emoji here.
uint64_t t = now();
uint64_t seconds = (t - this->last_play_time_update) / 1000000;
this->character_data->disp.play_time += seconds;
this->character_data->play_time_seconds = this->character_data->disp.play_time;
this->character_data->play_time_seconds += seconds;
player_data_log.info("Added %" PRIu64 " seconds to play time", seconds);
this->last_play_time_update = t;
}
+22 -20
View File
@@ -1439,26 +1439,28 @@ struct S_GenerateID_DC_PC_V3_80 {
// contains uninitialized memory when the client sends this command. newserv
// clears the uninitialized data for security reasons before forwarding.
template <TextEncoding Encoding>
struct SC_SimpleMail_81 {
struct SC_SimpleMail_PC_81 {
// If player_tag and from_guild_card_number are zero, the message cannot be
// replied to.
le_uint32_t player_tag = 0x00010000;
le_uint32_t from_guild_card_number = 0;
pstring<Encoding, 0x10> from_name;
pstring<TextEncoding::UTF16, 0x10> from_name;
le_uint32_t to_guild_card_number = 0;
pstring<Encoding, 0x200> text;
pstring<TextEncoding::UTF16, 0x200> text;
} __packed__;
struct SC_SimpleMail_PC_81 : SC_SimpleMail_81<TextEncoding::UTF16> {
} __packed__;
struct SC_SimpleMail_DC_V3_81 : SC_SimpleMail_81<TextEncoding::MARKED> {
struct SC_SimpleMail_DC_V3_81 {
le_uint32_t player_tag = 0x00010000;
le_uint32_t from_guild_card_number = 0;
pstring<TextEncoding::MARKED, 0x10> from_name;
le_uint32_t to_guild_card_number = 0;
pstring<TextEncoding::MARKED, 0x200> text;
} __packed__;
struct SC_SimpleMail_BB_81 {
le_uint32_t player_tag = 0x00010000;
le_uint32_t from_guild_card_number = 0;
pstring<TextEncoding::UTF16, 0x10> from_name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> from_name;
le_uint32_t to_guild_card_number = 0;
pstring<TextEncoding::UTF16, 0x14> received_date;
pstring<TextEncoding::UTF16, 0x200> text;
@@ -2506,7 +2508,7 @@ struct S_ChoiceSearchResultEntry_DC_V3_C4 : S_ChoiceSearchResultEntry_C4<PSOComm
} __packed__;
struct S_ChoiceSearchResultEntry_PC_C4 : S_ChoiceSearchResultEntry_C4<PSOCommandHeaderPC, TextEncoding::UTF16, TextEncoding::UTF16, TextEncoding::UTF16> {
} __packed__;
struct S_ChoiceSearchResultEntry_BB_C4 : S_ChoiceSearchResultEntry_C4<PSOCommandHeaderBB, TextEncoding::UTF16, TextEncoding::UTF16, TextEncoding::UTF16> {
struct S_ChoiceSearchResultEntry_BB_C4 : S_ChoiceSearchResultEntry_C4<PSOCommandHeaderBB, TextEncoding::UTF16_ALWAYS_MARKED, TextEncoding::UTF16, TextEncoding::UTF16> {
} __packed__;
// C5 (S->C): Player records update (DCv2 and later versions)
@@ -2703,7 +2705,7 @@ struct S_InfoBoardEntry_D8 {
pstring<NameEncoding, 0x10> name;
pstring<MessageEncoding, 0xAC> message;
} __packed__;
struct S_InfoBoardEntry_BB_D8 : S_InfoBoardEntry_D8<TextEncoding::UTF16, TextEncoding::UTF16> {
struct S_InfoBoardEntry_BB_D8 : S_InfoBoardEntry_D8<TextEncoding::UTF16_ALWAYS_MARKED, TextEncoding::UTF16> {
} __packed__;
struct S_InfoBoardEntry_V3_D8 : S_InfoBoardEntry_D8<TextEncoding::ASCII, TextEncoding::MARKED> {
} __packed__;
@@ -3336,7 +3338,7 @@ struct C_AddOrRemoveTeamMember_BB_03EA_05EA {
// 07EA: Team chat
struct SC_TeamChat_BB_07EA {
pstring<TextEncoding::UTF16, 0x10> sender_name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> sender_name;
// Text follows here. The message is truncated by the client if it is longer
// than 0x8F wchar_ts.
} __packed__;
@@ -3353,7 +3355,7 @@ struct S_TeamMemberList_BB_09EA {
le_uint32_t rank = 0;
le_uint32_t privilege_level = 0; // 0x10 or 0x20 = green, 0x30 = blue, 0x40 = red, anything else = white
le_uint32_t guild_card_number = 0;
pstring<TextEncoding::UTF16, 0x10> name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> name;
} __packed__;
// Variable-length field:
// Entry entries[entry_count];
@@ -3374,7 +3376,7 @@ struct S_Unknown_BB_0CEA {
struct S_TeamName_BB_0EEA {
parray<uint8_t, 0x10> unused;
pstring<TextEncoding::UTF16, 0x10> team_name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
} __packed__;
// 0FEA (C->S): Set team flag
@@ -3412,7 +3414,7 @@ struct S_TeamMembershipInformation_BB_12EA {
uint8_t unknown_a7 = 0;
uint8_t unknown_a8 = 0;
uint8_t unknown_a9 = 0;
pstring<TextEncoding::UTF16, 0x10> team_name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
} __packed__;
// 13EA: Team info for lobby players
@@ -3429,10 +3431,10 @@ struct S_TeamInfoForPlayer_BB_13EA_15EA_Entry {
/* 0011 */ uint8_t unknown_a7 = 0;
/* 0012 */ uint8_t unknown_a8 = 0;
/* 0013 */ uint8_t unknown_a9 = 0;
/* 0014 */ pstring<TextEncoding::UTF16, 0x10> team_name;
/* 0014 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
/* 0034 */ le_uint32_t guild_card_number2 = 0;
/* 0038 */ le_uint32_t lobby_client_id = 0;
/* 003C */ pstring<TextEncoding::UTF16, 0x10> player_name;
/* 003C */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> player_name;
/* 005C */ parray<le_uint16_t, 0x20 * 0x20> flag_data;
/* 085C */
} __packed__;
@@ -3460,7 +3462,7 @@ struct S_IntraTeamRanking_BB_18EA {
/* 00 */ le_uint32_t rank = 0;
/* 04 */ le_uint32_t privilege_level = 0;
/* 08 */ le_uint32_t guild_card_number = 0;
/* 0C */ pstring<TextEncoding::UTF16, 0x10> player_name;
/* 0C */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> player_name;
/* 2C */ le_uint32_t points = 0;
/* 30 */
} __packed__;
@@ -3497,7 +3499,7 @@ struct S_TeamRewardList_BB_19EA_1AEA {
struct S_CrossTeamRanking_BB_1CEA {
le_uint32_t num_entries;
struct Entry {
/* 00 */ pstring<TextEncoding::UTF16, 0x10> team_name;
/* 00 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
/* 20 */ le_uint32_t team_points = 0;
/* 24 */ le_uint32_t unknown_a1 = 0;
/* 28 */
@@ -3513,7 +3515,7 @@ struct S_CrossTeamRanking_BB_1CEA {
// header.flag is used, but it's unknown what the value means.
struct C_RenameTeam_BB_1EEA {
pstring<TextEncoding::UTF16, 0x10> new_team_name;
pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> new_team_name;
} __packed__;
// 1FEA (S->C): Rename team result
@@ -4907,7 +4909,7 @@ struct G_SyncPlayerDispAndInventory_BB_6x70 {
// Offsets in this struct are relative to the overall command header
/* 0008 */ G_ExtendedHeader<G_ClientIDHeader> header = {{0x70, 0x00, 0x0000}, sizeof(G_SyncPlayerDispAndInventory_BB_6x70)};
/* 0010 */ G_SyncPlayerDispAndInventory_BaseV1 base;
/* 0128 */ pstring<TextEncoding::UTF16, 0x10> name;
/* 0128 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> name;
/* 0148 */ PlayerStats stats;
/* 016C */ le_uint32_t num_items = 0;
/* 0170 */ parray<PlayerInventoryItem, 0x1E> items;
+1 -1
View File
@@ -337,7 +337,7 @@ JSON HTTPServer::generate_game_client_json(shared_ptr<const Client> c) const {
ret.emplace("ProportionY", p->disp.visual.proportion_y.load());
ret.emplace("Name", p->disp.name.decode(c->language()));
ret.emplace("PlayTimeSeconds", p->disp.play_time.load());
ret.emplace("PlayTimeSeconds", p->play_time_seconds.load());
ret.emplace("AutoReply", p->auto_reply.decode(c->language()));
ret.emplace("InfoBoard", p->info_board.decode(c->language()));
+2 -23
View File
@@ -165,10 +165,6 @@ void PlayerVisualConfig::enforce_lobby_join_limits_for_version(Version v) {
this->name_color_checksum = 0;
}
this->class_flags = class_flags_for_class(this->char_class);
if (!is_v4(v) && (this->name.at(0) == '\t') && (this->name.at(1) == 'J' || this->name.at(1) == 'E')) {
this->name.encode(this->name.decode().substr(2));
}
}
void PlayerDispDataDCPCV3::enforce_lobby_join_limits_for_version(Version v) {
@@ -177,13 +173,6 @@ void PlayerDispDataDCPCV3::enforce_lobby_join_limits_for_version(Version v) {
void PlayerDispDataBB::enforce_lobby_join_limits_for_version(Version v) {
this->visual.enforce_lobby_join_limits_for_version(v);
if (!is_v4(v)) {
throw logic_error("PlayerDispDataBB being sent to non-BB client");
}
this->play_time = 0;
if (this->name.at(0) != '\t' || (this->name.at(1) != 'E' && this->name.at(1) != 'J')) {
this->name.encode("\tJ" + this->name.decode());
}
}
PlayerDispDataBB PlayerDispDataDCPCV3::to_bb(uint8_t to_language, uint8_t from_language) const {
@@ -209,16 +198,6 @@ PlayerDispDataDCPCV3 PlayerDispDataBB::to_dcpcv3(uint8_t to_language, uint8_t fr
return ret;
}
PlayerDispDataBBPreview PlayerDispDataBB::to_preview() const {
PlayerDispDataBBPreview pre;
pre.level = this->stats.level;
pre.experience = this->stats.experience;
pre.visual = this->visual;
pre.name = this->name;
pre.play_time = this->play_time;
return pre;
}
void PlayerDispDataBB::apply_dressing_room(const PlayerDispDataBBPreview& pre) {
this->visual.name_color = pre.visual.name_color;
this->visual.extra_model = pre.visual.extra_model;
@@ -343,7 +322,7 @@ PlayerRecordsBB_Challenge::PlayerRecordsBB_Challenge(const PlayerRecordsPC_Chall
grave_message(rec.grave_message.decode(), 1),
unknown_m5(0),
unknown_t6(0),
rank_title(rec.rank_title),
rank_title(rec.rank_title.decode(), 1),
unknown_l7(0) {}
PlayerRecordsBB_Challenge::PlayerRecordsBB_Challenge(const PlayerRecordsV3_Challenge<false>& rec)
@@ -407,7 +386,7 @@ PlayerRecordsBB_Challenge::operator PlayerRecordsPC_Challenge() const {
PlayerRecordsPC_Challenge ret;
ret.title_color = this->title_color;
ret.unknown_u0 = this->unknown_u0;
ret.rank_title = this->rank_title;
ret.rank_title.encode(this->rank_title.decode());
ret.times_ep1_online = this->times_ep1_online;
if (this->grave_is_ep2) {
ret.grave_stage_num = 0;
+8 -10
View File
@@ -174,8 +174,8 @@ struct PlayerDispDataBBPreview {
// The name field in this structure is used for the player's Guild Card
// number, apparently (possibly because it's a char array and this is BB)
/* 08 */ PlayerVisualConfig visual;
/* 58 */ pstring<TextEncoding::UTF16, 0x10> name;
/* 78 */ uint32_t play_time = 0;
/* 58 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> name;
/* 78 */ uint32_t play_time_seconds = 0;
/* 7C */
} __attribute__((packed));
@@ -183,16 +183,14 @@ struct PlayerDispDataBBPreview {
struct PlayerDispDataBB {
/* 0000 */ PlayerStats stats;
/* 0024 */ PlayerVisualConfig visual;
/* 0074 */ pstring<TextEncoding::UTF16, 0x0C> name;
/* 008C */ le_uint32_t play_time = 0;
/* 0090 */ uint32_t unknown_a3 = 0;
/* 0074 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x0C> name;
/* 008C */ parray<uint8_t, 0x08> unknown_a1; // Probably actually unused
/* 0094 */ parray<uint8_t, 0xE8> config;
/* 017C */ parray<uint8_t, 0x14> technique_levels_v1;
/* 0190 */
void enforce_lobby_join_limits_for_version(Version v);
PlayerDispDataDCPCV3 to_dcpcv3(uint8_t to_language, uint8_t from_language) const;
PlayerDispDataBBPreview to_preview() const;
void apply_preview(const PlayerDispDataBBPreview&);
void apply_dressing_room(const PlayerDispDataBBPreview&);
} __attribute__((packed));
@@ -251,8 +249,8 @@ struct GuildCardXB {
struct GuildCardBB {
/* 0000 */ le_uint32_t guild_card_number = 0;
/* 0004 */ pstring<TextEncoding::UTF16, 0x18> name;
/* 0034 */ pstring<TextEncoding::UTF16, 0x10> team_name;
/* 0004 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x18> name;
/* 0034 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
/* 0054 */ pstring<TextEncoding::UTF16, 0x58> description;
/* 0104 */ uint8_t present = 0;
/* 0105 */ uint8_t language = 0;
@@ -320,7 +318,7 @@ struct PlayerLobbyDataBB {
/* 0C */ le_uint32_t team_id = 0;
/* 10 */ parray<uint8_t, 0x0C> unknown_a1;
/* 1C */ le_uint32_t client_id = 0;
/* 20 */ pstring<TextEncoding::UTF16, 0x10> name;
/* 20 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> name;
// If this field is zero, the "Press F1 for help" prompt appears in the corner
// of the screen in the lobby and on Pioneer 2.
/* 40 */ le_uint32_t hide_help_prompt = 1;
@@ -441,7 +439,7 @@ struct PlayerRecordsBB_Challenge {
/* 00F4 */ ChallengeAwardState<false> ep1_online_award_state;
/* 00FC */ ChallengeAwardState<false> ep2_online_award_state;
/* 0104 */ ChallengeAwardState<false> ep1_offline_award_state;
/* 010C */ pstring<TextEncoding::UTF16, 0x0C> rank_title; // Encrypted; see decrypt_challenge_rank_text
/* 010C */ pstring<TextEncoding::CHALLENGE16, 0x0C> rank_title;
/* 0124 */ parray<uint8_t, 0x1C> unknown_l7;
/* 0140 */
+1 -1
View File
@@ -518,7 +518,7 @@ static HandlerResult S_V123_04(shared_ptr<ProxyServer::LinkedSession> ses, uint1
ses->log.info("Remote guild card number set to %" PRId64,
ses->remote_guild_card_number);
string message = string_printf(
"The remote server\nhas assigned your\nGuild Card number:\n\tC6%" PRId64,
"The remote server\nhas assigned your\nGuild Card number:\n$C6%" PRId64,
ses->remote_guild_card_number);
send_ship_info(ses->client_channel, message);
}
+1 -1
View File
@@ -826,7 +826,7 @@ void ProxyServer::LinkedSession::send_to_game_server(const char* error_message)
this->disconnect();
} else {
send_ship_info(this->client_channel, string_printf("You\'ve returned to\n\tC6%s$C7\n\n%s", s->name.c_str(), error_message ? error_message : ""));
send_ship_info(this->client_channel, string_printf("You\'ve returned to\n$C6%s$C7\n\n%s", s->name.c_str(), error_message ? error_message : ""));
// Restore newserv_client_config, so the login server gets the client flags
if (is_v3(this->version())) {
+1
View File
@@ -51,6 +51,7 @@ static string escape_string(const string& data, TextEncoding encoding = TextEnco
decoded = data;
break;
case TextEncoding::UTF16:
case TextEncoding::UTF16_ALWAYS_MARKED:
decoded = tt_utf16_to_utf8(data);
break;
case TextEncoding::SJIS:
+1 -7
View File
@@ -3168,9 +3168,6 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->license->save();
string name_str = player->disp.name.decode(c->language());
if ((name_str.size() > 2) && (name_str[0] == '\t') && ((name_str[1] == 'E') || (name_str[1] == 'J'))) {
name_str = name_str.substr(2);
}
c->channel.name = string_printf("C-%" PRIX64 " (%s)", c->id, name_str.c_str());
// 98 should only be sent when leaving a game, and we should leave the client
@@ -3303,9 +3300,6 @@ static void on_06(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
auto p = c->character();
string from_name = p->disp.name.decode(c->language());
if (from_name.size() >= 2 && from_name[0] == '\t' && (from_name[1] == 'E' || from_name[1] == 'J')) {
from_name = from_name.substr(2);
}
static const string whisper_text = "(whisper)";
for (size_t x = 0; x < l->max_clients; x++) {
if (l->clients[x]) {
@@ -3368,7 +3362,7 @@ static void on_E3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
auto s = c->require_server_state();
try {
auto preview = c->character()->disp.to_preview();
auto preview = c->character()->to_preview();
send_player_preview_bb(c, cmd.character_index, &preview);
} catch (const exception& e) {
+1 -4
View File
@@ -587,9 +587,6 @@ public:
this->xb_user_id = this->default_xb_user_id();
this->xb_unknown_a16 = cmd.unknown_a16;
this->name = cmd.name.decode(cmd.base.language);
if ((this->name.size() > 2) && (this->name[0] == '\t') && ((this->name[1] == 'E') || (this->name[1] == 'J'))) {
this->name = this->name.substr(2);
}
this->visual.name.encode(this->name, cmd.base.language);
}
@@ -663,7 +660,7 @@ public:
G_SyncPlayerDispAndInventory_BB_6x70 as_bb(uint8_t language) const {
G_SyncPlayerDispAndInventory_BB_6x70 ret;
ret.base = this->base_v1();
ret.name.encode("\tJ" + this->name, language);
ret.name.encode(this->name, language);
ret.base.visual.name.encode(string_printf("%10" PRId32, this->guild_card_number), language);
ret.stats = this->stats;
ret.num_items = this->num_items;
+10
View File
@@ -210,6 +210,16 @@ PSOBBBaseSystemFile::PSOBBBaseSystemFile() {
}
}
PlayerDispDataBBPreview PSOBBCharacterFile::to_preview() const {
PlayerDispDataBBPreview pre;
pre.level = this->disp.stats.level;
pre.experience = this->disp.stats.experience;
pre.visual = this->disp.visual;
pre.name = this->disp.name;
pre.play_time_seconds = this->play_time_seconds;
return pre;
}
shared_ptr<PSOBBCharacterFile> PSOBBCharacterFile::create_from_config(
uint32_t guild_card_number,
uint8_t language,
+5 -3
View File
@@ -142,7 +142,7 @@ struct PSOBBTeamMembership {
/* 0011 */ uint8_t unknown_a7 = 0;
/* 0012 */ uint8_t unknown_a8 = 0;
/* 0013 */ uint8_t unknown_a9 = 0;
/* 0014 */ pstring<TextEncoding::UTF16, 0x0010> team_name;
/* 0014 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x0010> team_name;
/* 0034 */ parray<le_uint16_t, 0x20 * 0x20> flag_data;
/* 0834 */ le_uint32_t reward_flags = 0;
/* 0838 */
@@ -173,7 +173,7 @@ struct PSOBBFullSystemFile {
struct PSOBBCharacterFile {
struct SymbolChatEntry {
/* 00 */ le_uint32_t present = 0;
/* 04 */ pstring<TextEncoding::UTF16, 0x14> name;
/* 04 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x14> name;
/* 2C */ SymbolChat data;
/* 68 */
} __attribute__((packed));
@@ -219,6 +219,8 @@ struct PSOBBCharacterFile {
PSOBBCharacterFile() = default;
PlayerDispDataBBPreview to_preview() const;
static std::shared_ptr<PSOBBCharacterFile> create_from_config(
uint32_t guild_card_number,
uint8_t language,
@@ -784,6 +786,6 @@ struct LegacySavedAccountDataBB { // .nsa file format
/* E13C */ le_uint32_t option_flags;
/* E140 */ parray<uint8_t, 0x0A40> shortcuts;
/* EB80 */ parray<PSOBBCharacterFile::SymbolChatEntry, 12> symbol_chats;
/* F060 */ pstring<TextEncoding::UTF16, 0x0010> team_name;
/* F060 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x0010> team_name;
/* F080 */
} __attribute__((packed));
+5 -9
View File
@@ -653,7 +653,6 @@ void send_complete_player_bb(shared_ptr<Client> c) {
if (team) {
cmd.system_file.team_membership = team->membership_for_member(c->license->serial_number);
}
cmd.char_file.disp.play_time = 0;
send_command_t(c, 0x00E7, 0x00000000, cmd);
}
@@ -837,7 +836,7 @@ string prepare_chat_data(
string data;
if (version == Version::BB_V4) {
data.append("\tJ");
data.append(language ? "\tE" : "\tJ");
}
data.append(from_name);
if (version == Version::DC_NTE) {
@@ -1415,7 +1414,9 @@ void send_game_menu(
shared_ptr<Client> c,
bool is_spectator_team_list,
bool show_tournaments_only) {
if (uses_utf16(c->version())) {
if (is_v4(c->version())) {
send_game_menu_t<TextEncoding::UTF16_ALWAYS_MARKED>(c, is_spectator_team_list, show_tournaments_only);
} else if (uses_utf16(c->version())) {
send_game_menu_t<TextEncoding::UTF16>(c, is_spectator_team_list, show_tournaments_only);
} else {
send_game_menu_t<TextEncoding::MARKED>(c, is_spectator_team_list, show_tournaments_only);
@@ -1639,12 +1640,7 @@ void populate_lobby_data_for_client<PlayerLobbyDataBB>(PlayerLobbyDataBB& ret, s
ret.team_id = 0;
}
string name = c->character()->disp.name.decode(c->language());
if ((name.size() >= 2) && (name[0] == '\t') && (name[1] != 'C')) {
ret.name.encode(name, viewer_c->language());
} else {
const char* marker = c->language() ? "\tE" : "\tJ";
ret.name.encode(marker + name, viewer_c->language());
}
ret.name.encode(name, viewer_c->language());
}
static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l) {
+1 -1
View File
@@ -136,7 +136,7 @@ PSOBBTeamMembership TeamIndex::Team::membership_for_member(uint32_t serial_numbe
ret.unknown_a7 = 0;
ret.unknown_a8 = 0;
ret.unknown_a9 = 0;
ret.team_name.encode("\tE" + this->name);
ret.team_name.encode(this->name);
if (this->flag_data) {
ret.flag_data = *this->flag_data;
} else {
+17 -1
View File
@@ -252,6 +252,7 @@ enum class TextEncoding {
ISO8859,
ASCII,
MARKED,
UTF16_ALWAYS_MARKED,
CHALLENGE8, // MARKED but with challenge encryption on top
CHALLENGE16, // UTF16 but with challenge encryption on top
};
@@ -290,7 +291,7 @@ void decrypt_challenge_rank_text_t(void* vdata, size_t count) {
template <
TextEncoding Encoding,
size_t Chars,
size_t BytesPerChar = (((Encoding == TextEncoding::UTF16) || (Encoding == TextEncoding::CHALLENGE16)) ? 2 : 1)>
size_t BytesPerChar = (((Encoding == TextEncoding::UTF16) || (Encoding == TextEncoding::UTF16_ALWAYS_MARKED) || (Encoding == TextEncoding::CHALLENGE16)) ? 2 : 1)>
struct pstring {
static constexpr size_t Bytes = Chars * BytesPerChar;
@@ -349,6 +350,17 @@ struct pstring {
this->clear_after_bytes(ret.bytes_written);
break;
}
case TextEncoding::UTF16_ALWAYS_MARKED:
if (s.empty()) {
this->clear();
break;
} else if (s.size() <= 2 || s[0] != '\t' || s[1] == 'C') {
std::string to_encode = ((client_language == 0) ? "\tJ" : "\tE") + s;
auto ret = tt_utf8_to_utf16(this->data, Bytes, to_encode.data(), to_encode.size(), true);
this->clear_after_bytes(ret.bytes_written);
break;
}
[[fallthrough]];
case TextEncoding::UTF16: {
auto ret = tt_utf8_to_utf16(this->data, Bytes, s.data(), s.size(), true);
this->clear_after_bytes(ret.bytes_written);
@@ -437,6 +449,10 @@ struct pstring {
return tt_sjis_to_utf8(this->data, this->used_chars_8());
case TextEncoding::UTF16:
return tt_utf16_to_utf8(this->data, this->used_chars_16() * 2);
case TextEncoding::UTF16_ALWAYS_MARKED: {
std::string ret = tt_utf16_to_utf8(this->data, this->used_chars_16() * 2);
return ((ret.size() >= 2) && (ret[0] == '\t') && (ret[1] != 'C')) ? ret.substr(2) : ret;
}
case TextEncoding::UTF8:
return std::string(reinterpret_cast<const char*>(&this->data[0]), this->used_chars_8());
case TextEncoding::CHALLENGE16: {