mirror of
https://github.com/evennia/evennia.git
synced 2026-03-20 23:06:31 +01:00
Migrate. Made Exits work differently, by use of commands directly instead of an exithandler assigning commands on-the-fly. This solution is a lot cleaner and also solves an issue where @reload would kill typeclasses in situations where an exit was painting to an object whose typeclass was reloaded (same issue occured if the exit typeclass itself was reloaded). As part of these fixes I cleaned up the merging of cmdsets to now merge in strict priority order, as one would expect them to do. Many small bug-fixes and cleanups all over. Resolves issue 164. Resolves issue 163.
This commit is contained in:
parent
4bcd5239b5
commit
b8a13a2389
17 changed files with 323 additions and 298 deletions
|
|
@ -17,8 +17,6 @@ they control by simply linking to a new object's user property.
|
|||
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
from src.commands import cmdset, command
|
||||
from src.objects.exithandler import EXITHANDLER
|
||||
|
||||
|
||||
#
|
||||
# Base class to inherit from.
|
||||
|
|
@ -77,6 +75,12 @@ class Object(TypeClass):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_cache(self):
|
||||
"""
|
||||
Called whenever this object is cached or reloaded.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_first_login(self):
|
||||
"""
|
||||
Only called once, the very first
|
||||
|
|
@ -401,49 +405,113 @@ class Room(Object):
|
|||
|
||||
class Exit(Object):
|
||||
"""
|
||||
This is the base exit object - it connects a location
|
||||
to another. What separates it from other objects
|
||||
is that it has the 'destination' property defined.
|
||||
Note that property is the only identifier to
|
||||
separate an exit from normal objects, so if the property
|
||||
is removed, it will be treated like any other object. This
|
||||
also means that any object can be made an exit by setting
|
||||
the property destination to a valid location
|
||||
('Quack like a duck...' and so forth).
|
||||
This is the base exit object - it connects a location to
|
||||
another. This is done by the exit assigning a "command" on itself
|
||||
with the same name as the exit object (to do this we need to
|
||||
remember to re-create the command when the object is cached since it must be
|
||||
created dynamically depending on what the exit is called). This
|
||||
command (which has a high priority) will thus allow us to traverse exits
|
||||
simply by giving the exit-object's name on its own.
|
||||
|
||||
"""
|
||||
|
||||
# Helper classes and methods to implement the Exit. These need not
|
||||
# be overloaded unless one want to change the foundation for how
|
||||
# Exits work. See the end of the class for hook methods to overload.
|
||||
|
||||
def create_exit_cmdset(self, exidbobj):
|
||||
"""
|
||||
Helper function for creating an exit command set + command.
|
||||
|
||||
Note that exitdbobj is an ObjectDB instance. This is necessary for
|
||||
handling reloads and avoid tracebacks while the typeclass system
|
||||
is rebooting.
|
||||
"""
|
||||
|
||||
class ExitCommand(command.Command):
|
||||
"""
|
||||
This is a command that simply cause the caller
|
||||
to traverse the object it is attached to.
|
||||
"""
|
||||
locks = "cmd:all()" # should always be set to this.
|
||||
obj = None
|
||||
|
||||
def func(self):
|
||||
"Default exit traverse if no syscommand is defined."
|
||||
|
||||
if self.obj.access(self.caller, 'traverse'):
|
||||
# we may traverse the exit.
|
||||
|
||||
old_location = None
|
||||
if hasattr(self.caller, "location"):
|
||||
old_location = self.caller.location
|
||||
|
||||
# call pre/post hooks and move object.
|
||||
self.obj.at_before_traverse(self.caller)
|
||||
self.caller.move_to(self.obj.destination)
|
||||
self.obj.at_after_traverse(self.caller, old_location)
|
||||
|
||||
else:
|
||||
if self.obj.db.err_traverse:
|
||||
# if exit has a better error message, let's use it.
|
||||
self.caller.msg(self.obj.db.err_traverse)
|
||||
else:
|
||||
# No shorthand error message. Call hook.
|
||||
self.obj.at_failed_traverse(self.caller)
|
||||
|
||||
# create an exit command.
|
||||
cmd = ExitCommand()
|
||||
cmd.key = exidbobj.db_key.strip().lower()
|
||||
cmd.obj = exidbobj
|
||||
cmd.aliases = exidbobj.aliases
|
||||
cmd.destination = exidbobj.db_destination
|
||||
# create a cmdset
|
||||
exit_cmdset = cmdset.CmdSet(None)
|
||||
exit_cmdset.key = '_exitset'
|
||||
exit_cmdset.priority = 9
|
||||
exit_cmdset.duplicates = True
|
||||
# add command to cmdset
|
||||
exit_cmdset.add(cmd)
|
||||
return exit_cmdset
|
||||
|
||||
# Command hooks
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
Setup exit-security
|
||||
|
||||
Don't change this, instead edit at_object_creation() to
|
||||
overload the defaults (it is called after this one).
|
||||
overload the default locks (it is called after this one).
|
||||
"""
|
||||
# the lock is open to all by default
|
||||
super(Exit, self).basetype_setup()
|
||||
|
||||
self.locks.add("puppet:false()") # would be weird to puppet an exit ...
|
||||
self.locks.add("traverse:all()") # who can pass through exit by default
|
||||
self.locks.add("get:false()") # noone can pick up the exit
|
||||
|
||||
|
||||
# this is the fundamental thing for making the Exit work:
|
||||
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
|
||||
# an exit should have a destination (this is replaced at creation time)
|
||||
if self.dbobj.location:
|
||||
self.destination = self.dbobj.location
|
||||
|
||||
# setting default locks (overload these in at_object_creation()
|
||||
self.locks.add("puppet:false()") # would be weird to puppet an exit ...
|
||||
self.locks.add("traverse:all()") # who can pass through exit by default
|
||||
self.locks.add("get:false()") # noone can pick up the exit
|
||||
|
||||
def at_object_delete(self):
|
||||
"""
|
||||
We have to make sure to clean the exithandler cache
|
||||
when deleting the exit, or a new exit could be created
|
||||
out of sync with the cache. You should do this also if
|
||||
overloading this function in a child class.
|
||||
"""
|
||||
EXITHANDLER.clear(self.dbobj)
|
||||
return True
|
||||
def at_cache(self):
|
||||
"Called when the typeclass is re-cached or reloaded. Should usually not be edited."
|
||||
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
|
||||
|
||||
# this and other hooks are what usually can be modified safely.
|
||||
|
||||
def at_object_creation(self):
|
||||
"Called once, when object is first created (after basetype_setup)."
|
||||
pass
|
||||
|
||||
def at_failed_traverse(self, traversing_object):
|
||||
"""
|
||||
This is called if an object fails to traverse this object for some
|
||||
reason. It will not be called if the attribute "err_traverse" is defined,
|
||||
that attribute will then be echoed back instead as a convenient shortcut.
|
||||
|
||||
(See also hooks at_before_traverse and at_after_traverse).
|
||||
"""
|
||||
traversing_object.msg("You cannot enter %s." % self.key)
|
||||
|
||||
traversing_object.msg("You cannot go there.")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue