add cross-play options
This commit is contained in:
+5
-7
@@ -359,11 +359,9 @@ static void server_command_exit(shared_ptr<Client> c, const std::u16string&) {
|
||||
send_message_box(c, u"");
|
||||
}
|
||||
|
||||
const auto& port_name = version_to_login_port_name.at(
|
||||
static_cast<size_t>(c->version()));
|
||||
const auto& port_name = version_to_login_port_name.at(static_cast<size_t>(c->version()));
|
||||
auto s = c->require_server_state();
|
||||
send_reconnect(c, s->connect_address_for_client(c),
|
||||
s->name_to_port_config.at(port_name)->port);
|
||||
send_reconnect(c, s->connect_address_for_client(c), s->name_to_port_config.at(port_name)->port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +595,7 @@ static void server_command_playrec(shared_ptr<Client> c, const std::u16string& a
|
||||
string file_path = file_path_for_recording(args, c->license->serial_number);
|
||||
|
||||
auto s = c->require_server_state();
|
||||
uint32_t flags = Lobby::Flag::NON_V1_ONLY | Lobby::Flag::IS_SPECTATOR_TEAM;
|
||||
uint32_t flags = Lobby::Flag::IS_SPECTATOR_TEAM;
|
||||
string filename = encode_sjis(args);
|
||||
if (filename[0] == '!') {
|
||||
flags |= Lobby::Flag::START_BATTLE_PLAYER_IMMEDIATELY;
|
||||
@@ -614,8 +612,8 @@ static void server_command_playrec(shared_ptr<Client> c, const std::u16string& a
|
||||
shared_ptr<Episode3::BattleRecord> record(new Episode3::BattleRecord(data));
|
||||
shared_ptr<Episode3::BattleRecordPlayer> battle_player(
|
||||
new Episode3::BattleRecordPlayer(record, s->game_server->get_base()));
|
||||
auto game = create_game_generic(s, c, args.c_str(), u"", Episode::EP3, GameMode::NORMAL,
|
||||
0, flags, nullptr, battle_player);
|
||||
auto game = create_game_generic(
|
||||
s, c, args, u"", Episode::EP3, GameMode::NORMAL, 0, flags, false, nullptr, battle_player);
|
||||
if (game) {
|
||||
s->change_client_lobby(c, game);
|
||||
c->flags |= Client::Flag::LOADING;
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@ Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id)
|
||||
min_level(0),
|
||||
max_level(0xFFFFFFFF),
|
||||
next_game_item_id(0x00810000),
|
||||
version(GameVersion::GC),
|
||||
base_version(GameVersion::GC),
|
||||
allowed_versions(0xFFFF),
|
||||
section_id(0),
|
||||
episode(Episode::NONE),
|
||||
mode(GameMode::NORMAL),
|
||||
|
||||
+14
-3
@@ -27,8 +27,7 @@ struct ServerState;
|
||||
struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
enum Flag {
|
||||
GAME = 0x00000001,
|
||||
NON_V1_ONLY = 0x00000002, // DC NTE and DCv1 not allowed
|
||||
PERSISTENT = 0x00000004,
|
||||
PERSISTENT = 0x00000002,
|
||||
|
||||
// Flags used only for games
|
||||
CHEATS_ENABLED = 0x00000100,
|
||||
@@ -45,6 +44,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
// Flags used only for lobbies
|
||||
PUBLIC = 0x01000000,
|
||||
DEFAULT = 0x02000000,
|
||||
V2_AND_LATER = 0x04000000, // Lobby does not appear on v1
|
||||
};
|
||||
|
||||
std::weak_ptr<ServerState> server_state;
|
||||
@@ -69,7 +69,11 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
parray<le_uint32_t, 0x20> variations;
|
||||
|
||||
// Game config
|
||||
GameVersion version;
|
||||
GameVersion base_version;
|
||||
// Bits in allowed_versions specify who is allowed to join this game. The
|
||||
// bits are indexed as (1 << version), where version is a value from the
|
||||
// QuestScriptVersion enum.
|
||||
uint16_t allowed_versions;
|
||||
uint8_t section_id;
|
||||
Episode episode;
|
||||
GameMode mode;
|
||||
@@ -127,6 +131,13 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
return this->episode == Episode::EP3;
|
||||
}
|
||||
|
||||
inline bool version_is_allowed(QuestScriptVersion v) const {
|
||||
return this->allowed_versions & (1 << static_cast<size_t>(v));
|
||||
}
|
||||
inline void allow_version(QuestScriptVersion v) {
|
||||
this->allowed_versions |= (1 << static_cast<size_t>(v));
|
||||
}
|
||||
|
||||
void reassign_leader_on_client_departure(size_t leaving_client_id);
|
||||
size_t count_clients() const;
|
||||
bool any_client_loading() const;
|
||||
|
||||
+1
-1
@@ -1895,7 +1895,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
shared_ptr<DNSServer> dns_server;
|
||||
if (state->dns_server_port && (behavior != Behavior::REPLAY_LOG)) {
|
||||
config_log.info("Starting DNS server");
|
||||
config_log.info("Starting DNS server on port %hu", state->dns_server_port);
|
||||
dns_server.reset(new DNSServer(base, state->local_address,
|
||||
state->external_address));
|
||||
dns_server->listen("", state->dns_server_port);
|
||||
|
||||
@@ -27,6 +27,9 @@ void PlayerDispDataDCPCV3::enforce_v2_limits() {
|
||||
this->visual.char_class = 5; // HUcaseal -> RAcaseal
|
||||
}
|
||||
|
||||
// V1/V2 has fewer costumes, so substitute them here too
|
||||
this->visual.costume %= 9;
|
||||
|
||||
// If the player is somehow still not a valid class, make them appear as the
|
||||
// "ninja" NPC
|
||||
if (this->visual.char_class > 8) {
|
||||
|
||||
+64
-29
@@ -185,7 +185,7 @@ static void send_main_menu(shared_ptr<Client> c) {
|
||||
const auto& l = it.second;
|
||||
if (l->is_game()) {
|
||||
num_games++;
|
||||
if (l->version == c->version() &&
|
||||
if (l->version_is_allowed(c->quest_version()) &&
|
||||
(!l->is_ep3() == !(c->flags & Client::Flag::IS_EPISODE_3))) {
|
||||
num_compatible_games++;
|
||||
}
|
||||
@@ -1119,11 +1119,8 @@ static bool start_ep3_battle_table_game_if_ready(shared_ptr<Lobby> l, int16_t ta
|
||||
|
||||
auto c = game_clients.begin()->second;
|
||||
auto s = c->require_server_state();
|
||||
uint32_t flags = Lobby::Flag::NON_V1_ONLY;
|
||||
u16string name = tourn ? decode_sjis(tourn->get_name()) : u"<BattleTable>";
|
||||
auto game = create_game_generic(
|
||||
s, c, name, u"", Episode::EP3,
|
||||
GameMode::NORMAL, 0, flags);
|
||||
auto game = create_game_generic(s, c, name, u"", Episode::EP3);
|
||||
if (!game) {
|
||||
return false;
|
||||
}
|
||||
@@ -1914,10 +1911,9 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, const string& data)
|
||||
send_lobby_message_box(c, u"$C6You cannot join this\ngame because it is\nfull.");
|
||||
break;
|
||||
}
|
||||
if ((game->version != c->version()) ||
|
||||
if (!game->version_is_allowed(c->quest_version()) ||
|
||||
(!game->is_ep3() != !(c->flags & Client::Flag::IS_EPISODE_3)) ||
|
||||
(!(game->flags & Lobby::Flag::IS_EP3_TRIAL) != !(c->flags & Client::Flag::IS_EP3_TRIAL_EDITION)) ||
|
||||
((game->flags & Lobby::Flag::NON_V1_ONLY) && (c->flags & Client::Flag::IS_DC_V1))) {
|
||||
(!(game->flags & Lobby::Flag::IS_EP3_TRIAL) != !(c->flags & Client::Flag::IS_EP3_TRIAL_EDITION))) {
|
||||
send_lobby_message_box(c, u"$C6You cannot join this\ngame because it is\nfor a different\nversion of PSO.");
|
||||
break;
|
||||
}
|
||||
@@ -2375,7 +2371,7 @@ static void on_AC_V3_BB(shared_ptr<Client> c, uint16_t, uint32_t, const string&
|
||||
|
||||
if (c->flags & Client::Flag::LOADING_RUNNING_QUEST) {
|
||||
c->flags &= ~Client::Flag::LOADING_RUNNING_QUEST;
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
throw logic_error("joinable quest started on non-BB version");
|
||||
}
|
||||
|
||||
@@ -2395,7 +2391,7 @@ static void on_AC_V3_BB(shared_ptr<Client> c, uint16_t, uint32_t, const string&
|
||||
}
|
||||
|
||||
if (send_quest_barrier_if_all_clients_ready(l) &&
|
||||
(l->version == GameVersion::BB) &&
|
||||
(l->base_version == GameVersion::BB) &&
|
||||
l->map &&
|
||||
l->quest) {
|
||||
auto dat_contents = prs_decompress(*l->quest->dat_contents());
|
||||
@@ -3203,6 +3199,7 @@ shared_ptr<Lobby> create_game_generic(
|
||||
GameMode mode,
|
||||
uint8_t difficulty,
|
||||
uint32_t flags,
|
||||
bool allow_v1,
|
||||
shared_ptr<Lobby> watched_lobby,
|
||||
shared_ptr<Episode3::BattleRecordPlayer> battle_player) {
|
||||
|
||||
@@ -3276,7 +3273,54 @@ shared_ptr<Lobby> create_game_generic(
|
||||
(is_ep3_trial ? Lobby::Flag::IS_EP3_TRIAL : 0) |
|
||||
((s->cheat_mode_behavior == ServerState::CheatModeBehavior::ON_BY_DEFAULT) ? Lobby::Flag::CHEATS_ENABLED : 0);
|
||||
game->password = password;
|
||||
game->version = c->version();
|
||||
|
||||
game->allowed_versions = 0;
|
||||
switch (c->quest_version()) {
|
||||
case QuestScriptVersion::DC_NTE:
|
||||
game->allow_version(QuestScriptVersion::DC_NTE);
|
||||
break;
|
||||
case QuestScriptVersion::DC_V1:
|
||||
game->allow_version(QuestScriptVersion::DC_V1);
|
||||
game->allow_version(QuestScriptVersion::DC_V2);
|
||||
if (s->allow_dc_pc_games) {
|
||||
game->allow_version(QuestScriptVersion::PC_V2);
|
||||
}
|
||||
break;
|
||||
case QuestScriptVersion::DC_V2:
|
||||
case QuestScriptVersion::PC_V2:
|
||||
if (allow_v1 && (difficulty <= 2)) {
|
||||
game->allow_version(QuestScriptVersion::DC_V1);
|
||||
}
|
||||
game->allow_version(QuestScriptVersion::DC_V2);
|
||||
if (s->allow_dc_pc_games) {
|
||||
game->allow_version(QuestScriptVersion::PC_V2);
|
||||
}
|
||||
break;
|
||||
case QuestScriptVersion::GC_NTE:
|
||||
game->allow_version(QuestScriptVersion::GC_NTE);
|
||||
break;
|
||||
case QuestScriptVersion::GC_V3:
|
||||
game->allow_version(QuestScriptVersion::GC_V3);
|
||||
if (s->allow_gc_xb_games) {
|
||||
game->allow_version(QuestScriptVersion::XB_V3);
|
||||
}
|
||||
break;
|
||||
case QuestScriptVersion::XB_V3:
|
||||
game->allow_version(QuestScriptVersion::XB_V3);
|
||||
if (s->allow_gc_xb_games) {
|
||||
game->allow_version(QuestScriptVersion::GC_V3);
|
||||
}
|
||||
break;
|
||||
case QuestScriptVersion::GC_EP3:
|
||||
game->allow_version(QuestScriptVersion::GC_EP3);
|
||||
break;
|
||||
case QuestScriptVersion::BB_V4:
|
||||
game->allow_version(QuestScriptVersion::BB_V4);
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid quest script version");
|
||||
}
|
||||
|
||||
game->section_id = c->options.override_section_id >= 0
|
||||
? c->options.override_section_id
|
||||
: c->game_data.player()->disp.visual.section_id;
|
||||
@@ -3291,7 +3335,7 @@ shared_ptr<Lobby> create_game_generic(
|
||||
game->battle_player = battle_player;
|
||||
battle_player->set_lobby(game);
|
||||
}
|
||||
if (game->version == GameVersion::BB) {
|
||||
if (game->base_version == GameVersion::BB) {
|
||||
// TODO: Use appropriate restrictions here if in battle mode
|
||||
game->item_creator.reset(new ItemCreator(
|
||||
s->common_item_set,
|
||||
@@ -3326,7 +3370,7 @@ shared_ptr<Lobby> create_game_generic(
|
||||
generate_variations(game->variations, game->random_crypt, game->episode, is_solo);
|
||||
}
|
||||
|
||||
if (game->version == GameVersion::BB) {
|
||||
if (game->base_version == GameVersion::BB) {
|
||||
for (size_t x = 0; x < 4; x++) {
|
||||
game->next_item_id[x] = (0x00200000 * x) + 0x00010000;
|
||||
}
|
||||
@@ -3382,15 +3426,13 @@ static void on_C1_PC(shared_ptr<Client> c, uint16_t, uint32_t, const string& dat
|
||||
const auto& cmd = check_size_t<C_CreateGame_PC_C1>(data);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
uint32_t flags = Lobby::Flag::NON_V1_ONLY;
|
||||
GameMode mode = GameMode::NORMAL;
|
||||
if (cmd.battle_mode) {
|
||||
mode = GameMode::BATTLE;
|
||||
} else if (cmd.challenge_mode) {
|
||||
mode = GameMode::CHALLENGE;
|
||||
}
|
||||
auto game = create_game_generic(
|
||||
s, c, cmd.name, cmd.password, Episode::EP1, mode, cmd.difficulty, flags);
|
||||
auto game = create_game_generic(s, c, cmd.name, cmd.password, Episode::EP1, mode, cmd.difficulty);
|
||||
if (game) {
|
||||
s->change_client_lobby(c, game);
|
||||
c->flags |= Client::Flag::LOADING;
|
||||
@@ -3405,8 +3447,7 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, con
|
||||
const auto& cmd = check_size_t<C_CreateGame_DCNTE<char>>(data);
|
||||
u16string name = decode_sjis(cmd.name);
|
||||
u16string password = decode_sjis(cmd.password);
|
||||
game = create_game_generic(
|
||||
s, c, name.c_str(), password.c_str(), Episode::EP1, GameMode::NORMAL, 0, 0);
|
||||
game = create_game_generic(s, c, name, password);
|
||||
|
||||
} else {
|
||||
const auto& cmd = check_size_t<C_CreateGame_DC_V3_0C_C1_Ep3_EC>(data);
|
||||
@@ -3419,16 +3460,13 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, con
|
||||
|
||||
Episode episode = Episode::NONE;
|
||||
uint32_t flags = 0;
|
||||
bool allow_v1 = false;
|
||||
if (c->version() == GameVersion::DC) {
|
||||
if (cmd.episode) {
|
||||
flags |= Lobby::Flag::NON_V1_ONLY;
|
||||
}
|
||||
allow_v1 = (cmd.episode == 0);
|
||||
episode = Episode::EP1;
|
||||
} else if (client_is_ep3) {
|
||||
flags |= Lobby::Flag::NON_V1_ONLY;
|
||||
episode = Episode::EP3;
|
||||
} else { // XB/GC non-Ep3
|
||||
flags |= Lobby::Flag::NON_V1_ONLY;
|
||||
episode = cmd.episode == 2 ? Episode::EP2 : Episode::EP1;
|
||||
}
|
||||
|
||||
@@ -3464,8 +3502,7 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, con
|
||||
flags |= Lobby::Flag::IS_SPECTATOR_TEAM;
|
||||
}
|
||||
|
||||
game = create_game_generic(
|
||||
s, c, name.c_str(), password.c_str(), episode, mode, cmd.difficulty, flags, watched_lobby);
|
||||
game = create_game_generic(s, c, name, password, episode, mode, cmd.difficulty, flags, allow_v1, watched_lobby);
|
||||
if (game && (game->episode == Episode::EP3)) {
|
||||
game->ep3_ex_result_values = s->ep3_default_ex_values;
|
||||
}
|
||||
@@ -3481,7 +3518,6 @@ static void on_C1_BB(shared_ptr<Client> c, uint16_t, uint32_t, const string& dat
|
||||
const auto& cmd = check_size_t<C_CreateGame_BB_C1>(data);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
uint32_t flags = Lobby::Flag::NON_V1_ONLY;
|
||||
GameMode mode = GameMode::NORMAL;
|
||||
if (cmd.battle_mode) {
|
||||
mode = GameMode::BATTLE;
|
||||
@@ -3508,8 +3544,7 @@ static void on_C1_BB(shared_ptr<Client> c, uint16_t, uint32_t, const string& dat
|
||||
throw runtime_error("invalid episode number");
|
||||
}
|
||||
|
||||
auto game = create_game_generic(
|
||||
s, c, cmd.name, cmd.password, episode, mode, cmd.difficulty, flags);
|
||||
auto game = create_game_generic(s, c, cmd.name, cmd.password, episode, mode, cmd.difficulty);
|
||||
if (game) {
|
||||
s->change_client_lobby(c, game);
|
||||
c->flags |= Client::Flag::LOADING;
|
||||
@@ -3539,7 +3574,7 @@ static void on_6F(shared_ptr<Client> c, uint16_t, uint32_t, const string& data)
|
||||
c->flags &= (~Client::Flag::LOADING);
|
||||
|
||||
send_resume_game(l, c);
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
send_set_exp_multiplier(l);
|
||||
}
|
||||
send_server_time(c);
|
||||
|
||||
@@ -8,11 +8,12 @@ std::shared_ptr<Lobby> create_game_generic(
|
||||
std::shared_ptr<ServerState> s,
|
||||
std::shared_ptr<Client> c,
|
||||
const std::u16string& name,
|
||||
const std::u16string& password,
|
||||
Episode episode,
|
||||
GameMode mode,
|
||||
uint8_t difficulty,
|
||||
uint32_t flags,
|
||||
const std::u16string& password = u"",
|
||||
Episode episode = Episode::EP1,
|
||||
GameMode mode = GameMode::NORMAL,
|
||||
uint8_t difficulty = 0,
|
||||
uint32_t flags = 0,
|
||||
bool allow_v1 = false,
|
||||
std::shared_ptr<Lobby> watched_lobby = nullptr,
|
||||
std::shared_ptr<Episode3::BattleRecordPlayer> battle_player = nullptr);
|
||||
|
||||
|
||||
+23
-23
@@ -697,7 +697,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, uint8_t command, uint8
|
||||
if (!l->is_game()) {
|
||||
return;
|
||||
}
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ static void on_drop_partial_stack(shared_ptr<Client> c, uint8_t command, uint8_t
|
||||
|
||||
static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_SplitStackedItem_BB_6xC3>(data, size);
|
||||
|
||||
if (!l->is_game() || (cmd.header.client_id != c->lobby_client_id)) {
|
||||
@@ -791,7 +791,7 @@ static void on_buy_shop_item(shared_ptr<Client> c, uint8_t command, uint8_t flag
|
||||
if (!l->is_game() || (cmd.header.client_id != c->lobby_client_id)) {
|
||||
return;
|
||||
}
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -828,7 +828,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, uint8_t command, u
|
||||
if (!l->is_game() || (c->lobby_client_id != l->leader_id)) {
|
||||
return;
|
||||
}
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ static void on_pick_up_item(shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
if (!l->is_game()) {
|
||||
return;
|
||||
}
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
// BB clients should never send this; only the server should send this
|
||||
return;
|
||||
}
|
||||
@@ -900,7 +900,7 @@ static void on_pick_up_item(shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
static void on_pick_up_item_request(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
// This is handled by the server on BB, and by the leader on other versions
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
auto& cmd = check_size_t<G_PickUpItemRequest_6x5A>(data, size);
|
||||
|
||||
if (!l->is_game() || (cmd.header.client_id != c->lobby_client_id)) {
|
||||
@@ -946,7 +946,7 @@ static void on_equip_unequip_item(shared_ptr<Client> c, uint8_t command, uint8_t
|
||||
} else { // Unequip
|
||||
c->game_data.player()->inventory.items[index].flags &= 0xFFFFFFF7;
|
||||
}
|
||||
} else if (l->version == GameVersion::BB) {
|
||||
} else if (l->base_version == GameVersion::BB) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
@@ -1021,7 +1021,7 @@ static void on_feed_mag(
|
||||
// a 6x29 immediately after to destroy the fed item. So on BB, we should
|
||||
// remove the fed item here, but on other versions, we allow the following
|
||||
// 6x29 command to do that.
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
c->game_data.player()->remove_item(cmd.fed_item_id, 1, false);
|
||||
}
|
||||
|
||||
@@ -1049,7 +1049,7 @@ static void on_open_shop_bb_or_ep3_battle_subs(shared_ptr<Client> c, uint8_t com
|
||||
|
||||
} else {
|
||||
const auto& cmd = check_size_t<G_ShopContentsRequest_BB_6xB5>(data, size);
|
||||
if ((l->version == GameVersion::BB) && l->is_game()) {
|
||||
if ((l->base_version == GameVersion::BB) && l->is_game()) {
|
||||
if (!l->item_creator) {
|
||||
throw logic_error("item creator missing from BB game");
|
||||
}
|
||||
@@ -1081,16 +1081,16 @@ static void on_open_shop_bb_or_ep3_battle_subs(shared_ptr<Client> c, uint8_t com
|
||||
|
||||
static void on_open_bank_bb_or_card_trade_counter_ep3(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if ((l->version == GameVersion::BB) && l->is_game()) {
|
||||
if ((l->base_version == GameVersion::BB) && l->is_game()) {
|
||||
send_bank(c);
|
||||
} else if ((l->version == GameVersion::GC) && l->is_ep3()) {
|
||||
} else if ((l->base_version == GameVersion::GC) && l->is_ep3()) {
|
||||
forward_subcommand(c, command, flag, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_BankAction_BB_6xBD>(data, size);
|
||||
|
||||
if (!l->is_game()) {
|
||||
@@ -1141,7 +1141,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
|
||||
|
||||
static void on_sort_inventory_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_SortInventory_BB_6xC4>(data, size);
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
@@ -1178,7 +1178,7 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
|
||||
// If the game is not BB, forward the request to the leader (if drops are
|
||||
// enabled, or just ignore it) instead of generating the item drop command
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
if (l->flags & Lobby::Flag::DROPS_ENABLED) {
|
||||
forward_subcommand(c, command, flag, data, size);
|
||||
}
|
||||
@@ -1304,7 +1304,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
|
||||
|
||||
static void on_enemy_hit(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_EnemyHitByPlayer_6x0A>(data, size);
|
||||
|
||||
if (!l->is_game()) {
|
||||
@@ -1333,7 +1333,7 @@ static void on_enemy_hit(shared_ptr<Client> c, uint8_t command, uint8_t flag, co
|
||||
|
||||
static void on_charge_attack_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
throw runtime_error("BB-only command sent in non-BB game");
|
||||
}
|
||||
|
||||
@@ -1375,7 +1375,7 @@ static void on_steal_exp_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
throw runtime_error("BB-only command sent in non-BB game");
|
||||
}
|
||||
if (!l->map) {
|
||||
@@ -1413,7 +1413,7 @@ static void on_enemy_killed_bb(shared_ptr<Client> c, uint8_t command, uint8_t fl
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
throw runtime_error("BB-only command sent in non-BB game");
|
||||
}
|
||||
|
||||
@@ -1574,7 +1574,7 @@ static void on_destroy_ground_item(shared_ptr<Client> c, uint8_t command, uint8_
|
||||
|
||||
static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_IdentifyItemRequest_6xB8>(data, size);
|
||||
if (!l->is_game()) {
|
||||
return;
|
||||
@@ -1605,7 +1605,7 @@ static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t f
|
||||
|
||||
static void on_accept_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_AcceptItemIdentification_BB_6xBA>(data, size);
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
@@ -1630,7 +1630,7 @@ static void on_accept_identify_item_bb(shared_ptr<Client> c, uint8_t command, ui
|
||||
static void on_sell_item_at_shop_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_SellItemAtShop_BB_6xC0>(data, size);
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
@@ -1658,7 +1658,7 @@ static void on_sell_item_at_shop_bb(shared_ptr<Client> c, uint8_t command, uint8
|
||||
|
||||
static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void* data, size_t size) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->version == GameVersion::BB) {
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
const auto& cmd = check_size_t<G_BuyShopItem_BB_6xB7>(data, size);
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
@@ -1695,7 +1695,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const vo
|
||||
|
||||
static void on_medical_center_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*, size_t) {
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->version == GameVersion::BB)) {
|
||||
if (l->is_game() && (l->base_version == GameVersion::BB)) {
|
||||
c->game_data.player()->remove_meseta(10, false);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-13
@@ -1188,15 +1188,7 @@ void send_game_menu_t(
|
||||
if (!l->is_game()) {
|
||||
continue;
|
||||
}
|
||||
if (l->version != c->version()) {
|
||||
continue;
|
||||
}
|
||||
bool l_is_ep3 = l->is_ep3();
|
||||
bool c_is_ep3 = !!(c->flags & Client::Flag::IS_EPISODE_3);
|
||||
if (l_is_ep3 != c_is_ep3) {
|
||||
continue;
|
||||
}
|
||||
if ((c->flags & Client::Flag::IS_DC_V1) && (l->flags & Lobby::Flag::NON_V1_ONLY)) {
|
||||
if (!l->version_is_allowed(c->quest_version())) {
|
||||
continue;
|
||||
}
|
||||
bool l_is_spectator_team = !!(l->flags & Lobby::Flag::IS_SPECTATOR_TEAM);
|
||||
@@ -1228,10 +1220,10 @@ void send_game_menu_t(
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = MenuID::GAME;
|
||||
e.game_id = l->lobby_id;
|
||||
e.difficulty_tag = (l_is_ep3 ? 0x0A : (l->difficulty + 0x22));
|
||||
e.difficulty_tag = (l->is_ep3() ? 0x0A : (l->difficulty + 0x22));
|
||||
e.num_players = l->count_clients();
|
||||
if (c->version() == GameVersion::DC) {
|
||||
e.episode = (l->flags & Lobby::Flag::NON_V1_ONLY) ? 1 : 0;
|
||||
e.episode = l->version_is_allowed(QuestScriptVersion::DC_V1) ? 1 : 0;
|
||||
} else {
|
||||
e.episode = ((c->version() == GameVersion::BB) ? (l->max_clients << 4) : 0) | episode_num;
|
||||
}
|
||||
@@ -1367,7 +1359,7 @@ void send_lobby_list(shared_ptr<Client> c) {
|
||||
if (!(l->flags & Lobby::Flag::DEFAULT)) {
|
||||
continue;
|
||||
}
|
||||
if ((l->flags & Lobby::Flag::NON_V1_ONLY) && (c->flags & Client::Flag::IS_DC_V1)) {
|
||||
if ((l->flags & Lobby::Flag::V2_AND_LATER) && (c->flags & Client::Flag::IS_DC_V1)) {
|
||||
continue;
|
||||
}
|
||||
if (l->is_ep3() && !(c->flags & Client::Flag::IS_EPISODE_3)) {
|
||||
@@ -2182,7 +2174,7 @@ void send_give_experience(shared_ptr<Client> c, uint32_t amount) {
|
||||
}
|
||||
|
||||
void send_set_exp_multiplier(std::shared_ptr<Lobby> l) {
|
||||
if (l->version != GameVersion::BB) {
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
throw logic_error("6xDD can only be sent to BB clients");
|
||||
}
|
||||
if (!l->is_game()) {
|
||||
|
||||
+8
-3
@@ -24,6 +24,8 @@ ServerState::ServerState(const char* config_filename, bool is_replay)
|
||||
ip_stack_debug(false),
|
||||
allow_unregistered_users(false),
|
||||
allow_saving(true),
|
||||
allow_dc_pc_games(false),
|
||||
allow_gc_xb_games(true),
|
||||
item_tracking_enabled(true),
|
||||
drops_enabled(true),
|
||||
ep3_send_function_call_enabled(false),
|
||||
@@ -53,7 +55,7 @@ void ServerState::init() {
|
||||
|
||||
for (size_t x = 0; x < 20; x++) {
|
||||
auto lobby_name = decode_sjis(string_printf("LOBBY%zu", x + 1));
|
||||
bool is_non_v1_only = (x > 9);
|
||||
bool v2_and_later_only = (x > 9);
|
||||
bool is_ep3_only = (x > 14);
|
||||
|
||||
shared_ptr<Lobby> l = this->create_lobby();
|
||||
@@ -61,7 +63,7 @@ void ServerState::init() {
|
||||
Lobby::Flag::PUBLIC |
|
||||
Lobby::Flag::DEFAULT |
|
||||
Lobby::Flag::PERSISTENT |
|
||||
(is_non_v1_only ? Lobby::Flag::NON_V1_ONLY : 0);
|
||||
(v2_and_later_only ? Lobby::Flag::V2_AND_LATER : 0);
|
||||
l->block = x + 1;
|
||||
l->name = lobby_name;
|
||||
l->max_clients = 12;
|
||||
@@ -69,7 +71,7 @@ void ServerState::init() {
|
||||
l->episode = Episode::EP3;
|
||||
}
|
||||
|
||||
if (!is_non_v1_only) {
|
||||
if (!v2_and_later_only) {
|
||||
this->public_lobby_search_order_v1.emplace_back(l);
|
||||
}
|
||||
if (!is_ep3_only) {
|
||||
@@ -655,6 +657,9 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
this->allow_dc_pc_games = json.get_bool("AllowDCPCGames", this->allow_dc_pc_games);
|
||||
this->allow_gc_xb_games = json.get_bool("AllowGCXBGames", this->allow_gc_xb_games);
|
||||
|
||||
try {
|
||||
auto v = json.at("LobbyEvent");
|
||||
uint8_t event = v.is_int() ? v.as_int() : event_for_name(v.as_string());
|
||||
|
||||
@@ -57,6 +57,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
bool ip_stack_debug;
|
||||
bool allow_unregistered_users;
|
||||
bool allow_saving;
|
||||
bool allow_dc_pc_games;
|
||||
bool allow_gc_xb_games;
|
||||
bool item_tracking_enabled;
|
||||
bool drops_enabled;
|
||||
bool ep3_send_function_call_enabled;
|
||||
|
||||
@@ -503,6 +503,16 @@
|
||||
// enable Episode 3 USA patches by default; it only does if this option is on.
|
||||
// "EnableEpisode3SendFunctionCall": true,
|
||||
|
||||
// Whether to allow cross-play for various game versions. DCv1 and DCv2 are
|
||||
// always allowed to join each other's games (though DCv2 can deny permission
|
||||
// for DCv1 players to join when creating a game); if AllowDCPCGames is
|
||||
// enabled, then PC players are allowed in DC games and vice versa. Similarly,
|
||||
// if AllowGCXBGames is enabled, then GameCube and Xbox players are allowed to
|
||||
// join each other's games. Note that this behavior is experimental; you are
|
||||
// likely to encounter bugs in cross-play games, especially in the DC/PC case.
|
||||
"AllowDCPCGames": false,
|
||||
"AllowGCXBGames": true,
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user