make it possible to disable item tracking

This commit is contained in:
Martin Michelsen
2022-06-24 22:00:47 -07:00
parent c2b112db43
commit fc078a5d51
10 changed files with 168 additions and 85 deletions
+5 -2
View File
@@ -590,7 +590,9 @@ static void command_what(shared_ptr<ServerState>, shared_ptr<Lobby> l,
if (!l->episode || (l->episode > 3)) { if (!l->episode || (l->episode > 3)) {
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
send_text_message(c, u"$C4Item tracking is off");
} else {
float min_dist2 = 0.0f; float min_dist2 = 0.0f;
uint32_t nearest_item_id = 0xFFFFFFFF; uint32_t nearest_item_id = 0xFFFFFFFF;
for (const auto& it : l->item_id_to_floor_item) { for (const auto& it : l->item_id_to_floor_item) {
@@ -607,13 +609,14 @@ static void command_what(shared_ptr<ServerState>, shared_ptr<Lobby> l,
} }
if (nearest_item_id == 0xFFFFFFFF) { if (nearest_item_id == 0xFFFFFFFF) {
send_text_message(c, u"No items are near you"); send_text_message(c, u"$C4No items are near you");
} else { } else {
const auto& item = l->item_id_to_floor_item.at(nearest_item_id); const auto& item = l->item_id_to_floor_item.at(nearest_item_id);
string name = name_for_item(item.inv_item.data, true); string name = name_for_item(item.inv_item.data, true);
send_text_message(c, decode_sjis(name)); send_text_message(c, decode_sjis(name));
} }
} }
}
static void command_song(shared_ptr<ServerState>, shared_ptr<Lobby>, static void command_song(shared_ptr<ServerState>, shared_ptr<Lobby>,
shared_ptr<Client> c, const std::u16string& args) { shared_ptr<Client> c, const std::u16string& args) {
+3 -2
View File
@@ -96,8 +96,9 @@ void Lobby::add_client(shared_ptr<Client> c) {
} }
} }
// If the lobby is a game, assign the inventory's item IDs // If the lobby is a game and item tracking is enabled, assign the inventory's
if (this->is_game()) { // item IDs
if (this->is_game() && (this->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto& inv = c->game_data.player()->inventory; auto& inv = c->game_data.player()->inventory;
size_t count = min<uint8_t>(inv.num_items, 30); size_t count = min<uint8_t>(inv.num_items, 30);
for (size_t x = 0; x < count; x++) { for (size_t x = 0; x < count; x++) {
+13 -8
View File
@@ -18,14 +18,19 @@
struct Lobby { struct Lobby {
enum Flag { enum Flag {
GAME = 0x01, GAME = 0x00000001,
CHEATS_ENABLED = 0x02, // game only EPISODE_3_ONLY = 0x00000002,
PUBLIC = 0x04, // lobby only
EPISODE_3_ONLY = 0x08, // lobby & game // Flags used only for games
QUEST_IN_PROGRESS = 0x10, // game only CHEATS_ENABLED = 0x00000100,
JOINABLE_QUEST_IN_PROGRESS = 0x20, // game only QUEST_IN_PROGRESS = 0x00000200,
DEFAULT = 0x40, // lobby only; not set for games and private lobbies JOINABLE_QUEST_IN_PROGRESS = 0x00000400,
PERSISTENT = 0x80, // if not set, lobby is deleted when empty ITEM_TRACKING_ENABLED = 0x00000800,
// Flags used only for lobbies
PUBLIC = 0x00010000,
DEFAULT = 0x00020000,
PERSISTENT = 0x00040000,
}; };
uint32_t lobby_id; uint32_t lobby_id;
+6
View File
@@ -128,6 +128,12 @@ void populate_state_from_config(shared_ptr<ServerState> s,
s->allow_unregistered_users = true; s->allow_unregistered_users = true;
} }
try {
s->item_tracking_enabled = d.at("EnableItemTracking")->as_bool();
} catch (const out_of_range&) {
s->item_tracking_enabled = true;
}
for (const string& filename : list_directory("system/blueburst/keys")) { for (const string& filename : list_directory("system/blueburst/keys")) {
if (!ends_with(filename, ".nsk")) { if (!ends_with(filename, ".nsk")) {
continue; continue;
+6 -1
View File
@@ -1767,6 +1767,8 @@ shared_ptr<Lobby> create_game_generic(shared_ptr<ServerState> s,
throw invalid_argument("level too low for difficulty"); throw invalid_argument("level too low for difficulty");
} }
bool item_tracking_enabled = (c->version == GameVersion::BB) | s->item_tracking_enabled;
shared_ptr<Lobby> game(new Lobby()); shared_ptr<Lobby> game(new Lobby());
game->name = name; game->name = name;
game->password = password; game->password = password;
@@ -1787,7 +1789,10 @@ shared_ptr<Lobby> create_game_generic(shared_ptr<ServerState> s,
game->event = Lobby::game_event_for_lobby_event(current_lobby->event); game->event = Lobby::game_event_for_lobby_event(current_lobby->event);
game->block = 0xFF; game->block = 0xFF;
game->max_clients = 4; game->max_clients = 4;
game->flags = (is_ep3 ? Lobby::Flag::EPISODE_3_ONLY : 0) | Lobby::Flag::GAME; game->flags =
(is_ep3 ? Lobby::Flag::EPISODE_3_ONLY : 0) |
(item_tracking_enabled ? Lobby::Flag::ITEM_TRACKING_ENABLED : 0) |
Lobby::Flag::GAME;
game->min_level = min_level; game->min_level = min_level;
game->max_level = 0xFFFFFFFF; game->max_level = 0xFFFFFFFF;
+52 -1
View File
@@ -273,12 +273,14 @@ static void process_subcommand_player_drop_item(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
l->add_item(c->game_data.player()->remove_item(cmd->item_id, 0), l->add_item(c->game_data.player()->remove_item(cmd->item_id, 0),
cmd->area, cmd->x, cmd->z); cmd->area, cmd->x, cmd->z);
log(INFO, "[Items/%08" PRIX32 "] Player %hhu dropped item %08" PRIX32 " at %hu:(%g, %g)", log(INFO, "[Items/%08" PRIX32 "] Player %hhu dropped item %08" PRIX32 " at %hu:(%g, %g)",
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load()); l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -297,6 +299,7 @@ static void process_subcommand_create_inventory_item(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
PlayerInventoryItem item; PlayerInventoryItem item;
item.equip_flags = 0; // TODO: Use the right default flags here item.equip_flags = 0; // TODO: Use the right default flags here
item.tech_flag = 0; item.tech_flag = 0;
@@ -307,6 +310,7 @@ static void process_subcommand_create_inventory_item(shared_ptr<ServerState>,
log(INFO, "[Items/%08" PRIX32 "] Player %hhu created inventory item %08" PRIX32, log(INFO, "[Items/%08" PRIX32 "] Player %hhu created inventory item %08" PRIX32,
l->lobby_id, cmd->client_id, cmd->item.id.load()); l->lobby_id, cmd->client_id, cmd->item.id.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -324,6 +328,7 @@ static void process_subcommand_drop_partial_stack(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
// TODO: Should we delete anything from the inventory here? Does the client // TODO: Should we delete anything from the inventory here? Does the client
// send an appropriate 6x29 alongside this? // send an appropriate 6x29 alongside this?
PlayerInventoryItem item; PlayerInventoryItem item;
@@ -336,6 +341,7 @@ static void process_subcommand_drop_partial_stack(shared_ptr<ServerState>,
log(INFO, "[Items/%08" PRIX32 "] Player %hhu split stack to create ground item %08" PRIX32 " at %hu:(%g, %g)", log(INFO, "[Items/%08" PRIX32 "] Player %hhu split stack to create ground item %08" PRIX32 " at %hu:(%g, %g)",
l->lobby_id, cmd->client_id, item.data.id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load()); l->lobby_id, cmd->client_id, item.data.id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -350,6 +356,10 @@ static void process_subcommand_drop_partial_stack_bb(shared_ptr<ServerState>,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
auto item = c->game_data.player()->remove_item(cmd->item_id, cmd->amount); auto item = c->game_data.player()->remove_item(cmd->item_id, cmd->amount);
// if a stack was split, the original item still exists, so the dropped item // if a stack was split, the original item still exists, so the dropped item
@@ -389,6 +399,7 @@ static void process_subcommand_buy_shop_item(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
PlayerInventoryItem item; PlayerInventoryItem item;
item.equip_flags = 0; // TODO: Use the right default flags here item.equip_flags = 0; // TODO: Use the right default flags here
item.tech_flag = 0; item.tech_flag = 0;
@@ -399,6 +410,7 @@ static void process_subcommand_buy_shop_item(shared_ptr<ServerState>,
log(INFO, "[Items/%08" PRIX32 "] Player %hhu bought item %08" PRIX32 " from shop", log(INFO, "[Items/%08" PRIX32 "] Player %hhu bought item %08" PRIX32 " from shop",
l->lobby_id, cmd->client_id, item.data.id.load()); l->lobby_id, cmd->client_id, item.data.id.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -447,10 +459,12 @@ static void process_subcommand_pick_up_item(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
effective_c->game_data.player()->add_item(l->remove_item(cmd->item_id)); effective_c->game_data.player()->add_item(l->remove_item(cmd->item_id));
log(INFO, "[Items/%08" PRIX32 "] Player %hu picked up %08" PRIX32, log(INFO, "[Items/%08" PRIX32 "] Player %hu picked up %08" PRIX32,
l->lobby_id, cmd->client_id.load(), cmd->item_id.load()); l->lobby_id, cmd->client_id.load(), cmd->item_id.load());
effective_c->game_data.player()->print_inventory(stderr); effective_c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -466,6 +480,10 @@ static void process_subcommand_pick_up_item_request(shared_ptr<ServerState>,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
c->game_data.player()->add_item(l->remove_item(cmd->item_id)); c->game_data.player()->add_item(l->remove_item(cmd->item_id));
log(INFO, "[Items/%08" PRIX32 "/BB] Player %hhu picked up %08" PRIX32, log(INFO, "[Items/%08" PRIX32 "/BB] Player %hhu picked up %08" PRIX32,
@@ -482,7 +500,7 @@ static void process_subcommand_pick_up_item_request(shared_ptr<ServerState>,
static void process_subcommand_equip_unequip_item(shared_ptr<ServerState>, static void process_subcommand_equip_unequip_item(shared_ptr<ServerState>,
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag, shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
const string& data) { const string& data) {
// We don't track equip state on non-BB versions // TODO: We should track equip state on non-BB versions
if (l->version == GameVersion::BB) { if (l->version == GameVersion::BB) {
const auto* cmd = check_size_sc<G_ItemSubcommand>(data); const auto* cmd = check_size_sc<G_ItemSubcommand>(data);
@@ -490,6 +508,10 @@ static void process_subcommand_equip_unequip_item(shared_ptr<ServerState>,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
size_t index = c->game_data.player()->inventory.find_item(cmd->item_id); size_t index = c->game_data.player()->inventory.find_item(cmd->item_id);
if (cmd->command == 0x25) { if (cmd->command == 0x25) {
c->game_data.player()->inventory.items[index].game_flags |= 0x00000008; // equip c->game_data.player()->inventory.items[index].game_flags |= 0x00000008; // equip
@@ -511,12 +533,14 @@ static void process_subcommand_use_item(shared_ptr<ServerState>,
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
size_t index = c->game_data.player()->inventory.find_item(cmd->item_id); size_t index = c->game_data.player()->inventory.find_item(cmd->item_id);
player_use_item(c, index); player_use_item(c, index);
log(INFO, "[Items/%08" PRIX32 "] Player used item %hhu:%08" PRIX32, log(INFO, "[Items/%08" PRIX32 "] Player used item %hhu:%08" PRIX32,
l->lobby_id, cmd->client_id, cmd->item_id.load()); l->lobby_id, cmd->client_id, cmd->item_id.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
}
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
@@ -572,6 +596,10 @@ static void process_subcommand_bank_action_bb(shared_ptr<ServerState>,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
if (cmd->action == 0) { // deposit if (cmd->action == 0) { // deposit
if (cmd->item_id == 0xFFFFFFFF) { // meseta if (cmd->item_id == 0xFFFFFFFF) { // meseta
if (cmd->meseta_amount > c->game_data.player()->disp.meseta) { if (cmd->meseta_amount > c->game_data.player()->disp.meseta) {
@@ -615,6 +643,10 @@ static void process_subcommand_sort_inventory_bb(shared_ptr<ServerState>,
if (l->version == GameVersion::BB) { if (l->version == GameVersion::BB) {
const auto* cmd = check_size_sc<G_SortInventory_6xC4>(data); const auto* cmd = check_size_sc<G_SortInventory_6xC4>(data);
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
PlayerInventory sorted; PlayerInventory sorted;
for (size_t x = 0; x < 30; x++) { for (size_t x = 0; x < 30; x++) {
@@ -647,6 +679,10 @@ static void process_subcommand_enemy_drop_item_request(shared_ptr<ServerState> s
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
PlayerInventoryItem item; PlayerInventoryItem item;
// TODO: Deduplicate this code with the box drop item request handler // TODO: Deduplicate this code with the box drop item request handler
@@ -701,6 +737,10 @@ static void process_subcommand_box_drop_item_request(shared_ptr<ServerState> s,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
PlayerInventoryItem item; PlayerInventoryItem item;
bool is_rare = false; bool is_rare = false;
@@ -891,12 +931,14 @@ static void process_subcommand_destroy_inventory_item(shared_ptr<ServerState>,
if (cmd->client_id != c->lobby_client_id) { if (cmd->client_id != c->lobby_client_id) {
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
c->game_data.player()->remove_item(cmd->item_id, cmd->amount); c->game_data.player()->remove_item(cmd->item_id, cmd->amount);
log(INFO, "[Items/%08" PRIX32 "] Inventory item %hhu:%08" PRIX32 " destroyed (%" PRIX32 " of them)", log(INFO, "[Items/%08" PRIX32 "] Inventory item %hhu:%08" PRIX32 " destroyed (%" PRIX32 " of them)",
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->amount.load()); l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->amount.load());
c->game_data.player()->print_inventory(stderr); c->game_data.player()->print_inventory(stderr);
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
}
static void process_subcommand_destroy_ground_item(shared_ptr<ServerState>, static void process_subcommand_destroy_ground_item(shared_ptr<ServerState>,
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag, shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
@@ -905,11 +947,13 @@ static void process_subcommand_destroy_ground_item(shared_ptr<ServerState>,
if (!l->is_game()) { if (!l->is_game()) {
return; return;
} }
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
l->remove_item(cmd->item_id); l->remove_item(cmd->item_id);
log(INFO, "[Items/%08" PRIX32 "] Ground item %08" PRIX32 " destroyed (%" PRIX32 " of them)", log(INFO, "[Items/%08" PRIX32 "] Ground item %08" PRIX32 " destroyed (%" PRIX32 " of them)",
l->lobby_id, cmd->item_id.load(), cmd->amount.load()); l->lobby_id, cmd->item_id.load(), cmd->amount.load());
forward_subcommand(l, c, command, flag, data); forward_subcommand(l, c, command, flag, data);
} }
}
static void process_subcommand_identify_item_bb(shared_ptr<ServerState>, static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag, shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
@@ -920,6 +964,10 @@ static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
return; return;
} }
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
throw logic_error("item tracking not enabled in BB game");
}
size_t x = c->game_data.player()->inventory.find_item(cmd->item_id); size_t x = c->game_data.player()->inventory.find_item(cmd->item_id);
if (c->game_data.player()->inventory.items[x].data.data1[0] != 0) { if (c->game_data.player()->inventory.items[x].data.data1[0] != 0) {
return; // only weapons can be identified return; // only weapons can be identified
@@ -956,6 +1004,9 @@ static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
// if (cmd->client_id != c->lobby_client_id) { // if (cmd->client_id != c->lobby_client_id) {
// return; // return;
// } // }
// if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
// throw logic_error("item tracking not enabled in BB game");
// }
// //
// size_t x = c->game_data.player()->inventory.find_item(cmd->item_id); // size_t x = c->game_data.player()->inventory.find_item(cmd->item_id);
// c->game_data.player()->inventory.items[x] = c->game_data.player()->identify_result; // c->game_data.player()->inventory.items[x] = c->game_data.player()->identify_result;
+1
View File
@@ -18,6 +18,7 @@ ServerState::ServerState()
: dns_server_port(0), : dns_server_port(0),
ip_stack_debug(false), ip_stack_debug(false),
allow_unregistered_users(false), allow_unregistered_users(false),
item_tracking_enabled(true),
run_shell_behavior(RunShellBehavior::DEFAULT), next_lobby_id(1), run_shell_behavior(RunShellBehavior::DEFAULT), next_lobby_id(1),
pre_lobby_event(0), pre_lobby_event(0),
ep3_menu_song(-1) { ep3_menu_song(-1) {
+1
View File
@@ -46,6 +46,7 @@ struct ServerState {
std::vector<std::string> ip_stack_addresses; std::vector<std::string> ip_stack_addresses;
bool ip_stack_debug; bool ip_stack_debug;
bool allow_unregistered_users; bool allow_unregistered_users;
bool item_tracking_enabled;
RunShellBehavior run_shell_behavior; RunShellBehavior run_shell_behavior;
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys; std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys;
std::shared_ptr<const FunctionCodeIndex> function_code_index; std::shared_ptr<const FunctionCodeIndex> function_code_index;
+2
View File
@@ -1468,6 +1468,8 @@ string name_for_item(const ItemData& item, bool include_color_codes) {
// For weapons, specials appear before the weapon name // For weapons, specials appear before the weapon name
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00)) { if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00)) {
// 0x80 is the unidentified flag, but we always return the identified name
// of the item here, so we ignore it
bool is_present = item.data1[4] & 0x40; bool is_present = item.data1[4] & 0x40;
uint8_t special_id = item.data1[4] & 0x3F; uint8_t special_id = item.data1[4] & 0x3F;
if (is_present) { if (is_present) {
+8
View File
@@ -128,6 +128,14 @@
// BB users. // BB users.
"WelcomeMessage": "", "WelcomeMessage": "",
// By default, the server keeps track of items in all games, even for versions
// other than Blue Burst. This enables use of the $what command, as well as
// protection against item duplication cheats (the cheater is disconnected
// instead of the other players). If item tracking causes any issues, it can
// be turned off here. This option has no effect on Blue Burst games - item
// tracking is always enabled for them.
"EnableItemTracking": true,
// Item drop rates for non-rare items in BB games. For each type (boxes or // Item drop rates for non-rare items in BB games. For each type (boxes or
// enemies), all the categories must add up to a number less than 0x100000000. // enemies), all the categories must add up to a number less than 0x100000000.
// Each number is a probability (out of 0x100000000) that the given item type // Each number is a probability (out of 0x100000000) that the given item type