summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiotr HaƂaczkiewicz <piotr.halaczkiewicz@gmail.com>2013-07-31 05:07:50 -0700
committerPiotr HaƂaczkiewicz <piotr.halaczkiewicz@gmail.com>2013-07-31 05:07:50 -0700
commit871e2f2a56431cf13f193e00b261aae5460bebc1 (patch)
treeaa2c7bd3223471328452b7b7980c0a379a9d4b9f
parent43d95751dcc937a2caddb5b793f5c45666abfee0 (diff)
parente7750ecfff5bf856ecc9f38ea327c6b6cc535761 (diff)
downloadhercules-871e2f2a56431cf13f193e00b261aae5460bebc1.tar.gz
hercules-871e2f2a56431cf13f193e00b261aae5460bebc1.tar.bz2
hercules-871e2f2a56431cf13f193e00b261aae5460bebc1.tar.xz
hercules-871e2f2a56431cf13f193e00b261aae5460bebc1.zip
Merge pull request #71 from HerculesWS/permission-cache-fix
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.
-rw-r--r--src/common/conf.c2
-rw-r--r--src/common/conf.h2
-rw-r--r--src/common/showmsg.c2
-rw-r--r--src/common/showmsg.h2
-rw-r--r--src/map/atcommand.c227
-rw-r--r--src/map/atcommand.h5
-rw-r--r--src/map/battle.c4
-rw-r--r--src/map/chat.c4
-rw-r--r--src/map/clif.c12
-rw-r--r--src/map/intif.c2
-rw-r--r--src/map/log.c2
-rw-r--r--src/map/map.c27
-rw-r--r--src/map/party.c2
-rw-r--r--src/map/pc.c88
-rw-r--r--src/map/pc.h24
-rw-r--r--src/map/pc_groups.c247
-rw-r--r--src/map/pc_groups.h84
-rw-r--r--src/map/pet.c2
-rw-r--r--src/map/script.c30
-rw-r--r--src/map/skill.c8
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 <time.h>
#include <stdlib.h> // 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> <password>)
@@ -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
+ * <commandname> : <bool> (only atcommand), or
+ * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
+ * Maps AtCommandType enums to indexes of <commandname> 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;
+
+ // <commandname> : <bool> (only atcommand)
+ if (config_setting_lookup_bool(commands, atcmd->command, &result) && result) {
+ atcmd->at_groups[idx] = 1;
+ }
+ else
+ // <commandname> : [ <bool>, <bool> ] ([ 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 613ea6258..f72bdce06 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -5785,11 +5785,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 a1e0eedb2..3657d0e43 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 bfacf7a35..6461dce8e 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 de805e83f..713577495 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 <optional params>"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;i<MAX_SKILL;i++){
switch( skill_db[i].nameid ) {
@@ -10236,12 +10290,16 @@ void pc_defaults(void) {
/* funcs */
+ pc->get_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
- * <commandname> : <bool> (only atcommand), or
- * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
- * Maps AtCommandType enums to indexes of <commandname> 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;
-
- // <commandname> : <bool> (only atcommand)
- if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result))
- return (bool)result;
-
- // <commandname> : [ <bool>, <bool> ] ([ 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;
}
/**
@@ -440,14 +408,25 @@ void do_init_pc_groups(void)
}
/**
+ * @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
*/
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 005768a58..3033a281b 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 42ab6450f..97f26cca6 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.