add proxy options menu
This commit is contained in:
@@ -40,6 +40,7 @@ Current known issues / missing features / things to do:
|
||||
- Implement private and overflow lobbies.
|
||||
- Enforce client-side size limits (e.g. for 60/62 commands) on the server side as well. (For 60/62 specifically, perhaps transform them to 6C/6D if needed.)
|
||||
- Encapsulate BB server-side random state and make replays deterministic.
|
||||
- The internal menu abstraction is ugly and hard to work with. Rewrite it.
|
||||
|
||||
## Compatibility
|
||||
|
||||
|
||||
@@ -198,6 +198,21 @@ static void server_command_dbgid(shared_ptr<ServerState>, shared_ptr<Lobby>,
|
||||
c->prefer_high_lobby_client_id ? "high" : "low");
|
||||
}
|
||||
|
||||
static void server_command_proxygc(shared_ptr<ServerState>, shared_ptr<Lobby>,
|
||||
shared_ptr<Client> c, const std::u16string& args) {
|
||||
uint32_t proxy_remote_guild_card_number = stoll(encode_sjis(args), nullptr, 0);
|
||||
client_options_cache.replace(
|
||||
string_printf("proxy_remote_guild_card_number:%" PRIX32, c->license->serial_number),
|
||||
string_printf("%08" PRIu32, proxy_remote_guild_card_number));
|
||||
send_text_message_printf(c, "Proxy remote Guild\nCard number set to\n$C6%" PRIu32,
|
||||
proxy_remote_guild_card_number);
|
||||
}
|
||||
|
||||
static void proxy_command_proxygc(shared_ptr<ServerState>,
|
||||
ProxyServer::LinkedSession& session, const std::u16string& args) {
|
||||
session.remote_guild_card_number = stoll(encode_sjis(args), nullptr, 0);
|
||||
}
|
||||
|
||||
static void server_command_persist(shared_ptr<ServerState>, shared_ptr<Lobby> l,
|
||||
shared_ptr<Client> c, const std::u16string&) {
|
||||
check_privileges(c, Privilege::DEBUG);
|
||||
@@ -919,6 +934,7 @@ static const unordered_map<u16string, ChatCommandDefinition> chat_commands({
|
||||
{u"$next", {server_command_next, nullptr, u"Usage:\nnext"}},
|
||||
{u"$password", {server_command_password, nullptr, u"Usage:\nlock [password]\nomit password to\nunlock game"}},
|
||||
{u"$persist", {server_command_persist, nullptr, u"Usage:\npersist"}},
|
||||
{u"$proxygc", {server_command_proxygc, proxy_command_proxygc, u"Usage:\nproxygc <gc#>"}},
|
||||
{u"$rand", {server_command_rand, proxy_command_rand, u"Usage:\nrand [hex seed]\nomit seed to revert\nto default"}},
|
||||
{u"$secid", {server_command_secid, proxy_command_secid, u"Usage:\nsecid [section ID]\nomit section ID to\nrevert to normal"}},
|
||||
{u"$silence", {server_command_silence, nullptr, u"Usage:\nsilence <name-or-number>"}},
|
||||
|
||||
@@ -19,6 +19,7 @@ using namespace std;
|
||||
|
||||
|
||||
const uint64_t CLIENT_CONFIG_MAGIC = 0x492A890E82AC9839;
|
||||
FileContentsCache client_options_cache(3600 * 1000 * 1000);
|
||||
|
||||
static atomic<uint64_t> next_id(1);
|
||||
|
||||
@@ -59,6 +60,8 @@ Client::Client(
|
||||
switch_assist(false),
|
||||
can_chat(true),
|
||||
pending_bb_save_player_index(0),
|
||||
proxy_save_files(false),
|
||||
proxy_suppress_remote_login(false),
|
||||
dol_base_addr(0) {
|
||||
this->last_switch_enabled_command.subcommand = 0;
|
||||
memset(&this->next_connection_addr, 0, sizeof(this->next_connection_addr));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "Channel.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "FileContentsCache.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "License.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
@@ -17,6 +18,7 @@
|
||||
|
||||
|
||||
extern const uint64_t CLIENT_CONFIG_MAGIC;
|
||||
extern FileContentsCache client_options_cache;
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +114,9 @@ struct Client {
|
||||
std::string pending_bb_save_username;
|
||||
uint8_t pending_bb_save_player_index;
|
||||
|
||||
bool proxy_save_files;
|
||||
bool proxy_suppress_remote_login;
|
||||
|
||||
// DOL file loading state
|
||||
uint32_t dol_base_addr;
|
||||
std::shared_ptr<DOLFileIndex::DOLFile> loading_dol_file;
|
||||
|
||||
@@ -620,11 +620,10 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 {
|
||||
// 17 (S->C): Start encryption at login server (except on BB)
|
||||
// Same format and usage as 02 command, but a different copyright string:
|
||||
// "DreamCast Port Map. Copyright SEGA Enterprises. 1999"
|
||||
// Unlike the 02 command, V3 clients will respond with a DB command the first
|
||||
// time they receive a 17 command in any online session, with the exception of
|
||||
// Episodes 1&2 trial edition (which responds with a 9A). After the first time,
|
||||
// V3 clients will respond with a 9E. DCv1 will respond with a 90. Other non-V3
|
||||
// clients will respond with a 9A or 9D.
|
||||
// Unlike the 02 command, V3 clients will respond with a DB command when they
|
||||
// receive a 17 command in any online session, with the exception of Episodes
|
||||
// 1&2 trial edition (which responds with a 9A). DCv1 will respond with a 90.
|
||||
// Other non-V3 clients will respond with a 9A or 9D.
|
||||
|
||||
// 18 (S->C): License verification result (PC/V3)
|
||||
// Behaves exactly the same as 9A (S->C). No arguments except header.flag.
|
||||
|
||||
+1
-2
@@ -621,9 +621,8 @@ int main(int argc, char** argv) {
|
||||
use_terminal_colors = true;
|
||||
}
|
||||
|
||||
shared_ptr<ServerState> state(new ServerState());
|
||||
|
||||
shared_ptr<struct event_base> base(event_base_new(), event_base_free);
|
||||
shared_ptr<ServerState> state(new ServerState());
|
||||
|
||||
config_log.info("Reading network addresses");
|
||||
state->all_addresses = get_local_addresses();
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "FileContentsCache.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
+15
-4
@@ -22,6 +22,7 @@ namespace MenuID {
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x77000077;
|
||||
constexpr uint32_t PROGRAMS = 0x88000088;
|
||||
constexpr uint32_t PATCHES = 0x99000099;
|
||||
constexpr uint32_t PROXY_OPTIONS = 0xAA0000AA;
|
||||
}
|
||||
|
||||
namespace MainMenuItemID {
|
||||
@@ -37,19 +38,29 @@ namespace MainMenuItemID {
|
||||
|
||||
namespace InformationMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x22FFFF22;
|
||||
};
|
||||
}
|
||||
|
||||
namespace ProxyDestinationsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x77FFFF77;
|
||||
};
|
||||
constexpr uint32_t OPTIONS = 0x77EEEE77;
|
||||
}
|
||||
|
||||
namespace ProgramsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x88FFFF88;
|
||||
};
|
||||
}
|
||||
|
||||
namespace PatchesMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x99FFFF99;
|
||||
};
|
||||
}
|
||||
|
||||
namespace ProxyOptionsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0xAAFFFFAA;
|
||||
constexpr uint32_t INFINITE_HP = 0xAA1111AA;
|
||||
constexpr uint32_t INFINITE_TP = 0xAA2222AA;
|
||||
constexpr uint32_t SWITCH_ASSIST = 0xAA3333AA;
|
||||
constexpr uint32_t SAVE_FILES = 0xAA4444AA;
|
||||
constexpr uint32_t SUPPRESS_LOGIN = 0xAA5555AA;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+67
-31
@@ -62,29 +62,6 @@ static void check_implemented_subcommand(
|
||||
|
||||
|
||||
|
||||
static void send_text_message_to_client(
|
||||
ProxyServer::LinkedSession& session,
|
||||
uint8_t command,
|
||||
const std::string& message) {
|
||||
StringWriter w;
|
||||
w.put<SC_TextHeader_01_06_11_B0_EE>({0, 0});
|
||||
if ((session.version == GameVersion::PC) ||
|
||||
(session.version == GameVersion::BB)) {
|
||||
auto decoded = decode_sjis(message);
|
||||
w.write(decoded.data(), decoded.size() * sizeof(decoded[0]));
|
||||
w.put_u16l(0);
|
||||
} else {
|
||||
w.write(message);
|
||||
w.put_u8(0);
|
||||
}
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
session.client_channel.send(command, 0x00, w.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Command handlers. These are called to preprocess or react to specific
|
||||
// commands in either direction. If they return true, the command (which the
|
||||
// function may have modified) is forwarded to the other end; if they return
|
||||
@@ -125,9 +102,26 @@ static HandlerResult on_server_97(shared_ptr<ServerState>,
|
||||
return HandlerResult::Type::FORWARD;
|
||||
}
|
||||
|
||||
static HandlerResult on_client_gc_9E(shared_ptr<ServerState>,
|
||||
ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) {
|
||||
if (session.suppress_remote_login) {
|
||||
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
|
||||
session.server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
|
||||
|
||||
S_UpdateClientConfig_DC_PC_V3_04 cmd = {0x00010000, session.license->serial_number, ClientConfig()};
|
||||
session.client_channel.send(0x04, 0x00, &cmd, sizeof(cmd));
|
||||
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
|
||||
} else {
|
||||
return HandlerResult::Type::FORWARD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static HandlerResult on_server_gc_9A(shared_ptr<ServerState>,
|
||||
ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) {
|
||||
if (!session.license) {
|
||||
if (!session.license || session.suppress_remote_login) {
|
||||
return HandlerResult::Type::FORWARD;
|
||||
}
|
||||
|
||||
@@ -318,6 +312,39 @@ static HandlerResult on_server_dc_pc_v3_patch_02_17(
|
||||
session.server_channel.send(0xDB, 0x00, &cmd, sizeof(cmd));
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
|
||||
} else if (session.suppress_remote_login) {
|
||||
uint32_t guild_card_number;
|
||||
if (session.remote_guild_card_number >= 0) {
|
||||
guild_card_number = session.remote_guild_card_number;
|
||||
log_info("Using Guild Card number %" PRIu32 " from session", guild_card_number);
|
||||
} else {
|
||||
guild_card_number = random_object<uint32_t>();
|
||||
log_info("Using Guild Card number %" PRIu32 " from random generator", guild_card_number);
|
||||
}
|
||||
|
||||
uint32_t fake_serial_number = random_object<uint32_t>() & 0x7FFFFFFF;
|
||||
uint64_t fake_access_key = random_object<uint64_t>();
|
||||
string fake_access_key_str = string_printf("00000000000%" PRIu64, fake_access_key);
|
||||
if (fake_access_key_str.size() > 12) {
|
||||
fake_access_key_str = fake_access_key_str.substr(fake_access_key_str.size() - 12);
|
||||
}
|
||||
|
||||
C_LoginExtended_GC_9E cmd;
|
||||
cmd.player_tag = 0x00010000;
|
||||
cmd.guild_card_number = guild_card_number;
|
||||
cmd.unused = 0;
|
||||
cmd.sub_version = session.sub_version;
|
||||
cmd.is_extended = 0;
|
||||
cmd.language = session.language;
|
||||
cmd.serial_number = string_printf("%08" PRIX32, fake_serial_number);
|
||||
cmd.access_key = fake_access_key_str;
|
||||
cmd.serial_number2 = cmd.serial_number;
|
||||
cmd.access_key2 = cmd.access_key;
|
||||
cmd.name = session.character_name;
|
||||
cmd.client_config.data = session.remote_client_config_data;
|
||||
session.server_channel.send(0x9E, 0x01, &cmd, sizeof(C_Login_GC_9E));
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
|
||||
} else {
|
||||
// For command 02, send the same as if we had received 9A from the server
|
||||
return on_server_gc_9A(s, session, command, flag, data);
|
||||
@@ -389,6 +416,13 @@ static HandlerResult on_server_bb_03(shared_ptr<ServerState> s,
|
||||
|
||||
static HandlerResult on_server_dc_pc_v3_04(shared_ptr<ServerState>,
|
||||
ProxyServer::LinkedSession& session, uint16_t, uint32_t, string& data) {
|
||||
// Suppress extremely short commands from the server instead of disconnecting.
|
||||
if (data.size() < offsetof(S_UpdateClientConfig_DC_PC_V3_04, cfg)) {
|
||||
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
|
||||
session.server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
}
|
||||
|
||||
// Some servers send a short 04 command if they don't use all of the 0x20
|
||||
// bytes available. We should be prepared to handle that.
|
||||
auto& cmd = check_size_t<S_UpdateClientConfig_DC_PC_V3_04>(data,
|
||||
@@ -404,9 +438,10 @@ static HandlerResult on_server_dc_pc_v3_04(shared_ptr<ServerState>,
|
||||
session.remote_guild_card_number = cmd.guild_card_number;
|
||||
session.log.info("Remote guild card number set to %" PRId64,
|
||||
session.remote_guild_card_number);
|
||||
send_text_message_to_client(session, 0x11, string_printf(
|
||||
string message = string_printf(
|
||||
"The remote server\nhas assigned your\nGuild Card number:\n\tC6%" PRId64,
|
||||
session.remote_guild_card_number));
|
||||
session.remote_guild_card_number);
|
||||
send_ship_info(session.client_channel, decode_sjis(message));
|
||||
}
|
||||
if (session.license) {
|
||||
cmd.guild_card_number = session.license->serial_number;
|
||||
@@ -431,10 +466,6 @@ static HandlerResult on_server_dc_pc_v3_04(shared_ptr<ServerState>,
|
||||
// the first 04 command the client has received. The client responds with a 96
|
||||
// (checksum) in that case.
|
||||
if (!had_guild_card_number) {
|
||||
// We don't actually have a client checksum, of course... hopefully just
|
||||
// random data will do (probably no private servers check this at all)
|
||||
// TODO: Presumably we can save these values from the client when they
|
||||
// connected to newserv originally, but I'm too lazy to do this right now
|
||||
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
|
||||
session.server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
|
||||
}
|
||||
@@ -918,6 +949,7 @@ static HandlerResult on_server_65_67_68(shared_ptr<ServerState>,
|
||||
auto& cmd = check_size_t<CmdT>(data, expected_size, expected_size);
|
||||
bool modified = false;
|
||||
|
||||
size_t num_replacements = 0;
|
||||
session.lobby_client_id = cmd.client_id;
|
||||
update_leader_id(session, cmd.leader_id);
|
||||
for (size_t x = 0; x < flag; x++) {
|
||||
@@ -927,6 +959,7 @@ static HandlerResult on_server_65_67_68(shared_ptr<ServerState>,
|
||||
} else {
|
||||
if (session.license && (cmd.entries[x].lobby_data.guild_card == session.remote_guild_card_number)) {
|
||||
cmd.entries[x].lobby_data.guild_card = session.license->serial_number;
|
||||
num_replacements++;
|
||||
modified = true;
|
||||
}
|
||||
session.lobby_players[index].guild_card_number = cmd.entries[x].lobby_data.guild_card;
|
||||
@@ -938,6 +971,9 @@ static HandlerResult on_server_65_67_68(shared_ptr<ServerState>,
|
||||
session.lobby_players[index].name.c_str());
|
||||
}
|
||||
}
|
||||
if (num_replacements > 1) {
|
||||
throw runtime_error("proxied player appears multiple times in lobby");
|
||||
}
|
||||
|
||||
if (session.override_lobby_event >= 0) {
|
||||
cmd.event = session.override_lobby_event;
|
||||
@@ -2157,7 +2193,7 @@ static on_command_t handlers[6][0x100][2] = {
|
||||
/* 9B */ {nullptr, nullptr},
|
||||
/* 9C */ {nullptr, nullptr},
|
||||
/* 9D */ {nullptr, nullptr},
|
||||
/* 9E */ {nullptr, nullptr},
|
||||
/* 9E */ {nullptr, on_client_gc_9E},
|
||||
/* 9F */ {nullptr, nullptr},
|
||||
// (GC) SERVER CLIENT
|
||||
/* A0 */ {nullptr, on_client_dc_pc_v3_A0_A1},
|
||||
|
||||
@@ -480,6 +480,7 @@ ProxyServer::LinkedSession::LinkedSession(
|
||||
infinite_hp(false),
|
||||
infinite_tp(false),
|
||||
save_files(false),
|
||||
suppress_remote_login(false),
|
||||
function_call_return_value(-1),
|
||||
next_item_id(0x0F000000),
|
||||
override_section_id(-1),
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
bool infinite_hp;
|
||||
bool infinite_tp;
|
||||
bool save_files;
|
||||
bool suppress_remote_login;
|
||||
int64_t function_call_return_value; // -1 = don't block function calls
|
||||
G_SwitchStateChanged_6x05 last_switch_enabled_command;
|
||||
PlayerInventoryItem next_drop_item;
|
||||
|
||||
+105
-4
@@ -875,18 +875,44 @@ static void on_menu_item_info_request(shared_ptr<ServerState> s, shared_ptr<Clie
|
||||
|
||||
case MenuID::PROXY_DESTINATIONS:
|
||||
if (cmd.item_id == ProxyDestinationsMenuItemID::GO_BACK) {
|
||||
send_ship_info(c, u"Return to the\nmain menu.");
|
||||
send_ship_info(c, u"Return to the\nmain menu");
|
||||
} else if (cmd.item_id == ProxyDestinationsMenuItemID::OPTIONS) {
|
||||
send_ship_info(c, u"Set proxy session\noptions");
|
||||
} else {
|
||||
try {
|
||||
const auto& menu = s->proxy_destinations_menu_for_version(c->version());
|
||||
// We use item_id + 1 here because "go back" is the first item
|
||||
send_ship_info(c, menu.at(cmd.item_id + 1).description.c_str());
|
||||
// We use item_id + 2 here because "go back" and "options" are the
|
||||
// first items
|
||||
send_ship_info(c, menu.at(cmd.item_id + 2).description.c_str());
|
||||
} catch (const out_of_range&) {
|
||||
send_ship_info(c, u"$C4Missing proxy\ndestination");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MenuID::PROXY_OPTIONS:
|
||||
switch (cmd.item_id) {
|
||||
case ProxyOptionsMenuItemID::GO_BACK:
|
||||
send_ship_info(c, u"Return to the\nproxy menu");
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::INFINITE_HP:
|
||||
send_ship_info(c, u"Enable or disable\ninfinite HP\n\nYou can change this\nduring the session\nwith the %sinfhp\ncommand");
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::INFINITE_TP:
|
||||
send_ship_info(c, u"Enable or disable\ninfinite TP\n\nYou can change this\nduring the session\nwith the %sinftp\ncommand");
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::SWITCH_ASSIST:
|
||||
send_ship_info(c, u"Enable or disable\nswitch assist\n\nYou can change this\nduring the session\nwith the %sswa\ncommand");
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::SAVE_FILES:
|
||||
send_ship_info(c, u"Enable or disable\nsaving of files from\nthe remote server\n(quests, etc.)");
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::SUPPRESS_LOGIN:
|
||||
send_ship_info(c, u"Enable or disable\nalternate login\nsequence");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MenuID::QUEST_FILTER:
|
||||
// Don't send anything here. The quest filter menu already has short
|
||||
// descriptions included with the entries, which the client shows in the
|
||||
@@ -1012,6 +1038,29 @@ static void on_menu_item_info_request(shared_ptr<ServerState> s, shared_ptr<Clie
|
||||
}
|
||||
}
|
||||
|
||||
static vector<MenuItem> proxy_options_menu_for_client(
|
||||
shared_ptr<const Client> c) {
|
||||
vector<MenuItem> ret;
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::GO_BACK, u"Go back",
|
||||
u"Return to the\nproxy menu", 0);
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::INFINITE_HP,
|
||||
c->infinite_hp ? u"Infinite HP ON" : u"Infinite HP OFF",
|
||||
u"Enable or disable\ninfinite HP", 0);
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::INFINITE_TP,
|
||||
c->infinite_tp ? u"Infinite TP ON" : u"Infinite TP OFF",
|
||||
u"Enable or disable\ninfinite TP", 0);
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::SWITCH_ASSIST,
|
||||
c->switch_assist ? u"Switch assist ON" : u"Switch assist OFF",
|
||||
u"Enable or disable\nswitch assist", 0);
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::SAVE_FILES,
|
||||
c->proxy_save_files ? u"Save files ON" : u"Save files OFF",
|
||||
u"Enable or disable\nsaving of files from\nthe remote server\n(quests, etc.)", 0);
|
||||
ret.emplace_back(ProxyOptionsMenuItemID::SUPPRESS_LOGIN,
|
||||
c->proxy_suppress_remote_login ? u"Skip login ON" : u"Skip login OFF",
|
||||
u"Enable or disable\nalternate login\nsequence", 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void on_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) { // 10
|
||||
bool uses_unicode = ((c->version() == GameVersion::PC) || (c->version() == GameVersion::BB));
|
||||
@@ -1066,6 +1115,13 @@ static void on_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
case MainMenuItemID::PROXY_DESTINATIONS:
|
||||
send_menu(c, u"Proxy server", MenuID::PROXY_DESTINATIONS,
|
||||
s->proxy_destinations_menu_for_version(c->version()));
|
||||
try {
|
||||
string key = string_printf("proxy_remote_guild_card_number:%" PRIX32, c->license->serial_number);
|
||||
const auto& entry = client_options_cache.get_or_throw(key);
|
||||
uint32_t proxy_remote_guild_card_number = stoul(entry->data, nullptr, 10);
|
||||
string info_str = string_printf("Your remote Guild\nCard number is\noverridden as\n$C6%" PRIu32, proxy_remote_guild_card_number);
|
||||
send_ship_info(c, decode_sjis(info_str));
|
||||
} catch (const out_of_range&) { }
|
||||
break;
|
||||
|
||||
case MainMenuItemID::DOWNLOAD_QUESTS:
|
||||
@@ -1127,10 +1183,45 @@ static void on_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
break;
|
||||
}
|
||||
|
||||
case MenuID::PROXY_OPTIONS: {
|
||||
switch (item_id) {
|
||||
case ProxyOptionsMenuItemID::GO_BACK:
|
||||
send_menu(c, u"Proxy server", MenuID::PROXY_DESTINATIONS,
|
||||
s->proxy_destinations_menu_for_version(c->version()));
|
||||
break;
|
||||
case ProxyOptionsMenuItemID::INFINITE_HP:
|
||||
c->infinite_hp = !c->infinite_hp;
|
||||
goto resend_proxy_options_menu;
|
||||
case ProxyOptionsMenuItemID::INFINITE_TP:
|
||||
c->infinite_tp = !c->infinite_tp;
|
||||
goto resend_proxy_options_menu;
|
||||
case ProxyOptionsMenuItemID::SWITCH_ASSIST:
|
||||
c->switch_assist = !c->switch_assist;
|
||||
goto resend_proxy_options_menu;
|
||||
case ProxyOptionsMenuItemID::SAVE_FILES:
|
||||
c->proxy_save_files = !c->proxy_save_files;
|
||||
goto resend_proxy_options_menu;
|
||||
case ProxyOptionsMenuItemID::SUPPRESS_LOGIN:
|
||||
c->proxy_suppress_remote_login = !c->proxy_suppress_remote_login;
|
||||
resend_proxy_options_menu:
|
||||
send_menu(c, s->name.c_str(), MenuID::PROXY_OPTIONS,
|
||||
proxy_options_menu_for_client(c));
|
||||
break;
|
||||
default:
|
||||
send_message_box(c, u"Incorrect menu item ID.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MenuID::PROXY_DESTINATIONS: {
|
||||
if (item_id == ProxyDestinationsMenuItemID::GO_BACK) {
|
||||
send_menu(c, s->name.c_str(), MenuID::MAIN, s->main_menu);
|
||||
|
||||
} else if (item_id == ProxyDestinationsMenuItemID::OPTIONS) {
|
||||
send_menu(c, s->name.c_str(), MenuID::PROXY_OPTIONS,
|
||||
proxy_options_menu_for_client(c));
|
||||
|
||||
} else {
|
||||
const pair<string, uint16_t>* dest = nullptr;
|
||||
try {
|
||||
@@ -1156,8 +1247,18 @@ static void on_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
send_update_client_config(c);
|
||||
|
||||
s->proxy_server->delete_session(c->license->serial_number);
|
||||
s->proxy_server->create_licensed_session(
|
||||
auto session = s->proxy_server->create_licensed_session(
|
||||
c->license, local_port, c->version(), c->export_config_bb());
|
||||
session->infinite_hp = c->infinite_hp;
|
||||
session->infinite_tp = c->infinite_tp;
|
||||
session->switch_assist = c->switch_assist;
|
||||
session->save_files = c->proxy_save_files;
|
||||
session->suppress_remote_login = c->proxy_suppress_remote_login;
|
||||
try {
|
||||
string key = string_printf("proxy_remote_guild_card_number:%" PRIX32, c->license->serial_number);
|
||||
const auto& entry = client_options_cache.get_or_throw(key);
|
||||
session->remote_guild_card_number = stoul(entry->data, nullptr, 10);
|
||||
} catch (const out_of_range&) { }
|
||||
|
||||
send_reconnect(c, s->connect_address_for_client(c), local_port);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,6 @@ using namespace std;
|
||||
|
||||
|
||||
|
||||
extern bool use_terminal_colors;
|
||||
extern FileContentsCache file_cache;
|
||||
|
||||
|
||||
|
||||
const unordered_set<uint32_t> v2_crypt_initial_client_commands({
|
||||
0x00260088, // (17) DCNTE license check
|
||||
0x00280090, // (17) DCv1 license check
|
||||
|
||||
@@ -344,6 +344,8 @@ void ServerState::create_menus(shared_ptr<const JSONObject> config_json) {
|
||||
|
||||
ret_menu.emplace_back(ProxyDestinationsMenuItemID::GO_BACK, u"Go back",
|
||||
u"Return to the\nmain menu", 0);
|
||||
ret_menu.emplace_back(ProxyDestinationsMenuItemID::OPTIONS, u"Options",
|
||||
u"Set proxy options", 0);
|
||||
|
||||
uint32_t item_id = 0;
|
||||
for (const auto& item : items->as_dict()) {
|
||||
|
||||
@@ -100,6 +100,7 @@ struct ServerState {
|
||||
|
||||
std::shared_ptr<ProxyServer> proxy_server;
|
||||
std::shared_ptr<Server> game_server;
|
||||
std::shared_ptr<FileContentsCache> client_options_cache;
|
||||
|
||||
ServerState();
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "FileContentsCache.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user