Patched the batch-processor's interactive mode so it will not abort if it processes an object/script parent that changes the player's state. Also added a variable BATCH_IMPORT_PATH to config so one can keep all batch scripts in one location and don't have to write the full path to get them. Default is the new directory game/gamesrc/world.
Added the permission genperms.admin_nostate so that builders can avoid entering a state when working on a room with a state-changing parent. Superusers have to set the flag ADMIN_NOSTATE on themselves to achieve the same effect (this is necessary since superusers always have all permissions, so they would otherwise never be able to enter states). /Griatch
This commit is contained in:
parent
c4114938cc
commit
a6ae6e936a
4 changed files with 63 additions and 16 deletions
|
|
@ -48,6 +48,7 @@ An example batch file is found in game/gamesrc/commands/examples.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from django.conf import settings
|
||||||
from src import logger
|
from src import logger
|
||||||
from src import defines_global
|
from src import defines_global
|
||||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||||
|
|
@ -55,7 +56,7 @@ from src.statetable import GLOBAL_STATE_TABLE
|
||||||
|
|
||||||
#global defines for storage
|
#global defines for storage
|
||||||
|
|
||||||
STATENAME="interactive batch processor"
|
STATENAME="_interactive batch processor"
|
||||||
CMDSTACKS={} # user:cmdstack pairs (for interactive)
|
CMDSTACKS={} # user:cmdstack pairs (for interactive)
|
||||||
STACKPTRS={} # user:stackpointer pairs (for interactive)
|
STACKPTRS={} # user:stackpointer pairs (for interactive)
|
||||||
FILENAMES={} # user:filename pairs (for interactive/reload)
|
FILENAMES={} # user:filename pairs (for interactive/reload)
|
||||||
|
|
@ -69,8 +70,10 @@ cnorm = r"%cn"
|
||||||
def read_batchbuild_file(filename):
|
def read_batchbuild_file(filename):
|
||||||
"""
|
"""
|
||||||
This reads the contents of batchfile.
|
This reads the contents of batchfile.
|
||||||
|
Filename is considered to be the name of the batch file
|
||||||
|
relative the directory specified in settings.py
|
||||||
"""
|
"""
|
||||||
filename = os.path.abspath(filename)
|
filename = os.path.abspath("%s/%s" % (settings.BATCH_IMPORT_PATH, filename))
|
||||||
try:
|
try:
|
||||||
f = open(filename)
|
f = open(filename)
|
||||||
except IOError:
|
except IOError:
|
||||||
|
|
@ -191,12 +194,15 @@ def cmd_batchprocess(command):
|
||||||
#parse indata file
|
#parse indata file
|
||||||
commands = parse_batchbuild_file(filename)
|
commands = parse_batchbuild_file(filename)
|
||||||
if not commands:
|
if not commands:
|
||||||
source_object.emit_to("'%s'\ncould not be found. Remember that you have to supply the absolute path to the file." % filename)
|
source_object.emit_to("'%s' not found.\nYou have to supply the real path to the file relative to \nyour batch-file directory (e.g. game/gamesrc/world)." % filename)
|
||||||
return
|
return
|
||||||
switches = command.command_switches
|
switches = command.command_switches
|
||||||
if switches and switches[0] in ['inter','interactive']:
|
if switches and switches[0] in ['inter','interactive']:
|
||||||
# allow more control over how batch file is executed
|
# allow more control over how batch file is executed
|
||||||
source_object.set_state(STATENAME)
|
if not source_object.set_state(STATENAME):
|
||||||
|
source_object.emit_to("You cannot use the interactive mode while you have the flag ADMIN_NOSTATE set.")
|
||||||
|
return
|
||||||
|
|
||||||
CMDSTACKS[source_object] = commands
|
CMDSTACKS[source_object] = commands
|
||||||
STACKPTRS[source_object] = 0
|
STACKPTRS[source_object] = 0
|
||||||
FILENAMES[source_object] = filename
|
FILENAMES[source_object] = filename
|
||||||
|
|
@ -288,7 +294,10 @@ def exit_state(source_object):
|
||||||
del FILENAMES[source_object]
|
del FILENAMES[source_object]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.log_errmsg("Batchprocessor quit error: all state vars could not be deleted.")
|
logger.log_errmsg("Batchprocessor quit error: all state vars could not be deleted.")
|
||||||
source_object.clear_state()
|
# since clear_state() is protected against exiting the interactive mode
|
||||||
|
# (to avoid accidental drop-outs by rooms clearing a player's state),
|
||||||
|
# we have to clear the state directly here.
|
||||||
|
source_object.state = None
|
||||||
|
|
||||||
def cmd_state_ll(command):
|
def cmd_state_ll(command):
|
||||||
"""
|
"""
|
||||||
|
|
@ -517,7 +526,7 @@ def cmd_state_hh(command):
|
||||||
#create the state; we want it as open as possible so we can do everything
|
#create the state; we want it as open as possible so we can do everything
|
||||||
# in our batch processing.
|
# in our batch processing.
|
||||||
GLOBAL_STATE_TABLE.add_state(STATENAME,global_cmds='all',
|
GLOBAL_STATE_TABLE.add_state(STATENAME,global_cmds='all',
|
||||||
allow_exits=True,allow_obj_cmds=True)
|
allow_exits=True,allow_obj_cmds=True,exit_command=True)
|
||||||
#add state commands
|
#add state commands
|
||||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_nn)
|
GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_nn)
|
||||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"nl",cmd_state_nl)
|
GLOBAL_STATE_TABLE.add_command(STATENAME,"nl",cmd_state_nl)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ SRC_DIR = os.path.join(BASE_PATH, 'src')
|
||||||
# Example: "/home/media/media.lawrence.com"
|
# Example: "/home/media/media.lawrence.com"
|
||||||
MEDIA_ROOT = os.path.join(GAME_DIR, 'web', 'media')
|
MEDIA_ROOT = os.path.join(GAME_DIR, 'web', 'media')
|
||||||
|
|
||||||
# Import style path to the script parent module. Must be in the import path.
|
# Import style path to the directory holding script parents. Must be in the import path.
|
||||||
SCRIPT_IMPORT_PATH = 'game.gamesrc.parents'
|
SCRIPT_IMPORT_PATH = 'game.gamesrc.parents'
|
||||||
# Default parent associated with non-player objects. This starts from where
|
# Default parent associated with non-player objects. This starts from where
|
||||||
# the SCRIPT_IMPORT_PATH left off.
|
# the SCRIPT_IMPORT_PATH left off.
|
||||||
|
|
@ -52,6 +52,10 @@ SCRIPT_DEFAULT_OBJECT = 'base.basicobject'
|
||||||
# Default parent associated with player objects. This starts from where
|
# Default parent associated with player objects. This starts from where
|
||||||
# the SCRIPT_IMPORT_PATH left off.
|
# the SCRIPT_IMPORT_PATH left off.
|
||||||
SCRIPT_DEFAULT_PLAYER = 'base.basicplayer'
|
SCRIPT_DEFAULT_PLAYER = 'base.basicplayer'
|
||||||
|
# Real path to a directory to be searched for batch scripts for the
|
||||||
|
# batch processor. Specify relative evennia's 'game' directory.
|
||||||
|
BATCH_IMPORT_PATH = 'gamesrc/world'
|
||||||
|
|
||||||
|
|
||||||
# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3', and 'oracle'.
|
# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3', and 'oracle'.
|
||||||
DATABASE_ENGINE = 'sqlite3'
|
DATABASE_ENGINE = 'sqlite3'
|
||||||
|
|
@ -125,9 +129,10 @@ PERM_GENPERMS = (
|
||||||
("announce", "May make announcements to everyone."),
|
("announce", "May make announcements to everyone."),
|
||||||
("admin_perm", "Can modify individual permissions."),
|
("admin_perm", "Can modify individual permissions."),
|
||||||
("admin_group", "Can manage membership in groups."),
|
("admin_group", "Can manage membership in groups."),
|
||||||
("process_control", "May shutdown/restart/reload the game"),
|
("process_control", "May shutdown/restart/reload the game."),
|
||||||
("manage_players", "Can change passwords, siteban, etc."),
|
("manage_players", "Can change passwords, siteban, etc."),
|
||||||
("game_info", "Can review game metadata"),)
|
("game_info", "Can review game metadata."),
|
||||||
|
("admin_nostate", "Do not enter states (should be set only temporarily)."),)
|
||||||
|
|
||||||
## These permissions are not yet used in the default engine.
|
## These permissions are not yet used in the default engine.
|
||||||
## ("boot", "May use @boot to kick players"),
|
## ("boot", "May use @boot to kick players"),
|
||||||
|
|
|
||||||
|
|
@ -1090,12 +1090,45 @@ class Object(models.Model):
|
||||||
"""
|
"""
|
||||||
Only allow setting a state on a player object, otherwise
|
Only allow setting a state on a player object, otherwise
|
||||||
fail silently.
|
fail silently.
|
||||||
|
|
||||||
|
This command safeguards the batch processor against dropping
|
||||||
|
out of interactive mode; it also allows builders to
|
||||||
|
sidestep room-based states when building (the genperm.admin_nostate
|
||||||
|
permission is not set on anyone by default, set it temporarily
|
||||||
|
when building a state-based room).
|
||||||
"""
|
"""
|
||||||
if self.is_player():
|
if not self.is_player():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.is_superuser():
|
||||||
|
# we have to deal with superusers separately since
|
||||||
|
# they would always appear to have the genperm.admin_nostate
|
||||||
|
# permission. Instead we expect them to set the flag
|
||||||
|
# ADMIN_NOSTATE on themselves if they don't want to
|
||||||
|
# enter states.
|
||||||
|
nostate = self.has_flag("admin_nostate")
|
||||||
|
else:
|
||||||
|
# for other users we request the permission as normal.
|
||||||
|
nostate = self.has_perm("genperms.admin_nostate")
|
||||||
|
|
||||||
|
# we never enter other states if we are in the interactive batch processor.
|
||||||
|
nostate = nostate or self.state == "_interactive batch processor"
|
||||||
|
|
||||||
|
if nostate:
|
||||||
|
return False
|
||||||
self.state = state_name
|
self.state = state_name
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def clear_state(self):
|
def clear_state(self):
|
||||||
"Set to no state (return to normal operation)"
|
"""
|
||||||
|
Set to no state (return to normal operation)
|
||||||
|
|
||||||
|
This safeguards the batch processor from exiting its
|
||||||
|
interactive mode when entering a room cancelling states.
|
||||||
|
(batch processor clears the state directly instead)
|
||||||
|
"""
|
||||||
|
if not self.state == "_interactive batch processor":
|
||||||
self.state = None
|
self.state = None
|
||||||
|
|
||||||
def purge_object(self):
|
def purge_object(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue