diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index f8af820b..21d124a9 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -690,8 +690,12 @@ static void transcode_inventory_items( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_DCNTE_6x70& cmd, uint32_t guild_card_number, Version from_version) + const G_SyncPlayerDispAndInventory_DCNTE_6x70& cmd, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) : from_version(from_version), + from_client_customization(from_client_customization), item_version(from_version), base(cmd.base), unknown_a5_nte(cmd.unknown_a5), @@ -719,8 +723,13 @@ Parsed6x70Data::Parsed6x70Data( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_DC112000_6x70& cmd, uint32_t guild_card_number, uint8_t language, Version from_version) + const G_SyncPlayerDispAndInventory_DC112000_6x70& cmd, + uint32_t guild_card_number, + uint8_t language, + Version from_version, + bool from_client_customization) : from_version(from_version), + from_client_customization(from_client_customization), item_version(from_version), base(cmd.base), unknown_a5_nte(0), @@ -749,8 +758,11 @@ Parsed6x70Data::Parsed6x70Data( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_DC_PC_6x70& cmd, uint32_t guild_card_number, Version from_version) - : Parsed6x70Data(cmd.base, guild_card_number, from_version) { + const G_SyncPlayerDispAndInventory_DC_PC_6x70& cmd, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) + : Parsed6x70Data(cmd.base, guild_card_number, from_version, from_client_customization) { this->stats = cmd.stats; this->num_items = cmd.num_items; this->items = cmd.items; @@ -761,8 +773,11 @@ Parsed6x70Data::Parsed6x70Data( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_GC_6x70& cmd, uint32_t guild_card_number, Version from_version) - : Parsed6x70Data(cmd.base, guild_card_number, from_version) { + const G_SyncPlayerDispAndInventory_GC_6x70& cmd, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) + : Parsed6x70Data(cmd.base, guild_card_number, from_version, from_client_customization) { this->stats = cmd.stats; this->num_items = cmd.num_items; this->items = cmd.items; @@ -773,8 +788,11 @@ Parsed6x70Data::Parsed6x70Data( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_XB_6x70& cmd, uint32_t guild_card_number, Version from_version) - : Parsed6x70Data(cmd.base, guild_card_number, from_version) { + const G_SyncPlayerDispAndInventory_XB_6x70& cmd, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) + : Parsed6x70Data(cmd.base, guild_card_number, from_version, from_client_customization) { this->stats = cmd.stats; this->num_items = cmd.num_items; this->items = cmd.items; @@ -785,8 +803,11 @@ Parsed6x70Data::Parsed6x70Data( } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_BB_6x70& cmd, uint32_t guild_card_number, Version from_version) - : Parsed6x70Data(cmd.base, guild_card_number, from_version) { + const G_SyncPlayerDispAndInventory_BB_6x70& cmd, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) + : Parsed6x70Data(cmd.base, guild_card_number, from_version, from_client_customization) { this->stats = cmd.stats; this->num_items = cmd.num_items; this->items = cmd.items; @@ -815,8 +836,10 @@ G_SyncPlayerDispAndInventory_DCNTE_6x70 Parsed6x70Data::as_dc_nte(shared_ptritem_version, Version::DC_NTE, s->item_parameter_table_for_encode(Version::DC_NTE)); ret.visual.enforce_lobby_join_limits_for_version(Version::DC_NTE); - if (s->version_name_colors) { - ret.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.visual.name_color = name_color; ret.visual.compute_name_color_checksum(); } return ret; @@ -841,10 +864,13 @@ G_SyncPlayerDispAndInventory_DC112000_6x70 Parsed6x70Data::as_dc_112000(shared_p transcode_inventory_items( ret.items, ret.num_items, this->item_version, Version::DC_V1_11_2000_PROTOTYPE, s->item_parameter_table_for_encode(Version::DC_V1_11_2000_PROTOTYPE)); ret.visual.enforce_lobby_join_limits_for_version(Version::DC_V1_11_2000_PROTOTYPE); - if (s->version_name_colors) { - ret.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.visual.name_color = name_color; ret.visual.compute_name_color_checksum(); } + return ret; } @@ -858,10 +884,13 @@ G_SyncPlayerDispAndInventory_DC_PC_6x70 Parsed6x70Data::as_dc_pc(shared_ptritem_version, to_version, s->item_parameter_table_for_encode(to_version)); ret.base.visual.enforce_lobby_join_limits_for_version(to_version); - if (s->version_name_colors) { - ret.base.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.base.visual.name_color = name_color; ret.base.visual.compute_name_color_checksum(); } + return ret; } @@ -876,14 +905,17 @@ G_SyncPlayerDispAndInventory_GC_6x70 Parsed6x70Data::as_gc_gcnte(shared_ptritem_version, to_version, s->item_parameter_table_for_encode(to_version)); ret.base.visual.enforce_lobby_join_limits_for_version(to_version); - if (s->version_name_colors) { - ret.base.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.base.visual.name_color = name_color; if (is_v1_or_v2(to_version)) { ret.base.visual.compute_name_color_checksum(); } else { ret.base.visual.name_color_checksum = 0; } } + return ret; } @@ -901,10 +933,13 @@ G_SyncPlayerDispAndInventory_XB_6x70 Parsed6x70Data::as_xb(shared_ptritem_version, Version::XB_V3, s->item_parameter_table_for_encode(Version::XB_V3)); ret.base.visual.enforce_lobby_join_limits_for_version(Version::XB_V3); - if (s->version_name_colors) { - ret.base.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.base.visual.name_color = name_color; ret.base.visual.name_color_checksum = 0; } + return ret; } @@ -924,10 +959,13 @@ G_SyncPlayerDispAndInventory_BB_6x70 Parsed6x70Data::as_bb(shared_ptritem_version, Version::BB_V4, s->item_parameter_table_for_encode(Version::BB_V4)); ret.base.visual.enforce_lobby_join_limits_for_version(Version::BB_V4); - if (s->version_name_colors) { - ret.base.visual.name_color = s->name_color_for_version(this->from_version); + + uint32_t name_color = s->name_color_for_client(this->from_version, this->from_client_customization); + if (name_color) { + ret.base.visual.name_color = name_color; ret.base.visual.name_color_checksum = 0; } + return ret; } @@ -955,8 +993,12 @@ void Parsed6x70Data::clear_dc_protos_unused_item_fields() { } Parsed6x70Data::Parsed6x70Data( - const G_SyncPlayerDispAndInventory_BaseV1& base, uint32_t guild_card_number, Version from_version) + const G_SyncPlayerDispAndInventory_BaseV1& base, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization) : from_version(from_version), + from_client_customization(from_client_customization), item_version(this->from_version), base(base.base), bonus_hp_from_materials(base.bonus_hp_from_materials), @@ -1018,17 +1060,18 @@ static void on_sync_joining_player_disp_and_inventory( send_command(target, 0x62, target->lobby_client_id, &data, sizeof(data)); } + bool is_client_customisation = c->config.check_flag(Client::Flag::IS_CLIENT_CUSTOMIZATION); switch (c_v) { case Version::DC_NTE: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c_v)); + c->login->account->account_id, c_v, is_client_customisation)); c->last_reported_6x70->clear_dc_protos_unused_item_fields(); break; case Version::DC_V1_11_2000_PROTOTYPE: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c->language(), c_v)); + c->login->account->account_id, c->language(), c_v, is_client_customisation)); c->last_reported_6x70->clear_dc_protos_unused_item_fields(); break; case Version::DC_V1: @@ -1037,7 +1080,7 @@ static void on_sync_joining_player_disp_and_inventory( case Version::PC_V2: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c_v)); + c->login->account->account_id, c_v, is_client_customisation)); if (c_v == Version::DC_V1) { c->last_reported_6x70->clear_v1_unused_item_fields(); } @@ -1048,17 +1091,17 @@ static void on_sync_joining_player_disp_and_inventory( case Version::GC_EP3: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c_v)); + c->login->account->account_id, c_v, is_client_customisation)); break; case Version::XB_V3: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c_v)); + c->login->account->account_id, c_v, is_client_customisation)); break; case Version::BB_V4: c->last_reported_6x70.reset(new Parsed6x70Data( check_size_t(data, size), - c->login->account->account_id, c_v)); + c->login->account->account_id, c_v, is_client_customisation)); break; default: throw logic_error("6x70 command from unknown game version"); diff --git a/src/ReceiveSubcommands.hh b/src/ReceiveSubcommands.hh index e0f7ccce..094d0f62 100644 --- a/src/ReceiveSubcommands.hh +++ b/src/ReceiveSubcommands.hh @@ -40,6 +40,7 @@ DropReconcileResult reconcile_drop_request_with_map( class Parsed6x70Data { public: Version from_version; + bool from_client_customization; Version item_version; G_SyncPlayerDispAndInventory_BaseDCNTE base; @@ -73,28 +74,34 @@ public: Parsed6x70Data( const G_SyncPlayerDispAndInventory_DCNTE_6x70& cmd, uint32_t guild_card_number, - Version from_version); + Version from_version, + bool from_client_customization); Parsed6x70Data( const G_SyncPlayerDispAndInventory_DC112000_6x70& cmd, uint32_t guild_card_number, uint8_t language, - Version from_version); + Version from_version, + bool from_client_customization); Parsed6x70Data( const G_SyncPlayerDispAndInventory_DC_PC_6x70& cmd, uint32_t guild_card_number, - Version from_version); + Version from_version, + bool from_client_customization); Parsed6x70Data( const G_SyncPlayerDispAndInventory_GC_6x70& cmd, uint32_t guild_card_number, - Version from_version); + Version from_version, + bool from_client_customization); Parsed6x70Data( const G_SyncPlayerDispAndInventory_XB_6x70& cmd, uint32_t guild_card_number, - Version from_version); + Version from_version, + bool from_client_customization); Parsed6x70Data( const G_SyncPlayerDispAndInventory_BB_6x70& cmd, uint32_t guild_card_number, - Version from_version); + Version from_version, + bool from_client_customization); G_SyncPlayerDispAndInventory_DCNTE_6x70 as_dc_nte(std::shared_ptr s) const; G_SyncPlayerDispAndInventory_DC112000_6x70 as_dc_112000(std::shared_ptr s) const; @@ -108,6 +115,10 @@ public: void clear_dc_protos_unused_item_fields(); protected: - Parsed6x70Data(const G_SyncPlayerDispAndInventory_BaseV1& base, uint32_t guild_card_number, Version from_version); + Parsed6x70Data( + const G_SyncPlayerDispAndInventory_BaseV1& base, + uint32_t guild_card_number, + Version from_version, + bool from_client_customization); G_SyncPlayerDispAndInventory_BaseV1 base_v1() const; }; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index ad6b4fe8..a2cd1954 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -1842,9 +1842,10 @@ static void send_join_spectator_team(shared_ptr c, shared_ptr l) : wc_p->disp.stats.level.load(); e.name_color = wc_p->disp.visual.name_color; - if (s->version_name_colors) { - p.disp.visual.name_color = s->name_color_for_version(wc->version()); - e.name_color = p.disp.visual.name_color; + uint32_t name_color = s->name_color_for_client(wc); + if (name_color) { + p.disp.visual.name_color = name_color; + e.name_color = name_color; } player_count++; @@ -1910,9 +1911,10 @@ static void send_join_spectator_team(shared_ptr c, shared_ptr l) : other_p->disp.stats.level.load(); cmd_e.name_color = other_p->disp.visual.name_color; - if (s->version_name_colors) { - cmd_p.disp.visual.name_color = s->name_color_for_version(other_c->version()); - cmd_e.name_color = cmd_p.disp.visual.name_color; + uint32_t name_color = s->name_color_for_client(other_c); + if (name_color) { + cmd_p.disp.visual.name_color = name_color; + cmd_e.name_color = name_color; } player_count++; @@ -2014,15 +2016,17 @@ void send_join_game(shared_ptr c, shared_ptr l) { size_t player_count = populate_v3_cmd(cmd); auto s = c->require_server_state(); for (size_t x = 0; x < 4; x++) { - if (l->clients[x]) { - auto other_p = l->clients[x]->character(); + auto lc = l->clients[x]; + if (lc) { + auto other_p = lc->character(); auto& cmd_p = cmd.players_ep3[x]; cmd_p.inventory = other_p->inventory; cmd_p.inventory.encode_for_client(c->version(), s->item_parameter_table_for_encode(c->version())); cmd_p.disp = convert_player_disp_data(other_p->disp, c->language(), other_p->inventory.language); cmd_p.disp.enforce_lobby_join_limits_for_version(c->version()); - if (s->version_name_colors) { - cmd_p.disp.visual.name_color = s->name_color_for_version(l->clients[x]->version()); + uint32_t name_color = s->name_color_for_client(lc); + if (name_color) { + cmd_p.disp.visual.name_color = name_color; } } } @@ -2140,8 +2144,9 @@ void send_join_lobby_t(shared_ptr c, shared_ptr l, shared_ptr(lp->disp, c->language(), lp->inventory.language); e.disp.enforce_lobby_join_limits_for_version(c->version()); - if (s->version_name_colors) { - e.disp.visual.name_color = s->name_color_for_version(lc->version()); + uint32_t name_color = s->name_color_for_client(lc); + if (name_color) { + e.disp.visual.name_color = name_color; if (is_v1_or_v2(c->version())) { e.disp.visual.compute_name_color_checksum(); } @@ -2212,8 +2217,9 @@ void send_join_lobby_xb(shared_ptr c, shared_ptr l, shared_ptrversion(), s->item_parameter_table_for_encode(c->version())); e.disp = convert_player_disp_data(lp->disp, c->language(), lp->inventory.language); e.disp.enforce_lobby_join_limits_for_version(c->version()); - if (s->version_name_colors) { - e.disp.visual.name_color = s->name_color_for_version(lc->version()); + uint32_t name_color = s->name_color_for_client(lc); + if (name_color) { + e.disp.visual.name_color = name_color; } } @@ -2263,8 +2269,9 @@ void send_join_lobby_dc_nte(shared_ptr c, shared_ptr l, } else { e.disp = convert_player_disp_data(lp->disp, c->language(), lp->inventory.language); e.disp.enforce_lobby_join_limits_for_version(c->version()); - if (s->version_name_colors) { - e.disp.visual.name_color = s->name_color_for_version(lc->version()); + uint32_t name_color = s->name_color_for_client(lc); + if (name_color) { + e.disp.visual.name_color = name_color; e.disp.visual.compute_name_color_checksum(); } } diff --git a/src/ServerState.cc b/src/ServerState.cc index f098ac28..6cd8b71a 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -951,6 +951,7 @@ void ServerState::load_config_early() { this->enable_chat_commands = this->config_json->get_bool("EnableChatCommands", true); this->version_name_colors.reset(); + this->client_customization_name_color = 0; try { const auto& colors_json = this->config_json->get_list("VersionNameColors"); if (colors_json.size() != NUM_NON_PATCH_VERSIONS) { @@ -963,6 +964,10 @@ void ServerState::load_config_early() { this->version_name_colors = std::move(new_colors); } catch (const out_of_range&) { } + try { + this->client_customization_name_color = this->config_json->get_int("ClientCustomizationNameColor"); + } catch (const out_of_range&) { + } for (auto& order : this->public_lobby_search_orders) { order.clear(); diff --git a/src/ServerState.hh b/src/ServerState.hh index 375c34df..1804205f 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -95,6 +95,7 @@ struct ServerState : public std::enable_shared_from_this { bool allow_gc_xb_games = true; bool enable_chat_commands = true; std::unique_ptr> version_name_colors; + uint32_t client_customization_name_color = 0x00000000; uint8_t allowed_drop_modes_v1_v2_normal = 0x1F; uint8_t allowed_drop_modes_v1_v2_battle = 0x07; uint8_t allowed_drop_modes_v1_v2_challenge = 0x07; @@ -316,9 +317,15 @@ struct ServerState : public std::enable_shared_from_this { const std::vector public_lobby_search_order(Version version) const; - inline uint32_t name_color_for_version(Version v) const { + inline uint32_t name_color_for_client(Version v, bool is_client_customization) const { + if (is_client_customization && this->client_customization_name_color) { + return this->client_customization_name_color; + } return this->version_name_colors ? this->version_name_colors->at(static_cast(v) - NUM_PATCH_VERSIONS) : 0; } + inline uint32_t name_color_for_client(std::shared_ptr c) const { + return this->name_color_for_client(c->version(), c->config.check_flag(Client::Flag::IS_CLIENT_CUSTOMIZATION)); + } std::shared_ptr> information_contents_for_client(std::shared_ptr c) const; std::shared_ptr quest_index(Version version) const; diff --git a/system/config.example.json b/system/config.example.json index 03e8c0d5..68cdbde4 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -1065,6 +1065,7 @@ // 0xFFBBFFBB, // Xbox // 0xFF55FDE3, // BB (the official Episode 4 color is probably 0xFFC69141) // ], + // "ClientCustomizationNameColor": 0xFFFFBBBB, // These options control which item drop modes are used by default, and which // can be chosen by the player. The AllowedDropModes fields are bit fields