From e7750ecfff5bf856ecc9f38ea327c6b6cc535761 Mon Sep 17 00:00:00 2001 From: Piotr HaƂaczkiewicz Date: Wed, 24 Jul 2013 12:41:50 +0200 Subject: Permission cache overhaul * Reworked group permission caching in session data (follow-up to cd45c30ab2dcc44bfbfac283d15bb09b3d4644bc) * Removed duplicated information from session data in favor of direct pointer to group settings. * Added getters for all group data required to process permissions and related stuff. * Added new functions to PC interface and updated calls everywhere. * Extracted function to set new group for a player (used at login, group config reload, manual adjustment of group). * Moved command permission config parsing to atcommand module. * Improved dummy map session handling. * Since it's required for all map sessions to have a valid group, dummy sessions are now created by a designated function. * Updated related code that uses dummy sessions (console `gm use` and script `atcommand`, `useatcmd`). * Various minor improvements and cleanups. * Eliminated some global variables related to loading atcommand permissions for group by passing them directly to function. * Moved definition of global array holding PC permission names from header file to source file. * Streamlined destuction of atcommands database to use DBApply helper function instead of DBIterator. * Replaced hardcoded position of console dummy session with defines from mapindex.h (thx Haruna for pointing it out). * Removed fixed length restriction on group names. --- src/common/conf.c | 2 +- src/common/conf.h | 2 +- src/common/showmsg.c | 2 +- src/common/showmsg.h | 2 +- src/map/atcommand.c | 227 +++++++++++++++++++++++++++------------------- src/map/atcommand.h | 5 +- src/map/battle.c | 4 +- src/map/chat.c | 4 +- src/map/clif.c | 12 +-- src/map/intif.c | 2 +- src/map/log.c | 2 +- src/map/map.c | 27 +++--- src/map/party.c | 2 +- src/map/pc.c | 88 ++++++++++++++---- src/map/pc.h | 24 ++--- src/map/pc_groups.c | 247 ++++++++++++++++++++++++--------------------------- src/map/pc_groups.h | 84 ++++++++---------- src/map/pet.c | 2 +- src/map/script.c | 30 +++---- src/map/skill.c | 8 +- 20 files changed, 426 insertions(+), 350 deletions(-) diff --git a/src/common/conf.c b/src/common/conf.c index 3057bd4dc..6802f728b 100644 --- a/src/common/conf.c +++ b/src/common/conf.c @@ -2,7 +2,7 @@ // For more information, see LICENCE in the main folder #include "conf.h" -#include "libconfig.h" +#include "../../3rdparty/libconfig/libconfig.h" #include "../common/showmsg.h" // ShowError diff --git a/src/common/conf.h b/src/common/conf.h index 666853ba6..d223505db 100644 --- a/src/common/conf.h +++ b/src/common/conf.h @@ -5,7 +5,7 @@ #define _CONF_H_ #include "../common/cbasetypes.h" -#include "libconfig.h" +#include "../../3rdparty/libconfig/libconfig.h" int conf_read_file(config_t *config, const char *config_filename); int config_setting_copy(config_setting_t *parent, const config_setting_t *src); diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 2a3146d35..9e0f63003 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -13,7 +13,7 @@ #include #include // atexit -#include "libconfig.h" +#include "../../3rdparty/libconfig/libconfig.h" #ifdef WIN32 #include "../common/winapi.h" diff --git a/src/common/showmsg.h b/src/common/showmsg.h index a88985770..59a0d9538 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -6,7 +6,7 @@ #define _SHOWMSG_H_ #ifndef _HPMi_H_ - #include "libconfig.h" + #include "../../3rdparty/libconfig/libconfig.h" #endif // for help with the console colors look here: // http://www.edoceo.com/liberum/?doc=printf-with-color diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 74dc04889..8fd9e6043 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -418,11 +418,11 @@ ACMD(mapmove) if (!iMap->search_freecell(NULL, m, &x, &y, 10, 10, 1)) x = y = 0; //Invalid cell, use random spot. } - if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (map[m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(247)); return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); return false; } @@ -453,7 +453,7 @@ ACMD(where) pl_sd = iMap->nick2sd(atcmd_player_name); if (pl_sd == NULL || strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || - (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > pc->get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + (pc->has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > pc->get_group_level(sd) && !pc->has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) ) { clif->message(fd, msg_txt(3)); // Character not found. return false; @@ -485,13 +485,13 @@ ACMD(jumpto) return false; } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(247)); // You are not authorized to warp to this map. return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; @@ -523,7 +523,7 @@ ACMD(jump) sscanf(message, "%hd %hd", &x, &y); - if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (map[sd->bl.m].flag.noteleport && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; } @@ -587,7 +587,7 @@ ACMD(who) iter = mapit_getallusers(); for (pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter)) { - if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc->get_group_level(pl_sd) > level)) { // you can look only lower or same level + if (!((pc->has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc->get_group_level(pl_sd) > level)) { // you can look only lower or same level if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive || (map_id >= 0 && pl_sd->bl.m != map_id)) continue; @@ -595,17 +595,17 @@ ACMD(who) case 2: { StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pc_group_get_name(pl_sd->group)); // "(%s) " StrBuf->Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, pc->job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" break; } case 3: { - if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + if (pc->has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) StrBuf->Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pc_group_get_name(pl_sd->group)); // "(%s) " StrBuf->Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" break; } @@ -615,7 +615,7 @@ ACMD(who) StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pc_group_get_name(pl_sd->group)); // "(%s) " if (p != NULL) StrBuf->Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" if (g != NULL) @@ -764,11 +764,11 @@ ACMD(load) nullpo_retr(-1, sd); m = iMap->mapindex2mapid(sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (m >= 0 && map[m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(249)); // You are not authorized to warp to your save map. return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; } @@ -1866,11 +1866,11 @@ ACMD(go) if (town >= 0 && town < ARRAYLENGTH(data)) { m = iMap->mapname2mapid(data[town].map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (m >= 0 && map[m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(247)); return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); return false; } @@ -2714,11 +2714,11 @@ ACMD(recall) { return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. return false; } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. return false; } @@ -3425,7 +3425,7 @@ ACMD(recallall) memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. return false; } @@ -3438,7 +3438,7 @@ ACMD(recallall) { if (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y) continue; // Don't waste time warping the character to the same place. - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else { if (pc_isdead(pl_sd)) { //Wake them up @@ -3480,7 +3480,7 @@ ACMD(guildrecall) return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. return false; } @@ -3501,7 +3501,7 @@ ACMD(guildrecall) { if (pc->get_group_level(pl_sd) > pc->get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) continue; // Skip GMs greater than you... or chars already on the cell - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else pc->setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); @@ -3539,7 +3539,7 @@ ACMD(partyrecall) return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. return false; } @@ -3560,7 +3560,7 @@ ACMD(partyrecall) { if (pc->get_group_level(pl_sd) > pc->get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) continue; // Skip GMs greater than you... or chars already on the cell - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else pc->setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); @@ -6394,13 +6394,11 @@ ACMD(adjgroup) return false; } - if (!pc_group_exists(new_group)) { + if (pc->set_group(sd, new_group) != 0) { clif->message(fd, msg_txt(1227)); // Specified group does not exist. return false; } - - sd->group_id = new_group; - pc_group_pc_load(sd);/* update cache */ + clif->message(fd, msg_txt(1228)); // Group changed successfully. clif->message(sd->fd, msg_txt(1229)); // Your group has changed. return true; @@ -6771,7 +6769,7 @@ ACMD(showmobs) return true; } - if(mob_db(mob_id)->status.mode&MD_BOSS && !pc_has_permission(sd, PC_PERM_SHOW_BOSS)){ // If player group does not have access to boss mobs. + if(mob_db(mob_id)->status.mode&MD_BOSS && !pc->has_permission(sd, PC_PERM_SHOW_BOSS)){ // If player group does not have access to boss mobs. clif->message(fd, msg_txt(1251)); // Can't show boss mobs! return true; } @@ -8423,11 +8421,11 @@ static void atcommand_commands_sub(struct map_session_data* sd, const int fd, At switch( type ) { case COMMAND_CHARCOMMAND: - if( cmd->char_groups[sd->group_pos] == 0 ) + if( cmd->char_groups[pc_group_get_idx(sd->group)] == 0 ) continue; break; case COMMAND_ATCOMMAND: - if( cmd->at_groups[sd->group_pos] == 0 ) + if( cmd->at_groups[pc_group_get_idx(sd->group)] == 0 ) continue; break; default: @@ -8664,17 +8662,17 @@ ACMD(addperm) { return false; } - if( add && (sd->permissions&pc_g_permission_name[i].permission) ) { + if( add && (sd->extra_temp_permissions&pc_g_permission_name[i].permission) ) { sprintf(atcmd_output, msg_txt(1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission. clif->message(fd, atcmd_output); return false; - } else if ( !add && !(sd->permissions&pc_g_permission_name[i].permission) ) { + } else if ( !add && !(sd->extra_temp_permissions&pc_g_permission_name[i].permission) ) { sprintf(atcmd_output, msg_txt(1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission. clif->message(fd, atcmd_output); sprintf(atcmd_output,msg_txt(1383),sd->status.name); // -- User '%s' Permissions clif->message(fd, atcmd_output); for( i = 0; i < perm_size; i++ ) { - if( sd->permissions&pc_g_permission_name[i].permission ) { + if( sd->extra_temp_permissions&pc_g_permission_name[i].permission ) { sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name); clif->message(fd, atcmd_output); } @@ -8684,9 +8682,9 @@ ACMD(addperm) { } if( add ) - sd->permissions |= pc_g_permission_name[i].permission; + sd->extra_temp_permissions |= pc_g_permission_name[i].permission; else - sd->permissions &=~ pc_g_permission_name[i].permission; + sd->extra_temp_permissions &=~ pc_g_permission_name[i].permission; sprintf(atcmd_output, msg_txt(1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary. @@ -8782,7 +8780,7 @@ ACMD(join) { return false; } if( channel->pass[0] != '\0' && strcmp(channel->pass,pass) != 0 ) { - if( pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sd->stealth = true; } else { sprintf(atcmd_output, msg_txt(1401),name,command); // '%s' Channel is password protected (usage: %s <#channel_name> ) @@ -8875,11 +8873,11 @@ ACMD(channel) { sub1[0] = sub2[0] = sub3[0] = '\0'; if( !message || !*message || sscanf(message, "%s %s %s %s", key, sub1, sub2, sub3) < 1 ) { - atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); + atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); return true; } - if( strcmpi(key,"create") == 0 && ( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) ) { + if( strcmpi(key,"create") == 0 && ( hChSys.allow_user_channel_creation || pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) ) { if( sub1[0] != '#' ) { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; @@ -8928,7 +8926,7 @@ ACMD(channel) { } } else { DBIterator *iter = db_iterator(clif->channel_db); - bool show_all = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ? true : false; + bool show_all = pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ? true : false; clif->message(fd, msg_txt(1410)); // -- Public Channels if( hChSys.local ) { sprintf(atcmd_output, msg_txt(1409), hChSys.local_name, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s ( %d users ) @@ -8961,7 +8959,7 @@ ACMD(channel) { return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->owner != sd->status.char_id && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; @@ -9053,7 +9051,7 @@ ACMD(channel) { return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->owner != sd->status.char_id && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; @@ -9071,7 +9069,7 @@ ACMD(channel) { return false; } - if( pc_has_permission(pl_sd, PC_PERM_HCHSYS_ADMIN) ) { + if( pc->has_permission(pl_sd, PC_PERM_HCHSYS_ADMIN) ) { clif->message(fd, msg_txt(1464)); // Ban failed, not possible to ban this user. return false; } @@ -9109,7 +9107,7 @@ ACMD(channel) { return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->owner != sd->status.char_id && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; @@ -9154,7 +9152,7 @@ ACMD(channel) { return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->owner != sd->status.char_id && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; @@ -9175,7 +9173,7 @@ ACMD(channel) { DBIterator *iter = NULL; DBKey key; DBData *data; - bool isA = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)?true:false; + bool isA = pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN)?true:false; if( sub1[0] != '#' ) { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; @@ -9234,7 +9232,7 @@ ACMD(channel) { return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->owner != sd->status.char_id && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; @@ -9325,7 +9323,7 @@ ACMD(channel) { } } else { - atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); + atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); } return true; @@ -9894,7 +9892,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message if( !pc->get_group_level(sd) ) { if( x >= 1 || y >= 1 ) { /* we have command */ info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); - if( !info || info->char_groups[sd->group_pos] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */ + if( !info || info->char_groups[pc_group_get_idx(sd->group)] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */ return false; } else return false;/* display as normal message */ @@ -9966,17 +9964,17 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message // type == 1 : player invoked if (type == 1) { int i; - if ((*command == atcommand->at_symbol && info->at_groups[sd->group_pos] == 0) || - (*command == atcommand->char_symbol && info->char_groups[sd->group_pos] == 0) ) { + if ((*command == atcommand->at_symbol && info->at_groups[pc_group_get_idx(sd->group)] == 0) || + (*command == atcommand->char_symbol && info->char_groups[pc_group_get_idx(sd->group)] == 0) ) { return false; } - if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) { + if( pc_isdead(sd) && pc->has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) { clif->message(fd, msg_txt(1393)); // You can't use commands while dead return true; } for(i = 0; i < map[sd->bl.m].zone->disabled_commands_count; i++) { if( info->func == map[sd->bl.m].zone->disabled_commands[i]->cmd ) { - if( sd->group_level < map[sd->bl.m].zone->disabled_commands[i]->group_lv ) { + if( pc->get_group_level(sd) < map[sd->bl.m].zone->disabled_commands[i]->group_lv ) { clif->colormes(sd->fd,COLOR_RED,"This command is disabled in this area"); return true; } else @@ -10128,39 +10126,87 @@ static void atcommand_config_read(const char* config_filename) { config_destroy(&atcommand_config); return; } -void atcommand_db_load_groups(void) { + +/** + * In group configuration file, setting for each command is either + * : (only atcommand), or + * : [ , ] ([ atcommand, charcommand ]) + * Maps AtCommandType enums to indexes of value array, + * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1. + * @private + */ +static inline int AtCommandType2idx(AtCommandType type) { return (type-1); } + +/** + * Loads permissions for groups to use commands. + * + */ +void atcommand_db_load_groups(GroupSettings **groups, config_setting_t **commands_, size_t sz) +{ DBIterator *iter = db_iterator(atcommand->db); - AtCommandInfo* cmd; - int i; + AtCommandInfo *atcmd; - for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { - cmd->at_groups = aMalloc( pc_group_max * sizeof(char) ); - cmd->char_groups = aMalloc( pc_group_max * sizeof(char) ); - for(i = 0; i < pc_group_max; i++) { - int idx = pc_group_id2idx(atcommand->group_ids[i]); - if( pc_group_can_use_command(atcommand->group_ids[i], cmd->command, COMMAND_ATCOMMAND ) ) - cmd->at_groups[idx] = 1; - else - cmd->at_groups[idx] = 0; - if( pc_group_can_use_command(atcommand->group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) ) - cmd->char_groups[idx] = 1; - else - cmd->char_groups[idx] = 0; + for (atcmd = dbi_first(iter); dbi_exists(iter); atcmd = dbi_next(iter)) { + int i; + CREATE(atcmd->at_groups, char, sz); + CREATE(atcmd->char_groups, char, sz); + for (i = 0; i < sz; i++) { + GroupSettings *group = groups[i]; + config_setting_t *commands = commands_[i]; + int result = 0; + int idx = -1; + + if (group == NULL) { + ShowError("atcommand_db_load_groups: group is NULL\n"); + continue; + } + + idx = pc_group_get_idx(group); + if (idx < 0 || idx >= sz) { + ShowError("atcommand_db_load_groups: index (%d) out of bounds [0,%d]\n", idx, sz - 1); + continue; + } + + if (pc_group_has_permission(group, PC_PERM_USE_ALL_COMMANDS)) { + atcmd->at_groups[idx] = atcmd->char_groups[idx] = 1; + continue; + } + + if (commands != NULL) { + config_setting_t *cmd = NULL; + + // : (only atcommand) + if (config_setting_lookup_bool(commands, atcmd->command, &result) && result) { + atcmd->at_groups[idx] = 1; + } + else + // : [ , ] ([ atcommand, charcommand ]) + if ((cmd = config_setting_get_member(commands, atcmd->command)) != NULL && + config_setting_is_aggregate(cmd) && + config_setting_length(cmd) == 2 + ) { + if (config_setting_get_bool_elem(cmd, AtCommandType2idx(COMMAND_ATCOMMAND))) { + atcmd->at_groups[idx] = 1; + } + if (config_setting_get_bool_elem(cmd, AtCommandType2idx(COMMAND_CHARCOMMAND))) { + atcmd->char_groups[idx] = 1; + } + } + } } } - dbi_destroy(iter); - return; } + bool atcommand_can_use(struct map_session_data *sd, const char *command) { AtCommandInfo *info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); if (info == NULL) return false; - if ((*command == atcommand->at_symbol && info->at_groups[sd->group_pos] != 0) || - (*command == atcommand->char_symbol && info->char_groups[sd->group_pos] != 0) ) { + if ((*command == atcommand->at_symbol && info->at_groups[pc_group_get_idx(sd->group)] != 0) || + (*command == atcommand->char_symbol && info->char_groups[pc_group_get_idx(sd->group)] != 0) ) { return true; } @@ -10172,8 +10218,8 @@ bool atcommand_can_use2(struct map_session_data *sd, const char *command, AtComm if (info == NULL) return false; - if ((type == COMMAND_ATCOMMAND && info->at_groups[sd->group_pos] != 0) || - (type == COMMAND_CHARCOMMAND && info->char_groups[sd->group_pos] != 0) ) { + if ((type == COMMAND_ATCOMMAND && info->at_groups[pc_group_get_idx(sd->group)] != 0) || + (type == COMMAND_CHARCOMMAND && info->char_groups[pc_group_get_idx(sd->group)] != 0) ) { return true; } @@ -10205,23 +10251,24 @@ bool atcommand_hp_add(char *name, AtCommandFunc func) { strdb_put(atcommand->db, cmd->command, cmd); return true; } -void atcommand_db_clear(void) { - if (atcommand->db != NULL) { - DBIterator *iter = db_iterator(atcommand->db); - AtCommandInfo* cmd; - - for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { - aFree(cmd->at_groups); - aFree(cmd->char_groups); - if( cmd->help != NULL ) - aFree(cmd->help); - } - dbi_destroy(iter); +/** + * @see DBApply + */ +static int atcommand_db_clear_sub(DBKey key, DBData *data, va_list args) +{ + AtCommandInfo *cmd = DB->data2ptr(data); + aFree(cmd->at_groups); + aFree(cmd->char_groups); + if (cmd->help != NULL) + aFree(cmd->help); + return 0; +} - db_destroy(atcommand->db); - atcommand->db = NULL; - } +void atcommand_db_clear(void) +{ + if (atcommand->db != NULL) + atcommand->db->destroy(atcommand->db, atcommand_db_clear_sub); if (atcommand->alias_db != NULL) db_destroy(atcommand->alias_db); } @@ -10246,8 +10293,6 @@ void do_init_atcommand(void) { void do_final_atcommand(void) { atcommand_db_clear(); - if( atcommand->group_ids ) - aFree(atcommand->group_ids); } void atcommand_defaults(void) { diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 12439ab32..ad191a014 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -5,7 +5,9 @@ #ifndef _ATCOMMAND_H_ #define _ATCOMMAND_H_ +#include "../common/conf.h" #include "../common/db.h" +#include "pc_groups.h" /** * Declarations @@ -68,7 +70,6 @@ struct atcommand_interface { /* atcommand binding */ struct atcmd_binding_data** binding; int binding_count; - unsigned int *group_ids; /* other vars */ DBMap* db; //name -> AtCommandInfo DBMap* alias_db; //alias -> AtCommandInfo @@ -80,7 +81,7 @@ struct atcommand_interface { bool (*create) (char *name, AtCommandFunc func); bool (*can_use) (struct map_session_data *sd, const char *command); bool (*can_use2) (struct map_session_data *sd, const char *command, AtCommandType type); - void (*load_groups) (void); + void (*load_groups) (GroupSettings **groups, config_setting_t **commands_, size_t sz); AtCommandInfo* (*exists) (const char* name); int (*msg_read) (const char* cfgName); void (*final_msg) (void); diff --git a/src/map/battle.c b/src/map/battle.c index c1f568843..dbd3bf8e4 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -5779,11 +5779,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if ( s_bl->type == BL_PC ) { switch( t_bl->type ) { case BL_MOB: // Source => PC, Target => MOB - if ( pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVM) ) + if (pc->has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVM) ) return 0; break; case BL_PC: - if (pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVP)) + if (pc->has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVP)) return 0; break; default:/* anything else goes */ diff --git a/src/map/chat.c b/src/map/chat.c index a6a5d2c8b..75ae3681b 100644 --- a/src/map/chat.c +++ b/src/map/chat.c @@ -125,7 +125,7 @@ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) return 0; } - if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) + if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc->has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) { clif->joinchatfail(sd,1); return 0; @@ -325,7 +325,7 @@ int chat_kickchat(struct map_session_data* sd, const char* kickusername) if( i == cd->users ) return -1; - if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK)) + if (pc->has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK)) return 0; //gm kick protection [Valaris] idb_put(cd->kick_list,cd->usersd[i]->status.char_id,(void*)1); diff --git a/src/map/clif.c b/src/map/clif.c index 117a315e9..5cdd543cb 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -2948,7 +2948,7 @@ int clif_hpmeter_sub(struct block_list *bl, va_list ap) { if( !tsd->fd || tsd == sd ) return 0; - if( !pc_has_permission(tsd, PC_PERM_VIEW_HPMETER) ) + if( !pc->has_permission(tsd, PC_PERM_VIEW_HPMETER) ) return 0; WFIFOHEAD(tsd->fd,packet_len(cmd)); WFIFOW(tsd->fd,0) = cmd; @@ -3776,7 +3776,7 @@ void clif_useitemack(struct map_session_data *sd,int index,int amount,bool ok) } void clif_hercules_chsys_send(struct hChSysCh *channel, struct map_session_data *sd, char *msg) { - if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), iTimer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), iTimer->gettick()) > 0 && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { clif->colormes(sd->fd,COLOR_RED,msg_txt(1455)); return; } else { @@ -4345,7 +4345,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds } if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround - pc_has_permission(sd, PC_PERM_VIEW_HPMETER) + pc->has_permission(sd, PC_PERM_VIEW_HPMETER) ) clif->hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp); @@ -13527,7 +13527,7 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd) { int x,y,type; - if( pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE) ) + if (!pc->has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE)) return; x = RFIFOW(fd,2); @@ -14389,7 +14389,7 @@ void clif_parse_Check(int fd, struct map_session_data *sd) char charname[NAME_LENGTH]; struct map_session_data* pl_sd; - if(!pc_has_permission(sd, PC_PERM_USE_CHECK)) + if(!pc->has_permission(sd, PC_PERM_USE_CHECK)) return; safestrncpy(charname, (const char*)RFIFOP(fd,packet_db[RFIFOW(fd,0)].pos[0]), sizeof(charname)); @@ -15411,7 +15411,7 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) if (!tsd) return; - if( tsd->status.show_equip || pc_has_permission(sd, PC_PERM_VIEW_EQUIPMENT) ) + if( tsd->status.show_equip || pc->has_permission(sd, PC_PERM_VIEW_EQUIPMENT) ) clif->viewequip_ack(sd, tsd); else clif->viewequip_fail(sd); diff --git a/src/map/intif.c b/src/map/intif.c index b252d2607..a16b5cda3 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -910,7 +910,7 @@ static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va) char *message; int len; - if (!pc_has_permission(sd, permission)) + if (!pc->has_permission(sd, permission)) return 0; wisp_name = va_arg(va, char*); message = va_arg(va, char*); diff --git a/src/map/log.c b/src/map/log.c index daf96b930..8ed621df5 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -291,7 +291,7 @@ void log_atcommand(struct map_session_data* sd, const char* message) nullpo_retv(sd); if( !logs->config.commands || - !pc_should_log_commands(sd) ) + !pc->should_log_commands(sd) ) return; logs->atcommand_sub(sd,message); diff --git a/src/map/map.c b/src/map/map.c index dbada2e96..55ec5effa 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -134,6 +134,8 @@ char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so struct map_interface iMap_s; +struct map_session_data *cpsd; + /*========================================== * server player count (of all mapservers) *------------------------------------------*/ @@ -4901,6 +4903,7 @@ void do_final(void) ShowStatus("Terminating...\n"); hChSys.closing = true; HPM->event(HPET_FINAL); + if (cpsd) aFree(cpsd); //Ladies and babies first. iter = mapit_getallusers(); @@ -5076,7 +5079,7 @@ static bool map_arg_next_value(const char* option, int i, int argc) return true; } -struct map_session_data cpsd; + CPCMD(gm_position) { int x = 0, y = 0, m = 0; char map_name[25]; @@ -5097,9 +5100,9 @@ CPCMD(gm_position) { } ShowInfo("HCP: updated console's game position to '"CL_WHITE"%d %d %s"CL_RESET"'\n",x,y,map_name); - cpsd.bl.x = x; - cpsd.bl.y = y; - cpsd.bl.m = m; + cpsd->bl.x = x; + cpsd->bl.y = y; + cpsd->bl.m = m; } CPCMD(gm_use) { @@ -5107,23 +5110,23 @@ CPCMD(gm_use) { ShowError("gm:use invalid syntax. use '"CL_WHITE"gm:use @command "CL_RESET"'\n"); return; } - cpsd.fd = -2; - if( !atcommand->parse(cpsd.fd, &cpsd, line, 0) ) + cpsd->fd = -2; + if( !atcommand->parse(cpsd->fd, cpsd, line, 0) ) ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' failed\n",line); else ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' was used\n",line); - cpsd.fd = 0; + cpsd->fd = 0; } /* Hercules Console Parser */ void map_cp_defaults(void) { #ifdef CONSOLE_INPUT /* default HCP data */ - memset(&cpsd, 0, sizeof(struct map_session_data)); - strcpy(cpsd.status.name, "Hercules Console"); - cpsd.bl.x = 150; - cpsd.bl.y = 150; - cpsd.bl.m = iMap->mapname2mapid("prontera"); + cpsd = pc->get_dummy_sd(); + strcpy(cpsd->status.name, "Hercules Console"); + cpsd->bl.x = MAP_DEFAULT_X; + cpsd->bl.y = MAP_DEFAULT_Y; + cpsd->bl.m = iMap->mapname2mapid(MAP_DEFAULT); console->addCommand("gm:info",CPCMD_A(gm_position)); console->addCommand("gm:use",CPCMD_A(gm_use)); diff --git a/src/map/party.c b/src/map/party.c index 0d9859345..cacd016e4 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -365,7 +365,7 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd) } // confirm whether the account has the ability to invite before checking the player - if( !pc_has_permission(sd, PC_PERM_PARTY) || (tsd && !pc_has_permission(tsd, PC_PERM_PARTY)) ) { + if( !pc->has_permission(sd, PC_PERM_PARTY) || (tsd && !pc->has_permission(tsd, PC_PERM_PARTY)) ) { clif->message(sd->fd, msg_txt(81)); // "Your GM level doesn't authorize you to preform this action on the specified player." return 0; } diff --git a/src/map/pc.c b/src/map/pc.c index 35a283752..9984cb7d7 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -15,6 +15,7 @@ #include "../common/conf.h" #include "../common/mmo.h" //NAME_LENGTH +#include "pc.h" #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config #include "battleground.h" @@ -41,7 +42,6 @@ #include "skill.h" #include "status.h" // struct status_data #include "storage.h" -#include "pc.h" #include "pc_groups.h" #include "quest.h" @@ -101,8 +101,59 @@ int pc_class2idx(int class_) { return class_; } -int pc_get_group_level(struct map_session_data *sd) { - return sd->group_level; +/** + * Creates a new dummy map session data. + * Used when there is no real player attached, but it is + * required to provide a session. + * Caller must release dummy on its own when it's no longer needed. + */ +struct map_session_data* pc_get_dummy_sd(void) +{ + struct map_session_data *dummy_sd; + CREATE(dummy_sd, struct map_session_data, 1); + dummy_sd->group = pc_group_get_dummy_group(); // map_session_data.group is expected to be non-NULL at all times + return dummy_sd; +} + +/** + * Gets player's group level. + * @see pc_group_get_level() + */ +int pc_get_group_level(struct map_session_data *sd) +{ + return pc_group_get_level(sd->group); +} + +/** + * Sets player's group. + * Caller should handle error (preferably display message and disconnect). + * @param group_id Group ID + * @return 1 on error, 0 on success + */ +int pc_set_group(struct map_session_data *sd, int group_id) +{ + GroupSettings *group = pc_group_id2group(group_id); + if (group == NULL) + return 1; + sd->group_id = group_id; + sd->group = group; + return 0; +} + +/** + * Checks if player has permission to perform action. + */ +bool pc_has_permission(struct map_session_data *sd, enum e_pc_permission permission) +{ + return ((sd->extra_temp_permissions&permission) != 0 || pc_group_has_permission(sd->group, permission)); +} + +/** + * Checks if commands used by player should be logged. + */ +bool pc_should_log_commands(struct map_session_data *sd) +{ + return pc_group_should_log_commands(sd->group); } static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data) @@ -503,7 +554,7 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds) */ bool pc_can_give_items(struct map_session_data *sd) { - return pc_has_permission(sd, PC_PERM_TRADE); + return pc->has_permission(sd, PC_PERM_TRADE); } /*========================================== @@ -857,7 +908,7 @@ int pc_isequip(struct map_session_data *sd,int n) item = sd->inventory_data[n]; - if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT)) + if(pc->has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT)) return 1; if(item == NULL) @@ -931,10 +982,13 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim uint32 ip = session[sd->fd]->client_addr; sd->login_id2 = login_id2; - sd->group_id = group_id; - - /* load user permissions */ - pc_group_pc_load(sd); + + if (pc->set_group(sd, group_id) != 0) { + ShowWarning("pc_authok: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", + st->name, sd->status.account_id, group_id); + clif->authfail_fd(sd->fd, 0); + return false; + } memcpy(&sd->status, st, sizeof(*st)); @@ -1370,7 +1424,7 @@ int pc_calc_skilltree(struct map_session_data *sd) } } - if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) { + if( pc->has_permission(sd, PC_PERM_ALL_SKILL) ) { for( i = 0; i < MAX_SKILL; i++ ) { switch(skill_db[i].nameid) { /** @@ -1566,7 +1620,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) int skill_point, novice_skills; int c = sd->class_; - if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) + if (!battle_config.skillup_limit || pc->has_permission(sd, PC_PERM_ALL_SKILL)) return c; skill_point = pc_calc_skillpoint(sd); @@ -4989,7 +5043,7 @@ int pc_memo(struct map_session_data* sd, int pos) nullpo_ret(sd); // check mapflags - if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { + if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc->has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { clif->skill_mapinfomessage(sd, 1); // "Saved point cannot be memorized." return 0; } @@ -6246,7 +6300,7 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { clif->updatestatus(sd,SP_SKILLPOINT); if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ clif->updatestatus(sd,SP_CARTINFO); - if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown + if (!pc->has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown clif->skillinfoblock(sd); } return 0; @@ -6270,7 +6324,7 @@ int pc_allskillup(struct map_session_data *sd) } } - if (pc_has_permission(sd, PC_PERM_ALL_SKILL)) { //Get ALL skills except npc/guild ones. [Skotlex] + if (pc->has_permission(sd, PC_PERM_ALL_SKILL)) { //Get ALL skills except npc/guild ones. [Skotlex] //and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage] for(i=0;iget_dummy_sd = pc_get_dummy_sd; pc->class2idx = pc_class2idx; pc->get_group_level = pc_get_group_level; pc->can_give_items = pc_can_give_items; pc->can_use_command = pc_can_use_command; - + pc->has_permission = pc_has_permission; + pc->set_group = pc_set_group; + pc->should_log_commands = pc_should_log_commands; + pc->setrestartvalue = pc_setrestartvalue; pc->makesavestatus = pc_makesavestatus; pc->respawn = pc_respawn; diff --git a/src/map/pc.h b/src/map/pc.h index 8544650a3..ab6de114e 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -12,15 +12,16 @@ #include "battleground.h" #include "buyingstore.h" // struct s_buyingstore #include "itemdb.h" +#include "log.h" #include "map.h" // RC_MAX +#include "mob.h" +#include "pc_groups.h" #include "script.h" // struct script_reg, struct script_regstr #include "searchstore.h" // struct s_search_store_info #include "status.h" // OPTION_*, struct weapon_atk #include "unit.h" // unit_stop_attack(), unit_stop_walking() #include "vending.h" // struct s_vending -#include "mob.h" -#include "log.h" -#include "pc_groups.h" + #define MAX_PC_BONUS 10 #define MAX_PC_SKILL_REQUIRE 5 @@ -181,9 +182,11 @@ struct map_session_data { } special_state; int login_id1, login_id2; unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] - int group_id, group_pos, group_level; - unsigned int permissions;/* group permissions */ - bool group_log_command; + + /// Groups & permissions + int group_id; + GroupSettings *group; + unsigned int extra_temp_permissions; /* permissions from @addperm */ struct mmo_charstatus status; struct registry save_reg; @@ -685,9 +688,6 @@ enum equip_pos { #define pc_get_group_id(sd) ( (sd)->group_id ) -#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 ) -#define pc_should_log_commands(sd) ( (sd)->group_log_command != false ) - #define pc_checkoverhp(sd) ((sd)->battle_status.hp == (sd)->battle_status.max_hp) #define pc_checkoversp(sd) ((sd)->battle_status.sp == (sd)->battle_status.max_sp) @@ -751,13 +751,17 @@ struct pc_interface { /* funcs */ + struct map_session_data* (*get_dummy_sd) (void); int (*class2idx) (int class_); int (*get_group_level) (struct map_session_data *sd); //int (*getrefinebonus) (int lv,int type); FIXME: This function does not exist, nor it is ever called bool (*can_give_items) (struct map_session_data *sd); bool (*can_use_command) (struct map_session_data *sd, const char *command); - + bool (*has_permission) (struct map_session_data *sd, enum e_pc_permission permission); + int (*set_group) (struct map_session_data *sd, int group_id); + bool (*should_log_commands) (struct map_session_data *sd); + int (*setrestartvalue) (struct map_session_data *sd,int type); int (*makesavestatus) (struct map_session_data *); void (*respawn) (struct map_session_data* sd, clr_type clrtype); diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index f1f69f7cb..9ca0fd17a 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -8,23 +8,22 @@ #include "../common/nullpo.h" #include "../common/showmsg.h" #include "../common/strlib.h" // strcmp -#include "../common/socket.h" -#include "atcommand.h" // AtCommandType #include "pc_groups.h" -#include "pc.h" // e_pc_permission +#include "atcommand.h" // atcommand->exists(), atcommand->load_groups() +#include "clif.h" // clif->GM_kick() +#include "map.h" // mapiterator +#include "pc.h" // pc->set_group() -typedef struct GroupSettings GroupSettings; - -// Cached config settings/pointers for quick lookup +// Cached config settings for quick lookup struct GroupSettings { unsigned int id; // groups.[].id int level; // groups.[].level - char name[60]; // copy of groups.[].name + char *name; // copy of groups.[].name unsigned int e_permissions; // packed groups.[].permissions bool log_commands; // groups.[].log_commands - int group_pos;/* pos on load [Ind] */ - /// Following are used/avaialble only during config reading + int index; // internal index of the group (contiguous range starting at 0) [Ind] + /// Following are used/available only during config reading config_setting_t *commands; // groups.[].commands config_setting_t *permissions; // groups.[].permissions config_setting_t *inherit; // groups.[].inherit @@ -32,18 +31,44 @@ struct GroupSettings { config_setting_t *root; // groups.[] }; -int pc_group_max; /* known number of groups */ +const struct pc_permission_name_table pc_g_permission_name[NUM_PC_PERM] = { + { "can_trade", PC_PERM_TRADE }, + { "can_party", PC_PERM_PARTY }, + { "all_skill", PC_PERM_ALL_SKILL }, + { "all_equipment", PC_PERM_USE_ALL_EQUIPMENT }, + { "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL }, + { "join_chat", PC_PERM_JOIN_ALL_CHAT }, + { "kick_chat", PC_PERM_NO_CHAT_KICK }, + { "hide_session", PC_PERM_HIDE_SESSION }, + { "who_display_aid", PC_PERM_WHO_DISPLAY_AID }, + { "hack_info", PC_PERM_RECEIVE_HACK_INFO }, + { "any_warp", PC_PERM_WARP_ANYWHERE }, + { "view_hpmeter", PC_PERM_VIEW_HPMETER }, + { "view_equipment", PC_PERM_VIEW_EQUIPMENT }, + { "use_check", PC_PERM_USE_CHECK }, + { "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE }, + { "all_commands", PC_PERM_USE_ALL_COMMANDS }, + { "receive_requests", PC_PERM_RECEIVE_REQUESTS }, + { "show_bossmobs", PC_PERM_SHOW_BOSS }, + { "disable_pvm", PC_PERM_DISABLE_PVM }, + { "disable_pvp", PC_PERM_DISABLE_PVP }, + { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, + { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, +}; static DBMap* pc_group_db; // id -> GroupSettings static DBMap* pc_groupname_db; // name -> GroupSettings +static GroupSettings dummy_group; ///< dummy group used in dummy map sessions @see pc_get_dummy_sd() + /** - * @retval NULL if not found - * @private + * Returns dummy group. + * Used in dummy map sessions. + * @see pc_get_dummy_sd() */ -static inline GroupSettings* id2group(int group_id) +GroupSettings* pc_group_get_dummy_group(void) { - return (GroupSettings*)idb_get(pc_group_db, group_id); + return &dummy_group; } /** @@ -52,7 +77,7 @@ static inline GroupSettings* id2group(int group_id) */ static inline GroupSettings* name2group(const char* group_name) { - return (GroupSettings*)strdb_get(pc_groupname_db, group_name); + return strdb_get(pc_groupname_db, group_name); } /** @@ -90,7 +115,7 @@ static void read_config(void) { continue; } - if (id2group(id) != NULL) { + if (pc_group_exists(id)) { ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i); config_setting_remove_elem(groups, i); --i; @@ -109,6 +134,8 @@ static void read_config(void) { !config_setting_set_string(name, temp)) { ShowError("pc_groups:read_config: failed to set missing group name, id=%d, skipping... (%s:%d)\n", id, config_setting_source_file(group), config_setting_source_line(group)); + --i; + --group_count; continue; } config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer @@ -125,20 +152,21 @@ static void read_config(void) { CREATE(group_settings, GroupSettings, 1); group_settings->id = id; group_settings->level = level; - safestrncpy(group_settings->name, groupname, 60); + group_settings->name = aStrdup(groupname); group_settings->log_commands = (bool)log_commands; group_settings->inherit = config_setting_get_member(group, "inherit"); group_settings->commands = config_setting_get_member(group, "commands"); group_settings->permissions = config_setting_get_member(group, "permissions"); group_settings->inheritance_done = false; group_settings->root = group; - group_settings->group_pos = i; + group_settings->index = i; strdb_put(pc_groupname_db, groupname, group_settings); idb_put(pc_group_db, id, group_settings); } group_count = config_setting_length(groups); // Save number of groups + assert(group_count == db_size(pc_group_db)); // Check if all commands and permissions exist iter = db_iterator(pc_group_db); @@ -249,7 +277,7 @@ static void read_config(void) { break; } } // while(i < group_count) - + // Pack permissions into GroupSettings.e_permissions for faster checking iter = db_iterator(pc_group_db); for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { @@ -269,111 +297,51 @@ static void read_config(void) { } } dbi_destroy(iter); + + // Atcommand permissions are processed by atcommand module. + // Fetch all groups and relevant config setting and send them + // to atcommand->load_group() for processing. + if (group_count > 0) { + int i = 0; + GroupSettings **groups = NULL; + config_setting_t **commands = NULL; + CREATE(groups, GroupSettings*, group_count); + CREATE(commands, config_setting_t*, group_count); + iter = db_iterator(pc_group_db); + for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { + groups[i] = group_settings; + commands[i] = group_settings->commands; + i++; + } + atcommand->load_groups(groups, commands, group_count); + dbi_destroy(iter); + aFree(groups); + aFree(commands); + } } ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename); - - if( ( pc_group_max = group_count ) ) { - DBIterator *iter = db_iterator(pc_group_db); - GroupSettings *group_settings = NULL; - unsigned int* group_ids = aMalloc( pc_group_max * sizeof(unsigned int) ); - int i = 0; - for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { - group_ids[i++] = group_settings->id; - } - - if( atcommand->group_ids ) - aFree(atcommand->group_ids); - atcommand->group_ids = group_ids; - - atcommand->load_groups(); - - dbi_destroy(iter); - } - + // All data is loaded now, discard config config_destroy(&pc_group_config); } -/** - * In group configuration file, setting for each command is either - * : (only atcommand), or - * : [ , ] ([ atcommand, charcommand ]) - * Maps AtCommandType enums to indexes of value array, - * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1. - * @private - */ -static inline int AtCommandType2idx(AtCommandType type) { return (type-1); } - -/** - * Checks if player group can use @/#command, used only during parse (only available during parse) - * @param group_id ID of the group - * @param command Command name without @/# and params - * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 } - */ -bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type) { - int result = 0; - config_setting_t *commands = NULL; - GroupSettings *group = NULL; - - if (pc_group_has_permission(group_id, PC_PERM_USE_ALL_COMMANDS)) - return true; - - if ((group = id2group(group_id)) == NULL) - return false; - - commands = group->commands; - if (commands != NULL) { - config_setting_t *cmd = NULL; - - // : (only atcommand) - if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result)) - return (bool)result; - - // : [ , ] ([ atcommand, charcommand ]) - if ((cmd = config_setting_get_member(commands, command)) != NULL && - config_setting_is_aggregate(cmd) && config_setting_length(cmd) == 2) - return (bool)config_setting_get_bool_elem(cmd, AtCommandType2idx(type)); - } - return false; -} -void pc_group_pc_load(struct map_session_data * sd) { - GroupSettings *group = NULL; - if ((group = id2group(sd->group_id)) == NULL) { - 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->permissions = group->e_permissions; - sd->group_pos = group->group_pos; - sd->group_level = group->level; - sd->group_log_command = group->log_commands; -} /** * Checks if player group has a permission - * @param group_id ID of the group + * @param group group * @param permission permission to check */ -bool pc_group_has_permission(int group_id, int permission) +bool pc_group_has_permission(GroupSettings *group, enum e_pc_permission permission) { - GroupSettings *group = NULL; - if ((group = id2group(group_id)) == NULL) - return false; return ((group->e_permissions&permission) != 0); } /** - * Checks commands used by player group should be logged - * @param group_id ID of the group + * Checks if commands used by player group should be logged + * @param group group */ -bool pc_group_should_log_commands(int group_id) +bool pc_group_should_log_commands(GroupSettings *group) { - GroupSettings *group = NULL; - if ((group = id2group(group_id)) == NULL) - return false; return group->log_commands; } @@ -388,44 +356,44 @@ bool pc_group_exists(int group_id) } /** - * Group ID -> group name lookup. Used only in @who atcommands. - * @param group_id group id + * @retval NULL if not found + */ +GroupSettings* pc_group_id2group(int group_id) +{ + return idb_get(pc_group_db, group_id); +} + +/** + * Group name lookup. Used only in @who atcommands. + * @param group group * @return group name * @public */ -const char* pc_group_id2name(int group_id) +const char* pc_group_get_name(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return "Non-existent group!"; return group->name; } /** - * Group ID -> group level lookup. A way to provide backward compatibility with GM level system. - * @param group id + * Group level lookup. A way to provide backward compatibility with GM level system. + * @param group group * @return group level * @public */ -int pc_group_id2level(int group_id) +int pc_group_get_level(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return 0; return group->level; } + /** - * Group ID -> group level lookup. - * @param group id + * Group -> index lookup. + * @param group group * @return group index * @public */ -int pc_group_id2idx(int group_id) +int pc_group_get_idx(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return 0; - return group->group_pos; + return group->index; } /** @@ -439,6 +407,17 @@ void do_init_pc_groups(void) read_config(); } +/** + * @see DBApply + */ +static int group_db_clear_sub(DBKey key, DBData *data, va_list args) +{ + GroupSettings *group = DB->data2ptr(data); + if (group->name) + aFree(group->name); + return 0; +} + /** * Finalize PC Groups: free DBMaps and config. * @public @@ -446,8 +425,8 @@ void do_init_pc_groups(void) void do_final_pc_groups(void) { if (pc_group_db != NULL) - db_destroy(pc_group_db); - if (pc_groupname_db != NULL ) + pc_group_db->destroy(pc_group_db, group_db_clear_sub); + if (pc_groupname_db != NULL) db_destroy(pc_groupname_db); } @@ -457,18 +436,20 @@ void do_final_pc_groups(void) * @public */ void pc_groups_reload(void) { - struct map_session_data* sd = NULL; - struct s_mapiterator* iter; + struct map_session_data *sd = NULL; + struct s_mapiterator *iter; do_final_pc_groups(); do_init_pc_groups(); /* refresh online users permissions */ iter = mapit_getallusers(); - for (sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter)) { - pc_group_pc_load(sd); + for (sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter)) { + if (pc->set_group(sd, sd->group_id) != 0) { + ShowWarning("pc_groups_reload: %s (AID:%d) has unknown group id (%d)! kicking...\n", + sd->status.name, sd->status.account_id, pc_get_group_id(sd)); + clif->GM_kick(NULL, sd); + } } mapit->free(iter); - - } diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index 0ce7b0d51..8f350c2b6 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -5,26 +5,10 @@ #ifndef _PC_GROUPS_H_ #define _PC_GROUPS_H_ -#include "atcommand.h" // AtCommandType - -extern int pc_group_max; - -bool pc_group_exists(int group_id); -bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type); -bool pc_group_has_permission(int group_id, int permission); -bool pc_group_should_log_commands(int group_id); -const char* pc_group_id2name(int group_id); -int pc_group_id2level(int group_id); -int pc_group_id2idx(int group_id); -void pc_group_pc_load(struct map_session_data *); - -void do_init_pc_groups(void); -void do_final_pc_groups(void); -void pc_groups_reload(void); - +/// PC permissions enum e_pc_permission { - PC_PERM_NONE = 0, - PC_PERM_TRADE = 0x000001, + PC_PERM_NONE = 0, // #0 + PC_PERM_TRADE = 0x000001, // #1 PC_PERM_PARTY = 0x000002, PC_PERM_ALL_SKILL = 0x000004, PC_PERM_USE_ALL_EQUIPMENT = 0x000008, @@ -33,7 +17,7 @@ enum e_pc_permission { PC_PERM_NO_CHAT_KICK = 0x000040, PC_PERM_HIDE_SESSION = 0x000080, PC_PERM_WHO_DISPLAY_AID = 0x000100, - PC_PERM_RECEIVE_HACK_INFO = 0x000200, + PC_PERM_RECEIVE_HACK_INFO = 0x000200, // #10 PC_PERM_WARP_ANYWHERE = 0x000400, PC_PERM_VIEW_HPMETER = 0x000800, PC_PERM_VIEW_EQUIPMENT = 0x001000, @@ -41,39 +25,41 @@ enum e_pc_permission { PC_PERM_USE_CHANGEMAPTYPE = 0x004000, PC_PERM_USE_ALL_COMMANDS = 0x008000, PC_PERM_RECEIVE_REQUESTS = 0x010000, - PC_PERM_SHOW_BOSS = 0x020000, - PC_PERM_DISABLE_PVM = 0x040000, - PC_PERM_DISABLE_PVP = 0x080000, + PC_PERM_SHOW_BOSS = 0x020000, + PC_PERM_DISABLE_PVM = 0x040000, + PC_PERM_DISABLE_PVP = 0x080000, // #20 PC_PERM_DISABLE_CMD_DEAD = 0x100000, - PC_PERM_HCHSYS_ADMIN = 0x200000, + PC_PERM_HCHSYS_ADMIN = 0x200000, }; -static const struct { +/// Total number of PC permissions (without PC_PERM_NONE). +/// This is manifest constant for the size of pc_g_permission_name array, +/// so it's possible to apply sizeof to it [C-FAQ 1.24] +/// Whenever adding new permission: 1. add enum entry above, 2. add entry into +/// pc_g_permission_name (in pc.c), 3. increase NUM_PC_PERM below by 1. +#define NUM_PC_PERM 22 + +struct pc_permission_name_table { const char *name; - unsigned int permission; -} pc_g_permission_name[] = { - { "can_trade", PC_PERM_TRADE }, - { "can_party", PC_PERM_PARTY }, - { "all_skill", PC_PERM_ALL_SKILL }, - { "all_equipment", PC_PERM_USE_ALL_EQUIPMENT }, - { "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL }, - { "join_chat", PC_PERM_JOIN_ALL_CHAT }, - { "kick_chat", PC_PERM_NO_CHAT_KICK }, - { "hide_session", PC_PERM_HIDE_SESSION }, - { "who_display_aid", PC_PERM_WHO_DISPLAY_AID }, - { "hack_info", PC_PERM_RECEIVE_HACK_INFO }, - { "any_warp", PC_PERM_WARP_ANYWHERE }, - { "view_hpmeter", PC_PERM_VIEW_HPMETER }, - { "view_equipment", PC_PERM_VIEW_EQUIPMENT }, - { "use_check", PC_PERM_USE_CHECK }, - { "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE }, - { "all_commands", PC_PERM_USE_ALL_COMMANDS }, - { "receive_requests", PC_PERM_RECEIVE_REQUESTS }, - { "show_bossmobs", PC_PERM_SHOW_BOSS }, - { "disable_pvm", PC_PERM_DISABLE_PVM }, - { "disable_pvp", PC_PERM_DISABLE_PVP }, - { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, - { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, + enum e_pc_permission permission; }; +/// Name <-> enum table for PC permissions +extern const struct pc_permission_name_table pc_g_permission_name[NUM_PC_PERM]; + +typedef struct GroupSettings GroupSettings; + +GroupSettings* pc_group_get_dummy_group(void); +bool pc_group_exists(int group_id); +GroupSettings* pc_group_id2group(int group_id); +bool pc_group_has_permission(GroupSettings *group, enum e_pc_permission permission); +bool pc_group_should_log_commands(GroupSettings *group); +const char* pc_group_get_name(GroupSettings *group); +int pc_group_get_level(GroupSettings *group); +int pc_group_get_idx(GroupSettings *group); + +void do_init_pc_groups(void); +void do_final_pc_groups(void); +void pc_groups_reload(void); + #endif // _PC_GROUPS_H_ diff --git a/src/map/pet.c b/src/map/pet.c index 236ffe98b..ae8216fc2 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -885,7 +885,7 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns } } - if(!target && pd->loot && pd->msd && pc_has_permission(pd->msd, PC_PERM_TRADE) && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) { + if(!target && pd->loot && pd->msd && pc->has_permission(pd->msd, PC_PERM_TRADE) && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) { //Use half the pet's range of sight. iMap->foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl, pd->db->range2/2, BL_ITEM,pd,&target); diff --git a/src/map/script.c b/src/map/script.c index 2a917236a..336ab7b9f 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9287,7 +9287,7 @@ BUILDIN(getusersname) iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > group_level) + if (pc->has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > group_level) continue; // skip hidden sessions /* Temporary fix for bugreport:1023. @@ -12280,10 +12280,10 @@ BUILDIN(nude) *------------------------------------------*/ BUILDIN(atcommand) { - TBL_PC dummy_sd; - TBL_PC* sd; + TBL_PC *sd, *dummy_sd = NULL; int fd; const char* cmd; + bool ret = true; cmd = script_getstr(st,2); @@ -12291,26 +12291,25 @@ BUILDIN(atcommand) sd = script_rid2sd(st); fd = sd->fd; } else { //Use a dummy character. - sd = &dummy_sd; + sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - memset(&dummy_sd, 0, sizeof(TBL_PC)); if (st->oid) { struct block_list* bl = iMap->id2bl(st->oid); - memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); + memcpy(&sd->bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) - safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } if (!atcommand->parse(fd, sd, cmd, 0)) { ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd); script_reportsrc(st); - return false; + ret = false; } - - return true; + if (dummy_sd) aFree(dummy_sd); + return ret; } /*========================================== @@ -16849,8 +16848,7 @@ BUILDIN(unbindatcmd) { BUILDIN(useatcmd) { - TBL_PC dummy_sd; - TBL_PC* sd; + TBL_PC *sd, *dummy_sd = NULL; int fd; const char* cmd; @@ -16863,16 +16861,15 @@ BUILDIN(useatcmd) } else { // Use a dummy character. - sd = &dummy_sd; + sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - memset(&dummy_sd, 0, sizeof(TBL_PC)); if( st->oid ) { struct block_list* bl = iMap->id2bl(st->oid); - memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); + memcpy(&sd->bl, bl, sizeof(struct block_list)); if( bl->type == BL_NPC ) - safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } @@ -16884,6 +16881,7 @@ BUILDIN(useatcmd) } atcommand->parse(fd, sd, cmd, 1); + if (dummy_sd) aFree(dummy_sd); return true; } diff --git a/src/map/skill.c b/src/map/skill.c index 0fbd340fa..995c20083 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -485,7 +485,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) if (idx == 0) return 1; // invalid skill id - if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) + if (pc->has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) return 0; // can do any damn thing they want if( skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2 ) @@ -12235,7 +12235,7 @@ int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, uint16 int i; bool is_chorus = ( skill->get_inf2(skill_id)&INF2_CHORUS_SKILL ); - if (!battle_config.player_skill_partner_check || pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) + if (!battle_config.player_skill_partner_check || pc->has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) return is_chorus ? MAX_PARTY : 99; //As if there were infinite partners. if (cast_flag) { //Execute the skill on the partners. @@ -12332,7 +12332,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id if (sd->chatID) return 0; - if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) + if( pc->has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. @@ -13217,7 +13217,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, if( sd->chatID ) return 0; - if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { + if( pc->has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. -- cgit v1.2.3-60-g2f50