mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-04 22:40:05 +00:00
Implement /ban command
This commit is contained in:
parent
5e569d4324
commit
c5e08b81da
@ -845,6 +845,86 @@ void unregisterallCommand(std::string full, std::vector<std::string>& args, CNSo
|
|||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void banCommand(std::string full, std::vector<std::string>& args, CNSocket *sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Usage: /ban PlayerID [reason...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
int playerId = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid PlayerID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string reason;
|
||||||
|
if (args.size() == 2) {
|
||||||
|
reason = "no reason given";
|
||||||
|
} else {
|
||||||
|
reason = args[2];
|
||||||
|
for (int i = 3; i < args.size(); i++)
|
||||||
|
reason += " " + args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ban the account that player belongs to
|
||||||
|
if (!Database::banPlayer(playerId, reason)) {
|
||||||
|
// propagating a more descriptive error message from banPlayer() would be too much work
|
||||||
|
ChatManager::sendServerMessage(sock, "Failed to ban target player. Check server logs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "Banned target player.");
|
||||||
|
std::cout << "[INFO] " << PlayerManager::getPlayerName(plr) << " banned player " << playerId << std::endl;
|
||||||
|
|
||||||
|
// if the player is online, kick them
|
||||||
|
CNSocket *otherSock = PlayerManager::getSockFromID(playerId);
|
||||||
|
if (otherSock == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Player wasn't online. Didn't need to kick.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player *otherPlr = PlayerManager::getPlayer(otherSock);
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, pkt);
|
||||||
|
|
||||||
|
pkt.iID = otherPlr->iID;
|
||||||
|
pkt.iExitCode = 3; // "a GM has terminated your connection"
|
||||||
|
|
||||||
|
// send to target player
|
||||||
|
otherSock->sendPacket((void*)&pkt, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
|
||||||
|
|
||||||
|
// ensure that the connection has terminated
|
||||||
|
otherSock->kill();
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(otherPlr) + " was online. Kicked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void unbanCommand(std::string full, std::vector<std::string>& args, CNSocket *sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Usage: /unban PlayerID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
int playerId = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid PlayerID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Database::unbanPlayer(playerId)) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Unbanned player.");
|
||||||
|
std::cout << "[INFO] " << PlayerManager::getPlayerName(plr) << " unbanned player " << playerId << std::endl;
|
||||||
|
} else {
|
||||||
|
ChatManager::sendServerMessage(sock, "Failed to unban player. Check server logs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChatManager::init() {
|
void ChatManager::init() {
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
|
||||||
@ -873,6 +953,8 @@ void ChatManager::init() {
|
|||||||
registerCommand("players", 30, playersCommand, "print all players on the server");
|
registerCommand("players", 30, playersCommand, "print all players on the server");
|
||||||
registerCommand("summonGroup", 30, summonGroupCommand, "summon group NPCs");
|
registerCommand("summonGroup", 30, summonGroupCommand, "summon group NPCs");
|
||||||
registerCommand("summonGroupW", 30, summonGroupCommand, "permanently summon group NPCs");
|
registerCommand("summonGroupW", 30, summonGroupCommand, "permanently summon group NPCs");
|
||||||
|
registerCommand("ban", 30, banCommand, "ban the account the given PlayerID belongs to");
|
||||||
|
registerCommand("unban", 30, unbanCommand, "unban the account the given PlayerID belongs to");
|
||||||
registerCommand("whois", 50, whoisCommand, "describe nearest NPC");
|
registerCommand("whois", 50, whoisCommand, "describe nearest NPC");
|
||||||
registerCommand("lair", 50, lairUnlockCommand, "get the required mission for the nearest fusion lair");
|
registerCommand("lair", 50, lairUnlockCommand, "get the required mission for the nearest fusion lair");
|
||||||
registerCommand("hide", 100, hideCommand, "hide yourself from the global player map");
|
registerCommand("hide", 100, hideCommand, "hide yourself from the global player map");
|
||||||
|
111
src/Database.cpp
111
src/Database.cpp
@ -304,24 +304,121 @@ int Database::addAccount(std::string login, std::string password) {
|
|||||||
return sqlite3_last_insert_rowid(db);
|
return sqlite3_last_insert_rowid(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::banAccount(int accountId, int days) {
|
// NOTE: internal function; does not lock dbCrit
|
||||||
std::lock_guard<std::mutex> lock(dbCrit);
|
bool Database::banAccount(int accountId, int days, std::string& reason) {
|
||||||
|
|
||||||
const char* sql = R"(
|
const char* sql = R"(
|
||||||
UPDATE Accounts SET
|
UPDATE Accounts SET
|
||||||
BannedSince = (strftime('%s', 'now')),
|
BannedSince = (strftime('%s', 'now')),
|
||||||
BannedUntil = (strftime('%s', 'now')) + ?
|
BannedUntil = (strftime('%s', 'now')) + ?,
|
||||||
|
BanReason = ?
|
||||||
WHERE AccountID = ?;
|
WHERE AccountID = ?;
|
||||||
)";
|
)";
|
||||||
sqlite3_stmt* stmt;
|
sqlite3_stmt* stmt;
|
||||||
|
|
||||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||||
|
|
||||||
sqlite3_bind_int(stmt, 1, days * 86400); // convert days to seconds
|
sqlite3_bind_int(stmt, 1, days * 86400); // convert days to seconds
|
||||||
sqlite3_bind_int(stmt, 2, accountId);
|
sqlite3_bind_text(stmt, 2, reason.c_str(), -1, NULL);
|
||||||
|
sqlite3_bind_int(stmt, 3, accountId);
|
||||||
|
|
||||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||||
std::cout << "[WARN] Database: failed to ban player: " << sqlite3_errmsg(db) << std::endl;
|
std::cout << "[WARN] Database: failed to ban account: " << sqlite3_errmsg(db) << std::endl;
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: internal function; does not lock dbCrit
|
||||||
|
bool Database::unbanAccount(int accountId) {
|
||||||
|
const char* sql = R"(
|
||||||
|
UPDATE Accounts SET
|
||||||
|
BannedSince = 0,
|
||||||
|
BannedUntil = 0,
|
||||||
|
BanReason = ''
|
||||||
|
WHERE AccountID = ?;
|
||||||
|
)";
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
|
||||||
|
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||||
|
|
||||||
|
sqlite3_bind_int(stmt, 1, accountId);
|
||||||
|
|
||||||
|
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||||
|
std::cout << "[WARN] Database: failed to unban account: " << sqlite3_errmsg(db) << std::endl;
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expressed in days
|
||||||
|
#define THIRTY_YEARS 10957
|
||||||
|
|
||||||
|
bool Database::banPlayer(int playerId, std::string& reason) {
|
||||||
|
std::lock_guard<std::mutex> lock(dbCrit);
|
||||||
|
|
||||||
|
int accountLevel;
|
||||||
|
int accountId = getAccountIDFromPlayerID(playerId, &accountLevel);
|
||||||
|
if (accountId < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountLevel <= 30) {
|
||||||
|
std::cout << "[WARN] Cannot ban a GM." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the ban
|
||||||
|
if (!banAccount(accountId, THIRTY_YEARS, reason)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::unbanPlayer(int playerId) {
|
||||||
|
std::lock_guard<std::mutex> lock(dbCrit);
|
||||||
|
|
||||||
|
int accountId = getAccountIDFromPlayerID(playerId);
|
||||||
|
if (accountId < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return unbanAccount(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Database::getAccountIDFromPlayerID(int playerId, int *accountLevel) {
|
||||||
|
const char *sql = R"(
|
||||||
|
SELECT Players.AccountID, AccountLevel
|
||||||
|
FROM Players
|
||||||
|
JOIN Accounts ON Players.AccountID = Accounts.AccountID
|
||||||
|
WHERE PlayerID = ?;
|
||||||
|
)";
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
|
// get AccountID from PlayerID
|
||||||
|
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||||
|
sqlite3_bind_int(stmt, 1, playerId);
|
||||||
|
|
||||||
|
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||||
|
std::cout << "[WARN] Database: failed to get AccountID from PlayerID: " << sqlite3_errmsg(db) << std::endl;
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int accountId = sqlite3_column_int(stmt, 0);
|
||||||
|
|
||||||
|
// optional secondary return value, for checking GM status
|
||||||
|
if (accountLevel != nullptr)
|
||||||
|
*accountLevel = sqlite3_column_int(stmt, 1);
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
|
return accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::updateSelected(int accountId, int slot) {
|
void Database::updateSelected(int accountId, int slot) {
|
||||||
@ -1845,7 +1942,7 @@ void Database::postRaceRanking(Database::RaceRanking ranking) {
|
|||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::isCodeRedeemed (int playerId, std::string code) {
|
bool Database::isCodeRedeemed(int playerId, std::string code) {
|
||||||
std::lock_guard<std::mutex> lock(dbCrit);
|
std::lock_guard<std::mutex> lock(dbCrit);
|
||||||
|
|
||||||
const char* sql = R"(
|
const char* sql = R"(
|
||||||
|
@ -48,7 +48,12 @@ namespace Database {
|
|||||||
void findAccount(Account* account, std::string login);
|
void findAccount(Account* account, std::string login);
|
||||||
/// returns ID, 0 if something failed
|
/// returns ID, 0 if something failed
|
||||||
int addAccount(std::string login, std::string password);
|
int addAccount(std::string login, std::string password);
|
||||||
void banAccount(int accountId, int days);
|
bool banAccount(int accountId, int days, std::string& reason);
|
||||||
|
bool unbanAccount(int accountId);
|
||||||
|
bool banPlayer(int playerId, std::string& reason);
|
||||||
|
bool unbanPlayer(int playerId);
|
||||||
|
|
||||||
|
int getAccountIDFromPlayerID(int playerId, int *accountLevel=nullptr);
|
||||||
void updateSelected(int accountId, int playerId);
|
void updateSelected(int accountId, int playerId);
|
||||||
|
|
||||||
bool validateCharacter(int characterID, int userID);
|
bool validateCharacter(int characterID, int userID);
|
||||||
|
Loading…
Reference in New Issue
Block a user