From 8023adddef1b4724ce717bb5ba8518a102ee1387 Mon Sep 17 00:00:00 2001 From: davewiththenicehat <54369722+davewiththenicehat@users.noreply.github.com> Date: Fri, 28 May 2021 15:46:37 -0400 Subject: [PATCH 01/14] CmdTasks Created Created a system command for displaying and manipulating tasks. A single unit test in evennia.commands.default.tests.TestHelp fails. Message pattern mismatch. All other unit tests pass. --- evennia/commands/default/cmdset_character.py | 1 + evennia/commands/default/system.py | 184 ++++++++++++++++++- evennia/commands/default/tests.py | 103 +++++++++++ 3 files changed, 287 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/cmdset_character.py b/evennia/commands/default/cmdset_character.py index 28c8fdd641..dc3b2b58b4 100644 --- a/evennia/commands/default/cmdset_character.py +++ b/evennia/commands/default/cmdset_character.py @@ -50,6 +50,7 @@ class CharacterCmdSet(CmdSet): self.add(system.CmdServerLoad()) # self.add(system.CmdPs()) self.add(system.CmdTickers()) + self.add(system.CmdTasks()) # Admin commands self.add(admin.CmdBoot()) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 54db99093e..146e59bc61 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -8,7 +8,6 @@ System commands import code import traceback import os -import io import datetime import sys import django @@ -26,8 +25,10 @@ from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.evmore import EvMore from evennia.utils.utils import crop, class_from_module +from evennia.scripts.taskhandler import TaskHandlerTask COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) +_TASK_HANDLER = None # delayed imports _RESOURCE = None @@ -45,6 +46,7 @@ __all__ = ( "CmdAbout", "CmdTime", "CmdServerLoad", + "CmdTasks", ) @@ -1203,3 +1205,183 @@ class CmdTickers(COMMAND_DEFAULT_CLASS): "*" if sub[5] else "-", ) self.caller.msg("|wActive tickers|n:\n" + str(table)) + + +class CmdTasks(COMMAND_DEFAULT_CLASS): + """ + Manage active tasks (delays). + + Note: + Only the action requested on the first switch will be processed. All other switches will + be ignored. + + Manipulation of a single task is intended to be done via the clickable links or through + code directly. Due to generally short life of a task, the inclusion of completion date + and function's memory reference guarentees an incorrect task will not be manipulated. + + By default, tasks that are canceled and never called are automatically removed after + one minute. + + Usage: + tasks + show all current active taks. + tasks[/switch] [function name] + Process the action in the switch to all tasks that are deferring a specific function name. + This would match the name of the callback you passed to a delay or the task handler. + tasks[/switch] [task id], [completion date], [function memory reference] + Process the action in the switch to a specific task. + + Example: + tasks/cancel move_callback + Cancel all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with: utils.delay(move_delay, move_callback) + + Switches: + pause - Pause the callback of a task. + unpause - Process all callbacks made since pause() was called. + do_task - Execute the task (call its callback). + call - Call the callback of this task. + remove - Remove a task without executing it. + cancel - Stop a task from automatically executing. + """ + + key = "tasks" + aliases = ["delays"] + switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel") + locks = "perm(Developer)" + help_category = "System" + + @staticmethod + def coll_date_func(task): + """Replace regex characters in date string and collect deferred function name.""" + t_comp_date = str(task[0]).replace('-', '/').replace('.', ' ms:') + t_func_name = str(task[1]).split(' ') + t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None + return t_comp_date, t_func_mem_ref + + def func(self): + caller = self.caller + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + # handle no tasks active. + if not _TASK_HANDLER.tasks: + self.msg('There are no active tasks.') + if self.switches or self.args: + self.msg('Likely the task has completed and been removed.') + return + # handle caller's request to manipulate a task(s) + if self.switches or self.lhs: + action_request = self.switches[0] + # handle caller requesting an action on specific deferred function + if len(self.lhslist) == 1: + name_match_found = False + arg_func_name = self.lhslist[0].lower() + # repack tasks into a new dictionary + current_tasks = {} + for task_id, task_args in _TASK_HANDLER.tasks.items(): + current_tasks.update({task_id: task_args}) + # call requested action on all tasks with the function name + for task_id, task_args in current_tasks.items(): + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + # skip this task if it is not for the function desired + if arg_func_name != t_func_name: + continue + name_match_found = True + task = TaskHandlerTask(task_id) + switch_action = getattr(task, action_request, False) + if switch_action: + action_return = switch_action() + self.msg(f'Task action {action_request} completed on task ID {task_id}.') + self.msg(f'The task function {action_request} returned: {action_return}') + # provide a message if not tasks of the function name was found + if not name_match_found: + self.msg(f'No tasks deferring function name {arg_func_name} found.') + return + return True + err_arg_msg = 'Task ID, completion date and memory reference are required when manipulating a delay.' + task_comp_msg = 'Task completed while processing request.' + # handle missing arguments or switches + if not self.switches and self.lhs: + self.msg(err_arg_msg) + return + # handle incorrect arguments + if len(self.lhslist) < 2: + self.msg(err_arg_msg) + return + # create a handle for the task + task_id = int(self.lhslist[0]) + task = TaskHandlerTask(task_id) + # handle task no longer existing + if not task.exists(): + self.msg(f'Task {task_id} does not exist.') + return + # get a reference of the function caller requested + switch_action = getattr(task, action_request, False) + if not switch_action: + self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ + f'{task_comp_msg.lower()}') + # verify manipulating the correct task + if task_id in _TASK_HANDLER.tasks: + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if task_args: # check if the task is still active + sw_comp_date = self.lhslist[1] + sw_func_mem_ref = self.lhslist[2] + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + # handle completion date mismatch + if not t_comp_date == sw_comp_date: + self.msg('Task completion time does not match time passed.') + self.msg(task_comp_msg) + self.msg('Likely a new task with the same ID was created') + return + # handle function memory reference mismatch + if not t_func_mem_ref == sw_func_mem_ref: + self.msg("Memory reference for the task's function does not match argument") + self.msg(task_comp_msg) + self.msg('Likely a new task with the same ID was created') + return + else: # task no longer exists + self.msg(task_comp_msg) + return + if task.exists(): # make certain the task has not been called yet. + # call the task's method + action_return = switch_action() + self.msg(f'Task action {action_request} completed.') + self.msg(f'The task function {action_request} returned: {action_return}') + return True + else: + self.msg(task_comp_msg) + return + # No task manupilation requested, build a table of tasks and display it + # get the width of screen in characters + def_screen_width = settings.CLIENT_DEFAULT_WIDTH if settings.CLIENT_DEFAULT_WIDTH else 80 + caller_session = caller.sessions.get() + width = caller_session[0].protocol_flags.get("SCREENWIDTH", def_screen_width) + # create table header and list to hold tasks data and actions + tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', 'persistent') + tasks_list = [list() for i in range(len(tasks_header))] # empty list of lists, the size of the header + for task_id, task in _TASK_HANDLER.tasks.items(): + # collect data from the task + t_comp_date, t_func_mem_ref = self.coll_date_func(task) + t_func_name = str(task[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + t_args = str(task[2]) + t_kwargs = str(task[3]) + t_pers = str(task[4]) + # add task data to the tasks list + task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) + for i in range(len(tasks_header)): + tasks_list[i].append(task_data[i]) + # add task actions to the tasks list + actions = ('pause', 'unpause', 'do_task', 'remove', 'call', 'cancel') + for i in range(len(tasks_header)): + tasks_list[i].append(f"|lc{self.key}/{actions[i]} {task_id}, {t_comp_date}, " \ + f"{t_func_mem_ref}|lt{actions[i]}|le") + # if the screen width is large enough, add directional arrows + if width >= 75: + tasks_list[i][-1] = f"^{tasks_list[i][-1]}^" + # create and display the table + tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', align='center') + self.msg(tasks_table) diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index c086916aca..815ac7ee26 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -18,6 +18,7 @@ from anything import Anything from parameterized import parameterized from django.conf import settings +from twisted.internet import task from unittest.mock import patch, Mock, MagicMock from evennia import DefaultRoom, DefaultExit, ObjectDB @@ -574,6 +575,108 @@ class TestSystem(CommandTest): def test_server_load(self): self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:") +_TASK_HANDLER = None + +def func_test_cmd_tasks(): + return 'success' + +class TestCmdTasks(CommandTest): + + def setUp(self): + super().setUp() + # get a reference of TASK_HANDLER + self.timedelay = 5 + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + _TASK_HANDLER.clock = task.Clock() + self.task_handler = _TASK_HANDLER + self.task_handler.clear() + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + task_args = self.task_handler.tasks.get(self.task.get_id(), False) + self.t_comp_date, self.t_func_mem_ref = system.CmdTasks.coll_date_func(task_args) + + + def tearDown(self): + super().tearDown() + self.task_handler.clear() + + def test_no_tasks(self): + self.task_handler.clear() + self.call(system.CmdTasks(), '', 'There are no active tasks.') + + def test_active_task(self): + cmd_result = self.call(system.CmdTasks(), '') + for ptrn in ('Task ID', 'Completion Date', 'Function', 'KWARGS', 'persisten', + '1', r'\d+/\d+/\d+', r'\d+\:\d+\:\d+', r'ms\:\d+', 'func_test', '{}', + 'False'): + self.assertRegex(cmd_result, ptrn) + + def test_persistent_task(self): + self.task_handler.clear() + self.task_handler.add(self.timedelay, func_test_cmd_tasks, persistent=True) + cmd_result = self.call(system.CmdTasks(), '') + self.assertRegex(cmd_result, 'True') + + def test_pause_unpause(self): + # test pause + args = f'/pause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + wanted_msg = 'Task action pause completed.|The task function pause returned:' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertTrue(self.task.paused) + self.task_handler.clock.advance(self.timedelay + 1) + # test unpause + args = f'/unpause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + self.assertTrue(self.task.exists()) + wanted_msg = 'Task action unpause completed.|The task function unpause returned: None' + self.call(system.CmdTasks(), args, wanted_msg) + # verify task continues after unpause + self.task_handler.clock.advance(1) + self.assertFalse(self.task.exists()) + + def test_do_task(self): + args = f'/do_task {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + wanted_msg = 'Task action do_task completed.|The task function do_task returned: success' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertFalse(self.task.exists()) + + def test_remove(self): + args = f'/remove {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + wanted_msg = 'Task action remove completed.|The task function remove returned: True' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertFalse(self.task.exists()) + + def test_call(self): + args = f'/call {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + wanted_msg = 'Task action call completed.|The task function call returned: success' + self.call(system.CmdTasks(), args, wanted_msg) + # make certain the task is still active + self.assertTrue(self.task.active()) + # go past delay time, the task should call do_task and remove itself after calling. + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists()) + + def test_cancel(self): + args = f'/cancel {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + wanted_msg = 'Task action cancel completed.|The task function cancel returned: True' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertTrue(self.task.exists()) + self.assertFalse(self.task.active()) + + def test_func_name_manipulation(self): + self.task_handler.add(self.timedelay, func_test_cmd_tasks) # add an extra task + args = f'/remove func_test_cmd_tasks' + wanted_msg = 'Task action remove completed on task ID 1.|The task function remove returned: True|' \ + 'Task action remove completed on task ID 2.|The task function remove returned: True' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertFalse(self.task_handler.tasks) # no tasks should exist. + + def test_wrong_func_name(self): + args = f'/remove intentional_fail' + wanted_msg = 'No tasks deferring function name intentional_fail found.' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertTrue(self.task.active()) + class TestAdmin(CommandTest): def test_emit(self): From 03b0bc47a059cc31e96193d30d82255c04c54f9f Mon Sep 17 00:00:00 2001 From: davewiththenicehat <54369722+davewiththenicehat@users.noreply.github.com> Date: Mon, 31 May 2021 20:04:13 -0400 Subject: [PATCH 02/14] CmdTask Misc Updates --- evennia/commands/default/system.py | 85 +++++++++++++++++------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 146e59bc61..9bb1f05b40 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -1209,40 +1209,46 @@ class CmdTickers(COMMAND_DEFAULT_CLASS): class CmdTasks(COMMAND_DEFAULT_CLASS): """ - Manage active tasks (delays). - - Note: - Only the action requested on the first switch will be processed. All other switches will - be ignored. - - Manipulation of a single task is intended to be done via the clickable links or through - code directly. Due to generally short life of a task, the inclusion of completion date - and function's memory reference guarentees an incorrect task will not be manipulated. - - By default, tasks that are canceled and never called are automatically removed after - one minute. + Display or terminate active tasks (delays). Usage: - tasks - show all current active taks. - tasks[/switch] [function name] - Process the action in the switch to all tasks that are deferring a specific function name. - This would match the name of the callback you passed to a delay or the task handler. - tasks[/switch] [task id], [completion date], [function memory reference] - Process the action in the switch to a specific task. - - Example: - tasks/cancel move_callback - Cancel all movement delays from the slow_exit contrib. - In this example slow exits creates it's tasks with: utils.delay(move_delay, move_callback) + tasks + show all current active taks. + tasks[/switch] [function name] + Process the action in the switch to all tasks that are deferring a specific function name. + This would match the name of the callback you passed to a delay or the task handler. + tasks[/switch] [task id], [completion date], [function memory reference] + Process the action in the switch to a specific task. Switches: - pause - Pause the callback of a task. - unpause - Process all callbacks made since pause() was called. - do_task - Execute the task (call its callback). - call - Call the callback of this task. - remove - Remove a task without executing it. - cancel - Stop a task from automatically executing. + pause - Pause the callback of a task. + unpause - Process all callbacks made since pause() was called. + do_task - Execute the task (call its callback). + call - Call the callback of this task. + remove - Remove a task without executing it. + cancel - Stop a task from automatically executing. + + Notes: + A task is a single use method of delaying the call of a function. + + Tasks can be created using utils.delay. + Reference: https://evennia.readthedocs.io/en/latest/Command-Duration.html + + Only the action requested on the first switch will be processed. All other switches will + be ignored. + + Manipulation of a single task is intended to be done via the clickable links or through + code directly. Due to generally short life of a task, the inclusion of completion date + and function's memory reference guarentees an incorrect task will not be manipulated. + + By default, tasks that are canceled and never called are automatically removed after + one minute. + + Example: + tasks/cancel move_callback + Cancel all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with: utils.delay(move_delay, move_callback) + """ key = "tasks" @@ -1260,7 +1266,6 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): return t_comp_date, t_func_mem_ref def func(self): - caller = self.caller # get a reference of the global task handler global _TASK_HANDLER if _TASK_HANDLER is None: @@ -1271,6 +1276,7 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): if self.switches or self.args: self.msg('Likely the task has completed and been removed.') return + # handle caller's request to manipulate a task(s) if self.switches or self.lhs: action_request = self.switches[0] @@ -1301,7 +1307,8 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): self.msg(f'No tasks deferring function name {arg_func_name} found.') return return True - err_arg_msg = 'Task ID, completion date and memory reference are required when manipulating a delay.' + err_arg_msg = 'Task ID, completion date and memory reference are required when ' \ + 'manipulating a delay.' task_comp_msg = 'Task completed while processing request.' # handle missing arguments or switches if not self.switches and self.lhs: @@ -1354,14 +1361,15 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): else: self.msg(task_comp_msg) return + # No task manupilation requested, build a table of tasks and display it # get the width of screen in characters - def_screen_width = settings.CLIENT_DEFAULT_WIDTH if settings.CLIENT_DEFAULT_WIDTH else 80 - caller_session = caller.sessions.get() - width = caller_session[0].protocol_flags.get("SCREENWIDTH", def_screen_width) + width = self.client_width() # create table header and list to hold tasks data and actions - tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', 'persistent') - tasks_list = [list() for i in range(len(tasks_header))] # empty list of lists, the size of the header + tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', + 'persistent') + # empty list of lists, the size of the header + tasks_list = [list() for i in range(len(tasks_header))] for task_id, task in _TASK_HANDLER.tasks.items(): # collect data from the task t_comp_date, t_func_mem_ref = self.coll_date_func(task) @@ -1383,5 +1391,6 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): if width >= 75: tasks_list[i][-1] = f"^{tasks_list[i][-1]}^" # create and display the table - tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', align='center') + tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', + align='center') self.msg(tasks_table) From 7a30822ee1c4531da903e619ebbaedb050687fc1 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 13 Jun 2021 14:11:05 +0200 Subject: [PATCH 03/14] Fix up unittests --- .../server/profiling/dummyrunner_settings.py | 18 +++---- evennia/server/profiling/tests.py | 54 +++++++++---------- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/evennia/server/profiling/dummyrunner_settings.py b/evennia/server/profiling/dummyrunner_settings.py index aff9404ab5..924c7453f7 100644 --- a/evennia/server/profiling/dummyrunner_settings.py +++ b/evennia/server/profiling/dummyrunner_settings.py @@ -128,8 +128,8 @@ def c_login(client): def c_login_nodig(client): "logins, don't dig its own room" - cname = DUMMY_NAME % client.gid - cpwd = DUMMY_PWD % client.gid + cname = DUMMY_NAME.format(gid=client.gid) + cpwd = DUMMY_PWD.format(gid=client.gid) cmds = ( f"create {cname} {cpwd}", f"connect {cname} {cpwd}" @@ -183,7 +183,7 @@ def c_digs(client): exitname1 = EXIT_TEMPLATE % client.counter() exitname2 = EXIT_TEMPLATE % client.counter() client.exits.extend([exitname1, exitname2]) - return ("@dig/tel %s = %s, %s" % (roomname, exitname1, exitname2),) + return ("dig/tel %s = %s, %s" % (roomname, exitname1, exitname2),) def c_creates_obj(client): @@ -191,10 +191,10 @@ def c_creates_obj(client): objname = OBJ_TEMPLATE % client.counter() client.objs.append(objname) cmds = ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ) return cmds @@ -203,7 +203,7 @@ def c_creates_button(client): "creates example button, storing name on client" objname = TOBJ_TEMPLATE % client.counter() client.objs.append(objname) - cmds = ("@create %s:%s" % (objname, TOBJ_TYPECLASS), "@desc %s = test red button!" % objname) + cmds = ("create %s:%s" % (objname, TOBJ_TYPECLASS), "desc %s = test red button!" % objname) return cmds @@ -295,7 +295,7 @@ elif PROFILE == 'normal_builder': (0.1, c_help), (0.01, c_digs), (0.01, c_creates_obj), - (0.2, c_moves) + (0.2, c_moves), (0.1, c_measure_lag) ) elif PROFILE == 'heavy_builder': diff --git a/evennia/server/profiling/tests.py b/evennia/server/profiling/tests.py index 447229d4c4..d887a669c6 100644 --- a/evennia/server/profiling/tests.py +++ b/evennia/server/profiling/tests.py @@ -1,5 +1,6 @@ from django.test import TestCase from mock import Mock, patch, mock_open +from anything import Something from .dummyrunner_settings import ( c_creates_button, c_creates_obj, @@ -29,8 +30,8 @@ class TestDummyrunnerSettings(TestCase): self.client.cid = 1 self.client.counter = Mock(return_value=1) self.client.gid = "20171025161153-1" - self.client.name = "Dummy-%s" % self.client.gid - self.client.password = "password-%s" % self.client.gid + self.client.name = "Dummy_%s" % self.client.gid + self.client.password = Something, self.client.start_room = "testing_room_start_%s" % self.client.gid self.client.objs = [] self.client.exits = [] @@ -43,28 +44,25 @@ class TestDummyrunnerSettings(TestCase): self.assertEqual( c_login(self.client), ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - "@dig %s" % self.client.start_room, - "@teleport %s" % self.client.start_room, - "@dig testing_room_1 = exit_1, exit_1", + Something, # create + Something, # connect + "dig %s" % self.client.start_room, + "teleport %s" % self.client.start_room, + "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" + "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" ), ) def test_c_login_no_dig(self): - self.assertEqual( - c_login_nodig(self.client), - ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - ), - ) + cmd1, cmd2 = c_login_nodig(self.client) + self.assertTrue(cmd1.startswith("create " + self.client.name + " ")) + self.assertTrue(cmd2.startswith("connect " + self.client.name + " ")) def test_c_logout(self): - self.assertEqual(c_logout(self.client), "@quit") + self.assertEqual(c_logout(self.client), ("quit",)) def perception_method_tests(self, func, verb, alone_suffix=""): - self.assertEqual(func(self.client), "%s%s" % (verb, alone_suffix)) + self.assertEqual(func(self.client), ("%s%s" % (verb, alone_suffix),)) self.client.exits = ["exit1", "exit2"] self.assertEqual(func(self.client), ["%s exit1" % verb, "%s exit2" % verb]) self.client.objs = ["foo", "bar"] @@ -83,11 +81,11 @@ class TestDummyrunnerSettings(TestCase): def test_c_help(self): self.assertEqual( c_help(self.client), - ("help", "help @teleport", "help look", "help @tunnel", "help @dig"), + ("help", "dummyrunner_echo_response"), ) def test_c_digs(self): - self.assertEqual(c_digs(self.client), ("@dig/tel testing_room_1 = exit_1, exit_1")) + self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1", )) self.assertEqual(self.client.exits, ["exit_1", "exit_1"]) self.clear_client_lists() @@ -96,10 +94,10 @@ class TestDummyrunnerSettings(TestCase): self.assertEqual( c_creates_obj(self.client), ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ), ) self.assertEqual(self.client.objs, [objname]) @@ -110,7 +108,7 @@ class TestDummyrunnerSettings(TestCase): typeclass_name = "contrib.tutorial_examples.red_button.RedButton" self.assertEqual( c_creates_button(self.client), - ("@create %s:%s" % (objname, typeclass_name), "@desc %s = test red button!" % objname), + ("create %s:%s" % (objname, typeclass_name), "desc %s = test red button!" % objname), ) self.assertEqual(self.client.objs, [objname]) self.clear_client_lists() @@ -119,25 +117,23 @@ class TestDummyrunnerSettings(TestCase): self.assertEqual( c_socialize(self.client), ( - "ooc Hello!", - "ooc Testing ...", - "ooc Testing ... times 2", + "pub Hello!", "say Yo!", "emote stands looking around.", ), ) def test_c_moves(self): - self.assertEqual(c_moves(self.client), "look") + self.assertEqual(c_moves(self.client), ("look",)) self.client.exits = ["south", "north"] self.assertEqual(c_moves(self.client), ["south", "north"]) self.clear_client_lists() def test_c_move_n(self): - self.assertEqual(c_moves_n(self.client), "north") + self.assertEqual(c_moves_n(self.client), ("north",)) def test_c_move_s(self): - self.assertEqual(c_moves_s(self.client), "south") + self.assertEqual(c_moves_s(self.client), ("south",)) class TestMemPlot(TestCase): From 95a2b18d43a48937ae178bb11f48fb75398c31cc Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 13 Jun 2021 22:02:18 +0200 Subject: [PATCH 04/14] Fix some broken master-doc pages --- docs/source/Add-a-simple-new-web-page.md | 5 +- docs/source/Async-Process.md | 13 +- docs/source/Attributes.md | 3 +- docs/source/Bootstrap-&-Evennia.md | 3 +- docs/source/Coordinates.md | 9 +- docs/source/Customize-channels.md | 3 +- docs/source/Default-Command-Help.md | 315 ++++++------------ docs/source/Dialogues-in-events.md | 3 +- docs/source/Evennia-for-MUSH-Users.md | 16 +- docs/source/Game-Planning.md | 6 +- docs/source/Glossary.md | 8 +- docs/source/Help-System-Tutorial.md | 4 +- docs/source/How-To-Get-And-Give-Help.md | 25 +- docs/source/Links.md | 16 +- docs/source/Online-Setup.md | 5 +- docs/source/Portal-And-Server.md | 3 +- docs/source/Python-3.md | 85 +---- docs/source/Python-basic-introduction.md | 3 +- docs/source/Python-basic-tutorial-part-two.md | 51 ++- docs/source/Screenshot.md | 3 +- docs/source/Server-Conf.md | 4 +- docs/source/Static-In-Game-Map.md | 22 +- docs/source/Turn-based-Combat-System.md | 18 +- docs/source/Tutorial-World-Introduction.md | 10 +- docs/source/Tutorials.md | 20 +- docs/source/Unit-Testing.md | 55 ++- docs/source/Web-Character-Generation.md | 20 +- docs/source/Web-Character-View-Tutorial.md | 5 +- docs/source/Web-Features.md | 5 +- 29 files changed, 236 insertions(+), 502 deletions(-) diff --git a/docs/source/Add-a-simple-new-web-page.md b/docs/source/Add-a-simple-new-web-page.md index f960c5a3e9..c146a54f10 100644 --- a/docs/source/Add-a-simple-new-web-page.md +++ b/docs/source/Add-a-simple-new-web-page.md @@ -69,14 +69,13 @@ If you'd rather not take advantage of Evennia's base styles, you can do somethin ``` - + ### The URL When you enter the address `http://localhost:4001/story` in your web browser, Django will parse that field to figure out which page you want to go to. You tell it which patterns are relevant in the file -[mygame/web/urls.py](https://github.com/evennia/evennia/blob/master/evennia/game_template/web/urls.p -y). +[mygame/web/urls.py](https://github.com/evennia/evennia/blob/master/evennia/game_template/web/urls.py). Open it now. Django looks for the variable `urlpatterns` in this file. You want to add your new pattern to the diff --git a/docs/source/Async-Process.md b/docs/source/Async-Process.md index f994d63ea4..ae18635738 100644 --- a/docs/source/Async-Process.md +++ b/docs/source/Async-Process.md @@ -98,16 +98,16 @@ An example of making an asynchronous call from inside a [Command](./Commands) de class CmdAsync(Command): key = "asynccommand" - + def func(self): - + def long_running_function(): #[... lots of time-consuming code ...] return final_value - + def at_return_function(r): self.caller.msg("The final value is %s" % r) - + def at_err_function(e): self.caller.msg("There was an error: %s" % e) @@ -150,8 +150,7 @@ Wait 10 seconds and 'Test!' should be echoed back to you. ## The @interactive decorator -As of Evennia 0.9, the `@interactive` [decorator](https://realpython.com/primer-on-python- -decorators/) +As of Evennia 0.9, the `@interactive` [decorator](https://realpython.com/primer-on-python-decorators/) is available. This makes any function or method possible to 'pause' and/or await player input in an interactive way. @@ -160,7 +159,7 @@ in an interactive way. @interactive def myfunc(caller): - + while True: caller.msg("Getting ready to wait ...") yield(5) diff --git a/docs/source/Attributes.md b/docs/source/Attributes.md index e8f91e7529..4ca0e82566 100644 --- a/docs/source/Attributes.md +++ b/docs/source/Attributes.md @@ -237,8 +237,7 @@ entities you can loop over in a for-loop. Attribute-saving supports the followin * [Dicts](https://docs.python.org/2/tutorial/datastructures.html#dictionaries), like `{1:2, "test":]`. * [Sets](https://docs.python.org/2/tutorial/datastructures.html#sets), like `{1,2,"test",}`. -* [collections.OrderedDict](https://docs.python.org/2/library/collections.html#collections.OrderedDi -ct), like `OrderedDict((1,2), ("test", ))`. +* [collections.OrderedDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict), like `OrderedDict((1,2), ("test", ))`. * [collections.Deque](https://docs.python.org/2/library/collections.html#collections.deque), like `deque((1,2,"test",))`. * *Nestings* of any combinations of the above, like lists in dicts or an OrderedDict of tuples, each diff --git a/docs/source/Bootstrap-&-Evennia.md b/docs/source/Bootstrap-&-Evennia.md index 8f9781af51..fd7db78909 100644 --- a/docs/source/Bootstrap-&-Evennia.md +++ b/docs/source/Bootstrap-&-Evennia.md @@ -97,5 +97,4 @@ docs](https://getbootstrap.com/docs/4.0/layout/grid/) ## More Bootstrap Bootstrap also provides a huge amount of utilities, as well as styling and content elements. To -learn more about them, please [read the Bootstrap docs](https://getbootstrap.com/docs/4.0/getting- -started/introduction/) or read one of our other web tutorials. \ No newline at end of file +learn more about them, please [read the Bootstrap docs](https://getbootstrap.com/docs/4.0/getting-started/introduction/) or read one of our other web tutorials. diff --git a/docs/source/Coordinates.md b/docs/source/Coordinates.md index 410b779c95..beed340e48 100644 --- a/docs/source/Coordinates.md +++ b/docs/source/Coordinates.md @@ -51,7 +51,7 @@ class Room(DefaultRoom): See examples/object.py for a list of properties and methods available on all Objects. """ - + @property def x(self): """Return the X coordinate or None.""" @@ -72,7 +72,7 @@ class Room(DefaultRoom): """Return the Y coordinate or None.""" y = self.tags.get(category="coordy") return int(y) if isinstance(y, str) else None - + @y.setter def y(self, y): """Change the Y coordinate.""" @@ -87,7 +87,7 @@ class Room(DefaultRoom): """Return the Z coordinate or None.""" z = self.tags.get(category="coordz") return int(z) if isinstance(z, str) else None - + @z.setter def z(self, z): """Change the Z coordinate.""" @@ -99,8 +99,7 @@ class Room(DefaultRoom): ``` If you aren't familiar with the concept of properties in Python, I encourage you to read a good -tutorial on the subject. [This article on Python properties](https://www.programiz.com/python- -programming/property) +tutorial on the subject. [This article on Python properties](https://www.programiz.com/python-programming/property) is well-explained and should help you understand the idea. Let's look at our properties for `x`. First of all is the read property. diff --git a/docs/source/Customize-channels.md b/docs/source/Customize-channels.md index aeed0f4cd4..9c755eec4e 100644 --- a/docs/source/Customize-channels.md +++ b/docs/source/Customize-channels.md @@ -480,5 +480,4 @@ close from the code I've provided here. Notice, however, that this resource is external to Evennia and not maintained by anyone but the original author of this article. -[Read the full example on Github](https://github.com/vincent- -lg/avenew/blob/master/commands/comms.py) +[Read the full example on Github](https://github.com/vincent-lg/avenew/blob/master/commands/comms.py) diff --git a/docs/source/Default-Command-Help.md b/docs/source/Default-Command-Help.md index 11aeea97a7..42601a0a69 100644 --- a/docs/source/Default-Command-Help.md +++ b/docs/source/Default-Command-Help.md @@ -12,8 +12,7 @@ information about how commands work can be found in the documentation for [Comma ## A-Z -- [`__unloggedin_look_command`](https://github.com/evennia/evennia/wiki/Default-Command- -Help#wiki-`--unloggedin-look-command`-cmdunconnectedlook) - look when in unlogged-in state +- [`__unloggedin_look_command`](https://github.com/evennia/evennia/wiki/Default-Command-Help#wiki-`--unloggedin-look-command`-cmdunconnectedlook) - look when in unlogged-in state - [about](./Default-Command-Help#wiki-about-cmdabout) - show Evennia info - [access](./Default-Command-Help#wiki-access-cmdaccess) - show your current game access - [addcom](./Default-Command-Help#wiki-addcom-cmdaddcom) - add a channel alias and/or subscribe to a @@ -137,14 +136,12 @@ another ## Command details These are generated from the auto-documentation and are ordered by their source file location in -[evennia/commands/default/](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ -) +[evennia/commands/default/](https://github.com/evennia/evennia/tree/master/evennia/commands/default/) ### `account.py` -[View account.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py) +[View account.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py) #### charcreate (CmdCharCreate) @@ -165,8 +162,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdCharCreate` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### chardelete (CmdCharDelete) @@ -184,8 +180,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdCharDelete` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### color (CmdColorTest) @@ -207,8 +202,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdColorTest` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### ic (CmdIC) @@ -234,8 +228,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdIC` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### look (CmdOOCLook) @@ -253,8 +246,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdOOCLook` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### ooc (CmdOOC) @@ -274,8 +266,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdOOC` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### option (CmdOption) @@ -299,8 +290,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdOption` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### password (CmdPassword) @@ -318,8 +308,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdPassword` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### quell (CmdQuell) @@ -386,8 +375,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdSessions` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultSession'* of class `SessionCmdSet` in [cmdset_session.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_session.py). +Belongs to command set *'DefaultSession'* of class `SessionCmdSet` in [cmdset_session.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_session.py). #### style (CmdStyle) @@ -407,8 +395,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_session.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdStyle` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### who (CmdWho) @@ -428,14 +415,12 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdWho` in [account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/account.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). ### `admin.py` -[View admin.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py) +[View admin.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py) #### ban (CmdBan) @@ -476,8 +461,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdBan` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### boot (CmdBoot) @@ -500,8 +484,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdBoot` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### emit (CmdEmit) @@ -530,8 +513,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdEmit` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### force (CmdForce) @@ -550,8 +532,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdForce` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### perm (CmdPerm) @@ -575,8 +556,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdPerm` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### unban (CmdUnban) @@ -597,8 +577,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdUnban` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### userpassword (CmdNewPassword) @@ -616,8 +595,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdNewPassword` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### wall (CmdWall) @@ -636,14 +614,12 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Admin"* - **Source:** class `CmdWall` in [admin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/admin.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `batchprocess.py` -[View batchprocess.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/batchprocess.py) +[View batchprocess.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/batchprocess.py) #### batchcode (CmdBatchCode) @@ -668,10 +644,8 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **aliases:** *batchcodes* - **[locks](./Locks):** *"cmd:superuser()"* - **[`help_category`](./Help-System):** *"Building"* -- **Source:** class `CmdBatchCode` in [batchprocess.py](https://github.com/evennia/evennia/tree/mast -er/evennia/commands/default/batchprocess.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +- **Source:** class `CmdBatchCode` in [batchprocess.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/batchprocess.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### batchcommands (CmdBatchCommands) @@ -692,16 +666,13 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **aliases:** *batchcmd*, *batchcommand* - **[locks](./Locks):** *"cmd:perm(batchcommands) or perm(Developer)"* - **[`help_category`](./Help-System):** *"Building"* -- **Source:** class `CmdBatchCommands` in [batchprocess.py](https://github.com/evennia/evennia/tree/ -master/evennia/commands/default/batchprocess.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +- **Source:** class `CmdBatchCommands` in [batchprocess.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/batchprocess.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `building.py` -[View building.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py) +[View building.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py) #### alias (CmdSetObjAlias) @@ -732,8 +703,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdSetObjAlias` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### cmdsets (CmdListCmdSets) @@ -752,8 +722,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdListCmdSets` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### command (ObjManipCommand) @@ -807,8 +776,7 @@ Belongs to command set *''* of class `` in - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdCopy` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### cpattr (CmdCpAttr) @@ -839,8 +807,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdCpAttr` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### create (CmdCreate) @@ -871,8 +838,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdCreate` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### desc (CmdDesc) @@ -894,8 +860,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdDesc` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### destroy (CmdDestroy) @@ -925,8 +890,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdDestroy` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### dig (CmdDig) @@ -958,8 +922,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdDig` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### examine (CmdExamine) @@ -986,8 +949,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdExamine` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### find (CmdFind) @@ -1018,8 +980,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdFind` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### link (CmdLink) @@ -1048,8 +1009,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdLink` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### lock (CmdLock) @@ -1089,8 +1049,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdLock` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### mvattr (CmdMvAttr) @@ -1115,8 +1074,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdMvAttr` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### name (CmdName) @@ -1135,8 +1093,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdName` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### open (CmdOpen) @@ -1144,8 +1101,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara open a new exit from the current room Usage: - open [;alias;alias..][:typeclass] [,[;alias;..][:typeclass]]] = - + open [;alias;alias..][:typeclass] [,[;alias;..][:typeclass]]] = Handles the creation of exits. If a destination is given, the exit will point there. The argument sets up an exit at the @@ -1159,8 +1115,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdOpen` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### script (CmdScript) @@ -1188,8 +1143,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdScript` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### set (CmdSetAttribute) @@ -1237,8 +1191,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdSetAttribute` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### sethome (CmdSetHome) @@ -1262,8 +1215,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdSetHome` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### spawn (CmdSpawn) @@ -1334,8 +1286,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdSpawn` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### tag (CmdTag) @@ -1365,8 +1316,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdTag` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### tel (CmdTeleport) @@ -1402,8 +1352,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdTeleport` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### tunnel (CmdTunnel) @@ -1438,8 +1387,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdTunnel` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### typeclass (CmdTypeclass) @@ -1495,8 +1443,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdTypeclass` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### unlink (CmdUnLink) @@ -1515,8 +1462,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdUnLink` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### wipe (CmdWipe) @@ -1539,14 +1485,12 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdWipe` in [building.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/building.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `comms.py` -[View comms.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py) +[View comms.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py) #### addcom (CmdAddCom) @@ -1567,8 +1511,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdAddCom` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### allcom (CmdAllCom) @@ -1590,8 +1533,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdAllCom` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### cboot (CmdCBoot) @@ -1612,8 +1554,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdCBoot` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### ccreate (CmdChannelCreate) @@ -1631,8 +1572,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdChannelCreate` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### cdesc (CmdCdesc) @@ -1651,8 +1591,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdCdesc` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### cdestroy (CmdCdestroy) @@ -1670,8 +1609,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdCdestroy` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### cemit (CmdCemit) @@ -1695,8 +1633,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdCemit` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### channels (CmdChannels) @@ -1718,8 +1655,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdChannels` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### clock (CmdClock) @@ -1738,8 +1674,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdClock` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### cwho (CmdCWho) @@ -1757,8 +1692,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdCWho` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### delcom (CmdDelCom) @@ -1780,8 +1714,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdDelCom` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### irc2chan (CmdIRC2Chan) @@ -1820,8 +1753,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdIRC2Chan` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### page (CmdPage) @@ -1846,8 +1778,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdPage` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### rss2chan (CmdRSS2Chan) @@ -1880,14 +1811,12 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Comms"* - **Source:** class `CmdRSS2Chan` in [comms.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/comms.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). ### `general.py` -[View general.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py) +[View general.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py) #### access (CmdAccess) @@ -1926,8 +1855,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdDrop` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### get (CmdGet) @@ -1946,8 +1874,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdGet` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### give (CmdGive) @@ -1966,8 +1893,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdGive` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### home (CmdHome) @@ -1985,8 +1911,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdHome` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### inventory (CmdInventory) @@ -2005,8 +1930,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdInventory` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### look (CmdLook) @@ -2026,8 +1950,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdLook` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### nick (CmdNick) @@ -2077,8 +2000,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdNick` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### pose (CmdPose) @@ -2103,8 +2025,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdPose` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### say (CmdSay) @@ -2122,8 +2043,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdSay` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### setdesc (CmdSetDesc) @@ -2143,8 +2063,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdSetDesc` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### whisper (CmdWhisper) @@ -2164,8 +2083,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdWhisper` in [general.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/general.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `help.py` @@ -2192,8 +2110,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdHelp` in [help.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/help.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### sethelp (CmdSetHelp) @@ -2227,14 +2144,12 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"Building"* - **Source:** class `CmdSetHelp` in [help.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/help.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `system.py` -[View system.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py) +[View system.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py) #### about (CmdAbout) @@ -2252,8 +2167,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdAbout` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### objects (CmdObjects) @@ -2273,8 +2187,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdObjects` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### py (CmdPy) @@ -2329,8 +2242,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdPy` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### reload (CmdReload) @@ -2350,8 +2262,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdReload` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### reset (CmdReset) @@ -2379,8 +2290,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdReset` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### scripts (CmdScripts) @@ -2410,8 +2320,7 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdScripts` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### server (CmdServerLoad) @@ -2455,8 +2364,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdServerLoad` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### service (CmdService) @@ -2484,8 +2392,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdService` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). #### shutdown (CmdShutdown) @@ -2503,8 +2410,7 @@ s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_chara - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdShutdown` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://gi -thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). +Belongs to command set *'DefaultAccount'* of class `AccountCmdSet` in [cmdset_account.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py). #### time (CmdTime) @@ -2523,14 +2429,12 @@ thub.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_account.py) - **[`help_category`](./Help-System):** *"System"* - **Source:** class `CmdTime` in [system.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/system.py). -Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](http -s://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). +Belongs to command set *'DefaultCharacter'* of class `CharacterCmdSet` in [cmdset_character.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_character.py). ### `unloggedin.py` -[View unloggedin.py -source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py) +[View unloggedin.py source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py) #### __unloggedin_look_command (CmdUnconnectedLook) @@ -2551,8 +2455,7 @@ source](https://github.com/evennia/evennia/tree/master/evennia/commands/default/ - **[`help_category`](./Help-System):** *"General"* - **Source:** class `CmdUnconnectedLook` in [unloggedin.py](https://github.com/evennia/evennia/tree/ master/evennia/commands/default/unloggedin.py). -Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](h -ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). +Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). *OBS: This is a [[System Command|Commands]]. System commands have fixed keys and are called by the server in specific situations.* @@ -2573,10 +2476,8 @@ server in specific situations.* - **aliases:** *con*, *conn*, *co* - **[locks](./Locks):** *"cmd:all()"* - **[`help_category`](./Help-System):** *"General"* -- **Source:** class `CmdUnconnectedConnect` in [unloggedin.py](https://github.com/evennia/evennia/tr -ee/master/evennia/commands/default/unloggedin.py). -Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](h -ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). +- **Source:** class `CmdUnconnectedConnect` in [unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py). +Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). #### create (CmdUnconnectedCreate) @@ -2595,10 +2496,8 @@ ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_un - **aliases:** *cre*, *cr* - **[locks](./Locks):** *"cmd:all()"* - **[`help_category`](./Help-System):** *"General"* -- **Source:** class `CmdUnconnectedCreate` in [unloggedin.py](https://github.com/evennia/evennia/tre -e/master/evennia/commands/default/unloggedin.py). -Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](h -ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). +- **Source:** class `CmdUnconnectedCreate` in [unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py). +Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). #### help (CmdUnconnectedHelp) @@ -2615,10 +2514,8 @@ ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_un - **aliases:** *?*, *h* - **[locks](./Locks):** *"cmd:all()"* - **[`help_category`](./Help-System):** *"General"* -- **Source:** class `CmdUnconnectedHelp` in [unloggedin.py](https://github.com/evennia/evennia/tree/ -master/evennia/commands/default/unloggedin.py). -Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](h -ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). +- **Source:** class `CmdUnconnectedHelp` in [unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py). +Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). #### quit (CmdUnconnectedQuit) @@ -2636,8 +2533,6 @@ ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_un - **aliases:** *qu*, *q* - **[locks](./Locks):** *"cmd:all()"* - **[`help_category`](./Help-System):** *"General"* -- **Source:** class `CmdUnconnectedQuit` in [unloggedin.py](https://github.com/evennia/evennia/tree/ -master/evennia/commands/default/unloggedin.py). -Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](h -ttps://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). +- **Source:** class `CmdUnconnectedQuit` in [unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/unloggedin.py). +Belongs to command set *'DefaultUnloggedin'* of class `UnloggedinCmdSet` in [cmdset_unloggedin.py](https://github.com/evennia/evennia/tree/master/evennia/commands/default/cmdset_unloggedin.py). diff --git a/docs/source/Dialogues-in-events.md b/docs/source/Dialogues-in-events.md index 9e4760c6ba..f3bb5c0d06 100644 --- a/docs/source/Dialogues-in-events.md +++ b/docs/source/Dialogues-in-events.md @@ -236,8 +236,7 @@ another. - **Q:** can I have two characters answering to the same dialogue in exactly the same way? - **A:** It's possible but not so easy to do. Usually, event grouping is set in code, and depends on different games. However, if it is for some infrequent occurrences, it's easy to do using -[chained events](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README -.md#chained-events). +[chained events](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md#chained-events). - **Q:** is it possible to deploy callbacks on all characters sharing the same prototype? - **A:** not out of the box. This depends on individual settings in code. One can imagine that all characters of some type would share some events, but this is game-specific. Rooms of the same zone diff --git a/docs/source/Evennia-for-MUSH-Users.md b/docs/source/Evennia-for-MUSH-Users.md index ad579dc68c..db742eb0e0 100644 --- a/docs/source/Evennia-for-MUSH-Users.md +++ b/docs/source/Evennia-for-MUSH-Users.md @@ -88,8 +88,8 @@ another which is again somewhat remniscent at least of the *effect* of `@parent based inheritance of MUSH. There are other differences for sure, but that should give some feel for things. Enough with the -theory. Let's get down to more practical matters next. To install, see the [Getting Started -instructions](Getting-Started). +theory. Let's get down to more practical matters next. To install, see the +[Getting Started instructions](./Getting-Started). ## A first step making things more familiar @@ -138,8 +138,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): Note that Python cares about indentation, so make sure to indent with the same number of spaces as shown above! -So what happens above? We [import the module](http://www.linuxtopia.org/online_books/programming_boo -ks/python_programming/python_ch28s03.html) `evennia/contrib/multidescer.py` at the top. Once +So what happens above? We [import the module](http://www.linuxtopia.org/online_books/programming_books/python_programming/python_ch28s03.html) `evennia/contrib/multidescer.py` at the top. Once imported we can access stuff inside that module using full stop (`.`). The multidescer is defined as a class `CmdMultiDesc` (we could find this out by opening said module in a text editor). At the bottom we create a new instance of this class and add it to the `CharacterCmdSet` class. For the @@ -206,17 +205,14 @@ developer changing the underlying Python code. If you are a *Developer* and are interested in making a more MUSH-like Evennia game, a good start is to look into the Evennia [Tutorial for a first MUSH-like game](./Tutorial-for-basic-MUSH-like-game). That steps through building a simple little game from scratch and helps to acquaint you with the -various corners of Evennia. There is also the [Tutorial for running roleplaying sessions](Evennia- -for-roleplaying-sessions) that can be of interest. +various corners of Evennia. There is also the [Tutorial for running roleplaying sessions](./Evennia-for-roleplaying-sessions) that can be of interest. An important aspect of making things more familiar for *Players* is adding new and tweaking existing -commands. How this is done is covered by the [Tutorial on adding new commands](Adding-Command- -Tutorial). You may also find it useful to shop through the `evennia/contrib/` folder. The [Tutorial +commands. How this is done is covered by the [Tutorial on adding new commands](./Adding-Command-Tutorial). You may also find it useful to shop through the `evennia/contrib/` folder. The [Tutorial world](Tutorial-World-Introduction) is a small single-player quest you can try (it’s not very MUSH- like but it does show many Evennia concepts in action). Beyond that there are [many more tutorials](Tutorials) to try out. If you feel you want a more visual overview you can also look at [Evennia in pictures](https://evennia.blogspot.se/2016/05/evennia-in-pictures.html). -… And of course, if you need further help you can always drop into the [Evennia chatroom](http://web -chat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) or post a +… And of course, if you need further help you can always drop into the [Evennia chatroom](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) or post a question in our [forum/mailing list](https://groups.google.com/forum/#%21forum/evennia)! diff --git a/docs/source/Game-Planning.md b/docs/source/Game-Planning.md index f272d978f9..f5e2f6e663 100644 --- a/docs/source/Game-Planning.md +++ b/docs/source/Game-Planning.md @@ -4,11 +4,7 @@ So you have Evennia up and running. You have a great game idea in mind. Now it's time to start cracking! But where to start? Here are some ideas for a workflow. Note that the suggestions on this page are just that - suggestions. Also, they are primarily aimed at a lone hobby designer or a small -team developing a game in their free time. There is an article in the Imaginary Realities e-zine -which was written by the Evennia lead dev. It focuses more on you finding out your motivations for -making a game - you can [read the article here](http://journal.imaginary- -realities.com/volume-07/issue-03/where-do-i-begin/index.html). - +team developing a game in their free time. Below are some minimal steps for getting the first version of a new game world going with players. It's worth to at least make the attempt to do these steps in order even if you are itching to jump diff --git a/docs/source/Glossary.md b/docs/source/Glossary.md index cb93d7c731..65ea8eca11 100644 --- a/docs/source/Glossary.md +++ b/docs/source/Glossary.md @@ -90,7 +90,7 @@ monsters and other NPCs. You can [read more about it here](./Objects#subclasses- similar to Rails for the Ruby language. It is one of Evennia's central library dependencies (the other one is [Twisted](./Glossary#twisted)). Evennia uses Django for two main things - to map all database operations to Python and for structuring our web site. - + Through Django, we can work with any supported database (SQlite3, Postgres, MySQL ...) using generic Python instead of database-specific SQL: A database table is represented in Django as a Python class (called a *model*). An Python instance of such a class represents a row in that table. @@ -204,8 +204,7 @@ infrastructure. Git itself is a separate project. ### _object_ -In general Python (and other [object-oriented languages](https://en.wikipedia.org/wiki/Object- -oriented_programming)), an `object` is what we call the instance of a *class*. But one of Evennia's +In general Python (and other [object-oriented languages](https://en.wikipedia.org/wiki/Object-oriented_programming)), an `object` is what we call the instance of a *class*. But one of Evennia's core [typeclasses](./Glossary#typeclasss) is also called "Object". To separate these in the docs we try to use `object` to refer to the general term and capitalized `Object` when we refer to the typeclass. @@ -246,8 +245,7 @@ not have to be. ### _property_ A _property_ is a general term used for properties on any Python object. The term also sometimes -refers to the `property` built-in function of Python ([read more here](https://www.python- -course.eu/python3_properties.php)). Note the distinction between properties, +refers to the `property` built-in function of Python ([read more here](https://www.python-course.eu/python3_properties.php)). Note the distinction between properties, [fields](./Glossary#field) and [Attributes](./Glossary#attribute). ### _repository_ diff --git a/docs/source/Help-System-Tutorial.md b/docs/source/Help-System-Tutorial.md index c191838bd0..3d570c98c5 100644 --- a/docs/source/Help-System-Tutorial.md +++ b/docs/source/Help-System-Tutorial.md @@ -1,9 +1,7 @@ # Help System Tutorial -**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](Web- -Tutorial).** Reading the three first parts of the [Django -tutorial](https://docs.djangoproject.com/en/2.2/) might help as well. +**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](./Web-Tutorial).** Reading the three first parts of the [Django tutorial](https://docs.djangoproject.com/en/2.2/) might help as well. This tutorial will show you how to access the help system through your website. Both help commands and regular help entries will be visible, depending on the logged-in user or an anonymous character. diff --git a/docs/source/How-To-Get-And-Give-Help.md b/docs/source/How-To-Get-And-Give-Help.md index 03de9701b7..dd3d817c6f 100644 --- a/docs/source/How-To-Get-And-Give-Help.md +++ b/docs/source/How-To-Get-And-Give-Help.md @@ -4,12 +4,12 @@ ### How to *get* Help If you cannot find what you are looking for in the [online documentation](./index), here's what to do: - + - If you think the documentation is not clear enough and are short on time, fill in our quick little [online form][form] and let us know - no login required. Maybe the docs need to be improved or a new tutorial added! Note that while this form is useful as a suggestion box we cannot answer questions or reply to you. Use the discussion group or chat (linked below) if you want feedback. -- If you have trouble with a missing feature or a problem you think is a bug, go to the +- If you have trouble with a missing feature or a problem you think is a bug, go to the [issue tracker][issues] and search to see if has been reported/suggested already. If you can't find an existing entry create a new one. - If you need help, want to start a discussion or get some input on something you are working on, @@ -28,8 +28,8 @@ eventually! Evennia is a completely non-funded project. It relies on the time donated by its users and developers in order to progress. -The first and easiest way you as a user can help us out is by taking part in [community -discussions][group] and by giving feedback on what is good or bad. Report bugs you find and features +The first and easiest way you as a user can help us out is by taking part in +[community discussions][group] and by giving feedback on what is good or bad. Report bugs you find and features you lack to our [issue tracker][issues]. Just the simple act of letting developers know you are out there using their program is worth a lot. Generally mentioning and reviewing Evennia elsewhere is also a nice way to spread the word. @@ -50,24 +50,19 @@ fixed (if you want to put up a bounty yourself you can do so via our page on github. ... And finally, if you want to help motivate and support development you can also drop some coins -in the developer's cup. You can [make a donation via PayPal][paypal] or, even better, [become an -Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you +in the developer's cup. You can [make a donation via PayPal][paypal] or, even better, +[become an Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you appreciate the work done with the server! Finally, if you want to encourage the community to resolve a particular -[form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZG -c6MQ#gid=0 +[form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid=0 [group]: http://groups.google.com/group/evennia/ [issues]: https://github.com/evennia/evennia/issues -[issues-master]: https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%2 -0label%3Abug%20label%3Amaster-branch +[issues-master]: https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Abug%20label%3Amaster-branch [chat]: http://webchat.freenode.net/?channels=evennia -[paypal]: https://www.paypal.com/se/cgi-bin/webscr?cmd=_flow&SESSION=Z-VlOvfGjYq2qvCDOUGpb6C8Due7skT -0qOklQEy5EbaD1f0eyEQaYlmCc8O&dispatch=5885d80a13c0db1f8e263663d3faee8d64ad11bbf4d2a5a1a0d303a50933f9 +[paypal]: https://www.paypal.com/se/cgi-bin/webscr?cmd=_flow&SESSION=Z-VlOvfGjYq2qvCDOUGpb6C8Due7skT0qOklQEy5EbaD1f0eyEQaYlmCc8O&dispatch=5885d80a13c0db1f8e263663d3faee8d64ad11bbf4d2a5a1a0d303a50933f9 b2 -[donate-img]: http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.pay -palobjects.com/en%255fUS/SE/i/btn/btn%255fdonateCC%255fLG.gif&container=focus&gadget=a&rewriteMime=i -mage/* +[donate-img]: http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.paypalobjects.com/en%255fUS/SE/i/btn/btn%255fdonateCC%255fLG.gif&container=focus&gadget=a&rewriteMime=image/* [patreon]: https://www.patreon.com/griatch [patreon-img]: http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png [issues-bounties]: https://github.com/evennia/evennia/labels/bounty diff --git a/docs/source/Links.md b/docs/source/Links.md index 92ca8974f1..e0945bdcb4 100644 --- a/docs/source/Links.md +++ b/docs/source/Links.md @@ -6,8 +6,7 @@ - [evennia.com](http://www.evennia.com) - Main Evennia portal page. Links to all corners of Evennia. - [Evennia github page](https://github.com/evennia/evennia) - Download code and read documentation. -- [Evennia official chat channel](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRy -dWUmMTE9MTk1JjEyPXRydWUbb) - Our official IRC chat #evennia at irc.freenode.net:6667. +- [Evennia official chat channel](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) - Our official IRC chat #evennia at irc.freenode.net:6667. - [Evennia forums/mailing list](http://groups.google.com/group/evennia) - Web interface to our google group. - [Evennia development blog](http://evennia.blogspot.se/) - Musings from the lead developer. @@ -106,8 +105,7 @@ Influential mailing list active 1996-2004. Advanced game design discussions. - [Mud-dev wiki](http://mud-dev.wikidot.com/) - A (very) slowly growing resource on MUD creation. - [Mud Client/Server Interaction](http://cryosphere.net/mud-protocol.html) - A page on classic MUD telnet protocols. -- [Mud Tech's fun/cool but ...](http://gc-taylor.com/blog/2013/01/08/mud-tech-funcool-dont-forget- -ship-damned-thing/) - Greg Taylor gives good advice on mud design. +- [Mud Tech's fun/cool but ...](http://gc-taylor.com/blog/2013/01/08/mud-tech-funcool-dont-forget-ship-damned-thing/) - Greg Taylor gives good advice on mud design. - [Lost Library of MOO](http://www.hayseed.net/MOO/) - Archive of scientific articles on mudding (in particular moo). - [Nick Gammon's hints thread](http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=5959) - @@ -118,14 +116,12 @@ articles (not MUD-specific) - [The Alexandrian](http://thealexandrian.net/) - A blog about tabletop roleplaying and board games, but with lots of general discussion about rule systems and game balance that could be applicable also for MUDs. -- [Raph Koster's laws of game design](https://www.raphkoster.com/games/laws-of-online-world- -design/the-laws-of-online-world-design/) - thought-provoking guidelines and things to think about +- [Raph Koster's laws of game design](https://www.raphkoster.com/games/laws-of-online-world-design/the-laws-of-online-world-design/) - thought-provoking guidelines and things to think about when designing a virtual multiplayer world (Raph is known for *Ultima Online* among other things). ### Literature -- Richard Bartle *Designing Virtual Worlds* ([amazon page](http://www.amazon.com/Designing-Virtual- -Worlds-Richard-Bartle/dp/0131018167)) - Essential reading for the design of any persistent game +- Richard Bartle *Designing Virtual Worlds* ([amazon page](http://www.amazon.com/Designing-Virtual-Worlds-Richard-Bartle/dp/0131018167)) - Essential reading for the design of any persistent game world, written by the co-creator of the original game *MUD*. Published in 2003 but it's still as relevant now as when it came out. Covers everything you need to know and then some. - Zed A. Shaw *Learn Python the Hard way* ([homepage](https://learnpythonthehardway.org/)) - Despite @@ -161,7 +157,7 @@ economic system. - [GIT](http://git-scm.com/) - [Documentation](http://git-scm.com/documentation) - [Learn GIT in 15 minutes](http://try.github.io/levels/1/challenges/1) (interactive tutorial) - + ### Python Info - [Python Website](http://www.python.org/) @@ -177,4 +173,4 @@ programming curriculum for different skill levels - Wiki [Home](./index) Icons made by [Freepik](http://www.freepik.com"-title="Freepik">Freepik) from [flaticon.com](http://www.flaticon.com), licensed under [Creative Commons BY -3.0](http://creativecommons.org/licenses/by/3.0). \ No newline at end of file +3.0](http://creativecommons.org/licenses/by/3.0). diff --git a/docs/source/Online-Setup.md b/docs/source/Online-Setup.md index 52a0b5f8a5..998488fcb4 100644 --- a/docs/source/Online-Setup.md +++ b/docs/source/Online-Setup.md @@ -238,8 +238,7 @@ Also, on Freenode visit the #letsencrypt channel for assistance from the communi additional resource, Let's Encrypt has a very active [community forum](https://community.letsencrypt.org/). -[A blog where someone sets up Let's Encrypt](https://www.digitalocean.com/community/tutorials/how- -to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04) +[A blog where someone sets up Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04) The only process missing from all of the above documentation is how to pass verification. This is how Let's Encrypt verifies that you have control over your domain (not necessarily ownership, it's @@ -415,7 +414,7 @@ Evennia users: | `Linode`_ | Cloud | $5/month / | Multiple regions. Smallest option provides 1GB RAM | | | | on-demand | | +------------------------+----------------+----------------+----------------------------------------------------------+ - | `Genesis MUD hosting`_ | Shell account | $8/month | Dedicated MUD host with very limited memory offerings. | + | `Genesis MUD hosting`_ | Shell account | $8/month | Dedicated MUD host with very limited memory offerings. | | | | | When last investigated (2017) ran a 13 years old Python | | | | | version (2.4) (convince them to update or compile). | | | | | Note that Evennia needs *at least* the "Deluxe" package | diff --git a/docs/source/Portal-And-Server.md b/docs/source/Portal-And-Server.md index 22aa115db3..03ad6de9bc 100644 --- a/docs/source/Portal-And-Server.md +++ b/docs/source/Portal-And-Server.md @@ -8,8 +8,7 @@ If you are new to the concept, the main purpose of separating the two is to have the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the Server part) without Accounts getting disconnected. -![portal and server layout](https://474a3b9f-a-62cb3a1a-s- -sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png) +![portal and server layout](https://474a3b9f-a-62cb3a1a-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png) The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to communicate seamlessly. diff --git a/docs/source/Python-3.md b/docs/source/Python-3.md index 10cbd03093..96b3479a83 100644 --- a/docs/source/Python-3.md +++ b/docs/source/Python-3.md @@ -1,87 +1,4 @@ # Python 3 -> *Note: Evennia only supports Python 2.7+ at this time. This page gathers various development -information relevant to server developers.* +Evennia supports Python 3+ since v0.8. This page is deprecated. -Django can work with Python 2 and 3 already, though changes may be required to how the Evennia code -uses it. Twisted has much Python 3 compatibility, but not all modules within it have been ported -yet. The -[twisted.python.dist3](https://twistedmatrix.com/documents/current/api/twisted.python.dist3.html) -module gives some information about what's ported, and I'm compiling a list of missing modules with -related bug reports which can be found below. The list is based on a search for import statements in -the Evennia source code, please add anything that's missing. - -Part of this process is expected to be writing more tests for Evennia. One encouraging recent port -to Python 3 in Twisted is its Trial test framework, which may need to be used by Evennia to ensure -it still works correctly with Twisted on Python 3. - -# "Strings" -Broadly (and perhaps over-simplified): - -* Twisted [expects bytes](http://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#WhydontTwisted -snetworkmethodssupportUnicodeobjectsaswellasstrings) -* Django [expects "" to be unicode](https://docs.djangoproject.com/en/1.8/topics/python3/#unicode- -literals) - -I think we should use (roughly speaking) "" for unicode and b"" for bytes everywhere, but I need to -look at the impacts of this more closely. - -# Links - -* http://twistedmatrix.com/documents/current/core/howto/python3.html -* https://twistedmatrix.com/trac/wiki/Plan/Python3 -* [Twisted Python3 bugs](https://twistedmatrix.com/trac/query?status=assigned&status=new&status=reop -ened&group=status&milestone=Python-3.x) - -# Twisted module status - -x = not ported to Python 3 -/ = ported to Python 3 - -* twisted.application.internet / -* twisted.application.service / -* twisted.conch x (not used directly) - * ~https://twistedmatrix.com/trac/ticket/5102~ / - * ~https://twistedmatrix.com/trac/ticket/4993~ / -* twisted.conch.insults.insults x -* twisted.conch.interfaces x -* twisted.conch.manhole x -* twisted.conch.manhole_ssh x -* twisted.conch.ssh.common x -* twisted.conch.ssh.keys x - * ~https://twistedmatrix.com/trac/ticket/7998~ / - * "twisted.conch.ssh.keys should be ported to Python 3" -* twisted.conch.ssh.userauth x -* twisted.conch.telnet x -* twisted.cred.checkers / -* twisted.cred.portal / -* twisted.internet.defer / -* twisted.internet.interfaces / -* twisted.internet.protocol / -* twisted.internet.reactor / -* twisted.internet.ssl / -* twisted.internet.task / -* twisted.internet.threads / -* twisted.protocols.amp x - * ~https://twistedmatrix.com/trac/ticket/6833~ / - * "Port twisted.protocols.amp to Python 3" -* twisted.protocols.policies / -* twisted.python.components / -* twisted.python.log / -* twisted.python.threadpool / -* twisted.web.http (x) - * Partial support. Sufficient? -* twisted.web.resource / -* twisted.web.server (x) - * Partial support. Sufficient? -* twisted.web.static / -* twisted.web.proxy / -* twisted.web.wsgi x - * ~https://twistedmatrix.com/trac/ticket/7993~ / - * "'twisted.web.wsgi' should be ported to Python 3" - * Seems to be making good progress -* twisted.words.protocols.irc x - * https://twistedmatrix.com/trac/ticket/6320 - * "Python 3 support for twisted.words.protocols.irc" - * ~https://twistedmatrix.com/trac/ticket/6564~ - * "Replace usage of builtin reduce in twisted.words" diff --git a/docs/source/Python-basic-introduction.md b/docs/source/Python-basic-introduction.md index 759aa570d8..f79688367f 100644 --- a/docs/source/Python-basic-introduction.md +++ b/docs/source/Python-basic-introduction.md @@ -196,8 +196,7 @@ your life a lot easier. This is a [reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html); try not to use these words anywhere else. - A function name can not have spaces but otherwise we could have called it almost anything. We call -it `hello_world`. Evennia follows [Python's standard naming -style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style- +it `hello_world`. Evennia follows [Python's standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style- points) with lowercase letters and underscores. Use this style for now. - `who` is what we call the *argument* to our function. Arguments are variables we pass to the function. We could have named it anything and we could also have multiple arguments separated by diff --git a/docs/source/Python-basic-tutorial-part-two.md b/docs/source/Python-basic-tutorial-part-two.md index 7eebbd04d3..a95bb74d7f 100644 --- a/docs/source/Python-basic-tutorial-part-two.md +++ b/docs/source/Python-basic-tutorial-part-two.md @@ -55,8 +55,7 @@ A *class* is like a "factory" or blueprint. From a class you then create individ if class is`Dog`, an instance of `Dog` might be `fido`. Our in-game persona is of a class `Character`. The superuser `christine` is an *instance* of the `Character` class (an instance is also often referred to as an *object*). This is an important concept in *object oriented -programming*. You are wise to [familiarize yourself with it](https://en.wikipedia.org/wiki/Class- -based_programming) a little. +programming*. You are wise to [familiarize yourself with it](https://en.wikipedia.org/wiki/Class-based_programming) a little. > In other terms: > * class: A description of a thing, all the methods (code) and data (information) @@ -176,8 +175,7 @@ also explore it [online on github](https://github.com/evennia/evennia/tree/maste The structure of the library directly reflects how you import from it. -- To, for example, import [the text justify -function](https://github.com/evennia/evennia/blob/master/evennia/utils/utils.py#L201) from +- To, for example, import [the text justify function](https://github.com/evennia/evennia/blob/master/evennia/utils/utils.py#L201) from `evennia/utils/utils.py` you would do `from evennia.utils.utils import justify`. In your code you could then just call `justify(...)` to access its functionality. - You could also do `from evennia.utils import utils`. In code you would then have to write @@ -191,15 +189,13 @@ import in Python. Now, remember that our `characters.py` module did `from evennia import DefaultCharacter`. But if we look at the contents of the `evennia` folder, there is no `DefaultCharacter` anywhere! This is -because Evennia gives a large number of optional "shortcuts", known as [the "flat" API](Evennia- -API). The intention is to make it easier to remember where to find stuff. The flat API is defined in +because Evennia gives a large number of optional "shortcuts", known as [the "flat" API](./Evennia-API). The intention is to make it easier to remember where to find stuff. The flat API is defined in that weirdly named `__init__.py` file. This file just basically imports useful things from all over Evennia so you can more easily find them in one place. We could [just look at the documenation](github:evennia#typeclasses) to find out where we can look at our `DefaultCharacter` parent. But for practice, let's figure it out. Here is where -`DefaultCharacter` [is imported -from](https://github.com/evennia/evennia/blob/master/evennia/__init__.py#L188) inside `__init__.py`: +`DefaultCharacter` [is imported from](https://github.com/evennia/evennia/blob/master/evennia/__init__.py#L188) inside `__init__.py`: ```python from .objects.objects import DefaultCharacter @@ -231,8 +227,7 @@ is the same thing, just a little easier to remember. In the previous section we traced the parent of our `Character` class to be `DefaultCharacter` in -[evennia/objects/objects.py](https://github.com/evennia/evennia/blob/master/evennia/objects/objects. -py). +[evennia/objects/objects.py](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py). Open that file and locate the `DefaultCharacter` class. It's quite a bit down in this module so you might want to search using your editor's (or browser's) search function. Once you find it, you'll find that the class starts like this: @@ -276,8 +271,7 @@ outside ``` -... And so on (you can see the full [class online -here](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1915)). Here we +... And so on (you can see the full [class online here](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1915)). Here we have functional code! These methods may not be directly visible in `Character` back in our game dir, but they are still available since `Character` is a child of `DefaultCharacter` above. Here is a brief summary of the methods we find in `DefaultCharacter` (follow in the code to see if you can see @@ -309,8 +303,7 @@ class DefaultCharacter(DefaultObject): This means that `DefaultCharacter` is in *itself* a child of something called `DefaultObject`! Let's see what this parent class provides. It's in the same module as `DefaultCharacter`, you just need to -[scroll up near the -top](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L193): +[scroll up near the top](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L193): ```python class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): @@ -327,11 +320,9 @@ the doc string of `msg`. > As seen, `DefaultObject` actually has multiple parents. In one of those the basic `key` property is defined, but we won't travel further up the inheritance tree in this tutorial. If you are -interested to see them, you can find `TypeclassBase` in [evennia/typeclasses/models.py](https://gith -ub.com/evennia/evennia/blob/master/evennia/typeclasses/models.py#L93) and `ObjectDB` in [evennia/obj +interested to see them, you can find `TypeclassBase` in [evennia/typeclasses/models.py](https://github.com/evennia/evennia/blob/master/evennia/typeclasses/models.py#L93) and `ObjectDB` in [evennia/obj ects/models.py](https://github.com/evennia/evennia/blob/master/evennia/objects/models.py#L121). We -will also not go into the details of [Multiple -Inheritance](https://docs.python.org/2/tutorial/classes.html#multiple-inheritance) or +will also not go into the details of [Multiple Inheritance](https://docs.python.org/2/tutorial/classes.html#multiple-inheritance) or [Metaclasses](http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html) here. The general rule is that if you realize that you need these features, you already know enough to use them. @@ -384,8 +375,7 @@ By default the `at_before_say` method doesn't do anything. It just takes the `me `return`s it just the way it was (the `return` is another reserved Python word). > We won't go into `**kwargs` here, but it (and its sibling `*args`) is also important to -understand, extra reading is [here for -`**kwargs`](https://stackoverflow.com/questions/1769403/understanding-kwargs-in-python). +understand, extra reading is [here for `**kwargs`](https://stackoverflow.com/questions/1769403/understanding-kwargs-in-python). Now, open your game folder and edit `mygame/typeclasses/characters.py`. Locate your `Character` class and modify it as such: @@ -407,8 +397,7 @@ through the method. Note that `f` in front of the string, it means we turned the string into a 'formatted string'. We can now easily inject stuff directly into the string by wrapping them in curly brackets `{ }`. In this example, we put the incoming `message` into the string, followed by an ellipsis. This is only -one way to format a string. Python has very powerful [string -formatting](https://docs.python.org/2/library/string.html#format-specification-mini-language) and +one way to format a string. Python has very powerful [string formatting](https://docs.python.org/2/library/string.html#format-specification-mini-language) and you are wise to learn it well, considering your game will be mainly text-based. > You could also copy & paste the relevant method from `DefaultObject` here to get the full doc @@ -454,8 +443,7 @@ program. IPython ... ... - In [1]: -IPython has some very nice ways to explore what Evennia has to offer. + In [1]: IPython has some very nice ways to explore what Evennia has to offer. > import evennia > evennia. @@ -489,15 +477,14 @@ and resources [on our link page](./Links). We have touched upon many of the concepts here but to use Evennia and to be able to follow along in the code, you will need basic understanding of Python [modules](http://docs.python.org/2/tutorial/modules.html), -[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), [conditional -statements](http://docs.python.org/tutorial/controlflow.html#if-statements), +[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), +[conditional statements](http://docs.python.org/tutorial/controlflow.html#if-statements), [loops](http://docs.python.org/tutorial/controlflow.html#for-statements), -[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), [lists, -dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) and [string -formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic -understanding of [object-oriented -programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) and what Python -[Classes](http://docs.python.org/tutorial/classes.html) are. +[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), +[lists, dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) +and [string formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic +understanding of [object-oriented programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) +and what Python [Classes](http://docs.python.org/tutorial/classes.html) are. Once you have familiarized yourself, or if you prefer to pick Python up as you go, continue to one of the beginning-level [Evennia tutorials](./Tutorials) to gradually build up your understanding. diff --git a/docs/source/Screenshot.md b/docs/source/Screenshot.md index 71352aac94..29bd21024f 100644 --- a/docs/source/Screenshot.md +++ b/docs/source/Screenshot.md @@ -1,8 +1,7 @@ # Screenshot -![evennia_screenshot2017](https://user- -images.githubusercontent.com/294267/30773728-ea45afb6-a076-11e7-8820-49be2168a6b8.png) +![evennia_screenshot2017](https://user-images.githubusercontent.com/294267/30773728-ea45afb6-a076-11e7-8820-49be2168a6b8.png) *(right-click and choose your browser's equivalent of "view image" to see it full size)* This screenshot shows a vanilla [install](./Getting-Started) of the just started Evennia MUD server. diff --git a/docs/source/Server-Conf.md b/docs/source/Server-Conf.md index eedb0b3d3e..b0b6afe19f 100644 --- a/docs/source/Server-Conf.md +++ b/docs/source/Server-Conf.md @@ -10,8 +10,8 @@ The "Settings" file referenced throughout the documentation is the file `mygame/server/conf/settings.py`. This is automatically created on the first run of `evennia --init` (see the [Getting Started](./Getting-Started) page). -Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually [ -evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default +Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually +[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default .py) and is considerably more extensive (it is also heavily documented so you should refer to this file directly for the available settings). diff --git a/docs/source/Static-In-Game-Map.md b/docs/source/Static-In-Game-Map.md index a0c4e3d1b0..6d0a4a8435 100644 --- a/docs/source/Static-In-Game-Map.md +++ b/docs/source/Static-In-Game-Map.md @@ -18,8 +18,7 @@ sanity of their players. And when they do, the game becomes possible to map. Thi an example of a simple but flexible in-game map system to further help player's to navigate. We will To simplify development and error-checking we'll break down the work into bite-size chunks, each -building on what came before. For this we'll make extensive use of the [Batch code processor](Batch- -Code-Processor), so you may want to familiarize yourself with that. +building on what came before. For this we'll make extensive use of the [Batch code processor](./Batch-Code-Processor), so you may want to familiarize yourself with that. 1. **Planning the map** - Here we'll come up with a small example map to use for the rest of the tutorial. @@ -36,7 +35,7 @@ map we designed before. O─O─O To the south, the glow of a campfire can be seen. To the east lie ≈↑│↑∩ the vast mountains and to the west is heard the waves of the sea. ↑▲O▲↑ - + Exits: north(#8), east(#9), south(#10), west(#11) ``` @@ -46,9 +45,7 @@ don't show in the documentation wiki. ## Planning the Map -Let's begin with the fun part! Maps in MUDs come in many different [shapes and -sizes](http://journal.imaginary-realities.com/volume-05/issue-01/modern-interface-modern- -mud/index.html). Some appear as just boxes connected by lines. Others have complex graphics that are +Let's begin with the fun part! Maps in MUDs come in many different [shapes and sizes](http://journal.imaginary-realities.com/volume-05/issue-01/modern-interface-modern-mud/index.html). Some appear as just boxes connected by lines. Others have complex graphics that are external to the game itself. Our map will be in-game text but that doesn't mean we're restricted to the normal alphabet! If @@ -275,12 +272,12 @@ def return_map(): This function returns the whole map """ map = "" - + #For each row in our map, add it to map for valuey in world_map: map += valuey map += "\n" - + return map def return_minimap(x, y, radius = 2): @@ -289,12 +286,12 @@ def return_minimap(x, y, radius = 2): Returning all chars in a 2 char radius from (x,y) """ map = "" - + #For each row we need, add the characters we need. for valuey in world_map[y-radius:y+radius+1]: for valuex in valuey[x-radius:x+radius+1]: map += valuex map += "\n" - + return map ``` @@ -411,6 +408,5 @@ You should now have a mapped little world and a basic understanding of batchcode easily new game defining features can be added to Evennia. You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why -not add more features to your game by trying other tutorials: [Add weather to your world](Weather- -Tutorial), [fill your world with NPC's](./Tutorial-Aggressive-NPCs) or [implement a combat -system](Turn-based-Combat-System). +not add more features to your game by trying other tutorials: [Add weather to your world](./Weather-Tutorial), +[fill your world with NPC's](./Tutorial-Aggressive-NPCs) or [implement a combat system](./Turn-based-Combat-System). diff --git a/docs/source/Turn-based-Combat-System.md b/docs/source/Turn-based-Combat-System.md index d0a0dc864c..578129453a 100644 --- a/docs/source/Turn-based-Combat-System.md +++ b/docs/source/Turn-based-Combat-System.md @@ -2,8 +2,7 @@ This tutorial gives an example of a full, if simplified, combat system for Evennia. It was inspired -by the discussions held on the [mailing -list](https://groups.google.com/forum/#!msg/evennia/wnJNM2sXSfs/-dbLRrgWnYMJ). +by the discussions held on the [mailing list](https://groups.google.com/forum/#!msg/evennia/wnJNM2sXSfs/-dbLRrgWnYMJ). ## Overview of combat system concepts @@ -49,8 +48,7 @@ free. - The commands are (in our example) simple; they can either `hit `, `feint ` or `parry `. They can also `defend`, a generic passive defense. Finally they may choose to `disengage/flee`. -- When attacking we use a classic [rock-paper-scissors](https://en.wikipedia.org/wiki/Rock-paper- -scissors) mechanic to determine success: `hit` defeats `feint`, which defeats `parry` which defeats +- When attacking we use a classic [rock-paper-scissors](https://en.wikipedia.org/wiki/Rock-paper-scissors) mechanic to determine success: `hit` defeats `feint`, which defeats `parry` which defeats `hit`. `defend` is a general passive action that has a percentage chance to win against `hit` (only). - `disengage/flee` must be entered two times in a row and will only succeed if there is no `hit` @@ -67,8 +65,7 @@ characters and handles all the combat information. Since Scripts are database en that the combat will not be affected by a server reload. - A combat [command set](./Command-Sets) with the relevant commands needed for combat, such as the various attack/defend options and the `flee/disengage` command to leave the combat mode. -- A rule resolution system. The basics of making such a module is described in the [rule system -tutorial](Implementing-a-game-rule-system). We will only sketch such a module here for our end-turn +- A rule resolution system. The basics of making such a module is described in the [rule system tutorial](./Implementing-a-game-rule-system). We will only sketch such a module here for our end-turn combat resolution. - An `attack` [command](./Commands) for initiating the combat mode. This is added to the default command set. It will create the combat handler and add the character(s) to it. It will also assign @@ -168,7 +165,7 @@ class CombatHandler(DefaultScript): commands). We know this by checking the existence of the `normal_turn_end` NAttribute, set just before calling force_repeat. - + """ if self.ndb.normal_turn_end: # we get here because the turn ended normally @@ -190,7 +187,7 @@ class CombatHandler(DefaultScript): ("defend", character, None)] # set up back-reference self._init_character(character) - + def remove_character(self, character): "Remove combatant from handler" if character.id in self.db.characters: @@ -311,7 +308,7 @@ class CmdHit(Command): self.caller.msg("You add 'hit' to the combat queue") else: self.caller.msg("You can only queue two actions per turn!") - + # tell the handler to check if turn is over self.caller.ndb.combat_handler.check_end_turn() ``` @@ -347,8 +344,7 @@ class CombatCmdSet(CmdSet): ## Rules module -A general way to implement a rule module is found in the [rule system tutorial](Implementing-a-game- -rule-system). Proper resolution would likely require us to change our Characters to store things +A general way to implement a rule module is found in the [rule system tutorial](./Implementing-a-game-rule-system). Proper resolution would likely require us to change our Characters to store things like strength, weapon skills and so on. So for this example we will settle for a very simplistic rock-paper-scissors kind of setup with some randomness thrown in. We will not deal with damage here but just announce the results of each turn. In a real system the Character objects would hold stats diff --git a/docs/source/Tutorial-World-Introduction.md b/docs/source/Tutorial-World-Introduction.md index 4c45e041ae..746647d4f7 100644 --- a/docs/source/Tutorial-World-Introduction.md +++ b/docs/source/Tutorial-World-Introduction.md @@ -60,13 +60,7 @@ will automatically be unquelled. ## Gameplay -![the castle off the moor](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/22916c25-6299-4 -53d-a221-446ec839f567/da2pmzu-46d63c6d-9cdc-41dd-87d6-1106db5a5e1a.jpg/v1/fill/w_600,h_849,q_75,strp -/the_castle_off_the_moor_by_griatch_art_da2pmzu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1N -iJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04NDkiLCJwYXRoIjoiXC9m -XC8yMjkxNmMyNS02Mjk5LTQ1M2QtYTIyMS00NDZlYzgzOWY1NjdcL2RhMnBtenUtNDZkNjNjNmQtOWNkYy00MWRkLTg3ZDYtMTEw -NmRiNWE1ZTFhLmpwZyIsIndpZHRoIjoiPD02MDAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.o -muS3D1RmFiZCy9OSXiIita-HxVGrBok3_7asq0rflw) +![the castle off the moor](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/22916c25-6299-453d-a221-446ec839f567/da2pmzu-46d63c6d-9cdc-41dd-87d6-1106db5a5e1a.jpg/v1/fill/w_600,h_849,q_75,strp/the_castle_off_the_moor_by_griatch_art_da2pmzu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04NDkiLCJwYXRoIjoiXC9mXC8yMjkxNmMyNS02Mjk5LTQ1M2QtYTIyMS00NDZlYzgzOWY1NjdcL2RhMnBtenUtNDZkNjNjNmQtOWNkYy00MWRkLTg3ZDYtMTEwNmRiNWE1ZTFhLmpwZyIsIndpZHRoIjoiPD02MDAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.omuS3D1RmFiZCy9OSXiIita-HxVGrBok3_7asq0rflw) *To get into the mood of this miniature quest, imagine you are an adventurer out to find fame and @@ -88,7 +82,7 @@ the scenes of the tutorial). - *defend* will lower the chance to taking damage on your enemy's next attack. - You *can* run from a fight that feels too deadly. Expect to be chased though. - Being defeated is a part of the experience ... - + ## Uninstall Uninstalling the tutorial world basically means deleting all the rooms and objects it consists of. diff --git a/docs/source/Tutorials.md b/docs/source/Tutorials.md index 32fc379b3e..7a2dc54bf7 100644 --- a/docs/source/Tutorials.md +++ b/docs/source/Tutorials.md @@ -2,8 +2,8 @@ Before continuing to read these tutorials (and especially before you start to code or build your -game in earnest) it's strongly recommended that you read the [Evennia coding introduction](Coding- -Introduction) as well as the [Planning your own game](./Game-Planning) pages first. +game in earnest) it's strongly recommended that you read the +[Evennia coding introduction](./Coding-Introduction) as well as the [Planning your own game](./Game-Planning) pages first. Please note that it's not within the scope of our tutorials to teach you basic Python. If you are new to the language, expect to have to look up concepts you are unfamiliar with. Usually a quick @@ -34,22 +34,17 @@ _General code practices for newbie game developers._ To use Evennia, you will need basic understanding of Python [modules](http://docs.python.org/3.7/tutorial/modules.html), -[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), [conditional -statements](http://docs.python.org/tutorial/controlflow.html#if-statements), +[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), [conditional statements](http://docs.python.org/tutorial/controlflow.html#if-statements), [loops](http://docs.python.org/tutorial/controlflow.html#for-statements), -[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), [lists, -dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) and [string -formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic -understanding of [object-oriented -programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) and what Python +[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), [lists, dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) and [string formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic +understanding of [object-oriented programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) and what Python [Classes](http://docs.python.org/tutorial/classes.html) are. - [Python tutorials for beginners](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) - external link with tutorials for those not familiar with coding in general or Python in particular. - [Tutorial: Version Control](./Version-Control) - use GIT to organize your code both for your own game project and for contributing to Evennia. -- MIT offers free courses in many subjects. Their [Introduction to Computer Science and -Programming](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc- +- MIT offers free courses in many subjects. Their [Introduction to Computer Science and Programming](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc- introduction-to-computer-science-and-programming-spring-2011/) uses Python as its language of choice. Longer path, but more in-depth. Definitely worth a look. @@ -113,8 +108,7 @@ Evennia. - [Tutorial: Handling virtual time in your game](./Gametime-Tutorial) - [Tutorial: Setting up a coordinate system for rooms](./Coordinates) - [Tutorial: customize the way channels and channel commands work in your game](./Customize-channels) -- [Tutorial: Adding unit tests to your game project](./Unit-Testing#testing-for-game-development-mini- -tutorial) +- [Tutorial: Adding unit tests to your game project](./Unit-Testing#testing-for-game-development-mini- tutorial) ### Contrib diff --git a/docs/source/Unit-Testing.md b/docs/source/Unit-Testing.md index edf43efda8..2e2e1a9e08 100644 --- a/docs/source/Unit-Testing.md +++ b/docs/source/Unit-Testing.md @@ -55,8 +55,7 @@ forces Evennia to use this settings file over the default one. Evennia's test suite makes use of Django unit test system, which in turn relies on Python's *unittest* module. -> If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io -page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of +> If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of test coverage and which does not. To make the test runner find the tests, they must be put in a module named `test*.py` (so `test.py`, @@ -74,16 +73,16 @@ To test the results, you use special methods of the `TestCase` class. Many of t "`assert`", such as `assertEqual` or `assertTrue`. Example of a `TestCase` class: - + ```python import unittest - + # the function we want to test from mypath import myfunc - + class TestObj(unittest.TestCase): "This tests a function myfunc." - + def test_return_value(self): "test method. Makes sure return value is as expected." expected_return = "This is me being nice." @@ -98,8 +97,7 @@ Example of a `TestCase` class: self.assertEqual(expected_return, actual_return) ``` -You might also want to read the [documentation for the unittest -module](http://docs.python.org/library/unittest.html). +You might also want to read the [documentation for the unittest module](http://docs.python.org/library/unittest.html). ### Using the EvenniaTest class @@ -108,8 +106,7 @@ initiates a range of useful properties on themselves for testing Evennia systems `.account` and `.session` representing a mock connected Account and its Session and `.char1` and `.char2` representing Characters complete with a location in the test database. These are all useful when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full -definition of the `EvenniaTest` class in [evennia/utils/test_resources.py](https://github.com/evenni -a/evennia/blob/master/evennia/utils/test_resources.py). +definition of the `EvenniaTest` class in [evennia/utils/test_resources.py](https://github.com/evennia/evennia/blob/master/evennia/utils/test_resources.py). ```python # in a test module @@ -164,9 +161,7 @@ of the Evennia distribution and its unit tests should be run with all other Even The way to do this is to only temporarily add your models to the `INSTALLED_APPS` directory when the test runs. here is an example of how to do it. -> Note that this solution, derived from this [stackexchange -answer](http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for- -testing#503435) is currently untested! Please report your findings. +> Note that this solution, derived from this [stackexchange answer](http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-testing#503435) is currently untested! Please report your findings. ```python # a file contrib/mycontrib/tests.py @@ -199,7 +194,7 @@ class TestMyModel(EvenniaTest): from django.db.models import loading loading.cache.loaded = False call_command('syncdb', verbosity=0) - + def tearDown(self): settings.configure(**OLD_DEFAULT_SETTINGS) django.setup() @@ -290,11 +285,11 @@ just to show how unit testing works: # mygame/commands/tests.py import unittest - + class TestString(unittest.TestCase): - + """Unittest for strings (just a basic example).""" - + def test_upper(self): """Test the upper() str method.""" self.assertEqual('foo'.upper(), 'FOO') @@ -317,7 +312,7 @@ Let's execute that test to see if it works. . ---------------------------------------------------------------------- Ran 1 test in 0.001s - + OK Destroying test database for alias 'default'... @@ -330,8 +325,8 @@ to see how it looks when it fails. ### Testing commands -This section will test the proper execution of the 'abilities' command, as described in the [First -Steps Coding](First-Steps-Coding) page. Follow this tutorial to create the 'abilities' command, we +This section will test the proper execution of the 'abilities' command, as described in the +[First Steps Coding](./First-Steps-Coding) page. Follow this tutorial to create the 'abilities' command, we will need it to test it. Testing commands in Evennia is a bit more complex than the simple testing example we have seen. @@ -347,14 +342,14 @@ already have in `commands` from before. # bottom of mygame/commands/tests.py from evennia.commands.default.tests import CommandTest - + from commands.command import CmdAbilities from typeclasses.characters import Character - + class TestAbilities(CommandTest): - + character_typeclass = Character - + def test_simple(self): self.call(CmdAbilities(), "", "STR: 5, AGI: 4, MAG: 2") ``` @@ -390,7 +385,7 @@ Let's run our new test: .. ---------------------------------------------------------------------- Ran 2 tests in 0.156s - + OK Destroying test database for alias 'default'... @@ -405,19 +400,19 @@ will have nothing but static output to test. Here we are going to learn how to t output.
This tutorial assumes you have a basic understanding of what regular expressions are. If you do not -I recommend reading the `Introduction` and `Simple Pattern` sections at [Python regular expressions -tutorial](https://docs.python.org/3/howto/regex.html). If you do plan on making a complete Evennia +I recommend reading the `Introduction` and `Simple Pattern` sections at +[Python regular expressions tutorial](https://docs.python.org/3/howto/regex.html). If you do plan on making a complete Evennia project learning regular expressions will save a great deal of time.
Append the code below to your `tests.py` file.
```python # bottom of mygame/commands/tests.py - + class TestDynamicAbilities(CommandTest): - + character_typeclass = Character - + def test_simple(self): cmd_abil_result = self.call(CmdAbilities(), "") self.assertRegex(cmd_abil_result, "STR: \d+, AGI: \d+, MAG: \d+") diff --git a/docs/source/Web-Character-Generation.md b/docs/source/Web-Character-Generation.md index e570af528c..fe7e129b61 100644 --- a/docs/source/Web-Character-Generation.md +++ b/docs/source/Web-Character-Generation.md @@ -15,8 +15,7 @@ selection screen when you log into the game later). Other modes can be used with auto-puppet the new Character. You should have some familiarity with how Django sets up its Model Template View framework. You need -to understand what is happening in the basic [Web Character View tutorial](Web-Character-View- -Tutorial). If you don’t understand the listed tutorial or have a grasp of Django basics, please look +to understand what is happening in the basic [Web Character View tutorial](./Web-Character-View-Tutorial). If you don’t understand the listed tutorial or have a grasp of Django basics, please look at the [Django tutorial](https://docs.djangoproject.com/en/1.8/intro/) to get a taste of what Django does, before throwing Evennia into the mix (Evennia shares its API and attributes with the website interface). This guide will outline the format of the models, views, urls, and html templates @@ -29,32 +28,28 @@ Here are some screenshots of the simple app we will be making. Index page, with no character application yet done: *** -![Index page, with no character application yet done.](https://lh3.googleusercontent.com/-57KuSWHXQ_ -M/VWcULN152tI/AAAAAAAAEZg/kINTmVlHf6M/w425-h189-no/webchargen_index2.gif) +![Index page, with no character application yet done.](https://lh3.googleusercontent.com/-57KuSWHXQ_M/VWcULN152tI/AAAAAAAAEZg/kINTmVlHf6M/w425-h189-no/webchargen_index2.gif) *** Having clicked the "create" link you get to create your character (here we will only have name and background, you can add whatever is needed to fit your game): *** -![Character creation.](https://lh3.googleusercontent.com/-ORiOEM2R_yQ/VWcUKgy84rI/AAAAAAAAEZY/B3CBh3 -FHii4/w607-h60-no/webchargen_creation.gif) +![Character creation.](https://lh3.googleusercontent.com/-ORiOEM2R_yQ/VWcUKgy84rI/AAAAAAAAEZY/B3CBh3FHii4/w607-h60-no/webchargen_creation.gif) *** Back to the index page. Having entered our character application (we called our character "TestApp") you see it listed: *** -![Having entered an application.](https://lh6.googleusercontent.com/-HlxvkvAimj4/VWcUKjFxEiI/AAAAAAA -AEZo/gLppebr05JI/w321-h194-no/webchargen_index1.gif) +![Having entered an application.](https://lh6.googleusercontent.com/-HlxvkvAimj4/VWcUKjFxEiI/AAAAAAAAEZo/gLppebr05JI/w321-h194-no/webchargen_index1.gif) *** We can also view an already written character application by clicking on it - this brings us to the *detail* page: *** -![Detail view of character application.](https://lh6.googleusercontent.com/-2m1UhSE7s_k/VWcUKfLRfII/ -AAAAAAAAEZc/UFmBOqVya4k/w267-h175-no/webchargen_detail.gif) +![Detail view of character application.](https://lh6.googleusercontent.com/-2m1UhSE7s_k/VWcUKfLRfII/AAAAAAAAEZc/UFmBOqVya4k/w267-h175-no/webchargen_detail.gif) *** ## Installing an App @@ -281,7 +276,7 @@ After all of this, our `views.py` file should look like something like this: ```python # file mygame/web/chargen/views.py - + from django.shortcuts import render from web.chargen.models import CharApp from web.chargen.forms import AppForm @@ -544,8 +539,7 @@ created character object. Thankfully, the Evennia API makes this easy. As sad as it is, if your server is open to the web, bots might come to visit and take advantage of your open form to create hundreds, thousands, millions of characters if you give them the -opportunity. This section shows you how to use the [No CAPCHA -reCAPCHA](https://www.google.com/recaptcha/intro/invisible.html) designed by Google. Not only is it +opportunity. This section shows you how to use the [No CAPCHA reCAPCHA](https://www.google.com/recaptcha/intro/invisible.html) designed by Google. Not only is it easy to use, it is user-friendly... for humans. A simple checkbox to check, except if Google has some suspicion, in which case you will have a more difficult test with an image and the usual text inside. It's worth pointing out that, as long as Google doesn't suspect you of being a robot, this diff --git a/docs/source/Web-Character-View-Tutorial.md b/docs/source/Web-Character-View-Tutorial.md index 880093be8a..e5992e10ee 100644 --- a/docs/source/Web-Character-View-Tutorial.md +++ b/docs/source/Web-Character-View-Tutorial.md @@ -1,8 +1,7 @@ # Web Character View Tutorial -**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](Web- -Tutorial).** +**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](./Web-Tutorial).** In this tutorial we will create a web page that displays the stats of a game character. For this, and all other pages we want to make specific to our game, we'll need to create our own Django "app" @@ -226,4 +225,4 @@ page by using {{ object.get_absolute_url }} in any template where you have a giv *Now that you've made a basic page and app with Django, you may want to read the full Django tutorial to get a better idea of what it can do. [You can find Django's tutorial -here](https://docs.djangoproject.com/en/1.8/intro/tutorial01/).* \ No newline at end of file +here](https://docs.djangoproject.com/en/1.8/intro/tutorial01/).* diff --git a/docs/source/Web-Features.md b/docs/source/Web-Features.md index 40709ef43f..e28b630913 100644 --- a/docs/source/Web-Features.md +++ b/docs/source/Web-Features.md @@ -35,7 +35,7 @@ You customize your website from your game directory. In the folder `web` you'll `static`, `templates`, `static_overrides` and `templates_overrides`. The first two of those are populated automatically by Django and used to serve the website. You should not edit anything in them - the change will be lost. To customize the website you'll need to copy the file you want to -change from the `web/website/template/` or `web/website/static/ path to the corresponding place +change from the `web/website/template/` or `web/website/static/` path to the corresponding place under one of `_overrides` directories. Example: To override or modify `evennia/web/website/template/website/index.html` you need to @@ -89,8 +89,7 @@ the root of the website. It will now our own function `myview` from a new module `mygame.com` in the address bar. If we had wanted to add a view for `http://mygame.com/awesome`, the regular expression would have been `^/awesome`. -Look at [evennia/web/website/views.py](https://github.com/evennia/evennia/blob/master/evennia/web/we -bsite/views.py#L82) to see the inputs and outputs you must have to define a view. Easiest may be to +Look at [evennia/web/website/views.py](https://github.com/evennia/evennia/blob/master/evennia/web/website/views.py#L82) to see the inputs and outputs you must have to define a view. Easiest may be to copy the default file to `mygame/web` to have something to modify and expand on. Restart the server and reload the page in the browser - the website will now use your custom view. From 93b68e3a312ba6f53d2ff9fa52fa91e74bfade16 Mon Sep 17 00:00:00 2001 From: davewiththenicehat <54369722+davewiththenicehat@users.noreply.github.com> Date: Mon, 14 Jun 2021 18:43:18 -0400 Subject: [PATCH 05/14] CmdTasks removed text tags added yes no --- evennia/commands/default/system.py | 183 +++++++++++++++++------------ evennia/commands/default/tests.py | 100 +++++++++++++--- 2 files changed, 192 insertions(+), 91 deletions(-) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 9bb1f05b40..88e8421152 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -24,6 +24,7 @@ from evennia.utils import logger, utils, gametime, create, search from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.evmore import EvMore +from evennia.utils.evmenu import ask_yes_no from evennia.utils.utils import crop, class_from_module from evennia.scripts.taskhandler import TaskHandlerTask @@ -1217,7 +1218,7 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): tasks[/switch] [function name] Process the action in the switch to all tasks that are deferring a specific function name. This would match the name of the callback you passed to a delay or the task handler. - tasks[/switch] [task id], [completion date], [function memory reference] + tasks[/switch] [task id] Process the action in the switch to a specific task. Switches: @@ -1237,17 +1238,16 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): Only the action requested on the first switch will be processed. All other switches will be ignored. - Manipulation of a single task is intended to be done via the clickable links or through - code directly. Due to generally short life of a task, the inclusion of completion date - and function's memory reference guarentees an incorrect task will not be manipulated. - By default, tasks that are canceled and never called are automatically removed after one minute. Example: tasks/cancel move_callback - Cancel all movement delays from the slow_exit contrib. - In this example slow exits creates it's tasks with: utils.delay(move_delay, move_callback) + Cancel all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with: + utils.delay(move_delay, move_callback) + tasks/cancel 2 + Cancel task id 2. """ @@ -1265,6 +1265,36 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None return t_comp_date, t_func_mem_ref + def do_task_action(self, *args, **kwargs): + """ + Process the action of a tasks command. + + This exists to gain support with yes or no function from EvMenu. + """ + task_id = self.task_id + + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + + # verify manipulating the correct task + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg('Task completed while waiting for input.') + return + else: + # make certain a task with matching IDs has not been created + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref: + self.msg('Task completed while waiting for input.') + return + + # Do the action requested by command caller + action_return = self.task_action() + self.msg(f'{self.action_request} request completed.') + self.msg(f'The task function {self.action_request} returned: {action_return}') + def func(self): # get a reference of the global task handler global _TASK_HANDLER @@ -1278,16 +1308,80 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): return # handle caller's request to manipulate a task(s) - if self.switches or self.lhs: + if self.switches and self.lhs: + + # find if the argument is a task id or function name action_request = self.switches[0] - # handle caller requesting an action on specific deferred function - if len(self.lhslist) == 1: + try: + arg_is_id = int(self.lhslist[0]) + except ValueError: + arg_is_id = False + + # if the argument is a task id, proccess the action on a single task + if arg_is_id: + + err_arg_msg = 'Switch and task ID are required when manipulating a task.' + task_comp_msg = 'Task completed while processing request.' + + # handle missing arguments or switches + if not self.switches and self.lhs: + self.msg(err_arg_msg) + return + + # create a handle for the task + task_id = arg_is_id + task = TaskHandlerTask(task_id) + + # handle task no longer existing + if not task.exists(): + self.msg(f'Task {task_id} does not exist.') + return + + # get a reference of the function caller requested + switch_action = getattr(task, action_request, False) + if not switch_action: + self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ + f'{task_comp_msg.lower()}') + + # verify manipulating the correct task + if task_id in _TASK_HANDLER.tasks: + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg(task_comp_msg) + return + else: + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + + if task.exists(): # make certain the task has not been called yet. + prompt = f'Yes or No, {action_request} task {task_id}? With completion date ' \ + f'{t_comp_date}. Deferring function {t_func_name}.' + no_msg = f'No {action_request} processed.' + # record variables for use in do_task_action method + self.task_id = task_id + self.t_comp_date = t_comp_date + self.t_func_mem_ref = t_func_mem_ref + self.task_action = switch_action + self.action_request = action_request + ask_yes_no(self.caller, prompt, self.do_task_action, no_msg, no_msg, True) + return True + else: + self.msg(task_comp_msg) + return + + # the argument is not a task id, process the action on all task deferring the function + # specified as an argument + else: + name_match_found = False arg_func_name = self.lhslist[0].lower() + # repack tasks into a new dictionary current_tasks = {} for task_id, task_args in _TASK_HANDLER.tasks.items(): current_tasks.update({task_id: task_args}) + # call requested action on all tasks with the function name for task_id, task_args in current_tasks.items(): t_func_name = str(task_args[1]).split(' ') @@ -1302,65 +1396,18 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): action_return = switch_action() self.msg(f'Task action {action_request} completed on task ID {task_id}.') self.msg(f'The task function {action_request} returned: {action_return}') + # provide a message if not tasks of the function name was found if not name_match_found: self.msg(f'No tasks deferring function name {arg_func_name} found.') return return True - err_arg_msg = 'Task ID, completion date and memory reference are required when ' \ - 'manipulating a delay.' - task_comp_msg = 'Task completed while processing request.' - # handle missing arguments or switches - if not self.switches and self.lhs: - self.msg(err_arg_msg) - return - # handle incorrect arguments - if len(self.lhslist) < 2: - self.msg(err_arg_msg) - return - # create a handle for the task - task_id = int(self.lhslist[0]) - task = TaskHandlerTask(task_id) - # handle task no longer existing - if not task.exists(): - self.msg(f'Task {task_id} does not exist.') - return - # get a reference of the function caller requested - switch_action = getattr(task, action_request, False) - if not switch_action: - self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ - f'{task_comp_msg.lower()}') - # verify manipulating the correct task - if task_id in _TASK_HANDLER.tasks: - task_args = _TASK_HANDLER.tasks.get(task_id, False) - if task_args: # check if the task is still active - sw_comp_date = self.lhslist[1] - sw_func_mem_ref = self.lhslist[2] - t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) - # handle completion date mismatch - if not t_comp_date == sw_comp_date: - self.msg('Task completion time does not match time passed.') - self.msg(task_comp_msg) - self.msg('Likely a new task with the same ID was created') - return - # handle function memory reference mismatch - if not t_func_mem_ref == sw_func_mem_ref: - self.msg("Memory reference for the task's function does not match argument") - self.msg(task_comp_msg) - self.msg('Likely a new task with the same ID was created') - return - else: # task no longer exists - self.msg(task_comp_msg) - return - if task.exists(): # make certain the task has not been called yet. - # call the task's method - action_return = switch_action() - self.msg(f'Task action {action_request} completed.') - self.msg(f'The task function {action_request} returned: {action_return}') - return True - else: - self.msg(task_comp_msg) - return + + # check if an maleformed request was created + elif self.switches or self.lhs: + self.msg('Task command misformed.') + self.msg('Proper format tasks[/switch] [function name or task id]') + return # No task manupilation requested, build a table of tasks and display it # get the width of screen in characters @@ -1382,14 +1429,6 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) for i in range(len(tasks_header)): tasks_list[i].append(task_data[i]) - # add task actions to the tasks list - actions = ('pause', 'unpause', 'do_task', 'remove', 'call', 'cancel') - for i in range(len(tasks_header)): - tasks_list[i].append(f"|lc{self.key}/{actions[i]} {task_id}, {t_comp_date}, " \ - f"{t_func_mem_ref}|lt{actions[i]}|le") - # if the screen width is large enough, add directional arrows - if width >= 75: - tasks_list[i][-1] = f"^{tasks_list[i][-1]}^" # create and display the table tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', align='center') diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 815ac7ee26..f7d70d059f 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -594,7 +594,6 @@ class TestCmdTasks(CommandTest): self.task_handler.clear() self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) task_args = self.task_handler.tasks.get(self.task.get_id(), False) - self.t_comp_date, self.t_func_mem_ref = system.CmdTasks.coll_date_func(task_args) def tearDown(self): @@ -620,36 +619,46 @@ class TestCmdTasks(CommandTest): def test_pause_unpause(self): # test pause - args = f'/pause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' - wanted_msg = 'Task action pause completed.|The task function pause returned:' - self.call(system.CmdTasks(), args, wanted_msg) + args = f'/pause {self.task.get_id()}' + wanted_msg = 'Yes or No, pause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') self.assertTrue(self.task.paused) self.task_handler.clock.advance(self.timedelay + 1) # test unpause - args = f'/unpause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' + args = f'/unpause {self.task.get_id()}' self.assertTrue(self.task.exists()) - wanted_msg = 'Task action unpause completed.|The task function unpause returned: None' - self.call(system.CmdTasks(), args, wanted_msg) + wanted_msg = 'Yes or No, unpause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') # verify task continues after unpause self.task_handler.clock.advance(1) self.assertFalse(self.task.exists()) def test_do_task(self): - args = f'/do_task {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' - wanted_msg = 'Task action do_task completed.|The task function do_task returned: success' - self.call(system.CmdTasks(), args, wanted_msg) + args = f'/do_task {self.task.get_id()}' + wanted_msg = 'Yes or No, do_task task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') self.assertFalse(self.task.exists()) def test_remove(self): - args = f'/remove {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' - wanted_msg = 'Task action remove completed.|The task function remove returned: True' - self.call(system.CmdTasks(), args, wanted_msg) + args = f'/remove {self.task.get_id()}' + wanted_msg = 'Yes or No, remove task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') self.assertFalse(self.task.exists()) def test_call(self): - args = f'/call {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' - wanted_msg = 'Task action call completed.|The task function call returned: success' - self.call(system.CmdTasks(), args, wanted_msg) + args = f'/call {self.task.get_id()}' + wanted_msg = 'Yes or No, call task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') # make certain the task is still active self.assertTrue(self.task.active()) # go past delay time, the task should call do_task and remove itself after calling. @@ -657,9 +666,11 @@ class TestCmdTasks(CommandTest): self.assertFalse(self.task.exists()) def test_cancel(self): - args = f'/cancel {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' - wanted_msg = 'Task action cancel completed.|The task function cancel returned: True' - self.call(system.CmdTasks(), args, wanted_msg) + args = f'/cancel {self.task.get_id()}' + wanted_msg = 'Yes or No, cancel task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') self.assertTrue(self.task.exists()) self.assertFalse(self.task.active()) @@ -677,6 +688,57 @@ class TestCmdTasks(CommandTest): self.call(system.CmdTasks(), args, wanted_msg) self.assertTrue(self.task.active()) + def test_no_input(self): + args = f'/cancel {self.task.get_id()}' + self.call(system.CmdTasks(), args) + # task should complete since no input was received + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists()) + + def test_responce_of_yes(self): + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'cancel request completed.The task function cancel returned: True') + self.assertTrue(self.task.exists()) + + def test_task_complete_waiting_input(self): + """Test for task completing while waiting for input.""" + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.') + self.assertFalse(self.task.exists()) + + def test_new_task_waiting_input(self): + """ + Test task completing than a new task with the same ID being made while waitinf for input. + """ + self.assertTrue(self.task.get_id(), 1) + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists()) + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + self.assertTrue(self.task.get_id(), 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.') + + def test_misformed_command(self): + wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \ + '[function name or task id]' + self.call(system.CmdTasks(), f'/cancel', wanted_msg) + class TestAdmin(CommandTest): def test_emit(self): From 0bd7860974575d1e97a1dc4d53a217b52b76d74c Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 17 Jun 2021 20:56:55 +0200 Subject: [PATCH 06/14] doc style improvements --- docs/source/How-To-Get-And-Give-Help.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/source/How-To-Get-And-Give-Help.md b/docs/source/How-To-Get-And-Give-Help.md index 5e0b4dc87d..6f4560c1d5 100644 --- a/docs/source/How-To-Get-And-Give-Help.md +++ b/docs/source/How-To-Get-And-Give-Help.md @@ -4,10 +4,10 @@ ### How to *get* Help If you cannot find what you are looking for in the documentation, here's what to do: - + - If you think the documentation is not clear enough, create a [documentation ticket](github:issue). -- If you have trouble with a missing feature or a problem you think is a bug, look through the - the list of known [issue][issues] if you can't find your issue in the list, make a +- If you have trouble with a missing feature or a problem you think is a bug, look through the + the list of known [issue][issues] if you can't find your issue in the list, make a new one [here](github:issue). - If you need help, want to start a discussion or get some input on something you are working on, make a post to the [discussions group][group] This is technically a 'mailing list', but you don't @@ -26,8 +26,8 @@ eventually! Evennia is open-source and non-commercial. It relies on the time donated by its users and developers in order to progress. - Spread the word! If you like Evennia, consider writing a blog post about it. -- Take part in the Evennia community! Join the [chat][chat] or [forum][group]. -- Report problems you find or features you'd like to our [issue tracker](github:issue). +- Take part in the Evennia community! Join the [chat][chat] or [forum][group]. +- Report problems you find or features you'd like to our [issue tracker](github:issue). ```important:: Just the simple act of us know you are out there using Evennia helps a lot! @@ -35,9 +35,9 @@ Evennia is open-source and non-commercial. It relies on the time donated by its If you'd like to help develop Evennia more hands-on, here are some ways to get going: -- Look through this [online documentation](./index#Evennia-documentation) and see if you can help improve or expand the -documentation (even small things like fixing typos!). [See here](./Contributing-Docs) on how you -contribute to the docs. +- Look through this [online documentation](./index#Evennia-documentation) and see if you can help improve or expand the +documentation (even small things like fixing typos!). [See here](./Contributing-Docs) on how you +contribute to the docs. - Send a message to our [discussion group][group] and/or our [IRC chat][chat] asking about what needs doing, along with what your interests and skills are. - Take a look at our [issue tracker][issues] and see if there's something you feel like taking on. @@ -47,10 +47,10 @@ needs doing, along with what your interests and skills are. github. ... And finally, if you want to help motivate and support development you can also drop some coins -in the developer's cup. You can [make a donation via PayPal][paypal] or, even better, [become an -Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you +in the developer's cup. You can [make a donation via PayPal][paypal] or, even better, +[become an Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you appreciate the work done with the server! You can also encourage the community to take on particular -issues by putting up a monetary [bounty][bountysource] on it. +issues by putting up a monetary [bounty][bountysource] on it. [form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid=0 @@ -63,4 +63,4 @@ issues by putting up a monetary [bounty][bountysource] on it. [patreon]: https://www.patreon.com/griatch [patreon-img]: http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png [issues-bounties]:https://github.com/evennia/evennia/labels/bounty -[bountysource]: https://www.bountysource.com/teams/evennia \ No newline at end of file +[bountysource]: https://www.bountysource.com/teams/evennia From 41986e12886f96b9d2d3b540f7c36497e648ccb3 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 18 Jun 2021 19:34:39 +0200 Subject: [PATCH 07/14] Try reporting a little more info from taskhandler deserialization error --- evennia/scripts/taskhandler.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index ab1b29666d..3b826844a1 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -340,11 +340,11 @@ class TaskHandler(object): # an unsaveable callback should immediately abort try: dbserialize(callback) - except (TypeError, AttributeError, PickleError): + except (TypeError, AttributeError, PickleError) as err: raise ValueError( - "the specified callback {} cannot be pickled. " + "the specified callback {callback} cannot be pickled. " "It must be a top-level function in a module or an " - "instance method.".format(callback) + "instance method ({err}).".format(callback=callback, err=err) ) return From e6733ba7ff2594bd813528b8eba694484317ca14 Mon Sep 17 00:00:00 2001 From: fariparedes Date: Fri, 18 Jun 2021 14:07:59 -0400 Subject: [PATCH 08/14] Update iter_to_string with handling for list size of 2 --- CHANGELOG.md | 1 + evennia/utils/tests/test_utils.py | 5 +++-- evennia/utils/utils.py | 16 +++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e45bc07133..3408f0d9e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Up requirements to Django 3.2+ into a more consistent structure for overriding. Expanded webpage documentation considerably. - REST API list-view was shortened (#2401). New CSS/HTML. Add ReDoc for API autodoc page. - Update and fix dummyrunner with cleaner code and setup. +- Made `iter_to_str` format prettier strings ### Evennia 0.9.5 (2019-2020) diff --git a/evennia/utils/tests/test_utils.py b/evennia/utils/tests/test_utils.py index 2c4011c73b..9c18e1ccd8 100644 --- a/evennia/utils/tests/test_utils.py +++ b/evennia/utils/tests/test_utils.py @@ -72,10 +72,11 @@ class TestListToString(TestCase): def test_list_to_string(self): self.assertEqual("1, 2, 3", utils.list_to_string([1, 2, 3], endsep="")) self.assertEqual('"1", "2", "3"', utils.list_to_string([1, 2, 3], endsep="", addquote=True)) - self.assertEqual("1, 2 and 3", utils.list_to_string([1, 2, 3])) + self.assertEqual("1, 2, and 3", utils.list_to_string([1, 2, 3])) self.assertEqual( - '"1", "2" and "3"', utils.list_to_string([1, 2, 3], endsep="and", addquote=True) + '"1", "2", and "3"', utils.list_to_string([1, 2, 3], endsep="and", addquote=True) ) + self.assertEqual("1 and 2", utils.list_to_string([1, 2])) class TestMLen(TestCase): diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index ee8274efe5..6e3d274080 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -381,15 +381,13 @@ def iter_to_str(initer, endsep="and", addquote=False): >>> list_to_string([1,2,3], endsep='') '1, 2, 3' >>> list_to_string([1,2,3], ensdep='and') - '1, 2 and 3' + '1, 2, and 3' >>> list_to_string([1,2,3], endsep='and', addquote=True) - '"1", "2" and "3"' + '"1", "2", and "3"' ``` """ - if not endsep: - endsep = "," - else: + if endsep: endsep = " " + endsep if not initer: return "" @@ -397,11 +395,15 @@ def iter_to_str(initer, endsep="and", addquote=False): if addquote: if len(initer) == 1: return '"%s"' % initer[0] - return ", ".join('"%s"' % v for v in initer[:-1]) + "%s %s" % (endsep, '"%s"' % initer[-1]) + elif len(initer) == 2: + return '"%s"' % ('"%s "' % endsep).join(str(v) for v in initer) + return ", ".join('"%s"' % v for v in initer[:-1]) + ",%s %s" % (endsep, '"%s"' % initer[-1]) else: if len(initer) == 1: return str(initer[0]) - return ", ".join(str(v) for v in initer[:-1]) + "%s %s" % (endsep, initer[-1]) + elif len(initer) == 2: + return ("%s " % endsep).join(str(v) for v in initer) + return ", ".join(str(v) for v in initer[:-1]) + ",%s %s" % (endsep, initer[-1]) # legacy aliases From 7358758987f72fc3c56f1eb732c641cded4f4226 Mon Sep 17 00:00:00 2001 From: fariparedes Date: Fri, 18 Jun 2021 14:26:36 -0400 Subject: [PATCH 09/14] Add MXP support for anchor tags --- CHANGELOG.md | 1 + docs/source/Concepts/Clickable-Links.md | 7 ++++--- evennia/server/portal/mxp.py | 3 +++ evennia/utils/ansi.py | 6 +++++- evennia/utils/tests/test_tagparsing.py | 4 ++++ evennia/utils/text2html.py | 19 ++++++++++++++++++- 6 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e45bc07133..6775456698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Up requirements to Django 3.2+ into a more consistent structure for overriding. Expanded webpage documentation considerably. - REST API list-view was shortened (#2401). New CSS/HTML. Add ReDoc for API autodoc page. - Update and fix dummyrunner with cleaner code and setup. +- Added an MXP anchor tag in addition to the command tag ### Evennia 0.9.5 (2019-2020) diff --git a/docs/source/Concepts/Clickable-Links.md b/docs/source/Concepts/Clickable-Links.md index b29065e9e2..5a4f9ed262 100644 --- a/docs/source/Concepts/Clickable-Links.md +++ b/docs/source/Concepts/Clickable-Links.md @@ -1,11 +1,12 @@ ## Clickable links Evennia supports clickable links for clients that supports it. This marks certain text so it can be -clicked by a mouse and trigger a given Evennia command. To support clickable links, Evennia requires -the webclient or an third-party telnet client with [MXP](http://www.zuggsoft.com/zmud/mxp.htm) -support (*Note: Evennia only supports clickable links, no other MXP features*). +clicked by a mouse and either trigger a given Evennia command, or open a URL in an external web +browser. To support clickable links, Evennia requires the webclient or an third-party telnet client +with [MXP](http://www.zuggsoft.com/zmud/mxp.htm) support (*Note: Evennia only supports clickable links, no other MXP features*). - `|lc` to start the link, by defining the command to execute. +- `|lu` to start the link, by defining the URL to open. - `|lt` to continue with the text to show to the user (the link text). - `|le` to end the link text and the link definition. diff --git a/evennia/server/portal/mxp.py b/evennia/server/portal/mxp.py index 6c938ab709..7f5b39d392 100644 --- a/evennia/server/portal/mxp.py +++ b/evennia/server/portal/mxp.py @@ -16,12 +16,14 @@ http://www.gammon.com.au/mushclient/addingservermxp.htm import re LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) +URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) # MXP Telnet option MXP = bytes([91]) # b"\x5b" MXP_TEMPSECURE = "\x1B[4z" MXP_SEND = MXP_TEMPSECURE + '' + "\\2" + MXP_TEMPSECURE + "" +MXP_URL = MXP_TEMPSECURE + '' + "\\2" + MXP_TEMPSECURE + "" def mxp_parse(text): @@ -38,6 +40,7 @@ def mxp_parse(text): text = text.replace("&", "&").replace("<", "<").replace(">", ">") text = LINKS_SUB.sub(MXP_SEND, text) + text = URL_SUB.sub(MXP_URL, text) return text diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index 0dd2d8234c..490621329c 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -223,6 +223,7 @@ class ANSIParser(object): ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP mxp_re = r"\|lc(.*?)\|lt(.*?)\|le" + mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le" # prepare regex matching brightbg_sub = re.compile( @@ -237,6 +238,7 @@ class ANSIParser(object): # xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL) ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL) mxp_sub = re.compile(mxp_re, re.DOTALL) + mxp_url_sub = re.compile(mxp_url_re, re.DOTALL) # used by regex replacer to correctly map ansi sequences ansi_map_dict = dict(ansi_map) @@ -424,7 +426,9 @@ class ANSIParser(object): string (str): The processed string. """ - return self.mxp_sub.sub(r"\2", string) + string = self.mxp_sub.sub(r"\2", string) + string = self.mxp_url_sub.sub(r"\2", string) + return string def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): """ diff --git a/evennia/utils/tests/test_tagparsing.py b/evennia/utils/tests/test_tagparsing.py index 5c47bc5b6a..ae78c8fd0d 100644 --- a/evennia/utils/tests/test_tagparsing.py +++ b/evennia/utils/tests/test_tagparsing.py @@ -145,13 +145,17 @@ class ANSIStringTestCase(TestCase): """ mxp1 = "|lclook|ltat|le" mxp2 = "Start to |lclook here|ltclick somewhere here|le first" + mxp3 = "Check out |luhttps://www.example.com|ltmy website|le!" self.assertEqual(15, len(ANSIString(mxp1))) self.assertEqual(53, len(ANSIString(mxp2))) + self.assertEqual(53, len(ANSIString(mxp3))) # These would indicate an issue with the tables. self.assertEqual(len(ANSIString(mxp1)), len(ANSIString(mxp1).split("\n")[0])) self.assertEqual(len(ANSIString(mxp2)), len(ANSIString(mxp2).split("\n")[0])) + self.assertEqual(len(ANSIString(mxp3)), len(ANSIString(mxp3).split("\n")[0])) self.assertEqual(mxp1, ANSIString(mxp1)) self.assertEqual(mxp2, str(ANSIString(mxp2))) + self.assertEqual(mxp3, str(ANSIString(mxp3))) def test_add(self): """ diff --git a/evennia/utils/text2html.py b/evennia/utils/text2html.py index 7fb19a8ab8..bb4251caf7 100644 --- a/evennia/utils/text2html.py +++ b/evennia/utils/text2html.py @@ -103,9 +103,10 @@ class TextToHTMLparser(object): ) re_dblspace = re.compile(r" {2,}", re.M) re_url = re.compile( - r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' + r'(?\[\]\s])+)(\.(?:\s|$)|&\w+;|)' ) re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) + re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) def _sub_bgfg(self, colormatch): # print("colormatch.groups()", colormatch.groups()) @@ -290,6 +291,21 @@ class TextToHTMLparser(object): ) return val + def sub_mxp_urls(self, match): + """ + Helper method to be passed to re.sub, + replaces MXP links with HTML code. + Args: + match (re.Matchobject): Match for substitution. + Returns: + text (str): Processed text. + """ + url, text = [grp.replace('"', "\\"") for grp in match.groups()] + val = ( + r"""{text}""".format(url=url, text=text) + ) + return val + def sub_text(self, match): """ Helper method to be passed to re.sub, @@ -337,6 +353,7 @@ class TextToHTMLparser(object): # convert all ansi to html result = re.sub(self.re_string, self.sub_text, text) result = re.sub(self.re_mxplink, self.sub_mxp_links, result) + result = re.sub(self.re_mxpurl, self.sub_mxp_urls, result) result = self.re_color(result) result = self.re_bold(result) result = self.re_underline(result) From de8fe64841f6db58ff9e9aa0380f20d9d1488705 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 19 Jun 2021 12:38:35 +0200 Subject: [PATCH 10/14] Fix unit tests for PR #2440. --- evennia/contrib/crafting/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/contrib/crafting/tests.py b/evennia/contrib/crafting/tests.py index 2e87df1615..3c3dfa1452 100644 --- a/evennia/contrib/crafting/tests.py +++ b/evennia/contrib/crafting/tests.py @@ -182,9 +182,9 @@ class TestCraftingRecipe(TestCase): "i1": "cons2", "i2": "cons3", "o0": "Result1", - "tools": "bar, bar2 and bar3", + "tools": "bar, bar2, and bar3", "consumables": "cons1 and cons2", - "inputs": "cons1, cons2 and cons3", + "inputs": "cons1, cons2, and cons3", "outputs": "Result1", } From d12dce8959388f2f6679dae4ea0ebbf165e69c77 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 19 Jun 2021 13:51:28 +0200 Subject: [PATCH 11/14] Formatting/style updates to new tasks command --- CHANGELOG.md | 2 ++ evennia/commands/default/system.py | 54 +++++++++++++----------------- evennia/utils/ansi.py | 2 +- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec6983a098..b77feca3be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Up requirements to Django 3.2+ - Update and fix dummyrunner with cleaner code and setup. - Made `iter_to_str` format prettier strings, using Oxford comma. - Added an MXP anchor tag to also support clickable web links. +- New `tasks` command for managing tasks started with `utils.delay` (PR by davewiththenicehat) ### Evennia 0.9.5 (2019-2020) @@ -151,6 +152,7 @@ without arguments starts a full interactive Python console. - Include more Web-client info in `session.protocol_flags`. - Fixes in multi-match situations - don't allow finding/listing multimatches for 3-box when only two boxes in location. +- Fix for TaskHandler with proper deferred returns/ability to cancel etc (PR by davewiththenicehat) ## Evennia 0.9 (2018-2019) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 88e8421152..08dee11376 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -25,7 +25,7 @@ from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.evmore import EvMore from evennia.utils.evmenu import ask_yes_no -from evennia.utils.utils import crop, class_from_module +from evennia.utils.utils import crop, class_from_module, iter_to_str from evennia.scripts.taskhandler import TaskHandlerTask COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) @@ -1213,13 +1213,7 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): Display or terminate active tasks (delays). Usage: - tasks - show all current active taks. - tasks[/switch] [function name] - Process the action in the switch to all tasks that are deferring a specific function name. - This would match the name of the callback you passed to a delay or the task handler. - tasks[/switch] [task id] - Process the action in the switch to a specific task. + tasks[/switch] [task_id or function_name] Switches: pause - Pause the callback of a task. @@ -1230,29 +1224,22 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): cancel - Stop a task from automatically executing. Notes: - A task is a single use method of delaying the call of a function. + A task is a single use method of delaying the call of a function. Calls are created + in code, using `evennia.utils.delay`. + See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help. - Tasks can be created using utils.delay. - Reference: https://evennia.readthedocs.io/en/latest/Command-Duration.html + By default, tasks that are canceled and never called are cleaned up after one minute. - Only the action requested on the first switch will be processed. All other switches will - be ignored. - - By default, tasks that are canceled and never called are automatically removed after - one minute. - - Example: - tasks/cancel move_callback - Cancel all movement delays from the slow_exit contrib. - In this example slow exits creates it's tasks with: - utils.delay(move_delay, move_callback) - tasks/cancel 2 - Cancel task id 2. + Examples: + - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with + `utils.delay(move_delay, move_callback)` + - `tasks/cancel 2` - Cancel task id 2. """ key = "tasks" - aliases = ["delays"] + aliases = ["delays", "task"] switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel") locks = "perm(Developer)" help_category = "System" @@ -1260,7 +1247,7 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): @staticmethod def coll_date_func(task): """Replace regex characters in date string and collect deferred function name.""" - t_comp_date = str(task[0]).replace('-', '/').replace('.', ' ms:') + t_comp_date = str(task[0]).replace('-', '/') t_func_name = str(task[1]).split(' ') t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None return t_comp_date, t_func_mem_ref @@ -1355,8 +1342,8 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None if task.exists(): # make certain the task has not been called yet. - prompt = f'Yes or No, {action_request} task {task_id}? With completion date ' \ - f'{t_comp_date}. Deferring function {t_func_name}.' + prompt = (f'{action_request.capitalize()} task {task_id} with completion date ' + f'{t_comp_date} ({t_func_name}) {{options}}?') no_msg = f'No {action_request} processed.' # record variables for use in do_task_action method self.task_id = task_id @@ -1364,7 +1351,12 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): self.t_func_mem_ref = t_func_mem_ref self.task_action = switch_action self.action_request = action_request - ask_yes_no(self.caller, prompt, self.do_task_action, no_msg, no_msg, True) + ask_yes_no(self.caller, + prompt=prompt, + yes_action=self.do_task_action, + no_action=no_msg, + default="Y", + allow_abort=True) return True else: self.msg(task_comp_msg) @@ -1432,4 +1424,6 @@ class CmdTasks(COMMAND_DEFAULT_CLASS): # create and display the table tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', align='center') - self.msg(tasks_table) + actions = (f'/{switch}' for switch in self.switch_options) + helptxt = f"\nActions: {iter_to_str(actions)}" + self.msg(str(tasks_table) + helptxt) diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index 490621329c..605a133397 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -427,7 +427,7 @@ class ANSIParser(object): """ string = self.mxp_sub.sub(r"\2", string) - string = self.mxp_url_sub.sub(r"\2", string) + string = self.mxp_url_sub.sub(r"\1", string) # replace with url verbatim return string def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): From 9df1f9f25f39d069b94ae816f08bda2748d37840 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 19 Jun 2021 14:57:24 +0200 Subject: [PATCH 12/14] Fix legacy bytes conversion for older twisted --- evennia/server/portal/mccp.py | 3 +-- evennia/server/portal/mssp.py | 7 +++---- evennia/server/portal/mxp.py | 3 +-- evennia/server/portal/naws.py | 5 ++--- evennia/server/portal/suppress_ga.py | 4 +--- evennia/server/portal/telnet_oob.py | 17 ++++++++--------- evennia/server/portal/ttype.py | 8 +++----- 7 files changed, 19 insertions(+), 28 deletions(-) diff --git a/evennia/server/portal/mccp.py b/evennia/server/portal/mccp.py index 2d00e479b6..7ecba2d9d4 100644 --- a/evennia/server/portal/mccp.py +++ b/evennia/server/portal/mccp.py @@ -15,10 +15,9 @@ This protocol is implemented by the telnet protocol importing mccp_compress and calling it from its write methods. """ import zlib -from twisted.python.compat import _bytesChr as chr # negotiations for v1 and v2 of the protocol -MCCP = chr(86) # b"\x56" +MCCP = bytes([86]) # b"\x56" FLUSH = zlib.Z_SYNC_FLUSH diff --git a/evennia/server/portal/mssp.py b/evennia/server/portal/mssp.py index d939bcc37b..227a713cbf 100644 --- a/evennia/server/portal/mssp.py +++ b/evennia/server/portal/mssp.py @@ -12,11 +12,10 @@ active players and so on. """ from django.conf import settings from evennia.utils import utils -from twisted.python.compat import _bytesChr as bchr -MSSP = bchr(70) # b"\x46" -MSSP_VAR = bchr(1) # b"\x01" -MSSP_VAL = bchr(2) # b"\x02" +MSSP = bytes([70]) # b"\x46" +MSSP_VAR = bytes([1]) # b"\x01" +MSSP_VAL = bytes([2]) # b"\x02" # try to get the customized mssp info, if it exists. MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={}) diff --git a/evennia/server/portal/mxp.py b/evennia/server/portal/mxp.py index 8ff773036d..7c0f2325a5 100644 --- a/evennia/server/portal/mxp.py +++ b/evennia/server/portal/mxp.py @@ -14,12 +14,11 @@ http://www.gammon.com.au/mushclient/addingservermxp.htm """ import re -from twisted.python.compat import _bytesChr as bchr LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) # MXP Telnet option -MXP = bchr(91) # b"\x5b" +MXP = bytes([91]) # b"\x5b" MXP_TEMPSECURE = "\x1B[4z" MXP_SEND = MXP_TEMPSECURE + '' + "\\2" + MXP_TEMPSECURE + "" diff --git a/evennia/server/portal/naws.py b/evennia/server/portal/naws.py index caa9f73402..23bc6f2e7b 100644 --- a/evennia/server/portal/naws.py +++ b/evennia/server/portal/naws.py @@ -11,10 +11,9 @@ client and update it when the size changes """ from codecs import encode as codecs_encode from django.conf import settings -from twisted.python.compat import _bytesChr as bchr -NAWS = bchr(31) # b"\x1f" -IS = bchr(0) # b"\x00" +NAWS = bytes([31]) # b"\x1f" +IS = bytes([0]) # b"\x00" # default taken from telnet specification DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH DEFAULT_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT diff --git a/evennia/server/portal/suppress_ga.py b/evennia/server/portal/suppress_ga.py index 21332ea070..4bd8dc2c45 100644 --- a/evennia/server/portal/suppress_ga.py +++ b/evennia/server/portal/suppress_ga.py @@ -13,9 +13,7 @@ It is set as the NOGOAHEAD protocol_flag option. http://www.faqs.org/rfcs/rfc858.html """ -from twisted.python.compat import _bytesChr as bchr - -SUPPRESS_GA = bchr(3) # b"\x03" +SUPPRESS_GA = bytes([3]) # b"\x03" # default taken from telnet specification diff --git a/evennia/server/portal/telnet_oob.py b/evennia/server/portal/telnet_oob.py index 1570feb003..656aac9eaa 100644 --- a/evennia/server/portal/telnet_oob.py +++ b/evennia/server/portal/telnet_oob.py @@ -31,23 +31,22 @@ applicable. import re import json from evennia.utils.utils import is_iter -from twisted.python.compat import _bytesChr as bchr # General Telnet from twisted.conch.telnet import IAC, SB, SE # MSDP-relevant telnet cmd/opt-codes -MSDP = bchr(69) -MSDP_VAR = bchr(1) -MSDP_VAL = bchr(2) -MSDP_TABLE_OPEN = bchr(3) -MSDP_TABLE_CLOSE = bchr(4) +MSDP = bytes([69]) +MSDP_VAR = bytes([1]) +MSDP_VAL = bytes([2]) +MSDP_TABLE_OPEN = bytes([3]) +MSDP_TABLE_CLOSE = bytes([4]) -MSDP_ARRAY_OPEN = bchr(5) -MSDP_ARRAY_CLOSE = bchr(6) +MSDP_ARRAY_OPEN = bytes([5]) +MSDP_ARRAY_CLOSE = bytes([6]) # GMCP -GMCP = bchr(201) +GMCP = bytes([201]) # pre-compiled regexes diff --git a/evennia/server/portal/ttype.py b/evennia/server/portal/ttype.py index d74b3ae9db..e74b8e638d 100644 --- a/evennia/server/portal/ttype.py +++ b/evennia/server/portal/ttype.py @@ -10,12 +10,10 @@ etc. If the client does not support TTYPE, this will be ignored. All data will be stored on the protocol's protocol_flags dictionary, under the 'TTYPE' key. """ -from twisted.python.compat import _bytesChr as bchr - # telnet option codes -TTYPE = bchr(24) # b"\x18" -IS = bchr(0) # b"\x00" -SEND = bchr(1) # b"\x01" +TTYPE = bytes([24]) # b"\x18" +IS = bytes([0]) # b"\x00" +SEND = bytes([1]) # b"\x01" # terminal capabilities and their codes MTTS = [ From 8964c903740f3571e5680570ca58ab0b43d8b3ea Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 19 Jun 2021 15:29:15 +0200 Subject: [PATCH 13/14] Python 3.9 support. Resolves #2436. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24de2405fa..5aff3dc50c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ - Latin (la) i18n translation (jamalainm) - Made the `evennia` dir possible to use without gamedir for purpose of doc generation. +### Backports from 1.0 to 0.9.5 since 0.9.5 release + +- Fix to TaskHandler to complate api and allow manipulation of `utils.delay` + return as originall intended. +- Support for Python 3.9. + ### Evennia 0.9.5 (Nov 2020) A transitional release, including new doc system. From b80fe31d041718cedab2b6f49899548875acc50f Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 19 Jun 2021 15:57:36 +0200 Subject: [PATCH 14/14] Fix taskhandler pickling method instances. Resolves #2439 --- evennia/scripts/taskhandler.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index 3b826844a1..ac2fef9890 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -279,17 +279,24 @@ class TaskHandler(object): if not persistent: continue + safe_callback = callback if getattr(callback, "__self__", None): # `callback` is an instance method obj = callback.__self__ name = callback.__name__ - callback = (obj, name) + safe_callback = (obj, name) # Check if callback can be pickled. args and kwargs have been checked - safe_callback = None + try: + dbserialize(safe_callback) + except (TypeError, AttributeError, PickleError) as err: + raise ValueError( + "the specified callback {callback} cannot be pickled. " + "It must be a top-level function in a module or an " + "instance method ({err}).".format(callback=callback, err=err) + ) - - self.to_save[task_id] = dbserialize((date, callback, args, kwargs)) + self.to_save[task_id] = dbserialize((date, safe_callback, args, kwargs)) ServerConfig.objects.conf("delayed_tasks", self.to_save) def add(self, timedelay, callback, *args, **kwargs): @@ -337,17 +344,6 @@ class TaskHandler(object): safe_args = [] safe_kwargs = {} - # an unsaveable callback should immediately abort - try: - dbserialize(callback) - except (TypeError, AttributeError, PickleError) as err: - raise ValueError( - "the specified callback {callback} cannot be pickled. " - "It must be a top-level function in a module or an " - "instance method ({err}).".format(callback=callback, err=err) - ) - return - # Check that args and kwargs contain picklable information for arg in args: try: