evennia/src/server.py

206 lines
7.6 KiB
Python
Raw Normal View History

2008-06-15 19:55:38 +00:00
import time
import sys
from twisted.application import internet, service
from twisted.internet import protocol, reactor, defer
from twisted.python import rebuild
from django.db import connection
from django.conf import settings
from src.config.models import ConfigValue
from src.session import SessionProtocol
from src import events
from src import logger
from src import comsys
from src import session_mgr
from src import alias_mgr
from src import cmdtable
from src import initial_setup
from src.util import functions_general
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
from src.cache import cache
from src import scheduler
from src import gametime
2006-12-05 22:06:50 +00:00
class EvenniaService(service.Service):
def __init__(self):
# Holds the TCP services.
self.service_collection = None
self.game_running = True
sys.path.append('.')
# Database-specific startup optimizations.
if settings.DATABASE_ENGINE == "sqlite3":
self.sqlite3_prep()
# Wipe our temporary flags on all of the objects.
cursor = connection.cursor()
cursor.execute("UPDATE objects_object SET nosave_flags=''")
# Begin startup debug output.
print '-'*50
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
firstrun = False
try:
# If this fails, this is an empty DB that needs populating.
ConfigValue.objects.get_configvalue('game_firstrun')
except ConfigValue.DoesNotExist:
print ' Game started for the first time, setting defaults.'
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
firstrun = True
initial_setup.handle_setup()
self.start_time = time.time()
print ' %s started on port(s):' % (ConfigValue.objects.get_configvalue('site_name'),)
for port in settings.GAMEPORTS:
print ' * %s' % (port)
# Populate the command table.
self.load_command_table()
# Cache the aliases from the database for quick access.
alias_mgr.load_cmd_aliases()
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
# Load persistent cache from database into memory
cache.load_pcache()
if not firstrun:
# Find out how much offset the timer is (due to being
# offline).
downtime_sync = gametime.time_last_sync()
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
# Sync the in-game timer.
gametime.time_save()
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
# 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 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
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
scheduler.add_event(event)
print '-'*50
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
"""
BEGIN SERVER STARTUP METHODS
"""
def sqlite3_prep(self):
"""
Optimize some SQLite stuff at startup since we can't save it to the
database.
"""
cursor = connection.cursor()
cursor.execute("PRAGMA cache_size=10000")
cursor.execute("PRAGMA synchronous=OFF")
cursor.execute("PRAGMA count_changes=OFF")
cursor.execute("PRAGMA temp_store=2")
def get_command_modules(self):
"""
Combines all of the command modules and returns a tuple. Order is
preserved.
"""
return settings.COMMAND_MODULES +\
settings.CUSTOM_COMMAND_MODULES +\
settings.UNLOGGED_COMMAND_MODULES +\
settings.CUSTOM_UNLOGGED_COMMAND_MODULES
def load_command_table(self):
"""
Imports command modules and loads them into the command tables.
"""
# Combine the tuples of command modules to load.
cmd_modules = self.get_command_modules()
# Import the command modules, which populates the command tables.
for cmd_mod in cmd_modules:
try:
__import__(cmd_mod)
except ImportError, e:
logger.log_errmsg("ERROR: Unable to load command module: %s (%s)" % (cmd_mod, e))
continue
"""
BEGIN GENERAL METHODS
"""
def shutdown(self, message='The server has been shutdown. Please check back soon.'):
"""
Gracefully disconnect everyone and kill the reactor.
"""
Implemented persistent cache, events and gametime counter. 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
2009-11-22 21:18:55 +00:00
gametime.time_save()
cache.save_pcache()
logger.log_infomsg("Persistent cache and time saved prior to shutdown.")
session_mgr.announce_all(message)
session_mgr.disconnect_all_sessions()
reactor.callLater(0, reactor.stop)
def reload(self, source_object=None):
"""
Reload modules that don't have any variables that can be reset.
For changes to the scheduler, server, or session_mgr modules, a cold
restart is needed.
"""
cmd_modules = self.get_command_modules()
s = []
for mod_str in cmd_modules:
if not sys.modules.has_key(mod_str):
comsys.cemit_mudinfo("... %s not reloadable." % mod_str)
logger.log_errmsg("Module %s not reloadable." % mod_str)
else:
mod = sys.modules[mod_str]
s.append(mod_str)
try:
rebuild.rebuild(mod)
except:
comsys.cemit_mudinfo("... Error reloading %s!" % mod_str)
raise
logger.log_infomsg("%s reloaded %i modules: %s" % (source_object, len(s), s))
2009-04-06 22:00:08 +00:00
def reload_aliases(self, source_object=None):
"""
Reload the aliases from the Alias model into the local table.
"""
alias_mgr.load_cmd_aliases()
def getEvenniaServiceFactory(self):
f = protocol.ServerFactory()
f.protocol = SessionProtocol
f.server = self
return f
def start_services(self, application):
"""
Starts all of the TCP services.
"""
self.service_collection = service.IServiceCollection(application)
for port in settings.GAMEPORTS:
evennia_server = internet.TCPServer(port, self.getEvenniaServiceFactory())
evennia_server.setName('Evennia%s' %port)
evennia_server.setServiceParent(self.service_collection)
if settings.IMC2_ENABLED:
from src.imc2.connection import IMC2ClientFactory
from src.imc2 import events as imc2_events
imc2_factory = IMC2ClientFactory()
svc = internet.TCPClient(settings.IMC2_SERVER_ADDRESS,
settings.IMC2_SERVER_PORT,
imc2_factory)
svc.setName('IMC2')
svc.setServiceParent(self.service_collection)
imc2_events.add_events()
if settings.IRC_ENABLED:
from src.irc.connection import IRC_BotFactory
irc = internet.TCPClient(settings.IRC_NETWORK,
settings.IRC_PORT,
IRC_BotFactory(settings.IRC_CHANNEL,
settings.IRC_NETWORK,
settings.IRC_NICKNAME))
irc.setName("%s:%s" % ("IRC",settings.IRC_CHANNEL))
irc.setServiceParent(self.service_collection)
application = service.Application('Evennia')
mud_service = EvenniaService()
mud_service.start_services(application)