add validation for 2.4.x packets, and a lot more
This commit is contained in:
parent
6503b514d4
commit
fde0c4b78f
@ -15,6 +15,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS_WARN_OFF -= -Wunused-parameter
|
||||||
|
|
||||||
DESTDIR = $$PWD/bin
|
DESTDIR = $$PWD/bin
|
||||||
OBJECTS_DIR = $$PWD/build
|
OBJECTS_DIR = $$PWD/build
|
||||||
MOC_DIR = $$PWD/build
|
MOC_DIR = $$PWD/build
|
||||||
@ -28,7 +30,6 @@ SOURCES += src/advertiser.cpp \
|
|||||||
src/commands.cpp \
|
src/commands.cpp \
|
||||||
src/config_manager.cpp \
|
src/config_manager.cpp \
|
||||||
src/db_manager.cpp \
|
src/db_manager.cpp \
|
||||||
src/icchatpacket.cpp \
|
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
src/packets.cpp \
|
src/packets.cpp \
|
||||||
src/server.cpp \
|
src/server.cpp \
|
||||||
@ -42,7 +43,6 @@ HEADERS += include/advertiser.h \
|
|||||||
include/area_data.h \
|
include/area_data.h \
|
||||||
include/config_manager.h \
|
include/config_manager.h \
|
||||||
include/db_manager.h \
|
include/db_manager.h \
|
||||||
include/icchatpacket.h \
|
|
||||||
include/server.h \
|
include/server.h \
|
||||||
include/ws_client.h \
|
include/ws_client.h \
|
||||||
include/ws_proxy.h
|
include/ws_proxy.h
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "include/aopacket.h"
|
#include "include/aopacket.h"
|
||||||
#include "include/server.h"
|
#include "include/server.h"
|
||||||
#include "include/icchatpacket.h"
|
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
#include "include/db_manager.h"
|
#include "include/db_manager.h"
|
||||||
|
|
||||||
@ -106,6 +105,13 @@ class AOClient : public QObject {
|
|||||||
void pktHpBar(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
void pktHpBar(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
||||||
void pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
void pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
||||||
|
|
||||||
|
// Packet helper functions
|
||||||
|
AOPacket validateIcPacket(AOPacket packet);
|
||||||
|
|
||||||
|
// Packet helper global variables
|
||||||
|
bool last_msg_blankpost = false;
|
||||||
|
int char_id = -1;
|
||||||
|
|
||||||
struct PacketInfo {
|
struct PacketInfo {
|
||||||
unsigned long long acl_mask;
|
unsigned long long acl_mask;
|
||||||
int minArgs;
|
int minArgs;
|
||||||
@ -121,7 +127,7 @@ class AOClient : public QObject {
|
|||||||
{"RD", {ACLFlags.value("NONE"), 0, &AOClient::pktLoadingDone}},
|
{"RD", {ACLFlags.value("NONE"), 0, &AOClient::pktLoadingDone}},
|
||||||
{"PW", {ACLFlags.value("NONE"), 1, &AOClient::pktCharPassword}},
|
{"PW", {ACLFlags.value("NONE"), 1, &AOClient::pktCharPassword}},
|
||||||
{"CC", {ACLFlags.value("NONE"), 3, &AOClient::pktSelectChar}},
|
{"CC", {ACLFlags.value("NONE"), 3, &AOClient::pktSelectChar}},
|
||||||
{"MS", {ACLFlags.value("NONE"), 1, &AOClient::pktIcChat}}, // TODO: doublecheck
|
{"MS", {ACLFlags.value("NONE"), 15, &AOClient::pktIcChat}},
|
||||||
{"CT", {ACLFlags.value("NONE"), 2, &AOClient::pktOocChat}},
|
{"CT", {ACLFlags.value("NONE"), 2, &AOClient::pktOocChat}},
|
||||||
{"CH", {ACLFlags.value("NONE"), 1, &AOClient::pktPing}},
|
{"CH", {ACLFlags.value("NONE"), 1, &AOClient::pktPing}},
|
||||||
{"MC", {ACLFlags.value("NONE"), 2, &AOClient::pktChangeMusic}},
|
{"MC", {ACLFlags.value("NONE"), 2, &AOClient::pktChangeMusic}},
|
||||||
@ -147,6 +153,7 @@ class AOClient : public QObject {
|
|||||||
void cmdAddPerms(int argc, QStringList argv);
|
void cmdAddPerms(int argc, QStringList argv);
|
||||||
void cmdRemovePerms(int argc, QStringList argv);
|
void cmdRemovePerms(int argc, QStringList argv);
|
||||||
void cmdListUsers(int argc, QStringList argv);
|
void cmdListUsers(int argc, QStringList argv);
|
||||||
|
void cmdLogout(int argc, QStringList argv);
|
||||||
|
|
||||||
// Command helper functions
|
// Command helper functions
|
||||||
QStringList buildAreaList(int area_idx);
|
QStringList buildAreaList(int area_idx);
|
||||||
@ -176,7 +183,8 @@ class AOClient : public QObject {
|
|||||||
{"listperms", {ACLFlags.value("NONE"), 0, &AOClient::cmdListPerms}},
|
{"listperms", {ACLFlags.value("NONE"), 0, &AOClient::cmdListPerms}},
|
||||||
{"addperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddPerms}},
|
{"addperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddPerms}},
|
||||||
{"removeperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdRemovePerms}},
|
{"removeperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdRemovePerms}},
|
||||||
{"listusers", {ACLFlags.value("MODIFY_USERS"), 0, &AOClient::cmdListUsers}}
|
{"listusers", {ACLFlags.value("MODIFY_USERS"), 0, &AOClient::cmdListUsers}},
|
||||||
|
{"logout", {ACLFlags.value("NONE"), 0, &AOClient::cmdLogout}}
|
||||||
};
|
};
|
||||||
|
|
||||||
QString partial_packet;
|
QString partial_packet;
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
|
|
||||||
void addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason);
|
void addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason);
|
||||||
|
|
||||||
void createUser(QString username, QString salt, QString password, unsigned long long acl);
|
bool createUser(QString username, QString salt, QString password, unsigned long long acl);
|
||||||
unsigned long long getACL(QString moderator_name);
|
unsigned long long getACL(QString moderator_name);
|
||||||
bool authenticate(QString username, QString password);
|
bool authenticate(QString username, QString password);
|
||||||
bool updateACL(QString username, unsigned long long acl, bool mode);
|
bool updateACL(QString username, unsigned long long acl, bool mode);
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// akashi - a server for Attorney Online 2 //
|
|
||||||
// Copyright (C) 2020 scatterflower //
|
|
||||||
// //
|
|
||||||
// This program is free software: you can redistribute it and/or modify //
|
|
||||||
// it under the terms of the GNU Affero General Public License as //
|
|
||||||
// published by the Free Software Foundation, either version 3 of the //
|
|
||||||
// License, or (at your option) any later version. //
|
|
||||||
// //
|
|
||||||
// This program is distributed in the hope that it will be useful, //
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
||||||
// GNU Affero General Public License for more details. //
|
|
||||||
// //
|
|
||||||
// You should have received a copy of the GNU Affero General Public License //
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef ICCHATPACKET_H
|
|
||||||
#define ICCHATPACKET_H
|
|
||||||
|
|
||||||
#endif // ICCHATPACKET_H
|
|
||||||
|
|
||||||
#include "include/aopacket.h"
|
|
||||||
|
|
||||||
class ICChatPacket : public AOPacket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ICChatPacket(AOPacket packet);
|
|
||||||
|
|
||||||
const int MIN_FIELDS = 15;
|
|
||||||
const int MAX_FIELDS = 30;
|
|
||||||
|
|
||||||
bool is_valid;
|
|
||||||
|
|
||||||
QString desk_override;
|
|
||||||
QString preanim;
|
|
||||||
QString character;
|
|
||||||
QString emote;
|
|
||||||
QString message;
|
|
||||||
QString side;
|
|
||||||
QString sfx_name;
|
|
||||||
int emote_modifier;
|
|
||||||
int char_id;
|
|
||||||
QString sfx_delay;
|
|
||||||
int objection_modifier;
|
|
||||||
QString evidence;
|
|
||||||
bool flip;
|
|
||||||
bool realization;
|
|
||||||
int text_color;
|
|
||||||
QString showname;
|
|
||||||
int other_charid;
|
|
||||||
QString other_name;
|
|
||||||
QString other_emote;
|
|
||||||
int self_offset;
|
|
||||||
int other_offset;
|
|
||||||
bool other_flip;
|
|
||||||
bool noninterrupting_preanim;
|
|
||||||
bool sfx_looping;
|
|
||||||
bool screenshake;
|
|
||||||
QString frames_shake;
|
|
||||||
QString frames_realization;
|
|
||||||
QString frames_sfx;
|
|
||||||
bool additive;
|
|
||||||
QString effect;
|
|
||||||
};
|
|
@ -70,8 +70,7 @@ void AOClient::clientDisconnected()
|
|||||||
|
|
||||||
void AOClient::handlePacket(AOPacket packet)
|
void AOClient::handlePacket(AOPacket packet)
|
||||||
{
|
{
|
||||||
// TODO: like everything here should send a signal
|
qDebug() << "Received packet:" << packet.header << ":" << packet.contents << "args length:" << packet.contents.length();
|
||||||
// qDebug() << "Received packet:" << packet.header << ":" << packet.contents;
|
|
||||||
AreaData* area = server->areas[current_area];
|
AreaData* area = server->areas[current_area];
|
||||||
PacketInfo info = packets.value(packet.header, {false, 0, &AOClient::pktDefault});
|
PacketInfo info = packets.value(packet.header, {false, 0, &AOClient::pktDefault});
|
||||||
|
|
||||||
@ -175,7 +174,7 @@ void AOClient::fullArup() {
|
|||||||
|
|
||||||
void AOClient::sendPacket(AOPacket packet)
|
void AOClient::sendPacket(AOPacket packet)
|
||||||
{
|
{
|
||||||
// qDebug() << "Sent packet:" << packet.header << ":" << packet.contents;
|
qDebug() << "Sent packet:" << packet.header << ":" << packet.contents;
|
||||||
socket->write(packet.toUtf8());
|
socket->write(packet.toUtf8());
|
||||||
socket->flush();
|
socket->flush();
|
||||||
}
|
}
|
||||||
|
@ -209,8 +209,10 @@ void AOClient::cmdAddUser(int argc, QStringList argv)
|
|||||||
quint64 salt_number = QRandomGenerator::system()->generate64();
|
quint64 salt_number = QRandomGenerator::system()->generate64();
|
||||||
QString salt = QStringLiteral("%1").arg(salt_number, 16, 16, QLatin1Char('0'));
|
QString salt = QStringLiteral("%1").arg(salt_number, 16, 16, QLatin1Char('0'));
|
||||||
|
|
||||||
server->db_manager->createUser(argv[0], salt, argv[1], ACLFlags.value("NONE"));
|
if (server->db_manager->createUser(argv[0], salt, argv[1], ACLFlags.value("NONE")))
|
||||||
sendServerMessage("Created user " + argv[0] + ".\nUse /addperm to modify their permissions.");
|
sendServerMessage("Created user " + argv[0] + ".\nUse /addperm to modify their permissions.");
|
||||||
|
else
|
||||||
|
sendServerMessage("Unable to create user " + argv[0] + ".\nDoes a user with that name already exist?");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::cmdListPerms(int argc, QStringList argv)
|
void AOClient::cmdListPerms(int argc, QStringList argv)
|
||||||
@ -232,7 +234,7 @@ void AOClient::cmdListPerms(int argc, QStringList argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((user_acl & ACLFlags.value("MANAGE_USERS")) == 0) {
|
if ((user_acl & ACLFlags.value("MODIFY_USERS")) == 0) {
|
||||||
sendServerMessage("You do not have permission to view other users' permissions.");
|
sendServerMessage("You do not have permission to view other users' permissions.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -297,6 +299,11 @@ void AOClient::cmdRemovePerms(int argc, QStringList argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argv[0] == "root") {
|
||||||
|
sendServerMessage("You cannot change the permissions of the root account!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (argv[1] == "SUPER") {
|
if (argv[1] == "SUPER") {
|
||||||
if (user_acl != ACLFlags.value("SUPER")) {
|
if (user_acl != ACLFlags.value("SUPER")) {
|
||||||
// This has to be checked separately, because SUPER & anything will always be truthy
|
// This has to be checked separately, because SUPER & anything will always be truthy
|
||||||
@ -327,6 +334,18 @@ void AOClient::cmdListUsers(int argc, QStringList argv)
|
|||||||
sendServerMessage("All users:\n" + users.join("\n"));
|
sendServerMessage("All users:\n" + users.join("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdLogout(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
if (!authenticated) {
|
||||||
|
sendServerMessage("You are not logged in!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
authenticated = false;
|
||||||
|
moderator_name = "";
|
||||||
|
sendServerMessage("You have been logged out.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList AOClient::buildAreaList(int area_idx)
|
QStringList AOClient::buildAreaList(int area_idx)
|
||||||
{
|
{
|
||||||
QStringList entries;
|
QStringList entries;
|
||||||
@ -335,7 +354,7 @@ QStringList AOClient::buildAreaList(int area_idx)
|
|||||||
entries.append("=== " + area_name + " ===");
|
entries.append("=== " + area_name + " ===");
|
||||||
entries.append("[" + QString::number(area->player_count) + " users][" + area->status + "]");
|
entries.append("[" + QString::number(area->player_count) + " users][" + area->status + "]");
|
||||||
for (AOClient* client : server->clients) {
|
for (AOClient* client : server->clients) {
|
||||||
if (client->current_area == area_idx && client->authenticated) {
|
if (client->current_area == area_idx && client->joined) {
|
||||||
QString char_entry = client->current_char;
|
QString char_entry = client->current_char;
|
||||||
if (char_entry == "")
|
if (char_entry == "")
|
||||||
char_entry = "Spectator";
|
char_entry = "Spectator";
|
||||||
|
@ -87,8 +87,16 @@ void DBManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned lon
|
|||||||
qDebug() << "SQL Error:" << query.lastError().text();
|
qDebug() << "SQL Error:" << query.lastError().text();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::createUser(QString username, QString salt, QString password, unsigned long long acl)
|
bool DBManager::createUser(QString username, QString salt, QString password, unsigned long long acl)
|
||||||
{
|
{
|
||||||
|
QSqlQuery username_exists;
|
||||||
|
username_exists.prepare("SELECT ACL FROM users WHERE USERNAME = ?");
|
||||||
|
username_exists.addBindValue(username);
|
||||||
|
username_exists.exec();
|
||||||
|
|
||||||
|
if (username_exists.first())
|
||||||
|
return false;
|
||||||
|
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
|
|
||||||
QString salted_password;
|
QString salted_password;
|
||||||
@ -105,6 +113,7 @@ void DBManager::createUser(QString username, QString salt, QString password, uns
|
|||||||
query.exec();
|
query.exec();
|
||||||
|
|
||||||
qDebug() << "Created user" << username << "with password" << password << "and salted with value" << salt << ": stored as" << salted_password;
|
qDebug() << "Created user" << username << "with password" << password << "and salted with value" << salt << ": stored as" << salted_password;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long DBManager::getACL(QString moderator_name)
|
unsigned long long DBManager::getACL(QString moderator_name)
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// akashi - a server for Attorney Online 2 //
|
|
||||||
// Copyright (C) 2020 scatterflower //
|
|
||||||
// //
|
|
||||||
// This program is free software: you can redistribute it and/or modify //
|
|
||||||
// it under the terms of the GNU Affero General Public License as //
|
|
||||||
// published by the Free Software Foundation, either version 3 of the //
|
|
||||||
// License, or (at your option) any later version. //
|
|
||||||
// //
|
|
||||||
// This program is distributed in the hope that it will be useful, //
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
||||||
// GNU Affero General Public License for more details. //
|
|
||||||
// //
|
|
||||||
// You should have received a copy of the GNU Affero General Public License //
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#include "include/icchatpacket.h"
|
|
||||||
|
|
||||||
ICChatPacket::ICChatPacket(AOPacket packet)
|
|
||||||
: AOPacket(packet.header, packet.contents)
|
|
||||||
{
|
|
||||||
// Perform some basic validation
|
|
||||||
if (packet.contents.length() > MAX_FIELDS || packet.contents.length() < MIN_FIELDS) {
|
|
||||||
is_valid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate information about the message
|
|
||||||
is_valid = true;
|
|
||||||
}
|
|
156
src/packets.cpp
156
src/packets.cpp
@ -108,9 +108,11 @@ void AOClient::pktCharPassword(AreaData* area, int argc, QStringList argv, AOPac
|
|||||||
void AOClient::pktSelectChar(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktSelectChar(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
bool argument_ok;
|
bool argument_ok;
|
||||||
int char_id = argv[1].toInt(&argument_ok);
|
char_id = argv[1].toInt(&argument_ok);
|
||||||
if (!argument_ok)
|
if (!argument_ok) {
|
||||||
|
char_id = -1;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (current_char != "") {
|
if (current_char != "") {
|
||||||
area->characters_taken[current_char] = false;
|
area->characters_taken[current_char] = false;
|
||||||
@ -139,9 +141,11 @@ void AOClient::pktSelectChar(AreaData* area, int argc, QStringList argv, AOPacke
|
|||||||
void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
// TODO: validate, validate, validate
|
// TODO: validate, validate, validate
|
||||||
ICChatPacket ic_packet(packet);
|
AOPacket validated_packet = validateIcPacket(packet);
|
||||||
if (ic_packet.is_valid)
|
if (validated_packet.header == "INVALID")
|
||||||
server->broadcast(ic_packet, current_area);
|
return;
|
||||||
|
|
||||||
|
server->broadcast(validated_packet, current_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
@ -229,3 +233,145 @@ void AOClient::pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
remote_ip = QHostAddress(argv[0]);
|
remote_ip = QHostAddress(argv[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AOPacket AOClient::validateIcPacket(AOPacket packet)
|
||||||
|
{
|
||||||
|
// Welcome to the super cursed server-side IC chat validation hell
|
||||||
|
|
||||||
|
// I wanted to use enums or #defines here to make the
|
||||||
|
// indicies of the args arrays more readable. But,
|
||||||
|
// in typical AO fasion, the indicies for the incoming
|
||||||
|
// and outgoing packets are different. Just RTFM.
|
||||||
|
|
||||||
|
AOPacket invalid("INVALID", {});
|
||||||
|
|
||||||
|
QStringList args;
|
||||||
|
if (current_char == "" || !joined)
|
||||||
|
// Spectators cannot use IC
|
||||||
|
return invalid;
|
||||||
|
|
||||||
|
QList<QVariant> incoming_args;
|
||||||
|
for (QString arg : packet.contents) {
|
||||||
|
incoming_args.append(QVariant(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// message type
|
||||||
|
if (incoming_args[0].toInt() == 1)
|
||||||
|
args.append("1");
|
||||||
|
else if (incoming_args[0].toInt() == 0) {
|
||||||
|
if (incoming_args[0].toString() == "chat")
|
||||||
|
args.append("chat");
|
||||||
|
else
|
||||||
|
args.append("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// preanim
|
||||||
|
args.append(incoming_args[1].toString());
|
||||||
|
|
||||||
|
// char name
|
||||||
|
if (!server->characters.contains(incoming_args[2].toString()))
|
||||||
|
return invalid;
|
||||||
|
if (current_char != incoming_args[2].toString()) {
|
||||||
|
// Selected char is different from supplied folder name
|
||||||
|
// This means the user is INI-swapped
|
||||||
|
// TODO: ini swap locking
|
||||||
|
qDebug() << "INI swap detected from " << getIpid();
|
||||||
|
}
|
||||||
|
args.append(incoming_args[2].toString());
|
||||||
|
|
||||||
|
// emote
|
||||||
|
args.append(incoming_args[3].toString());
|
||||||
|
|
||||||
|
// message text
|
||||||
|
QString incoming_msg = incoming_args[4].toString().trimmed();
|
||||||
|
if (incoming_msg == "") {
|
||||||
|
if (last_msg_blankpost)
|
||||||
|
return invalid;
|
||||||
|
last_msg_blankpost = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
last_msg_blankpost = false;
|
||||||
|
|
||||||
|
if (incoming_msg == last_message)
|
||||||
|
return invalid;
|
||||||
|
|
||||||
|
last_message = incoming_msg;
|
||||||
|
args.append(incoming_msg);
|
||||||
|
|
||||||
|
// side
|
||||||
|
// this is validated clientside so w/e
|
||||||
|
args.append(incoming_args[5].toString());
|
||||||
|
|
||||||
|
// sfx name
|
||||||
|
args.append(incoming_args[6].toString());
|
||||||
|
|
||||||
|
// emote modifier
|
||||||
|
// Now, gather round, y'all. Here is a story that is truly a microcosm of the AO dev experience.
|
||||||
|
// If this value is a 4, it will crash the client. Why? Who knows, but it does.
|
||||||
|
// Now here is the kicker: in certain versions, the client would incorrectly send a 4 here
|
||||||
|
// For a long time, by configuring the client to do a zoom with a preanim, it would send 4
|
||||||
|
// This would crash everyone else's client, and the feature had to be disabled
|
||||||
|
// But, for some reason, nobody traced the cause of this issue for many many years.
|
||||||
|
// The serverside fix is needed to ensure invalid values are not sent, because the client sucks
|
||||||
|
int emote_mod = incoming_args[7].toInt();
|
||||||
|
|
||||||
|
if (emote_mod == 4)
|
||||||
|
emote_mod = 6;
|
||||||
|
if (emote_mod != 0 && emote_mod != 1 && emote_mod != 2 && emote_mod != 5 && emote_mod != 6)
|
||||||
|
return invalid;
|
||||||
|
args.append(QString::number(emote_mod));
|
||||||
|
|
||||||
|
// char id
|
||||||
|
if (incoming_args[8].toInt() != char_id)
|
||||||
|
return invalid;
|
||||||
|
args.append(incoming_args[8].toString());
|
||||||
|
|
||||||
|
// sfx delay
|
||||||
|
args.append(incoming_args[9].toString());
|
||||||
|
|
||||||
|
// objection modifier
|
||||||
|
if (incoming_args[10].toString().contains("4")) {
|
||||||
|
// custom shout includes text metadata
|
||||||
|
args.append(incoming_args[10].toString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int obj_mod = incoming_args[10].toInt();
|
||||||
|
if (obj_mod != 0 && obj_mod != 1 && obj_mod != 2 && obj_mod != 3)
|
||||||
|
return invalid;
|
||||||
|
args.append(QString::number(obj_mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
// evidence
|
||||||
|
// TODO: add to this once evidence is implemented
|
||||||
|
args.append(incoming_args[11].toString());
|
||||||
|
|
||||||
|
// flipping
|
||||||
|
int flip = incoming_args[12].toInt();
|
||||||
|
if (flip != 0 && flip != 1)
|
||||||
|
return invalid;
|
||||||
|
args.append(QString::number(flip));
|
||||||
|
|
||||||
|
// realization
|
||||||
|
int realization = incoming_args[13].toInt();
|
||||||
|
if (realization != 0 && realization != 1)
|
||||||
|
return invalid;
|
||||||
|
args.append(QString::number(realization));
|
||||||
|
|
||||||
|
// text color
|
||||||
|
int text_color = incoming_args[14].toInt();
|
||||||
|
if (text_color != 0 && text_color != 1 && text_color != 2 && text_color != 3 && text_color != 4 && text_color != 5 && text_color != 6)
|
||||||
|
return invalid;
|
||||||
|
args.append(QString::number(text_color));
|
||||||
|
|
||||||
|
// 2.6 packet extensions
|
||||||
|
if (incoming_args.length() > 15) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.8 packet extensions
|
||||||
|
if (incoming_args.length() > 19) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return AOPacket("MS", args);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user