Converted player groups to YAML (#6488)
Finally adds import functionality for player groups and therefore atcommand and permission defining. Co-authored-by: Aleos <aleos89@users.noreply.github.com>
This commit is contained in:
parent
6e5461a34e
commit
51ddc63a02
303
conf/groups.conf
303
conf/groups.conf
@ -1,303 +0,0 @@
|
||||
/*
|
||||
|
||||
Player groups configuration file
|
||||
---------------------------------
|
||||
|
||||
This file defines "player groups" and their privileges.
|
||||
|
||||
Each group has its id and name, lists of available commands and other
|
||||
permissions, and a list of other groups it inherits from.
|
||||
|
||||
|
||||
Group settings
|
||||
--------------
|
||||
<id>
|
||||
Unique group number. The only required field.
|
||||
|
||||
<name>
|
||||
Any string. If empty, defaults to "Group <id>". It is used in several @who
|
||||
commands.
|
||||
|
||||
<level>
|
||||
Equivalent of GM level, which was used in revisions before r15572. You can
|
||||
set it to any number, but usually it's between 0 (default) and 99. Members of
|
||||
groups with lower level can not perform some actions/commands (like @kick) on
|
||||
members of groups with higher level. It is what script command getgmlevel()
|
||||
returns. Group level can also be used to override trade restrictions
|
||||
(db/item_trade.txt).
|
||||
|
||||
<commands>
|
||||
A group of settings
|
||||
<command name> : <bool>
|
||||
or
|
||||
<commandname> : [ <bool>, <bool> ]
|
||||
First boolean value is for atcommand, second one for charcommand. If set to
|
||||
true, group can use command. If only atcommand value is provided, false is
|
||||
assumed for charcommand. If a command name is not included, false is assumed for
|
||||
both atcommand and charcommand.
|
||||
For a full list of available commands, see: doc/atcommands.txt.
|
||||
Command names must not be aliases.
|
||||
|
||||
<log_commands>
|
||||
Boolean value. If true then all commands used by the group will be logged to
|
||||
atcommandlog. If setting is omitted in a group definition, false is assumed.
|
||||
Requires 'log_commands' to be enabled in 'conf/log_athena.conf'.
|
||||
|
||||
<permissions>
|
||||
A group of settings
|
||||
<permission> : <bool>
|
||||
If a permission is not included, false is assumed.
|
||||
For a full list of available permissions, see: doc/permissions.txt
|
||||
|
||||
<inherit>
|
||||
A list of group names that given group will inherit commands and permissions
|
||||
from. Group names are case-sensitive.
|
||||
|
||||
Inheritance results
|
||||
-------------------
|
||||
Both multiple inheritance (Group 2 -> Group 1 and Group 3 -> Group 1) and
|
||||
recursive inheritance (Group 3 -> Group 2 -> Group 1) are allowed.
|
||||
|
||||
Inheritance rules should not create cycles (eg Group 1 inherits from Group 2,
|
||||
and Group inherits from Group 1 at the same time). Configuration with cycles is
|
||||
considered faulty and can't be processed fully by server.
|
||||
|
||||
Command or permission is inherited ONLY if it's not already defined for the
|
||||
group.
|
||||
If group inherits from multiple groups, and the same command or permission is
|
||||
defined for more than one of these groups, it's undefined which one will be
|
||||
inherited.
|
||||
|
||||
Syntax
|
||||
------
|
||||
This config file uses libconfig syntax:
|
||||
http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
||||
|
||||
|
||||
Upgrading from revisions before r15572
|
||||
-------------------------------------
|
||||
http://rathena.org/board/index.php?showtopic=58877
|
||||
*/
|
||||
|
||||
groups: (
|
||||
{
|
||||
id: 0 /* group 0 is the default group for every new account */
|
||||
name: "Player"
|
||||
level: 0
|
||||
inherit: ( /*empty list*/ )
|
||||
commands: {
|
||||
changedress: true
|
||||
resurrect: true
|
||||
}
|
||||
permissions: {
|
||||
/* without this basic permissions regular players could not
|
||||
trade or party */
|
||||
can_trade: true
|
||||
can_party: true
|
||||
attendance: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 1
|
||||
name: "Super Player"
|
||||
inherit: ( "Player" ) /* can do everything Players can and more */
|
||||
level: 0
|
||||
commands: {
|
||||
/* informational commands */
|
||||
commands: true
|
||||
charcommands: true
|
||||
help: true
|
||||
rates: true
|
||||
uptime: true
|
||||
showdelay: true
|
||||
exp: true
|
||||
mobinfo: true
|
||||
iteminfo: true
|
||||
whodrops: true
|
||||
time: true
|
||||
jailtime: true
|
||||
hominfo: true
|
||||
homstats: true
|
||||
showexp: true
|
||||
showzeny: true
|
||||
whereis: true
|
||||
/* feature commands */
|
||||
refresh: true
|
||||
noask: true
|
||||
noks: true
|
||||
autoloot: true
|
||||
alootid: true
|
||||
autoloottype: true
|
||||
autotrade: true
|
||||
request: true
|
||||
go: true
|
||||
breakguild: true
|
||||
channel: true
|
||||
langtype: true
|
||||
}
|
||||
permissions: {
|
||||
attendance: false
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2
|
||||
name: "Support"
|
||||
inherit: ( "Super Player" )
|
||||
level: 1
|
||||
commands: {
|
||||
version: true
|
||||
where: true
|
||||
jumpto: true
|
||||
who: true
|
||||
who2: true
|
||||
who3: true
|
||||
whomap: true
|
||||
whomap2: true
|
||||
whomap3: true
|
||||
users: true
|
||||
broadcast: true
|
||||
localbroadcast: true
|
||||
}
|
||||
log_commands: true
|
||||
permissions: {
|
||||
receive_requests: true
|
||||
view_equipment: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3
|
||||
name: "Script Manager"
|
||||
inherit: ( "Support" )
|
||||
level: 1
|
||||
commands: {
|
||||
tonpc: true
|
||||
hidenpc: true
|
||||
shownpc: true
|
||||
loadnpc: true
|
||||
unloadnpc: true
|
||||
npcmove: true
|
||||
addwarp: true
|
||||
}
|
||||
log_commands: true
|
||||
permissions: {
|
||||
any_warp: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 4
|
||||
name: "Event Manager"
|
||||
inherit: ( "Support" )
|
||||
level: 1
|
||||
commands: {
|
||||
monster: true
|
||||
monstersmall: true
|
||||
monsterbig: true
|
||||
killmonster2: true
|
||||
cleanarea: true
|
||||
cleanmap: true
|
||||
item: [true, true]
|
||||
zeny: [true, true]
|
||||
disguise: [true, true]
|
||||
undisguise: [true, true]
|
||||
size: [true, true]
|
||||
raise: true
|
||||
raisemap: true
|
||||
day: true
|
||||
night: true
|
||||
skillon: true
|
||||
skilloff: true
|
||||
pvpon: true
|
||||
pvpoff: true
|
||||
gvgon: true
|
||||
gvgoff: true
|
||||
allowks: true
|
||||
me: true
|
||||
marry: true
|
||||
divorce: true
|
||||
refreshall: true
|
||||
}
|
||||
log_commands: true
|
||||
permissions: {
|
||||
can_trade: false
|
||||
any_warp: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 5
|
||||
name: "VIP"
|
||||
inherit: ( "Player" ) /* can do everything Players can */
|
||||
level: 0
|
||||
commands: {
|
||||
rates: true
|
||||
who: true
|
||||
}
|
||||
permissions: {
|
||||
/* no permissions by default */
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 10
|
||||
name: "Law Enforcement"
|
||||
inherit: ( "Support" )
|
||||
level: 2
|
||||
commands: {
|
||||
hide: true
|
||||
follow: true
|
||||
kick: true
|
||||
disguise: true
|
||||
fakename: true
|
||||
option: true
|
||||
speed: true
|
||||
warp: true
|
||||
kill: true
|
||||
recall: true
|
||||
ban: true
|
||||
block: true
|
||||
jail: true
|
||||
jailfor: true
|
||||
mute: true
|
||||
storagelist: true
|
||||
cartlist: true
|
||||
itemlist: true
|
||||
stats: true
|
||||
}
|
||||
log_commands: true
|
||||
permissions: {
|
||||
join_chat: true
|
||||
kick_chat: true
|
||||
hide_session: true
|
||||
who_display_aid: true
|
||||
hack_info: true
|
||||
any_warp: true
|
||||
view_hpmeter: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 99
|
||||
name: "Admin"
|
||||
level: 99
|
||||
inherit: ( "Support", "Law Enforcement" )
|
||||
commands: {
|
||||
/* not necessary due to all_commands: true */
|
||||
}
|
||||
log_commands: true
|
||||
permissions: {
|
||||
can_trade: true
|
||||
can_party: true
|
||||
command_enable: true
|
||||
all_skill: false
|
||||
all_equipment: false
|
||||
skill_unconditional: false
|
||||
use_check: true
|
||||
use_changemaptype: true
|
||||
all_commands: true
|
||||
channel_admin: true
|
||||
can_trade_bounded: true
|
||||
item_unconditional: false
|
||||
bypass_stat_onclone: true
|
||||
bypass_max_stat: true
|
||||
/* all_permission: true */
|
||||
}
|
||||
}
|
||||
)
|
||||
|
245
conf/groups.yml
Normal file
245
conf/groups.yml
Normal file
@ -0,0 +1,245 @@
|
||||
# This file is a part of rAthena.
|
||||
# Copyright(C) 2022 rAthena Development Team
|
||||
# https://rathena.org - https://github.com/rathena
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# Player Group Database
|
||||
###########################################################################
|
||||
#
|
||||
# Player Group Settings
|
||||
#
|
||||
###########################################################################
|
||||
# - Id Group ID.
|
||||
# Name Group name.
|
||||
# Level GM Level used for ranking groups. (Default: 0)
|
||||
# LogCommands Whether atcommands should be logged or not. (Default: false)
|
||||
# Commands: List of atcommands that can be used by this group. (Default: none)
|
||||
# <atcommand name> Whether the specified atcommand can be used by this group or not.
|
||||
# CharCommands: List of charcommands that can be used by this group. (Default: none)
|
||||
# <charcommand name> Whether the specified charcommand can be used by this group or not.
|
||||
# Permissions: List of permissions the group has. (Default: none)
|
||||
# <permission name> Whether the group has this permission or not.
|
||||
# Inherit: List of groups that will be inherited. (Default: none)
|
||||
# <group name> Whether this group will be inherited or not.
|
||||
###########################################################################
|
||||
|
||||
Header:
|
||||
Type: PLAYER_GROUP_DB
|
||||
Version: 1
|
||||
|
||||
Body:
|
||||
- Id: 0
|
||||
# group 0 is the default group for every new account
|
||||
Name: Player
|
||||
Level: 0
|
||||
Commands:
|
||||
changedress: true
|
||||
resurrect: true
|
||||
Permissions:
|
||||
# without this basic permissions regular players could not trade or party
|
||||
can_trade: true
|
||||
can_party: true
|
||||
attendance: true
|
||||
- Id: 1
|
||||
Name: Super Player
|
||||
# Can do everything Players can and more
|
||||
Inherit:
|
||||
Player: true
|
||||
Level: 0
|
||||
Commands:
|
||||
# Informational commands
|
||||
commands: true
|
||||
charcommands: true
|
||||
help: true
|
||||
rates: true
|
||||
uptime: true
|
||||
showdelay: true
|
||||
exp: true
|
||||
mobinfo: true
|
||||
iteminfo: true
|
||||
whodrops: true
|
||||
time: true
|
||||
jailtime: true
|
||||
hominfo: true
|
||||
homstats: true
|
||||
showexp: true
|
||||
showzeny: true
|
||||
whereis: true
|
||||
# Feature commands
|
||||
refresh: true
|
||||
noask: true
|
||||
noks: true
|
||||
autoloot: true
|
||||
alootid: true
|
||||
autoloottype: true
|
||||
autotrade: true
|
||||
request: true
|
||||
go: true
|
||||
breakguild: true
|
||||
channel: true
|
||||
langtype: true
|
||||
Permissions:
|
||||
attendance: false
|
||||
- Id: 2
|
||||
Name: Support
|
||||
Inherit:
|
||||
Super Player: true
|
||||
Level: 1
|
||||
Commands:
|
||||
version: true
|
||||
where: true
|
||||
jumpto: true
|
||||
who: true
|
||||
who2: true
|
||||
who3: true
|
||||
whomap: true
|
||||
whomap2: true
|
||||
whomap3: true
|
||||
users: true
|
||||
broadcast: true
|
||||
localbroadcast: true
|
||||
LogCommands: true
|
||||
Permissions:
|
||||
receive_requests: true
|
||||
view_equipment: true
|
||||
- Id: 3
|
||||
Name: Script Manager
|
||||
Inherit:
|
||||
Support: true
|
||||
Level: 1
|
||||
Commands:
|
||||
tonpc: true
|
||||
hidenpc: true
|
||||
shownpc: true
|
||||
loadnpc: true
|
||||
unloadnpc: true
|
||||
npcmove: true
|
||||
addwarp: true
|
||||
LogCommands: true
|
||||
Permissions:
|
||||
any_warp: true
|
||||
- Id: 4
|
||||
Name: Event Manager
|
||||
Inherit:
|
||||
Support: true
|
||||
Level: 1
|
||||
Commands:
|
||||
monster: true
|
||||
monstersmall: true
|
||||
monsterbig: true
|
||||
killmonster2: true
|
||||
cleanarea: true
|
||||
cleanmap: true
|
||||
item: true
|
||||
zeny: true
|
||||
disguise: true
|
||||
undisguise: true
|
||||
size: true
|
||||
raise: true
|
||||
raisemap: true
|
||||
day: true
|
||||
night: true
|
||||
skillon: true
|
||||
skilloff: true
|
||||
pvpon: true
|
||||
pvpoff: true
|
||||
gvgon: true
|
||||
gvgoff: true
|
||||
allowks: true
|
||||
me: true
|
||||
marry: true
|
||||
divorce: true
|
||||
refreshall: true
|
||||
CharCommands:
|
||||
item: true
|
||||
zeny: true
|
||||
disguise: true
|
||||
undisguise: true
|
||||
size: true
|
||||
LogCommands: true
|
||||
Permissions:
|
||||
can_trade: false
|
||||
any_warp: true
|
||||
- Id: 5
|
||||
Name: VIP
|
||||
# Can do everything Players can
|
||||
Inherit:
|
||||
Player: true
|
||||
Level: 0
|
||||
Commands:
|
||||
rates: true
|
||||
who: true
|
||||
- Id: 10
|
||||
Name: Law Enforcement
|
||||
Inherit:
|
||||
Support: true
|
||||
Level: 2
|
||||
Commands:
|
||||
hide: true
|
||||
follow: true
|
||||
kick: true
|
||||
disguise: true
|
||||
fakename: true
|
||||
option: true
|
||||
speed: true
|
||||
warp: true
|
||||
kill: true
|
||||
recall: true
|
||||
ban: true
|
||||
block: true
|
||||
jail: true
|
||||
jailfor: true
|
||||
mute: true
|
||||
storagelist: true
|
||||
cartlist: true
|
||||
itemlist: true
|
||||
stats: true
|
||||
LogCommands: true
|
||||
Permissions:
|
||||
join_chat: true
|
||||
kick_chat: true
|
||||
hide_session: true
|
||||
who_display_aid: true
|
||||
hack_info: true
|
||||
any_warp: true
|
||||
view_hpmeter: true
|
||||
- Id: 99
|
||||
Name: Admin
|
||||
Level: 99
|
||||
Inherit:
|
||||
Support: true
|
||||
Law Enforcement: true
|
||||
LogCommands: true
|
||||
Permissions:
|
||||
can_trade: true
|
||||
can_party: true
|
||||
command_enable: true
|
||||
all_skill: false
|
||||
all_equipment: false
|
||||
skill_unconditional: false
|
||||
use_check: true
|
||||
use_changemaptype: true
|
||||
all_commands: true
|
||||
channel_admin: true
|
||||
can_trade_bounded: true
|
||||
item_unconditional: false
|
||||
bypass_stat_onclone: true
|
||||
bypass_max_stat: true
|
||||
#all_permission: true
|
||||
|
||||
Footer:
|
||||
Imports:
|
||||
- Path: conf/import/groups.yml
|
41
conf/import-tmpl/groups.yml
Normal file
41
conf/import-tmpl/groups.yml
Normal file
@ -0,0 +1,41 @@
|
||||
# This file is a part of rAthena.
|
||||
# Copyright(C) 2022 rAthena Development Team
|
||||
# https://rathena.org - https://github.com/rathena
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# Player Group Database
|
||||
###########################################################################
|
||||
#
|
||||
# Player Group Settings
|
||||
#
|
||||
###########################################################################
|
||||
# - Id Group ID.
|
||||
# Name Group name.
|
||||
# Level GM Level used for ranking groups. (Default: 0)
|
||||
# LogCommands Whether atcommands should be logged or not. (Default: false)
|
||||
# Commands: List of atcommands that can be used by this group. (Default: none)
|
||||
# <atcommand name> Whether the specified atcommand can be used by this group or not.
|
||||
# CharCommands: List of charcommands that can be used by this group. (Default: none)
|
||||
# <charcommand name> Whether the specified charcommand can be used by this group or not.
|
||||
# Permissions: List of permissions the group has. (Default: none)
|
||||
# <permission name> Whether the group has this permission or not.
|
||||
# Inherit: List of groups that will be inherited. (Default: none)
|
||||
# <group name> Whether this group will be inherited or not.
|
||||
###########################################################################
|
||||
|
||||
Header:
|
||||
Type: PLAYER_GROUP_DB
|
||||
Version: 1
|
@ -616,7 +616,7 @@ ACMD_FUNC(mapmove)
|
||||
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
|
||||
x = y = 0; //Invalid cell, use random spot.
|
||||
}
|
||||
if ((map_getmapflag(m, MF_NOWARPTO) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) || !pc_job_can_entermap((enum e_job)sd->status.class_, m, sd->group_level)) {
|
||||
if ((map_getmapflag(m, MF_NOWARPTO) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) || !pc_job_can_entermap((enum e_job)sd->status.class_, m, pc_get_group_level(sd))) {
|
||||
clif_displaymessage(fd, msg_txt(sd,247)); // You are not authorized to warp to this map.
|
||||
return -1;
|
||||
}
|
||||
@ -794,7 +794,7 @@ ACMD_FUNC(who) {
|
||||
case 2: {
|
||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344),pl_sd->group->name.c_str()); // "(%s) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,347), pl_sd->status.base_level, pl_sd->status.job_level,
|
||||
job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
|
||||
break;
|
||||
@ -804,7 +804,7 @@ ACMD_FUNC(who) {
|
||||
StringBuf_Printf(&buf, msg_txt(sd,912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344), pl_sd->group->name.c_str()); // "(%s) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
|
||||
break;
|
||||
}
|
||||
@ -814,7 +814,7 @@ ACMD_FUNC(who) {
|
||||
|
||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
||||
StringBuf_Printf(&buf, msg_txt(sd,344), pl_sd->group->name.c_str()); // "(%s) "
|
||||
if (p != NULL)
|
||||
StringBuf_Printf(&buf, msg_txt(sd,345), p->party.name); // " | Party: '%s'"
|
||||
if (g != NULL)
|
||||
@ -7284,7 +7284,7 @@ ACMD_FUNC(adjgroup)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!pc_group_exists(new_group)) {
|
||||
if (!player_group_db.exists(new_group)) {
|
||||
clif_displaymessage(fd, msg_txt(sd,1227)); // Specified group does not exist.
|
||||
return -1;
|
||||
}
|
||||
@ -9552,11 +9552,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[sd->group->index] == 0 )
|
||||
continue;
|
||||
break;
|
||||
case COMMAND_ATCOMMAND:
|
||||
if( cmd->at_groups[sd->group_pos] == 0 )
|
||||
if( cmd->at_groups[sd->group->index] == 0 )
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
@ -9815,17 +9815,17 @@ ACMD_FUNC(addperm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( add && (sd->permissions&pc_g_permission_name[i].permission) ) {
|
||||
if( add && pc_has_permission( sd, pc_g_permission_name[i].permission) ){
|
||||
sprintf(atcmd_output, msg_txt(sd,1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission.
|
||||
clif_displaymessage(fd, atcmd_output);
|
||||
return -1;
|
||||
} else if ( !add && !(sd->permissions&pc_g_permission_name[i].permission) ) {
|
||||
}else if( !add && !pc_has_permission( sd, pc_g_permission_name[i].permission ) ){
|
||||
sprintf(atcmd_output, msg_txt(sd,1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission.
|
||||
clif_displaymessage(fd, atcmd_output);
|
||||
sprintf(atcmd_output,msg_txt(sd,1383),sd->status.name); // -- User '%s' Permissions
|
||||
clif_displaymessage(fd, atcmd_output);
|
||||
for( i = 0; i < perm_size; i++ ) {
|
||||
if( sd->permissions&pc_g_permission_name[i].permission ) {
|
||||
if( pc_has_permission( sd, pc_g_permission_name[i].permission ) ){
|
||||
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
||||
clif_displaymessage(fd, atcmd_output);
|
||||
}
|
||||
@ -9834,10 +9834,11 @@ ACMD_FUNC(addperm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( add )
|
||||
sd->permissions |= pc_g_permission_name[i].permission;
|
||||
else
|
||||
sd->permissions &=~ pc_g_permission_name[i].permission;
|
||||
if( add ){
|
||||
sd->permissions.set( pc_g_permission_name[i].permission );
|
||||
}else{
|
||||
sd->permissions.reset( pc_g_permission_name[i].permission );
|
||||
}
|
||||
|
||||
|
||||
sprintf(atcmd_output, msg_txt(sd,1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary.
|
||||
@ -11212,7 +11213,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
||||
return false; // No command found. Display as normal message.
|
||||
|
||||
info = get_atcommandinfo_byname(atcommand_alias_db.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[sd->group->index] == 0) // If we can't use or doesn't exist: don't even display the command failed message
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -11295,8 +11296,8 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
||||
|
||||
// type == 1 : player invoked
|
||||
if (type == 1) {
|
||||
if ((is_atcommand && info->at_groups[sd->group_pos] == 0) ||
|
||||
(!is_atcommand && info->char_groups[sd->group_pos] == 0) )
|
||||
if ((is_atcommand && info->at_groups[sd->group->index] == 0) ||
|
||||
(!is_atcommand && info->char_groups[sd->group->index] == 0) )
|
||||
return false;
|
||||
|
||||
if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
|
||||
@ -11319,29 +11320,22 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
||||
return true;
|
||||
}
|
||||
|
||||
void atcommand_db_load_groups(int* group_ids) {
|
||||
void atcommand_db_load_groups(){
|
||||
DBIterator *iter = db_iterator(atcommand_db);
|
||||
AtCommandInfo* cmd;
|
||||
int i;
|
||||
int pc_group_max = player_group_db.size();
|
||||
|
||||
for (cmd = (AtCommandInfo*)dbi_first(iter); dbi_exists(iter); cmd = (AtCommandInfo*)dbi_next(iter)) {
|
||||
cmd->at_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
||||
cmd->char_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
||||
for(i = 0; i < pc_group_max; i++) {
|
||||
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_ATCOMMAND ) )
|
||||
cmd->at_groups[i] = 1;
|
||||
else
|
||||
cmd->at_groups[i] = 0;
|
||||
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) )
|
||||
cmd->char_groups[i] = 1;
|
||||
else
|
||||
cmd->char_groups[i] = 0;
|
||||
|
||||
for( auto& it : player_group_db ){
|
||||
cmd->at_groups[it.second->index] = it.second->can_use_command( cmd->command, COMMAND_ATCOMMAND );
|
||||
cmd->char_groups[it.second->index] = it.second->can_use_command( cmd->command, COMMAND_CHARCOMMAND );
|
||||
}
|
||||
}
|
||||
|
||||
dbi_destroy(iter);
|
||||
|
||||
return;
|
||||
}
|
||||
void atcommand_db_clear(void) {
|
||||
|
||||
|
@ -25,7 +25,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
||||
|
||||
void do_init_atcommand(void);
|
||||
void do_final_atcommand(void);
|
||||
void atcommand_db_load_groups(int* group_ids);
|
||||
void atcommand_db_load_groups();
|
||||
|
||||
bool atcommand_exists(const char* name);
|
||||
|
||||
|
@ -1342,7 +1342,7 @@ int intif_parse_WisEnd(int fd)
|
||||
*/
|
||||
static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
|
||||
{
|
||||
int permission = va_arg(va, int);
|
||||
e_pc_permission permission = va_arg(va, e_pc_permission);
|
||||
char *wisp_name;
|
||||
char *message;
|
||||
int len;
|
||||
|
@ -294,6 +294,7 @@
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\atcommands.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\atcommands.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\battle_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\battle_conf.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\char_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\char_conf.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\groups.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\groups.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_conf.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_server.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_server.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\log_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\log_conf.txt')" />
|
||||
|
@ -1858,7 +1858,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y, st
|
||||
case NPCTYPE_WARP:
|
||||
if ((!nd->trigger_on_hidden && (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]))) || pc_isdead(sd))
|
||||
break; // hidden or dead chars cannot use warps
|
||||
if (!pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(nd->u.warp.mapindex), sd->group_level))
|
||||
if (!pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(nd->u.warp.mapindex), pc_get_group_level(sd)))
|
||||
break;
|
||||
if (sd->count_rewarp > 10) {
|
||||
ShowWarning("Prevented infinite warp loop for player (%d:%d). Please fix NPC: '%s', path: '%s'\n", sd->status.account_id, sd->status.char_id, nd->exname, nd->path);
|
||||
|
@ -443,7 +443,7 @@ int pc_get_group_id(struct map_session_data *sd) {
|
||||
* @return Group Level
|
||||
*/
|
||||
int pc_get_group_level(struct map_session_data *sd) {
|
||||
return sd->group_level;
|
||||
return sd->group->level;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12454,9 +12454,12 @@ bool pc_isautolooting(struct map_session_data *sd, t_itemid nameid)
|
||||
* @param command Command name without @/# and params
|
||||
* @param type is it atcommand or charcommand
|
||||
*/
|
||||
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type)
|
||||
{
|
||||
return pc_group_can_use_command(pc_get_group_id(sd), command, type);
|
||||
bool pc_can_use_command( struct map_session_data *sd, const char *command, AtCommandType type ){
|
||||
return sd->group->can_use_command( command, type );
|
||||
}
|
||||
|
||||
bool pc_has_permission( struct map_session_data* sd, e_pc_permission permission ){
|
||||
return sd->permissions.test( permission );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12464,9 +12467,8 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command, AtComm
|
||||
* according to their group setting.
|
||||
* @param sd Player map session data
|
||||
*/
|
||||
bool pc_should_log_commands(struct map_session_data *sd)
|
||||
{
|
||||
return pc_group_should_log_commands(pc_get_group_id(sd));
|
||||
bool pc_should_log_commands( struct map_session_data *sd ){
|
||||
return sd->group->log_commands;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef PC_HPP
|
||||
#define PC_HPP
|
||||
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -19,6 +20,7 @@
|
||||
#include "itemdb.hpp" // MAX_ITEMGROUP
|
||||
#include "map.hpp" // RC_ALL
|
||||
#include "mob.hpp" //e_size
|
||||
#include "pc_groups.hpp" // s_player_group
|
||||
#include "script.hpp" // struct script_reg, struct script_regstr
|
||||
#include "searchstore.hpp" // struct s_search_store_info
|
||||
#include "status.hpp" // unit_data
|
||||
@ -408,8 +410,9 @@ struct map_session_data {
|
||||
} special_state;
|
||||
uint32 login_id1, login_id2;
|
||||
uint64 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 */
|
||||
int group_id;
|
||||
std::shared_ptr<s_player_group> group;
|
||||
std::bitset<PC_PERM_MAX> permissions; // group permissions have to be copied, because they might be adjusted by atcommand addperm
|
||||
int count_rewarp; //count how many time we being rewarped
|
||||
|
||||
int langtype;
|
||||
@ -1238,7 +1241,7 @@ bool pc_can_give_bounded_items(struct map_session_data *sd);
|
||||
bool pc_can_trade_item(map_session_data *sd, int index);
|
||||
|
||||
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
|
||||
#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 )
|
||||
bool pc_has_permission( struct map_session_data* sd, e_pc_permission permission );
|
||||
bool pc_should_log_commands(struct map_session_data *sd);
|
||||
|
||||
void pc_setrestartvalue(struct map_session_data *sd, char type);
|
||||
|
@ -3,353 +3,343 @@
|
||||
|
||||
#include "pc_groups.hpp"
|
||||
|
||||
#include "../common/conf.hpp"
|
||||
#include "../common/db.hpp"
|
||||
#include "../common/malloc.hpp"
|
||||
#include "../common/showmsg.hpp"
|
||||
#include "../common/socket.hpp"
|
||||
#include "../common/strlib.hpp" // strcmp
|
||||
#include "../common/socket.hpp" // set_eof
|
||||
#include "../common/strlib.hpp" // strcmpi
|
||||
#include "../common/utilities.hpp"
|
||||
|
||||
#include "atcommand.hpp" // AtCommandType
|
||||
#include "pc.hpp" // e_pc_permission
|
||||
#include "pc.hpp" // struct map_session_data
|
||||
|
||||
typedef struct GroupSettings GroupSettings;
|
||||
using namespace rathena;
|
||||
|
||||
// Cached config settings/pointers for quick lookup
|
||||
struct GroupSettings {
|
||||
unsigned int id; // groups.[].id
|
||||
int level; // groups.[].level
|
||||
const char *name; // groups.[].name
|
||||
config_setting_t *commands; // groups.[].commands
|
||||
unsigned int e_permissions; // packed groups.[].permissions
|
||||
bool log_commands; // groups.[].log_commands
|
||||
/// Following are used only during config reading
|
||||
config_setting_t *permissions; // groups.[].permissions
|
||||
config_setting_t *inherit; // groups.[].inherit
|
||||
bool inheritance_done; // have all inheritance rules been evaluated?
|
||||
config_setting_t *root; // groups.[]
|
||||
int group_pos;/* pos on load */
|
||||
};
|
||||
|
||||
int pc_group_max; /* known number of groups */
|
||||
|
||||
static config_t pc_group_config;
|
||||
static DBMap* pc_group_db; // id -> GroupSettings
|
||||
static DBMap* pc_groupname_db; // name -> GroupSettings
|
||||
|
||||
/**
|
||||
* @retval NULL if not found
|
||||
* @private
|
||||
*/
|
||||
static inline GroupSettings* id2group(int group_id)
|
||||
{
|
||||
return (GroupSettings*)idb_get(pc_group_db, group_id);
|
||||
const std::string PlayerGroupDatabase::getDefaultLocation() {
|
||||
return std::string( conf_path ) + "/groups.yml";
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval NULL if not found
|
||||
* @private
|
||||
*/
|
||||
static inline GroupSettings* name2group(const char* group_name)
|
||||
{
|
||||
return (GroupSettings*)strdb_get(pc_groupname_db, group_name);
|
||||
bool PlayerGroupDatabase::parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands ){
|
||||
for( const auto& it : node.children() ){
|
||||
std::string command;
|
||||
|
||||
c4::from_chars( it.key(), &command );
|
||||
|
||||
bool allowed;
|
||||
|
||||
if( !this->asBool( node, command, allowed ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads group configuration from config file into memory.
|
||||
* @private
|
||||
*/
|
||||
static void read_config(void)
|
||||
{
|
||||
config_setting_t *groups = NULL;
|
||||
const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name
|
||||
int group_count = 0;
|
||||
|
||||
if (conf_read_file(&pc_group_config, config_filename))
|
||||
return;
|
||||
|
||||
groups = config_lookup(&pc_group_config, "groups");
|
||||
|
||||
if (groups != NULL) {
|
||||
GroupSettings *group_settings = NULL;
|
||||
DBIterator *iter = NULL;
|
||||
int i, loop = 0;
|
||||
|
||||
group_count = config_setting_length(groups);
|
||||
for (i = 0; i < group_count; ++i) {
|
||||
int id = 0, level = 0;
|
||||
const char *groupname = NULL;
|
||||
int log_commands = 0;
|
||||
config_setting_t *group = config_setting_get_elem(groups, i);
|
||||
|
||||
if (!config_setting_lookup_int(group, "id", &id)) {
|
||||
ShowConfigWarning(group, "pc_groups:read_config: \"groups\" list member #%d has undefined id, removing...", i);
|
||||
config_setting_remove_elem(groups, i);
|
||||
--i;
|
||||
--group_count;
|
||||
continue;
|
||||
if( !atcommand_exists( command.c_str() ) ){
|
||||
this->invalidWarning( it, "Unknown atcommand: %s\n", command.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id2group(id) != NULL) {
|
||||
ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i);
|
||||
config_setting_remove_elem(groups, i);
|
||||
--i;
|
||||
--group_count;
|
||||
continue;
|
||||
util::tolower( command );
|
||||
|
||||
if( allowed ){
|
||||
if( util::vector_exists( commands, command ) ){
|
||||
this->invalidWarning( it, "Group already has command \"%s\". Please check your data.\n", command.c_str() );
|
||||
return false;
|
||||
}else{
|
||||
commands.push_back( command );
|
||||
}
|
||||
|
||||
config_setting_lookup_int(group, "level", &level);
|
||||
config_setting_lookup_bool(group, "log_commands", &log_commands);
|
||||
|
||||
if (!config_setting_lookup_string(group, "name", &groupname)) {
|
||||
char temp[20];
|
||||
config_setting_t *name = NULL;
|
||||
snprintf(temp, sizeof(temp), "Group %d", id);
|
||||
if ((name = config_setting_add(group, "name", CONFIG_TYPE_STRING)) == NULL ||
|
||||
!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));
|
||||
continue;
|
||||
}
|
||||
config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer
|
||||
}
|
||||
|
||||
if (name2group(groupname) != NULL) {
|
||||
ShowConfigWarning(group, "pc_groups:read_config: duplicate group name %s, removing...", groupname);
|
||||
config_setting_remove_elem(groups, i);
|
||||
--i;
|
||||
--group_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
CREATE(group_settings, GroupSettings, 1);
|
||||
group_settings->id = id;
|
||||
group_settings->level = level;
|
||||
group_settings->name = groupname;
|
||||
group_settings->log_commands = log_commands != 0;
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
// Check if all commands and permissions exist
|
||||
iter = db_iterator(pc_group_db);
|
||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
||||
config_setting_t *commands = group_settings->commands, *permissions = group_settings->permissions;
|
||||
int count = 0, j;
|
||||
|
||||
// Make sure there is "commands" group
|
||||
if (commands == NULL)
|
||||
commands = group_settings->commands = config_setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP);
|
||||
count = config_setting_length(commands);
|
||||
|
||||
for (j = 0; j < count; ++j) {
|
||||
config_setting_t *command = config_setting_get_elem(commands, j);
|
||||
const char *name = config_setting_name(command);
|
||||
if (!atcommand_exists(name)) {
|
||||
ShowConfigWarning(command, "pc_groups:read_config: non-existent command name '%s', removing...", name);
|
||||
config_setting_remove(commands, name);
|
||||
--j;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure there is "permissions" group
|
||||
if (permissions == NULL)
|
||||
permissions = group_settings->permissions = config_setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP);
|
||||
count = config_setting_length(permissions);
|
||||
|
||||
for(j = 0; j < count; ++j) {
|
||||
config_setting_t *permission = config_setting_get_elem(permissions, j);
|
||||
const char *name = config_setting_name(permission);
|
||||
int p;
|
||||
|
||||
ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), p, strcmp(pc_g_permission_name[p].name, name) == 0);
|
||||
if (p == ARRAYLENGTH(pc_g_permission_name)) {
|
||||
ShowConfigWarning(permission, "pc_groups:read_config: non-existent permission name '%s', removing...", name);
|
||||
config_setting_remove(permissions, name);
|
||||
--p;
|
||||
--count;
|
||||
}else{
|
||||
if( !util::vector_exists( commands, command ) ){
|
||||
this->invalidWarning( it, "Group does not have command \"%s\". Please check your data.\n", command.c_str() );
|
||||
return false;
|
||||
}else{
|
||||
util::vector_erase_if_exists( commands, command );
|
||||
}
|
||||
}
|
||||
}
|
||||
dbi_destroy(iter);
|
||||
|
||||
// Apply inheritance
|
||||
i = 0; // counter for processed groups
|
||||
while (i < group_count) {
|
||||
iter = db_iterator(pc_group_db);
|
||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
||||
config_setting_t *inherit = NULL,
|
||||
*commands = group_settings->commands,
|
||||
*permissions = group_settings->permissions;
|
||||
int j, inherit_count = 0, done = 0;
|
||||
|
||||
if (group_settings->inheritance_done) // group already processed
|
||||
continue;
|
||||
|
||||
if ((inherit = group_settings->inherit) == NULL ||
|
||||
(inherit_count = config_setting_length(inherit)) <= 0) { // this group does not inherit from others
|
||||
++i;
|
||||
group_settings->inheritance_done = true;
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (j = 0; j < inherit_count; ++j) {
|
||||
GroupSettings *inherited_group = NULL;
|
||||
const char *groupname = config_setting_get_string_elem(inherit, j);
|
||||
uint64 PlayerGroupDatabase::parseBodyNode( const ryml::NodeRef& node ){
|
||||
uint32 groupId;
|
||||
|
||||
if (groupname == NULL) {
|
||||
ShowConfigWarning(inherit, "pc_groups:read_config: \"inherit\" array member #%d is not a name, removing...", j);
|
||||
config_setting_remove_elem(inherit,j);
|
||||
continue;
|
||||
}
|
||||
if ((inherited_group = name2group(groupname)) == NULL) {
|
||||
ShowConfigWarning(inherit, "pc_groups:read_config: non-existent group name \"%s\", removing...", groupname);
|
||||
config_setting_remove_elem(inherit,j);
|
||||
continue;
|
||||
}
|
||||
if (!inherited_group->inheritance_done)
|
||||
continue; // we need to do that group first
|
||||
|
||||
// Copy settings (commands/permissions) that are not defined yet
|
||||
if (inherited_group->commands != NULL) {
|
||||
int l = 0, commands_count = config_setting_length(inherited_group->commands);
|
||||
for (l = 0; l < commands_count; ++l)
|
||||
config_setting_copy(commands, config_setting_get_elem(inherited_group->commands, l));
|
||||
if( !this->asUInt32( node, "Id", groupId ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inherited_group->permissions != NULL) {
|
||||
int l = 0, permissions_count = config_setting_length(inherited_group->permissions);
|
||||
for (l = 0; l < permissions_count; ++l)
|
||||
config_setting_copy(permissions, config_setting_get_elem(inherited_group->permissions, l));
|
||||
std::shared_ptr<s_player_group> group = this->find( groupId );
|
||||
bool exists = group != nullptr;
|
||||
|
||||
if( !exists ){
|
||||
if( !this->nodesExist( node, { "Name", "Level" })) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
++done; // copied commands and permissions from one of inherited groups
|
||||
group = std::make_shared<s_player_group>();
|
||||
group->id = groupId;
|
||||
group->permissions.reset();
|
||||
}
|
||||
|
||||
if (done == inherit_count) { // copied commands from all of inherited groups
|
||||
++i;
|
||||
group_settings->inheritance_done = true; // we're done with this group
|
||||
}
|
||||
}
|
||||
dbi_destroy(iter);
|
||||
if( this->nodeExists( node, "Name" ) ){
|
||||
std::string name;
|
||||
|
||||
if (++loop > group_count) {
|
||||
ShowWarning("pc_groups:read_config: Could not process inheritance rules, check your config '%s' for cycles...\n",
|
||||
config_filename);
|
||||
if( !this->asString( node, "Name", name ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
group->name = name;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Level" ) ){
|
||||
uint32 level;
|
||||
|
||||
if( !this->asUInt32( node, "Level", level ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level > 99) {
|
||||
this->invalidWarning(node["Level"], "Group level %u exceeds 99, capping.\n", level);
|
||||
level = 99;
|
||||
}
|
||||
|
||||
group->level = level;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "LogCommands" ) ){
|
||||
bool log;
|
||||
|
||||
if( !this->asBool( node, "LogCommands", log ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
group->log_commands = log;
|
||||
}else{
|
||||
if( !exists ){
|
||||
group->log_commands = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Commands" ) && !this->parseCommands( node["Commands"], group->commands ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "CharCommands" ) && !this->parseCommands( node["CharCommands"], group->char_commands ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Permissions" ) ){
|
||||
const auto& permissions = node["Permissions"];
|
||||
|
||||
for( const auto& it : permissions ){
|
||||
std::string permission;
|
||||
|
||||
c4::from_chars( it.key(), &permission );
|
||||
|
||||
bool allowed;
|
||||
|
||||
if( !this->asBool( permissions, permission, allowed ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* str = permission.c_str();
|
||||
bool found = false;
|
||||
|
||||
for( const auto& permission_name : pc_g_permission_name ){
|
||||
if( strcmpi( "all_permission", str ) == 0 ){
|
||||
if( allowed ){
|
||||
group->permissions.set();
|
||||
}else{
|
||||
group->permissions.reset();
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}else if( strcmpi( permission_name.name, str ) == 0 ){
|
||||
if( allowed ){
|
||||
group->permissions.set( permission_name.permission );
|
||||
}else{
|
||||
group->permissions.reset( permission_name.permission );
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
} // while(i < group_count)
|
||||
}
|
||||
|
||||
// Pack permissions into GroupSettings.e_permissions for faster checking
|
||||
iter = db_iterator(pc_group_db);
|
||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
||||
config_setting_t *permissions = group_settings->permissions;
|
||||
int c, count = config_setting_length(permissions);
|
||||
if( !found ){
|
||||
this->invalidWarning( it, "Unknown permission: %s\n", str );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (c = 0; c < count; ++c) {
|
||||
config_setting_t *perm = config_setting_get_elem(permissions, c);
|
||||
const char *name = config_setting_name(perm);
|
||||
int val = config_setting_get_bool(perm);
|
||||
int j;
|
||||
if( this->nodeExists( node, "Inherit" ) ){
|
||||
const auto& inherits = node["Inherit"];
|
||||
|
||||
if (val == 0) // does not have this permission
|
||||
auto& inheritanceVector = this->inheritance[groupId];
|
||||
|
||||
for( const auto& it : inherits ){
|
||||
std::string inherit;
|
||||
|
||||
c4::from_chars( it.key(), &inherit );
|
||||
|
||||
bool enable;
|
||||
|
||||
if( !this->asBool( inherits, inherit, enable ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
util::tolower( inherit );
|
||||
|
||||
if( enable ){
|
||||
if( !util::vector_exists( inheritanceVector, inherit ) ){
|
||||
inheritanceVector.push_back( inherit );
|
||||
}
|
||||
}else{
|
||||
if( !util::vector_exists( inheritanceVector, inherit ) ){
|
||||
this->invalidWarning( it, "Trying to remove inheritance of non-inherited group %s\n", inherit.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
util::vector_erase_if_exists( inheritanceVector, inherit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !exists ){
|
||||
this->put( groupId, group );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PlayerGroupDatabase::loadingFinished(){
|
||||
static const int MAX_CYCLES = 10;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_CYCLES; i++ ){
|
||||
auto inheritanceIt = this->inheritance.begin();
|
||||
|
||||
while( inheritanceIt != this->inheritance.end() ){
|
||||
auto& entry = *inheritanceIt;
|
||||
|
||||
if( entry.second.empty() ){
|
||||
inheritanceIt = this->inheritance.erase( inheritanceIt );
|
||||
continue;
|
||||
ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), j, strcmp(pc_g_permission_name[j].name, name) == 0);
|
||||
group_settings->e_permissions |= pc_g_permission_name[j].permission;
|
||||
}
|
||||
}
|
||||
dbi_destroy(iter);
|
||||
}
|
||||
|
||||
ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' groups in '" CL_WHITE "%s" CL_RESET "'.\n", group_count, config_filename);
|
||||
std::shared_ptr<s_player_group> group = this->find( entry.first );
|
||||
|
||||
auto it = entry.second.begin();
|
||||
|
||||
if( ( pc_group_max = group_count ) ) {
|
||||
DBIterator *iter = db_iterator(pc_group_db);
|
||||
GroupSettings *group_settings = NULL;
|
||||
int* group_ids = (int*)aMalloc( pc_group_max * sizeof(int) );
|
||||
int i = 0;
|
||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
||||
group_ids[i++] = group_settings->id;
|
||||
while( it != entry.second.end() ){
|
||||
std::string& otherName = *it;
|
||||
bool found = false;
|
||||
bool inherited = false;
|
||||
|
||||
for( const auto& it : *this ){
|
||||
std::shared_ptr<s_player_group> otherGroup = it.second;
|
||||
// Copy the string
|
||||
std::string otherGroupName = otherGroup->name;
|
||||
|
||||
util::tolower( otherGroupName );
|
||||
|
||||
if( otherName == otherGroupName ){
|
||||
found = true;
|
||||
|
||||
auto* otherGroupInheritance = util::map_find( this->inheritance, otherGroup->id );
|
||||
|
||||
if( otherGroupInheritance != nullptr && !otherGroupInheritance->empty() ){
|
||||
// Try it again in the next cycle
|
||||
break;
|
||||
}
|
||||
|
||||
atcommand_db_load_groups(group_ids);
|
||||
|
||||
aFree(group_ids);
|
||||
|
||||
dbi_destroy(iter);
|
||||
// Inherit atcommands
|
||||
for( auto& command : otherGroup->commands ){
|
||||
if( !util::vector_exists( group->commands, command ) ){
|
||||
group->commands.push_back( command );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes group configuration from memory.
|
||||
* @private
|
||||
*/
|
||||
static void destroy_config(void)
|
||||
{
|
||||
config_destroy(&pc_group_config);
|
||||
// Inherit charcommands
|
||||
for( auto& command : otherGroup->char_commands ){
|
||||
if( !util::vector_exists( group->char_commands, command ) ){
|
||||
group->char_commands.push_back( command );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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); }
|
||||
// Inherit permissions
|
||||
group->permissions |= otherGroup->permissions;
|
||||
|
||||
inherited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( inherited ){
|
||||
it = entry.second.erase( it );
|
||||
continue;
|
||||
}else if( !found ){
|
||||
ShowError( "Inherited group \"%s\" for group id %u does not exist.\n", otherName.c_str(), group->id );
|
||||
it = entry.second.erase( it );
|
||||
continue;
|
||||
}else{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( this->inheritance.empty() ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i == MAX_CYCLES && !this->inheritance.empty() ){
|
||||
ShowError( "Could not process inheritance rules, check your config for cycles...\n" );
|
||||
}
|
||||
|
||||
// Not needed anymore
|
||||
this->inheritance.clear();
|
||||
|
||||
uint32 index = 0;
|
||||
for( auto& it : *this ){
|
||||
it.second->index = index++;
|
||||
}
|
||||
|
||||
// Initialize command cache
|
||||
atcommand_db_load_groups();
|
||||
}
|
||||
|
||||
PlayerGroupDatabase player_group_db;
|
||||
|
||||
/**
|
||||
* Checks if player group can use @/#command
|
||||
* @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))
|
||||
bool s_player_group::can_use_command( const std::string& command, AtCommandType type ){
|
||||
if( this->has_permission( 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 result != 0;
|
||||
|
||||
// <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 config_setting_get_bool_elem(cmd, AtCommandType2idx(type)) != 0;
|
||||
}
|
||||
|
||||
std::string command_lower = command;
|
||||
|
||||
util::tolower( command_lower );
|
||||
|
||||
switch( type ){
|
||||
case COMMAND_ATCOMMAND:
|
||||
return util::vector_exists( this->commands, command_lower );
|
||||
case COMMAND_CHARCOMMAND:
|
||||
return util::vector_exists( this->char_commands, command_lower );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load permission for player based on group id
|
||||
* @param sd Player
|
||||
*/
|
||||
void pc_group_pc_load(struct map_session_data * sd) {
|
||||
GroupSettings *group = NULL;
|
||||
if ((group = id2group(sd->group_id)) == NULL) {
|
||||
std::shared_ptr<s_player_group> group = player_group_db.find( sd->group_id );
|
||||
|
||||
if( group == nullptr ){
|
||||
ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
|
||||
sd->status.name,
|
||||
sd->status.account_id,
|
||||
@ -357,108 +347,50 @@ void pc_group_pc_load(struct map_session_data * sd) {
|
||||
set_eof(sd->fd);
|
||||
return;
|
||||
}
|
||||
sd->permissions = group->e_permissions;
|
||||
sd->group_pos = group->group_pos;
|
||||
sd->group_level = group->level;
|
||||
|
||||
sd->group = group;
|
||||
sd->permissions = group->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if player group has a permission
|
||||
* @param group_id ID of the group
|
||||
* @param permission permission to check
|
||||
*/
|
||||
bool pc_group_has_permission(int group_id, int permission)
|
||||
{
|
||||
GroupSettings *group = NULL;
|
||||
return (group = id2group(group_id)) == NULL ? false : (group->e_permissions&permission) != 0;
|
||||
bool s_player_group::has_permission( e_pc_permission permission ){
|
||||
return this->permissions.test( permission );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks commands used by player group should be logged
|
||||
* @param group_id ID of the group
|
||||
*/
|
||||
bool pc_group_should_log_commands(int group_id)
|
||||
{
|
||||
GroupSettings *group = NULL;
|
||||
return (group = id2group(group_id)) == NULL ? false : group->log_commands;
|
||||
bool s_player_group::should_log_commands(){
|
||||
return this->log_commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if player group with given ID exists.
|
||||
* @param group_id group id
|
||||
* @returns true if group exists, false otherwise
|
||||
* Initialize PC Groups and read config.
|
||||
*/
|
||||
bool pc_group_exists(int group_id)
|
||||
{
|
||||
return idb_exists(pc_group_db, group_id);
|
||||
void do_init_pc_groups( void ){
|
||||
player_group_db.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group ID -> group name lookup. Used only in @who atcommands.
|
||||
* @param group_id group id
|
||||
* @return group name
|
||||
* @public
|
||||
* Finalize PC Groups
|
||||
*/
|
||||
const char* pc_group_id2name(int group_id)
|
||||
{
|
||||
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
|
||||
* @return group level
|
||||
* @public
|
||||
*/
|
||||
int pc_group_id2level(int group_id)
|
||||
{
|
||||
GroupSettings *group = id2group(group_id);
|
||||
if (group == NULL)
|
||||
return 0;
|
||||
return group->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize PC Groups: allocate DBMaps and read config.
|
||||
* @public
|
||||
*/
|
||||
void do_init_pc_groups(void)
|
||||
{
|
||||
pc_group_db = idb_alloc(DB_OPT_RELEASE_DATA);
|
||||
pc_groupname_db = stridb_alloc(DB_OPT_DUP_KEY, 0);
|
||||
read_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
db_destroy(pc_groupname_db);
|
||||
destroy_config();
|
||||
void do_final_pc_groups( void ){
|
||||
player_group_db.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload PC Groups
|
||||
* Used in @reloadatcommand
|
||||
* @public
|
||||
*/
|
||||
void pc_groups_reload( void ){
|
||||
struct map_session_data* sd = NULL;
|
||||
struct s_mapiterator* iter;
|
||||
|
||||
do_final_pc_groups();
|
||||
do_init_pc_groups();
|
||||
player_group_db.reload();
|
||||
|
||||
/* refresh online users permissions */
|
||||
iter = mapit_getallusers();
|
||||
for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
|
||||
struct s_mapiterator* iter = mapit_getallusers();
|
||||
for( struct map_session_data* sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ){
|
||||
pc_group_pc_load(sd);
|
||||
}
|
||||
mapit_free(iter);
|
||||
|
@ -4,62 +4,58 @@
|
||||
#ifndef PC_GROUPS_HPP
|
||||
#define PC_GROUPS_HPP
|
||||
|
||||
#include "../common/cbasetypes.hpp"
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../common/cbasetypes.hpp"
|
||||
#include "../common/database.hpp"
|
||||
|
||||
// Forward declaration from atcommands.hpp
|
||||
enum AtCommandType : uint8;
|
||||
|
||||
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);
|
||||
void pc_group_pc_load(struct map_session_data *sd);
|
||||
|
||||
void do_init_pc_groups(void);
|
||||
void do_final_pc_groups(void);
|
||||
void pc_groups_reload(void);
|
||||
|
||||
enum e_pc_permission : uint32 {
|
||||
PC_PERM_NONE = 0,
|
||||
PC_PERM_TRADE = 0x00000001,
|
||||
PC_PERM_PARTY = 0x00000002,
|
||||
PC_PERM_ALL_SKILL = 0x00000004,
|
||||
PC_PERM_USE_ALL_EQUIPMENT = 0x00000008,
|
||||
PC_PERM_SKILL_UNCONDITIONAL = 0x00000010,
|
||||
PC_PERM_JOIN_ALL_CHAT = 0x00000020,
|
||||
PC_PERM_NO_CHAT_KICK = 0x00000040,
|
||||
PC_PERM_HIDE_SESSION = 0x00000080,
|
||||
PC_PERM_WHO_DISPLAY_AID = 0x00000100,
|
||||
PC_PERM_RECEIVE_HACK_INFO = 0x00000200,
|
||||
PC_PERM_WARP_ANYWHERE = 0x00000400,
|
||||
PC_PERM_VIEW_HPMETER = 0x00000800,
|
||||
PC_PERM_VIEW_EQUIPMENT = 0x00001000,
|
||||
PC_PERM_USE_CHECK = 0x00002000,
|
||||
PC_PERM_USE_CHANGEMAPTYPE = 0x00004000,
|
||||
PC_PERM_USE_ALL_COMMANDS = 0x00008000,
|
||||
PC_PERM_RECEIVE_REQUESTS = 0x00010000,
|
||||
PC_PERM_SHOW_BOSS = 0x00020000,
|
||||
PC_PERM_DISABLE_PVM = 0x00040000,
|
||||
PC_PERM_DISABLE_PVP = 0x00080000,
|
||||
PC_PERM_DISABLE_CMD_DEAD = 0x00100000,
|
||||
PC_PERM_CHANNEL_ADMIN = 0x00200000,
|
||||
PC_PERM_TRADE_BOUNDED = 0x00400000,
|
||||
PC_PERM_ITEM_UNCONDITIONAL = 0x00800000,
|
||||
PC_PERM_ENABLE_COMMAND = 0x01000000,
|
||||
PC_PERM_BYPASS_STAT_ONCLONE = 0x02000000,
|
||||
PC_PERM_BYPASS_MAX_STAT = 0x04000000,
|
||||
PC_PERM_ATTENDANCE = 0x08000000,
|
||||
PC_PERM_TRADE = 0,
|
||||
PC_PERM_PARTY,
|
||||
PC_PERM_ALL_SKILL,
|
||||
PC_PERM_USE_ALL_EQUIPMENT,
|
||||
PC_PERM_SKILL_UNCONDITIONAL,
|
||||
PC_PERM_JOIN_ALL_CHAT,
|
||||
PC_PERM_NO_CHAT_KICK,
|
||||
PC_PERM_HIDE_SESSION,
|
||||
PC_PERM_WHO_DISPLAY_AID,
|
||||
PC_PERM_RECEIVE_HACK_INFO,
|
||||
PC_PERM_WARP_ANYWHERE,
|
||||
PC_PERM_VIEW_HPMETER,
|
||||
PC_PERM_VIEW_EQUIPMENT,
|
||||
PC_PERM_USE_CHECK,
|
||||
PC_PERM_USE_CHANGEMAPTYPE,
|
||||
PC_PERM_USE_ALL_COMMANDS,
|
||||
PC_PERM_RECEIVE_REQUESTS,
|
||||
PC_PERM_SHOW_BOSS,
|
||||
PC_PERM_DISABLE_PVM,
|
||||
PC_PERM_DISABLE_PVP,
|
||||
PC_PERM_DISABLE_CMD_DEAD,
|
||||
PC_PERM_CHANNEL_ADMIN,
|
||||
PC_PERM_TRADE_BOUNDED,
|
||||
PC_PERM_ITEM_UNCONDITIONAL,
|
||||
PC_PERM_ENABLE_COMMAND,
|
||||
PC_PERM_BYPASS_STAT_ONCLONE,
|
||||
PC_PERM_BYPASS_MAX_STAT,
|
||||
PC_PERM_ATTENDANCE,
|
||||
//.. add other here
|
||||
PC_PERM_ALLPERMISSION = 0xFFFFFFFF,
|
||||
PC_PERM_MAX,
|
||||
};
|
||||
|
||||
static const struct s_pcg_permission_name {
|
||||
const char *name;
|
||||
enum e_pc_permission permission;
|
||||
} pc_g_permission_name[] = {
|
||||
} pc_g_permission_name[PC_PERM_MAX] = {
|
||||
{ "can_trade", PC_PERM_TRADE },
|
||||
{ "can_party", PC_PERM_PARTY },
|
||||
{ "all_skill", PC_PERM_ALL_SKILL },
|
||||
@ -88,7 +84,39 @@ static const struct s_pcg_permission_name {
|
||||
{ "bypass_stat_onclone",PC_PERM_BYPASS_STAT_ONCLONE },
|
||||
{ "bypass_max_stat",PC_PERM_BYPASS_MAX_STAT },
|
||||
{ "attendance",PC_PERM_ATTENDANCE },
|
||||
{ "all_permission", PC_PERM_ALLPERMISSION },
|
||||
};
|
||||
|
||||
struct s_player_group{
|
||||
uint32 id;
|
||||
std::string name;
|
||||
uint32 level;
|
||||
bool log_commands;
|
||||
std::vector<std::string> commands;
|
||||
std::vector<std::string> char_commands;
|
||||
std::bitset<PC_PERM_MAX> permissions;
|
||||
uint32 index;
|
||||
|
||||
public:
|
||||
bool can_use_command( const std::string& command, AtCommandType type );
|
||||
bool has_permission( e_pc_permission permission );
|
||||
bool should_log_commands();
|
||||
};
|
||||
|
||||
class PlayerGroupDatabase : public TypesafeYamlDatabase<uint32, s_player_group>{
|
||||
private:
|
||||
std::map<uint32, std::vector<std::string>> inheritance;
|
||||
bool parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands );
|
||||
|
||||
public:
|
||||
PlayerGroupDatabase() : TypesafeYamlDatabase( "PLAYER_GROUP_DB", 1 ){
|
||||
|
||||
}
|
||||
|
||||
const std::string getDefaultLocation() override;
|
||||
uint64 parseBodyNode( const ryml::NodeRef& node ) override;
|
||||
void loadingFinished() override;
|
||||
};
|
||||
|
||||
extern PlayerGroupDatabase player_group_db;
|
||||
|
||||
#endif /* PC_GROUPS_HPP */
|
||||
|
@ -5833,7 +5833,7 @@ BUILDIN_FUNC(warpparty)
|
||||
}
|
||||
// Fall through
|
||||
case WARPPARTY_RANDOMALLAREA:
|
||||
if(!mapdata->flag[MF_NORETURN] && !mapdata->flag[MF_NOWARP] && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level)){
|
||||
if(!mapdata->flag[MF_NORETURN] && !mapdata->flag[MF_NOWARP] && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pc_get_group_level(pl_sd))){
|
||||
if (rx || ry) {
|
||||
int x1 = x + rx, y1 = y + ry,
|
||||
x0 = x - rx, y0 = y - ry,
|
||||
@ -5929,7 +5929,7 @@ BUILDIN_FUNC(warpguild)
|
||||
pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
|
||||
break;
|
||||
case 3: // m,x,y
|
||||
if(!map_getmapflag(pl_sd->bl.m, MF_NORETURN) && !map_getmapflag(pl_sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
|
||||
if(!map_getmapflag(pl_sd->bl.m, MF_NORETURN) && !map_getmapflag(pl_sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pc_get_group_level(pl_sd)))
|
||||
pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
|
||||
break;
|
||||
}
|
||||
@ -15205,8 +15205,8 @@ int atcommand_sub(struct script_state* st,int type) {
|
||||
}
|
||||
|
||||
// Init Group ID, Level, & permissions
|
||||
sd->group_id = sd->group_level = 99;
|
||||
sd->permissions |= PC_PERM_ALLPERMISSION;
|
||||
sd->group_id = 99;
|
||||
pc_group_pc_load( sd );
|
||||
}
|
||||
|
||||
if (!is_atcommand(fd, sd, cmd, type)) {
|
||||
@ -24100,7 +24100,7 @@ BUILDIN_FUNC(jobcanentermap) {
|
||||
jobid = sd->status.class_;
|
||||
}
|
||||
|
||||
script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? sd->group_level : 0));
|
||||
script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? pc_get_group_level(sd) : 0));
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -10100,7 +10100,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
||||
if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) {
|
||||
if (map_getmapflag(dstsd->bl.m, MF_NOWARP) && !map_flag_gvg2(dstsd->bl.m))
|
||||
continue;
|
||||
if (!pc_job_can_entermap((enum e_job)dstsd->status.class_, src->m, dstsd->group_level))
|
||||
if (!pc_job_can_entermap((enum e_job)dstsd->status.class_, src->m, pc_get_group_level(dstsd)))
|
||||
continue;
|
||||
if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
|
||||
dx[j] = dy[j] = 0;
|
||||
@ -14990,7 +14990,7 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, t_
|
||||
|
||||
sg->val1 = (count<<16)|working;
|
||||
|
||||
if (pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(m), sd->group_level))
|
||||
if (pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(m), pc_get_group_level(sd)))
|
||||
pc_setpos(sd,m,x,y,CLR_TELEPORT);
|
||||
}
|
||||
} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
|
||||
@ -20542,13 +20542,13 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
|
||||
if(group->val1) {
|
||||
sd = map_charid2sd(group->val1);
|
||||
group->val1 = 0;
|
||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
|
||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, pc_get_group_level(sd)))
|
||||
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
||||
}
|
||||
if(group->val2) {
|
||||
sd = map_charid2sd(group->val2);
|
||||
group->val2 = 0;
|
||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
|
||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, pc_get_group_level(sd)))
|
||||
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
||||
}
|
||||
skill_delunit(unit);
|
||||
|
Loading…
x
Reference in New Issue
Block a user