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.
"""
from datetime import datetime
from django.conf import settings
from evennia import Command
from evennia.contrib.events.extend import get_event_handler
from evennia.utils.eveditor import EvEditor
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)
# Permissions
@ -120,81 +124,203 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
lock = "perm({}) or perm(events_validating)".format(VALIDATING)
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.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:
caller.msg("The event handler is not running, can't " \
"access the event system.")
return
# Before the equal sign is always an object name
obj = None
if self.args.strip():
obj = caller.search(self.lhs)
if not obj:
self.obj = caller.search(self.lhs)
if not self.obj:
return
# Switches are mutually exclusive
switch = self.switches and self.switches[0] or ""
if switch == "":
if not obj:
if not self.obj:
caller.msg("Specify an object's name or #ID.")
return
self.list_events(obj)
self.list_events()
elif switch == "add":
if not obj:
if not self.obj:
caller.msg("Specify an object's name or #ID.")
return
self.add_event(obj)
self.add_event()
elif switch == "edit":
if not obj:
if not self.obj:
caller.msg("Specify an object's name or #ID.")
return
self.edit_event(obj)
self.edit_event()
elif switch == "del":
if not obj:
if not self.obj:
caller.msg("Specify an object's name or #ID.")
return
self.del_event(obj)
self.del_event()
elif switch == "accept" and validator:
self.accept_event(obj)
self.accept_event()
else:
caller.msg("Mutually exclusive or invalid switches were " \
"used, cannot proceed.")
def list_events(self, obj):
def list_events(self):
"""Display the list of events connected to the object."""
obj = self.obj
event_name = self.event_name
events = self.handler.get_events(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")
table.reformat_column(2, align="r")
self.msg(table)
if event_name:
# Check that the event name can be found in this object
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."""
self.msg("Calling add.")
obj = self.obj
event_name = self.event_name
types = self.handler.get_event_types(obj)
def edit_event(self, obj):
"""Add an event."""
self.msg("Calling edit.")
# Check that the event exists
if not event_name in types:
self.msg("The event name {} can't be found in {} of " \
"typeclass {}.".format(event_name, obj, type(obj)))
return
def del_event(self, obj):
"""Add an event."""
definition = types[event_name]
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.")
def accept_event(self, obj):
"""Add an event."""
def accept_event(self):
"""Accept an event."""
obj = self.obj
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 logger
from evennia.contrib.events.exceptions import InterruptEvent
from evennia.contrib.events.extend import patch_hooks
from evennia.contrib.events import typeclasses
from evennia.utils.utils import all_from_module
class EventHandler(DefaultScript):
@ -60,7 +62,7 @@ class EventHandler(DefaultScript):
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.
@ -92,6 +94,46 @@ class EventHandler(DefaultScript):
"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):
"""
Call the event.
@ -115,7 +157,7 @@ class EventHandler(DefaultScript):
return False
# Prepare the locals
locals = {}
locals = all_from_module("evennia.contrib.events.helpers")
for i, variable in enumerate(event_type[0]):
try:
locals[variable] = args[i]
@ -131,4 +173,9 @@ class EventHandler(DefaultScript):
if not event["valid"]:
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):
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)
if not allow:
return
hook(exit, traversing_object, target_location)
# Default events
create_event_type(DefaultExit, "at_traverse", ["character", "exit", "room"],
"""When traversing""")
create_event_type(DefaultExit, "can_traverse", ["character", "exit", "room"],
"""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.""")