From 27babf4469ffb1927bcab4fb585933d13e1b8c48 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 17 Feb 2020 01:11:31 +0100 Subject: [PATCH] Add inside_rec lockfunc. Resolves #1618 --- CHANGELOG.md | 2 ++ evennia/locks/lockfuncs.py | 30 +++++++++++++++++++++++++++++- evennia/locks/tests.py | 8 ++++++++ evennia/server/portal/amp.py | 8 ++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c011be68..6a22e04dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,8 @@ without arguments starts a full interactive Python console. `.get_command_info()` method for easier overloading and access. (Volund) - Removed unused `CYCLE_LOGFILES` setting. Added `SERVER_LOG_DAY_ROTATION` and `SERVER_LOG_MAX_SIZE` (and equivalent for PORTAL) to control log rotation. +- Addded `inside_rec` lockfunc - if room is locked, the normal `inside()` lockfunc will + fail e.g. for your inventory objs (since their loc is you), whereas this will pass. ## Evennia 0.9 (2018-2019) diff --git a/evennia/locks/lockfuncs.py b/evennia/locks/lockfuncs.py index bd137aed8b..eda4c2d733 100644 --- a/evennia/locks/lockfuncs.py +++ b/evennia/locks/lockfuncs.py @@ -547,11 +547,39 @@ def inside(accessing_obj, accessed_obj, *args, **kwargs): Usage: inside() - Only true if accessing_obj is "inside" accessed_obj + True if accessing_obj is 'inside' accessing_obj. Note that this only checks + one level down. So if if the lock is on a room, you will pass but not your + inventory (since their location is you, not the locked object). If you + want also nested objects to pass the lock, use the `insiderecursive` + lockfunc. """ return accessing_obj.location == accessed_obj +def inside_rec(accessing_obj, accessed_obj, *args, **kwargs): + """ + Usage: + inside_rec() + + True if accessing_obj is inside the accessed obj, at up to 10 levels + of recursion (so if this lock is on a room, then an object inside a box + in your inventory will also pass the lock). + """ + + def _recursive_inside(obj, accessed_obj, lvl=1): + if obj.location: + if obj.location == accessed_obj: + return True + elif lvl >= 10: + # avoid infinite recursions + return False + else: + return _recursive_inside(obj.location, accessed_obj, lvl + 1) + return False + + return _recursive_inside(accessing_obj, accessed_obj) + + def holds(accessing_obj, accessed_obj, *args, **kwargs): """ Usage: diff --git a/evennia/locks/tests.py b/evennia/locks/tests.py index bb02877f06..dce0e28fff 100644 --- a/evennia/locks/tests.py +++ b/evennia/locks/tests.py @@ -17,6 +17,7 @@ except ImportError: from evennia import settings_default from evennia.locks import lockfuncs +from evennia.utils.create import create_object # ------------------------------------------------------------ # Lock testing @@ -179,6 +180,13 @@ class TestLockfuncs(EvenniaTest): self.assertEqual(False, lockfuncs.inside(self.char1, self.room2)) self.assertEqual(True, lockfuncs.holds(self.room1, self.char1)) self.assertEqual(False, lockfuncs.holds(self.room2, self.char1)) + # test recursively + self.assertEqual(True, lockfuncs.inside_rec(self.char1, self.room1)) + self.assertEqual(False, lockfuncs.inside_rec(self.char1, self.room2)) + inventory_item = create_object(key="InsideTester", location=self.char1) + self.assertEqual(True, lockfuncs.inside_rec(inventory_item, self.room1)) + self.assertEqual(False, lockfuncs.inside_rec(inventory_item, self.room2)) + inventory_item.delete() def test_has_account(self): self.assertEqual(True, lockfuncs.has_account(self.char1, None)) diff --git a/evennia/server/portal/amp.py b/evennia/server/portal/amp.py index 0d4924a540..505ea5e3e0 100644 --- a/evennia/server/portal/amp.py +++ b/evennia/server/portal/amp.py @@ -314,7 +314,9 @@ class AMPMultiConnectionProtocol(amp.AMP): try: super(AMPMultiConnectionProtocol, self).dataReceived(data) except KeyError: - _get_logger().log_trace("Discarded incoming partial (packed) data (len {})".format(len(data))) + _get_logger().log_trace( + "Discarded incoming partial (packed) data (len {})".format(len(data)) + ) elif self.multibatches: # invalid AMP, but we have a pending multi-batch that is not yet complete if data[-2:] == NULNUL: @@ -323,7 +325,9 @@ class AMPMultiConnectionProtocol(amp.AMP): try: super(AMPMultiConnectionProtocol, self).dataReceived(data) except KeyError: - _get_logger().log_trace("Discarded incoming multi-batch (packed) data (len {})".format(len(data))) + _get_logger().log_trace( + "Discarded incoming multi-batch (packed) data (len {})".format(len(data)) + ) else: # not an AMP communication, return warning self.transport.write(_HTTP_WARNING)