mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 21:36:30 +01:00
234 lines
8.5 KiB
Python
234 lines
8.5 KiB
Python
"""
|
|
The custom manager for Scripts.
|
|
"""
|
|
|
|
from django.db.models import Q
|
|
from src.typeclasses.managers import TypedObjectManager, TypeclassManager
|
|
from src.typeclasses.managers import returns_typeclass_list
|
|
from src.utils.utils import make_iter
|
|
__all__ = ("ScriptManager",)
|
|
_GA = object.__getattribute__
|
|
|
|
VALIDATE_ITERATION = 0
|
|
|
|
|
|
class ScriptDBManager(TypedObjectManager):
|
|
"""
|
|
This Scriptmanager implements methods for searching
|
|
and manipulating Scripts directly from the database.
|
|
|
|
Evennia-specific search methods (will return Typeclasses or
|
|
lists of Typeclasses, whereas Django-general methods will return
|
|
Querysets or database objects).
|
|
|
|
dbref (converter)
|
|
get_id (or dbref_search)
|
|
get_dbref_range
|
|
object_totals
|
|
typeclass_search
|
|
get_all_scripts_on_obj
|
|
get_all_scripts
|
|
delete_script
|
|
remove_non_persistent
|
|
validate
|
|
script_search (equivalent to ev.search_script)
|
|
copy_script
|
|
|
|
"""
|
|
@returns_typeclass_list
|
|
def get_all_scripts_on_obj(self, obj, key=None):
|
|
"""
|
|
Returns as result all the Scripts related to a particular object.
|
|
key can be given as a dbref or name string. If given, only scripts
|
|
matching the key on the object will be returned.
|
|
"""
|
|
if not obj:
|
|
return []
|
|
player = _GA(_GA(obj, "__class__"), "__name__") == "PlayerDB"
|
|
if key:
|
|
dbref = self.dbref(key)
|
|
if dbref or dbref == 0:
|
|
if player:
|
|
return self.filter(db_player=obj, id=dbref)
|
|
else:
|
|
return self.filter(db_obj=obj, id=dbref)
|
|
elif player:
|
|
return self.filter(db_player=obj, db_key=key)
|
|
else:
|
|
return self.filter(db_obj=obj, db_key=key)
|
|
elif player:
|
|
return self.filter(db_player=obj)
|
|
else:
|
|
return self.filter(db_obj=obj)
|
|
|
|
@returns_typeclass_list
|
|
def get_all_scripts(self, key=None):
|
|
"""
|
|
Return all scripts, alternative only
|
|
scripts with a certain key/dbref
|
|
"""
|
|
if key:
|
|
script = []
|
|
dbref = self.dbref(key)
|
|
if dbref or dbref == 0:
|
|
script = self.dbref_search(dbref)
|
|
if not script:
|
|
script = self.filter(db_key=key)
|
|
return script
|
|
return self.all()
|
|
|
|
def delete_script(self, dbref):
|
|
"""
|
|
This stops and deletes a specific script directly
|
|
from the script database. This might be
|
|
needed for global scripts not tied to
|
|
a specific game object.
|
|
"""
|
|
scripts = self.get_id(dbref)
|
|
for script in make_iter(scripts):
|
|
script.stop()
|
|
|
|
def remove_non_persistent(self, obj=None):
|
|
"""
|
|
This cleans up the script database of all non-persistent
|
|
scripts, or only those on obj. It is called every time the server
|
|
restarts.
|
|
"""
|
|
if obj:
|
|
to_stop = self.filter(db_obj=obj, db_persistent=False, db_is_active=True)
|
|
to_delete = self.filter(db_obj=obj, db_persistent=False, db_is_active=False)
|
|
else:
|
|
to_stop = self.filter(db_persistent=False, db_is_active=True)
|
|
to_delete = self.filter(db_persistent=False, db_is_active=False)
|
|
nr_deleted = to_stop.count() + to_delete.count()
|
|
for script in to_stop:
|
|
script.stop()
|
|
for script in to_delete:
|
|
script.delete()
|
|
return nr_deleted
|
|
|
|
def validate(self, scripts=None, obj=None, key=None, dbref=None,
|
|
init_mode=False):
|
|
"""
|
|
This will step through the script database and make sure
|
|
all objects run scripts that are still valid in the context
|
|
they are in. This is called by the game engine at regular
|
|
intervals but can also be initiated by player scripts.
|
|
If key and/or obj is given, only update the related
|
|
script/object.
|
|
|
|
Only one of the arguments are supposed to be supplied
|
|
at a time, since they are exclusive to each other.
|
|
|
|
scripts = a list of scripts objects obtained somewhere.
|
|
obj = validate only scripts defined on a special object.
|
|
key = validate only scripts with a particular key
|
|
dbref = validate only the single script with this particular id.
|
|
|
|
init_mode - This is used during server upstart and can have
|
|
three values:
|
|
False (no init mode). Called during run.
|
|
"reset" - server reboot. Kill non-persistent scripts
|
|
"reload" - server reload. Keep non-persistent scripts.
|
|
|
|
This method also makes sure start any scripts it validates,
|
|
this should be harmless, since already-active scripts
|
|
have the property 'is_running' set and will be skipped.
|
|
"""
|
|
|
|
# we store a variable that tracks if we are calling a
|
|
# validation from within another validation (avoids
|
|
# loops).
|
|
|
|
global VALIDATE_ITERATION
|
|
if VALIDATE_ITERATION > 0:
|
|
# we are in a nested validation. Exit.
|
|
VALIDATE_ITERATION -= 1
|
|
return None, None
|
|
VALIDATE_ITERATION += 1
|
|
|
|
# not in a validation - loop. Validate as normal.
|
|
|
|
nr_started = 0
|
|
nr_stopped = 0
|
|
|
|
if init_mode:
|
|
if init_mode == 'reset':
|
|
# special mode when server starts or object logs in.
|
|
# This deletes all non-persistent scripts from database
|
|
nr_stopped += self.remove_non_persistent(obj=obj)
|
|
# turn off the activity flag for all remaining scripts
|
|
scripts = self.get_all_scripts()
|
|
for script in scripts:
|
|
script.is_active = False
|
|
|
|
elif not scripts:
|
|
# normal operation
|
|
if dbref and self.dbref(dbref, reqhash=False):
|
|
scripts = self.get_id(dbref)
|
|
elif obj:
|
|
#print "calling get_all_scripts_on_obj", obj, key, VALIDATE_ITERATION
|
|
scripts = self.get_all_scripts_on_obj(obj, key=key)
|
|
else:
|
|
scripts = self.get_all_scripts(key=key) #self.model.get_all_cached_instances()
|
|
|
|
if not scripts:
|
|
# no scripts available to validate
|
|
VALIDATE_ITERATION -= 1
|
|
return None, None
|
|
|
|
#print "scripts to validate: [%s]" % (", ".join(script.key for script in scripts))
|
|
for script in scripts:
|
|
#print "validating %s (%i) (init_mode=%s)" % (script.key, id(script), init_mode)
|
|
if script.is_valid():
|
|
nr_started += script.start(force_restart=init_mode)
|
|
#print "back from start. nr_started=", nr_started
|
|
else:
|
|
script.stop()
|
|
nr_stopped += 1
|
|
VALIDATE_ITERATION -= 1
|
|
return nr_started, nr_stopped
|
|
|
|
@returns_typeclass_list
|
|
def script_search(self, ostring, obj=None, only_timed=False):
|
|
"""
|
|
Search for a particular script.
|
|
|
|
ostring - search criterion - a script ID or key
|
|
obj - limit search to scripts defined on this object
|
|
only_timed - limit search only to scripts that run
|
|
on a timer.
|
|
"""
|
|
|
|
ostring = ostring.strip()
|
|
|
|
dbref = self.dbref(ostring)
|
|
if dbref or dbref == 0:
|
|
# this is a dbref, try to find the script directly
|
|
dbref_match = self.dbref_search(dbref)
|
|
if dbref_match and not ((obj and obj != dbref_match.obj)
|
|
or (only_timed and dbref_match.interval)):
|
|
return [dbref_match]
|
|
|
|
# not a dbref; normal search
|
|
obj_restriction = obj and Q(db_obj=obj) or Q()
|
|
timed_restriction = only_timed and Q(interval__gt=0) or Q()
|
|
scripts = self.filter(timed_restriction & obj_restriction & Q(db_key__iexact=ostring))
|
|
return scripts
|
|
|
|
def copy_script(self, original_script, new_key=None, new_obj=None, new_locks=None):
|
|
"""
|
|
Make an identical copy of the original_script
|
|
"""
|
|
typeclass = original_script.typeclass_path
|
|
new_key = new_key if new_key is not None else original_script.key
|
|
new_obj = new_obj if new_obj is not None else original_script.obj
|
|
new_locks = new_locks if new_locks is not None else original_script.db_lock_storage
|
|
|
|
from src.utils import create
|
|
new_script = create.create_script(typeclass, key=new_key, obj=new_obj,
|
|
locks=new_locks, autostart=True)
|
|
return new_script
|
|
|
|
class ScriptManager(ScriptDBManager, TypeclassManager):
|
|
pass
|