Added .gitignore file to template
This commit is contained in:
parent
12e1ea6e6e
commit
8ac011bf66
3 changed files with 956 additions and 7 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -10,7 +10,6 @@ dist
|
||||||
build
|
build
|
||||||
eggs
|
eggs
|
||||||
parts
|
parts
|
||||||
bin
|
|
||||||
var
|
var
|
||||||
sdist
|
sdist
|
||||||
develop-eggs
|
develop-eggs
|
||||||
|
|
@ -26,12 +25,6 @@ __pycache__
|
||||||
*.restart
|
*.restart
|
||||||
*.db3
|
*.db3
|
||||||
|
|
||||||
# Installation-specific
|
|
||||||
game/settings.py
|
|
||||||
game/logs/*.log.*
|
|
||||||
game/gamesrc/web/static/*
|
|
||||||
game/gamesrc/web/media/*
|
|
||||||
|
|
||||||
# Installer logs
|
# Installer logs
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
|
|
||||||
|
|
|
||||||
905
bin/evennia.py
Executable file
905
bin/evennia.py
Executable file
|
|
@ -0,0 +1,905 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
EVENNIA SERVER STARTUP SCRIPT
|
||||||
|
|
||||||
|
This is the start point for running Evennia.
|
||||||
|
|
||||||
|
Sets the appropriate environmental variables and launches the server
|
||||||
|
and portal through the evennia_runner. Run without arguments to get a
|
||||||
|
menu. Run the script with the -h flag to see usage information.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import shutil
|
||||||
|
import importlib
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from subprocess import Popen, check_output, call, CalledProcessError, STDOUT
|
||||||
|
import django
|
||||||
|
|
||||||
|
# Signal processing
|
||||||
|
SIG = signal.SIGINT
|
||||||
|
|
||||||
|
# Set up the main python paths to Evennia
|
||||||
|
EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
EVENNIA_BIN = os.path.join(EVENNIA_ROOT, "bin")
|
||||||
|
|
||||||
|
import evennia
|
||||||
|
EVENNIA_LIB = os.path.join(os.path.dirname(os.path.abspath(evennia.__file__)))
|
||||||
|
EVENNIA_RUNNER = os.path.join(EVENNIA_BIN, "evennia_runner.py")
|
||||||
|
EVENNIA_TEMPLATE = os.path.join(EVENNIA_LIB, "game_template")
|
||||||
|
EVENNIA_BINTESTING = os.path.join(EVENNIA_BIN, "testing")
|
||||||
|
EVENNIA_DUMMYRUNNER = os.path.join(EVENNIA_BINTESTING, "dummyrunner.py")
|
||||||
|
|
||||||
|
TWISTED_BINARY = "twistd"
|
||||||
|
|
||||||
|
# Game directory structure
|
||||||
|
SETTINGFILE = "settings.py"
|
||||||
|
SERVERDIR = "server"
|
||||||
|
CONFDIR = os.path.join(SERVERDIR, "conf")
|
||||||
|
SETTINGS_PATH = os.path.join(CONFDIR, SETTINGFILE)
|
||||||
|
SETTINGS_DOTPATH = "server.conf.settings"
|
||||||
|
CURRENT_DIR = os.getcwd()
|
||||||
|
GAMEDIR = CURRENT_DIR
|
||||||
|
|
||||||
|
# Operational setup
|
||||||
|
SERVER_LOGFILE = None
|
||||||
|
PORTAL_LOGFILE = None
|
||||||
|
HTTP_LOGFILE = None
|
||||||
|
SERVER_PIDFILE = None
|
||||||
|
PORTAL_PIDFILE = None
|
||||||
|
SERVER_RESTART = None
|
||||||
|
PORTAL_RESTART = None
|
||||||
|
SERVER_PY_FILE = None
|
||||||
|
PORTAL_PY_FILE = None
|
||||||
|
|
||||||
|
PYTHON_MIN = '2.7'
|
||||||
|
TWISTED_MIN = '12.0'
|
||||||
|
DJANGO_MIN = '1.7'
|
||||||
|
DJANGO_REC = '1.7'
|
||||||
|
|
||||||
|
# add Evennia root to PYTHONPATH note that bin/evennia.py is
|
||||||
|
# automatically added to sys.modules and will be imported first, which
|
||||||
|
# is not what we want. So we remove it manually and set the path so
|
||||||
|
# the root/evennia package is found first instead.
|
||||||
|
del sys.modules["evennia"]
|
||||||
|
sys.path[0] = EVENNIA_ROOT
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Messages
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATED_NEW_GAMEDIR = \
|
||||||
|
"""
|
||||||
|
Welcome to Evennia!
|
||||||
|
Created a new Evennia game directory '{gamedir}'.
|
||||||
|
|
||||||
|
You can now optionally edit your new settings file
|
||||||
|
at {settings_path}. If you don't, the defaults
|
||||||
|
will work out of the box. When ready to continue, 'cd' to your
|
||||||
|
game directory and run:
|
||||||
|
|
||||||
|
evennia migrate
|
||||||
|
|
||||||
|
This initializes the database. To start the server for the first
|
||||||
|
time, run:
|
||||||
|
|
||||||
|
evennia -i start
|
||||||
|
|
||||||
|
Make sure to create a superuser when asked for it. You should now
|
||||||
|
be able to (by default) connect to your server on server
|
||||||
|
'localhost', port 4000 using a telnet/mud client or
|
||||||
|
http://localhost:8000 using your web browser. If things don't
|
||||||
|
work, check so those ports are open.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_NO_GAMEDIR = \
|
||||||
|
"""
|
||||||
|
No Evennia settings file was found. You must run this command from
|
||||||
|
inside a valid game directory first created with --init.
|
||||||
|
"""
|
||||||
|
|
||||||
|
WARNING_RUNSERVER = \
|
||||||
|
"""
|
||||||
|
WARNING: There is no need to run the Django development
|
||||||
|
webserver to test out Evennia web features (the web client
|
||||||
|
will in fact not work since the Django test server knows
|
||||||
|
nothing about MUDs). Instead, just start Evennia with the
|
||||||
|
webserver component active (this is the default).
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_SETTINGS = \
|
||||||
|
"""
|
||||||
|
There was an error importing Evennia's config file {settingspath}. There is usually
|
||||||
|
one of three reasons for this:
|
||||||
|
1) You are not running this command from your game directory.
|
||||||
|
Change directory to your game directory and try again (or
|
||||||
|
create a new game directory using evennia --init <dirname>)
|
||||||
|
2) The settings file contains a syntax error. If you see a
|
||||||
|
traceback above, review it, resolve the problem and try again.
|
||||||
|
3) Django is not correctly installed. This usually shows as
|
||||||
|
errors mentioning 'DJANGO_SETTINGS_MODULE'. If you run a
|
||||||
|
virtual machine, it might be worth to restart it to see if
|
||||||
|
this resolves the issue.
|
||||||
|
""".format(settingsfile=SETTINGFILE, settingspath=SETTINGS_PATH)
|
||||||
|
|
||||||
|
ERROR_DATABASE = \
|
||||||
|
"""
|
||||||
|
Your database does not seem to be set up correctly.
|
||||||
|
(error was '{traceback}')
|
||||||
|
|
||||||
|
Standing in your game directory, try to run
|
||||||
|
|
||||||
|
evennia migrate
|
||||||
|
|
||||||
|
to initialize/update the database according to your settings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_WINDOWS_WIN32API = \
|
||||||
|
"""
|
||||||
|
ERROR: Unable to import win32api, which Twisted requires to run.
|
||||||
|
You may download it from:
|
||||||
|
|
||||||
|
http://sourceforge.net/projects/pywin32
|
||||||
|
or
|
||||||
|
http://starship.python.net/crew/mhammond/win32/Downloads.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
INFO_WINDOWS_BATFILE = \
|
||||||
|
"""
|
||||||
|
INFO: Since you are running Windows, a file 'twistd.bat' was
|
||||||
|
created for you. This is a simple batch file that tries to call
|
||||||
|
the twisted executable. Evennia determined this to be:
|
||||||
|
|
||||||
|
%(twistd_path)s
|
||||||
|
|
||||||
|
If you run into errors at startup you might need to edit
|
||||||
|
twistd.bat to point to the actual location of the Twisted
|
||||||
|
executable (usually called twistd.py) on your machine.
|
||||||
|
|
||||||
|
This procedure is only done once. Run evennia.py again when you
|
||||||
|
are ready to start the server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
CMDLINE_HELP = \
|
||||||
|
"""
|
||||||
|
Starts or operates the Evennia MU* server. Also allows for
|
||||||
|
initializing a new game directory and managing the game's
|
||||||
|
database. You can also pass django manage.py arguments through
|
||||||
|
this launcher. If you need manage.py --options, use djangoadmin
|
||||||
|
directly instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
VERSION_INFO = \
|
||||||
|
"""
|
||||||
|
{about}
|
||||||
|
Evennia {version}
|
||||||
|
OS: {os}
|
||||||
|
Python: {python}
|
||||||
|
Twisted: {twisted}
|
||||||
|
Django: {django}
|
||||||
|
"""
|
||||||
|
|
||||||
|
ABOUT_INFO= \
|
||||||
|
"""
|
||||||
|
Evennia MUD/MUX/MU* development system
|
||||||
|
|
||||||
|
Licence: BSD 3-Clause Licence
|
||||||
|
Web: http://www.evennia.com
|
||||||
|
Irc: #evennia on FreeNode
|
||||||
|
Forum: http://www.evennia.com/discussions
|
||||||
|
Maintainer (2010-): Griatch (griatch AT gmail DOT com)
|
||||||
|
Maintainer (2006-10): Greg Taylor
|
||||||
|
|
||||||
|
Use -h for command line options.
|
||||||
|
"""
|
||||||
|
|
||||||
|
HELP_ENTRY = \
|
||||||
|
"""
|
||||||
|
Enter 'evennia -h' for command-line options.
|
||||||
|
|
||||||
|
Use option (1) in a production environment. During development (2) is
|
||||||
|
usually enough, portal debugging is usually only useful if you are
|
||||||
|
adding new protocols or are debugging Evennia itself.
|
||||||
|
|
||||||
|
Reload with (5) to update the server with your changes without
|
||||||
|
disconnecting any players.
|
||||||
|
|
||||||
|
Note: Reload and stop are sometimes poorly supported in Windows. If you have
|
||||||
|
issues, log into the game to stop or restart the server instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MENU = \
|
||||||
|
"""
|
||||||
|
+----Evennia Launcher-------------------------------------------+
|
||||||
|
| |
|
||||||
|
+--- Starting --------------------------------------------------+
|
||||||
|
| |
|
||||||
|
| 1) (normal): All output to logfiles |
|
||||||
|
| 2) (server devel): Server logs to terminal (-i option) |
|
||||||
|
| 3) (portal devel): Portal logs to terminal |
|
||||||
|
| 4) (full devel): Both Server and Portal logs to terminal |
|
||||||
|
| |
|
||||||
|
+--- Restarting ------------------------------------------------+
|
||||||
|
| |
|
||||||
|
| 5) Reload the Server |
|
||||||
|
| 6) Reload the Portal (only works with portal/full debug) |
|
||||||
|
| |
|
||||||
|
+--- Stopping --------------------------------------------------+
|
||||||
|
| |
|
||||||
|
| 7) Stopping both Portal and Server |
|
||||||
|
| 8) Stopping only Server |
|
||||||
|
| 9) Stopping only Portal |
|
||||||
|
| |
|
||||||
|
+---------------------------------------------------------------+
|
||||||
|
| h) Help i) About info q) Abort |
|
||||||
|
+---------------------------------------------------------------+
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_PYTHON_VERSION = \
|
||||||
|
"""
|
||||||
|
ERROR: Python {pversion} used. Evennia requires version
|
||||||
|
{python_min} or higher (but not 3.x).
|
||||||
|
"""
|
||||||
|
|
||||||
|
WARNING_TWISTED_VERSION = \
|
||||||
|
"""
|
||||||
|
WARNING: Twisted {tversion} found. Evennia recommends
|
||||||
|
v{twisted_min} or higher."
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_NOTWISTED = \
|
||||||
|
"""
|
||||||
|
ERROR: Twisted does not seem to be installed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_DJANGO_MIN = \
|
||||||
|
"""
|
||||||
|
ERROR: Django {dversion} found. Evennia requires version
|
||||||
|
{django_min} or higher.
|
||||||
|
"""
|
||||||
|
|
||||||
|
NOTE_DJANGO_MIN = \
|
||||||
|
"""
|
||||||
|
NOTE: Django {dversion} found. This will work, but v{django_rec}
|
||||||
|
is recommended for production.
|
||||||
|
"""
|
||||||
|
|
||||||
|
NOTE_DJANGO_NEW = \
|
||||||
|
"""
|
||||||
|
NOTE: Django {dversion} found. This is newer than Evennia's
|
||||||
|
recommended version (v{django_rec}). It will probably work, but
|
||||||
|
may be new enough not to be fully tested yet. Report any issues."
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_NODJANGO = \
|
||||||
|
"""
|
||||||
|
ERROR: Django does not seem to be installed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Functions
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
def evennia_version():
|
||||||
|
"""
|
||||||
|
Get the Evennia version info from the main package.
|
||||||
|
"""
|
||||||
|
version = "Unknown"
|
||||||
|
try:
|
||||||
|
import evennia
|
||||||
|
version = evennia.__version__
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
version = "%s (rev %s)" % (version, check_output("git rev-parse --short HEAD", shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT).strip())
|
||||||
|
except (IOError, CalledProcessError):
|
||||||
|
pass
|
||||||
|
return version
|
||||||
|
|
||||||
|
EVENNIA_VERSION = evennia_version()
|
||||||
|
|
||||||
|
|
||||||
|
def check_main_evennia_dependencies():
|
||||||
|
"""
|
||||||
|
Checks and imports the Evennia dependencies. This must be done
|
||||||
|
already before the paths are set up.
|
||||||
|
"""
|
||||||
|
error = False
|
||||||
|
|
||||||
|
# Python
|
||||||
|
pversion = ".".join(str(num) for num in sys.version_info if type(num) == int)
|
||||||
|
if pversion < PYTHON_MIN:
|
||||||
|
print ERROR_PYTHON_VERSION.format(pversion=pversion, python_min=PYTHON_MIN)
|
||||||
|
error = True
|
||||||
|
# Twisted
|
||||||
|
try:
|
||||||
|
import twisted
|
||||||
|
tversion = twisted.version.short()
|
||||||
|
if tversion < TWISTED_MIN:
|
||||||
|
print WARNING_TWISTED_VERSION.format(tversion=tversion, twisted_min=TWISTED_MIN)
|
||||||
|
except ImportError:
|
||||||
|
print ERROR_NOTWISTED
|
||||||
|
error = True
|
||||||
|
# Django
|
||||||
|
try:
|
||||||
|
dversion = ".".join(str(num) for num in django.VERSION if type(num) == int)
|
||||||
|
# only the main version (1.5, not 1.5.4.0)
|
||||||
|
dversion_main = ".".join(dversion.split(".")[:2])
|
||||||
|
if dversion < DJANGO_MIN:
|
||||||
|
print ERROR_DJANGO_MIN.format(dversion=dversion_main, django_min=DJANGO_MIN)
|
||||||
|
error = True
|
||||||
|
elif DJANGO_MIN <= dversion < DJANGO_REC:
|
||||||
|
print NOTE_DJANGO_MIN.format(dversion=dversion_main, django_rec=DJANGO_REC)
|
||||||
|
elif DJANGO_REC < dversion_main:
|
||||||
|
print NOTE_DJANGO_NEW.format(dversion=dversion_main, django_rec=DJANGO_REC)
|
||||||
|
except ImportError:
|
||||||
|
print ERROR_NODJANGO
|
||||||
|
error = True
|
||||||
|
if error:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
def set_gamedir(path):
|
||||||
|
"""
|
||||||
|
Set GAMEDIR based on path, by figuring out where the setting file
|
||||||
|
is inside the directory tree.
|
||||||
|
"""
|
||||||
|
|
||||||
|
global GAMEDIR
|
||||||
|
if os.path.exists(os.path.join(path, SETTINGS_PATH)):
|
||||||
|
# path at root of game dir
|
||||||
|
GAMEDIR = os.path.abspath(path)
|
||||||
|
elif os.path.exists(os.path.join(path, os.path.pardir, SETTINGS_PATH)):
|
||||||
|
# path given to somewhere one level down
|
||||||
|
GAMEDIR = os.path.dirname(path)
|
||||||
|
elif os.path.exists(os.path.join(path, os.path.pardir, os.path.pardir, SETTINGS_PATH)):
|
||||||
|
# path given to somwhere two levels down
|
||||||
|
GAMEDIR = os.path.dirname(os.path.dirname(path))
|
||||||
|
elif os.path.exists(os.path.join(path, os.path.pardir, os.path. pardir, os.path.pardir, SETTINGS_PATH)):
|
||||||
|
# path given to somewhere three levels down (custom directories)
|
||||||
|
GAMEDIR = os.path.dirname(os.path.dirname(os.path.dirname(path)))
|
||||||
|
else:
|
||||||
|
# we don't look further down than this ...
|
||||||
|
print ERROR_NO_GAMEDIR
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
def create_secret_key():
|
||||||
|
"""
|
||||||
|
Randomly create the secret key for the settings file
|
||||||
|
"""
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
secret_key = list((string.letters +
|
||||||
|
string.digits + string.punctuation).replace("\\", "").replace("'", '"'))
|
||||||
|
random.shuffle(secret_key)
|
||||||
|
secret_key = "".join(secret_key[:40])
|
||||||
|
return secret_key
|
||||||
|
|
||||||
|
|
||||||
|
def create_settings_file():
|
||||||
|
"""
|
||||||
|
Uses the template settings file to build a working
|
||||||
|
settings file.
|
||||||
|
"""
|
||||||
|
settings_path = os.path.join(GAMEDIR, "server", "conf", "settings.py")
|
||||||
|
with open(settings_path, 'r') as f:
|
||||||
|
settings_string = f.read()
|
||||||
|
|
||||||
|
# tweak the settings
|
||||||
|
setting_dict = {"settings_default": os.path.join(EVENNIA_LIB, "settings_default.py"),
|
||||||
|
"servername":"\"%s\"" % GAMEDIR.rsplit(os.path.sep, 1)[1].capitalize(),
|
||||||
|
"game_dir":"\"%s\"" % GAMEDIR,
|
||||||
|
"secret_key":"\'%s\'" % create_secret_key()}
|
||||||
|
|
||||||
|
# modify the settings
|
||||||
|
settings_string = settings_string.format(**setting_dict)
|
||||||
|
|
||||||
|
with open(settings_path, 'w') as f:
|
||||||
|
f.write(settings_string)
|
||||||
|
|
||||||
|
|
||||||
|
def create_game_directory(dirname):
|
||||||
|
"""
|
||||||
|
Initialize a new game directory named dirname
|
||||||
|
at the current path. This means copying the
|
||||||
|
template directory from evennia's root.
|
||||||
|
"""
|
||||||
|
global GAMEDIR
|
||||||
|
GAMEDIR = os.path.abspath(os.path.join(CURRENT_DIR, dirname))
|
||||||
|
if os.path.exists(GAMEDIR):
|
||||||
|
print "Cannot create new Evennia game dir: '%s' already exists." % dirname
|
||||||
|
sys.exit()
|
||||||
|
# copy template directory
|
||||||
|
shutil.copytree(EVENNIA_TEMPLATE, GAMEDIR)
|
||||||
|
# pre-build settings file in the new GAMEDIR
|
||||||
|
create_settings_file()
|
||||||
|
|
||||||
|
|
||||||
|
def create_superuser():
|
||||||
|
"Create the superuser player"
|
||||||
|
print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n"
|
||||||
|
django.core.management.call_command("createsuperuser", interactive=True)
|
||||||
|
|
||||||
|
|
||||||
|
def check_database(exit_on_error=False):
|
||||||
|
"""
|
||||||
|
Check database exists
|
||||||
|
"""
|
||||||
|
# Check so a database exists and is accessible
|
||||||
|
from django.db import connection
|
||||||
|
tables = connection.introspection.get_table_list(connection.cursor())
|
||||||
|
if tables and u'players_playerdb' in tables:
|
||||||
|
# database exists and seems set up. Initialize evennia.
|
||||||
|
import evennia
|
||||||
|
evennia.init()
|
||||||
|
else:
|
||||||
|
if exit_on_error:
|
||||||
|
print ERROR_DATABASE.format(traceback=e)
|
||||||
|
sys.exit()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
# Try to get Player#1
|
||||||
|
from evennia.players.models import PlayerDB
|
||||||
|
try:
|
||||||
|
PlayerDB.objects.get(id=1)
|
||||||
|
except PlayerDB.DoesNotExist:
|
||||||
|
# no superuser yet. We need to create it.
|
||||||
|
create_superuser()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def getenv():
|
||||||
|
"""
|
||||||
|
Get current environment and add PYTHONPATH
|
||||||
|
"""
|
||||||
|
sep = ";" if os.name == 'nt' else ":"
|
||||||
|
env = os.environ.copy()
|
||||||
|
env['PYTHONPATH'] = sep.join(sys.path)
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def get_pid(pidfile):
|
||||||
|
"""
|
||||||
|
Get the PID (Process ID) by trying to access
|
||||||
|
an PID file.
|
||||||
|
"""
|
||||||
|
pid = None
|
||||||
|
if os.path.exists(pidfile):
|
||||||
|
f = open(pidfile, 'r')
|
||||||
|
pid = f.read()
|
||||||
|
return pid
|
||||||
|
|
||||||
|
|
||||||
|
def del_pid(pidfile):
|
||||||
|
"""
|
||||||
|
The pidfile should normally be removed after a process has
|
||||||
|
finished, but when sending certain signals they remain, so we need
|
||||||
|
to clean them manually.
|
||||||
|
"""
|
||||||
|
if os.path.exists(pidfile):
|
||||||
|
os.remove(pidfile)
|
||||||
|
|
||||||
|
|
||||||
|
def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart=False):
|
||||||
|
"""
|
||||||
|
Send a kill signal to a process based on PID. A customized
|
||||||
|
success/error message will be returned. If clean=True, the system
|
||||||
|
will attempt to manually remove the pid file.
|
||||||
|
"""
|
||||||
|
pid = get_pid(pidfile)
|
||||||
|
if pid:
|
||||||
|
if os.name == 'nt':
|
||||||
|
os.remove(pidfile)
|
||||||
|
# set restart/norestart flag
|
||||||
|
if restart:
|
||||||
|
django.core.management.call_command('collectstatic', interactive=False, verbosity=0)
|
||||||
|
with open(restart_file, 'w') as f:
|
||||||
|
f.write("reload")
|
||||||
|
else:
|
||||||
|
with open(restart_file, 'w') as f:
|
||||||
|
f.write("shutdown")
|
||||||
|
try:
|
||||||
|
os.kill(int(pid), signal)
|
||||||
|
except OSError:
|
||||||
|
print "Process %(pid)s cannot be stopped. "\
|
||||||
|
"The PID file 'server/%(pidfile)s' seems stale. "\
|
||||||
|
"Try removing it." % {'pid': pid, 'pidfile': pidfile}
|
||||||
|
return
|
||||||
|
print "Evennia:", succmsg
|
||||||
|
return
|
||||||
|
print "Evennia:", errmsg
|
||||||
|
|
||||||
|
|
||||||
|
def show_version_info(about=False):
|
||||||
|
"""
|
||||||
|
Display version info
|
||||||
|
"""
|
||||||
|
import os, sys
|
||||||
|
import twisted
|
||||||
|
import django
|
||||||
|
|
||||||
|
return VERSION_INFO.format(version=EVENNIA_VERSION,
|
||||||
|
about=ABOUT_INFO if about else "",
|
||||||
|
os=os.name, python=sys.version.split()[0],
|
||||||
|
twisted=twisted.version.short(),
|
||||||
|
django=django.get_version())
|
||||||
|
|
||||||
|
|
||||||
|
def error_check_python_modules():
|
||||||
|
"""
|
||||||
|
Import settings modules in settings. This will raise exceptions on
|
||||||
|
pure python-syntax issues which are hard to catch gracefully
|
||||||
|
with exceptions in the engine (since they are formatting errors in
|
||||||
|
the python source files themselves). Best they fail already here
|
||||||
|
before we get any further.
|
||||||
|
"""
|
||||||
|
from django.conf import settings
|
||||||
|
def imp(path, split=True):
|
||||||
|
mod, fromlist = path, "None"
|
||||||
|
if split:
|
||||||
|
mod, fromlist = path.rsplit('.', 1)
|
||||||
|
__import__(mod, fromlist=[fromlist])
|
||||||
|
|
||||||
|
# core modules
|
||||||
|
imp(settings.COMMAND_PARSER)
|
||||||
|
imp(settings.SEARCH_AT_RESULT)
|
||||||
|
imp(settings.SEARCH_AT_MULTIMATCH_INPUT)
|
||||||
|
imp(settings.CONNECTION_SCREEN_MODULE)
|
||||||
|
#imp(settings.AT_INITIAL_SETUP_HOOK_MODULE, split=False)
|
||||||
|
for path in settings.LOCK_FUNC_MODULES:
|
||||||
|
imp(path, split=False)
|
||||||
|
# cmdsets
|
||||||
|
|
||||||
|
deprstring = "settings.%s should be renamed to %s. If defaults are used, " \
|
||||||
|
"their path/classname must be updated (see evennia/settings_default.py)."
|
||||||
|
if hasattr(settings, "CMDSET_DEFAULT"):
|
||||||
|
raise DeprecationWarning(deprstring % ("CMDSET_DEFAULT", "CMDSET_CHARACTER"))
|
||||||
|
if hasattr(settings, "CMDSET_OOC"):
|
||||||
|
raise DeprecationWarning(deprstring % ("CMDSET_OOC", "CMDSET_PLAYER"))
|
||||||
|
if settings.WEBSERVER_ENABLED and not isinstance(settings.WEBSERVER_PORTS[0], tuple):
|
||||||
|
raise DeprecationWarning("settings.WEBSERVER_PORTS must be on the form [(proxyport, serverport), ...]")
|
||||||
|
if hasattr(settings, "BASE_COMM_TYPECLASS"):
|
||||||
|
raise DeprecationWarning(deprstring % ("BASE_COMM_TYPECLASS", "BASE_CHANNEL_TYPECLASS"))
|
||||||
|
if hasattr(settings, "COMM_TYPECLASS_PATHS"):
|
||||||
|
raise DeprecationWarning(deprstring % ("COMM_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS"))
|
||||||
|
if hasattr(settings, "CHARACTER_DEFAULT_HOME"):
|
||||||
|
raise DeprecationWarning("settings.CHARACTER_DEFAULT_HOME should be renamed to DEFAULT_HOME. " \
|
||||||
|
"See also settings.START_LOCATION (see evennia/settings_default.py).")
|
||||||
|
|
||||||
|
from evennia.commands import cmdsethandler
|
||||||
|
if not cmdsethandler.import_cmdset(settings.CMDSET_UNLOGGEDIN, None): print "Warning: CMDSET_UNLOGGED failed to load!"
|
||||||
|
if not cmdsethandler.import_cmdset(settings.CMDSET_CHARACTER, None): print "Warning: CMDSET_CHARACTER failed to load"
|
||||||
|
if not cmdsethandler.import_cmdset(settings.CMDSET_PLAYER, None): print "Warning: CMDSET_PLAYER failed to load"
|
||||||
|
# typeclasses
|
||||||
|
imp(settings.BASE_PLAYER_TYPECLASS)
|
||||||
|
imp(settings.BASE_OBJECT_TYPECLASS)
|
||||||
|
imp(settings.BASE_CHARACTER_TYPECLASS)
|
||||||
|
imp(settings.BASE_ROOM_TYPECLASS)
|
||||||
|
imp(settings.BASE_EXIT_TYPECLASS)
|
||||||
|
imp(settings.BASE_SCRIPT_TYPECLASS)
|
||||||
|
|
||||||
|
|
||||||
|
def init_game_directory(path, check_db=True):
|
||||||
|
"""
|
||||||
|
Try to analyze the given path to find settings.py - this defines
|
||||||
|
the game directory and also sets PYTHONPATH as well as the
|
||||||
|
django path.
|
||||||
|
"""
|
||||||
|
# set the GAMEDIR path
|
||||||
|
set_gamedir(path)
|
||||||
|
|
||||||
|
# Add gamedir to python path
|
||||||
|
sys.path.insert(1, GAMEDIR)
|
||||||
|
|
||||||
|
# Prepare django; set the settings location
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = SETTINGS_DOTPATH
|
||||||
|
|
||||||
|
# required since django1.7
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
# test existence of the settings module
|
||||||
|
try:
|
||||||
|
from django.conf import settings
|
||||||
|
except Exception, ex:
|
||||||
|
if not str(ex).startswith("No module named"):
|
||||||
|
import traceback
|
||||||
|
print traceback.format_exc().strip()
|
||||||
|
print ERROR_SETTINGS
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
# this will both check the database and initialize the evennia dir.
|
||||||
|
if check_db:
|
||||||
|
check_database()
|
||||||
|
|
||||||
|
# set up the Evennia executables and log file locations
|
||||||
|
global SERVER_PY_FILE, PORTAL_PY_FILE
|
||||||
|
global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE
|
||||||
|
global SERVER_PIDFILE, PORTAL_PIDFILE
|
||||||
|
global SERVER_RESTART, PORTAL_RESTART
|
||||||
|
global EVENNIA_VERSION
|
||||||
|
|
||||||
|
SERVER_PY_FILE = os.path.join(EVENNIA_LIB, "server", "server.py")
|
||||||
|
PORTAL_PY_FILE = os.path.join(EVENNIA_LIB, "portal", "portal", "portal.py")
|
||||||
|
|
||||||
|
SERVER_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "server.pid")
|
||||||
|
PORTAL_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "portal.pid")
|
||||||
|
|
||||||
|
SERVER_RESTART = os.path.join(GAMEDIR, SERVERDIR, "server.restart")
|
||||||
|
PORTAL_RESTART = os.path.join(GAMEDIR, SERVERDIR, "portal.restart")
|
||||||
|
|
||||||
|
SERVER_LOGFILE = settings.SERVER_LOG_FILE
|
||||||
|
PORTAL_LOGFILE = settings.PORTAL_LOG_FILE
|
||||||
|
HTTP_LOGFILE = settings.HTTP_LOG_FILE
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
# We need to handle Windows twisted separately. We create a
|
||||||
|
# batchfile in game/server, linking to the actual binary
|
||||||
|
|
||||||
|
global TWISTED_BINARY
|
||||||
|
TWISTED_BINARY = "twistd.bat"
|
||||||
|
|
||||||
|
# add path so system can find the batfile
|
||||||
|
sys.path.insert(1, os.path.join(GAMEDIR, SERVERDIR))
|
||||||
|
|
||||||
|
try:
|
||||||
|
importlib.import_module("win32api")
|
||||||
|
except ImportError:
|
||||||
|
print ERROR_WINDOWS_WIN32API
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(EVENNIA_BIN, TWISTED_BINARY)):
|
||||||
|
# Test for executable twisted batch file. This calls the
|
||||||
|
# twistd.py executable that is usually not found on the
|
||||||
|
# path in Windows. It's not enough to locate
|
||||||
|
# scripts.twistd, what we want is the executable script
|
||||||
|
# C:\PythonXX/Scripts/twistd.py. Alas we cannot hardcode
|
||||||
|
# this location since we don't know if user has Python in
|
||||||
|
# a non-standard location. So we try to figure it out.
|
||||||
|
twistd = importlib.import_module("twisted.scripts.twistd")
|
||||||
|
twistd_dir = os.path.dirname(twistd.__file__)
|
||||||
|
|
||||||
|
# note that we hope the twistd package won't change here, since we
|
||||||
|
# try to get to the executable by relative path.
|
||||||
|
twistd_path = os.path.abspath(os.path.join(twistd_dir,
|
||||||
|
os.pardir, os.pardir, os.pardir, os.pardir,
|
||||||
|
'scripts', 'twistd.py'))
|
||||||
|
|
||||||
|
with open('twistd.bat', 'w') as bat_file:
|
||||||
|
# build a custom bat file for windows
|
||||||
|
bat_file.write("@\"%s\" \"%s\" %%*" % (sys.executable, twistd_path))
|
||||||
|
|
||||||
|
print INFO_WINDOWS_BATFILE.format(twistd_path=twistd_path)
|
||||||
|
|
||||||
|
def run_dummyrunner(number_of_dummies):
|
||||||
|
"""
|
||||||
|
Start an instance of the dummyrunner
|
||||||
|
|
||||||
|
The dummy players' behavior can be customized by adding a
|
||||||
|
dummyrunner_settings.py config file in the game's conf directory.
|
||||||
|
"""
|
||||||
|
number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1
|
||||||
|
cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies]
|
||||||
|
config_file = os.path.join(SETTINGS_PATH, "dummyrunner_settings.py")
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
cmdstr.extend(["--config", config_file])
|
||||||
|
try:
|
||||||
|
call(cmdstr, env=getenv())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run_menu():
|
||||||
|
"""
|
||||||
|
This launches an interactive menu.
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
# menu loop
|
||||||
|
|
||||||
|
print MENU
|
||||||
|
inp = raw_input(" option > ")
|
||||||
|
|
||||||
|
# quitting and help
|
||||||
|
if inp.lower() == 'q':
|
||||||
|
return
|
||||||
|
elif inp.lower() == 'h':
|
||||||
|
print HELP_ENTRY
|
||||||
|
raw_input("press <return> to continue ...")
|
||||||
|
continue
|
||||||
|
elif inp.lower() in ('v', 'i', 'a'):
|
||||||
|
print show_version_info(about=True)
|
||||||
|
raw_input("press <return> to continue ...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# options
|
||||||
|
try:
|
||||||
|
inp = int(inp)
|
||||||
|
except ValueError:
|
||||||
|
print "Not a valid option."
|
||||||
|
continue
|
||||||
|
if inp == 1:
|
||||||
|
# start everything, log to log files
|
||||||
|
server_operation("start", "all", False, False)
|
||||||
|
elif inp == 2:
|
||||||
|
# start everything, server interactive start
|
||||||
|
server_operation("start", "all", True, False)
|
||||||
|
elif inp == 3:
|
||||||
|
# start everything, portal interactive start
|
||||||
|
server_operation("start", "server", False, False)
|
||||||
|
server_operation("start", "portal", True, False)
|
||||||
|
elif inp == 4:
|
||||||
|
# start both server and portal interactively
|
||||||
|
server_operation("start", "server", True, False)
|
||||||
|
server_operation("start", "portal", True, False)
|
||||||
|
elif inp == 5:
|
||||||
|
# reload the server
|
||||||
|
server_operation("reload", "server", None, None)
|
||||||
|
elif inp == 6:
|
||||||
|
# reload the portal
|
||||||
|
server_operation("reload", "portal", None, None)
|
||||||
|
elif inp == 7:
|
||||||
|
# stop server and portal
|
||||||
|
server_operation("stop", "all", None, None)
|
||||||
|
elif inp == 8:
|
||||||
|
# stop server
|
||||||
|
server_operation("stop", "server", None, None)
|
||||||
|
elif inp == 9:
|
||||||
|
# stop portal
|
||||||
|
server_operation("stop", "portal", None, None)
|
||||||
|
else:
|
||||||
|
print "Not a valid option."
|
||||||
|
continue
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def server_operation(mode, service, interactive, profiler):
|
||||||
|
"""
|
||||||
|
Handle argument options given on the command line.
|
||||||
|
|
||||||
|
mode - str; start/stop etc
|
||||||
|
service - str; server, portal or all
|
||||||
|
interactive - bool; use interactive mode or daemon
|
||||||
|
profiler - run the service under the profiler
|
||||||
|
"""
|
||||||
|
|
||||||
|
cmdstr = [sys.executable, EVENNIA_RUNNER]
|
||||||
|
errmsg = "The %s does not seem to be running."
|
||||||
|
|
||||||
|
if mode == 'start':
|
||||||
|
|
||||||
|
# launch the error checker. Best to catch the errors already here.
|
||||||
|
error_check_python_modules()
|
||||||
|
|
||||||
|
# starting one or many services
|
||||||
|
if service == 'server':
|
||||||
|
if profiler:
|
||||||
|
cmdstr.append('--pserver')
|
||||||
|
if interactive:
|
||||||
|
cmdstr.append('--iserver')
|
||||||
|
cmdstr.append('--noportal')
|
||||||
|
elif service == 'portal':
|
||||||
|
if profiler:
|
||||||
|
cmdstr.append('--pportal')
|
||||||
|
if interactive:
|
||||||
|
cmdstr.append('--iportal')
|
||||||
|
cmdstr.append('--noserver')
|
||||||
|
django.core.management.call_command('collectstatic', verbosity=1, interactive=False)
|
||||||
|
else: # all
|
||||||
|
# for convenience we don't start logging of
|
||||||
|
# portal, only of server with this command.
|
||||||
|
if profiler:
|
||||||
|
cmdstr.append('--pserver') # this is the common case
|
||||||
|
if interactive:
|
||||||
|
cmdstr.append('--iserver')
|
||||||
|
django.core.management.call_command('collectstatic', verbosity=1, interactive=False)
|
||||||
|
cmdstr.extend([GAMEDIR, TWISTED_BINARY, SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE])
|
||||||
|
# start the server
|
||||||
|
Popen(cmdstr, env=getenv())
|
||||||
|
|
||||||
|
elif mode == 'reload':
|
||||||
|
# restarting services
|
||||||
|
if os.name == 'nt':
|
||||||
|
print "Restarting from command line is not supported under Windows. Log into the game to restart."
|
||||||
|
return
|
||||||
|
if service == 'server':
|
||||||
|
kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server', SERVER_RESTART, restart=True)
|
||||||
|
elif service == 'portal':
|
||||||
|
print """
|
||||||
|
Note: Portal usually doesnt't need to be reloaded unless you are debugging in interactive mode.
|
||||||
|
If Portal was running in default Daemon mode, it cannot be restarted. In that case you have
|
||||||
|
to restart it manually with 'evennia.py start portal'
|
||||||
|
"""
|
||||||
|
kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART, restart=True)
|
||||||
|
else: # all
|
||||||
|
# default mode, only restart server
|
||||||
|
kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server', SERVER_RESTART, restart=True)
|
||||||
|
|
||||||
|
elif mode == 'stop':
|
||||||
|
# stop processes, avoiding reload
|
||||||
|
if service == 'server':
|
||||||
|
kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', SERVER_RESTART)
|
||||||
|
elif service == 'portal':
|
||||||
|
kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART)
|
||||||
|
else:
|
||||||
|
kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART)
|
||||||
|
kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', SERVER_RESTART)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Run the evennia main program.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# set up argument parser
|
||||||
|
|
||||||
|
parser = ArgumentParser(description=CMDLINE_HELP)
|
||||||
|
parser.add_argument('-v', '--version', action='store_true',
|
||||||
|
dest='show_version', default=False,
|
||||||
|
help="Show version info.")
|
||||||
|
parser.add_argument('-i', '--interactive', action='store_true',
|
||||||
|
dest='interactive', default=False,
|
||||||
|
help="Start given processes in interactive mode.")
|
||||||
|
parser.add_argument('--init', action='store', dest="init", metavar="name",
|
||||||
|
help="Creates a new game directory 'name' at the current location.")
|
||||||
|
parser.add_argument('--profiler', action='store_true', dest='profiler', default=False,
|
||||||
|
help="Start given server component under the Python profiler.")
|
||||||
|
parser.add_argument('--dummyrunner', nargs=1, action='store', dest='dummyrunner', metavar="N",
|
||||||
|
help="Tests a running server by connecting N dummy players to it.")
|
||||||
|
parser.add_argument("mode", metavar="option", nargs='?', default="help",
|
||||||
|
help="Operational mode or management option. Commonly start, stop, reload, migrate, or menu (default).")
|
||||||
|
parser.add_argument("service", metavar="component", nargs='?', choices=["all", "server", "portal"], default="all",
|
||||||
|
help="Which server component to operate on. One of server, portal or all (default).")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# handle arguments
|
||||||
|
|
||||||
|
mode, service = args.mode, args.service
|
||||||
|
|
||||||
|
check_main_evennia_dependencies()
|
||||||
|
|
||||||
|
if args.init:
|
||||||
|
create_game_directory(args.init)
|
||||||
|
print CREATED_NEW_GAMEDIR.format(gamedir=args.init,
|
||||||
|
settings_path=os.path.join(args.init, SETTINGS_PATH))
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if args.show_version:
|
||||||
|
print show_version_info(mode=="help")
|
||||||
|
sys.exit()
|
||||||
|
if mode == "help" and not args.dummyrunner:
|
||||||
|
print ABOUT_INFO
|
||||||
|
sys.exit()
|
||||||
|
check_db = not mode == "migrate"
|
||||||
|
|
||||||
|
# this must be done first - it sets up all the global properties
|
||||||
|
# and initializes django for the game directory
|
||||||
|
init_game_directory(CURRENT_DIR, check_db=check_db)
|
||||||
|
|
||||||
|
if args.dummyrunner:
|
||||||
|
# launch the dummy runner
|
||||||
|
run_dummyrunner(args.dummyrunner[0])
|
||||||
|
elif mode == 'menu':
|
||||||
|
# launch menu for operation
|
||||||
|
run_menu()
|
||||||
|
elif mode in ('start', 'reload', 'stop'):
|
||||||
|
# operate the server directly
|
||||||
|
server_operation(mode, service, args.interactive, args.profiler)
|
||||||
|
else:
|
||||||
|
# pass-through to django manager
|
||||||
|
if mode in ('runserver', 'testserver'):
|
||||||
|
print WARNING_RUNSERVER
|
||||||
|
django.core.management.call_command(mode)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# start Evennia from the command line
|
||||||
|
main()
|
||||||
51
evennia/game_template/.gitignore
vendored
Normal file
51
evennia/game_template/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
*.py[cod]
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Packages
|
||||||
|
*.egg
|
||||||
|
*.egg-info
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
eggs
|
||||||
|
parts
|
||||||
|
var
|
||||||
|
sdist
|
||||||
|
develop-eggs
|
||||||
|
.installed.cfg
|
||||||
|
lib
|
||||||
|
lib64
|
||||||
|
__pycache__
|
||||||
|
|
||||||
|
# Other
|
||||||
|
*.swp
|
||||||
|
*.log
|
||||||
|
*.pid
|
||||||
|
*.restart
|
||||||
|
*.db3
|
||||||
|
|
||||||
|
# Installation-specific
|
||||||
|
server/conf/settings.py
|
||||||
|
server/logs/*.log.*
|
||||||
|
web/static/*
|
||||||
|
web/media/*
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
.coverage
|
||||||
|
.tox
|
||||||
|
nosetests.xml
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# PyCharm config
|
||||||
|
.idea
|
||||||
Loading…
Add table
Add a link
Reference in a new issue