From 4d9081d710aaf6c28087206de1936e9bc0715e46 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 25 Nov 2009 19:27:32 +0000 Subject: [PATCH] Various cleanups in the recent modifications, and improvements to how time is handled and displayed. . Griatch --- src/commands/general.py | 1 - src/commands/info.py | 53 +++++++++++++++++-------- src/events.py | 11 ++---- src/gametime.py | 86 ++++++++++++++++++++++++++--------------- src/initial_setup.py | 12 +----- src/objects/models.py | 85 ++++++++++++++++++++++------------------ src/server.py | 12 +++--- 7 files changed, 152 insertions(+), 108 deletions(-) diff --git a/src/commands/general.py b/src/commands/general.py index 2d0226de7c..a93cf4e452 100644 --- a/src/commands/general.py +++ b/src/commands/general.py @@ -766,7 +766,6 @@ def cmd_help(command): GLOBAL_CMD_TABLE.add_command("help", cmd_help) - ## def cmd_testevent(command): ## from src import events ## from src import scheduler diff --git a/src/commands/info.py b/src/commands/info.py index d5ccb1ee9d..ac2e3228fd 100644 --- a/src/commands/info.py +++ b/src/commands/info.py @@ -9,6 +9,7 @@ if not functions_general.host_os_is('nt'): # Don't import the resource module if the host OS is Windows. import resource import django +from django.conf import settings from src.objects.models import Object from src import scheduler from src import defines_global @@ -43,11 +44,24 @@ def cmd_time(command): Server local time. """ gtime = gametime.time() + gtime_h = functions_general.time_format(gtime, style=2) + ictime = gtime * settings.TIME_FACTOR + ictime_h = functions_general.time_format(ictime, style=2) + uptime = time.time() - command.session.server.start_time + uptime_h = functions_general.time_format(uptime, style=2) synctime = gametime.time_last_sync() - ltime = time.strftime('%a %b %d %H:%M:%S %Y (%Z)', time.localtime()) - string = " Current game time: %i s." % gtime - string += "\n Time since cache was last saved: %i s." % synctime - string += "\n Current server time: %s" % ltime + synctime_h = functions_general.time_format(synctime, style=2) + ltime = time.strftime('%a %b %d %H:%M:%S %Y (%Z)', time.localtime()) + string = " Real-world times:" + string += "\n -- Main time counter: %s (%i s)." % (gtime_h, gtime) + + string += "\n -- Time since last reboot: %s (%i s). " % (uptime_h, uptime) + string += "\n -- Time since cache was last saved: %s (%i s)." % (synctime_h, + synctime) + string += "\n -- Current server time: %s" % ltime + string += "\n In-game time (time factor %s):" % settings.TIME_FACTOR + string += "\n -- Time passed: %s" % ictime_h + command.source_object.emit_to(string) GLOBAL_CMD_TABLE.add_command("@time", cmd_time, priv_tuple=("genperms.game_info",), @@ -66,19 +80,22 @@ def cmd_uptime(command): server = command.session.server start_delta = time.time() - server.start_time - source_object.emit_to('Current server time : %s' % - (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),))) - source_object.emit_to('Server start time : %s' % - (time.strftime('%a %b %d %H:%M %Y', time.localtime(server.start_time),))) - source_object.emit_to('Server uptime : %s' % - functions_general.time_format(start_delta, style=2)) - - # os.getloadavg() is not available on Windows. + string = " Server time info:" + string += "\n -- Current server time : %s" % \ + (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),)) + string += "\n -- Server start time : %s" % \ + (time.strftime('%a %b %d %H:%M %Y', + time.localtime(server.start_time),)) + string += "\n -- Server uptime : %s" % \ + (functions_general.time_format(start_delta, style=2)) if not functions_general.host_os_is('nt'): + # os.getloadavg() is not available on Windows. loadavg = os.getloadavg() - source_object.emit_to('Server load (1 min) : %.2f' % - loadavg[0]) -GLOBAL_CMD_TABLE.add_command("@uptime", cmd_uptime, priv_tuple=("genperms.game_info",), + string += "\n -- Server load (1 min) : %.2f" % loadavg[0] + source_object.emit_to(string) +GLOBAL_CMD_TABLE.add_command("@uptime", + cmd_uptime, + priv_tuple=("genperms.game_info",), help_category="Admin") def cmd_list(command): @@ -195,10 +212,12 @@ def cmd_showcache(command): """ source_object = command.source_object str_cache, str_pcache = cache.show() + ncache = len(str_cache.split(',')) + npcache = len(str_pcache.split(',')) string = "" if str_cache: - string += "\nVolatile cache:\n " + str_cache + string += "\nVolatile cache (%i):\n %s" % (ncache, str_cache) if str_pcache: - string += "\nPersistent cache:\n " + str_pcache + string += "\nPersistent cache (%i):\n %s" % (npcache, str_pcache) source_object.emit_to(string) GLOBAL_CMD_TABLE.add_command("@showcache", cmd_showcache, priv_tuple=("genperms.game_info",), help_category="Admin"), diff --git a/src/events.py b/src/events.py index 81d45ad8dd..60db3bc408 100644 --- a/src/events.py +++ b/src/events.py @@ -184,13 +184,10 @@ class IEvt_Sync_PCache(IntervalEvent): """ This is the function that is fired every self.interval seconds. """ - infostring = "Syncing time, events and persistent cache to disk." - logger.log_infomsg(infostring) - # updating the current time - time0 = time.time() - time1 = gametime.time(time0) - cache.set_pcache("_game_time0", time0) - cache.set_pcache("_game_time", time1) + #infostring = "Syncing time, events and persistent cache to disk." + #logger.log_infomsg(infostring) + # save the current time + gametime.time_save() # update the event database to pcache ecache = [event for event in scheduler.SCHEDULE if event.persistent] diff --git a/src/gametime.py b/src/gametime.py index 83916dedde..90c37bae0c 100644 --- a/src/gametime.py +++ b/src/gametime.py @@ -1,8 +1,8 @@ """ The gametime module handles the global passage of time in the mud. -It also - +It also supplies some useful methods to convert between +in-mud time and real-worl time. """ from django.conf import settings @@ -33,6 +33,34 @@ WEEK = DAY * settings.TIME_DAY_PER_WEEK MONTH = WEEK * settings.TIME_WEEK_PER_MONTH YEAR = MONTH * settings.TIME_MONTH_PER_YEAR +# Access routines + +def time(currtime=None): + """ + 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). + + Obs: depending on how often the persistent cache is saved to disk + (this is defined in the config file), there might be some discrepancy + here after a server crash, notably that some time will be 'lost' (i.e. + the time since last backup). If this is a concern, consider saving + the cache more often. + + currtime : An externally calculated current time to compare with. + This is used by Evennia to make sure to sync the game + time to a new real-world timestamp + """ + # saved real world timestamp (seconds since 1970 or so) + time0 = cache.get_pcache("_game_time0") + # saved game time at real-world time time0 + time1 = cache.get_pcache("_game_time") + if currtime: + return time1 + (currtime - time0) + else: + return time1 + (time_module.time() - time0) + def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0, weeks=0, months=0, yrs=0): """ @@ -63,37 +91,20 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks*604800 + months*2419200 + yrs*29030400) return stot -def time(currtime=None): - """ - Find the current in-game time (in seconds) since the start of the mud. - This is the main measure of in-game time and is persistently saved to - disk, so is the main thing to use to determine passage of time like - seasons etc. - - Obs depending on how often the persistent cache is saved to disk - (this is defined in the config file), there might be some discrepancy - here after a server crash, notably that some time will be 'lost' (i.e. - the time since last backup). If this is a concern, consider saving - the cache more often. - currtime : An externally calculated current time to compare with. - """ - time0 = cache.get_pcache("_game_time0") - time1 = cache.get_pcache("_game_time") - if currtime: - return time1 + (currtime - time0) - else: - return time1 + (time_module.time() - time0) - -def time_last_sync(): - """ - Calculates the time since the system was last synced to disk. This e.g. used - to adjust event counters for offline time. The error of this measure is - dependent on how often the cache is saved to disk. - """ - time0 = cache.get_pcache("_game_time0") - return time_module.time() - time0 +# Time administration routines +def time_init(): + """ + Called by Evennia's initial startup; this should normally not be called from + a running game, it resets the global in-game time! + """ + time0 = time_module.time() + time1 = 0 + cache.set_pcache("_game_time0", time0) + cache.set_pcache("_game_time", time1) + cache.save_pcache() + def time_save(): """ Force a save of the current time to persistent cache. @@ -106,4 +117,17 @@ def time_save(): cache.set_pcache("_game_time0", time0) cache.set_pcache("_game_time", time1) cache.save_pcache() + +def time_last_sync(): + """ + Calculates the time since the system was last synced to disk. This e.g. used + to adjust event counters for offline time, resulting in a maximum error being + the time between backups. + """ + # Real-world timestamp for last backup + time0 = cache.get_pcache("_game_time0") + # The correction factor is the time + # since last backup + downtime. + return time_module.time() - time0 + diff --git a/src/initial_setup.py b/src/initial_setup.py index e0be8e04db..4f9acfc56e 100644 --- a/src/initial_setup.py +++ b/src/initial_setup.py @@ -17,7 +17,7 @@ from src import session_mgr from src import scheduler from src import events from src.cache import cache - +from src import gametime # Main module methods def get_god_user(): @@ -170,16 +170,8 @@ def start_game_time(): """ This creates a persistent time stamp (in s since an arbitrary start) upon first server start and is saved and updated regularly in persistent cache. - _game_time0 is the current absolute time (in s since an arbitrary start) - _game_time is the current relative number of seconds that the server has been running - (not counting offline time), accurate to the time between - cache saves, when this is stored. """ - time0 = time.time() - time1 = 0 - cache.set_pcache("_game_time0", time0) - cache.set_pcache("_game_time", time1) - cache.save_pcache() + gametime.time_init() def handle_setup(): """ diff --git a/src/objects/models.py b/src/objects/models.py index 91d9033103..ace06f6bc5 100755 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -64,7 +64,25 @@ class Attribute(models.Model): if self.attr_ispickled: attr_value = pickle.loads(attr_value) return attr_value - + + def set_value(self, new_value): + """ + Sets an attributes value + """ + if new_value == None: + self.delete() + return + #pickle everything but strings + if type(new_value) != type(str()): + new_value = pickle.dumps(new_value) #,pickle.HIGHEST_PROTOCOL) + ispickled = True + else: + new_value = new_value + ispickled = False + self.attr_value = new_value + self.attr_ispickled = ispickled + self.save() + def get_object(self): """ Returns the object that the attribute resides on. @@ -99,6 +117,8 @@ class Attribute(models.Model): return "%s%s%s: %s" % (ANSITable.ansi["hilite"], self.get_name(),ANSITable.ansi["normal"], self.get_value()) + value = property(fget=get_value,fset=set_value) + class Object(models.Model): """ @@ -634,35 +654,22 @@ class Object(models.Model): if self.has_attribute(attribute): attrib_obj = \ Attribute.objects.filter(attr_object=self).filter(attr_name__iexact=attribute)[0] - - if new_value != None: - #pickle if anything else than str - if type(new_value) != type(str()): - new_value = pickle.dumps(new_value)#,pickle.HIGHEST_PROTOCOL) - ispickled = True - else: - new_value = new_value - ispickled = False - if attrib_obj: - # Save over the existing attribute's value. - attrib_obj.attr_value = new_value - attrib_obj.attr_ispickled = ispickled - attrib_obj.save() - else: - # Create a new attribute - new_attrib = Attribute() - new_attrib.attr_name = attribute - new_attrib.attr_value = new_value - new_attrib.attr_object = self - new_attrib.attr_hidden = False - new_attrib.attr_ispickled = ispickled - new_attrib.save() - - elif attrib_obj: - # If you do something like @set me=attrib: , destroy the attrib. - attrib_obj.delete() - + if new_value == None: + if attrib_obj: + attrib_obj.delete() + return + + if attrib_obj: + # Save over the existing attribute's value. + attrib_obj.set_value(new_value) + else: + # Create a new attribute + new_attrib = Attribute() + new_attrib.attr_name = attribute + new_attrib.attr_object = self + new_attrib.attr_hidden = False + new_attrib.set_value(new_value) def get_attribute_value(self, attrib, default=None): """ @@ -682,10 +689,8 @@ class Object(models.Model): return attrib.get_value() else: return default - - attribute = property(fget=get_attribute_value, fset=set_attribute) - def get_attribute_obj(self, attrib): + def get_attribute_obj(self, attrib, auto_create=False): """ Returns the attribute object matching the specified name. @@ -694,9 +699,16 @@ class Object(models.Model): if self.has_attribute(attrib): return Attribute.objects.filter(attr_object=self).filter(attr_name=attrib) else: - return False - - + if auto_create: + new_attrib = Attribute() + new_attrib.attr_name = attrib + new_attrib.attr_object = self + new_attrib.attr_hidden = False + new_attrib.save() + return new_attrib + else: + return False + def clear_attribute(self, attribute): """ Removes an attribute entirely. @@ -717,8 +729,7 @@ class Object(models.Model): """ return [attr for attr in self.attribute_set.all() if not attr.is_hidden()] - - + def clear_all_attributes(self): """ Clears all of an object's attributes. diff --git a/src/server.py b/src/server.py index df6a233255..0ded8667b2 100755 --- a/src/server.py +++ b/src/server.py @@ -63,17 +63,19 @@ class EvenniaService(service.Service): if not firstrun: # Find out how much offset the timer is (due to being # offline). - time_sync = gametime.time_last_sync() + downtime_sync = gametime.time_last_sync() # Sync the in-game timer. - cache.set_pcache("_game_time0", self.start_time) - + gametime.time_save() + # Fire up the event scheduler. event_cache = cache.get_pcache("_persistent_event_cache") if event_cache and type(event_cache) == type(list()): for event in event_cache: - # we adjust the executed time to account for offline time. - event.time_last_executed = event.time_last_executed + time_sync + # We adjust the last executed time to account for offline time. + # If we don't, the events will be confused since their last + # executed time is further away than their firing interval. + event.time_last_executed = event.time_last_executed + downtime_sync scheduler.add_event(event) print '-'*50