diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/aoapplication.cpp | 4 | ||||
| -rw-r--r-- | src/aooptionsdialog.cpp | 16 | ||||
| -rw-r--r-- | src/aopacket.cpp | 10 | ||||
| -rw-r--r-- | src/courtroom.cpp | 165 | ||||
| -rw-r--r-- | src/demoserver.cpp | 304 | ||||
| -rw-r--r-- | src/lobby.cpp | 11 | ||||
| -rw-r--r-- | src/packet_distribution.cpp | 48 | ||||
| -rw-r--r-- | src/text_file_functions.cpp | 17 |
8 files changed, 463 insertions, 112 deletions
diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index fa58ab84..a7f41e3e 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -45,6 +45,10 @@ void AOApplication::construct_lobby() if (is_discord_enabled()) discord->state_lobby(); + if (demo_server) + demo_server->deleteLater(); + demo_server = new DemoServer(); + w_lobby->show(); } diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 7b425207..0fbee478 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -182,7 +182,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_stay_time_lbl->setText(tr("Text Stay Time:")); ui_stay_time_lbl->setToolTip(tr( "Minimum amount of time (in miliseconds) an IC message must stay on screen before " - "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor.")); + "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior.")); ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stay_time_lbl); @@ -219,6 +219,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_instant_objection_cb); row += 1; + ui_chat_ratelimit_lbl = new QLabel(ui_form_layout_widget); + ui_chat_ratelimit_lbl->setText(tr("Chat Rate Limit:")); + ui_chat_ratelimit_lbl->setToolTip(tr( + "Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_chat_ratelimit_lbl); + + ui_chat_ratelimit_spinbox = new QSpinBox(ui_form_layout_widget); + ui_chat_ratelimit_spinbox->setMaximum(5000); + ui_chat_ratelimit_spinbox->setValue(p_ao_app->get_chat_ratelimit()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_chat_ratelimit_spinbox); + row += 1; ui_log_names_divider = new QFrame(ui_form_layout_widget); ui_log_names_divider->setFrameShape(QFrame::HLine); ui_log_names_divider->setFrameShadow(QFrame::Sunken); @@ -824,6 +837,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("desync_logs", ui_desync_logs_cb->isChecked()); configini->setValue("stay_time", ui_stay_time_spinbox->value()); configini->setValue("instant_objection", ui_instant_objection_cb->isChecked()); + configini->setValue("chat_ratelimit", ui_chat_ratelimit_spinbox->value()); configini->setValue("default_username", ui_username_textbox->text()); configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); configini->setValue("master", ui_ms_textbox->text()); diff --git a/src/aopacket.cpp b/src/aopacket.cpp index bb6ac73b..a40d2ef7 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -8,9 +8,15 @@ AOPacket::AOPacket(QString p_packet_string) m_contents = packet_contents.mid(1, packet_contents.size()-2); // trims % } -QString AOPacket::to_string() +QString AOPacket::to_string(bool encoded) { - return m_header + "#" + m_contents.join("#") + "#%"; + QStringList contents = m_contents; + if (encoded) + contents.replaceInStrings("#", "<num>") + .replaceInStrings("%", "<percent>") + .replaceInStrings("$", "<dollar>") + .replaceInStrings("&", "<and>"); + return m_header + "#" + contents.join("#") + "#%"; } void AOPacket::net_encode() diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 443fb305..5f5f0b90 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -299,6 +299,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(editTextChanged(QString)), this, + SLOT(on_sfx_dropdown_custom(QString))); connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); connect(ui_sfx_remove, SIGNAL(clicked()), this, @@ -731,7 +733,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); ui_sfx_dropdown->setEditable(true); - ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_sfx_dropdown->setInsertPolicy(QComboBox::NoInsert); ui_sfx_dropdown->setToolTip( tr("Set a sound effect to play on your next 'Preanim'. Leaving it on " "Default will use the emote-defined sound (if any).\n" @@ -1159,13 +1161,20 @@ void Courtroom::done_received() objection_player->set_volume(0); blip_player->set_volume(0); - set_char_select_page(); + if (char_list.size() > 0) + { + set_char_select_page(); + set_char_select(); + } + else + { + update_character(m_cid); + enter_courtroom(); + } set_mute_list(); set_pair_list(); - set_char_select(); - show(); ui_spectator->show(); @@ -1279,8 +1288,6 @@ void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) ui_pos_dropdown->addItems(pos_dropdown_list); // Unblock the signals so the element can be used for setting pos again ui_pos_dropdown->blockSignals(false); - - qDebug() << pos_dropdown_list; } void Courtroom::update_character(int p_cid) @@ -1323,7 +1330,6 @@ void Courtroom::update_character(int p_cid) set_sfx_dropdown(); set_effects_dropdown(); - qDebug() << "update_character called"; if (newchar) // Avoid infinite loop of death and suffering set_iniswap_dropdown(); @@ -1621,7 +1627,7 @@ void Courtroom::on_chat_return_pressed() return; ui_ic_chat_message->blockSignals(true); - QTimer::singleShot(200, this, + QTimer::singleShot(ao_app->get_chat_ratelimit(), this, [=] { ui_ic_chat_message->blockSignals(false); }); // MS# // deskmod# @@ -1680,12 +1686,6 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(current_side); packet_contents.append(get_char_sfx()); - if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled() && ui_sfx_dropdown->currentIndex() > 1) { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(0); - ui_sfx_dropdown->blockSignals(false); - ui_sfx_remove->hide(); - } int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); @@ -1861,8 +1861,6 @@ void Courtroom::reset_ui() realization_state = 0; screenshake_state = 0; is_presenting_evidence = false; - if (!ao_app->is_stickypres_enabled()) - ui_pre->setChecked(false); ui_hold_it->set_image("holdit"); ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); @@ -1870,6 +1868,14 @@ void Courtroom::reset_ui() ui_realization->set_image("realization"); ui_screenshake->set_image("screenshake"); ui_evidence_present->set_image("present"); + + if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) { + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_remove->hide(); + custom_sfx = ""; + } + if (!ao_app->is_stickypres_enabled()) + ui_pre->setChecked(false); } void Courtroom::chatmessage_enqueue(QStringList p_contents) @@ -2520,7 +2526,7 @@ void Courtroom::play_char_sfx(QString sfx_name) void Courtroom::initialize_chatbox() { int f_charid = m_chatmessage[CHAR_ID].toInt(); - if (f_charid >= 0 && + if (f_charid >= 0 && f_charid < char_list.size() && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { QString real_name = char_list.at(f_charid).name; @@ -2968,7 +2974,7 @@ void Courtroom::log_ic_text(QString p_name, QString p_showname, { chatlogpiece log_entry(p_name, p_showname, p_message, p_action, p_color); ic_chatlog_history.append(log_entry); - if (ao_app->get_auto_logging_enabled()) + if (ao_app->get_auto_logging_enabled() && !ao_app->log_filename.isEmpty()) ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true); while (ic_chatlog_history.size() > log_maximum_blocks && @@ -3133,7 +3139,7 @@ void Courtroom::play_preanim(bool immediate) else anim_state = 1; preanim_done(); - qDebug() << "could not find " + anim_to_find; + qDebug() << "W: could not find " + anim_to_find; return; } @@ -3795,9 +3801,6 @@ void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); - if (ooc_message == "" || ui_ooc_chat_name->text() == "") - return; - if (ooc_message.startsWith("/pos")) { if (ooc_message == "/pos jud") { toggle_judge_buttons(true); @@ -4322,28 +4325,28 @@ void Courtroom::set_sfx_dropdown() ui_sfx_remove->hide(); return; } - QStringList soundlist = ao_app->get_list_file( + // Initialzie character sound list first. Will be empty if not found. + sound_list = ao_app->get_list_file( ao_app->get_character_path(current_char, "soundlist.ini")); - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file( - ao_app->get_theme_path("character_soundlist.ini")); - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file( - ao_app->get_default_theme_path("character_soundlist.ini")); - } - } + // Append default sound list after the character sound list. + sound_list += ao_app->get_list_file( + ao_app->get_base_path() + "soundlist.ini"); - if (soundlist.size() <= 0) { - ui_sfx_dropdown->hide(); - ui_sfx_remove->hide(); - return; + QStringList display_sounds; + for (QString sound : sound_list) { + QStringList unpacked = sound.split("="); + QString display = unpacked[0].trimmed(); + if (unpacked.size() > 1) + display = unpacked[1].trimmed(); + + display_sounds.append(display); } - soundlist.prepend("Nothing"); - soundlist.prepend("Default"); + display_sounds.prepend("Nothing"); + display_sounds.prepend("Default"); ui_sfx_dropdown->show(); - ui_sfx_dropdown->addItems(soundlist); + ui_sfx_dropdown->addItems(display_sounds); ui_sfx_dropdown->setCurrentIndex(0); ui_sfx_remove->hide(); ui_sfx_dropdown->blockSignals(false); @@ -4352,36 +4355,14 @@ void Courtroom::set_sfx_dropdown() void Courtroom::on_sfx_dropdown_changed(int p_index) { ui_ic_chat_message->setFocus(); + ui_sfx_remove->hide(); + custom_sfx = ""; +} - QStringList soundlist; - for (int i = 2; i < ui_sfx_dropdown->count(); ++i) { - QString entry = ui_sfx_dropdown->itemText(i); - if (!soundlist.contains(entry)) - soundlist.append(entry); - } - - QStringList defaultlist = - ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (defaultlist.size() <= 0) { - defaultlist = ao_app->get_list_file( - ao_app->get_default_theme_path("character_soundlist.ini")); - } - - if (defaultlist.size() > 0 && - defaultlist.toSet().subtract(soundlist.toSet()).size() > - 0) // There's a difference from the default configuration - ao_app->write_to_file( - soundlist.join("\n"), - ao_app->get_character_path(current_char, - "soundlist.ini")); // Create a new sound list - - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(p_index); - ui_sfx_dropdown->blockSignals(false); - if (p_index > 1) - ui_sfx_remove->show(); - else - ui_sfx_remove->hide(); +void Courtroom::on_sfx_dropdown_custom(QString p_sfx) +{ + ui_sfx_remove->show(); + custom_sfx = p_sfx; } void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) @@ -4394,40 +4375,27 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); else - menu->addAction(QString("Edit theme's character_soundlist.ini"), this, + menu->addAction(QString("Edit global soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - if (ui_sfx_dropdown->currentIndex() > 1) - menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText( - ui_sfx_dropdown->currentIndex())), - this, SLOT(on_sfx_remove_clicked())); + if (!custom_sfx.isEmpty()) + menu->addAction(QString("Clear Edit Text"), this, SLOT(on_sfx_remove_clicked())); menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); } + void Courtroom::on_sfx_edit_requested() { QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); if (!file_exists(p_path)) { - p_path = ao_app->get_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - p_path = ao_app->get_default_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - return; - } + p_path = ao_app->get_base_path() + "soundlist.ini"; } - } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_sfx_remove_clicked() { - if (ui_sfx_dropdown->count() <= 0) { - ui_sfx_remove->hide(); // We're not supposed to see it. Do this or the - // client will crash - return; - } - if (ui_sfx_dropdown->currentIndex() > 1) { - ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); - on_sfx_dropdown_changed(0); // Reset back to original - } + ui_sfx_remove->hide(); + ui_sfx_dropdown->setCurrentIndex(0); + custom_sfx = ""; } void Courtroom::set_effects_dropdown() @@ -4530,19 +4498,21 @@ bool Courtroom::effects_dropdown_find_and_set(QString effect) QString Courtroom::get_char_sfx() { - QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - if (sfx == "Nothing") - return "1"; - if (sfx != "" && sfx != "Default") - return sfx; - return ao_app->get_sfx_name(current_char, current_emote); + if (!custom_sfx.isEmpty()) + return custom_sfx; + int index = ui_sfx_dropdown->currentIndex(); + if (index == 0) // Default + return ao_app->get_sfx_name(current_char, current_emote); + if (index == 1) // Nothing + return "1"; + QString sfx = sound_list[index-2].split("=")[0].trimmed(); + if (sfx == "") + return "1"; + return sfx; } int Courtroom::get_char_sfx_delay() { - // QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - // if (sfx != "" && sfx != "Default") - // return 0; //todo: a way to define this return ao_app->get_sfx_delay(current_char, current_emote); } @@ -4750,7 +4720,6 @@ void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) QStringList packet_contents; packet_contents.append(p_area); packet_contents.append(QString::number(m_cid)); - qDebug() << packet_contents; ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } diff --git a/src/demoserver.cpp b/src/demoserver.cpp new file mode 100644 index 00000000..fcb5003d --- /dev/null +++ b/src/demoserver.cpp @@ -0,0 +1,304 @@ +#include "demoserver.h" +#include "lobby.h" + +DemoServer::DemoServer(QObject *parent) : QObject(parent) +{ + timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setSingleShot(true); + + tcp_server = new QTcpServer(this); + connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); + connect(timer, &QTimer::timeout, this, &DemoServer::playback); +} + +void DemoServer::start_server() +{ + if (server_started) return; + if (!tcp_server->listen(QHostAddress::LocalHost, 0)) { + qCritical() << "Could not start demo playback server..."; + qDebug() << tcp_server->errorString(); + return; + } + this->port = tcp_server->serverPort(); + qDebug() << "Server started"; + server_started = true; +} + +void DemoServer::destroy_connection() +{ + QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; +} + +void DemoServer::accept_connection() +{ + QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); + if (path.isEmpty()) + { + destroy_connection(); + return; + } + load_demo(path); + + if (demo_data.isEmpty()) + { + destroy_connection(); + return; + } + + if (demo_data.head().startsWith("SC#")) + { + sc_packet = demo_data.dequeue(); + AOPacket sc(sc_packet); + num_chars = sc.get_contents().length(); + } + else + { + sc_packet = "SC#%"; + num_chars = 0; + } + + if (client_sock) { + // Client is already connected... + qDebug() << "Multiple connections to demo server disallowed."; + QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; + } + client_sock = tcp_server->nextPendingConnection(); + connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); + connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); + client_sock->write("decryptor#NOENCRYPT#%"); +} + +void DemoServer::recv_data() +{ + QString in_data = QString::fromUtf8(client_sock->readAll()); + + // Copypasted from NetworkManager + if (!in_data.endsWith("%")) { + partial_packet = true; + temp_packet += in_data; + return; + } + + else { + if (partial_packet) { + in_data = temp_packet + in_data; + temp_packet = ""; + partial_packet = false; + } + } + + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + + for (QString packet : packet_list) { + AOPacket ao_packet(packet); + handle_packet(ao_packet); + } +} + +void DemoServer::handle_packet(AOPacket packet) +{ + packet.net_decode(); + + // This code is literally a barebones AO server + // It is wise to do it this way, because I can + // avoid touching any of this disgusting shit + // related to hardcoding this stuff in. + + // Also, at some point, I will make akashit + // into a shared library. + + QString header = packet.get_header(); + QStringList contents = packet.get_contents(); + + if (header == "HI") { + client_sock->write("ID#0#DEMOINTERNAL#0#%"); + } + else if (header == "ID") { + QStringList feature_list = { + "noencryption", "yellowtext", "prezoom", + "flipping", "customobjections", "fastloading", + "deskmod", "evidence", "cccc_ic_support", + "arup", "casing_alerts", "modcall_reason", + "looping_sfx", "additive", "effects", + "y_offset", "expanded_desk_mods"}; + client_sock->write("PN#0#1#%"); + client_sock->write("FL#"); + client_sock->write(feature_list.join('#').toUtf8()); + client_sock->write("#%"); + } + else if (header == "askchaa") { + client_sock->write("SI#"); + client_sock->write(QString::number(num_chars).toUtf8()); + client_sock->write("#0#1#%"); + } + else if (header == "RC") { + client_sock->write(sc_packet.toUtf8()); + } + else if (header == "RM") { + client_sock->write("SM#%"); + } + else if (header == "RD") { + client_sock->write("DONE#%"); + } + else if (header == "CC") { + client_sock->write("PV#0#CID#-1#%"); + client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%"); + } + else if (header == "CT") { + if (contents[1].startsWith("/load")) + { + QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); + if (path.isEmpty()) + return; + load_demo(path); + client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%"); + } + else if (contents[1].startsWith("/play") || contents[1] == ">") + { + if (timer->interval() != 0 && !timer->isActive()) + { + timer->start(); + client_sock->write("CT#DEMO#Resuming playback.#1#%"); + } + else + { + if (demo_data.isEmpty() && p_path != "") + load_demo(p_path); + playback(); + } + } + else if (contents[1].startsWith("/pause") || contents[1] == "|") + { + int timeleft = timer->remainingTime(); + timer->stop(); + timer->setInterval(timeleft); + client_sock->write("CT#DEMO#Pausing playback.#1#%"); + } + else if (contents[1].startsWith("/max_wait")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int p_max_wait = args.at(1).toInt(&ok); + if (ok) + { + if (p_max_wait < 0) + p_max_wait = -1; + max_wait = p_max_wait; + client_sock->write("CT#DEMO#Setting max_wait to "); + client_sock->write(QString::number(max_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + else + { + client_sock->write("CT#DEMO#Not a valid integer!#1#%"); + } + } + else + { + client_sock->write("CT#DEMO#Current max_wait is "); + client_sock->write(QString::number(max_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + } + else if (contents[1].startsWith("/min_wait")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int p_min_wait = args.at(1).toInt(&ok); + if (ok) + { + if (p_min_wait < 0) + p_min_wait = -1; + min_wait = p_min_wait; + client_sock->write("CT#DEMO#Setting min_wait to "); + client_sock->write(QString::number(min_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + else + { + client_sock->write("CT#DEMO#Not a valid integer!#1#%"); + } + } + else + { + client_sock->write("CT#DEMO#Current min_wait is "); + client_sock->write(QString::number(min_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + } + else if (contents[1].startsWith("/help")) + { + client_sock->write("CT#DEMO#Available commands:\nload, play, pause, max_wait, min_wait, help#1#%"); + } + } +} + +void DemoServer::load_demo(QString filename) +{ + QFile demo_file(filename); + demo_file.open(QIODevice::ReadOnly); + if (!demo_file.isOpen()) + return; + demo_data.clear(); + p_path = filename; + QTextStream demo_stream(&demo_file); + QString line = demo_stream.readLine(); + while (!line.isNull()) { + if (!line.endsWith("%")) { + line += "\n"; + } + demo_data.enqueue(line); + line = demo_stream.readLine(); + } +} + +void DemoServer::playback() +{ + if (demo_data.isEmpty()) + return; + + QString current_packet = demo_data.dequeue(); + // We reset the elapsed time with this packet + if (current_packet.startsWith("MS#")) + elapsed_time = 0; + + while (!current_packet.startsWith("wait") && !demo_data.isEmpty()) { + client_sock->write(current_packet.toUtf8()); + current_packet = demo_data.dequeue(); + } + if (!demo_data.isEmpty()) { + AOPacket wait_packet = AOPacket(current_packet); + + int duration = wait_packet.get_contents().at(0).toInt(); + if (max_wait != -1 && duration + elapsed_time > max_wait) + duration = qMax(0, max_wait - elapsed_time); + // We use elapsed_time to make sure that the packet we're using min_wait on is "priority" (e.g. IC) + if (elapsed_time == 0 && min_wait != -1 && duration < min_wait) + duration = min_wait; + elapsed_time += duration; + timer->start(duration); + } + else + { + client_sock->write("CT#DEMO#Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.#1#%"); + timer->setInterval(0); + } +} + +void DemoServer::client_disconnect() +{ + client_sock->deleteLater(); + client_sock = nullptr; +} diff --git a/src/lobby.cpp b/src/lobby.cpp index 954c30a8..f1a61f4c 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -3,6 +3,7 @@ #include "aoapplication.h" #include "aosfxplayer.h" #include "debug_functions.h" +#include "demoserver.h" #include "networkmanager.h" #include <QImageReader> @@ -438,7 +439,15 @@ void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) ui_connect->setEnabled(false); - ao_app->net_manager->connect_to_server(f_server); + if (f_server.port == 99999 && f_server.ip == "127.0.0.1") { + // Demo playback server selected + ao_app->demo_server->start_server(); + server_type demo_server; + demo_server.ip = "127.0.0.1"; + demo_server.port = ao_app->demo_server->port; + ao_app->net_manager->connect_to_server(demo_server); + } + else ao_app->net_manager->connect_to_server(f_server); } } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index f21c4acd..822b2dc9 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -102,6 +102,19 @@ end: delete p_packet; } +void AOApplication::append_to_demofile(QString packet_string) +{ + if (get_auto_logging_enabled() && !log_filename.isEmpty()) + { + QString path = log_filename.left(log_filename.size()).replace(".log", ".demo"); + append_to_file(packet_string, path, true); + if (!demo_timer.isValid()) + demo_timer.start(); + else + append_to_file("wait#"+ QString::number(demo_timer.restart()) + "#%", path, true); + } +} + void AOApplication::server_packet_received(AOPacket *p_packet) { p_packet->net_decode(); @@ -164,6 +177,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) else w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + + append_to_demofile(p_packet->to_string(true)); } } else if (header == "FL") { @@ -232,7 +247,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) evidence_list_size = f_contents.at(1).toInt(); music_list_size = f_contents.at(2).toInt(); - if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) + if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0) goto end; loaded_chars = 0; @@ -255,7 +270,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) server_name = info.name; server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); - qDebug() << server_address; window_title += ": " + server_name; } } @@ -265,7 +279,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) server_name = info.name; server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); - qDebug() << server_address; window_title += ": " + server_name; } } @@ -283,7 +296,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) // Remove any characters not accepted in folder names for the server_name // here - if (AOApplication::get_auto_logging_enabled()) { + if (AOApplication::get_auto_logging_enabled() && server_name != "Demo playback") { this->log_filename = QDateTime::currentDateTime().toUTC().toString( "'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'yyyy-MM-dd hh-mm-ss t'.log'"); @@ -292,6 +305,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) QDateTime::currentDateTime().toUTC().toString(), log_filename, true); } + else + this->log_filename = ""; QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); @@ -312,7 +327,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } else if (header == "SC") { - if (!courtroom_constructed) + if (!courtroom_constructed || courtroom_loaded) goto end; for (int n_element = 0; n_element < f_contents.size(); ++n_element) { @@ -344,9 +359,10 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } send_server_packet(new AOPacket("RM#%")); + append_to_demofile(p_packet->to_string(true)); } else if (header == "SM") { - if (!courtroom_constructed) + if (!courtroom_constructed || courtroom_loaded) goto end; bool musics_time = false; @@ -445,6 +461,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) 2) // We have a pos included in the background packet! w_courtroom->set_side(f_contents.at(1)); w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); + append_to_demofile(p_packet->to_string(true)); } } else if (header == "SP") { @@ -454,6 +471,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (courtroom_constructed) // We were sent a "set position" packet { w_courtroom->set_side(f_contents.at(0)); + append_to_demofile(p_packet->to_string(true)); } } else if (header == "SD") // Send pos dropdown @@ -475,27 +493,37 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } else if (header == "MS") { if (courtroom_constructed && courtroom_loaded) + { w_courtroom->chatmessage_enqueue(p_packet->get_contents()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "MC") { if (courtroom_constructed && courtroom_loaded) + { w_courtroom->handle_song(&p_packet->get_contents()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "RT") { if (f_contents.size() < 1) goto end; if (courtroom_constructed) { - if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); - else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + if (f_contents.size() == 1) + w_courtroom->handle_wtce(f_contents.at(0), 0); + else if (f_contents.size() == 2) { + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + append_to_demofile(p_packet->to_string(true)); } } } else if (header == "HP") { if (courtroom_constructed && f_contents.size() > 1) + { w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "LE") { if (courtroom_constructed) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 1ea27bff..e79411a2 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -52,6 +52,12 @@ int AOApplication::stay_time() return result; } +int AOApplication::get_chat_ratelimit() +{ + int result = configini->value("chat_ratelimit", 300).toInt(); + return result; +} + bool AOApplication::get_log_goes_downwards() { QString result = @@ -178,6 +184,10 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir) { + if(!file_exists(p_file)) //Don't create a newline if file didn't exist before now + { + return write_to_file(p_text, p_file, make_dir); + } QString path = QFileInfo(p_file).path(); // Create the dir if it doesn't exist yet if (make_dir) { @@ -249,6 +259,13 @@ QVector<server_type> AOApplication::read_serverlist_txt() f_server_list.append(f_server); } + server_type demo_server; + demo_server.ip = "127.0.0.1"; + demo_server.port = 99999; + demo_server.name = "Demo playback"; + demo_server.desc = "Play back demos you have previously recorded"; + f_server_list.append(demo_server); + return f_server_list; } |
