pc_groups.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "pc_groups.hpp"
  4. #include <common/showmsg.hpp>
  5. #include <common/socket.hpp> // set_eof
  6. #include <common/strlib.hpp> // strcmpi
  7. #include <common/utilities.hpp>
  8. #include "atcommand.hpp" // AtCommandType
  9. #include "pc.hpp" // map_session_data
  10. using namespace rathena;
  11. const std::string PlayerGroupDatabase::getDefaultLocation() {
  12. return std::string( conf_path ) + "/groups.yml";
  13. }
  14. bool PlayerGroupDatabase::parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands ){
  15. for( const auto& it : node.children() ){
  16. std::string command;
  17. c4::from_chars( it.key(), &command );
  18. bool allowed;
  19. if( !this->asBool( node, command, allowed ) ){
  20. return false;
  21. }
  22. if( !atcommand_exists( command.c_str() ) ){
  23. this->invalidWarning( it, "Unknown atcommand: %s\n", command.c_str() );
  24. return false;
  25. }
  26. util::tolower( command );
  27. if( allowed ){
  28. if( util::vector_exists( commands, command ) ){
  29. this->invalidWarning( it, "Group already has command \"%s\". Please check your data.\n", command.c_str() );
  30. return false;
  31. }else{
  32. commands.push_back( command );
  33. }
  34. }else{
  35. if( !util::vector_exists( commands, command ) ){
  36. this->invalidWarning( it, "Group does not have command \"%s\". Please check your data.\n", command.c_str() );
  37. return false;
  38. }else{
  39. util::vector_erase_if_exists( commands, command );
  40. }
  41. }
  42. }
  43. return true;
  44. }
  45. uint64 PlayerGroupDatabase::parseBodyNode( const ryml::NodeRef& node ){
  46. uint32 groupId;
  47. if( !this->asUInt32( node, "Id", groupId ) ){
  48. return 0;
  49. }
  50. std::shared_ptr<s_player_group> group = this->find( groupId );
  51. bool exists = group != nullptr;
  52. if( !exists ){
  53. if( !this->nodesExist( node, { "Name", "Level" })) {
  54. return 0;
  55. }
  56. group = std::make_shared<s_player_group>();
  57. group->id = groupId;
  58. group->permissions.reset();
  59. }
  60. if( this->nodeExists( node, "Name" ) ){
  61. std::string name;
  62. if( !this->asString( node, "Name", name ) ){
  63. return 0;
  64. }
  65. group->name = name;
  66. }
  67. if( this->nodeExists( node, "Level" ) ){
  68. uint32 level;
  69. if( !this->asUInt32( node, "Level", level ) ){
  70. return 0;
  71. }
  72. if (level > 99) {
  73. this->invalidWarning(node["Level"], "Group level %u exceeds 99, capping.\n", level);
  74. level = 99;
  75. }
  76. group->level = level;
  77. }
  78. if( this->nodeExists( node, "LogCommands" ) ){
  79. bool log;
  80. if( !this->asBool( node, "LogCommands", log ) ){
  81. return 0;
  82. }
  83. group->log_commands = log;
  84. }else{
  85. if( !exists ){
  86. group->log_commands = false;
  87. }
  88. }
  89. if( this->nodeExists( node, "Commands" ) && !this->parseCommands( node["Commands"], group->commands ) ){
  90. return 0;
  91. }
  92. if( this->nodeExists( node, "CharCommands" ) && !this->parseCommands( node["CharCommands"], group->char_commands ) ){
  93. return 0;
  94. }
  95. if( this->nodeExists( node, "Permissions" ) ){
  96. const auto& permissions = node["Permissions"];
  97. for( const auto& it : permissions ){
  98. std::string permission;
  99. c4::from_chars( it.key(), &permission );
  100. bool allowed;
  101. if( !this->asBool( permissions, permission, allowed ) ){
  102. return 0;
  103. }
  104. const char* str = permission.c_str();
  105. bool found = false;
  106. for( const auto& permission_name : pc_g_permission_name ){
  107. if( strcmpi( "all_permission", str ) == 0 ){
  108. if( allowed ){
  109. group->permissions.set();
  110. }else{
  111. group->permissions.reset();
  112. }
  113. found = true;
  114. break;
  115. }else if( strcmpi( permission_name.name, str ) == 0 ){
  116. if( allowed ){
  117. group->permissions.set( permission_name.permission );
  118. }else{
  119. group->permissions.reset( permission_name.permission );
  120. }
  121. found = true;
  122. break;
  123. }
  124. }
  125. if( !found ){
  126. this->invalidWarning( it, "Unknown permission: %s\n", str );
  127. return 0;
  128. }
  129. }
  130. }
  131. if( this->nodeExists( node, "Inherit" ) ){
  132. const auto& inherits = node["Inherit"];
  133. auto& inheritanceVector = this->inheritance[groupId];
  134. for( const auto& it : inherits ){
  135. std::string inherit;
  136. c4::from_chars( it.key(), &inherit );
  137. bool enable;
  138. if( !this->asBool( inherits, inherit, enable ) ){
  139. return 0;
  140. }
  141. util::tolower( inherit );
  142. if( enable ){
  143. if( !util::vector_exists( inheritanceVector, inherit ) ){
  144. inheritanceVector.push_back( inherit );
  145. }
  146. }else{
  147. if( !util::vector_exists( inheritanceVector, inherit ) ){
  148. this->invalidWarning( it, "Trying to remove inheritance of non-inherited group %s\n", inherit.c_str() );
  149. return 0;
  150. }
  151. util::vector_erase_if_exists( inheritanceVector, inherit );
  152. }
  153. }
  154. }
  155. if( !exists ){
  156. this->put( groupId, group );
  157. }
  158. return 1;
  159. }
  160. void PlayerGroupDatabase::loadingFinished(){
  161. static const int MAX_CYCLES = 10;
  162. int i;
  163. for( i = 0; i < MAX_CYCLES; i++ ){
  164. auto inheritanceIt = this->inheritance.begin();
  165. while( inheritanceIt != this->inheritance.end() ){
  166. auto& entry = *inheritanceIt;
  167. if( entry.second.empty() ){
  168. inheritanceIt = this->inheritance.erase( inheritanceIt );
  169. continue;
  170. }
  171. std::shared_ptr<s_player_group> group = this->find( entry.first );
  172. auto it = entry.second.begin();
  173. while( it != entry.second.end() ){
  174. std::string& otherName = *it;
  175. bool found = false;
  176. bool inherited = false;
  177. for( const auto& it : *this ){
  178. std::shared_ptr<s_player_group> otherGroup = it.second;
  179. // Copy the string
  180. std::string otherGroupName = otherGroup->name;
  181. util::tolower( otherGroupName );
  182. if( otherName == otherGroupName ){
  183. found = true;
  184. auto* otherGroupInheritance = util::map_find( this->inheritance, otherGroup->id );
  185. if( otherGroupInheritance != nullptr && !otherGroupInheritance->empty() ){
  186. // Try it again in the next cycle
  187. break;
  188. }
  189. // Inherit atcommands
  190. for( auto& command : otherGroup->commands ){
  191. if( !util::vector_exists( group->commands, command ) ){
  192. group->commands.push_back( command );
  193. }
  194. }
  195. // Inherit charcommands
  196. for( auto& command : otherGroup->char_commands ){
  197. if( !util::vector_exists( group->char_commands, command ) ){
  198. group->char_commands.push_back( command );
  199. }
  200. }
  201. // Inherit permissions
  202. group->permissions |= otherGroup->permissions;
  203. inherited = true;
  204. break;
  205. }
  206. }
  207. if( inherited ){
  208. it = entry.second.erase( it );
  209. continue;
  210. }else if( !found ){
  211. ShowError( "Inherited group \"%s\" for group id %u does not exist.\n", otherName.c_str(), group->id );
  212. it = entry.second.erase( it );
  213. continue;
  214. }else{
  215. it++;
  216. }
  217. }
  218. }
  219. if( this->inheritance.empty() ){
  220. break;
  221. }
  222. }
  223. if( i == MAX_CYCLES && !this->inheritance.empty() ){
  224. ShowError( "Could not process inheritance rules, check your config for cycles...\n" );
  225. }
  226. // Not needed anymore
  227. this->inheritance.clear();
  228. uint32 index = 0;
  229. for( auto& it : *this ){
  230. it.second->index = index++;
  231. }
  232. // Initialize command cache
  233. atcommand_db_load_groups();
  234. TypesafeYamlDatabase::loadingFinished();
  235. }
  236. PlayerGroupDatabase player_group_db;
  237. /**
  238. * Checks if player group can use @/#command
  239. * @param command Command name without @/# and params
  240. * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
  241. */
  242. bool s_player_group::can_use_command( const std::string& command, AtCommandType type ){
  243. if( this->has_permission( PC_PERM_USE_ALL_COMMANDS ) ){
  244. return true;
  245. }
  246. std::string command_lower = command;
  247. util::tolower( command_lower );
  248. switch( type ){
  249. case COMMAND_ATCOMMAND:
  250. return util::vector_exists( this->commands, command_lower );
  251. case COMMAND_CHARCOMMAND:
  252. return util::vector_exists( this->char_commands, command_lower );
  253. }
  254. return false;
  255. }
  256. /**
  257. * Load permission for player based on group id
  258. * @param sd Player
  259. */
  260. void pc_group_pc_load(map_session_data * sd) {
  261. std::shared_ptr<s_player_group> group = player_group_db.find( sd->group_id );
  262. if( group == nullptr ){
  263. ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
  264. sd->status.name,
  265. sd->status.account_id,
  266. sd->group_id);
  267. set_eof(sd->fd);
  268. return;
  269. }
  270. sd->group = group;
  271. sd->permissions = group->permissions;
  272. }
  273. /**
  274. * Checks if player group has a permission
  275. * @param permission permission to check
  276. */
  277. bool s_player_group::has_permission( e_pc_permission permission ){
  278. return this->permissions.test( permission );
  279. }
  280. /**
  281. * Checks commands used by player group should be logged
  282. */
  283. bool s_player_group::should_log_commands(){
  284. return this->log_commands;
  285. }
  286. /**
  287. * Initialize PC Groups and read config.
  288. */
  289. void do_init_pc_groups( void ){
  290. player_group_db.load();
  291. }
  292. /**
  293. * Finalize PC Groups
  294. */
  295. void do_final_pc_groups( void ){
  296. player_group_db.clear();
  297. }
  298. /**
  299. * Reload PC Groups
  300. * Used in @reloadatcommand
  301. */
  302. void pc_groups_reload( void ){
  303. player_group_db.reload();
  304. /* refresh online users permissions */
  305. struct s_mapiterator* iter = mapit_getallusers();
  306. for( map_session_data* sd = (map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (map_session_data*)mapit_next(iter) ){
  307. pc_group_pc_load(sd);
  308. }
  309. mapit_free(iter);
  310. }