fix play time field and marked utf16 fields
This commit is contained in:
+1
-3
@@ -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
@@ -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
@@ -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
@@ -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()));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
@@ -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())) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user