mirror of
https://github.com/evennia/evennia.git
synced 2026-03-29 20:17:16 +02:00
OBS - there is a new data table (for the persistent cache) so you need to sync or restart with your database. * Persistent cache (pcache)- this works the same as the volatile cache, except it is regularly saved to disk and recovered upon restart. How often the pcache is backed up is set in preferences. This was heck of a tricky thing to get right due to the intricacies of pickle; for example it turns out there is a bug in cPickle, so only normal pickle works to store the cache objects. * Persistent events - this makes use of the pcache to re-load the scheduled events every reload. Only events with the property "persistent" will be saved this way (if not set, events will get lost upon reboot, just like now). All the main system events have been implemented as persistent events, including a new event to regularly save the pcache to disk. * In order to track persistent event timers across reboots, there is also a global "game time" defined now. This is saved in cache and counts seconds only when the server is running. Event timers are adjusted with an offset when restarting (otherwise they will be confused by the real time jumping forward after a downtime). There are also a small set of helpful routines in src/gametime.py to help convert from real time to game time (for easy creation of new events). * Various info commands have been updated to incoorporate the time stamp and the cache sync information. * There are a few test commands commented out in commands/general.py that I used for testing; I left them in if you want to test things quickly. It works here, but as always more people testing is needed. /Griatch
97 lines
3.3 KiB
Python
97 lines
3.3 KiB
Python
"""
|
|
This file contains the event scheduler system.
|
|
|
|
ADDING AN EVENT:
|
|
* Create an event sub-class from the IntervalEvent class in events.py.
|
|
* Call src.scheduler.add_event() with your IntervalEvent subclass as the arg.
|
|
* Make sure that the module where your add_event() call resides is either
|
|
imported, or that add_event() is called by a command or some kind of action.
|
|
* Profit.
|
|
"""
|
|
from src.cache import cache
|
|
CACHE_NAME = "_persistent_event_cache"
|
|
|
|
# dict of IntervalEvent sub-classed objects, keyed by their
|
|
# process id:s.
|
|
SCHEDULE = []
|
|
|
|
def next_free_pid():
|
|
"""
|
|
Find the next free pid
|
|
"""
|
|
pids = [event.pid for event in SCHEDULE]
|
|
if not pids:
|
|
return 0
|
|
maxpid = max(pids)
|
|
freepids = [pid for pid in xrange(maxpid+1) if pid not in pids]
|
|
if freepids:
|
|
return min(freepids)
|
|
return maxpid + 1
|
|
|
|
def add_event(event):
|
|
"""
|
|
Adds an event instance to the scheduled event list. Call this any time you
|
|
need to add a custom event to the global scheduler.
|
|
|
|
Args:
|
|
* event: (IntervalEvent) The event to add to the scheduler.
|
|
Returns:
|
|
* pid : (int) The process ID assigned to this event, for future reference.
|
|
"""
|
|
# Make sure not to add multiple instances of the same event.
|
|
matches = [i for i, stored_event in enumerate(SCHEDULE)
|
|
if event == stored_event]
|
|
if matches:
|
|
#print "replacing existing event pid=%i: %s" % (event.pid, event.name)
|
|
# Before replacing an event, stop its old incarnation.
|
|
del_event(matches[0])
|
|
SCHEDULE[matches[0]] = event
|
|
else:
|
|
# Add a new event with a fresh pid.
|
|
event.pid = next_free_pid()
|
|
#print "adding new event with fresh pid=%i: %s" % (event.pid,event.name)
|
|
SCHEDULE.append(event)
|
|
event.start_event_loop()
|
|
|
|
if event.persistent:
|
|
# We have to sync to disk, otherwise we might end up
|
|
# in situations (such as after a crash) where an object exists,
|
|
# but the event tied to it does not.
|
|
ecache = [event for event in SCHEDULE if event.persistent]
|
|
cache.set_pcache("_persistent_event_cache", ecache)
|
|
cache.save_pcache()
|
|
|
|
return event.pid
|
|
|
|
def get_event(pid):
|
|
"""
|
|
Return an event with the given pid, if it exists,
|
|
otherwise return None.
|
|
"""
|
|
pid = int(pid)
|
|
imatches = [i for i, stored_event in enumerate(SCHEDULE)
|
|
if stored_event.pid == pid]
|
|
if imatches:
|
|
return SCHEDULE[imatches[0]]
|
|
|
|
def del_event(pid):
|
|
"""
|
|
Remove an event from scheduler. There should never be more than one
|
|
event with a certain pid, this cleans up in case there are any multiples.
|
|
"""
|
|
pid = int(pid)
|
|
imatches = [i for i, stored_event in enumerate(SCHEDULE)
|
|
if stored_event.pid == pid]
|
|
for imatch in imatches:
|
|
event = SCHEDULE[imatch]
|
|
event.stop_event_loop()
|
|
del SCHEDULE[imatch]
|
|
|
|
if event.persistent:
|
|
# We have to sync to disk, otherwise we might end
|
|
# up in situations (such as after a crash) where an
|
|
# object has been removed, but the event tied to it remains.
|
|
ecache = [event for event in SCHEDULE
|
|
if event.persistent]
|
|
cache.set_pcache("_persistent_event_cache", ecache)
|
|
cache.save_pcache()
|