mirror of
				https://github.com/OpenFusionProject/OpenFusion.git
				synced 2025-10-31 00:30:15 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			575754f727
			...
			02c1c681dd
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 02c1c681dd | |||
|   | 225515ec21 | ||
|   | f436108d24 | ||
|   | 47dbc6d35e | ||
|   | b780f5ee60 | ||
|   | 003186d97a | 
| @@ -83,7 +83,77 @@ static void helpCommand(std::string full, std::vector<std::string>& args, CNSock | ||||
| } | ||||
|  | ||||
| static void accessCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) { | ||||
|     Chat::sendServerMessage(sock, "Your access level is " + std::to_string(PlayerManager::getPlayer(sock)->accountLevel)); | ||||
|     if (args.size() < 2) { | ||||
|         Chat::sendServerMessage(sock, "Usage: /access <id> [new_level]"); | ||||
|         Chat::sendServerMessage(sock, "Use . for id to select yourself"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     char *tmp; | ||||
|  | ||||
|     Player* self = PlayerManager::getPlayer(sock); | ||||
|     int selfAccess = self->accountLevel; | ||||
|  | ||||
|     Player* player; | ||||
|     if (args[1].compare(".") == 0) { | ||||
|         player = self; | ||||
|     } else { | ||||
|         int id = std::strtol(args[1].c_str(), &tmp, 10); | ||||
|         if (*tmp) { | ||||
|             Chat::sendServerMessage(sock, "Invalid player ID " + args[1]); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         player = PlayerManager::getPlayerFromID(id); | ||||
|         if (player == nullptr) { | ||||
|             Chat::sendServerMessage(sock, "Could not find player with ID " + std::to_string(id)); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Messing with other players requires a baseline access of 30 | ||||
|         if (player != self && selfAccess > 30) { | ||||
|             Chat::sendServerMessage(sock, "Can't check or change other players access levels (insufficient privileges)"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string playerName = PlayerManager::getPlayerName(player); | ||||
|     int currentAccess = player->accountLevel; | ||||
|     if (args.size() < 3) { | ||||
|         // just check | ||||
|         Chat::sendServerMessage(sock, playerName + " has access level " + std::to_string(currentAccess)); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Can't change the access level of someone with stronger privileges | ||||
|     // N.B. lower value = stronger privileges | ||||
|     if (currentAccess <= selfAccess) { | ||||
|         Chat::sendServerMessage(sock, "Can't change this player's access level (insufficient privileges)"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     int newAccess = std::strtol(args[2].c_str(), &tmp, 10); | ||||
|     if (*tmp) { | ||||
|         Chat::sendServerMessage(sock, "Invalid access level " + args[2]); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Can only assign an access level weaker than yours | ||||
|     if (newAccess <= selfAccess) { | ||||
|         Chat::sendServerMessage(sock, "Can only assign privileges weaker than your own"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     player->accountLevel = newAccess; | ||||
|  | ||||
|     // Save to database | ||||
|     int accountId = Database::getAccountIdForPlayer(player->iID); | ||||
|     Database::updateAccountLevel(accountId, newAccess); | ||||
|  | ||||
|     std::string msg = "Changed access level for " + playerName + " from " + std::to_string(currentAccess) + " to " + std::to_string(newAccess); | ||||
|     if (newAccess <= 50 && currentAccess > 50) | ||||
|         msg += " (they must log out and back in for some commands to be enabled)"; | ||||
|     Chat::sendServerMessage(sock, msg); | ||||
| } | ||||
|  | ||||
| static void populationCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) { | ||||
| @@ -1200,7 +1270,7 @@ static void registerCommand(std::string cmd, int requiredLevel, CommandHandler h | ||||
|  | ||||
| void CustomCommands::init() { | ||||
|     registerCommand("help", 100, helpCommand, "list all unlocked server-side commands"); | ||||
|     registerCommand("access", 100, accessCommand, "print your access level"); | ||||
|     registerCommand("access", 100, accessCommand, "check or change access levels"); | ||||
|     registerCommand("instance", 30, instanceCommand, "print or change your current instance"); | ||||
|     registerCommand("mss", 30, mssCommand, "edit Monkey Skyway routes"); | ||||
|     registerCommand("npcr", 30, npcRotateCommand, "rotate NPCs"); | ||||
|   | ||||
| @@ -325,6 +325,13 @@ static void emailSend(CNSocket* sock, CNPacketData* data) { | ||||
|     std::string logEmail = "[Email] " + PlayerManager::getPlayerName(plr, true) + " (to " + PlayerManager::getPlayerName(&otherPlr, true) + "): <" + email.SubjectLine + ">\n" + email.MsgBody; | ||||
|     std::cout << logEmail << std::endl; | ||||
|     dump.push_back(logEmail); | ||||
|  | ||||
|     // notification to recipient if online | ||||
|     CNSocket* recipient = PlayerManager::getSockFromID(pkt->iTo_PCUID); | ||||
|     if (recipient != nullptr) | ||||
|     { | ||||
|         emailUpdateCheck(recipient, nullptr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Email::init() { | ||||
|   | ||||
| @@ -155,7 +155,7 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) { | ||||
|  * Nanos the player hasn't unlocked will (and should) be greyed out. Thus, all nanos should be accounted | ||||
|  * for in these packets, even if the player hasn't unlocked them. | ||||
|  */ | ||||
| static void sendNanoBookSubset(CNSocket *sock, Player *plr) { | ||||
| static void sendNanoBook(CNSocket *sock, Player *plr, bool resizeOnly) { | ||||
| #ifdef ACADEMY | ||||
|     int16_t id = 0; | ||||
|     INITSTRUCT(sP_FE2CL_REP_NANO_BOOK_SUBSET, pkt); | ||||
| @@ -163,6 +163,13 @@ static void sendNanoBookSubset(CNSocket *sock, Player *plr) { | ||||
|     pkt.PCUID = plr->iID; | ||||
|     pkt.bookSize = NANO_COUNT; | ||||
|  | ||||
|     if (resizeOnly) { | ||||
|         // triggers nano array resizing without | ||||
|         // actually sending nanos | ||||
|         sock->sendPacket(pkt, P_FE2CL_REP_NANO_BOOK_SUBSET); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     while (id < NANO_COUNT) { | ||||
|         pkt.elementOffset = id; | ||||
|  | ||||
| @@ -210,6 +217,7 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) { | ||||
|  | ||||
|     response.iID = plr->iID; | ||||
|     response.uiSvrTime = getTime(); | ||||
|  | ||||
|     response.PCLoadData2CL.iUserLevel = plr->accountLevel; | ||||
|     response.PCLoadData2CL.iHP = plr->HP; | ||||
|     response.PCLoadData2CL.iLevel = plr->level; | ||||
| @@ -292,14 +300,14 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) { | ||||
|     sock->setFEKey(lm->FEKey); | ||||
|     sock->setActiveKey(SOCKETKEY_FE); // send all packets using the FE key from now on | ||||
|  | ||||
|     // Academy builds receive nanos in a separate packet. These need to be sent | ||||
|     // before P_FE2CL_REP_PC_ENTER_SUCC as well as after | ||||
|     // due to a race condition in the client :( | ||||
|     sendNanoBookSubset(sock, plr); | ||||
|     // Academy builds receive nanos in a separate packet. An initial one with the size of the | ||||
|     // nano book needs to be sent before PC_ENTER_SUCC so the client can resize its nano arrays, | ||||
|     // and then proper packets with the nanos included must be sent after, while the game is loading. | ||||
|     sendNanoBook(sock, plr, true); | ||||
|  | ||||
|     sock->sendPacket(response, P_FE2CL_REP_PC_ENTER_SUCC); | ||||
|  | ||||
|     sendNanoBookSubset(sock, plr); | ||||
|     sendNanoBook(sock, plr, false); | ||||
|  | ||||
|     // transfer ownership of Player object into the shard (still valid in this function though) | ||||
|     addPlayer(sock, plr); | ||||
|   | ||||
| @@ -46,9 +46,13 @@ namespace Database { | ||||
|     void close(); | ||||
|  | ||||
|     void findAccount(Account* account, std::string login); | ||||
|     // returns ID, 0 if something failed | ||||
|  | ||||
|     // return ID, 0 if something failed | ||||
|     int getAccountIdForPlayer(int playerId); | ||||
|     int addAccount(std::string login, std::string password); | ||||
|  | ||||
|     void updateAccountLevel(int accountId, int accountLevel); | ||||
|  | ||||
|     // interface for the /ban command | ||||
|     bool banPlayer(int playerId, std::string& reason); | ||||
|     bool unbanPlayer(int playerId); | ||||
|   | ||||
| @@ -27,6 +27,32 @@ void Database::findAccount(Account* account, std::string login) { | ||||
|     sqlite3_finalize(stmt); | ||||
| } | ||||
|  | ||||
| int Database::getAccountIdForPlayer(int playerId) { | ||||
|     std::lock_guard<std::mutex> lock(dbCrit); | ||||
|  | ||||
|     const char* sql = R"( | ||||
|         SELECT AccountID | ||||
|         FROM Players | ||||
|         WHERE PlayerID = ? | ||||
|         LIMIT 1; | ||||
|         )"; | ||||
|     sqlite3_stmt* stmt; | ||||
|  | ||||
|     sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); | ||||
|     sqlite3_bind_int(stmt, 1, playerId); | ||||
|  | ||||
|     int rc = sqlite3_step(stmt); | ||||
|     if (rc != SQLITE_ROW) { | ||||
|         std::cout << "[WARN] Database: couldn't get account id for player " << playerId << std::endl; | ||||
|         sqlite3_finalize(stmt); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     int accountId = sqlite3_column_int(stmt, 0); | ||||
|     sqlite3_finalize(stmt); | ||||
|     return accountId; | ||||
| } | ||||
|  | ||||
| int Database::addAccount(std::string login, std::string password) { | ||||
|     std::lock_guard<std::mutex> lock(dbCrit); | ||||
|  | ||||
| @@ -52,6 +78,26 @@ int Database::addAccount(std::string login, std::string password) { | ||||
|     return sqlite3_last_insert_rowid(db); | ||||
| } | ||||
|  | ||||
| void Database::updateAccountLevel(int accountId, int accountLevel) { | ||||
|     std::lock_guard<std::mutex> lock(dbCrit); | ||||
|  | ||||
|     const char* sql = R"( | ||||
|         UPDATE Accounts SET | ||||
|             AccountLevel = ? | ||||
|         WHERE AccountID = ?; | ||||
|         )"; | ||||
|     sqlite3_stmt* stmt; | ||||
|  | ||||
|     sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); | ||||
|     sqlite3_bind_int(stmt, 1, accountLevel); | ||||
|     sqlite3_bind_int(stmt, 2, accountId); | ||||
|  | ||||
|     int rc = sqlite3_step(stmt); | ||||
|     if (rc != SQLITE_DONE) | ||||
|         std::cout << "[WARN] Database fail on updateAccountLevel(): " << sqlite3_errmsg(db) << std::endl; | ||||
|     sqlite3_finalize(stmt); | ||||
| } | ||||
|  | ||||
| void Database::updateSelected(int accountId, int slot) { | ||||
|     std::lock_guard<std::mutex> lock(dbCrit); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user