123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "pc_groups.hpp"
- #include <common/showmsg.hpp>
- #include <common/socket.hpp> // set_eof
- #include <common/strlib.hpp> // strcmpi
- #include <common/utilities.hpp>
- #include "atcommand.hpp" // AtCommandType
- #include "pc.hpp" // map_session_data
- using namespace rathena;
- const std::string PlayerGroupDatabase::getDefaultLocation() {
- return std::string( conf_path ) + "/groups.yml";
- }
- bool PlayerGroupDatabase::parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands ){
- for( const auto& it : node.children() ){
- std::string command;
- c4::from_chars( it.key(), &command );
- bool allowed;
- if( !this->asBool( node, command, allowed ) ){
- return false;
- }
- if( !atcommand_exists( command.c_str() ) ){
- this->invalidWarning( it, "Unknown atcommand: %s\n", command.c_str() );
- return false;
- }
- util::tolower( command );
- if( allowed ){
- if( util::vector_exists( commands, command ) ){
- this->invalidWarning( it, "Group already has command \"%s\". Please check your data.\n", command.c_str() );
- return false;
- }else{
- commands.push_back( command );
- }
- }else{
- if( !util::vector_exists( commands, command ) ){
- this->invalidWarning( it, "Group does not have command \"%s\". Please check your data.\n", command.c_str() );
- return false;
- }else{
- util::vector_erase_if_exists( commands, command );
- }
- }
- }
- return true;
- }
- uint64 PlayerGroupDatabase::parseBodyNode( const ryml::NodeRef& node ){
- uint32 groupId;
- if( !this->asUInt32( node, "Id", groupId ) ){
- return 0;
- }
- std::shared_ptr<s_player_group> group = this->find( groupId );
- bool exists = group != nullptr;
- if( !exists ){
- if( !this->nodesExist( node, { "Name", "Level" })) {
- return 0;
- }
- group = std::make_shared<s_player_group>();
- group->id = groupId;
- group->permissions.reset();
- }
- if( this->nodeExists( node, "Name" ) ){
- std::string name;
- if( !this->asString( node, "Name", name ) ){
- return 0;
- }
- group->name = name;
- }
- if( this->nodeExists( node, "Level" ) ){
- uint32 level;
- if( !this->asUInt32( node, "Level", level ) ){
- return 0;
- }
- if (level > 99) {
- this->invalidWarning(node["Level"], "Group level %u exceeds 99, capping.\n", level);
- level = 99;
- }
- group->level = level;
- }
- if( this->nodeExists( node, "LogCommands" ) ){
- bool log;
- if( !this->asBool( node, "LogCommands", log ) ){
- return 0;
- }
- group->log_commands = log;
- }else{
- if( !exists ){
- group->log_commands = false;
- }
- }
- if( this->nodeExists( node, "Commands" ) && !this->parseCommands( node["Commands"], group->commands ) ){
- return 0;
- }
- if( this->nodeExists( node, "CharCommands" ) && !this->parseCommands( node["CharCommands"], group->char_commands ) ){
- return 0;
- }
- if( this->nodeExists( node, "Permissions" ) ){
- const auto& permissions = node["Permissions"];
- for( const auto& it : permissions ){
- std::string permission;
- c4::from_chars( it.key(), &permission );
- bool allowed;
- if( !this->asBool( permissions, permission, allowed ) ){
- return 0;
- }
- const char* str = permission.c_str();
- bool found = false;
- for( const auto& permission_name : pc_g_permission_name ){
- if( strcmpi( "all_permission", str ) == 0 ){
- if( allowed ){
- group->permissions.set();
- }else{
- group->permissions.reset();
- }
- found = true;
- break;
- }else if( strcmpi( permission_name.name, str ) == 0 ){
- if( allowed ){
- group->permissions.set( permission_name.permission );
- }else{
- group->permissions.reset( permission_name.permission );
- }
- found = true;
- break;
- }
- }
- if( !found ){
- this->invalidWarning( it, "Unknown permission: %s\n", str );
- return 0;
- }
- }
- }
- if( this->nodeExists( node, "Inherit" ) ){
- const auto& inherits = node["Inherit"];
- auto& inheritanceVector = this->inheritance[groupId];
- for( const auto& it : inherits ){
- std::string inherit;
- c4::from_chars( it.key(), &inherit );
- bool enable;
- if( !this->asBool( inherits, inherit, enable ) ){
- return 0;
- }
- util::tolower( inherit );
- if( enable ){
- if( !util::vector_exists( inheritanceVector, inherit ) ){
- inheritanceVector.push_back( inherit );
- }
- }else{
- if( !util::vector_exists( inheritanceVector, inherit ) ){
- this->invalidWarning( it, "Trying to remove inheritance of non-inherited group %s\n", inherit.c_str() );
- return 0;
- }
- util::vector_erase_if_exists( inheritanceVector, inherit );
- }
- }
- }
- if( !exists ){
- this->put( groupId, group );
- }
- return 1;
- }
- void PlayerGroupDatabase::loadingFinished(){
- static const int MAX_CYCLES = 10;
- int i;
- for( i = 0; i < MAX_CYCLES; i++ ){
- auto inheritanceIt = this->inheritance.begin();
- while( inheritanceIt != this->inheritance.end() ){
- auto& entry = *inheritanceIt;
- if( entry.second.empty() ){
- inheritanceIt = this->inheritance.erase( inheritanceIt );
- continue;
- }
- std::shared_ptr<s_player_group> group = this->find( entry.first );
- auto it = entry.second.begin();
- while( it != entry.second.end() ){
- std::string& otherName = *it;
- bool found = false;
- bool inherited = false;
- for( const auto& it : *this ){
- std::shared_ptr<s_player_group> otherGroup = it.second;
- // Copy the string
- std::string otherGroupName = otherGroup->name;
- util::tolower( otherGroupName );
- if( otherName == otherGroupName ){
- found = true;
- auto* otherGroupInheritance = util::map_find( this->inheritance, otherGroup->id );
- if( otherGroupInheritance != nullptr && !otherGroupInheritance->empty() ){
- // Try it again in the next cycle
- break;
- }
- // Inherit atcommands
- for( auto& command : otherGroup->commands ){
- if( !util::vector_exists( group->commands, command ) ){
- group->commands.push_back( command );
- }
- }
- // Inherit charcommands
- for( auto& command : otherGroup->char_commands ){
- if( !util::vector_exists( group->char_commands, command ) ){
- group->char_commands.push_back( command );
- }
- }
- // Inherit permissions
- group->permissions |= otherGroup->permissions;
- inherited = true;
- break;
- }
- }
- if( inherited ){
- it = entry.second.erase( it );
- continue;
- }else if( !found ){
- ShowError( "Inherited group \"%s\" for group id %u does not exist.\n", otherName.c_str(), group->id );
- it = entry.second.erase( it );
- continue;
- }else{
- it++;
- }
- }
- }
- if( this->inheritance.empty() ){
- break;
- }
- }
- if( i == MAX_CYCLES && !this->inheritance.empty() ){
- ShowError( "Could not process inheritance rules, check your config for cycles...\n" );
- }
- // Not needed anymore
- this->inheritance.clear();
- uint32 index = 0;
- for( auto& it : *this ){
- it.second->index = index++;
- }
- // Initialize command cache
- atcommand_db_load_groups();
- TypesafeYamlDatabase::loadingFinished();
- }
- PlayerGroupDatabase player_group_db;
- /**
- * Checks if player group can use @/#command
- * @param command Command name without @/# and params
- * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
- */
- bool s_player_group::can_use_command( const std::string& command, AtCommandType type ){
- if( this->has_permission( PC_PERM_USE_ALL_COMMANDS ) ){
- return true;
- }
- std::string command_lower = command;
- util::tolower( command_lower );
- switch( type ){
- case COMMAND_ATCOMMAND:
- return util::vector_exists( this->commands, command_lower );
- case COMMAND_CHARCOMMAND:
- return util::vector_exists( this->char_commands, command_lower );
- }
- return false;
- }
- /**
- * Load permission for player based on group id
- * @param sd Player
- */
- void pc_group_pc_load(map_session_data * sd) {
- std::shared_ptr<s_player_group> group = player_group_db.find( sd->group_id );
- if( group == nullptr ){
- ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
- sd->status.name,
- sd->status.account_id,
- sd->group_id);
- set_eof(sd->fd);
- return;
- }
- sd->group = group;
- sd->permissions = group->permissions;
- }
- /**
- * Checks if player group has a permission
- * @param permission permission to check
- */
- bool s_player_group::has_permission( e_pc_permission permission ){
- return this->permissions.test( permission );
- }
- /**
- * Checks commands used by player group should be logged
- */
- bool s_player_group::should_log_commands(){
- return this->log_commands;
- }
- /**
- * Initialize PC Groups and read config.
- */
- void do_init_pc_groups( void ){
- player_group_db.load();
- }
- /**
- * Finalize PC Groups
- */
- void do_final_pc_groups( void ){
- player_group_db.clear();
- }
- /**
- * Reload PC Groups
- * Used in @reloadatcommand
- */
- void pc_groups_reload( void ){
- player_group_db.reload();
-
- /* refresh online users permissions */
- struct s_mapiterator* iter = mapit_getallusers();
- for( map_session_data* sd = (map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (map_session_data*)mapit_next(iter) ){
- pc_group_pc_load(sd);
- }
- mapit_free(iter);
- }
|