Add the script/functions to schedule events with a standard calendar

This commit is contained in:
Vincent Le Goff 2017-02-14 17:28:55 -08:00 committed by Griatch
parent c18bfe7388
commit 7cd7d68a5a

View file

@ -7,7 +7,11 @@ total runtime of the server and the current uptime.
""" """
from __future__ import division from __future__ import division
import time import time
from calendar import monthrange
from datetime import datetime, timedelta
from django.conf import settings from django.conf import settings
from evennia import DefaultScript
from evennia.server.models import ServerConfig from evennia.server.models import ServerConfig
# Speed-up factor of the in-game time compared # Speed-up factor of the in-game time compared
@ -107,6 +111,106 @@ def gametime(absolute=False):
gtime = epoch + (runtime() - GAME_TIME_OFFSET) * TIMEFACTOR gtime = epoch + (runtime() - GAME_TIME_OFFSET) * TIMEFACTOR
return gtime return gtime
def real_seconds_until(sec=None, min=None, hour=None, day=None,
month=None, year=None):
"""
Return the real seconds until game time.
If the game time is 5:00, TIME_FACTOR is set to 2 and you ask
the number of seconds until it's 5:10, then this function should
return 300 (5 minutes).
Args:
sec (int or None): number of absolute seconds.
min (int or None): number of absolute minutes.
hour (int or None): number of absolute hours.
day (int or None): number of absolute days.
month (int or None): number of absolute months.
year (int or None): number of absolute years.
Example:
real_seconds_until(hour=5, min=10, sec=0)
Returns:
The number of real seconds before the given game time is up.
"""
current = datetime.frmtimestamp(gametime(absolute=True))
s_sec = year if year is not None else current.second
s_min = min if min is not None else current.minute
s_hour = hour if hour is not None else current.hour
s_day = day if day is not None else current.day
s_month = month if month is not None else current.month
s_year = year if year is not None else current.year
projected = datetime(s_year, s_month, s_day, s_hour, s_min, s_sec)
if projected <= current:
# We increase one unit of time depending on parameters
days_in_month = monthrange(s_year, s_month)[1]
days_in_year = sum(monthrange(s_year, m + 1)[1] for m in range(12))
if month is not None:
projected += timedelta(days=days_in_year)
elif day is not None:
projected += timedelta(days=days_in_month)
elif hour is not None:
projected += timedelta(days=1)
elif min is not None:
projected += timedelta(seconds=3600)
else:
projected += timedelta(seconds=60)
# Get the number of gametime seconds between these two dates
print "Asked", current, projected
seconds = (projected - current).total_seconds()
print "Found", seconds
return seconds / TIMEFACTOR
def schedule(callback, repeat=False, sec=None, min=None, hour=None,
day=None, month=None, year=None):
"""
Call the callback when the game time is up.
This function will setup a script that will be called when the
time corresponds to the game time. If `repeat` is set to True,
the callback will be called again next time the game time matches
the given time. The time is given in units as keyword arguments.
For instance:
>>> schedule(func, min=5, sec=0) # Will call next hour at :05.
>>> schedule(func, hour=2, min=30, sec=0) # Will call the next day at 02:30.
Args:
callback (function): the callback function that will be called [1].
repeat (bool, optional): should the callback be called regularly?
sec (int or None): number of absolute seconds.
min (int or None): number of absolute minutes.
hour (int or None): number of absolute hours.
day (int or None): number of absolute days.
month (int or None): number of absolute months.
year (int or None): number of absolute years.
[1] The callback must be a top-level function, since the script will
be persistent.
Returns:
The created script (Script).
"""
seconds = real_seconds_until(sec=sec, min=min, hour=hour, day=day,
month=month, year=year)
script = create_script("evennia.utils.gametime.GametimeScript",
key="GametimeScript", desc="A gametime-sensitive script",
interval=seconds, start_delay=True,
repeats=-1 if repeat else 1)
script.db.callback = callback
script.db.gametime = {
"sec": sec,
"min": min,
"hour": hour,
"day": day,
"month": month,
"year": year,
}
return script
def reset_gametime(): def reset_gametime():
""" """
@ -117,3 +221,25 @@ def reset_gametime():
global GAME_TIME_OFFSET global GAME_TIME_OFFSET
GAME_TIME_OFFSET = runtime() GAME_TIME_OFFSET = runtime()
ServerConfig.objects.conf("gametime_offset", GAME_TIME_OFFSET) ServerConfig.objects.conf("gametime_offset", GAME_TIME_OFFSET)
# Scripts dealing in gametime (use `schedule` to create it)
class GametimeScript(DefaultScript):
"""Gametime-sensitive script."""
def at_script_creation(self):
"""The script is created."""
self.key = "unknown scr"
self.interval = 100
self.start_delay = True
self.persistent = True
def at_repeat(self):
"""Call the callback and reset interval."""
callback = self.db.callback
if callback:
callback()
seconds = real_seconds_until(**self.db.gametime)
self.restart(interval=seconds)