Merge pull request #20 from AttorneyOnline/in1tiate/commands-uwu
Add /help, /status, /forcepos, /currentmusic, /pm; 2.9 compatibility fixes
This commit is contained in:
commit
5b328859cd
@ -59,6 +59,13 @@ class AOClient : public QObject {
|
||||
QString ooc_name = "";
|
||||
QString showname = "";
|
||||
bool global_enabled = true;
|
||||
struct ClientVersion {
|
||||
QString string;
|
||||
int release = -1;
|
||||
int major = -1;
|
||||
int minor = -1;
|
||||
};
|
||||
ClientVersion version;
|
||||
|
||||
QMap<QString, unsigned long long> ACLFlags {
|
||||
{"NONE", 0ULL},
|
||||
@ -99,6 +106,7 @@ class AOClient : public QObject {
|
||||
void handleCommand(QString command, int argc, QStringList argv);
|
||||
void changeArea(int new_area);
|
||||
void changeCharacter(int char_id);
|
||||
void changePosition(QString new_pos);
|
||||
void arup(ARUPType type, bool broadcast);
|
||||
void fullArup();
|
||||
void sendServerMessage(QString message);
|
||||
@ -171,6 +179,7 @@ class AOClient : public QObject {
|
||||
|
||||
//// Commands
|
||||
void cmdDefault(int argc, QStringList argv);
|
||||
void cmdHelp(int argc, QStringList argv);
|
||||
// Authentication
|
||||
void cmdLogin(int argc, QStringList argv);
|
||||
void cmdChangeAuth(int argc, QStringList argv);
|
||||
@ -196,6 +205,8 @@ class AOClient : public QObject {
|
||||
void cmdSetBackground(int argc, QStringList argv);
|
||||
void cmdBgLock(int argc, QStringList argv);
|
||||
void cmdBgUnlock(int argc, QStringList argv);
|
||||
void cmdStatus(int argc, QStringList argv);
|
||||
void cmdCurrentMusic(int argc, QStringList argv);
|
||||
// Moderation
|
||||
void cmdMods(int argc, QStringList argv);
|
||||
void cmdBan(int argc, QStringList argv);
|
||||
@ -211,10 +222,12 @@ class AOClient : public QObject {
|
||||
void cmdTimer(int argc, QStringList argv);
|
||||
// Messaging/Client
|
||||
void cmdPos(int argc, QStringList argv);
|
||||
void cmdForcePos(int argc, QStringList argv);
|
||||
void cmdSwitch(int argc, QStringList argv);
|
||||
void cmdRandomChar(int argc, QStringList argv);
|
||||
void cmdG(int argc, QStringList argv);
|
||||
void cmdToggleGlobal(int argc, QStringList argv);
|
||||
void cmdPM(int argc, QStringList argv);
|
||||
|
||||
// Command helper functions
|
||||
QString getAreaTimer(int area_idx, QTimer* timer);
|
||||
@ -276,6 +289,11 @@ class AOClient : public QObject {
|
||||
{"switch", {ACLFlags.value("NONE"), 1, &AOClient::cmdSwitch}},
|
||||
{"toggleglobal", {ACLFlags.value("NONE"), 0, &AOClient::cmdToggleGlobal}},
|
||||
{"mods", {ACLFlags.value("NONE"), 0, &AOClient::cmdMods}},
|
||||
{"help", {ACLFlags.value("NONE"), 0, &AOClient::cmdHelp}},
|
||||
{"status", {ACLFlags.value("NONE"), 1, &AOClient::cmdStatus}},
|
||||
{"forcepos", {ACLFlags.value("CM"), 2, &AOClient::cmdForcePos}},
|
||||
{"currentmusic", {ACLFlags.value("NONE"), 0, &AOClient::cmdCurrentMusic}},
|
||||
{"pm", {ACLFlags.value("NONE"), 2, &AOClient::cmdPM}},
|
||||
};
|
||||
|
||||
QString partial_packet;
|
||||
|
@ -28,7 +28,8 @@
|
||||
#include <QElapsedTimer>
|
||||
|
||||
class Logger;
|
||||
class AreaData {
|
||||
class AreaData : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AreaData(QStringList p_characters, QString p_name, int p_index);
|
||||
|
||||
@ -43,7 +44,16 @@ class AreaData {
|
||||
QMap<QString, bool> characters_taken;
|
||||
QList<Evidence> evidence;
|
||||
int player_count;
|
||||
QString status;
|
||||
enum Status {
|
||||
IDLE,
|
||||
RP,
|
||||
CASING,
|
||||
LOOKING_FOR_PLAYERS,
|
||||
RECESS,
|
||||
GAMING
|
||||
};
|
||||
Q_ENUM(Status);
|
||||
Status status;
|
||||
QList<int> owners;
|
||||
QList<int> invited;
|
||||
enum LockStatus {
|
||||
@ -51,6 +61,7 @@ class AreaData {
|
||||
LOCKED,
|
||||
SPECTATABLE
|
||||
};
|
||||
Q_ENUM(LockStatus);
|
||||
LockStatus locked;
|
||||
QString background;
|
||||
bool is_protected;
|
||||
@ -60,6 +71,8 @@ class AreaData {
|
||||
QString document;
|
||||
int def_hp;
|
||||
int pro_hp;
|
||||
QString current_music;
|
||||
QString music_played_by;
|
||||
Logger* logger;
|
||||
};
|
||||
|
||||
|
@ -193,6 +193,13 @@ void AOClient::changeCharacter(int char_id)
|
||||
}
|
||||
}
|
||||
|
||||
void AOClient::changePosition(QString new_pos)
|
||||
{
|
||||
pos = new_pos;
|
||||
sendServerMessage("Position changed to " + pos + ".");
|
||||
sendPacket("SP", {pos});
|
||||
}
|
||||
|
||||
void AOClient::handleCommand(QString command, int argc, QStringList argv)
|
||||
{
|
||||
CommandInfo info = commands.value(command, {false, -1, &AOClient::cmdDefault});
|
||||
@ -215,42 +222,38 @@ void AOClient::arup(ARUPType type, bool broadcast)
|
||||
QStringList arup_data;
|
||||
arup_data.append(QString::number(type));
|
||||
for (AreaData* area : server->areas) {
|
||||
if (type == ARUPType::PLAYER_COUNT) {
|
||||
arup_data.append(QString::number(area->player_count));
|
||||
}
|
||||
else if (type == ARUPType::STATUS) {
|
||||
arup_data.append(area->status);
|
||||
}
|
||||
else if (type == ARUPType::CM) {
|
||||
if (area->owners.isEmpty())
|
||||
arup_data.append("FREE");
|
||||
else {
|
||||
QStringList area_owners;
|
||||
for (int owner_id : area->owners) {
|
||||
AOClient* owner = server->getClientByID(owner_id);
|
||||
area_owners.append("[" + QString::number(owner->id) + "] " + owner->current_char);
|
||||
switch(type) {
|
||||
case ARUPType::PLAYER_COUNT: {
|
||||
arup_data.append(QString::number(area->player_count));
|
||||
break;
|
||||
}
|
||||
case ARUPType::STATUS: {
|
||||
QString area_status = QVariant::fromValue(area->status).toString().replace("_", "-"); // LOOKING_FOR_PLAYERS to LOOKING-FOR-PLAYERS
|
||||
arup_data.append(area_status);
|
||||
break;
|
||||
}
|
||||
case ARUPType::CM: {
|
||||
if (area->owners.isEmpty())
|
||||
arup_data.append("FREE");
|
||||
else {
|
||||
QStringList area_owners;
|
||||
for (int owner_id : area->owners) {
|
||||
AOClient* owner = server->getClientByID(owner_id);
|
||||
area_owners.append("[" + QString::number(owner->id) + "] " + owner->current_char);
|
||||
}
|
||||
arup_data.append(area_owners.join(", "));
|
||||
}
|
||||
arup_data.append(area_owners.join(", "));
|
||||
break;
|
||||
}
|
||||
case ARUPType::LOCKED: {
|
||||
QString lock_status = QVariant::fromValue(area->locked).toString();
|
||||
arup_data.append(lock_status);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (type == ARUPType::LOCKED) {
|
||||
QString lock_status;
|
||||
switch (area->locked) {
|
||||
case AreaData::LockStatus::FREE:
|
||||
lock_status = "FREE";
|
||||
break;
|
||||
case AreaData::LockStatus::LOCKED:
|
||||
lock_status = "LOCKED";
|
||||
break;
|
||||
case AreaData::LockStatus::SPECTATABLE:
|
||||
lock_status = "SPECTATABLE";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
arup_data.append(lock_status);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
if (broadcast)
|
||||
server->broadcast(AOPacket("ARUP", arup_data));
|
||||
|
@ -33,7 +33,7 @@ AreaData::AreaData(QStringList characters, QString p_name, int p_index)
|
||||
areas_ini.endGroup();
|
||||
player_count = 0;
|
||||
locked = FREE;
|
||||
status = "FREE";
|
||||
status = IDLE;
|
||||
def_hp = 10;
|
||||
pro_hp = 10;
|
||||
document = "No document.";
|
||||
|
119
src/commands.cpp
119
src/commands.cpp
@ -364,8 +364,42 @@ void AOClient::cmdLogout(int argc, QStringList argv)
|
||||
|
||||
void AOClient::cmdPos(int argc, QStringList argv)
|
||||
{
|
||||
pos = argv[0];
|
||||
sendServerMessage("Position changed to " + pos + ".");
|
||||
changePosition(argv[0]);
|
||||
}
|
||||
|
||||
void AOClient::cmdForcePos(int argc, QStringList argv)
|
||||
{
|
||||
bool ok;
|
||||
QList<AOClient*> targets;
|
||||
AreaData* area = server->areas[current_area];
|
||||
int target_id = argv[1].toInt(&ok);
|
||||
int forced_clients = 0;
|
||||
if (!ok && argv[1] != "*") {
|
||||
sendServerMessage("That does not look like a valid ID.");
|
||||
return;
|
||||
}
|
||||
else if (ok) {
|
||||
AOClient* target_client = server->getClientByID(target_id);
|
||||
if (target_client != nullptr)
|
||||
targets.append(target_client);
|
||||
else {
|
||||
sendServerMessage("Target ID not found!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if (argv[1] == "*") { // force all clients in the area
|
||||
for (AOClient* client : server->clients) {
|
||||
if (client->current_area == current_area)
|
||||
targets.append(client);
|
||||
}
|
||||
}
|
||||
for (AOClient* target : targets) {
|
||||
target->sendServerMessage("Position forcibly changed by CM.");
|
||||
target->changePosition(argv[0]);
|
||||
forced_clients++;
|
||||
}
|
||||
sendServerMessage("Forced " + QString::number(forced_clients) + " into pos " + argv[0] + ".");
|
||||
}
|
||||
|
||||
void AOClient::cmdG(int argc, QStringList argv)
|
||||
@ -483,6 +517,10 @@ void AOClient::cmdInvite(int argc, QStringList argv)
|
||||
sendServerMessage("That does not look like a valid ID.");
|
||||
return;
|
||||
}
|
||||
else if (server->getClientByID(invited_id) == nullptr) {
|
||||
sendServerMessage("No client with that ID found.");
|
||||
return;
|
||||
}
|
||||
else if (area->invited.contains(invited_id)) {
|
||||
sendServerMessage("That ID is already on the invite list.");
|
||||
return;
|
||||
@ -500,6 +538,10 @@ void AOClient::cmdUnInvite(int argc, QStringList argv)
|
||||
sendServerMessage("That does not look like a valid ID.");
|
||||
return;
|
||||
}
|
||||
else if (server->getClientByID(uninvited_id) == nullptr) {
|
||||
sendServerMessage("No client with that ID found.");
|
||||
return;
|
||||
}
|
||||
else if (area->owners.contains(uninvited_id)) {
|
||||
sendServerMessage("You cannot uninvite a CM!");
|
||||
return;
|
||||
@ -653,7 +695,11 @@ void AOClient::cmdArea(int argc, QStringList argv)
|
||||
|
||||
void AOClient::cmdPlay(int argc, QStringList argv)
|
||||
{
|
||||
sendPacket("MC", {argv.join(" "), QString::number(server->getCharID(current_char)), showname, "1", "0"});
|
||||
AreaData* area = server->areas[current_area];
|
||||
QString song = argv.join(" ");
|
||||
area->current_music = song;
|
||||
area->music_played_by = showname;
|
||||
sendPacket("MC", {song, QString::number(server->getCharID(current_char)), showname, "1", "0"});
|
||||
}
|
||||
|
||||
void AOClient::cmdAreaKick(int argc, QStringList argv)
|
||||
@ -665,6 +711,10 @@ void AOClient::cmdAreaKick(int argc, QStringList argv)
|
||||
return;
|
||||
}
|
||||
AOClient* client_to_kick = server->getClientByID(idx);
|
||||
if (client_to_kick == nullptr) {
|
||||
sendServerMessage("No client with that ID found.");
|
||||
return;
|
||||
}
|
||||
client_to_kick->changeArea(0);
|
||||
sendServerMessage("Client " + argv[0] + " kicked back to area 0.");
|
||||
}
|
||||
@ -716,6 +766,69 @@ void AOClient::cmdMods(int argc, QStringList argv)
|
||||
sendServerMessage(entries.join("\n"));
|
||||
}
|
||||
|
||||
void AOClient::cmdHelp(int argc, QStringList argv)
|
||||
{
|
||||
QStringList entries;
|
||||
entries << "Allowed commands:";
|
||||
QMap<QString, CommandInfo>::const_iterator i;
|
||||
for (i = commands.constBegin(); i!= commands.constEnd(); ++i) {
|
||||
CommandInfo info = i.value();
|
||||
if (checkAuth(info.acl_mask)) { // if we are allowed to use this command
|
||||
entries << "/" + i.key();
|
||||
}
|
||||
}
|
||||
sendServerMessage(entries.join("\n"));
|
||||
}
|
||||
|
||||
void AOClient::cmdStatus(int argc, QStringList argv)
|
||||
{
|
||||
AreaData* area = server->areas[current_area];
|
||||
QString arg = argv[0].toLower();
|
||||
if (arg == "idle")
|
||||
area->status = AreaData::IDLE;
|
||||
else if (arg == "rp")
|
||||
area->status = AreaData::RP;
|
||||
else if (arg == "casing")
|
||||
area->status = AreaData::CASING;
|
||||
else if (arg == "looking-for-players" || arg == "lfp")
|
||||
area->status = AreaData::LOOKING_FOR_PLAYERS;
|
||||
else if (arg == "recess")
|
||||
area->status = AreaData::RECESS;
|
||||
else if (arg == "gaming")
|
||||
area->status = AreaData::GAMING;
|
||||
else {
|
||||
sendServerMessage("That does not look like a valid status. Valid statuses are idle, rp, casing, lfp, recess, gaming");
|
||||
return;
|
||||
}
|
||||
arup(ARUPType::STATUS, true);
|
||||
}
|
||||
|
||||
void AOClient::cmdCurrentMusic(int argc, QStringList argv)
|
||||
{
|
||||
AreaData* area = server->areas[current_area];
|
||||
if (area->current_music != "" && area->current_music != "~stop.mp3") // dummy track for stopping music
|
||||
sendServerMessage("The current song is " + area->current_music + " played by " + area->music_played_by);
|
||||
else
|
||||
sendServerMessage("There is no music playing.");
|
||||
}
|
||||
|
||||
void AOClient::cmdPM(int arc, QStringList argv)
|
||||
{
|
||||
bool ok;
|
||||
int target_id = argv.takeFirst().toInt(&ok); // using takeFirst removes the ID from our list of arguments...
|
||||
if (!ok) {
|
||||
sendServerMessage("That does not look like a valid ID.");
|
||||
return;
|
||||
}
|
||||
AOClient* target_client = server->getClientByID(target_id);
|
||||
if (target_client == nullptr) {
|
||||
sendServerMessage("No client with that ID found.");
|
||||
return;
|
||||
}
|
||||
QString message = argv.join(" "); //...which means it will not end up as part of the message
|
||||
target_client->sendServerMessage("Message from " + ooc_name + " (" + QString::number(id) + "): " + message);
|
||||
}
|
||||
|
||||
QStringList AOClient::buildAreaList(int area_idx)
|
||||
{
|
||||
QStringList entries;
|
||||
|
@ -54,6 +54,30 @@ void AOClient::pktSoftwareId(AreaData* area, int argc, QStringList argv, AOPacke
|
||||
"y_offset"
|
||||
};
|
||||
|
||||
|
||||
// Extremely cursed client version string validation
|
||||
// Ideally version strings should be X.X.X but it can be literally anything
|
||||
// so we have to be super careful
|
||||
version.string = argv[1];
|
||||
QStringList version_raw = version.string.split(".");
|
||||
bool ok;
|
||||
int release_version = version_raw[0].toInt(&ok);
|
||||
if (ok && version_raw.size() >= 1)
|
||||
version.release = release_version;
|
||||
if (ok && version_raw.size() >= 2) {
|
||||
int major_version = version_raw[1].toInt(&ok);
|
||||
if (ok)
|
||||
version.major = major_version;
|
||||
}
|
||||
if (ok && version_raw.size() >= 3) {
|
||||
int minor_version = version_raw[2].toInt(&ok);
|
||||
if (ok)
|
||||
version.minor = minor_version;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sendPacket("PN", {QString::number(server->player_count), max_players});
|
||||
sendPacket("FL", feature_list);
|
||||
}
|
||||
@ -177,9 +201,11 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack
|
||||
QString argument = argv[0];
|
||||
|
||||
for (QString song : server->music_list) {
|
||||
if (song == argument) {
|
||||
if (song == argument || song == "~stop.mp3") { // ~stop.mp3 is a dummy track used by 2.9+
|
||||
// We have a song here
|
||||
AOPacket music_change("MC", {song, argv[1], argv[2], "1", "0", argv[3]});
|
||||
area->current_music = song;
|
||||
area->music_played_by = argv[2];
|
||||
server->broadcast(music_change, current_area);
|
||||
return;
|
||||
}
|
||||
@ -454,8 +480,17 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
|
||||
|
||||
// self offset
|
||||
offset = incoming_args[17].toString();
|
||||
args.append(offset);
|
||||
args.append(other_offset);
|
||||
// versions 2.6-2.8 cannot validate y-offset so we send them just the x-offset
|
||||
if ((version.release == 2) && (version.major == 6 || version.major == 7 || version.major == 8)) {
|
||||
QString x_offset = offset.split("&")[0];
|
||||
args.append(x_offset);
|
||||
QString other_x_offset = other_offset.split("&")[0];
|
||||
args.append(other_x_offset);
|
||||
}
|
||||
else {
|
||||
args.append(offset);
|
||||
args.append(other_offset);
|
||||
}
|
||||
args.append(other_flip);
|
||||
|
||||
// noninterrupting preanim
|
||||
|
Loading…
Reference in New Issue
Block a user