add a bit more of dc nte
This commit is contained in:
@@ -47,7 +47,7 @@ Current known issues / missing features / things to do:
|
|||||||
newserv supports several versions of PSO. Specifically:
|
newserv supports several versions of PSO. Specifically:
|
||||||
| Version | Basic commands | Lobbies | Games | Proxy |
|
| Version | Basic commands | Lobbies | Games | Proxy |
|
||||||
|----------------------|----------------|---------------|---------------|---------------|
|
|----------------------|----------------|---------------|---------------|---------------|
|
||||||
| Dreamcast Trial | Not supported | Not supported | Not supported | Not supported |
|
| Dreamcast Trial | Partial (6) | Not supported | Not supported | Not supported |
|
||||||
| Dreamcast V1 | Supported (1) | Supported | Supported | Supported |
|
| Dreamcast V1 | Supported (1) | Supported | Supported | Supported |
|
||||||
| Dreamcast V2 | Supported (1) | Supported | Supported | Supported |
|
| Dreamcast V2 | Supported (1) | Supported | Supported | Supported |
|
||||||
| PC | Supported | Supported | Supported | Supported |
|
| PC | Supported | Supported | Supported | Supported |
|
||||||
@@ -65,6 +65,7 @@ newserv supports several versions of PSO. Specifically:
|
|||||||
3. *Episode 3 players can download quests, join lobbies, create and join games, and trade cards, but CARD battles are not implemented yet. Tournaments are also not supported.*
|
3. *Episode 3 players can download quests, join lobbies, create and join games, and trade cards, but CARD battles are not implemented yet. Tournaments are also not supported.*
|
||||||
4. *newserv's implementation of PSOX is based on disassembly of the client executable; it has never been tested with a real client and most likely doesn't work.*
|
4. *newserv's implementation of PSOX is based on disassembly of the client executable; it has never been tested with a real client and most likely doesn't work.*
|
||||||
5. *Some basic features are not implemented in Blue Burst games, so the games are not very playable. A lot of work has to be done to get BB games to a playable state.*
|
5. *Some basic features are not implemented in Blue Burst games, so the games are not very playable. A lot of work has to be done to get BB games to a playable state.*
|
||||||
|
6. *Support for PSO Dreamcast Trial Edition is very incomplete and probably never will be complete. This is really just exploring a curiosity that sheds some light on early network engineering done by Sega, not an actual attempt at supporting this version of the game.*
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -610,7 +610,7 @@ static void server_command_convert_char_to_bb(shared_ptr<ServerState> s,
|
|||||||
|
|
||||||
// Request the player data. The client will respond with a 61, and the handler
|
// Request the player data. The client will respond with a 61, and the handler
|
||||||
// for that command will execute the conversion
|
// for that command will execute the conversion
|
||||||
send_command(c, 0x95, 0x00);
|
send_get_player_info(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -1268,11 +1268,18 @@ struct C_Login_DCNTE_8B {
|
|||||||
ptext<char, 0x30> password;
|
ptext<char, 0x30> password;
|
||||||
ptext<char, 0x10> name;
|
ptext<char, 0x10> name;
|
||||||
parray<uint8_t, 2> unused;
|
parray<uint8_t, 2> unused;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct C_LoginExtended_DCNTE_8B : C_Login_DCNTE_8B {
|
||||||
SC_MeetUserExtension<char> extension;
|
SC_MeetUserExtension<char> extension;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 8C: Invalid command
|
// 8C: Invalid command
|
||||||
// 8D: Invalid command
|
|
||||||
|
// 8D (S->C): Request player data (DC NTE only)
|
||||||
|
// Behaves the same as 95 (S->C) on all other versions. DC NTE crashes if it
|
||||||
|
// receives 95, so this is used instead.
|
||||||
|
|
||||||
// 8E: Invalid command
|
// 8E: Invalid command
|
||||||
// 8F: Invalid command
|
// 8F: Invalid command
|
||||||
|
|
||||||
|
|||||||
+12
-8
@@ -68,19 +68,23 @@ namespace ProxyOptionsMenuItemID {
|
|||||||
|
|
||||||
struct MenuItem {
|
struct MenuItem {
|
||||||
enum Flag {
|
enum Flag {
|
||||||
INVISIBLE_ON_DC = 0x01,
|
// For menu items to be visible on DCNTE, they must not have either of the
|
||||||
INVISIBLE_ON_PC = 0x02,
|
// following two flags. (The INVISIBLE_ON_GCNTE flag behaves similarly.)
|
||||||
INVISIBLE_ON_GC = 0x04,
|
INVISIBLE_ON_DCNTE = 0x001,
|
||||||
INVISIBLE_ON_XB = 0x08,
|
INVISIBLE_ON_DC = 0x002,
|
||||||
INVISIBLE_ON_BB = 0x10,
|
INVISIBLE_ON_PC = 0x004,
|
||||||
|
INVISIBLE_ON_GC_TRIAL_EDITION = 0x008,
|
||||||
|
INVISIBLE_ON_GC = 0x010,
|
||||||
|
INVISIBLE_ON_XB = 0x020,
|
||||||
|
INVISIBLE_ON_BB = 0x040,
|
||||||
DC_ONLY = INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
DC_ONLY = INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
||||||
PC_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_GC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
PC_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_GC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
||||||
GC_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
GC_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_XB | INVISIBLE_ON_BB,
|
||||||
XB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_BB,
|
XB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_BB,
|
||||||
BB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_XB,
|
BB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_XB,
|
||||||
REQUIRES_MESSAGE_BOXES = 0x20,
|
REQUIRES_MESSAGE_BOXES = 0x080,
|
||||||
REQUIRES_SEND_FUNCTION_CALL = 0x40,
|
REQUIRES_SEND_FUNCTION_CALL = 0x100,
|
||||||
REQUIRES_SAVE_DISABLED = 0x80,
|
REQUIRES_SAVE_DISABLED = 0x200,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t item_id;
|
uint32_t item_id;
|
||||||
|
|||||||
+27
-7
@@ -336,7 +336,8 @@ static void on_login_8_dcnte(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
|
|
||||||
static void on_login_b_dcnte(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
static void on_login_b_dcnte(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||||
uint16_t, uint32_t, const string& data) { // 8B
|
uint16_t, uint32_t, const string& data) { // 8B
|
||||||
const auto& cmd = check_size_t<C_Login_DCNTE_8B>(data);
|
const auto& cmd = check_size_t<C_Login_DCNTE_8B>(data,
|
||||||
|
sizeof(C_Login_DCNTE_8B), sizeof(C_LoginExtended_DCNTE_8B));
|
||||||
c->channel.version = GameVersion::DC;
|
c->channel.version = GameVersion::DC;
|
||||||
c->flags |= flags_for_version(c->version(), -1);
|
c->flags |= flags_for_version(c->version(), -1);
|
||||||
c->flags |= Client::Flag::IS_DC_V1 | Client::Flag::IS_TRIAL_EDITION;
|
c->flags |= Client::Flag::IS_DC_V1 | Client::Flag::IS_TRIAL_EDITION;
|
||||||
@@ -346,7 +347,7 @@ static void on_login_b_dcnte(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
shared_ptr<const License> l = s->license_manager->verify_pc(
|
shared_ptr<const License> l = s->license_manager->verify_pc(
|
||||||
serial_number, cmd.access_key);
|
serial_number, cmd.access_key);
|
||||||
c->set_license(l);
|
c->set_license(l);
|
||||||
send_command(c, 0x8B, 0x01);
|
// send_command(c, 0x8B, 0x01);
|
||||||
|
|
||||||
} catch (const incorrect_access_key& e) {
|
} catch (const incorrect_access_key& e) {
|
||||||
send_message_box(c, u"Incorrect access key");
|
send_message_box(c, u"Incorrect access key");
|
||||||
@@ -361,9 +362,21 @@ static void on_login_b_dcnte(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
serial_number, cmd.access_key, true);
|
serial_number, cmd.access_key, true);
|
||||||
s->license_manager->add(l);
|
s->license_manager->add(l);
|
||||||
c->set_license(l);
|
c->set_license(l);
|
||||||
send_command(c, 0x8B, 0x01);
|
// send_command(c, 0x8B, 0x01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd.is_extended) {
|
||||||
|
const auto& ext_cmd = check_size_t<C_LoginExtended_DCNTE_8B>(data);
|
||||||
|
if (ext_cmd.extension.menu_id == MenuID::LOBBY) {
|
||||||
|
c->preferred_lobby_id = ext_cmd.extension.lobby_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c->should_disconnect) {
|
||||||
|
send_update_client_config(c);
|
||||||
|
on_login_complete(s, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_login_0_dc_pc_v3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
static void on_login_0_dc_pc_v3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||||
@@ -1188,8 +1201,14 @@ static void on_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
c->should_send_to_lobby_server = true;
|
c->should_send_to_lobby_server = true;
|
||||||
if (!(c->flags & Client::Flag::SAVE_ENABLED)) {
|
if (!(c->flags & Client::Flag::SAVE_ENABLED)) {
|
||||||
c->flags |= Client::Flag::SAVE_ENABLED;
|
c->flags |= Client::Flag::SAVE_ENABLED;
|
||||||
send_command(c, 0x97, 0x01);
|
// DC NTE crashes if it receives a 97 command, so we instead do the
|
||||||
send_update_client_config(c);
|
// redirect immediately
|
||||||
|
if ((c->version() == GameVersion::DC) && (c->flags & Client::Flag::IS_TRIAL_EDITION)) {
|
||||||
|
send_client_to_lobby_server(s, c);
|
||||||
|
} else {
|
||||||
|
send_command(c, 0x97, 0x01);
|
||||||
|
send_update_client_config(c);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
send_client_to_lobby_server(s, c);
|
send_client_to_lobby_server(s, c);
|
||||||
}
|
}
|
||||||
@@ -3178,7 +3197,7 @@ static on_command_t handlers[0x100][6] = {
|
|||||||
/* 88 */ {nullptr, on_login_8_dcnte, nullptr, on_login_8_dcnte, nullptr, nullptr, }, /* 88 */
|
/* 88 */ {nullptr, on_login_8_dcnte, nullptr, on_login_8_dcnte, nullptr, nullptr, }, /* 88 */
|
||||||
/* 89 */ {nullptr, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, }, /* 89 */
|
/* 89 */ {nullptr, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, on_change_arrow_color, }, /* 89 */
|
||||||
/* 8A */ {nullptr, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, }, /* 8A */
|
/* 8A */ {nullptr, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, on_lobby_name_request, }, /* 8A */
|
||||||
/* 8B */ {nullptr, on_login_b_dcnte, nullptr, nullptr, nullptr, nullptr, }, /* 8B */
|
/* 8B */ {nullptr, on_login_b_dcnte, nullptr, on_login_b_dcnte, nullptr, nullptr, }, /* 8B */
|
||||||
/* 8C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8C */
|
/* 8C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8C */
|
||||||
/* 8D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8D */
|
/* 8D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8D */
|
||||||
/* 8E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8E */
|
/* 8E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* 8E */
|
||||||
@@ -3317,13 +3336,14 @@ static void check_unlicensed_command(GameVersion version, uint8_t command) {
|
|||||||
case GameVersion::XB:
|
case GameVersion::XB:
|
||||||
// See comment in the DC case above for why DC commands are included here.
|
// See comment in the DC case above for why DC commands are included here.
|
||||||
if (command != 0x88 && // DC NTE
|
if (command != 0x88 && // DC NTE
|
||||||
|
command != 0x8B && // DC NTE
|
||||||
command != 0x90 && // DC v1
|
command != 0x90 && // DC v1
|
||||||
command != 0x93 && // DC v1
|
command != 0x93 && // DC v1
|
||||||
command != 0x9A && // DC v2
|
command != 0x9A && // DC v2
|
||||||
command != 0x9D && // DC v2, GC trial edition
|
command != 0x9D && // DC v2, GC trial edition
|
||||||
command != 0x9E && // GC non-trial
|
command != 0x9E && // GC non-trial
|
||||||
command != 0xDB) { // GC non-trial
|
command != 0xDB) { // GC non-trial
|
||||||
throw runtime_error("only commands 90, 93, 9A, 9D, 9E, and DB may be sent before login");
|
throw runtime_error("only commands 88, 8B, 90, 93, 9A, 9D, 9E, and DB may be sent before login");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameVersion::BB:
|
case GameVersion::BB:
|
||||||
|
|||||||
+50
-15
@@ -23,6 +23,8 @@ using namespace std;
|
|||||||
|
|
||||||
const unordered_set<uint32_t> v2_crypt_initial_client_commands({
|
const unordered_set<uint32_t> v2_crypt_initial_client_commands({
|
||||||
0x00260088, // (17) DCNTE license check
|
0x00260088, // (17) DCNTE license check
|
||||||
|
0x00B0008B, // (02) DCNTE login
|
||||||
|
0x0114008B, // (02) DCNTE extended login
|
||||||
0x00280090, // (17) DCv1 license check
|
0x00280090, // (17) DCv1 license check
|
||||||
0x00B00093, // (02) DCv1 login
|
0x00B00093, // (02) DCv1 login
|
||||||
0x01140093, // (02) DCv1 extended login
|
0x01140093, // (02) DCv1 extended login
|
||||||
@@ -881,21 +883,49 @@ void send_menu_t(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& item : items) {
|
for (const auto& item : items) {
|
||||||
if (((c->version() == GameVersion::DC) && (item.flags & MenuItem::Flag::INVISIBLE_ON_DC)) ||
|
bool is_visible = true;
|
||||||
((c->version() == GameVersion::PC) && (item.flags & MenuItem::Flag::INVISIBLE_ON_PC)) ||
|
switch (c->version()) {
|
||||||
((c->version() == GameVersion::GC) && (item.flags & MenuItem::Flag::INVISIBLE_ON_GC)) ||
|
case GameVersion::DC:
|
||||||
((c->version() == GameVersion::XB) && (item.flags & MenuItem::Flag::INVISIBLE_ON_XB)) ||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_DC);
|
||||||
((c->version() == GameVersion::BB) && (item.flags & MenuItem::Flag::INVISIBLE_ON_BB)) ||
|
if (c->flags & Client::Flag::IS_TRIAL_EDITION) {
|
||||||
((item.flags & MenuItem::Flag::REQUIRES_MESSAGE_BOXES) && (c->flags & Client::Flag::NO_D6)) ||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_DCNTE);
|
||||||
((item.flags & MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL) && (c->flags & Client::Flag::NO_SEND_FUNCTION_CALL)) ||
|
}
|
||||||
((item.flags & MenuItem::Flag::REQUIRES_SAVE_DISABLED) && (c->flags & Client::Flag::SAVE_ENABLED))) {
|
break;
|
||||||
continue;
|
case GameVersion::PC:
|
||||||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_PC);
|
||||||
|
break;
|
||||||
|
case GameVersion::GC:
|
||||||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_GC);
|
||||||
|
if (c->flags & Client::Flag::IS_TRIAL_EDITION) {
|
||||||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_GC_TRIAL_EDITION);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GameVersion::XB:
|
||||||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_XB);
|
||||||
|
break;
|
||||||
|
case GameVersion::BB:
|
||||||
|
is_visible &= !(item.flags & MenuItem::Flag::INVISIBLE_ON_BB);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw runtime_error("menus not supported for this game version");
|
||||||
|
}
|
||||||
|
if (item.flags & MenuItem::Flag::REQUIRES_MESSAGE_BOXES) {
|
||||||
|
is_visible &= !(c->flags & Client::Flag::NO_D6);
|
||||||
|
}
|
||||||
|
if (item.flags & MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL) {
|
||||||
|
is_visible &= !(c->flags & Client::Flag::NO_SEND_FUNCTION_CALL);
|
||||||
|
}
|
||||||
|
if (item.flags & MenuItem::Flag::REQUIRES_SAVE_DISABLED) {
|
||||||
|
is_visible &= !(c->flags & Client::Flag::SAVE_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_visible) {
|
||||||
|
auto& e = entries.emplace_back();
|
||||||
|
e.menu_id = menu_id;
|
||||||
|
e.item_id = item.item_id;
|
||||||
|
e.flags = (c->version() == GameVersion::BB) ? 0x0004 : 0x0F04;
|
||||||
|
e.text = item.name;
|
||||||
}
|
}
|
||||||
auto& e = entries.emplace_back();
|
|
||||||
e.menu_id = menu_id;
|
|
||||||
e.item_id = item.item_id;
|
|
||||||
e.flags = (c->version() == GameVersion::BB) ? 0x0004 : 0x0F04;
|
|
||||||
e.text = item.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
send_command_vt(c, is_info_menu ? 0x1F : 0x07, entries.size() - 1, entries);
|
send_command_vt(c, is_info_menu ? 0x1F : 0x07, entries.size() - 1, entries);
|
||||||
@@ -1294,7 +1324,12 @@ void send_self_leave_notification(shared_ptr<Client> c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void send_get_player_info(shared_ptr<Client> c) {
|
void send_get_player_info(shared_ptr<Client> c) {
|
||||||
send_command(c, 0x95, 0x00);
|
if ((c->version() == GameVersion::DC) &&
|
||||||
|
(c->flags & Client::Flag::IS_TRIAL_EDITION)) {
|
||||||
|
send_command(c, 0x8D, 0x00);
|
||||||
|
} else {
|
||||||
|
send_command(c, 0x95, 0x00);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -406,8 +406,11 @@ void ServerState::create_menus(shared_ptr<const JSONObject> config_json) {
|
|||||||
this->main_menu.emplace_back(MainMenuItemID::GO_TO_LOBBY, u"Go to lobby",
|
this->main_menu.emplace_back(MainMenuItemID::GO_TO_LOBBY, u"Go to lobby",
|
||||||
u"Join the lobby", 0);
|
u"Join the lobby", 0);
|
||||||
this->main_menu.emplace_back(MainMenuItemID::INFORMATION, u"Information",
|
this->main_menu.emplace_back(MainMenuItemID::INFORMATION, u"Information",
|
||||||
u"View server\ninformation", MenuItem::Flag::REQUIRES_MESSAGE_BOXES);
|
u"View server\ninformation", MenuItem::Flag::INVISIBLE_ON_DCNTE | MenuItem::Flag::REQUIRES_MESSAGE_BOXES);
|
||||||
uint32_t proxy_destinations_menu_item_flags =
|
uint32_t proxy_destinations_menu_item_flags =
|
||||||
|
// DCNTE doesn't support multiple ship select menus without changing
|
||||||
|
// servers (via a 19 command) apparently :(
|
||||||
|
MenuItem::Flag::INVISIBLE_ON_DCNTE |
|
||||||
(this->proxy_destinations_dc.empty() ? MenuItem::Flag::INVISIBLE_ON_DC : 0) |
|
(this->proxy_destinations_dc.empty() ? MenuItem::Flag::INVISIBLE_ON_DC : 0) |
|
||||||
(this->proxy_destinations_pc.empty() ? MenuItem::Flag::INVISIBLE_ON_PC : 0) |
|
(this->proxy_destinations_pc.empty() ? MenuItem::Flag::INVISIBLE_ON_PC : 0) |
|
||||||
(this->proxy_destinations_gc.empty() ? MenuItem::Flag::INVISIBLE_ON_GC : 0) |
|
(this->proxy_destinations_gc.empty() ? MenuItem::Flag::INVISIBLE_ON_GC : 0) |
|
||||||
@@ -416,7 +419,7 @@ void ServerState::create_menus(shared_ptr<const JSONObject> config_json) {
|
|||||||
this->main_menu.emplace_back(MainMenuItemID::PROXY_DESTINATIONS, u"Proxy server",
|
this->main_menu.emplace_back(MainMenuItemID::PROXY_DESTINATIONS, u"Proxy server",
|
||||||
u"Connect to another\nserver", proxy_destinations_menu_item_flags);
|
u"Connect to another\nserver", proxy_destinations_menu_item_flags);
|
||||||
this->main_menu.emplace_back(MainMenuItemID::DOWNLOAD_QUESTS, u"Download quests",
|
this->main_menu.emplace_back(MainMenuItemID::DOWNLOAD_QUESTS, u"Download quests",
|
||||||
u"Download quests", MenuItem::Flag::INVISIBLE_ON_BB);
|
u"Download quests", MenuItem::Flag::INVISIBLE_ON_DCNTE | MenuItem::Flag::INVISIBLE_ON_BB);
|
||||||
if (!this->function_code_index->patch_menu_empty()) {
|
if (!this->function_code_index->patch_menu_empty()) {
|
||||||
this->main_menu.emplace_back(MainMenuItemID::PATCHES, u"Patches",
|
this->main_menu.emplace_back(MainMenuItemID::PATCHES, u"Patches",
|
||||||
u"Change game\nbehaviors", MenuItem::Flag::GC_ONLY | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
u"Change game\nbehaviors", MenuItem::Flag::GC_ONLY | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||||
@@ -429,7 +432,7 @@ void ServerState::create_menus(shared_ptr<const JSONObject> config_json) {
|
|||||||
u"Disconnect", 0);
|
u"Disconnect", 0);
|
||||||
this->main_menu.emplace_back(MainMenuItemID::CLEAR_LICENSE, u"Clear license",
|
this->main_menu.emplace_back(MainMenuItemID::CLEAR_LICENSE, u"Clear license",
|
||||||
u"Disconnect with an\ninvalid license error\nso you can enter a\ndifferent serial\nnumber, access key,\nor password",
|
u"Disconnect with an\ninvalid license error\nso you can enter a\ndifferent serial\nnumber, access key,\nor password",
|
||||||
MenuItem::Flag::INVISIBLE_ON_BB);
|
MenuItem::Flag::INVISIBLE_ON_DCNTE | MenuItem::Flag::INVISIBLE_ON_BB);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this->welcome_message = decode_sjis(d.at("WelcomeMessage")->as_string());
|
this->welcome_message = decode_sjis(d.at("WelcomeMessage")->as_string());
|
||||||
|
|||||||
Reference in New Issue
Block a user