Revert "Revert "Merge branch 'master' into command-split""

This reverts commit 58f2d1e2b7.
This commit is contained in:
MangosArentLiterature 2021-04-15 18:01:51 -05:00
parent 58f2d1e2b7
commit 577e2b5095
10 changed files with 1880 additions and 17 deletions

View File

@ -4,10 +4,12 @@ protected_area=true
iniswap_allowed=false iniswap_allowed=false
evidence_mod=cm evidence_mod=cm
blankposting_allowed=true blankposting_allowed=true
force_immediate=true
[1:Courtroom 1] [1:Courtroom 1]
background=gs4 background=gs4
protected_area=false protected_area=false
iniswap_allowed=true iniswap_allowed=true
evidence_mod=ffa evidence_mod=ffa
blankposting_allowed=true blankposting_allowed=true
force_immediate=false

View File

@ -53,7 +53,11 @@ class AOClient : public QObject {
AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent = nullptr, int user_id = 0) AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent = nullptr, int user_id = 0)
: QObject(parent), id(user_id), remote_ip(p_socket->peerAddress()), password(""), : QObject(parent), id(user_id), remote_ip(p_socket->peerAddress()), password(""),
joined(false), current_area(0), current_char(""), socket(p_socket), server(p_server), joined(false), current_area(0), current_char(""), socket(p_socket), server(p_server),
is_partial(false), last_wtce_time(0) {}; is_partial(false), last_wtce_time(0) {
afk_timer = new QTimer;
afk_timer->setSingleShot(true);
connect(afk_timer, SIGNAL(timeout()), this, SLOT(onAfkTimeout()));
};
/** /**
* @brief Destructor for the AOClient instance. * @brief Destructor for the AOClient instance.
@ -218,6 +222,12 @@ class AOClient : public QObject {
{"SUPER", ~0ULL }, {"SUPER", ~0ULL },
}; };
/**
* @brief A list of 5 casing preferences (def, pro, judge, jury, steno)
*/
QList<bool> casing_preferences = {false, false, false, false, false};
/** /**
* @brief If true, the client's in-character messages will have their word order randomised. * @brief If true, the client's in-character messages will have their word order randomised.
*/ */
@ -233,6 +243,18 @@ class AOClient : public QObject {
*/ */
bool is_gimped = false; bool is_gimped = false;
/**
* @brief If true, the client will be marked as AFK in /getarea. Automatically applied when a configurable
* amount of time has passed since the last interaction, or manually applied by /afk.
*/
bool is_afk = false;
/**
* @brief Timer for tracking user interaction. Automatically restarted whenever a user interacts (i.e. sends any packet besides CH)
*/
QTimer* afk_timer;
public slots: public slots:
/** /**
* @brief A slot for when the client disconnects from the server. * @brief A slot for when the client disconnects from the server.
@ -261,6 +283,11 @@ class AOClient : public QObject {
*/ */
void sendPacket(QString header); void sendPacket(QString header);
/**
* @brief A slot for when the client's AFK timer runs out.
*/
void onAfkTimeout();
private: private:
/** /**
* @brief The TCP socket used to communicate with the client. * @brief The TCP socket used to communicate with the client.
@ -472,6 +499,12 @@ class AOClient : public QObject {
/// Implements [editing evidence](https://github.com/AttorneyOnline/docs/blob/master/docs/development/network.md#edit). /// Implements [editing evidence](https://github.com/AttorneyOnline/docs/blob/master/docs/development/network.md#edit).
void pktEditEvidence(AreaData* area, int argc, QStringList argv, AOPacket packet); void pktEditEvidence(AreaData* area, int argc, QStringList argv, AOPacket packet);
/// Implements [updating casing preferences](https://github.com/AttorneyOnline/docs/blob/master/docs/development/network.md#case-preferences-update).
void pktSetCase(AreaData* area, int argc, QStringList argv, AOPacket packet);
/// Implements [announcing a case](https://github.com/AttorneyOnline/docs/blob/master/docs/development/network.md#case-alert).
void pktAnnounceCase(AreaData* area, int argc, QStringList argv, AOPacket packet);
///@} ///@}
/** /**
@ -622,6 +655,8 @@ class AOClient : public QObject {
{"PE", {ACLFlags.value("NONE"), 3, &AOClient::pktAddEvidence }}, {"PE", {ACLFlags.value("NONE"), 3, &AOClient::pktAddEvidence }},
{"DE", {ACLFlags.value("NONE"), 1, &AOClient::pktRemoveEvidence }}, {"DE", {ACLFlags.value("NONE"), 1, &AOClient::pktRemoveEvidence }},
{"EE", {ACLFlags.value("NONE"), 4, &AOClient::pktEditEvidence }}, {"EE", {ACLFlags.value("NONE"), 4, &AOClient::pktEditEvidence }},
{"SETCASE", {ACLFlags.value("NONE"), 7, &AOClient::pktSetCase }},
{"CASEA", {ACLFlags.value("NONE"), 6, &AOClient::pktAnnounceCase }},
}; };
/** /**
@ -1067,7 +1102,7 @@ class AOClient : public QObject {
* *
* @iscommand * @iscommand
*/ */
void cmdAllow_Blankposting(int argc, QStringList argv); void cmdAllowBlankposting(int argc, QStringList argv);
/** /**
* @brief Looks up info on a ban. * @brief Looks up info on a ban.
@ -1535,6 +1570,33 @@ class AOClient : public QObject {
void cmdCurrentMusic(int argc, QStringList argv); void cmdCurrentMusic(int argc, QStringList argv);
/**
* @brief Toggles immediate text processing in the current area.
*
* @details No arguments.
*
* @iscommand
*/
void cmdForceImmediate(int argc, QStringList argv);
/**
* @brief Toggles whether iniswaps are allowed in the current area.
*
* @details No arguments.
*
* @iscommand
*/
void cmdAllowIniswap(int argc, QStringList argv);
/**
* @brief Toggles whether this client is considered AFK.
*
* @details No arguments.
*
* @iscommand
*/
void cmdAfk(int argc, QStringList argv);
///@} ///@}
/** /**
@ -1767,7 +1829,8 @@ class AOClient : public QObject {
{"8ball", {ACLFlags.value("NONE"), 1, &AOClient::cmd8Ball}}, {"8ball", {ACLFlags.value("NONE"), 1, &AOClient::cmd8Ball}},
{"lm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdLM}}, {"lm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdLM}},
{"judgelog", {ACLFlags.value("CM"), 0, &AOClient::cmdJudgeLog}}, {"judgelog", {ACLFlags.value("CM"), 0, &AOClient::cmdJudgeLog}},
{"allow_blankposting", {ACLFlags.value("MODCHAT"), 0, &AOClient::cmdAllow_Blankposting}}, {"allowblankposting", {ACLFlags.value("MODCHAT"), 0, &AOClient::cmdAllowBlankposting}},
{"allow_blankposting", {ACLFlags.value("MODCHAT"), 0, &AOClient::cmdAllowBlankposting}},
{"gimp", {ACLFlags.value("MUTE"), 1, &AOClient::cmdGimp}}, {"gimp", {ACLFlags.value("MUTE"), 1, &AOClient::cmdGimp}},
{"ungimp", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnGimp}}, {"ungimp", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnGimp}},
{"baninfo", {ACLFlags.value("BAN"), 1, &AOClient::cmdBanInfo}}, {"baninfo", {ACLFlags.value("BAN"), 1, &AOClient::cmdBanInfo}},
@ -1776,11 +1839,17 @@ class AOClient : public QObject {
{"pause", {ACLFlags.value("CM"), 0, &AOClient::cmdPauseTestimony}}, {"pause", {ACLFlags.value("CM"), 0, &AOClient::cmdPauseTestimony}},
{"delete", {ACLFlags.value("CM"), 0, &AOClient::cmdDeleteStatement}}, {"delete", {ACLFlags.value("CM"), 0, &AOClient::cmdDeleteStatement}},
{"update", {ACLFlags.value("CM"), 0, &AOClient::cmdUpdateStatement}}, {"update", {ACLFlags.value("CM"), 0, &AOClient::cmdUpdateStatement}},
{"add", {ACLFlags.value("CM"), 0, &AOClient::cmdAddStatement}},
{"reload", {ACLFlags.value("SUPER"), 0, &AOClient::cmdReload}}, {"reload", {ACLFlags.value("SUPER"), 0, &AOClient::cmdReload}},
{"disemvowel", {ACLFlags.value("MUTE"), 1, &AOClient::cmdDisemvowel}}, {"disemvowel", {ACLFlags.value("MUTE"), 1, &AOClient::cmdDisemvowel}},
{"undisemvowel", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnDisemvowel}}, {"undisemvowel", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnDisemvowel}},
{"shake", {ACLFlags.value("MUTE"), 1, &AOClient::cmdShake}}, {"shake", {ACLFlags.value("MUTE"), 1, &AOClient::cmdShake}},
{"unshake", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnShake}}, {"unshake", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnShake}},
{"forceimmediate", {ACLFlags.value("CM"), 0, &AOClient::cmdForceImmediate}},
{"force_noint_pres", {ACLFlags.value("CM"), 0, &AOClient::cmdForceImmediate}},
{"allowiniswap", {ACLFlags.value("CM"), 0, &AOClient::cmdAllowIniswap}},
{"allow_iniswap", {ACLFlags.value("CM"), 0, &AOClient::cmdAllowIniswap}},
{"afk", {ACLFlags.value("NONE"), 0, &AOClient::cmdAfk}},
}; };
/** /**

View File

@ -344,6 +344,11 @@ class AreaData : public QObject {
* @brief The value of logger in config.ini. * @brief The value of logger in config.ini.
*/ */
QString log_type; QString log_type;
/**
* @brief Whether or not to force immediate text processing in this area
*/
bool force_immediate;
}; };
#endif // AREA_DATA_H #endif // AREA_DATA_H

View File

@ -232,6 +232,11 @@ class Server : public QObject {
*/ */
int max_dice; int max_dice;
/**
* @brief The amount of time in seconds to wait before marking a user AFK.
*/
int afk_timeout;
/** /**
* @brief The server-wide global timer. * @brief The server-wide global timer.
*/ */

View File

@ -77,6 +77,13 @@ void AOClient::handlePacket(AOPacket packet)
return; return;
} }
if (packet.header != "CH") {
if (is_afk)
sendServerMessage("You are no longer AFK.");
is_afk = false;
afk_timer->start(server->afk_timeout * 1000);
}
if (packet.contents.length() < info.minArgs) { if (packet.contents.length() < info.minArgs) {
#ifdef NET_DEBUG #ifdef NET_DEBUG
qDebug() << "Invalid packet args length. Minimum is" << info.minArgs << "but only" << packet.contents.length() << "were given."; qDebug() << "Invalid packet args length. Minimum is" << info.minArgs << "but only" << packet.contents.length() << "were given.";
@ -311,9 +318,17 @@ bool AOClient::checkAuth(unsigned long long acl_mask)
return true; return true;
} }
QString AOClient::getIpid() { return ipid; } QString AOClient::getIpid() { return ipid; }
Server* AOClient::getServer() { return server; }; Server* AOClient::getServer() { return server; }
void AOClient::onAfkTimeout()
{
if (!is_afk)
sendServerMessage("You are now AFK.");
is_afk = true;
}
AOClient::~AOClient() { AOClient::~AOClient() {
socket->deleteLater(); socket->deleteLater();

View File

@ -39,6 +39,7 @@ AreaData::AreaData(QString p_name, int p_index) :
bg_locked = areas_ini.value("bg_locked", "false").toBool(); bg_locked = areas_ini.value("bg_locked", "false").toBool();
QString configured_evi_mod = areas_ini.value("evidence_mod", "FFA").toString().toLower(); QString configured_evi_mod = areas_ini.value("evidence_mod", "FFA").toString().toLower();
blankposting_allowed = areas_ini.value("blankposting_allowed","true").toBool(); blankposting_allowed = areas_ini.value("blankposting_allowed","true").toBool();
force_immediate = areas_ini.value("force_immediate", "false").toBool();
areas_ini.endGroup(); areas_ini.endGroup();
QSettings config_ini("config/config.ini", QSettings::IniFormat); QSettings config_ini("config/config.ini", QSettings::IniFormat);
config_ini.beginGroup("Options"); config_ini.beginGroup("Options");

File diff suppressed because it is too large Load Diff

View File

@ -344,6 +344,59 @@ void AOClient::pktEditEvidence(AreaData* area, int argc, QStringList argv, AOPac
sendEvidenceList(area); sendEvidenceList(area);
} }
void AOClient::pktSetCase(AreaData* area, int argc, QStringList argv, AOPacket packet)
{
QList<bool> prefs_list;
for (int i = 2; i <=6; i++) {
bool is_int = false;
bool pref = argv[i].toInt(&is_int);
if (!is_int)
return;
prefs_list.append(pref);
}
casing_preferences = prefs_list;
}
void AOClient::pktAnnounceCase(AreaData* area, int argc, QStringList argv, AOPacket packet)
{
QString case_title = argv[0];
QStringList needed_roles;
QList<bool> needs_list;
for (int i = 1; i <=5; i++) {
bool is_int = false;
bool need = argv[i].toInt(&is_int);
if (!is_int)
return;
needs_list.append(need);
}
QStringList roles = {"defense attorney", "prosecutor", "judge", "jurors", "stenographer"};
for (int i = 0; i < 5; i++) {
if (needs_list[i])
needed_roles.append(roles[i]);
}
if (needed_roles.isEmpty())
return;
QString message = "=== Case Announcement ===\r\n" + (ooc_name == "" ? current_char : ooc_name) + " needs " + needed_roles.join(", ") + " for " + (case_title == "" ? "a case" : case_title) + "!";
QList<AOClient*> clients_to_alert;
// here lies morton, RIP
QSet<bool> needs_set = needs_list.toSet();
for (AOClient* client : server->clients) {
QSet<bool> matches = client->casing_preferences.toSet().intersect(needs_set);
if (!matches.isEmpty() && !clients_to_alert.contains(client))
clients_to_alert.append(client);
}
for (AOClient* client : clients_to_alert) {
client->sendPacket(AOPacket("CASEA", {message, argv[1], argv[2], argv[3], argv[4], argv[5], "1"}));
// you may be thinking, "hey wait a minute the network protocol documentation doesn't mention that last argument!"
// if you are in fact thinking that, you are correct! it is not in the documentation!
// however for some inscrutable reason Attorney Online 2 will outright reject a CASEA packet that does not have
// at least 7 arguments despite only using the first 6. Cera, i kneel. you have truly broken me.
}
}
void AOClient::sendEvidenceList(AreaData* area) void AOClient::sendEvidenceList(AreaData* area)
{ {
for (AOClient* client : server->clients) { for (AOClient* client : server->clients) {
@ -594,11 +647,13 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
} }
args.append(other_flip); args.append(other_flip);
// noninterrupting preanim // immediate text processing
int ni_pa = incoming_args[18].toInt(); int immediate = incoming_args[18].toInt();
if (ni_pa != 1 && ni_pa != 0) if (area->force_immediate)
immediate = 1;
if (immediate != 1 && immediate != 0)
return invalid; return invalid;
args.append(QString::number(ni_pa)); args.append(QString::number(immediate));
} }
// 2.8 packet extensions // 2.8 packet extensions
@ -717,6 +772,4 @@ void AOClient::updateJudgeLog(AreaData* area, AOClient* client, QString action)
area->judgelog.append(logmessage); area->judgelog.append(logmessage);
} }
else area->judgelog.append(logmessage); else area->judgelog.append(logmessage);
} }

View File

@ -53,9 +53,7 @@ void Server::start()
loadServerConfig(); loadServerConfig();
loadCommandConfig(); loadCommandConfig();
maximum_statements = config.value("maximum_statements", 50).toInt();
proxy = new WSProxy(port, ws_port, this); proxy = new WSProxy(port, ws_port, this);
if(ws_port != -1) if(ws_port != -1)
proxy->start(); proxy->start();
@ -232,9 +230,17 @@ void Server::loadServerConfig()
auth_type = config.value("auth","simple").toString(); auth_type = config.value("auth","simple").toString();
modpass = config.value("modpass","").toString(); modpass = config.value("modpass","").toString();
bool zalgo_tolerance_conversion_success; bool zalgo_tolerance_conversion_success;
zalgo_tolerance = config.value("zalgo_tolerance", "3").toInt(&zalgo_tolerance_conversion_success); zalgo_tolerance = config.value("zalgo_tolerance", "3").toInt(&zalgo_tolerance_conversion_success);
if (!zalgo_tolerance_conversion_success) if (!zalgo_tolerance_conversion_success)
zalgo_tolerance = 3; zalgo_tolerance = 3;
bool maximum_statements_conversion_success;
maximum_statements = config.value("maximum_statements", "10").toInt(&maximum_statements_conversion_success);
if (!maximum_statements_conversion_success)
maximum_statements = 10;
bool afk_timeout_conversion_success;
afk_timeout = config.value("afk_timeout", "300").toInt(&afk_timeout_conversion_success);
if (!afk_timeout_conversion_success)
afk_timeout = 300;
config.endGroup(); config.endGroup();
//Load dice values //Load dice values

View File

@ -39,6 +39,7 @@ void AOClient::addStatement(QStringList packet)
} }
} }
else if (area->test_rec == AreaData::TestimonyRecording::ADD) { else if (area->test_rec == AreaData::TestimonyRecording::ADD) {
packet[14] = "1";
area->testimony.insert(c_statement,packet); area->testimony.insert(c_statement,packet);
area->test_rec = AreaData::TestimonyRecording::PLAYBACK; area->test_rec = AreaData::TestimonyRecording::PLAYBACK;
} }