diff --git a/evennia/utils/olc/__init__.py b/evennia/utils/olc/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/evennia/utils/olc/olc.py b/evennia/utils/olc/olc.py deleted file mode 100644 index 0e8754e84e..0000000000 --- a/evennia/utils/olc/olc.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -OLC - On-Line Creation - -This module is the core of the Evennia online creation helper system. -This is a resource intended for players with build privileges. - -While the OLC command can be used to start the OLC "from the top", the -system is also intended to be plugged in to enhance existing build commands -with a more menu-like building style. - -Functionality: - -- Prototype management: Allows to create and edit Prototype -dictionaries. Can store such Prototypes on the Builder Player as an Attribute -or centrally on a central store that all builders can fetch prototypes from. -- Creates a new entity either from an existing prototype or by creating the -prototype on the fly for the sake of that single object (the prototype can -then also be saved for future use). -- Recording of session, for performing a series of recorded build actions in sequence. -Stored so as to be possible to reproduce. -- Export of objects created in recording mode to a batchcode file (Immortals only). - - -""" - -from time import time -from collections import OrderedDict -from evennia.utils.evmenu import EvMenu -from evennia.commands.command import Command - - -# OLC settings -_SHOW_PROMPT = True # settings.OLC_SHOW_PROMPT -_DEFAULT_PROMPT = "" # settings.OLC_DEFAULT_PROMPT -_LEN_HISTORY = 10 # settings.OLC_HISTORY_LENGTH - - -# OLC Session - -def _new_session(): - - """ - This generates an empty olcsession structure, which is used to hold state - information in the olc but which can also be pickled. - - Returns: - olcsession (dict): An empty OLCSession. - - """ - return { - # header info - "caller": None, # the current user of this session - "modified": time(), - "db_model": None, # currently unused, ObjectDB for now - "prompt_template": _DEFAULT_PROMPT, # prompt display - "olcfields": OrderedDict(), # registered OLCFields. Order matters - "prototype_key": "", # current active prototype key - } - - -def _update_prompt(osession): - """ - Update the OLC status prompt. - - Returns: - prompt (str): The prompt based on the - prompt template, populated with - the olcsession state. - - """ - return "" - - -def search_entity(osession, query): - """ - Perform a query for a specified entity. Which type of entity is determined by the osession - state. - - Args: - query (str): This is a string, a #dbref or an extended search - - """ - pass - - - - -def display_prototype(osession): - """ - Display prototype fields according to the order of the registered olcfields. - - """ - # TODO: Simple one column display to begin with - make multi-column later - pkey = osession['prototype_key'] - outtxt = ["=== {pkey} ===".format(pkey=pkey)] - for field in osession['olcfields'].values(): - fname, flabel, fvalue = field.name, field.label, field.display() - outtxt.append(" {fieldname} ({label}): {value}".format(fieldname=fname, - label=flabel, value=fvalue)) - return '\n'.join(outtxt) - - -def display_field_value(osession, fieldname): - """ - Display info about a specific field. - """ - field = osession['olcfields'].get(fieldname, None) - if field: - return "{fieldname}: {value}".format(fieldname=field.name, value=field.display()) - - -# Access function - -from evennia.utils.olc import olc_pages -def display_obj(obj): - """ - Test of displaying object using fields and pages. - """ - olcsession = _new_session() - olcsession['caller'] = obj - page = olc_pages.OLCObjectPage(olcsession) - obj.msg(str(page)) - - - -def OLC(caller, target=None, startnode=None): - """ - This function is a common entry-point into the OLC menu system. It is used - by Evennia systems to jump into the different possible start points of the - OLC menu tree depending on what info is already available. - - Args: - caller (Object or Player): The one using the olc. - target (Object, optional): Object to operate on, if any is known. - startnode (str, optional): Where in the menu tree to start. If unset, - will be decided by whether target is given or not. - - """ - startnode = startnode or (target and "node_edit_top") or "node_top" - EvMenu(caller, "evennia.utils.olc.olc_menu", startnode=startnode, target=target) - - -class CmdOLC(Command): - """ - Test OLC - - Usage: - olc [target] - - Starts the olc to create a new object or to modify an existing one. - - """ - key = "olc" - def func(self): - OLC(self.caller, target=self.args) - diff --git a/evennia/utils/olc/olc_fields.py b/evennia/utils/olc/olc_fields.py deleted file mode 100644 index bd6217d49c..0000000000 --- a/evennia/utils/olc/olc_fields.py +++ /dev/null @@ -1,523 +0,0 @@ -""" -OLC fields describe how to edit and display a specific piece of data of a prototype within the OLC system. - -The OLC system imports and adds these field classes to its prototype manipulation pages in order to -know what data to read and how to display it. - -""" -from collections import deque -from evennia.utils.utils import to_str, to_unicode -from evennia.utils.olc import olc_utils - -# from django.conf import settings - -_OLC_VALIDATION_ERROR = """ -Error storing data in {fieldname}: - {value} -The reported error was - {error} -""" - -_LEN_HISTORY = 10 # settings.OLC_HISTORY_LENGTH - - -class InvalidActionError(RuntimeError): - """ - Raised when trying to perform a field action the field - does not support. - """ - pass - - -class ValidationError(RuntimeError): - """ - Raised when failing to validate new data being entered - into the field (from any source) - """ - pass - - -class OLCField(object): - """ - This is the parent for all OLC fields. This docstring acts - as the help text for the field. - - """ - # name of this field, for error reporting - key = "Empty field" - # if this field must have a value different than None - required = False - # used for displaying extra info in the OLC - label = "Empty field" - # initial value of field if not given - default = None - # actions available on this field. Available actions - # are replace, edit, append, remove, clear, help - actions = ['edit', 'clear', 'help'] - - def __init__(self, olcsession): - self._value_history = deque([self.default], _LEN_HISTORY) - self._history_pos = 0 - self._has_changed = False - - def __str__(self): - return to_str(self.display()) - - def __unicode__(self): - return to_unicode(self.display()) - - # perform actions - # TODO - include editor in check! - def action_edit(self, *args): - """ - Edit field value. - - Args: - newval (any): New value to add/replace with. - - Raises: - InvalidActionError: If editing is not allowed. - - """ - if args: - newval = args[0] - if 'edit' in self.actions: - self.value = newval - return - else: - newval = "" - raise InvalidActionError('Edit {value}->{newval}'.format(value=self.value, newval=newval)) - - def action_clear(self, *args): - """ - Clear field back to default. - - Returns: - default (any): The field'd default value, now set. - - Raises: - InvalidActionError: If clearing is not allowed. - - """ - if 'clear' in self.actions: - # don't validate this - object.__setattr__(self, 'value', self.default) - return self.value - raise InvalidActionError('Clear') - - def action_help(self, *args): - """ - Get the help text for the field. - - Returns: - help (str): Field help text. - - Raises: - InvalidActionError: If help is not given for this field, - either becuase it's disallowed or unset. - - """ - if 'help' not in self.actions or not self.__doc__: - raise InvalidActioNError('Help') - return self.__doc__ - - # storing data to the field in a history-aware way - @property - def value(self): - return self._value_history[self._history_pos] - - @value.setter - def value(self, value): - """ - Update field value by updating the history. - """ - original_value = value - try: - value = self.validate(value) - except Exception as err: - errtxt = _OLC_VALIDATION_ERROR.format(fieldname=self.key, value=original_value, error=err) - raise ValidationError(errtxt) - if (self._value_history and isinstance(value, (basestring, bool, int, float)) and - self._value_history[0] == value): - # don't change/update history if re-adding the same thing - return - else: - self._has_changed = True - self._history_pos = 0 - self._value_history.appendleft(value) - - @value.deleter - def value(self): - self.history_pos = 0 - self._value_history.appendleft(self.default) - - def history(self, step): - """ - Change history position. - - Args: - step (int): Step in the history stack. Positive movement - means moving futher back in history (with a maximum - of `settings.OLC_HISTORY_LENGTH`, negative steps - moves towards recent history (with 0 being the latest - value). - - """ - self._history_pos = min(len(self.value_history)-1, max(0, self._history_pos + step)) - - def has_changed(self): - """ - Check if this field has changed. - - Returns: - changed (bool): If the field changed or not. - - """ - return bool(self._has_changed) - - # overloadable methods - - def from_entity(self, entity, **kwargs): - """ - Populate this field by retrieving data from an entity. - All fields on a page will have this called, so must - be able to handle also incompatible entities. - - Args: - entity (any): An object to use for - populating this field (like an Object). - - """ - pass - - def to_prototype(self, prototype): - """ - Store this field value in a prototype. - - Args: - prototype (dict): The prototype dict - to update with the value of this field. - - """ - pass - - def validate(self, value, **kwargs): - """ - Validate/preprocess incoming data to store in this field. - - Args: - value (any): An input value to - validate - - Kwargs: - any (any): Optional info to send to field. - - Returns: - validated_value (any): The value, correctly - validated and/or processed to store in this field. - - Raises: - ValidateException: If the field was given an - invalid value to validate. - - """ - return str(value) - - def display(self): - """ - How to display the field contents in the OLC display. - - """ - return self.value - - -# OLCFields for all the standard model properties -# key, location, destination, home, aliases, -# permissions, tags, attributes ... - - -class OLCKeyField(OLCField): - """ - The name (key) of the object is its main identifier, used - throughout listings even if may not always be visible to - the end user. - """ - key = 'Name' - required = True - label = "The object's name" - - def from_entity(self, entity, **kwargs): - self.value = entity.db_key - - def to_prototype(self, prototype): - prototype['key'] = self.value - - -class OLCLocationField(OLCField): - """ - An object's location is usually a Room but could be any - other in-game entity. By convention, Rooms themselves have - a None location. Objects are otherwise only placed in a - None location to take them out of the game. - """ - key = 'Location' - required = False - label = "The object's current location" - - def validate(self, value): - return olc_utils.search_by_string(self.olcsession, value) - - def from_entity(self, entity, **kwargs): - self.value = entity.db_location - - def to_prototype(self, prototype): - prototype['location'] = self.value - - -class OLCHomeField(OLCField): - """ - An object's home location acts as a fallback when various - extreme situations occur. An example is when a location is - deleted - all its content (except exits) are then not deleted - but are moved to each object's home location. - """ - key = 'Home' - required = True - label = "The object's home location" - - def validate(self, value): - return olc_utils.search_by_string(self.olcsession, value) - - def from_entity(self, entity, **kwargs): - self.value = entity.db_home - - def to_prototype(self, prototype): - prototype['home'] = self.value - - -class OLCDestinationField(OLCField): - """ - An object's destination is usually not set unless the object - represents an exit between game locations. If set, the - destination should be set to the location you get to when - passing through this exit. - - """ - key = 'Destination' - required = False - label = "The object's (usually exit's) destination" - - def validate(self, value): - return olc_utils.search_by_string(self.olcsession, value) - - def from_entity(self, entity, **kwargs): - self.value = entity.db_destination - - def to_prototype(self, prototype): - prototype['destination'] = self.value - - -class OLCBatchField(OLCField): - """ - A field managing multiple values that can be appended to and - a given component popped out. - """ - actions = OLCField.actions + ['append', 'pop'] - - def action_append(self, value): - """ - Append a new value to this field. - - Args: - value (any): The value to append. - - """ - value = self.value - value.append(value) - self.value = value - - def action_pop(self, index=-1): - """ - Pop an element from the field. - - Args: - index (int, optional): Pop this index, otherwise pop the last - element in the field. - - Returns: - element (any or None): The popped element or None. - - """ - lst = self.value - try: - return lst.pop(int(index)) - except IndexError: - return None - - -# setting single Alias -class OLCAliasField(OLCField): - key = "Alias" - required = False - label = "An alternative name for the object" - - def from_entity(self, entity, **kwargs): - if "index" in kwargs: - self.value = entity.aliases.all()[int(kwargs)] - - def to_prototype(self, prototype): - if is_iter(prototype["aliases"]): - prototype["aliases"].append(self.value) - else: - prototype["aliases"] = [self.value] - - -# batch-setting aliases -class OLCAliasBatchField(OLCBatchField): - """ - Specify as a comma-separated list. Use quotes around the - alias if the alias itself contains a comma. - - Aliases are alternate names for an object. An alias is just - as fast to search for as a key and two objects are assumed - to have the same name is *either* their name or any of their - aliases match. - - """ - key = 'Aliases' - required = False - label = "The object's alternative name or names" - - def validate(self, value): - return olc_utils.split_by_comma(value) - - def from_entity(self, entity, **kwargs): - self.value = list(entity.aliases.all()) - - def to_prototype(self, prototype): - prototype['aliases'] = self.value - - -# setting single Tag -class OLCTagField(OLCField): - """ - Specify as tagname or tagname:category - - Tags are used to identify groups of objects for later quick retrieval. - This is very useful for anything from creating zones of rooms to - easily find all Characters belonging a given group etc. A tag can also - have a category for a second level of grouping. - - """ - key = "Tag" - required = False - label = "A single label for the object." - - def validate(self, value): - category = None - if ':' in value: - value, category = value.rsplit(':', 1) - return (value, category) - - def from_entity(self, entity, **kwargs): - if "index" in kwargs: - self.value = entity.tags.all()[int(kwargs)] - - def to_prototype(self, prototype): - if is_iter(prototype["tags"]): - prototype["tags"].append(self.value) - else: - prototype["tags"] = [self.value] - - -# batch-setting Tags -class OLCTagBatchField(OLCBatchField): - """ - Specify as a comma-separated list of tagname or tagname:category. - - Tags are used to identify groups of objects for later quick retrieval. - This is very useful for anything from creating zones of rooms to - easily find all Characters belonging a given group etc. - - """ - key = 'Tags' - required = False - label = "Attach labels to objects to group and find them." - - def validate(self, value): - if isinstance(value, basestring): - return [tuple(tagstr.split(':', 1)) if ':' in tagstr else (tagstr, None) - for tagstr in olc_utils.split_by_comma(value)] - else: - # assume a list of (key, category) - just let it pass - return value - - def from_entity(self, entity, **kwargs): - self.value = entity.tags.all(return_key_and_category=True) - - def to_prototype(self, prototype): - prototype['tags'] = self.value - - def display(self): - outstr = [] - for key, category in self.value: - outstr.append("{key}:{category}".format(key=key, category=category)) - return '\n'.join(outstr) - - -# TODO fix this to correctly handle key, value, category -# setting single Attribute -class OLCAttributeField(OLCField): - key = "Attribute" - required = False - label = "An alternative name for the object" - - def from_entity(self, entity, **kwargs): - if "index" in kwargs: - self.value = entity.attributes.all()[int(kwargs)] - - def to_prototype(self, prototype): - if is_iter(prototype["attrs"]): - prototype["attrs"].append(self.value) - else: - prototype["attrs"] = [self.value] - - -# batch-setting attributes -class OLCAttributeBatchField(OLCBatchField): - """ - Specify as a comma-separated list of attrname=value or attrname:category=value. - - Attributes are arbitrary pieces of data attached to an object. They can - contain references to other objects as well as simple Python structures such - as lists and dicts. - - """ - key = 'Attributes' - required = False - label = "Additional data attached to this object." - actions = OLCField.actions + ['append'] - - def validate(self, value): - if isinstance(value, basestring): - return [tuple(lhs.split(':', 1) + [rhs]) if ':' in lhs else (lhs, None) + (rhs, ) - for lhs, rhs in (attrstr.split('=', 1) if ':' in attrstr else ((attrstr, None),)) - for attrstr in olc_utils.split_by_comma(value)] - else: - # we assume this is a list of Attributes - return [(attr.key, attr.category, attr.value) for attr in value] - - def from_entity(self, entity, **kwargs): - self.value = entity.attributes.all() - - def to_prototype(self, prototype): - for key, category, value in self.value: - prototype['attrs'] = (key, value, category) - - def display(self): - outstr = [] - for key, category, value in self.value: - outstr.append("{key}:{category} = {value}".format(key=key, category=category, value=value)) - return '\n'.join(outstr) - - diff --git a/evennia/utils/olc/olc_menutree.py b/evennia/utils/olc/olc_menutree.py deleted file mode 100644 index a550782949..0000000000 --- a/evennia/utils/olc/olc_menutree.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -This describes the menu structure/logic of the OLC system editor, using the EvMenu subsystem. The -various nodes are modular and will when possible make use of the various utilities of the OLC rather -than hard-coding things in each node. - -Menu structure: - - start: - new object - edit object - manage prototypes - export session to batchcode file (immortals only) - - new/edit object: - Protoype - Typeclass - Key - Location - Destination - PErmissions - LOcks - Attributes - TAgs - Scripts - - create/update object - copy object - save prototype - save/delete object - update existing objects - - manage prototypes - list prototype - search prototype - import prototype (from global store) - - export session - -""" - -def node_top(caller, raw_input): - # top level node - # links to edit, manage, export - text = """OnLine Creation System""" - options = ({"key": ("|yN|new", "new", "n"), - "desc": "New object", - "goto": "node_new_top", - "exec": _obj_to_prototype}, - {"key": ("|yE|ndit", "edit", "e", "m"), - "desc": "Edit existing object", - "goto": "node_edit_top", - "exec": _obj_to_prototype}, - {"key": ("|yP|nrototype", "prototype", "manage", "p", "m"), - "desc": "Manage prototypes", - "goto": "node_prototype_top"}, - {"key": ("E|yx|nport", "export", "x"), - "desc": "Export to prototypes", - "goto": "node_prototype_top"}, - {"key": ("|yQ|nuit", "quit", "q"), - "desc": "Quit OLC", - "goto": "node_quit"},) - return text, options - -def node_quit(caller, raw_input): - return 'Exiting.', None - -def node_new_top(caller, raw_input): - pass - -def node_edit_top(caller, raw_input): - # edit top level - text = """Edit object""" - - -def node_prototype_top(caller, raw_input): - # manage prototypes - pass - - -def node_export_top(caller, raw_input): - # export top level - pass - diff --git a/evennia/utils/olc/olc_utils.py b/evennia/utils/olc/olc_utils.py deleted file mode 100644 index 68bfd3ac9d..0000000000 --- a/evennia/utils/olc/olc_utils.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -Miscellaneous utilities for the OLC system. - -""" -import csv - - -def search_by_string(olcsession, query): - pass - - -def split_by_comma(string): - return csv.reader([string], skipinitialspace=True)