diff --git a/src/commands/default/system.py b/src/commands/default/system.py index f4958156e9..a56bbae76e 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -215,7 +215,7 @@ def format_script_list(scripts): if not scripts: return "" - table = prettytable.PrettyTable(["{wid", + table = prettytable.PrettyTable(["{wdbref", "{wobj", "{wkey", "{wintval", @@ -245,7 +245,7 @@ class CmdScripts(MuxCommand): Operate and list global scripts, list all scrips. Usage: - @scripts[/switches] [] + @scripts[/switches] [#dbref, key, script.path or ] Switches: start - start a script (must supply a script path) @@ -256,7 +256,7 @@ class CmdScripts(MuxCommand): If no switches are given, this command just views all active scripts. The argument can be either an object, at which point it will be searched for all scripts defined on it, or an script name - or dbref. For using the /stop switch, a unique script dbref is + or #dbref. For using the /stop switch, a unique script #dbref is required since whole classes of scripts often have the same name. Use @script for managing commands on objects. @@ -287,7 +287,7 @@ class CmdScripts(MuxCommand): scripts = ScriptDB.objects.get_all_scripts(key=args) if not scripts: # try to find an object instead. - objects = ObjectDB.objects.object_search(args, caller=caller) + objects = ObjectDB.objects.object_search(args) if objects: scripts = [] for obj in objects: @@ -608,9 +608,9 @@ class CmdTime(MuxCommand): "Show server time data in a table." table = prettytable.PrettyTable(["{wserver time statistic","{wtime"]) table.align = 'l' - table.add_row(["Current server uptime", utils.time_format(time.time() - SESSIONS.server.start_time, 3)]) - table.add_row(["Total server running time", utils.time_format(gametime.runtime(format=False), 2)]) - table.add_row(["Total in-game time (realtime x %g" % (gametime.TIMEFACTOR), utils.time_format(gametime.gametime(format=False), 2)]) + table.add_row(["Current server uptime", utils.time_format(gametime.uptime(), 3)]) + table.add_row(["Total server running time", utils.time_format(gametime.runtime(), 2)]) + table.add_row(["Total in-game time (realtime x %g" % (gametime.TIMEFACTOR), utils.time_format(gametime.gametime(), 2)]) table.add_row(["Server time stamp", datetime.datetime.now()]) self.caller.msg(str(table)) diff --git a/src/scripts/manager.py b/src/scripts/manager.py index 5bc41487cb..4735a8eb1a 100644 --- a/src/scripts/manager.py +++ b/src/scripts/manager.py @@ -65,8 +65,8 @@ class ScriptManager(TypedObjectManager): if dbref or dbref == 0: script = self.dbref_search(dbref) if not script: - scripts = self.filter(db_key=key) - return scripts + script = self.filter(db_key=key) + return script return self.all() def delete_script(self, dbref): diff --git a/src/server/server.py b/src/server/server.py index 4efd303c12..42c3dde545 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -336,6 +336,10 @@ class Evennia(object): if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_cold_stop() + # stopping time + from src.utils import gametime + gametime.save() + if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_stop() # if _reactor_stopping is true, reactor does not need to diff --git a/src/settings_default.py b/src/settings_default.py index d50a3cfbee..b7a40ea0f8 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -293,14 +293,12 @@ BASE_BATCHPROCESS_PATHS = ['game.gamesrc.world', 'contrib'] # You don't actually have to use this, but it affects the routines in # src.utils.gametime.py and allows for a convenient measure to -# determine the current in-game time. You can of course read "week", -# "month" etc as your own in-game time units as desired. +# determine the current in-game time. You can of course interpret +# "week", "month" etc as your own in-game time units as desired. #The time factor dictates if the game world runs faster (timefactor>1) # or slower (timefactor<1) than the real world. TIME_FACTOR = 2.0 -# The tick is the smallest unit of time in the game. Smallest value is 1s. -TIME_TICK = 1.0 # These measures might or might not make sense to your game world. TIME_SEC_PER_MIN = 60 TIME_MIN_PER_HOUR = 60 @@ -308,8 +306,6 @@ TIME_HOUR_PER_DAY = 24 TIME_DAY_PER_WEEK = 7 TIME_WEEK_PER_MONTH = 4 TIME_MONTH_PER_YEAR = 12 -# How often the game time is updated -TIME_UPDATE_INTERVAL = 60 ###################################################################### # Default Player setup and access diff --git a/src/utils/gametime.py b/src/utils/gametime.py index a63d4219f5..97235cae55 100644 --- a/src/utils/gametime.py +++ b/src/utils/gametime.py @@ -6,37 +6,28 @@ in-mud time and real-world time as well allows to get the total runtime of the server and the current uptime. """ +from time import time from django.conf import settings from src.scripts.scripts import Script -from src.scripts.models import ScriptDB from src.utils.create import create_script -from src.utils import logger -# name of script that keeps track of the time - -GAME_TIME_SCRIPT = "sys_game_time" +GAMETIME_SCRIPT_NAME = "sys_game_time" # Speed-up factor of the in-game time compared # to real time. TIMEFACTOR = settings.TIME_FACTOR -# How often this script runs and updates the game time +# Common real-life time measure, in seconds. +# You should not change this. -UPDATE_INTERVAL = settings.TIME_UPDATE_INTERVAL - -# Common real-life time measures, in seconds. -# You should not change these. - -REAL_TICK = max(1.0, settings.TIME_TICK) # Smallest time unit (min 1s) REAL_MIN = 60.0 # seconds per minute in real world # Game-time units, in real-life seconds. These are supplied as # a convenient measure for determining the current in-game time, -# e.g. when defining events. The words month, week and year can -# of course mean whatever units of time are used in the game. +# e.g. when defining in-game events. The words month, week and year can +# be used to mean whatever units of time are used in the game. -TICK = REAL_TICK * TIMEFACTOR MIN = settings.TIME_SEC_PER_MIN HOUR = MIN * settings.TIME_MIN_PER_HOUR DAY = HOUR * settings.TIME_HOUR_PER_DAY @@ -44,22 +35,25 @@ WEEK = DAY * settings.TIME_DAY_PER_WEEK MONTH = WEEK * settings.TIME_WEEK_PER_MONTH YEAR = MONTH * settings.TIME_MONTH_PER_YEAR +# Cached time stamps +SERVER_STARTTIME = time() +SERVER_RUNTIME = 0.0 + class GameTime(Script): """ - This sets up an script that keeps track of the - in-game time and some other time units. + This script repeatedly saves server times so + it can be retrieved after server downtime. """ def at_script_creation(self): """ Setup the script """ - self.key = "sys_game_time" + self.key = GAMETIME_SCRIPT_NAME self.desc = "Keeps track of the game time" - self.interval = UPDATE_INTERVAL + self.interval = 60 self.persistent = True self.start_delay = True - self.attributes.add("game_time", 0.0) # IC time self.attributes.add("run_time", 0.0) # OOC time self.attributes.add("up_time", 0.0) # OOC time @@ -67,130 +61,78 @@ class GameTime(Script): """ Called every minute to update the timers. """ - # We store values as floats to avoid drift over time - game_time = float(self.attributes.get("game_time")) - run_time = float(self.attributes.get("run_time")) - up_time = float(self.attributes.get("up_time")) - self.attributes.add("game_time", game_time + UPDATE_INTERVAL * TIMEFACTOR) - self.attributes.add("run_time", run_time + UPDATE_INTERVAL) - self.attributes.add("up_time", up_time + UPDATE_INTERVAL) + self.attributes.add("run_time", runtime()) + self.attributes.add("up_time", uptime()) def at_start(self): """ This is called once every server restart. - We reset the up time. + We reset the up time and load the relevant + times. """ - self.attributes.add("up_time", 0.0) - self.interval = UPDATE_INTERVAL + global SERVER_RUNTIME + SERVER_RUNTIME = self.attributes.get("run_time") +def save(): + "Force save of time. This is called by server when shutting down/reloading." + from src.scripts.models import ScriptDB + try: + script = ScriptDB.objects.get(db_key=GAMETIME_SCRIPT_NAME) + script.at_repeat() + except Exception: + from src.utils import logger + logger.log_trace() -# Access routines - -def format(seconds, divisors, modify_seconds=True): +def _format(seconds, *divisors) : """ - Takes a list of divisors by which to divide the seconds, also passed - in, by. The result of each division will be returned in the order it - was performed, starting from the beginning of the divisors list. + Helper function. Creates a tuple of even dividends given + a range of divisors. - The default behavior is to, after first dividing the number of seconds - by the divisor, mod the seconds by the divisor and, at the very end, - return the left over seconds by appending to the list. When passed a - list of divisors such as [31536000, 2628000, 604800, 86400, 3600, 60] - this results in the years, months, weeks, days, hours, minutes, and - seconds that have passed, according to ths seconds value passed in, - being returned via tuple. + Inputs + seconds - number of seconds to format + *divisors - a number of integer dividends. The number of seconds will be + integer-divided by the first number in this sequence, the remainder + will be divided with the second and so on. + Output: + A tuple of length len(*args)+1, with the last element being the last remaining + seconds not evenly divided by the supplied dividends. - If modify_seconds=False then the order the divisors are passed in - have no meaning other than placement in the results set and there is - no remainder to append to the end of the results. """ results = [] + seconds = int(seconds) for divisor in divisors: results.append(seconds / divisor) - if modify_seconds: - seconds = seconds % divisor - if modify_seconds: - results.append(seconds) + seconds %= divisor + results.append(seconds) return tuple(results) -def gametime_format(seconds): - """ - Converts the count in seconds into an integer tuple of the form - (years, months, weeks, days, hours, minutes, seconds) where - several of the entries may be 0. - - We want to keep a separate version of this (rather than just - rescale the real time once and use the normal realtime_format - below) since the admin might for example decide to change how many - hours a 'day' is in their game etc. - """ - return format(seconds, [YEAR, MONTH, WEEK, DAY, HOUR, MIN]) - - -def realtime_format(seconds): - """ - As gametime format, but with real time units - """ - return format(seconds, [31536000, 2628000, 604800, 86400, 3600, 60]) - - -def gametime(format=False): - """ - Find the current in-game time (in seconds) since the start of the mud. - The value returned from this function can be used to track the 'true' - in-game time since only the time the game has actually been active will - be adding up (ignoring downtimes). - - format - instead of returning result in seconds, format to (game-) time - units. - """ - try: - script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0] - except (KeyError, IndexError): - logger.log_trace("GameTime script not found.") - return - # we return this as an integer (second-precision is good enough) - game_time = int(script.attributes.get("game_time")) - if format: - return gametime_format(game_time) - return game_time - +# Access functions def runtime(format=False): - """ - Get the total actual time the server has been running (minus downtimes) - """ - try: - script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0] - except (KeyError, IndexError): - logger.log_trace("GameTime script not found.") - return - # we return this as an integer (second-precision is good enough) - run_time = int(script.attributes.get("run_time")) + "Get the total runtime of the server since first start (minus downtimes)" + runtime = SERVER_RUNTIME + (time() - SERVER_STARTTIME) if format: - return realtime_format(run_time) - return run_time - + return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60) + return runtime def uptime(format=False): - """ - Get the actual time the server has been running since last downtime. - """ - try: - script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0] - except (KeyError, IndexError): - logger.log_trace("GameTime script not found.") - return - # we return this as an integer (second-precision is good enough) - up_time = int(script.attributes.get("up_time")) + "Get the current uptime of the server since last reload" + uptime = time() - SERVER_STARTTIME if format: - return realtime_format(up_time) - return up_time + return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60) + return uptime + +def gametime(format=False): + "Get the total gametime of the server since first start (minus downtimes)" + gametime = runtime() * TIMEFACTOR + if format: + return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN) + return gametime def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0, - weeks=0, months=0, yrs=0): + weeks=0, months=0, yrs=0, format=False): """ This method helps to figure out the real-world time it will take until an in-game time has passed. E.g. if an event should take place a month later @@ -201,15 +143,17 @@ def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0, gametime_to_realtime(days=2) -> number of seconds in real life from now after which 2 in-game days will have passed. """ - real_time = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \ - months * MONTH + yrs * YEAR) / TIMEFACTOR - return real_time + realtime = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \ + months * MONTH + yrs * YEAR) / TIMEFACTOR + if format: + return _format(realtime, 31536000, 2628000, 604800, 86400, 3600, 60) + return realtime def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, - weeks=0, months=0, yrs=0): + weeks=0, months=0, yrs=0, format=False): """ - This method calculates how large an in-game time a real-world time + This method calculates how much in-game time a real-world time interval would correspond to. This is usually a lot less interesting than the other way around. @@ -217,9 +161,11 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, realtime_to_gametime(days=2) -> number of game-world seconds corresponding to 2 real days. """ - game_time = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 + - weeks * 604800 + months * 2419200 + yrs * 29030400) - return game_time + gametime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 + + weeks * 604800 + months * 2628000 + yrs * 31536000) + if format: + return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN) + return gametime # Time administration routines