Add playerlist widget element (#996)
* Commit * Boyfailure code commit * Cooking code spaghetti * Accidental overwrite recursive function call hell * Implemented player list * Add partial moderator widget Sleepy time! Hee-Hoo! * Moderator Dialog - Step 1 - WIP * Appease the clang gods * Clang appeasement policy * *sacrifices goat to clang* * Added player report, reworked implementation, ... * Added player-specific report * Reworked implementation * No longer uses JSON. * Removed preset loader. --------- Co-authored-by: TrickyLeifa <date.epoch@gmail.com> Co-authored-by: Leifa <26681464+TrickyLeifa@users.noreply.github.com>
This commit is contained in:
parent
c745d0a1b7
commit
fb64ca386c
@ -98,7 +98,10 @@ add_executable(Attorney_Online
|
|||||||
src/widgets/server_editor_dialog.cpp
|
src/widgets/server_editor_dialog.cpp
|
||||||
src/widgets/server_editor_dialog.h
|
src/widgets/server_editor_dialog.h
|
||||||
data.qrc
|
data.qrc
|
||||||
|
src/widgets/playerlistwidget.h src/widgets/playerlistwidget.cpp
|
||||||
|
src/widgets/moderator_dialog.h src/widgets/moderator_dialog.cpp
|
||||||
src/screenslidetimer.h src/screenslidetimer.cpp
|
src/screenslidetimer.h src/screenslidetimer.cpp
|
||||||
|
src/moderation_functions.h src/moderation_functions.cpp
|
||||||
src/network/serverinfo.h src/network/serverinfo.cpp
|
src/network/serverinfo.h src/network/serverinfo.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
1
data.qrc
1
data.qrc
@ -15,5 +15,6 @@
|
|||||||
<file>data/ui/lobby.ui</file>
|
<file>data/ui/lobby.ui</file>
|
||||||
<file>data/ui/lobby_assets/down-arrow.png</file>
|
<file>data/ui/lobby_assets/down-arrow.png</file>
|
||||||
<file>data/ui/lobby_assets/up-arrow.png</file>
|
<file>data/ui/lobby_assets/up-arrow.png</file>
|
||||||
|
<file>data/ui/moderator_action_dialog.ui</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
133
data/ui/moderator_action_dialog.ui
Normal file
133
data/ui/moderator_action_dialog.ui
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>base_widget</class>
|
||||||
|
<widget class="QWidget" name="base_widget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>469</width>
|
||||||
|
<height>275</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QCheckBox" name="permanent">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Permanent</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="duration_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Duration</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="3">
|
||||||
|
<widget class="QComboBox" name="action">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="action_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Action</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" colspan="2">
|
||||||
|
<widget class="QSpinBox" name="duration">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> Hour(s)</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>876000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="details_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Details</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="details">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Sunken</enum>
|
||||||
|
</property>
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
hr { height: 1px; border-width: 0; }
|
||||||
|
li.unchecked::marker { content: "\2610"; }
|
||||||
|
li.checked::marker { content: "\2612"; }
|
||||||
|
</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="button_box">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>permanent</sender>
|
||||||
|
<signal>clicked(bool)</signal>
|
||||||
|
<receiver>duration</receiver>
|
||||||
|
<slot>setDisabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>416</x>
|
||||||
|
<y>74</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>234</x>
|
||||||
|
<y>74</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -193,6 +193,16 @@ void AOApplication::doBASSreset()
|
|||||||
load_bass_plugins();
|
load_bass_plugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOApplication::server_connected()
|
||||||
|
{
|
||||||
|
qInfo() << "Established connection to server.";
|
||||||
|
|
||||||
|
destruct_courtroom();
|
||||||
|
construct_courtroom();
|
||||||
|
|
||||||
|
courtroom_loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
void AOApplication::initBASS()
|
void AOApplication::initBASS()
|
||||||
{
|
{
|
||||||
BASS_SetConfig(BASS_CONFIG_DEV_DEFAULT, 1);
|
BASS_SetConfig(BASS_CONFIG_DEV_DEFAULT, 1);
|
||||||
|
@ -340,6 +340,7 @@ private:
|
|||||||
QSet<uint> dir_listing_exist_cache;
|
QSet<uint> dir_listing_exist_cache;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
void server_connected();
|
||||||
void server_disconnected();
|
void server_disconnected();
|
||||||
void loading_cancelled();
|
void loading_cancelled();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "courtroom.h"
|
#include "courtroom.h"
|
||||||
|
|
||||||
|
#include "moderation_functions.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
@ -168,6 +169,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app)
|
|||||||
ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents);
|
ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
ui_music_name->setObjectName("ui_music_name");
|
ui_music_name->setObjectName("ui_music_name");
|
||||||
|
|
||||||
|
ui_player_list = new PlayerListWidget(ao_app, this);
|
||||||
|
ui_player_list->setObjectName("ui_player_list");
|
||||||
|
|
||||||
for (int i = 0; i < max_clocks; i++)
|
for (int i = 0; i < max_clocks; i++)
|
||||||
{
|
{
|
||||||
ui_clock[i] = new AOClockLabel(this);
|
ui_clock[i] = new AOClockLabel(this);
|
||||||
@ -602,6 +606,11 @@ void Courtroom::clear_areas()
|
|||||||
area_list.clear();
|
area_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerListWidget *Courtroom::playerList()
|
||||||
|
{
|
||||||
|
return ui_player_list;
|
||||||
|
}
|
||||||
|
|
||||||
void Courtroom::fix_last_area()
|
void Courtroom::fix_last_area()
|
||||||
{
|
{
|
||||||
if (area_list.size() > 0)
|
if (area_list.size() > 0)
|
||||||
@ -868,6 +877,8 @@ void Courtroom::set_widgets()
|
|||||||
ui_music_list->setIndentation(music_list_indentation.toInt());
|
ui_music_list->setIndentation(music_list_indentation.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_size_and_pos(ui_player_list, "player_list");
|
||||||
|
|
||||||
QString music_list_animated = ao_app->get_design_element("music_list_animated", "courtroom_design.ini");
|
QString music_list_animated = ao_app->get_design_element("music_list_animated", "courtroom_design.ini");
|
||||||
ui_music_list->setAnimated(music_list_animated == "1" || music_list_animated.startsWith("true"));
|
ui_music_list->setAnimated(music_list_animated == "1" || music_list_animated.startsWith("true"));
|
||||||
|
|
||||||
@ -1879,6 +1890,7 @@ void Courtroom::on_authentication_state_received(int p_state)
|
|||||||
if (p_state >= 1)
|
if (p_state >= 1)
|
||||||
{
|
{
|
||||||
ui_guard->show();
|
ui_guard->show();
|
||||||
|
ui_player_list->setAuthenticated(true);
|
||||||
append_server_chatmessage(tr("CLIENT"), tr("You were granted the Disable Modcalls button."), "1");
|
append_server_chatmessage(tr("CLIENT"), tr("You were granted the Disable Modcalls button."), "1");
|
||||||
}
|
}
|
||||||
else if (p_state == 0)
|
else if (p_state == 0)
|
||||||
@ -1888,6 +1900,7 @@ void Courtroom::on_authentication_state_received(int p_state)
|
|||||||
else if (p_state < 0)
|
else if (p_state < 0)
|
||||||
{
|
{
|
||||||
ui_guard->hide();
|
ui_guard->hide();
|
||||||
|
ui_player_list->setAuthenticated(false);
|
||||||
append_server_chatmessage(tr("CLIENT"), tr("You were logged out."), "1");
|
append_server_chatmessage(tr("CLIENT"), tr("You were logged out."), "1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6380,35 +6393,11 @@ void Courtroom::on_call_mod_clicked()
|
|||||||
{
|
{
|
||||||
if (ao_app->m_serverdata.get_feature(server::BASE_FEATURE_SET::MODCALL_REASON))
|
if (ao_app->m_serverdata.get_feature(server::BASE_FEATURE_SET::MODCALL_REASON))
|
||||||
{
|
{
|
||||||
QMessageBox errorBox;
|
auto maybe_reason = call_moderator_support();
|
||||||
QInputDialog input;
|
if (maybe_reason)
|
||||||
|
|
||||||
input.setWindowFlags(Qt::WindowSystemMenuHint);
|
|
||||||
input.setLabelText(tr("Reason:"));
|
|
||||||
input.setWindowTitle(tr("Call Moderator"));
|
|
||||||
auto code = input.exec();
|
|
||||||
|
|
||||||
if (code != QDialog::Accepted)
|
|
||||||
{
|
{
|
||||||
return;
|
ao_app->send_server_packet(AOPacket("ZZ", {maybe_reason.value(), "-1"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString text = input.textValue();
|
|
||||||
if (text.isEmpty())
|
|
||||||
{
|
|
||||||
errorBox.critical(nullptr, tr("Error"), tr("You must provide a reason."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (text.length() > 256)
|
|
||||||
{
|
|
||||||
errorBox.critical(nullptr, tr("Error"), tr("The message is too long."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList mod_reason;
|
|
||||||
mod_reason.append(text);
|
|
||||||
|
|
||||||
ao_app->send_server_packet(AOPacket("ZZ", mod_reason));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "screenslidetimer.h"
|
#include "screenslidetimer.h"
|
||||||
#include "scrolltext.h"
|
#include "scrolltext.h"
|
||||||
#include "widgets/aooptionsdialog.h"
|
#include "widgets/aooptionsdialog.h"
|
||||||
|
#include "widgets/playerlistwidget.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
@ -84,6 +85,8 @@ public:
|
|||||||
void clear_music();
|
void clear_music();
|
||||||
void clear_areas();
|
void clear_areas();
|
||||||
|
|
||||||
|
PlayerListWidget *playerList();
|
||||||
|
|
||||||
void fix_last_area();
|
void fix_last_area();
|
||||||
|
|
||||||
void arup_append(int players, QString status, QString cm, QString locked);
|
void arup_append(int players, QString status, QString cm, QString locked);
|
||||||
@ -628,6 +631,7 @@ private:
|
|||||||
QListWidget *ui_mute_list;
|
QListWidget *ui_mute_list;
|
||||||
QTreeWidget *ui_area_list;
|
QTreeWidget *ui_area_list;
|
||||||
QTreeWidget *ui_music_list;
|
QTreeWidget *ui_music_list;
|
||||||
|
PlayerListWidget *ui_player_list;
|
||||||
|
|
||||||
ScrollText *ui_music_name;
|
ScrollText *ui_music_name;
|
||||||
kal::InterfaceAnimationLayer *ui_music_display;
|
kal::InterfaceAnimationLayer *ui_music_display;
|
||||||
|
@ -98,3 +98,42 @@ enum MUSIC_EFFECT
|
|||||||
FADE_OUT = 2,
|
FADE_OUT = 2,
|
||||||
SYNC_POS = 4
|
SYNC_POS = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PlayerData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int id = -1;
|
||||||
|
QString name;
|
||||||
|
QString character;
|
||||||
|
QString character_name;
|
||||||
|
int area_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlayerRegister
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum REGISTER_TYPE
|
||||||
|
{
|
||||||
|
ADD_PLAYER,
|
||||||
|
REMOVE_PLAYER,
|
||||||
|
};
|
||||||
|
|
||||||
|
int id;
|
||||||
|
REGISTER_TYPE type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlayerUpdate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum DATA_TYPE
|
||||||
|
{
|
||||||
|
NAME,
|
||||||
|
CHARACTER,
|
||||||
|
CHARACTER_NAME,
|
||||||
|
AREA_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
int id;
|
||||||
|
DATA_TYPE type;
|
||||||
|
QString data;
|
||||||
|
};
|
||||||
|
41
src/moderation_functions.cpp
Normal file
41
src/moderation_functions.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "moderation_functions.h"
|
||||||
|
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
std::optional<QString> call_moderator_support(QString title)
|
||||||
|
{
|
||||||
|
if (title.isEmpty())
|
||||||
|
{
|
||||||
|
title = QObject::tr("Call moderator");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = QObject::tr("Call moderator: %1").arg(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
QInputDialog input;
|
||||||
|
input.setLabelText(QObject::tr("Reason:"));
|
||||||
|
input.setWindowFlags(Qt::WindowSystemMenuHint);
|
||||||
|
input.setWindowTitle(title);
|
||||||
|
|
||||||
|
while (input.exec())
|
||||||
|
{
|
||||||
|
QString text = input.textValue();
|
||||||
|
if (text.isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(&input, QObject::tr("Error"), QObject::tr("Please, enter a reason."));
|
||||||
|
}
|
||||||
|
else if (text.length() > 255)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(&input, QObject::tr("Error"), QObject::tr("Reason is too long."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
7
src/moderation_functions.h
Normal file
7
src/moderation_functions.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
std::optional<QString> call_moderator_support(QString title = QString());
|
@ -149,7 +149,7 @@ void NetworkManager::connect_to_server(ServerInfo server)
|
|||||||
qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString());
|
qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString());
|
||||||
m_connection = new WebSocketConnection(ao_app, this);
|
m_connection = new WebSocketConnection(ao_app, this);
|
||||||
|
|
||||||
connect(m_connection, &WebSocketConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; });
|
connect(m_connection, &WebSocketConnection::connectedToServer, ao_app, &AOApplication::server_connected);
|
||||||
connect(m_connection, &WebSocketConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected);
|
connect(m_connection, &WebSocketConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected);
|
||||||
connect(m_connection, &WebSocketConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; });
|
connect(m_connection, &WebSocketConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; });
|
||||||
connect(m_connection, &WebSocketConnection::receivedPacket, this, &NetworkManager::handle_server_packet);
|
connect(m_connection, &WebSocketConnection::receivedPacket, this, &NetworkManager::handle_server_packet);
|
||||||
@ -188,7 +188,7 @@ void NetworkManager::ship_server_packet(AOPacket packet)
|
|||||||
|
|
||||||
void NetworkManager::join_to_server()
|
void NetworkManager::join_to_server()
|
||||||
{
|
{
|
||||||
ship_server_packet(AOPacket("askchaa").toString());
|
ship_server_packet(AOPacket("askchaa"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkManager::handle_server_packet(AOPacket packet)
|
void NetworkManager::handle_server_packet(AOPacket packet)
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#include "networkmanager.h"
|
#include "networkmanager.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
void AOApplication::append_to_demofile(QString packet_string)
|
void AOApplication::append_to_demofile(QString packet_string)
|
||||||
{
|
{
|
||||||
if (Options::getInstance().logToDemoFileEnabled() && !log_filename.isEmpty())
|
if (Options::getInstance().logToDemoFileEnabled() && !log_filename.isEmpty())
|
||||||
@ -38,6 +42,16 @@ void AOApplication::server_packet_received(AOPacket packet)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto convert_to_json = [](QString data) -> QJsonDocument {
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument document = QJsonDocument::fromJson(data.toUtf8(), &error);
|
||||||
|
if (error.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
qWarning().noquote() << "Invalid or malformed JSON data:" << error.errorString();
|
||||||
|
}
|
||||||
|
return document;
|
||||||
|
};
|
||||||
|
|
||||||
if (header == "decryptor")
|
if (header == "decryptor")
|
||||||
{
|
{
|
||||||
if (content.size() == 0)
|
if (content.size() == 0)
|
||||||
@ -117,11 +131,6 @@ void AOApplication::server_packet_received(AOPacket packet)
|
|||||||
|
|
||||||
generated_chars = 0;
|
generated_chars = 0;
|
||||||
|
|
||||||
destruct_courtroom();
|
|
||||||
construct_courtroom();
|
|
||||||
|
|
||||||
courtroom_loaded = false;
|
|
||||||
|
|
||||||
int selected_server = w_lobby->get_selected_server();
|
int selected_server = w_lobby->get_selected_server();
|
||||||
QString server_address;
|
QString server_address;
|
||||||
QString server_name;
|
QString server_name;
|
||||||
@ -529,6 +538,11 @@ void AOApplication::server_packet_received(AOPacket packet)
|
|||||||
}
|
}
|
||||||
else if (header == "ZZ")
|
else if (header == "ZZ")
|
||||||
{
|
{
|
||||||
|
if (content.size() < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_courtroom_constructed() && !content.isEmpty())
|
if (is_courtroom_constructed() && !content.isEmpty())
|
||||||
{
|
{
|
||||||
w_courtroom->mod_called(content.at(0));
|
w_courtroom->mod_called(content.at(0));
|
||||||
@ -676,6 +690,26 @@ void AOApplication::server_packet_received(AOPacket packet)
|
|||||||
|
|
||||||
m_serverdata.set_asset_url(content.at(0));
|
m_serverdata.set_asset_url(content.at(0));
|
||||||
}
|
}
|
||||||
|
else if (header == "PR")
|
||||||
|
{
|
||||||
|
if (content.size() < 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerRegister update{content.at(0).toInt(), PlayerRegister::REGISTER_TYPE(content.at(1).toInt())};
|
||||||
|
w_courtroom->playerList()->registerPlayer(update);
|
||||||
|
}
|
||||||
|
else if (header == "PU")
|
||||||
|
{
|
||||||
|
if (content.size() < 3)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerUpdate update{content.at(0).toInt(), PlayerUpdate::DATA_TYPE(content.at(1).toInt()), content.at(2)};
|
||||||
|
w_courtroom->playerList()->updatePlayer(update);
|
||||||
|
}
|
||||||
|
|
||||||
if (log_to_demo)
|
if (log_to_demo)
|
||||||
{
|
{
|
||||||
|
102
src/widgets/moderator_dialog.cpp
Normal file
102
src/widgets/moderator_dialog.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "moderator_dialog.h"
|
||||||
|
|
||||||
|
#include "aoapplication.h"
|
||||||
|
#include "gui_utils.h"
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QUiLoader>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
const QString ModeratorDialog::UI_FILE_PATH = "moderator_action_dialog.ui";
|
||||||
|
|
||||||
|
ModeratorDialog::ModeratorDialog(int clientId, bool ban, AOApplication *ao_app, QWidget *parent)
|
||||||
|
: QWidget{parent}
|
||||||
|
, ao_app(ao_app)
|
||||||
|
, m_client_id(clientId)
|
||||||
|
, m_ban(ban)
|
||||||
|
{
|
||||||
|
QFile file(Options::getInstance().getUIAsset(UI_FILE_PATH));
|
||||||
|
if (!file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
qFatal("Unable to open file %s", qPrintable(file.fileName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUiLoader loader;
|
||||||
|
ui_widget = loader.load(&file, this);
|
||||||
|
auto layout = new QVBoxLayout(this);
|
||||||
|
layout->addWidget(ui_widget);
|
||||||
|
|
||||||
|
FROM_UI(QComboBox, action);
|
||||||
|
FROM_UI(QSpinBox, duration);
|
||||||
|
FROM_UI(QLabel, duration_label);
|
||||||
|
FROM_UI(QCheckBox, permanent);
|
||||||
|
FROM_UI(QTextEdit, details);
|
||||||
|
FROM_UI(QDialogButtonBox, button_box);
|
||||||
|
|
||||||
|
if (m_ban)
|
||||||
|
{
|
||||||
|
ui_action->addItem(tr("Ban"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui_action->addItem(tr("Kick"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_duration->setVisible(m_ban);
|
||||||
|
ui_duration_label->setVisible(m_ban);
|
||||||
|
ui_permanent->setVisible(m_ban);
|
||||||
|
|
||||||
|
connect(ui_button_box, &QDialogButtonBox::accepted, this, &ModeratorDialog::onAcceptedClicked);
|
||||||
|
connect(ui_button_box, &QDialogButtonBox::rejected, this, &ModeratorDialog::close);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeratorDialog::~ModeratorDialog()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ModeratorDialog::onAcceptedClicked()
|
||||||
|
{
|
||||||
|
QString reason = ui_details->toPlainText();
|
||||||
|
if (reason.isEmpty())
|
||||||
|
{
|
||||||
|
if (QMessageBox::question(this, tr("Confirmation"), tr("Are you sure you want to confirm without a reason?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool permanent = ui_permanent->isChecked();
|
||||||
|
if (permanent)
|
||||||
|
{
|
||||||
|
if (QMessageBox::question(this, tr("Confirmation"), tr("Are you sure you want to ban permanently?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList arglist;
|
||||||
|
arglist.append(QString::number(m_client_id));
|
||||||
|
if (m_ban)
|
||||||
|
{
|
||||||
|
if (permanent)
|
||||||
|
{
|
||||||
|
arglist.append("-1");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arglist.append(QString::number(ui_duration->value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arglist.append("0");
|
||||||
|
}
|
||||||
|
arglist.append(reason);
|
||||||
|
|
||||||
|
ao_app->send_server_packet(AOPacket("MA", arglist));
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
38
src/widgets/moderator_dialog.h
Normal file
38
src/widgets/moderator_dialog.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class AOApplication;
|
||||||
|
|
||||||
|
class ModeratorDialog : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const QString UI_FILE_PATH;
|
||||||
|
|
||||||
|
explicit ModeratorDialog(int clientId, bool ban, AOApplication *ao_app, QWidget *parent = nullptr);
|
||||||
|
virtual ~ModeratorDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AOApplication *ao_app;
|
||||||
|
int m_client_id;
|
||||||
|
bool m_ban;
|
||||||
|
|
||||||
|
QWidget *ui_widget;
|
||||||
|
QComboBox *ui_action;
|
||||||
|
QSpinBox *ui_duration;
|
||||||
|
QLabel *ui_duration_label;
|
||||||
|
QCheckBox *ui_permanent;
|
||||||
|
QTextEdit *ui_details;
|
||||||
|
QDialogButtonBox *ui_button_box;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onAcceptedClicked();
|
||||||
|
};
|
169
src/widgets/playerlistwidget.cpp
Normal file
169
src/widgets/playerlistwidget.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "playerlistwidget.h"
|
||||||
|
|
||||||
|
#include "aoapplication.h"
|
||||||
|
#include "moderation_functions.h"
|
||||||
|
#include "widgets/moderator_dialog.h"
|
||||||
|
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
PlayerListWidget::PlayerListWidget(AOApplication *ao_app, QWidget *parent)
|
||||||
|
: QListWidget(parent)
|
||||||
|
, ao_app(ao_app)
|
||||||
|
{
|
||||||
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
connect(this, &PlayerListWidget::customContextMenuRequested, this, &PlayerListWidget::onCustomContextMenuRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerListWidget::~PlayerListWidget()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void PlayerListWidget::registerPlayer(const PlayerRegister &update)
|
||||||
|
{
|
||||||
|
switch (update.type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerRegister::ADD_PLAYER:
|
||||||
|
addPlayer(update.id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerRegister::REMOVE_PLAYER:
|
||||||
|
removePlayer(update.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::updatePlayer(const PlayerUpdate &update)
|
||||||
|
{
|
||||||
|
PlayerData &player = m_player_map[update.id];
|
||||||
|
|
||||||
|
bool update_icon = false;
|
||||||
|
switch (update.type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerUpdate::NAME:
|
||||||
|
player.name = update.data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerUpdate::CHARACTER:
|
||||||
|
player.character = update.data;
|
||||||
|
update_icon = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerUpdate::CHARACTER_NAME:
|
||||||
|
player.character_name = update.data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerUpdate::AREA_ID:
|
||||||
|
player.area_id = update.data.toInt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
updatePlayer(player.id, update_icon);
|
||||||
|
|
||||||
|
filterPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::setAuthenticated(bool f_state)
|
||||||
|
{
|
||||||
|
m_is_authenticated = f_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::onCustomContextMenuRequested(const QPoint &pos)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = itemAt(pos);
|
||||||
|
if (item == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int id = item->data(Qt::UserRole).toInt();
|
||||||
|
QString name = item->text();
|
||||||
|
|
||||||
|
QMenu *menu = new QMenu(this);
|
||||||
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QAction *report_player_action = menu->addAction("Report Player");
|
||||||
|
connect(report_player_action, &QAction::triggered, this, [this, id, name] {
|
||||||
|
auto maybe_reason = call_moderator_support(name);
|
||||||
|
if (maybe_reason.has_value())
|
||||||
|
{
|
||||||
|
ao_app->send_server_packet(AOPacket("ZZ", {maybe_reason.value(), QString::number(id)}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!m_is_authenticated)
|
||||||
|
{
|
||||||
|
QAction *kick_player_action = menu->addAction("Kick");
|
||||||
|
connect(kick_player_action, &QAction::triggered, this, [this, id, name] {
|
||||||
|
ModeratorDialog *dialog = new ModeratorDialog(id, false, ao_app);
|
||||||
|
dialog->setWindowTitle(tr("Kick %1").arg(name));
|
||||||
|
connect(this, &PlayerListWidget::destroyed, dialog, &ModeratorDialog::deleteLater);
|
||||||
|
dialog->show();
|
||||||
|
});
|
||||||
|
|
||||||
|
QAction *ban_player_action = menu->addAction("Ban");
|
||||||
|
connect(ban_player_action, &QAction::triggered, this, [this, id, name] {
|
||||||
|
ModeratorDialog *dialog = new ModeratorDialog(id, true, ao_app);
|
||||||
|
dialog->setWindowTitle(tr("Ban %1").arg(name));
|
||||||
|
connect(this, &PlayerListWidget::destroyed, dialog, &ModeratorDialog::deleteLater);
|
||||||
|
dialog->show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->popup(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::addPlayer(int playerId)
|
||||||
|
{
|
||||||
|
m_player_map.insert(playerId, PlayerData{.id = playerId});
|
||||||
|
QListWidgetItem *item = new QListWidgetItem(this);
|
||||||
|
item->setData(Qt::UserRole, playerId);
|
||||||
|
m_item_map.insert(playerId, item);
|
||||||
|
updatePlayer(playerId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::removePlayer(int playerId)
|
||||||
|
{
|
||||||
|
delete takeItem(row(m_item_map.take(playerId)));
|
||||||
|
m_player_map.remove(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::filterPlayerList()
|
||||||
|
{
|
||||||
|
int area_id = m_player_map.value(ao_app->client_id).area_id;
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
m_item_map[i]->setHidden(m_player_map[i].area_id != area_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerListWidget::updatePlayer(int playerId, bool updateIcon)
|
||||||
|
{
|
||||||
|
PlayerData &data = m_player_map[playerId];
|
||||||
|
QListWidgetItem *item = m_item_map[playerId];
|
||||||
|
item->setText(data.name.isEmpty() ? QObject::tr("Unnamed Player") : data.name);
|
||||||
|
if (data.character.isEmpty())
|
||||||
|
{
|
||||||
|
item->setToolTip(QString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tooltip = data.character;
|
||||||
|
if (!data.character_name.isEmpty())
|
||||||
|
{
|
||||||
|
tooltip = QObject::tr("%1 aka %2").arg(data.character, data.character_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setToolTip(tooltip);
|
||||||
|
|
||||||
|
if (updateIcon)
|
||||||
|
{
|
||||||
|
item->setIcon(QIcon(ao_app->get_image_suffix(ao_app->get_character_path(data.character, "char_icon"), true)));
|
||||||
|
}
|
||||||
|
}
|
36
src/widgets/playerlistwidget.h
Normal file
36
src/widgets/playerlistwidget.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
class AOApplication;
|
||||||
|
|
||||||
|
class PlayerListWidget : public QListWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PlayerListWidget(AOApplication *ao_app, QWidget *parent = nullptr);
|
||||||
|
virtual ~PlayerListWidget();
|
||||||
|
|
||||||
|
void registerPlayer(const PlayerRegister &update);
|
||||||
|
void updatePlayer(const PlayerUpdate &update);
|
||||||
|
|
||||||
|
void setAuthenticated(bool f_state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AOApplication *ao_app;
|
||||||
|
QMap<int, PlayerData> m_player_map;
|
||||||
|
QMap<int, QListWidgetItem *> m_item_map;
|
||||||
|
bool m_is_authenticated = false;
|
||||||
|
|
||||||
|
void addPlayer(int playerId);
|
||||||
|
void removePlayer(int playerId);
|
||||||
|
void updatePlayer(int playerId, bool updateIcon);
|
||||||
|
|
||||||
|
void filterPlayerList();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onCustomContextMenuRequested(const QPoint &pos);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user