Add the /add and /edit switches to the @event command

This commit is contained in:
Vincent Le Goff 2017-03-12 19:26:19 -07:00 committed by Griatch
parent 0d7b1cb2be
commit 4bdee14adb
3 changed files with 222 additions and 41 deletions

View file

@ -2,12 +2,16 @@
Module containing the commands of the event system. Module containing the commands of the event system.
""" """
from datetime import datetime
from django.conf import settings from django.conf import settings
from evennia import Command from evennia import Command
from evennia.contrib.events.extend import get_event_handler from evennia.contrib.events.extend import get_event_handler
from evennia.utils.eveditor import EvEditor
from evennia.utils.evtable import EvTable from evennia.utils.evtable import EvTable
from evennia.utils.utils import class_from_module from evennia.utils.utils import class_from_module, time_format
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
# Permissions # Permissions
@ -120,81 +124,203 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
lock = "perm({}) or perm(events_validating)".format(VALIDATING) lock = "perm({}) or perm(events_validating)".format(VALIDATING)
validator = caller.locks.check_lockstring(caller, lock) validator = caller.locks.check_lockstring(caller, lock)
# First and foremost, get the event handler # First and foremost, get the event handler and set other variables
self.handler = get_event_handler() self.handler = get_event_handler()
self.obj = None
rhs = self.rhs or ""
self.event_name, sep, self.parameters = rhs.partition(" ")
self.event_name = self.event_name.lower()
self.is_validator = validator
if self.handler is None: if self.handler is None:
caller.msg("The event handler is not running, can't " \ caller.msg("The event handler is not running, can't " \
"access the event system.") "access the event system.")
return return
# Before the equal sign is always an object name # Before the equal sign is always an object name
obj = None
if self.args.strip(): if self.args.strip():
obj = caller.search(self.lhs) self.obj = caller.search(self.lhs)
if not obj: if not self.obj:
return return
# Switches are mutually exclusive # Switches are mutually exclusive
switch = self.switches and self.switches[0] or "" switch = self.switches and self.switches[0] or ""
if switch == "": if switch == "":
if not obj: if not self.obj:
caller.msg("Specify an object's name or #ID.") caller.msg("Specify an object's name or #ID.")
return return
self.list_events(obj) self.list_events()
elif switch == "add": elif switch == "add":
if not obj: if not self.obj:
caller.msg("Specify an object's name or #ID.") caller.msg("Specify an object's name or #ID.")
return return
self.add_event(obj) self.add_event()
elif switch == "edit": elif switch == "edit":
if not obj: if not self.obj:
caller.msg("Specify an object's name or #ID.") caller.msg("Specify an object's name or #ID.")
return return
self.edit_event(obj) self.edit_event()
elif switch == "del": elif switch == "del":
if not obj: if not self.obj:
caller.msg("Specify an object's name or #ID.") caller.msg("Specify an object's name or #ID.")
return return
self.del_event(obj) self.del_event()
elif switch == "accept" and validator: elif switch == "accept" and validator:
self.accept_event(obj) self.accept_event()
else: else:
caller.msg("Mutually exclusive or invalid switches were " \ caller.msg("Mutually exclusive or invalid switches were " \
"used, cannot proceed.") "used, cannot proceed.")
def list_events(self, obj): def list_events(self):
"""Display the list of events connected to the object.""" """Display the list of events connected to the object."""
obj = self.obj
event_name = self.event_name
events = self.handler.get_events(obj) events = self.handler.get_events(obj)
types = self.handler.get_event_types(obj) types = self.handler.get_event_types(obj)
table = EvTable("Event name", "Number", "Lines", "Description",
width=78)
for name, infos in sorted(types.items()):
number = len(events.get(name, []))
lines = sum(len(e["code"].splitlines()) for e in \
events.get(name, []))
description = infos[1].splitlines()[0]
table.add_row(name, number, lines, description)
table.reformat_column(1, align="r") if event_name:
table.reformat_column(2, align="r") # Check that the event name can be found in this object
self.msg(table) created = events.get(event_name)
if created is None:
self.msg("No event {} has been set on {}.".format(event_name, obj))
return
def add_event(self, obj): # Create the table
cols = ["Number", "Author", "Updated"]
if self.is_validator:
cols.append("Valid")
table = EvTable(*cols, width=78)
now = datetime.now()
for i, event in enumerate(created):
author = event.get("author")
author = author.key if author else "|gUnknown|n"
updated_on = event.get("updated_on")
if updated_on is None:
updated_on = event.get("created_on")
if updated_on:
updated_on = time_format(
(now - updated_on).total_seconds(), 1)
else:
updated_on = "|gUnknown|n"
row = [str(i + 1), author, updated_on]
if self.is_validator:
row.append("Yes" if event.get("valid") else "no")
table.add_row(*row)
table.reformat_column(0, align="r")
self.msg(table)
else:
table = EvTable("Event name", "Number", "Lines", "Description",
width=78)
for name, infos in sorted(types.items()):
number = len(events.get(name, []))
lines = sum(len(e["code"].splitlines()) for e in \
events.get(name, []))
description = infos[1].splitlines()[0]
table.add_row(name, number, lines, description)
table.reformat_column(1, align="r")
table.reformat_column(2, align="r")
self.msg(table)
def add_event(self):
"""Add an event.""" """Add an event."""
self.msg("Calling add.") obj = self.obj
event_name = self.event_name
types = self.handler.get_event_types(obj)
def edit_event(self, obj): # Check that the event exists
"""Add an event.""" if not event_name in types:
self.msg("Calling edit.") self.msg("The event name {} can't be found in {} of " \
"typeclass {}.".format(event_name, obj, type(obj)))
return
def del_event(self, obj): definition = types[event_name]
"""Add an event.""" description = definition[1]
self.msg(description)
# Open the editor
event = self.handler.add_event(obj, event_name, "",
self.caller, False)
self.caller.db._event = event
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Event {} of {}".format(
event_name, obj), persistent=True, codefunc=_ev_save)
def edit_event(self):
"""Edit an event."""
obj = self.obj
event_name = self.event_name
parameters = self.parameters
events = self.handler.get_events(obj)
types = self.handler.get_event_types(obj)
# Check that the event exists
if not event_name in events:
self.msg("The event name {} can't be found in {}.".format(
event_name, obj))
return
# Check that the parameter points to an existing event
try:
parameters = int(parameters) - 1
assert parameters >= 0
event = events[event_name][parameters]
except (AssertionError, ValueError):
self.msg("The event {} {} cannot be found in {}.".format(
event_name, parameters, obj))
return
definition = types[event_name]
description = definition[1]
self.msg(description)
# Open the editor
event = dict(event)
event["obj"] = obj
event["name"] = event_name
event["number"] = parameters
self.caller.db._event = event
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Event {} of {}".format(
event_name, obj), persistent=True, codefunc=_ev_save)
def del_event(self):
"""Delete an event."""
obj = self.obj
self.msg("Calling del.") self.msg("Calling del.")
def accept_event(self, obj): def accept_event(self):
"""Add an event.""" """Accept an event."""
obj = self.obj
self.msg("Calling accept.") self.msg("Calling accept.")
# Private functions to handle editing
def _ev_load(caller):
return caller.db._event and caller.db._event.get("code", "") or ""
def _ev_save(caller, buf):
"""Save and add the event."""
lock = "perm({}) or perm(events_without_validation)".format(
WITHOUT_VALIDATION)
autovalid = caller.locks.check_lockstring(caller, lock)
event = caller.db._event
handler = get_event_handler()
if not handler or not event or not all(key in event for key in \
("obj", "name", "number", "valid")):
caller.msg("Couldn't save this event.")
return False
handler.edit_event(event["obj"], event["name"], event["number"], buf,
caller, valid=autovalid)
return True
def _ev_quit(caller):
del caller.db._event
caller.msg("Exited the code editor.")

View file

@ -7,8 +7,10 @@ from Queue import Queue
from evennia import DefaultScript from evennia import DefaultScript
from evennia import logger from evennia import logger
from evennia.contrib.events.exceptions import InterruptEvent
from evennia.contrib.events.extend import patch_hooks from evennia.contrib.events.extend import patch_hooks
from evennia.contrib.events import typeclasses from evennia.contrib.events import typeclasses
from evennia.utils.utils import all_from_module
class EventHandler(DefaultScript): class EventHandler(DefaultScript):
@ -60,7 +62,7 @@ class EventHandler(DefaultScript):
return types return types
def add_event(self, obj, event_name, code, author=None, valid=True): def add_event(self, obj, event_name, code, author=None, valid=False):
""" """
Add the specified event. Add the specified event.
@ -92,6 +94,46 @@ class EventHandler(DefaultScript):
"code": code, "code": code,
}) })
definition = dict(events[-1])
definition["obj"] = obj
definition["name"] = event_name
definition["number"] = len(events) - 1
return definition
def edit_event(self, obj, event_name, number, code, author=None,
valid=False):
"""
Edit the specified event.
Args:
obj (Object): the Evennia typeclassed object to be modified.
event_name (str): the name of the event to add.
number (int): the event number to be changed.
code (str): the Python code associated with this event.
author (optional, Character, Player): the author of the event.
valid (optional, bool): should the event be connected?
This method doesn't check that the event type exists.
"""
obj_events = self.db.events.get(obj, {})
if not obj_events:
self.db.events[obj] = {}
obj_events = self.db.events[obj]
events = obj_events.get(event_name, [])
if not events:
obj_events[event_name] = []
events = obj_events[event_name]
# Edit the event
events[number].update({
"updated_on": datetime.now(),
"updated_by": author,
"valid": valid,
"code": code,
})
def call_event(self, obj, event_name, *args): def call_event(self, obj, event_name, *args):
""" """
Call the event. Call the event.
@ -115,7 +157,7 @@ class EventHandler(DefaultScript):
return False return False
# Prepare the locals # Prepare the locals
locals = {} locals = all_from_module("evennia.contrib.events.helpers")
for i, variable in enumerate(event_type[0]): for i, variable in enumerate(event_type[0]):
try: try:
locals[variable] = args[i] locals[variable] = args[i]
@ -131,4 +173,9 @@ class EventHandler(DefaultScript):
if not event["valid"]: if not event["valid"]:
continue continue
exec(event["code"], locals, locals) try:
exec(event["code"], locals, locals)
except InterruptEvent:
return False
return True

View file

@ -30,11 +30,19 @@ class PatchedExit(object):
""" """
if inherits_from(traversing_object, DefaultCharacter): if inherits_from(traversing_object, DefaultCharacter):
script = ScriptDB.objects.get(db_key="event_handler") script = ScriptDB.objects.get(db_key="event_handler")
script.call_event(exit, "at_traverse", traversing_object, allow = script.call_event(exit, "can_traverse", traversing_object,
exit, exit.location) exit, exit.location)
if not allow:
return
hook(exit, traversing_object, target_location) hook(exit, traversing_object, target_location)
# Default events # Default events
create_event_type(DefaultExit, "at_traverse", ["character", "exit", "room"], create_event_type(DefaultExit, "can_traverse", ["character", "exit", "room"],
"""When traversing""") """Can the character traverse through this exit?
This event is called when a character is about to traverse this
exit. You can use the deny() function to deny the character from
using this exit for the time being. The 'character' variable
contains the character who wants to traverse through this exit.
The 'exit' variable contains the exit, the 'room' variable
contains the room in which the character and exit are.""")