diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0d1917c4e4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing to Evennia + +Evennia utilizes GitHub for issue tracking and contributions: + + - Reporting Issues issues/bugs and making feature requests can be done [in the issue tracker](https://github.com/evennia/evennia/issues). + - Evennia's documentation is a [wiki](https://github.com/evennia/evennia/wiki) that everyone can contribute to. Further + instructions and details about contributing is found [here](https://github.com/evennia/evennia/wiki/Contributing). diff --git a/evennia/contrib/tutorial_world/build.ev b/evennia/contrib/tutorial_world/build.ev index 1184865004..ce1bbe4bcf 100644 --- a/evennia/contrib/tutorial_world/build.ev +++ b/evennia/contrib/tutorial_world/build.ev @@ -744,7 +744,7 @@ hole the remains of the castle. There is also a standing archway offering passage to a path along the old |wsouth|nern inner wall. # -@detail portoculis;fall;fallen;grating = +@detail portcullis;fall;fallen;grating = This heavy iron grating used to block off the inner part of the gate house, now it has fallen to the ground together with the stone archway that once help it up. # @@ -786,7 +786,7 @@ archway The buildings make a half-circle along the main wall, here and there broken by falling stone and rubble. At one end (the |wnorth|nern) of this half-circle is the entrance to the castle, the ruined - gatehoue. |wEast|nwards from here is some sort of open courtyard. + gatehouse. |wEast|nwards from here is some sort of open courtyard. #------------------------------------------------------------ # @@ -808,7 +808,7 @@ archway Previously one could probably continue past the obelisk and eastward into the castle keep itself, but that way is now completely blocked by fallen rubble. To the |wwest|n is the gatehouse and entrance to - the castle, whereas |wsouth|nwards the collumns make way for a wide + the castle, whereas |wsouth|nwards the columns make way for a wide open courtyard. # @set here/tutorial_info = diff --git a/evennia/server/portal/irc.py b/evennia/server/portal/irc.py index d74fbaa86e..2b616f2ce1 100644 --- a/evennia/server/portal/irc.py +++ b/evennia/server/portal/irc.py @@ -421,7 +421,7 @@ class IRCBotFactory(protocol.ReconnectingClientFactory): def clientConnectionLost(self, connector, reason): """ - Called when Client looses connection. + Called when Client loses connection. Args: connector (Connection): Represents the connection. diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 9efbb6314b..d868898861 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -138,7 +138,7 @@ HTTP_LOG_FILE = os.path.join(LOG_DIR, 'http_requests.log') LOCKWARNING_LOG_FILE = os.path.join(LOG_DIR, 'lockwarnings.log') # Rotate log files when server and/or portal stops. This will keep log # file sizes down. Turn off to get ever growing log files and never -# loose log info. +# lose log info. CYCLE_LOGFILES = True # Number of lines to append to rotating channel logs when they rotate CHANNEL_LOG_NUM_TAIL_LINES = 20 diff --git a/evennia/utils/create.py b/evennia/utils/create.py index 36db7e5a60..ae7e867f27 100644 --- a/evennia/utils/create.py +++ b/evennia/utils/create.py @@ -229,6 +229,12 @@ def create_script(typeclass=None, key=None, obj=None, account=None, locks=None, # at_first_save hook on the typeclass, where the _createdict # can be used. new_script.save() + + if not new_script.id: + # this happens in the case of having a repeating script with `repeats=1` and + # `start_delay=False` - the script will run once and immediately stop before save is over. + return None + return new_script diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index fcda53cdfd..54b0ac33d2 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -397,6 +397,11 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): super(SharedMemoryModel, cls).save(*args, **kwargs) callFromThread(_save_callback, self, *args, **kwargs) + if not self.pk: + # this can happen if some of the startup methods immediately + # delete the object (an example are Scripts that start and die immediately) + return + # update field-update hooks and eventual OOB watchers new = False if "update_fields" in kwargs and kwargs["update_fields"]: @@ -421,6 +426,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): # fieldtracker = "_oob_at_%s_postsave" % fieldname # if hasattr(self, fieldtracker): # _GA(self, fieldtracker)(fieldname) + pass class WeakSharedMemoryModelBase(SharedMemoryModelBase): diff --git a/evennia/utils/tests/test_create_functions.py b/evennia/utils/tests/test_create_functions.py new file mode 100644 index 0000000000..2d5b1eeaf0 --- /dev/null +++ b/evennia/utils/tests/test_create_functions.py @@ -0,0 +1,79 @@ +""" +Tests of create functions + +""" + +from evennia.utils.test_resources import EvenniaTest +from evennia.scripts.scripts import DefaultScript +from evennia.utils import create + + +class TestCreateScript(EvenniaTest): + + def test_create_script(self): + class TestScriptA(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.persistent = False + + script = create.create_script(TestScriptA, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.key == 'test_script' + script.stop() + + def test_create_script_w_repeats_equal_1(self): + class TestScriptB(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 1 + self.persistent = False + + # script is already stopped (interval=1, start_delay=False) + script = create.create_script(TestScriptB, key='test_script') + assert script is None + + def test_create_script_w_repeats_equal_1_persisted(self): + class TestScriptB1(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 1 + self.persistent = True + + # script is already stopped (interval=1, start_delay=False) + script = create.create_script(TestScriptB1, key='test_script') + assert script is None + + def test_create_script_w_repeats_equal_2(self): + class TestScriptC(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 2 + self.persistent = False + + script = create.create_script(TestScriptC, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 2 + assert script.key == 'test_script' + script.stop() + + def test_create_script_w_repeats_equal_1_and_delayed(self): + class TestScriptD(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.start_delay = True + self.repeats = 1 + self.persistent = False + + script = create.create_script(TestScriptD, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 1 + assert script.key == 'test_script' + script.stop()