move patch servers to separate threads
This commit is contained in:
@@ -103,6 +103,7 @@ set(SOURCES
|
||||
src/Map.cc
|
||||
src/Menu.cc
|
||||
src/NetworkAddresses.cc
|
||||
src/PatchServer.cc
|
||||
src/PatchFileIndex.cc
|
||||
src/PlayerFilesManager.cc
|
||||
src/PlayerSubordinates.cc
|
||||
|
||||
@@ -186,9 +186,6 @@ public:
|
||||
uint8_t bb_connection_phase;
|
||||
uint64_t ping_start_time;
|
||||
|
||||
// Patch server
|
||||
std::vector<PatchFileChecksumRequest> patch_file_checksum_requests;
|
||||
|
||||
// Lobby/positioning
|
||||
Config config;
|
||||
Config synced_config;
|
||||
|
||||
+33
-1
@@ -33,6 +33,7 @@
|
||||
#include "NetworkAddresses.hh"
|
||||
#include "PSOGCObjectGraph.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "PatchServer.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "Quest.hh"
|
||||
#include "QuestScript.hh"
|
||||
@@ -2411,12 +2412,29 @@ Action a_run_server_replay_log(
|
||||
state->proxy_server->listen(pc->addr, pc->port, pc->version);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (pc->behavior == ServerBehavior::PATCH_SERVER_PC) {
|
||||
if (!state->pc_patch_server.get()) {
|
||||
config_log.info("Starting PC_V2 patch server");
|
||||
state->pc_patch_server = make_shared<PatchServer>(state->generate_patch_server_config(false));
|
||||
}
|
||||
string spec = string_printf("TU-%hu-%s-patch2", pc->port, pc->name.c_str());
|
||||
state->pc_patch_server->listen(spec, pc->addr, pc->port, Version::PC_PATCH);
|
||||
|
||||
} else if (pc->behavior == ServerBehavior::PATCH_SERVER_BB) {
|
||||
if (!state->bb_patch_server.get()) {
|
||||
config_log.info("Starting BB_V4 patch server");
|
||||
state->bb_patch_server = make_shared<PatchServer>(state->generate_patch_server_config(true));
|
||||
}
|
||||
string spec = string_printf("TU-%hu-%s-patch4", pc->port, pc->name.c_str());
|
||||
state->bb_patch_server->listen(spec, pc->addr, pc->port, Version::BB_PATCH);
|
||||
|
||||
} else {
|
||||
if (!state->game_server.get()) {
|
||||
config_log.info("Starting game server");
|
||||
state->game_server = make_shared<Server>(base, state);
|
||||
}
|
||||
string spec = string_printf("T-%hu-%s-%s-%s", pc->port, name_for_enum(pc->version), pc->name.c_str(), name_for_enum(pc->behavior));
|
||||
string spec = string_printf("TG-%hu-%s-%s-%s", pc->port, name_for_enum(pc->version), pc->name.c_str(), name_for_enum(pc->behavior));
|
||||
state->game_server->listen(spec, pc->addr, pc->port, pc->version, pc->behavior);
|
||||
}
|
||||
}
|
||||
@@ -2470,6 +2488,20 @@ Action a_run_server_replay_log(
|
||||
}
|
||||
|
||||
config_log.info("Normal shutdown");
|
||||
if (state->pc_patch_server) {
|
||||
state->pc_patch_server->schedule_stop();
|
||||
}
|
||||
if (state->bb_patch_server) {
|
||||
state->bb_patch_server->schedule_stop();
|
||||
}
|
||||
if (state->pc_patch_server) {
|
||||
config_log.info("Waiting for PC_V2 patch server to stop");
|
||||
state->pc_patch_server->wait_for_stop();
|
||||
}
|
||||
if (state->bb_patch_server) {
|
||||
config_log.info("Waiting for BB_V4 patch server to stop");
|
||||
state->bb_patch_server->wait_for_stop();
|
||||
}
|
||||
state->proxy_server.reset(); // Break reference cycle
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,453 @@
|
||||
#include "PatchServer.hh"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Network.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "EventUtils.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "ReceiveCommands.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static atomic<uint64_t> next_id(1);
|
||||
|
||||
PatchServer::Client::Client(
|
||||
shared_ptr<PatchServer> server,
|
||||
struct bufferevent* bev,
|
||||
Version version,
|
||||
uint64_t idle_timeout_usecs,
|
||||
bool hide_data_from_logs)
|
||||
: server(server),
|
||||
id(next_id++),
|
||||
log(string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level),
|
||||
channel(bev, version, 1, nullptr, nullptr, this, string_printf("C-%" PRIX64, this->id), TerminalFormat::FG_YELLOW, TerminalFormat::FG_GREEN),
|
||||
idle_timeout_usecs(idle_timeout_usecs),
|
||||
idle_timeout_event(
|
||||
event_new(bufferevent_get_base(bev), -1, EV_TIMEOUT, &PatchServer::Client::dispatch_idle_timeout, this),
|
||||
event_free) {
|
||||
this->reschedule_timeout_event();
|
||||
|
||||
// Don't print data sent to patch clients to the logs. The patch server
|
||||
// protocol is fully understood and data logs for patch clients are generally
|
||||
// more annoying than helpful at this point.
|
||||
if (hide_data_from_logs) {
|
||||
this->channel.terminal_recv_color = TerminalFormat::END;
|
||||
this->channel.terminal_send_color = TerminalFormat::END;
|
||||
}
|
||||
|
||||
this->log.info("Created");
|
||||
}
|
||||
|
||||
void PatchServer::Client::reschedule_timeout_event() {
|
||||
struct timeval idle_tv = usecs_to_timeval(this->idle_timeout_usecs);
|
||||
event_add(this->idle_timeout_event.get(), &idle_tv);
|
||||
}
|
||||
|
||||
void PatchServer::Client::dispatch_idle_timeout(evutil_socket_t, short, void* ctx) {
|
||||
reinterpret_cast<Client*>(ctx)->idle_timeout();
|
||||
}
|
||||
|
||||
void PatchServer::Client::idle_timeout() {
|
||||
this->log.info("Idle timeout expired");
|
||||
auto s = this->server.lock();
|
||||
if (s) {
|
||||
auto c = this->shared_from_this();
|
||||
s->disconnect_client(c);
|
||||
} else {
|
||||
this->channel.disconnect();
|
||||
this->log.info("Server is deleted; cannot disconnect client");
|
||||
}
|
||||
}
|
||||
|
||||
void PatchServer::send_server_init(shared_ptr<Client> c) const {
|
||||
uint32_t server_key = random_object<uint32_t>();
|
||||
uint32_t client_key = random_object<uint32_t>();
|
||||
|
||||
S_ServerInit_Patch_02 cmd;
|
||||
cmd.copyright.encode("Patch Server. Copyright SonicTeam, LTD. 2001");
|
||||
cmd.server_key = server_key;
|
||||
cmd.client_key = client_key;
|
||||
c->channel.send(0x02, 0x00, cmd);
|
||||
|
||||
c->channel.crypt_out = make_shared<PSOV2Encryption>(server_key);
|
||||
c->channel.crypt_in = make_shared<PSOV2Encryption>(client_key);
|
||||
}
|
||||
|
||||
void PatchServer::send_message_box(shared_ptr<Client> c, const string& text) const {
|
||||
StringWriter w;
|
||||
try {
|
||||
if (c->version() == Version::PC_PATCH) {
|
||||
w.write(tt_encode_marked_optional(text, c->channel.language, true));
|
||||
} else if (c->version() == Version::BB_PATCH) {
|
||||
w.write(tt_encode_marked_optional(add_color(text), c->channel.language, true));
|
||||
} else {
|
||||
throw logic_error("non-patch client on patch server");
|
||||
}
|
||||
} catch (const runtime_error& e) {
|
||||
log_warning("Failed to encode message for patch message box command: %s", e.what());
|
||||
return;
|
||||
}
|
||||
w.put_u16(0);
|
||||
while (w.str().size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
c->channel.send(0x13, 0x00, w.str());
|
||||
}
|
||||
|
||||
void PatchServer::send_enter_directory(shared_ptr<Client> c, const string& dir) const {
|
||||
S_EnterDirectory_Patch_09 cmd = {{dir, 1}};
|
||||
c->channel.send(0x09, 0x00, cmd);
|
||||
}
|
||||
|
||||
void PatchServer::on_02(shared_ptr<Client> c, string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
c->channel.send(0x04, 0x00); // This requests the user's login information
|
||||
}
|
||||
|
||||
void PatchServer::change_to_directory(
|
||||
shared_ptr<Client> c,
|
||||
vector<string>& client_path_directories,
|
||||
const vector<string>& file_path_directories) const {
|
||||
// First, exit all leaf directories that don't match the desired path
|
||||
while (!client_path_directories.empty() &&
|
||||
((client_path_directories.size() > file_path_directories.size()) ||
|
||||
(client_path_directories.back() != file_path_directories[client_path_directories.size() - 1]))) {
|
||||
c->channel.send(0x0A, 0x00);
|
||||
client_path_directories.pop_back();
|
||||
}
|
||||
|
||||
// At this point, client_path_directories should be a prefix of
|
||||
// file_path_directories (or should match exactly)
|
||||
if (client_path_directories.size() > file_path_directories.size()) {
|
||||
throw logic_error("did not exit all necessary directories");
|
||||
}
|
||||
for (size_t x = 0; x < client_path_directories.size(); x++) {
|
||||
if (client_path_directories[x] != file_path_directories[x]) {
|
||||
throw logic_error("intermediate path is not a prefix of final path");
|
||||
}
|
||||
}
|
||||
|
||||
// Second, enter all necessary leaf directories
|
||||
while (client_path_directories.size() < file_path_directories.size()) {
|
||||
const string& dir = file_path_directories[client_path_directories.size()];
|
||||
this->send_enter_directory(c, dir);
|
||||
client_path_directories.emplace_back(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void PatchServer::on_04(shared_ptr<Client> c, string& data) {
|
||||
const auto& cmd = check_size_t<C_Login_Patch_04>(data);
|
||||
|
||||
string username = cmd.username.decode();
|
||||
string password = cmd.password.decode();
|
||||
|
||||
// There are 3 cases here:
|
||||
// - No login information at all: just proceed without checking license
|
||||
// - Username only: check that license exists if allow_unregistered_users is off
|
||||
// - Username and password: call verify_bb
|
||||
if (!username.empty() && !password.empty()) {
|
||||
try {
|
||||
this->config->license_index->verify_bb(username, password);
|
||||
|
||||
} catch (const LicenseIndex::incorrect_password& e) {
|
||||
this->send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
this->disconnect_client(c);
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::missing_license& e) {
|
||||
if (!this->config->allow_unregistered_users) {
|
||||
this->send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
this->disconnect_client(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!username.empty() && !this->config->allow_unregistered_users) {
|
||||
try {
|
||||
this->config->license_index->get_by_bb_username(username);
|
||||
} catch (const LicenseIndex::missing_license& e) {
|
||||
this->send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
this->disconnect_client(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->config->message.empty()) {
|
||||
this->send_message_box(c, this->config->message.c_str());
|
||||
}
|
||||
|
||||
const auto& index = this->config->patch_file_index;
|
||||
if (index.get()) {
|
||||
c->channel.send(0x0B, 0x00); // Start patch session; go to root directory
|
||||
|
||||
vector<string> path_directories;
|
||||
for (const auto& file : index->all_files()) {
|
||||
this->change_to_directory(c, path_directories, file->path_directories);
|
||||
|
||||
S_FileChecksumRequest_Patch_0C req = {c->patch_file_checksum_requests.size(), {file->name, 1}};
|
||||
c->channel.send(0x0C, 0x00, req);
|
||||
c->patch_file_checksum_requests.emplace_back(file);
|
||||
}
|
||||
this->change_to_directory(c, path_directories, {});
|
||||
|
||||
c->channel.send(0x0D, 0x00); // End of checksum requests
|
||||
|
||||
} else {
|
||||
// No patch index present: just do something that will satisfy the client
|
||||
// without actually checking or downloading any files
|
||||
this->send_enter_directory(c, ".");
|
||||
this->send_enter_directory(c, "data");
|
||||
this->send_enter_directory(c, "scene");
|
||||
c->channel.send(0x0A, 0x00);
|
||||
c->channel.send(0x0A, 0x00);
|
||||
c->channel.send(0x0A, 0x00);
|
||||
c->channel.send(0x12, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void PatchServer::on_0F(shared_ptr<Client> c, string& data) {
|
||||
auto& cmd = check_size_t<C_FileInformation_Patch_0F>(data);
|
||||
auto& req = c->patch_file_checksum_requests.at(cmd.request_id);
|
||||
req.crc32 = cmd.checksum;
|
||||
req.size = cmd.size;
|
||||
req.response_received = true;
|
||||
}
|
||||
|
||||
void PatchServer::on_10(shared_ptr<Client> c, string&) {
|
||||
S_StartFileDownloads_Patch_11 start_cmd = {0, 0};
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (!req.response_received) {
|
||||
throw runtime_error("client did not respond to checksum request");
|
||||
}
|
||||
if (req.needs_update()) {
|
||||
c->log.info("File %s needs update (CRC: %08" PRIX32 "/%08" PRIX32 ", size: %" PRIu32 "/%" PRIu32 ")",
|
||||
req.file->name.c_str(), req.file->crc32, req.crc32, req.file->size, req.size);
|
||||
start_cmd.total_bytes += req.file->size;
|
||||
start_cmd.num_files++;
|
||||
} else {
|
||||
c->log.info("File %s is up to date", req.file->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (start_cmd.num_files) {
|
||||
c->channel.send(0x11, 0x00, start_cmd);
|
||||
vector<string> path_directories;
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (req.needs_update()) {
|
||||
this->change_to_directory(c, path_directories, req.file->path_directories);
|
||||
|
||||
S_OpenFile_Patch_06 open_cmd = {0, req.file->size, {req.file->name, 1}};
|
||||
c->channel.send(0x06, 0x00, open_cmd);
|
||||
|
||||
for (size_t x = 0; x < req.file->chunk_crcs.size(); x++) {
|
||||
auto data = req.file->load_data();
|
||||
size_t chunk_size = min<uint32_t>(req.file->size - (x * 0x4000), 0x4000);
|
||||
|
||||
vector<pair<const void*, size_t>> blocks;
|
||||
S_WriteFileHeader_Patch_07 cmd_header = {x, req.file->chunk_crcs[x], chunk_size};
|
||||
blocks.emplace_back(&cmd_header, sizeof(cmd_header));
|
||||
blocks.emplace_back(data->data() + (x * 0x4000), chunk_size);
|
||||
c->channel.send(0x07, 0x00, blocks);
|
||||
}
|
||||
|
||||
S_CloseCurrentFile_Patch_08 close_cmd = {0};
|
||||
c->channel.send(0x08, 0x00, close_cmd);
|
||||
}
|
||||
}
|
||||
this->change_to_directory(c, path_directories, {});
|
||||
}
|
||||
|
||||
c->channel.send(0x12, 0x00);
|
||||
}
|
||||
|
||||
void PatchServer::disconnect_client(shared_ptr<Client> c) {
|
||||
if (c->channel.is_virtual_connection) {
|
||||
server_log.info("Client disconnected: C-%" PRIX64 " on virtual connection %p", c->id, c->channel.bev.get());
|
||||
} else if (c->channel.bev) {
|
||||
server_log.info("Client disconnected: C-%" PRIX64 " on fd %d", c->id, bufferevent_getfd(c->channel.bev.get()));
|
||||
} else {
|
||||
server_log.info("Client C-%" PRIX64 " removed from game server", c->id);
|
||||
}
|
||||
|
||||
this->channel_to_client.erase(&c->channel);
|
||||
c->channel.disconnect();
|
||||
|
||||
// We can't just let c be destroyed here, since disconnect_client can be
|
||||
// called from within the client's channel's receive handler. So, we instead
|
||||
// move it to another set, which we'll clear in an immediately-enqueued
|
||||
// callback after the current event. This will also call the client's
|
||||
// disconnect hooks (if any).
|
||||
this->clients_to_destroy.insert(std::move(c));
|
||||
this->enqueue_destroy_clients();
|
||||
}
|
||||
|
||||
void PatchServer::enqueue_destroy_clients() {
|
||||
auto tv = usecs_to_timeval(0);
|
||||
event_add(this->destroy_clients_ev.get(), &tv);
|
||||
}
|
||||
|
||||
void PatchServer::dispatch_destroy_clients(evutil_socket_t, short, void* ctx) {
|
||||
reinterpret_cast<PatchServer*>(ctx)->clients_to_destroy.clear();
|
||||
}
|
||||
|
||||
void PatchServer::dispatch_on_listen_accept(
|
||||
struct evconnlistener* listener, evutil_socket_t fd,
|
||||
struct sockaddr* address, int socklen, void* ctx) {
|
||||
reinterpret_cast<PatchServer*>(ctx)->on_listen_accept(listener, fd, address, socklen);
|
||||
}
|
||||
|
||||
void PatchServer::dispatch_on_listen_error(
|
||||
struct evconnlistener* listener, void* ctx) {
|
||||
reinterpret_cast<PatchServer*>(ctx)->on_listen_error(listener);
|
||||
}
|
||||
|
||||
void PatchServer::on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr*, int) {
|
||||
int listen_fd = evconnlistener_get_fd(listener);
|
||||
ListeningSocket* listening_socket;
|
||||
try {
|
||||
listening_socket = &this->listening_sockets.at(listen_fd);
|
||||
} catch (const out_of_range& e) {
|
||||
server_log.warning("Can\'t determine version for socket %d; disconnecting client", listen_fd);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
struct bufferevent* bev = bufferevent_socket_new(this->base.get(), fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||
auto c = make_shared<Client>(
|
||||
this->shared_from_this(),
|
||||
bev,
|
||||
listening_socket->version,
|
||||
this->config->idle_timeout_usecs,
|
||||
this->config->hide_data_from_logs);
|
||||
c->channel.on_command_received = PatchServer::on_client_input;
|
||||
c->channel.on_error = PatchServer::on_client_error;
|
||||
c->channel.context_obj = this;
|
||||
this->channel_to_client.emplace(&c->channel, c);
|
||||
|
||||
server_log.info("Patch client connected: U-%" PRIX64 " on fd %d via %d (%s)",
|
||||
c->id, fd, listen_fd, listening_socket->addr_str.c_str());
|
||||
|
||||
this->send_server_init(c);
|
||||
}
|
||||
|
||||
void PatchServer::on_listen_error(struct evconnlistener* listener) {
|
||||
int err = EVUTIL_SOCKET_ERROR();
|
||||
server_log.error("Failure on listening socket %d: %d (%s)",
|
||||
evconnlistener_get_fd(listener), err, evutil_socket_error_to_string(err));
|
||||
event_base_loopexit(this->base.get(), nullptr);
|
||||
}
|
||||
|
||||
void PatchServer::on_client_input(Channel& ch, uint16_t command, uint32_t, std::string& data) {
|
||||
PatchServer* server = reinterpret_cast<PatchServer*>(ch.context_obj);
|
||||
shared_ptr<Client> c = server->channel_to_client.at(&ch);
|
||||
|
||||
try {
|
||||
switch (command) {
|
||||
case 0x02:
|
||||
server->on_02(c, data);
|
||||
break;
|
||||
case 0x04:
|
||||
server->on_04(c, data);
|
||||
break;
|
||||
case 0x0F:
|
||||
server->on_0F(c, data);
|
||||
break;
|
||||
case 0x10:
|
||||
server->on_10(c, data);
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("invalid command");
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
server_log.warning("Error processing client command: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void PatchServer::on_client_error(Channel& ch, short events) {
|
||||
PatchServer* server = reinterpret_cast<PatchServer*>(ch.context_obj);
|
||||
shared_ptr<Client> c = server->channel_to_client.at(&ch);
|
||||
|
||||
if (events & BEV_EVENT_ERROR) {
|
||||
int err = EVUTIL_SOCKET_ERROR();
|
||||
server_log.warning("Client caused error %d (%s)", err, evutil_socket_error_to_string(err));
|
||||
}
|
||||
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
|
||||
server->disconnect_client(c);
|
||||
}
|
||||
}
|
||||
|
||||
PatchServer::PatchServer(shared_ptr<const Config> config)
|
||||
: base(event_base_new(), event_base_free),
|
||||
config(config),
|
||||
destroy_clients_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &PatchServer::dispatch_destroy_clients, this), event_free),
|
||||
th(&PatchServer::thread_fn, this) {}
|
||||
|
||||
void PatchServer::schedule_stop() {
|
||||
event_base_loopexit(this->base.get(), nullptr);
|
||||
}
|
||||
|
||||
void PatchServer::wait_for_stop() {
|
||||
this->th.join();
|
||||
}
|
||||
|
||||
void PatchServer::listen(const std::string& addr_str, const string& socket_path, Version version) {
|
||||
int fd = ::listen(socket_path, 0, SOMAXCONN);
|
||||
server_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, addr_str.c_str());
|
||||
this->add_socket(addr_str, fd, version);
|
||||
}
|
||||
|
||||
void PatchServer::listen(const std::string& addr_str, const string& addr, int port, Version version) {
|
||||
if (port == 0) {
|
||||
this->listen(addr_str, addr, version);
|
||||
} else {
|
||||
int fd = ::listen(addr, port, SOMAXCONN);
|
||||
string netloc_str = render_netloc(addr, port);
|
||||
server_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, addr_str.c_str());
|
||||
this->add_socket(addr_str, fd, version);
|
||||
}
|
||||
}
|
||||
|
||||
void PatchServer::listen(const std::string& addr_str, int port, Version version) {
|
||||
this->listen(addr_str, "", port, version);
|
||||
}
|
||||
|
||||
PatchServer::ListeningSocket::ListeningSocket(PatchServer* s, const std::string& addr_str, int fd, Version version)
|
||||
: addr_str(addr_str),
|
||||
fd(fd),
|
||||
version(version),
|
||||
listener(evconnlistener_new(s->base.get(), PatchServer::dispatch_on_listen_accept, s, LEV_OPT_REUSEABLE, 0, this->fd),
|
||||
evconnlistener_free) {
|
||||
evconnlistener_set_error_cb(this->listener.get(), PatchServer::dispatch_on_listen_error);
|
||||
}
|
||||
|
||||
void PatchServer::add_socket(const std::string& addr_str, int fd, Version version) {
|
||||
this->listening_sockets.emplace(piecewise_construct, forward_as_tuple(fd), forward_as_tuple(this, addr_str, fd, version));
|
||||
}
|
||||
|
||||
void PatchServer::thread_fn() {
|
||||
event_base_loop(this->base.get(), EVLOOP_NO_EXIT_ON_EMPTY);
|
||||
}
|
||||
|
||||
void PatchServer::set_config(std::shared_ptr<const Config> config) {
|
||||
forward_to_event_thread(this->base, [s = this->shared_from_this(), config = std::move(config)]() {
|
||||
s->config = config;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Channel.hh"
|
||||
#include "License.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
class PatchServer : public std::enable_shared_from_this<PatchServer> {
|
||||
public:
|
||||
struct Config {
|
||||
bool allow_unregistered_users;
|
||||
bool hide_data_from_logs;
|
||||
uint64_t idle_timeout_usecs;
|
||||
std::string message;
|
||||
std::shared_ptr<const LicenseIndex> license_index;
|
||||
std::shared_ptr<const PatchFileIndex> patch_file_index;
|
||||
};
|
||||
|
||||
PatchServer() = delete;
|
||||
explicit PatchServer(std::shared_ptr<const Config> config);
|
||||
PatchServer(const PatchServer&) = delete;
|
||||
PatchServer(PatchServer&&) = delete;
|
||||
PatchServer& operator=(const PatchServer&) = delete;
|
||||
PatchServer& operator=(PatchServer&&) = delete;
|
||||
virtual ~PatchServer() = default;
|
||||
|
||||
void schedule_stop();
|
||||
void wait_for_stop();
|
||||
|
||||
void listen(const std::string& addr_str, const std::string& socket_path, Version version);
|
||||
void listen(const std::string& addr_str, const std::string& addr, int port, Version version);
|
||||
void listen(const std::string& addr_str, int port, Version version);
|
||||
void add_socket(const std::string& addr_str, int fd, Version version);
|
||||
|
||||
void set_config(std::shared_ptr<const Config> config);
|
||||
|
||||
private:
|
||||
class Client : public std::enable_shared_from_this<Client> {
|
||||
public:
|
||||
std::weak_ptr<PatchServer> server;
|
||||
uint64_t id;
|
||||
PrefixedLogger log;
|
||||
|
||||
Channel channel;
|
||||
std::vector<PatchFileChecksumRequest> patch_file_checksum_requests;
|
||||
uint64_t idle_timeout_usecs;
|
||||
|
||||
std::unique_ptr<struct event, void (*)(struct event*)> idle_timeout_event;
|
||||
|
||||
Client(
|
||||
std::shared_ptr<PatchServer> server,
|
||||
struct bufferevent* bev,
|
||||
Version version,
|
||||
uint64_t idle_timeout_usecs,
|
||||
bool hide_data_from_logs);
|
||||
~Client() = default;
|
||||
|
||||
void reschedule_timeout_event();
|
||||
|
||||
inline Version version() const {
|
||||
return this->channel.version;
|
||||
}
|
||||
|
||||
static void dispatch_idle_timeout(evutil_socket_t, short, void* ctx);
|
||||
void idle_timeout();
|
||||
|
||||
const std::string& get_bb_username() const;
|
||||
void set_bb_username(const std::string& bb_username);
|
||||
};
|
||||
|
||||
struct ListeningSocket {
|
||||
std::string addr_str;
|
||||
int fd;
|
||||
Version version;
|
||||
std::unique_ptr<struct evconnlistener, void (*)(struct evconnlistener*)> listener;
|
||||
|
||||
ListeningSocket(PatchServer* s, const std::string& name, int fd, Version version);
|
||||
};
|
||||
|
||||
std::shared_ptr<struct event_base> base;
|
||||
std::shared_ptr<const Config> config;
|
||||
|
||||
std::unordered_set<std::shared_ptr<Client>> clients_to_destroy;
|
||||
std::shared_ptr<struct event> destroy_clients_ev;
|
||||
|
||||
std::unordered_map<int, ListeningSocket> listening_sockets;
|
||||
std::unordered_map<Channel*, std::shared_ptr<Client>> channel_to_client;
|
||||
|
||||
std::thread th;
|
||||
|
||||
void send_server_init(std::shared_ptr<Client> c) const;
|
||||
void send_message_box(std::shared_ptr<Client> c, const std::string& text) const;
|
||||
void send_enter_directory(std::shared_ptr<Client> c, const std::string& dir) const;
|
||||
void change_to_directory(
|
||||
std::shared_ptr<Client> c,
|
||||
std::vector<std::string>& client_path_directories,
|
||||
const std::vector<std::string>& file_path_directories) const;
|
||||
void on_02(std::shared_ptr<Client> c, std::string& data);
|
||||
void on_04(std::shared_ptr<Client> c, std::string& data);
|
||||
void on_0F(std::shared_ptr<Client> c, std::string& data);
|
||||
void on_10(std::shared_ptr<Client> c, std::string& data);
|
||||
|
||||
void disconnect_client(std::shared_ptr<Client> c);
|
||||
|
||||
void enqueue_destroy_clients();
|
||||
static void dispatch_destroy_clients(evutil_socket_t, short, void* ctx);
|
||||
|
||||
static void dispatch_on_listen_accept(struct evconnlistener* listener,
|
||||
evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx);
|
||||
static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx);
|
||||
|
||||
void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen);
|
||||
void on_listen_error(struct evconnlistener* listener);
|
||||
|
||||
static void on_client_input(Channel& ch, uint16_t command, uint32_t flag, std::string& data);
|
||||
static void on_client_error(Channel& ch, short events);
|
||||
|
||||
void thread_fn();
|
||||
};
|
||||
+277
-464
@@ -5097,181 +5097,6 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
|
||||
}
|
||||
}
|
||||
|
||||
static void on_02_P(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
send_command(c, 0x04, 0x00); // This requests the user's login information
|
||||
}
|
||||
|
||||
static void change_to_directory_patch(
|
||||
shared_ptr<Client> c,
|
||||
vector<string>& client_path_directories,
|
||||
const vector<string>& file_path_directories) {
|
||||
// First, exit all leaf directories that don't match the desired path
|
||||
while (!client_path_directories.empty() &&
|
||||
((client_path_directories.size() > file_path_directories.size()) ||
|
||||
(client_path_directories.back() != file_path_directories[client_path_directories.size() - 1]))) {
|
||||
send_command(c, 0x0A, 0x00);
|
||||
client_path_directories.pop_back();
|
||||
}
|
||||
|
||||
// At this point, client_path_directories should be a prefix of
|
||||
// file_path_directories (or should match exactly)
|
||||
if (client_path_directories.size() > file_path_directories.size()) {
|
||||
throw logic_error("did not exit all necessary directories");
|
||||
}
|
||||
for (size_t x = 0; x < client_path_directories.size(); x++) {
|
||||
if (client_path_directories[x] != file_path_directories[x]) {
|
||||
throw logic_error("intermediate path is not a prefix of final path");
|
||||
}
|
||||
}
|
||||
|
||||
// Second, enter all necessary leaf directories
|
||||
while (client_path_directories.size() < file_path_directories.size()) {
|
||||
const string& dir = file_path_directories[client_path_directories.size()];
|
||||
send_enter_directory_patch(c, dir);
|
||||
client_path_directories.emplace_back(dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_04_P(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
const auto& cmd = check_size_t<C_Login_Patch_04>(data);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
string username = cmd.username.decode();
|
||||
string password = cmd.password.decode();
|
||||
|
||||
// There are 3 cases here:
|
||||
// - No login information at all: just proceed without checking license
|
||||
// - Username only: check that license exists if allow_unregistered_users is off
|
||||
// - Username and password: call verify_bb
|
||||
if (!username.empty() && !password.empty()) {
|
||||
try {
|
||||
auto l = s->license_index->verify_bb(username, password);
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::incorrect_password& e) {
|
||||
send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
|
||||
} catch (const LicenseIndex::missing_license& e) {
|
||||
if (!s->allow_unregistered_users) {
|
||||
send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
} else {
|
||||
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
|
||||
auto l = s->license_index->create_license();
|
||||
l->serial_number = fnv1a32(cmd.username.decode()) & 0x7FFFFFFF;
|
||||
l->bb_username = cmd.username.decode();
|
||||
l->bb_password = cmd.password.decode();
|
||||
s->license_index->add(l);
|
||||
if (!s->is_replay) {
|
||||
l->save();
|
||||
}
|
||||
c->set_license(l);
|
||||
string l_str = l->str();
|
||||
c->log.info("Created license %s", l_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!username.empty() && !s->allow_unregistered_users) {
|
||||
try {
|
||||
auto l = s->license_index->get_by_bb_username(username);
|
||||
c->set_license(l);
|
||||
} catch (const LicenseIndex::missing_license& e) {
|
||||
send_message_box(c, string_printf("Login failed: %s", e.what()));
|
||||
c->should_disconnect = true;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
auto l = s->license_index->create_temporary_license();
|
||||
l->serial_number = random_object<uint32_t>() & 0x7FFFFFFF;
|
||||
l->bb_username = "__unknown__";
|
||||
l->bb_password = "__unknown__";
|
||||
c->set_license(l);
|
||||
}
|
||||
|
||||
// On BB we can use colors and newlines should be \n; on PC we can't use
|
||||
// colors, the text is auto-word-wrapped, and newlines should be \r\n.
|
||||
bool is_bb_patch = (c->version() == Version::BB_PATCH);
|
||||
const string& message = is_bb_patch
|
||||
? s->bb_patch_server_message
|
||||
: s->pc_patch_server_message;
|
||||
if (!message.empty()) {
|
||||
send_message_box(c, message.c_str());
|
||||
}
|
||||
|
||||
auto index = is_bb_patch ? s->bb_patch_file_index : s->pc_patch_file_index;
|
||||
if (index.get()) {
|
||||
send_command(c, 0x0B, 0x00); // Start patch session; go to root directory
|
||||
|
||||
vector<string> path_directories;
|
||||
for (const auto& file : index->all_files()) {
|
||||
change_to_directory_patch(c, path_directories, file->path_directories);
|
||||
|
||||
S_FileChecksumRequest_Patch_0C req = {c->patch_file_checksum_requests.size(), {file->name, 1}};
|
||||
send_command_t(c, 0x0C, 0x00, req);
|
||||
c->patch_file_checksum_requests.emplace_back(file);
|
||||
}
|
||||
change_to_directory_patch(c, path_directories, {});
|
||||
|
||||
send_command(c, 0x0D, 0x00); // End of checksum requests
|
||||
|
||||
} else {
|
||||
// No patch index present: just do something that will satisfy the client
|
||||
// without actually checking or downloading any files
|
||||
send_enter_directory_patch(c, ".");
|
||||
send_enter_directory_patch(c, "data");
|
||||
send_enter_directory_patch(c, "scene");
|
||||
send_command(c, 0x0A, 0x00);
|
||||
send_command(c, 0x0A, 0x00);
|
||||
send_command(c, 0x0A, 0x00);
|
||||
send_command(c, 0x12, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_0F_P(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
auto& cmd = check_size_t<C_FileInformation_Patch_0F>(data);
|
||||
auto& req = c->patch_file_checksum_requests.at(cmd.request_id);
|
||||
req.crc32 = cmd.checksum;
|
||||
req.size = cmd.size;
|
||||
req.response_received = true;
|
||||
}
|
||||
|
||||
static void on_10_P(shared_ptr<Client> c, uint16_t, uint32_t, string&) {
|
||||
|
||||
S_StartFileDownloads_Patch_11 start_cmd = {0, 0};
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (!req.response_received) {
|
||||
throw runtime_error("client did not respond to checksum request");
|
||||
}
|
||||
if (req.needs_update()) {
|
||||
c->log.info("File %s needs update (CRC: %08" PRIX32 "/%08" PRIX32 ", size: %" PRIu32 "/%" PRIu32 ")",
|
||||
req.file->name.c_str(), req.file->crc32, req.crc32, req.file->size, req.size);
|
||||
start_cmd.total_bytes += req.file->size;
|
||||
start_cmd.num_files++;
|
||||
} else {
|
||||
c->log.info("File %s is up to date", req.file->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (start_cmd.num_files) {
|
||||
send_command_t(c, 0x11, 0x00, start_cmd);
|
||||
vector<string> path_directories;
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (req.needs_update()) {
|
||||
change_to_directory_patch(c, path_directories, req.file->path_directories);
|
||||
send_patch_file(c, req.file);
|
||||
}
|
||||
}
|
||||
change_to_directory_patch(c, path_directories, {});
|
||||
}
|
||||
|
||||
send_command(c, 0x12, 0x00);
|
||||
}
|
||||
|
||||
static void on_ignored(shared_ptr<Client>, uint16_t, uint32_t, string&) {}
|
||||
|
||||
static void on_unimplemented_command(
|
||||
@@ -5286,293 +5111,287 @@ typedef void (*on_command_t)(shared_ptr<Client> c, uint16_t command, uint32_t fl
|
||||
// Command handler table, indexed by command number and game version. Null
|
||||
// entries in this table cause on_unimplemented_command to be called, which
|
||||
// disconnects the client.
|
||||
static_assert(NUM_VERSIONS == 14, "Don\'t forget to update the ReceiveCommands handler table");
|
||||
static on_command_t handlers[0x100][NUM_VERSIONS] = {
|
||||
static_assert(NUM_VERSIONS - 2 == 12, "Don\'t forget to update the ReceiveCommands handler table");
|
||||
static on_command_t handlers[0x100][NUM_VERSIONS - 2] = {
|
||||
// clang-format off
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_112000 DCV1 DCV2 PC_NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 00 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 01 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 02 */ {on_02_P, on_02_P, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 03 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 04 */ {on_04_P, on_04_P, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 05 */ {nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_05_XB, on_ignored},
|
||||
/* 06 */ {nullptr, nullptr, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06},
|
||||
/* 07 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 08 */ {nullptr, nullptr, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6},
|
||||
/* 09 */ {nullptr, nullptr, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09},
|
||||
/* 0A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0C */ {nullptr, nullptr, on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0F */ {on_0F_P, on_0F_P, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 10 */ {on_10_P, on_10_P, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10},
|
||||
/* 11 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 12 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 13 */ {nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB},
|
||||
/* 14 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 15 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 16 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 17 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 18 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 19 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1D */ {nullptr, nullptr, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D},
|
||||
/* 1E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1F */ {nullptr, nullptr, on_1F, on_1F, on_1F, on_1F, on_1F, on_1F, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 20 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 21 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 22 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored},
|
||||
/* 23 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 24 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 25 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 26 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 27 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 28 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 29 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 30 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 31 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 32 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 33 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 34 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 35 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 36 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 37 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 38 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 39 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 40 */ {nullptr, nullptr, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40},
|
||||
/* 41 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 42 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 43 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 44 */ {nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB},
|
||||
/* 45 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 46 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 47 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 48 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 49 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 50 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 51 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 52 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 53 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 54 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 55 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 56 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 57 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 58 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 59 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 60 */ {nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 61 */ {nullptr, nullptr, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98},
|
||||
/* 62 */ {nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 63 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 64 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 65 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 66 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 67 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 68 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 69 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6C */ {nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 6D */ {nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 6E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6F */ {nullptr, nullptr, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 70 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 71 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 72 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 73 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 74 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 75 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 76 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 77 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 78 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 79 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 80 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 81 */ {nullptr, nullptr, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81},
|
||||
/* 82 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 83 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 84 */ {nullptr, nullptr, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84},
|
||||
/* 85 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 86 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 87 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 88 */ {nullptr, nullptr, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, nullptr, nullptr, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, nullptr, nullptr},
|
||||
/* 89 */ {nullptr, nullptr, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89},
|
||||
/* 8A */ {nullptr, nullptr, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A},
|
||||
/* 8B */ {nullptr, nullptr, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, nullptr, nullptr, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, nullptr, nullptr},
|
||||
/* 8C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8E */ {nullptr, nullptr, on_8E_DCNTE, on_8E_DCNTE, on_8E_DCNTE, on_8E_DCNTE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8F */ {nullptr, nullptr, on_8F_DCNTE, on_8F_DCNTE, on_8F_DCNTE, on_8F_DCNTE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 90 */ {nullptr, nullptr, on_90_DC, on_90_DC, on_90_DC, on_90_DC, nullptr, nullptr, on_90_DC, on_90_DC, on_90_DC, on_90_DC, nullptr, nullptr},
|
||||
/* 91 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 92 */ {nullptr, nullptr, on_92_DC, on_92_DC, on_92_DC, on_92_DC, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 93 */ {nullptr, nullptr, on_93_DC, on_93_DC, on_93_DC, on_93_DC, nullptr, nullptr, on_93_DC, on_93_DC, on_93_DC, on_93_DC, nullptr, on_93_BB},
|
||||
/* 94 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 95 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 96 */ {nullptr, nullptr, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, nullptr},
|
||||
/* 97 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 98 */ {nullptr, nullptr, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98},
|
||||
/* 99 */ {nullptr, nullptr, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99},
|
||||
/* 9A */ {nullptr, nullptr, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, nullptr, nullptr},
|
||||
/* 9B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 9C */ {nullptr, nullptr, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, nullptr},
|
||||
/* 9D */ {nullptr, nullptr, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, nullptr},
|
||||
/* 9E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9E_XB, nullptr},
|
||||
/* 9F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_9F, on_9F, on_9F, on_9F, on_9F},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* A0 */ {nullptr, nullptr, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0},
|
||||
/* A1 */ {nullptr, nullptr, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1},
|
||||
/* A2 */ {nullptr, nullptr, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2},
|
||||
/* A3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, nullptr},
|
||||
/* A7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, nullptr},
|
||||
/* A8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A9 */ {nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored},
|
||||
/* AA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA},
|
||||
/* AB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB},
|
||||
/* AD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* B0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B1 */ {nullptr, nullptr, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, nullptr},
|
||||
/* B2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B3 */ {nullptr, nullptr, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3},
|
||||
/* B4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_B7_Ep3, on_B7_Ep3, nullptr, nullptr},
|
||||
/* B8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, nullptr, nullptr},
|
||||
/* B9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, nullptr, nullptr},
|
||||
/* BA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_BA_Ep3, on_BA_Ep3, nullptr, nullptr},
|
||||
/* BB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* C0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0},
|
||||
/* C1 */ {nullptr, nullptr, on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC, on_C1_PC, on_C1_PC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_C1_BB},
|
||||
/* C2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2},
|
||||
/* C3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3},
|
||||
/* C4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* C5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* C6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6},
|
||||
/* C7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7},
|
||||
/* C8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8},
|
||||
/* C9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_C9_XB, nullptr},
|
||||
/* CA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_CA_Ep3, on_CA_Ep3, nullptr, nullptr},
|
||||
/* CB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, nullptr, nullptr},
|
||||
/* CC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* D0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB},
|
||||
/* D1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB},
|
||||
/* D3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB},
|
||||
/* D5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D6_V3, on_D6_V3, on_D6_V3, on_D6_V3, on_D6_V3, nullptr},
|
||||
/* D7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D7_GC, on_D7_GC, on_D7_GC, on_D7_GC, on_D7_GC, nullptr},
|
||||
/* D8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8},
|
||||
/* D9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9},
|
||||
/* DA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DB_V3, on_DB_V3, on_DB_V3, on_DB_V3, on_DB_V3, nullptr},
|
||||
/* DC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DC_Ep3, on_DC_Ep3, nullptr, on_DC_BB},
|
||||
/* DD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DF_BB},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* E0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E0_BB},
|
||||
/* E1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* E2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E2_Ep3, on_E2_Ep3, nullptr, on_E2_BB},
|
||||
/* E3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E3_BB},
|
||||
/* E4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E4_Ep3, on_E4_Ep3, nullptr, nullptr},
|
||||
/* E5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E5_Ep3, on_E5_Ep3, nullptr, on_E5_BB},
|
||||
/* E6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_08_E6, on_08_E6, nullptr, nullptr},
|
||||
/* E7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_0C_C1_E7_EC, on_0C_C1_E7_EC, nullptr, on_E7_BB},
|
||||
/* E8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E8_BB},
|
||||
/* E9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* EA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EA_BB},
|
||||
/* EB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EB_BB},
|
||||
/* EC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_0C_C1_E7_EC, on_0C_C1_E7_EC, nullptr, on_EC_BB},
|
||||
/* ED */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ED_BB},
|
||||
/* EE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EE_Ep3, on_EE_Ep3, nullptr, nullptr},
|
||||
/* EF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EF_Ep3, on_EF_Ep3, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* F0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PC_PATCH BB_PATCH DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
// DC_NTE DC_112000 DCV1 DCV2 PC_NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 00 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 01 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 02 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 03 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 04 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 05 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_05_XB, on_ignored},
|
||||
/* 06 */ {on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06, on_06},
|
||||
/* 07 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 08 */ {on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6, on_08_E6},
|
||||
/* 09 */ {on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09, on_09},
|
||||
/* 0A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0C */ {on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 0F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 10 */ {on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10},
|
||||
/* 11 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 12 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 13 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB},
|
||||
/* 14 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 15 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 16 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 17 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 18 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 19 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1D */ {on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D, on_1D},
|
||||
/* 1E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 1F */ {on_1F, on_1F, on_1F, on_1F, on_1F, on_1F, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 20 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 21 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 22 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored},
|
||||
/* 23 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 24 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 25 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 26 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 27 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 28 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 29 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 2F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 30 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 31 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 32 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 33 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 34 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 35 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 36 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 37 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 38 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 39 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 3F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 40 */ {on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40, on_40},
|
||||
/* 41 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 42 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 43 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 44 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB},
|
||||
/* 45 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 46 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 47 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 48 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 49 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 4F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 50 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 51 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 52 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 53 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 54 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 55 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 56 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 57 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 58 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 59 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 5F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 60 */ {on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 61 */ {on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98},
|
||||
/* 62 */ {on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 63 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 64 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 65 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 66 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 67 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 68 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 69 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6C */ {on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 6D */ {on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB, on_6x_C9_CB},
|
||||
/* 6E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 6F */ {on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F, on_6F},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 70 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 71 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 72 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 73 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 74 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 75 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 76 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 77 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 78 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 79 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7A */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7E */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 7F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 80 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 81 */ {on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81, on_81},
|
||||
/* 82 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 83 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 84 */ {on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84, on_84},
|
||||
/* 85 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 86 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 87 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 88 */ {on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, nullptr, nullptr, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, on_88_DCNTE, nullptr, nullptr},
|
||||
/* 89 */ {on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89, on_89},
|
||||
/* 8A */ {on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A, on_8A},
|
||||
/* 8B */ {on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, nullptr, nullptr, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, on_8B_DCNTE, nullptr, nullptr},
|
||||
/* 8C */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8D */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8E */ {on_8E_DCNTE, on_8E_DCNTE, on_8E_DCNTE, on_8E_DCNTE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 8F */ {on_8F_DCNTE, on_8F_DCNTE, on_8F_DCNTE, on_8F_DCNTE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* 90 */ {on_90_DC, on_90_DC, on_90_DC, on_90_DC, nullptr, nullptr, on_90_DC, on_90_DC, on_90_DC, on_90_DC, nullptr, nullptr},
|
||||
/* 91 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 92 */ {on_92_DC, on_92_DC, on_92_DC, on_92_DC, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 93 */ {on_93_DC, on_93_DC, on_93_DC, on_93_DC, nullptr, nullptr, on_93_DC, on_93_DC, on_93_DC, on_93_DC, nullptr, on_93_BB},
|
||||
/* 94 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 95 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 96 */ {on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, on_96, nullptr},
|
||||
/* 97 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 98 */ {on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98, on_61_98},
|
||||
/* 99 */ {on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99, on_99},
|
||||
/* 9A */ {on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, on_9A, nullptr, nullptr},
|
||||
/* 9B */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 9C */ {on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, on_9C, nullptr},
|
||||
/* 9D */ {on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, nullptr},
|
||||
/* 9E */ {nullptr, nullptr, nullptr, nullptr, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9D_9E, on_9E_XB, nullptr},
|
||||
/* 9F */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_9F, on_9F, on_9F, on_9F, on_9F},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* A0 */ {on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0, on_A0},
|
||||
/* A1 */ {on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1, on_A1},
|
||||
/* A2 */ {on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2, on_A2},
|
||||
/* A3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, on_44_A6_V3_BB, nullptr},
|
||||
/* A7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, on_13_A7_V3_BB, nullptr},
|
||||
/* A8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* A9 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored},
|
||||
/* AA */ {nullptr, nullptr, nullptr, nullptr, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA},
|
||||
/* AB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB, on_AC_V3_BB},
|
||||
/* AD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* AF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* B0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B1 */ {on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, on_B1, nullptr},
|
||||
/* B2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B3 */ {on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3, on_B3},
|
||||
/* B4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* B7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_B7_Ep3, on_B7_Ep3, nullptr, nullptr},
|
||||
/* B8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, nullptr, nullptr},
|
||||
/* B9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, nullptr, nullptr},
|
||||
/* BA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_BA_Ep3, on_BA_Ep3, nullptr, nullptr},
|
||||
/* BB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* BF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* C0 */ {nullptr, nullptr, nullptr, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0, on_C0},
|
||||
/* C1 */ {on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC,on_0C_C1_E7_EC, on_C1_PC, on_C1_PC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_0C_C1_E7_EC, on_C1_BB},
|
||||
/* C2 */ {nullptr, nullptr, nullptr, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2, on_C2},
|
||||
/* C3 */ {nullptr, nullptr, nullptr, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3, on_C3},
|
||||
/* C4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* C5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* C6 */ {nullptr, nullptr, nullptr, nullptr, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6, on_C6},
|
||||
/* C7 */ {nullptr, nullptr, nullptr, nullptr, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7, on_C7},
|
||||
/* C8 */ {nullptr, nullptr, nullptr, nullptr, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8, on_C8},
|
||||
/* C9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, on_C9_XB, nullptr},
|
||||
/* CA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_CA_Ep3, on_CA_Ep3, nullptr, nullptr},
|
||||
/* CB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_6x_C9_CB, on_6x_C9_CB, nullptr, nullptr},
|
||||
/* CC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* CF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* D0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB, on_D0_V3_BB},
|
||||
/* D1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB, on_D2_V3_BB},
|
||||
/* D3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB, on_D4_V3_BB},
|
||||
/* D5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* D6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D6_V3, on_D6_V3, on_D6_V3, on_D6_V3, on_D6_V3, nullptr},
|
||||
/* D7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_D7_GC, on_D7_GC, on_D7_GC, on_D7_GC, on_D7_GC, nullptr},
|
||||
/* D8 */ {nullptr, nullptr, nullptr, nullptr, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8, on_D8},
|
||||
/* D9 */ {nullptr, nullptr, nullptr, nullptr, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9, on_D9},
|
||||
/* DA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DB_V3, on_DB_V3, on_DB_V3, on_DB_V3, on_DB_V3, nullptr},
|
||||
/* DC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DC_Ep3, on_DC_Ep3, nullptr, on_DC_BB},
|
||||
/* DD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* DF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_DF_BB},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* E0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E0_BB},
|
||||
/* E1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* E2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E2_Ep3, on_E2_Ep3, nullptr, on_E2_BB},
|
||||
/* E3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E3_BB},
|
||||
/* E4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E4_Ep3, on_E4_Ep3, nullptr, nullptr},
|
||||
/* E5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E5_Ep3, on_E5_Ep3, nullptr, on_E5_BB},
|
||||
/* E6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_08_E6, on_08_E6, nullptr, nullptr},
|
||||
/* E7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_0C_C1_E7_EC, on_0C_C1_E7_EC, nullptr, on_E7_BB},
|
||||
/* E8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_E8_BB},
|
||||
/* E9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* EA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EA_BB},
|
||||
/* EB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EB_BB},
|
||||
/* EC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_0C_C1_E7_EC, on_0C_C1_E7_EC, nullptr, on_EC_BB},
|
||||
/* ED */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ED_BB},
|
||||
/* EE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EE_Ep3, on_EE_Ep3, nullptr, nullptr},
|
||||
/* EF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_EF_Ep3, on_EF_Ep3, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
/* F0 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F2 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* F9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FA */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FB */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FC */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FD */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// DC_NTE DC_PROTO DCV1 DCV2 PC-NTE PC GCNTE GC EP3TE EP3 XB BB
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static void check_unlicensed_command(Version version, uint8_t command) {
|
||||
switch (version) {
|
||||
case Version::PC_PATCH:
|
||||
case Version::BB_PATCH:
|
||||
if (command != 0x02 && command != 0x04) {
|
||||
throw runtime_error("only commands 02 and 04 may be sent before login");
|
||||
}
|
||||
break;
|
||||
case Version::DC_NTE:
|
||||
case Version::DC_V1_11_2000_PROTOTYPE:
|
||||
case Version::DC_V1:
|
||||
@@ -5619,11 +5438,7 @@ static void check_unlicensed_command(Version version, uint8_t command) {
|
||||
}
|
||||
}
|
||||
|
||||
void on_command(
|
||||
shared_ptr<Client> c,
|
||||
uint16_t command,
|
||||
uint32_t flag,
|
||||
string& data) {
|
||||
void on_command(shared_ptr<Client> c, uint16_t command, uint32_t flag, string& data) {
|
||||
c->reschedule_ping_and_timeout_events();
|
||||
|
||||
// Most of the command handlers assume the client is registered, logged in,
|
||||
@@ -5634,7 +5449,7 @@ void on_command(
|
||||
check_unlicensed_command(c->version(), command);
|
||||
}
|
||||
|
||||
auto fn = handlers[command & 0xFF][static_cast<size_t>(c->version())];
|
||||
auto fn = handlers[command & 0xFF][static_cast<size_t>(c->version()) - 2];
|
||||
if (fn) {
|
||||
fn(c, command, flag, data);
|
||||
} else {
|
||||
@@ -5658,8 +5473,6 @@ void on_command_with_header(shared_ptr<Client> c, const string& data) {
|
||||
on_command(c, header.command, header.flag, sub_data);
|
||||
break;
|
||||
}
|
||||
case Version::PC_PATCH:
|
||||
case Version::BB_PATCH:
|
||||
case Version::PC_NTE:
|
||||
case Version::PC_V2: {
|
||||
auto& header = check_size_t<PSOCommandHeaderPC>(data, 0xFFFF);
|
||||
|
||||
@@ -152,7 +152,6 @@ static const char* dc_port_map_copyright = "DreamCast Port Map. Copyright SEGA E
|
||||
static const char* dc_lobby_server_copyright = "DreamCast Lobby Server. Copyright SEGA Enterprises. 1999";
|
||||
static const char* bb_game_server_copyright = "Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.";
|
||||
static const char* bb_pm_server_copyright = "PSO NEW PM Server. Copyright 1999-2002 SONICTEAM.";
|
||||
static const char* patch_server_copyright = "Patch Server. Copyright SonicTeam, LTD. 2001";
|
||||
|
||||
S_ServerInitWithAfterMessage_DC_PC_V3_02_17_91_9B<0xB4>
|
||||
prepare_server_init_contents_console(
|
||||
@@ -240,20 +239,6 @@ void send_server_init_bb(shared_ptr<Client> c, uint8_t flags) {
|
||||
sizeof(cmd.basic_cmd.server_key), true);
|
||||
}
|
||||
|
||||
void send_server_init_patch(shared_ptr<Client> c) {
|
||||
uint32_t server_key = random_object<uint32_t>();
|
||||
uint32_t client_key = random_object<uint32_t>();
|
||||
|
||||
S_ServerInit_Patch_02 cmd;
|
||||
cmd.copyright.encode(patch_server_copyright);
|
||||
cmd.server_key = server_key;
|
||||
cmd.client_key = client_key;
|
||||
send_command_t(c, 0x02, 0x00, cmd);
|
||||
|
||||
c->channel.crypt_out = make_shared<PSOV2Encryption>(server_key);
|
||||
c->channel.crypt_in = make_shared<PSOV2Encryption>(client_key);
|
||||
}
|
||||
|
||||
void send_server_init(shared_ptr<Client> c, uint8_t flags) {
|
||||
switch (c->version()) {
|
||||
case Version::DC_NTE:
|
||||
@@ -269,10 +254,6 @@ void send_server_init(shared_ptr<Client> c, uint8_t flags) {
|
||||
case Version::XB_V3:
|
||||
send_server_init_dc_pc_v3(c, flags);
|
||||
break;
|
||||
case Version::PC_PATCH:
|
||||
case Version::BB_PATCH:
|
||||
send_server_init_patch(c);
|
||||
break;
|
||||
case Version::BB_V4:
|
||||
send_server_init_bb(c, flags);
|
||||
break;
|
||||
@@ -676,33 +657,6 @@ void send_complete_player_bb(shared_ptr<Client> c) {
|
||||
send_command_t(c, 0x00E7, 0x00000000, cmd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// patch functions
|
||||
|
||||
void send_enter_directory_patch(shared_ptr<Client> c, const string& dir) {
|
||||
S_EnterDirectory_Patch_09 cmd = {{dir, 1}};
|
||||
send_command_t(c, 0x09, 0x00, cmd);
|
||||
}
|
||||
|
||||
void send_patch_file(shared_ptr<Client> c, shared_ptr<PatchFileIndex::File> f) {
|
||||
S_OpenFile_Patch_06 open_cmd = {0, f->size, {f->name, 1}};
|
||||
send_command_t(c, 0x06, 0x00, open_cmd);
|
||||
|
||||
for (size_t x = 0; x < f->chunk_crcs.size(); x++) {
|
||||
auto data = f->load_data();
|
||||
size_t chunk_size = min<uint32_t>(f->size - (x * 0x4000), 0x4000);
|
||||
|
||||
vector<pair<const void*, size_t>> blocks;
|
||||
S_WriteFileHeader_Patch_07 cmd_header = {x, f->chunk_crcs[x], chunk_size};
|
||||
blocks.emplace_back(&cmd_header, sizeof(cmd_header));
|
||||
blocks.emplace_back(data->data() + (x * 0x4000), chunk_size);
|
||||
send_command(c, 0x07, 0x00, blocks);
|
||||
}
|
||||
|
||||
S_CloseCurrentFile_Patch_08 close_cmd = {0};
|
||||
send_command_t(c, 0x08, 0x00, close_cmd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// message functions
|
||||
|
||||
|
||||
@@ -178,9 +178,6 @@ void send_stream_file_chunk_bb(std::shared_ptr<Client> c, uint32_t chunk_index);
|
||||
void send_approve_player_choice_bb(std::shared_ptr<Client> c);
|
||||
void send_complete_player_bb(std::shared_ptr<Client> c);
|
||||
|
||||
void send_enter_directory_patch(std::shared_ptr<Client> c, const std::string& dir);
|
||||
void send_patch_file(std::shared_ptr<Client> c, std::shared_ptr<PatchFileIndex::File> f);
|
||||
|
||||
void send_message_box(std::shared_ptr<Client> c, const std::string& text);
|
||||
void send_ep3_timed_message_box(Channel& ch, uint32_t frames, const std::string& text);
|
||||
void send_lobby_name(std::shared_ptr<Client> c, const std::string& text);
|
||||
|
||||
+1
-2
@@ -134,6 +134,7 @@ void Server::connect_client(
|
||||
c->channel.on_command_received = Server::on_client_input;
|
||||
c->channel.on_error = Server::on_client_error;
|
||||
c->channel.context_obj = this;
|
||||
this->state->channel_to_client.emplace(&c->channel, c);
|
||||
|
||||
server_log.info(
|
||||
"Client connected: C-%" PRIX64 " on virtual connection %p via T-%hu-%s-%s-VI",
|
||||
@@ -143,8 +144,6 @@ void Server::connect_client(
|
||||
name_for_enum(version),
|
||||
name_for_enum(initial_state));
|
||||
|
||||
this->state->channel_to_client.emplace(&c->channel, c);
|
||||
|
||||
// Manually set the remote address, since the bufferevent has no fd and the
|
||||
// Channel constructor can't figure out the virtual remote address
|
||||
auto* remote_sin = reinterpret_cast<sockaddr_in*>(&c->channel.remote_addr);
|
||||
|
||||
@@ -645,6 +645,7 @@ void ServerState::load_config() {
|
||||
|
||||
this->client_ping_interval_usecs = json.get_int("ClientPingInterval", 30000000);
|
||||
this->client_idle_timeout_usecs = json.get_int("ClientIdleTimeout", 60000000);
|
||||
this->patch_client_idle_timeout_usecs = json.get_int("PatchClientIdleTimeout", 300000000);
|
||||
|
||||
this->ip_stack_debug = json.get_bool("IPStackDebug", false);
|
||||
this->allow_unregistered_users = json.get_bool("AllowUnregisteredUsers", false);
|
||||
@@ -1679,3 +1680,23 @@ void ServerState::load_all() {
|
||||
this->load_teams(false);
|
||||
this->load_quest_index(false);
|
||||
}
|
||||
|
||||
shared_ptr<PatchServer::Config> ServerState::generate_patch_server_config(bool is_bb) const {
|
||||
auto ret = make_shared<PatchServer::Config>();
|
||||
ret->allow_unregistered_users = this->allow_unregistered_users;
|
||||
ret->hide_data_from_logs = this->hide_download_commands;
|
||||
ret->idle_timeout_usecs = this->patch_client_idle_timeout_usecs;
|
||||
ret->message = is_bb ? this->bb_patch_server_message : this->pc_patch_server_message;
|
||||
ret->license_index = this->license_index;
|
||||
ret->patch_file_index = is_bb ? this->bb_patch_file_index : this->pc_patch_file_index;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ServerState::update_patch_server_configs() const {
|
||||
if (this->pc_patch_server) {
|
||||
this->pc_patch_server->set_config(this->generate_patch_server_config(false));
|
||||
}
|
||||
if (this->bb_patch_server) {
|
||||
this->bb_patch_server->set_config(this->generate_patch_server_config(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "License.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "Menu.hh"
|
||||
#include "PatchServer.hh"
|
||||
#include "PlayerFilesManager.hh"
|
||||
#include "Quest.hh"
|
||||
#include "TeamIndex.hh"
|
||||
@@ -79,6 +80,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::vector<std::string> ppp_stack_addresses;
|
||||
uint64_t client_ping_interval_usecs = 30000000;
|
||||
uint64_t client_idle_timeout_usecs = 60000000;
|
||||
uint64_t patch_client_idle_timeout_usecs = 300000000;
|
||||
bool ip_stack_debug = false;
|
||||
bool allow_unregistered_users = false;
|
||||
bool allow_pc_nte = false;
|
||||
@@ -235,6 +237,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
|
||||
std::shared_ptr<ProxyServer> proxy_server;
|
||||
std::shared_ptr<Server> game_server;
|
||||
std::shared_ptr<PatchServer> pc_patch_server;
|
||||
std::shared_ptr<PatchServer> bb_patch_server;
|
||||
|
||||
explicit ServerState(const std::string& config_filename = "");
|
||||
ServerState(std::shared_ptr<struct event_base> base, const std::string& config_filename, bool is_replay);
|
||||
@@ -312,6 +316,9 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<PatchServer::Config> generate_patch_server_config(bool is_bb) const;
|
||||
void update_patch_server_configs() const;
|
||||
|
||||
// The following functions may only be called from a non-event thread if they
|
||||
// take a from_non_event_thread argument; any function that does not have this
|
||||
// argument must be called only from the event thread.
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
// A third case is when inbuf is NULL or *inbuf is NULL, and outbuf is NULL or *outbuf is NULL. In this case, the iconv function sets cd’s conversion state to the initial state.
|
||||
|
||||
const iconv_t TextTranscoder::INVALID_IC = (iconv_t)(-1);
|
||||
const size_t TextTranscoder::FAILURE_RESULT = static_cast<size_t>(-1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user