This commit is contained in:
@@ -859,6 +859,13 @@ void Client::load_all_files() {
|
||||
if (this->character_data) {
|
||||
// Clear legacy play_time field
|
||||
this->character_data->disp.name.clear_after_bytes(0x18);
|
||||
|
||||
// Enforce item stack limits, in case they've changed
|
||||
auto s = this->require_server_state();
|
||||
auto stack_limits = s->item_stack_limits(this->version());
|
||||
this->character_data->inventory.enforce_stack_limits(stack_limits);
|
||||
this->character_data->bank.enforce_stack_limits(stack_limits);
|
||||
|
||||
this->login->account->auto_reply_message = this->character_data->auto_reply.decode();
|
||||
this->login->account->save();
|
||||
this->last_play_time_update = phosg::now();
|
||||
|
||||
+8
-3
@@ -254,9 +254,14 @@ size_t ItemData::max_stack_size(const StackLimits& limits) const {
|
||||
return limits.get(this->data1[0], this->data1[1]);
|
||||
}
|
||||
|
||||
void ItemData::enforce_min_stack_size(const StackLimits& limits) {
|
||||
if (this->stack_size(limits) == 0) {
|
||||
this->data1[5] = 1;
|
||||
void ItemData::enforce_stack_size_limits(const StackLimits& limits) {
|
||||
if (this->data1[0] == 0x03) {
|
||||
size_t max_stack_size = this->max_stack_size(limits);
|
||||
if (max_stack_size > 1) {
|
||||
this->data1[5] = std::clamp<uint8_t>(this->data1[5], 1, max_stack_size);
|
||||
} else {
|
||||
this->data1[5] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ struct ItemData {
|
||||
bool is_stackable(const StackLimits& limits) const;
|
||||
size_t stack_size(const StackLimits& limits) const;
|
||||
size_t max_stack_size(const StackLimits& limits) const;
|
||||
void enforce_min_stack_size(const StackLimits& limits);
|
||||
void enforce_stack_size_limits(const StackLimits& limits);
|
||||
|
||||
static bool is_common_consumable(uint32_t primary_identifier);
|
||||
bool is_common_consumable() const;
|
||||
|
||||
@@ -396,7 +396,7 @@ ItemData ItemNameIndex::parse_item_description(const std::string& desc) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.enforce_min_stack_size(*this->limits);
|
||||
ret.enforce_stack_size_limits(*this->limits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,6 +287,12 @@ struct PlayerInventoryT {
|
||||
}
|
||||
}
|
||||
|
||||
void enforce_stack_limits(std::shared_ptr<const ItemData::StackLimits> stack_limits) {
|
||||
for (size_t z = 0; z < std::min<uint8_t>(this->num_items, this->items.size()); z++) {
|
||||
this->items[z].data.enforce_stack_size_limits(*stack_limits);
|
||||
}
|
||||
}
|
||||
|
||||
operator PlayerInventoryT<!BE>() const {
|
||||
PlayerInventoryT<!BE> ret;
|
||||
ret.num_items = this->num_items;
|
||||
@@ -410,6 +416,12 @@ struct PlayerBankT {
|
||||
}
|
||||
}
|
||||
|
||||
void enforce_stack_limits(std::shared_ptr<const ItemData::StackLimits> stack_limits) {
|
||||
for (size_t z = 0; z < std::min<uint8_t>(this->num_items, this->items.size()); z++) {
|
||||
this->items[z].data.enforce_stack_size_limits(*stack_limits);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t DestSlotCount, bool DestBE>
|
||||
operator PlayerBankT<DestSlotCount, DestBE>() const {
|
||||
PlayerBankT<DestSlotCount, DestBE> ret;
|
||||
|
||||
@@ -4056,7 +4056,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
|
||||
|
||||
ItemData item;
|
||||
item = cmd.item_data;
|
||||
item.enforce_min_stack_size(limits);
|
||||
item.enforce_stack_size_limits(limits);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
|
||||
// The logic for the item_create and item_create2 opcodes (B3 and B4)
|
||||
@@ -4717,7 +4717,7 @@ static asio::awaitable<void> on_quest_exchange_item_bb(shared_ptr<Client> c, Sub
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.replace_item;
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.enforce_stack_size_limits(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
@@ -4775,7 +4775,7 @@ static asio::awaitable<void> on_photon_drop_exchange_for_item_bb(shared_ptr<Clie
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.new_item;
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.enforce_stack_size_limits(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
@@ -4875,7 +4875,7 @@ static asio::awaitable<void> on_secret_lottery_ticket_exchange_bb(shared_ptr<Cli
|
||||
ItemData item = (s->secret_lottery_results.size() == 1)
|
||||
? s->secret_lottery_results[0]
|
||||
: s->secret_lottery_results[l->rand_crypt->next() % s->secret_lottery_results.size()];
|
||||
item.enforce_min_stack_size(limits);
|
||||
item.enforce_stack_size_limits(limits);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
@@ -4950,7 +4950,7 @@ static asio::awaitable<void> on_quest_F95E_result_bb(shared_ptr<Client> c, Subco
|
||||
} else if (item.data1[0] == 0x00) {
|
||||
item.data1[4] |= 0x80; // Unidentified
|
||||
} else {
|
||||
item.enforce_min_stack_size(*s->item_stack_limits(c->version()));
|
||||
item.enforce_stack_size_limits(*s->item_stack_limits(c->version()));
|
||||
}
|
||||
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
@@ -4996,7 +4996,7 @@ static asio::awaitable<void> on_quest_F95F_result_bb(shared_ptr<Client> c, Subco
|
||||
send_command_t(c, 0x60, 0x00, cmd_6xDB);
|
||||
|
||||
ItemData new_item = result.second;
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.enforce_stack_size_limits(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
@@ -5116,7 +5116,7 @@ static asio::awaitable<void> on_momoka_item_exchange_bb(shared_ptr<Client> c, Su
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.replace_item;
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.enforce_stack_size_limits(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
Reference in New Issue
Block a user