Re-organization.

This commit is contained in:
Greg Taylor 2007-04-03 13:42:51 +00:00
parent 5db3ae2933
commit 5421ab7f6e
38 changed files with 0 additions and 0 deletions

View file

@ -1,74 +0,0 @@
Evennia Proof-of-Concept
------------------------
Evennia is a proof-of-concept MUD server written entirely in Python, backed
by SQL. The project rises from a general dissatisfaction with the limitations
of softcode in MUX and MUSH, and the generally inflexible Diku-derivatives and
relatives.
Evennia represents a combination of several technologies, and most importantly
of all, my first venture into codebase design. You may find things within
the source that look strange to you, perhaps not ideally designed. I'm open
to suggestions, but this really is largely an experiment and a learning
experience.
Design Objectives
-----------------
1) To create a MU* server that serves as a great foundation for capable admins
to craft into their respective games. It is not my intention to provide a
full-fledged, ready-to-run base, I'm releasing the means to make such games.
2) Development of games on Evennia must be easy for anyone with some degree
of Python experience. Building needs to be easy, and per-room, per-object,
and environmental customizations need to be simple to do.
3) The server must utilize SQL as a storage back-end to allow for web->game
integration. See the details on Django later on in the document for more
details.
4) Any and all game-specific configuration must reside in SQL, not
external configuration files. The only exception is the settings.py file
containing the SQL information.
How it all Works
----------------
Python (Including the SQL driver of your choice)
|-asynchat (included with Python2)
|-SQL (MySQL, SQLite, Postgresql)
|-Django (http://djangoproject.com)
Evennia is built on top of asynchat, an asynchronous TCP conversation/chat
library. This makes the actual socket/connection handling an absolute
no-brainer.
Serving as our storage medium, SQL is one of the more important and unique
features of the codebase. It allows for very simple code in many cases, and
can lead to a game being a lot more scalable due to the inherent speed of
most modern SQL servers. Another extremely important benefit is that by
storing everything in SQL, we make the entire game accessible from other
means, such as a website. Which leads us to the next component.
Django is perhaps one of the most interesting introductions to the codebase,
since I'm not aware of any other server using it to run MU*'s. Django is
technically a Python web framework, but it also includes a great data modeling
and database abstraction module. This means that things like Players or
Objects can be represented by a very short class, then related to one another.
This allows us to add, remove, delete, and manipulate things in our database
very easily. Another huge benefit is the admin interface that Django more
or less automatically generates for us. Instead of a bunch of clunky admin
commands, you can fire up your web browser and administer pretty much
everything from there, although equivalent in-game commands may be offered.
The possibilities for developing your game's website are nearly endless with
this tandem of MU* server, SQL, and Django.
Support
-------
At this time, I am offering no formal support for Evennia. It is not ready for
use and is subject to change in a major way from week to week. I can't hope
to support such a young product. However, if you have questions or ideas,
please direct them to squishywaffle@gmail.com.
Reporting Bugs
--------------
Feel free to contact me by email at squishywaffle@gmail.com with as much
details on the bug that you can find. Copy/pasting server logs is generally
a good idea.

View file

@ -1,59 +0,0 @@
About Evennia
-------------
Evennia is a proof-of-concept MU* server that aims to provide a functional
base for developers. While there are quite a few codebases that do the same
(and very well in many cases), we are taking a unique spin on the problem.
Some of our flagship features include (or will one day include):
* Extensive web integration.
* The ability to build/administer through a web browser.
* Shared accounts between the website and the game.
* Optional web-based character creation.
* Extremely easy-to-manipulate SQL database back-end via Django
(djangoproject.com)
* Simple and easily extensible design.
* Very granular permissions. Individual and group based.
The essential points here are the web integration and the SQL backing via
Django. The Django framework has database abstraction abilities that give us
many features free, such as:
* The codebase will run transparently on MySQL, SQLite, or Postgres
* At the time of this document's writing, our SQL-backed application here
contains 0 lines of SQL. Django's database abstraction layer is absolutely
simple yet very powerful.
* For any model we outline for the server's use, we have the ability to
more or less automatically generate a web-based admin interface for it with
two lines of code. This lets you Create, Update, or Delete entries.
* On the web-based side of things, features such as automatic form validation,
abstraction of sessions and cookies, and access to whatever game data you
desire are all attractive.
Installation
------------
At this point in time, the codebase is changing so rapidly that writing
installation instructions is pretty much pointless. When we get to that stage
in development, we'll make sure to update this. But for the really determined
(or stubborn), here's a rough outline:
* Install Django.
* Copy the Evennia source somewhere.
* Set up your apache2.conf to point mod-python to the settings.py file if you
want the web features.
* Copy settings.py.dist to settings.py.
* Edit settings.py with your database info.
* Run 'python manage.py syncdb'
* Run prepenv.sh. This will start the MU* server on port 4000 by default. You
may change this via the web interface or by editing the config table in SQL.
Support and Development
-----------------------
Since we're so early in development, we really can't hope to offer much support.
However, if you'd like to report bugs, make suggestions, or help with the
code work, visit either or both of the following links:
* Evennia Code Page
http://code.google.com/p/evennia/
* Evennia Google Group
http://groups-beta.google.com/group/evennia?hl=en

View file

@ -1,31 +0,0 @@
TODO List
---------
The TODO list has all of the things currently needing attention the most in it.
If you are feeling ambitious, tackle as much as you can and send patches
to the project site or via email to gtaylor@clemson.edu.
High Priority Tasks
-------------------
* Pretty much all of the commands need some kind of required permission(s).
Right now, pretty much everyone has access to everything. Django has
a built-in permissions system, it should be trivial to use it for
the purpose.
* Figure out how to handle our scripting support.
* Handle multi-word account names gracefully. Need to modify login prompt
to use quotes like MUX.
* Look into logging in with your email address instead of username.
* Implement @alias. Can probably just use an attribute instead of a new
object DB field. Shouldn't be too bad. Also needs proper search
functions in functions_db.py.
* Implement player to player paging/telling.
* Implement a global comsys of some sort. Use MUX2's commands and stuff.
Medium Priority Tasks
---------------------
* We're going to need a delayed event queue in addition to the scheduler.
For example: I want player X to perform this action in Y seconds.
Low Priority Tasks
------------------
* Write lots of in-game help files.
* Start webbifying the room/thing/exit building process.

View file

@ -1,94 +0,0 @@
import re
"""
ANSI related stuff.
"""
ansi = {}
ansi["beep"] = "\07"
ansi["escape"] = "\033"
ansi["normal"] = "\033[0m"
ansi["underline"] = "\033[4m"
ansi["hilite"] = "\033[1m"
ansi["blink"] = "\033[5m"
ansi["inverse"] = "\033[7m"
ansi["inv_hilite"] = "\033[1;7m"
ansi["inv_blink"] = "\033[7;5m"
ansi["blink_hilite"] = "\033[1;5m"
ansi["inv_blink_hilite"] = "\033[1;5;7m"
# Foreground colors
ansi["black"] = "\033[30m"
ansi["red"] = "\033[31m"
ansi["green"] = "\033[32m"
ansi["yellow"] = "\033[33m"
ansi["blue"] = "\033[34m"
ansi["magenta"] = "\033[35m"
ansi["cyan"] = "\033[36m"
ansi["white"] = "\033[37m"
# Background colors
ansi["back_black"] = "\033[40m"
ansi["back_red"] = "\033[41m"
ansi["back_green"] = "\033[42m"
ansi["back_yellow"] = "\033[43m"
ansi["back_blue"] = "\033[44m"
ansi["back_magenta"] = "\033[45m"
ansi["back_cyan"] = "\033[46m"
ansi["back_white"] = "\033[47m"
# Formatting Characters
ansi["return"] = "\r\n"
ansi["tab"] = "\t"
ansi["space"] = " "
def parse_ansi(string, strip_ansi=False, strip_formatting=False):
"""
Parses a string, subbing color codes as needed.
"""
if strip_formatting:
char_return = ""
char_tab = ""
char_space = ""
else:
char_return = ansi["return"]
char_tab = ansi["tab"]
char_space = ansi["space"]
ansi_subs = [
(r'%r', char_return),
(r'%t', char_tab),
(r'%b', char_space),
(r'%cf', ansi["blink"]),
(r'%ci', ansi["inverse"]),
(r'%ch', ansi["hilite"]),
(r'%cn', ansi["normal"]),
(r'%cx', ansi["black"]),
(r'%cX', ansi["back_black"]),
(r'%cr', ansi["red"]),
(r'%cR', ansi["back_red"]),
(r'%cg', ansi["green"]),
(r'%cG', ansi["back_green"]),
(r'%cy', ansi["yellow"]),
(r'%cY', ansi["back_yellow"]),
(r'%cb', ansi["blue"]),
(r'%cB', ansi["back_blue"]),
(r'%cm', ansi["magenta"]),
(r'%cM', ansi["back_magenta"]),
(r'%cc', ansi["cyan"]),
(r'%cC', ansi["back_cyan"]),
(r'%cw', ansi["white"]),
(r'%cW', ansi["back_white"]),
]
for sub in ansi_subs:
p = re.compile(sub[0], re.DOTALL)
if strip_ansi:
string = p.sub("", string)
else:
string = p.sub(sub[1], string)
if strip_ansi:
return '%s' % (string)
else:
return '%s%s' % (string, ansi["normal"])

View file

@ -1,26 +0,0 @@
from django.db import models
class CommandAlias(models.Model):
"""
Command aliases. If the player enters the value equal to user_input, the
command denoted by equiv_command is used instead.
"""
user_input = models.CharField(maxlength=50)
equiv_command = models.CharField(maxlength=50)
class Admin:
list_display = ('user_input', 'equiv_command',)
class Meta:
verbose_name_plural = "Command aliases"
ordering = ['user_input']
class ConfigValue(models.Model):
"""
Experimental new config model.
"""
conf_key = models.CharField(maxlength=100)
conf_value = models.CharField(maxlength=255 )
class Admin:
list_display = ('conf_key', 'conf_value',)

View file

@ -1 +0,0 @@
# Create your views here.

View file

@ -1,24 +0,0 @@
from django.db import models
class GenericPerm(models.Model):
"""
This is merely a container class for some generic permissions that don't
fit under a particular module.
"""
class Meta:
permissions = (
("announce", "May use @wall to make announcements"),
("boot", "May use @boot to kick players"),
("builder", "May build"),
("chown_all", "Can @chown anything to anyone."),
("control_all", "May control everything"),
("examine_all", "Can examine any object"),
("extended_who", "May see extended WHO list"),
("free_money", "Has infinite money"),
("long_fingers", "May get/look/examine etc. from a distance"),
("steal", "May give negative money"),
("set_hide", "May set themself invisible"),
("shutdown", "May @shutdown the site"),
("tel_anywhere", "May @teleport anywhere"),
("tel_anyone", "May @teleport anything"),
)

View file

@ -1 +0,0 @@
# Create your views here.

View file

@ -1,40 +0,0 @@
from django.db import models
import ansi
class HelpEntry(models.Model):
"""
A generic help entry.
"""
topicname = models.CharField(maxlength=255)
entrytext = models.TextField(blank=True, null=True)
staff_only = models.BooleanField(default=0)
class Admin:
list_display = ('id', 'topicname', 'staff_only')
list_filter = ('staff_only',)
search_fields = ['entrytext']
class Meta:
verbose_name_plural = "Help entries"
ordering = ['topicname']
def __str__(self):
return self.topicname
def get_topicname(self):
"""
Returns the topic's name.
"""
try:
return self.topicname
except:
return None
def get_entrytext_ingame(self):
"""
Gets the entry text for in-game viewing.
"""
try:
return ansi.parse_ansi(self.entrytext)
except:
return None

View file

@ -1 +0,0 @@
# Create your views here.

View file

@ -1,608 +0,0 @@
from django.db import models
from django.contrib.auth.models import User
import defines_global as global_defines
import ansi
class Attribute(models.Model):
"""
Attributes are things that are specific to different types of objects. For
example, a drink container needs to store its fill level, whereas an exit
needs to store its open/closed/locked/unlocked state. These are done via
attributes, rather than making different classes for each object type and
storing them directly. The added benefit is that we can add/remove
attributes on the fly as we like.
"""
name = models.CharField(maxlength=255)
value = models.CharField(maxlength=255)
is_hidden = models.BooleanField(default=0)
object = models.ForeignKey("Object")
def __str__(self):
return "%s(%s)" % (self.name, self.id)
class Admin:
list_display = ('object', 'name', 'value',)
search_fields = ['name']
def get_name(self):
"""
Returns an attribute's name.
"""
return self.name
class Object(models.Model):
"""
The Object class is very generic representation of a THING, PLAYER, EXIT,
ROOM, or other entities within the database. Pretty much anything in the
game is an object. Objects may be one of several different types, and
may be parented to allow for differing behaviors.
We eventually want to find some way to implement object parents via loadable
modules or sub-classing.
"""
name = models.CharField(maxlength=255)
ansi_name = models.CharField(maxlength=255)
owner = models.ForeignKey('self', related_name="obj_owner", blank=True, null=True)
zone = models.ForeignKey('self', related_name="obj_zone", blank=True, null=True)
home = models.ForeignKey('self', related_name="obj_home", blank=True, null=True)
type = models.SmallIntegerField(choices=global_defines.OBJECT_TYPES)
description = models.TextField(blank=True, null=True)
location = models.ForeignKey('self', related_name="obj_location", blank=True, null=True)
flags = models.TextField(blank=True, null=True)
nosave_flags = models.TextField(blank=True, null=True)
date_created = models.DateField(editable=False, auto_now_add=True)
def __cmp__(self, other):
"""
Used to figure out if one object is the same as another.
"""
return self.id == other.id
def __str__(self):
return "%s" % (self.get_name(),)
class Meta:
ordering = ['-date_created', 'id']
class Admin:
list_display = ('id', 'name', 'type', 'date_created')
list_filter = ('type',)
search_fields = ['name']
save_on_top = True
"""
BEGIN COMMON METHODS
"""
def emit_to(self, message):
"""
Emits something to any sessions attached to the object.
message: (str) The message to send
"""
# We won't allow emitting to objects... yet.
if not self.is_player():
return False
session = session_mgr.session_from_object(self)
if session:
session.msg(ansi.parse_ansi(message))
else:
return False
def emit_to_contents(self, message, exclude=None):
"""
Emits something to all objects inside an object.
"""
contents = self.get_contents()
if exclude:
contents.remove(exclude)
for obj in contents:
obj.emit_to(message)
def is_staff(self):
"""
Returns TRUE if the object is a staff player.
"""
if not self.is_player():
return False
profile = User.objects.filter(id=self.id)
if len(profile) == 0:
return False
else:
return profile[0].is_staff
def is_superuser(self):
"""
Returns TRUE if the object is a super user player.
"""
if not self.is_player():
return False
profile = User.objects.filter(id=self.id)
if len(profile) == 0:
return False
else:
return profile[0].is_superuser
def owns_other(self, other_obj):
"""
See if the envoked object owns another object.
other_obj: (Object) Reference for object to check ownership of.
"""
return self.id == other_obj.get_owner().id
def controls_other(self, other_obj):
"""
See if the envoked object controls another object.
other_obj: (Object) Reference for object to check dominance of.
"""
if self == other_obj:
return True
if self.is_superuser():
# Don't allow superusers to dominate other superusers.
if not other_obj.is_superuser():
return True
else:
return False
if self.owns_other(other_obj):
# If said object owns the target, then give it the green.
return True
else:
# Still pending more stuff here, for now assume we have
# dominance. Bad assumption.
return True
def set_home(self, new_home):
"""
Sets an object's home.
"""
self.home = new_home
self.save()
def set_name(self, new_name):
"""
Rename an object.
"""
self.name = ansi.parse_ansi(new_name, strip_ansi=True)
self.ansi_name = ansi.parse_ansi(new_name, strip_formatting=True)
self.save()
# If it's a player, we need to update their user object as well.
if self.is_player():
pobject = User.objects.get(id=self.id)
pobject.name = new_name
pobject.save()
def get_user_account(self):
"""
Returns the player object's account object.
"""
if not self.is_player():
return False
return User.objects.get(id=self.id)
def get_name(self, fullname=False):
"""
Returns an object's name.
"""
if fullname:
return "%s(#%s%s)" % (ansi.parse_ansi(self.name, strip_ansi=True),self.id, self.flag_string())
else:
return "%s(#%s%s)" % (ansi.parse_ansi(self.name.split(';')[0], strip_ansi=True), self.id, self.flag_string())
def get_ansiname(self, fullname=False):
"""
Returns an object's ANSI'd name.
"""
if self.ansi_name:
if fullname:
return "%s(#%s%s)" % (ansi.parse_ansi(self.ansi_name), self.id, self.flag_string())
else:
return "%s(#%s%s)" % (ansi.parse_ansi(self.ansi_name.split(';')[0]), self.id, self.flag_string())
else:
return self.get_name()
def set_description(self, new_desc):
"""
Rename an object.
"""
self.description = new_desc
self.save()
def get_description(self, no_parsing=False, wrap_width=False):
"""
Returns an object's ANSI'd description.
"""
try:
if no_parsing:
retval = self.description
else:
retval = ansi.parse_ansi(self.description)
if wrap_width:
# TODO: Broken for some reason? Returning None.
return functions_general.word_wrap(retval, width=wrap_width)
else:
return retval
except:
return ""
def get_flags(self):
"""
Returns an object's flag list.
"""
flags = self.flags
nosave_flags = self.nosave_flags
if not flags:
flags = ""
if not nosave_flags:
nosave_flags = ""
return '%s %s' % (flags, nosave_flags)
def clear_attribute(self, attribute):
"""
Removes an attribute entirely.
attribute: (str) The attribute's name.
"""
if self.has_attribute(attribute):
attrib_obj = self.get_attribute_obj(attribute)
attrib_obj.delete()
return True
else:
return False
def get_all_attributes(self):
"""
Returns a QuerySet of an object's attributes.
"""
return self.attribute_set.all()
def clear_all_attributes(self):
"""
Clears all of an object's attributes.
"""
attribs = self.get_all_attributes()
for attrib in attribs:
self.delete()
def destroy(self):
"""
Destroys an object, sets it to GOING. Can still be recovered
if the user decides to.
"""
# See if we need to kick the player off.
session = session_mgr.session_from_object(self)
if session:
session.msg("You have been destroyed, goodbye.")
session.handle_close()
# If the object is a player, set the player account object to inactive.
# It can still be recovered at this point.
if self.is_player():
try:
uobj = User.objects.get(id=self.id)
uobj.is_active = False
uobj.save()
except:
functions_general.print_errmsg('Destroying object %s but no matching player.' % (self,))
# Set the object type to GOING
self.type = 5
self.save()
def delete(self):
"""
Deletes an object permanently. Marks it for re-use by a new object.
"""
# Delete the associated player object permanently.
uobj = User.objects.filter(id=self.id)
if len(uobj) > 0:
uobj[0].delete()
# Set the object to type GARBAGE.
self.type = 6
self.save()
self.clear_all_attributes()
def set_attribute(self, attribute, new_value):
"""
Sets an attribute on an object. Creates the attribute if need
be.
attribute: (str) The attribute's name.
new_value: (str) The value to set the attribute to.
"""
if self.has_attribute(attribute):
# Attribute already exists, update it.
attrib_obj = Attribute.objects.filter(object=self).filter(name=attribute)
attrib_obj.value = new_value
attrib_obj.save()
else:
# Attribute object doesn't exist, create it.
new_attrib = Attribute()
new_attrib.name = attribute
new_attrib.value = new_value
new_attrib.object = self
new_attrib.save()
def has_attribute(self, attribute):
"""
See if we have an attribute set on the object.
attribute: (str) The attribute's name.
"""
attr = Attribute.objects.filter(object=self).filter(name=attribute)
if attr.count() == 0:
return False
else:
return True
def has_flag(self, flag):
"""
Does our object have a certain flag?
flag: (str) Flag name
"""
# For whatever reason, we have to do this so things work
# in SQLite.
flags = str(self.flags).split()
nosave_flags = str(self.nosave_flags).split()
return flag in flags or flag in nosave_flags
def set_flag(self, flag, value):
"""
Add a flag to our object's flag list.
flag: (str) Flag name
value: (bool) Set (True) or un-set (False)
"""
flag = flag.upper()
has_flag = self.has_flag(flag)
if value == False and has_flag:
# Clear the flag.
if functions_db.is_unsavable_flag(flag):
# Not a savable flag (CONNECTED, etc)
flags = self.nosave_flags.split()
flags.remove(flag)
self.nosave_flags = ' '.join(flags)
else:
# Is a savable flag.
flags = self.flags.split()
flags.remove(flag)
self.flags = ' '.join(flags)
self.save()
elif value == False and not has_flag:
# Object doesn't have the flag to begin with.
pass
elif value == True and has_flag:
# We've already go it.
pass
else:
# Setting a flag.
if functions_db.is_unsavable_flag(flag):
# Not a savable flag (CONNECTED, etc)
flags = str(self.nosave_flags).split()
flags.append(flag)
self.nosave_flags = ' '.join(flags)
else:
# Is a savable flag.
flags = str(self.flags).split()
flags.append(flag)
self.flags = ' '.join(flags)
self.save()
def is_connected_plr(self):
"""
Is this object a connected player?
"""
if self.is_player():
if session_mgr.session_from_object(self):
return True
else:
return False
else:
return False
def get_owner(self):
"""
Returns an object's owner.
"""
# Players always own themselves.
if self.is_player():
return self
else:
return self.owner
def get_home(self):
"""
Returns an object's home.
"""
try:
return self.home
except:
return None
def get_location(self):
"""
Returns an object's location.
"""
try:
return self.location
except:
return False
def get_attribute_value(self, attrib, default=False):
"""
Returns the value of an attribute on an object.
attrib: (str) The attribute's name.
"""
if self.has_attribute(attrib):
attrib = Attribute.objects.filter(object=self).filter(name=attrib)
attrib_value = attrib[0].value
return attrib_value.value
else:
if default:
return default
else:
return False
def get_attribute_obj(self, attrib):
"""
Returns the attribute object matching the specified name.
attrib: (str) The attribute's name.
"""
if self.has_attribute(attrib):
attrib_obj = Attribute.objects.filter(object=self).filter(name=attrib)
return attrib_obj
else:
return False
def get_contents(self, filter_type=None):
"""
Returns the contents of an object.
filter_type: (int) An object type number to filter by.
"""
if filter_type:
return list(Object.objects.filter(location__id=self.id).filter(type=filter_type))
else:
return list(Object.objects.filter(location__id=self.id).exclude(type__gt=4))
def get_zone(self):
"""
Returns the object that is marked as this object's zone.
"""
try:
return self.zone
except:
return None
def move_to(self, target, quiet=False):
"""
Moves the object to a new location.
target: (Object) Reference to the object to move to.
quiet: (bool) If true, don't emit left/arrived messages.
"""
if not quiet:
if self.get_location():
self.get_location().emit_to_contents("%s has left." % (self.get_ansiname(),), exclude=self)
self.location = target
self.save()
if not quiet:
self.get_location().emit_to_contents("%s has arrived." % (self.get_ansiname(),), exclude=self)
def dbref_match(self, oname):
"""
Check if the input (oname) can be used to identify this particular object
by means of a dbref match.
oname: (str) Name to match against.
"""
if not functions_db.is_dbref(oname):
return False
try:
is_match = int(oname[1:]) == self.id
except ValueError:
return False
return is_match
def name_match(self, oname):
"""
See if the input (oname) can be used to identify this particular object.
Check the # sign for dbref (exact) reference, and anything else is a
name comparison.
NOTE: A 'name' can be a dbref or the actual name of the object. See
dbref_match for an exclusively name-based match.
"""
if oname[0] == '#':
return self.dbref_match(oname)
else:
return oname.lower() in self.name.lower()
def filter_contents_from_str(self, oname):
"""
Search an object's contents for name and dbref matches. Don't put any
logic in here, we'll do that from the end of the command or function.
oname: (str) The string to filter from.
"""
contents = self.get_contents()
return [prospect for prospect in contents if prospect.name_match(oname)]
# Type comparison methods.
def is_player(self):
return self.type == 1
def is_room(self):
return self.type == 2
def is_thing(self):
return self.type == 3
def is_exit(self):
return self.type == 4
def is_going(self):
return self.type == 5
def is_garbage(self):
return self.type == 6
def get_type(self, return_number=False):
"""
Returns the numerical or string representation of an object's type.
return_number: (bool) True returns numeric type, False returns string.
"""
if return_number:
return self.type
else:
return global_defines.OBJECT_TYPES[self.type][1]
def is_type(self, otype):
"""
See if an object is a certain type.
otype: (str) A string representation of the object's type (ROOM, THING)
"""
otype = otype[0]
if otype == 'p':
return self.is_player()
elif otype == 'r':
return self.is_room()
elif otype == 't':
return self.is_thing()
elif otype == 'e':
return self.is_exit()
elif otype == 'g':
return self.is_garbage()
def flag_string(self):
"""
Returns the flag string for an object. This abbreviates all of the flags
set on the object into a list of single-character flag characters.
"""
# We have to cast this because the admin interface is really picky
# about tuple index types. Bleh.
otype = int(self.type)
return global_defines.OBJECT_TYPES[otype][1][0]
import functions_db
import functions_general
import session_mgr

View file

@ -1 +0,0 @@
# Create your views here.

View file

@ -1,92 +0,0 @@
import commands_privileged
import commands_general
import commands_unloggedin
import functions_db
"""
This is the command processing module. It is instanced once in the main
server module and the handle() function is hit every time a player sends
something.
"""
class UnknownCommand(Exception):
"""
Throw this when a user enters an an invalid command.
"""
def match_exits(pobject, searchstr):
"""
See if we can find an input match to exits.
"""
exits = pobject.get_location().get_contents(filter_type=4)
return functions_db.list_search_object_namestr(exits, searchstr)
def handle(cdat):
"""
Use the spliced (list) uinput variable to retrieve the correct
command, or return an invalid command error.
We're basically grabbing the player's command by tacking
their input on to 'cmd_' and looking it up in the GenCommands
class.
"""
session = cdat['session']
server = cdat['server']
try:
# TODO: Protect against non-standard characters.
if cdat['uinput'] == '':
raise UnknownCommand
uinput = cdat['uinput'].split()
parsed_input = {}
# First we split the input up by spaces.
parsed_input['splitted'] = uinput
# Now we find the root command chunk (with switches attached).
parsed_input['root_chunk'] = parsed_input['splitted'][0].split('/')
# And now for the actual root command. It's the first entry in root_chunk.
parsed_input['root_cmd'] = parsed_input['root_chunk'][0].lower()
# Now we'll see if the user is using an alias. We do a dictionary lookup,
# if the key (the player's root command) doesn't exist on the dict, we
# don't replace the existing root_cmd. If the key exists, its value
# replaces the previously splitted root_cmd. For example, sa -> say.
alias_list = server.cmd_alias_list
parsed_input['root_cmd'] = alias_list.get(parsed_input['root_cmd'],parsed_input['root_cmd'])
if session.logged_in:
# If it's prefixed by an '@', it's a staff command.
if parsed_input['root_cmd'][0] != '@':
cmd = getattr(commands_general, 'cmd_%s' % (parsed_input['root_cmd'],), None )
else:
parsed_input['root_cmd'] = parsed_input['root_cmd'][1:]
cmd = getattr(commands_privileged, 'cmd_%s' % (parsed_input['root_cmd'],), None )
else:
cmd = getattr(commands_unloggedin, 'cmd_%s' % (parsed_input['root_cmd'],), None )
if callable(cmd):
cdat['uinput'] = parsed_input
cmd(cdat)
return
if session.logged_in:
# If we're not logged in, don't check exits.
pobject = session.get_pobject()
exit_matches = match_exits(pobject, ' '.join(parsed_input['splitted']))
if exit_matches:
exit = exit_matches[0]
if exit.get_home():
cdat['uinput'] = parsed_input
pobject.move_to(exit.get_home())
commands_general.cmd_look(cdat)
else:
session.msg("That exit leads to nowhere.")
return
# If we reach this point, we haven't matched anything.
raise UnknownCommand
except UnknownCommand:
session.msg("Unknown command.")

View file

@ -1,361 +0,0 @@
import settings
import time
import functions_general
import functions_db
import functions_help
import defines_global as global_defines
import session_mgr
import ansi
import os
"""
Generic command module. Pretty much every command should go here for
now.
"""
def cmd_idle(cdat):
"""
Returns nothing, this lets the player set an idle timer without spamming
his screen.
"""
pass
def cmd_inventory(cdat):
"""
Shows a player's inventory.
"""
session = cdat['session']
pobject = session.get_pobject()
session.msg("You are carrying:")
for item in pobject.get_contents():
session.msg(" %s" % (item.get_ansiname(),))
money = pobject.get_attribute_value("MONEY", default=0)
if money > 0:
money_name = functions_db.get_server_config("MONEY_NAME_PLURAL")
else:
money_name = functions_db.get_server_config("MONEY_NAME_SINGULAR")
session.msg("You have %d %s." % (money,money_name))
def cmd_look(cdat):
"""
Handle looking at objects.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
target_obj = pobject.get_location()
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
target_obj = results[0]
retval = "%s\r\n%s" % (
target_obj.get_ansiname(),
target_obj.get_description(),
)
session.msg(retval)
con_players = []
con_things = []
con_exits = []
for obj in target_obj.get_contents():
if obj.is_player():
if obj != pobject and obj.is_connected_plr():
con_players.append(obj)
elif obj.is_exit():
con_exits.append(obj)
else:
con_things.append(obj)
if con_players:
session.msg("%sPlayers:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
for player in con_players:
session.msg('%s' %(player.get_ansiname(),))
if con_things:
session.msg("%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
for thing in con_things:
session.msg('%s' %(thing.get_ansiname(),))
if con_exits:
session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
for exit in con_exits:
session.msg('%s' %(exit.get_ansiname(),))
def cmd_get(cdat):
"""
Get an object and put it in a player's inventory.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
plr_is_staff = pobject.is_staff()
if len(args) == 0:
session.msg("Get what?")
return
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args), search_contents=False)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
# We've got a victim to get now.
target_obj = results[0]
if pobject == target_obj:
session.msg("You can't get yourself.")
return
if not plr_is_staff and (target_obj.is_player() or target_obj.is_exit()):
session.msg("You can't get that.")
return
if target_obj.is_room() or target_obj.is_garbage() or target_obj.is_going():
session.msg("You can't get that.")
return
target_obj.move_to(pobject, quiet=True)
session.msg("You pick up %s." % (target_obj.get_ansiname(),))
pobject.get_location().emit_to_contents("%s picks up %s." % (pobject.get_ansiname(), target_obj.get_ansiname()), exclude=pobject)
def cmd_drop(cdat):
"""
Drop an object from a player's inventory into their current location.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
plr_is_staff = pobject.is_staff()
if len(args) == 0:
session.msg("Drop what?")
return
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args), search_location=False)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("You don't appear to be carrying that.")
return
else:
# We've got a victim to get now.
target_obj = results[0]
if not pobject == target_obj.get_location():
session.msg("You don't appear to be carrying that.")
return
target_obj.move_to(pobject.get_location(), quiet=True)
session.msg("You drop %s." % (target_obj.get_ansiname(),))
pobject.get_location().emit_to_contents("%s drops %s." % (pobject.get_ansiname(), target_obj.get_ansiname()), exclude=pobject)
def cmd_examine(cdat):
"""
Detailed object examine command
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
target_obj = pobject.get_location()
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
target_obj = results[0]
session.msg("%s\r\n%s" % (
target_obj.get_ansiname(fullname=True),
target_obj.get_description(no_parsing=True),
))
session.msg("Type: %s Flags: %s" % (target_obj.get_type(), target_obj.get_flags()))
session.msg("Owner: %s " % (target_obj.get_owner(),))
session.msg("Zone: %s" % (target_obj.get_zone(),))
for attribute in target_obj.get_all_attributes():
session.msg("%s%s%s: %s" % (ansi.ansi["hilite"], attribute.get_name(), ansi.ansi["normal"], attribute.value))
con_players = []
con_things = []
con_exits = []
for obj in target_obj.get_contents():
if obj.is_player():
con_players.append(obj)
elif obj.is_exit():
con_exits.append(obj)
elif obj.is_thing():
con_things.append(obj)
if con_players or con_things:
session.msg("%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
for player in con_players:
session.msg('%s' % (player.get_ansiname(fullname=True),))
for thing in con_things:
session.msg('%s' % (thing.get_ansiname(fullname=True),))
if con_exits:
session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
for exit in con_exits:
session.msg('%s' %(exit.get_ansiname(fullname=True),))
if not target_obj.is_room():
if target_obj.is_exit():
session.msg("Destination: %s" % (target_obj.get_home(),))
else:
session.msg("Home: %s" % (target_obj.get_home(),))
session.msg("Location: %s" % (target_obj.get_location(),))
def cmd_quit(cdat):
"""
Gracefully disconnect the user as per his own request.
"""
session = cdat['session']
session.msg("Quitting!")
session.handle_close()
def cmd_who(cdat):
"""
Generic WHO command.
"""
session_list = session_mgr.get_session_list()
session = cdat['session']
pobject = session.get_pobject()
retval = "Player Name On For Idle Room Cmds Host\n\r"
for player in session_list:
if not player.logged_in:
continue
delta_cmd = time.time() - player.cmd_last
delta_conn = time.time() - player.conn_time
plr_pobject = player.get_pobject()
retval += '%-16s%9s %4s%-3s#%-6d%5d%3s%-25s\r\n' % \
(plr_pobject.get_name(), \
# On-time
functions_general.time_format(delta_conn,0), \
# Idle time
functions_general.time_format(delta_cmd,1), \
# Flags
'', \
# Location
plr_pobject.get_location().id, \
player.cmd_total, \
# More flags?
'', \
player.address[0])
retval += '%d Players logged in.' % (len(session_list),)
session.msg(retval)
def cmd_say(cdat):
"""
Room-based speech command.
"""
session_list = session_mgr.get_session_list()
session = cdat['session']
pobject = session.get_pobject()
speech = ' '.join(cdat['uinput']['splitted'][1:])
players_present = [player for player in session_list if player.get_pobject().get_location() == session.get_pobject().get_location() and player != session]
retval = "You say, '%s'" % (speech,)
for player in players_present:
player.msg("%s says, '%s'" % (pobject.get_name(), speech,))
session.msg(retval)
def cmd_help(cdat):
"""
Help system commands.
"""
session = cdat['session']
pobject = session.get_pobject()
topicstr = ' '.join(cdat['uinput']['splitted'][1:])
if len(topicstr) == 0:
topicstr = "Help Index"
elif len(topicstr) < 2 and not topicstr.isdigit():
session.msg("Your search query is too short. It must be at least three letters long.")
return
topics = functions_help.find_topicmatch(pobject, topicstr)
if len(topics) == 0:
session.msg("No matching topics found, please refine your search.")
suggestions = functions_help.find_topicsuggestions(pobject, topicstr)
if len(suggestions) > 0:
session.msg("Matching similarly named topics:")
for result in suggestions:
session.msg(" %s" % (result,))
session.msg("You may type 'help <#>' to see any of these topics.")
elif len(topics) > 1:
session.msg("More than one match found:")
for result in topics:
session.msg("%3d. %s" % (result.id, result.get_topicname()))
session.msg("You may type 'help <#>' to see any of these topics.")
else:
topic = topics[0]
session.msg("\r\n%s%s%s" % (ansi.ansi["hilite"], topic.get_topicname(), ansi.ansi["normal"]))
session.msg(topic.get_entrytext_ingame())
def cmd_version(cdat):
"""
Version info command.
"""
session = cdat['session']
retval = "-"*50 +"\n\r"
retval += "Evennia %s\n\r" % (global_defines.EVENNIA_VERSION,)
retval += "-"*50
session.msg(retval)
def cmd_time(cdat):
"""
Server local time.
"""
session = cdat['session']
session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),)))
def cmd_uptime(cdat):
"""
Server uptime and stats.
"""
session = cdat['session']
server = cdat['server']
start_delta = time.time() - server.start_time
loadavg = os.getloadavg()
session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),)))
session.msg('Server start time : %s' % (time.strftime('%a %b %d %H:%M %Y', time.localtime(server.start_time),)))
session.msg('Server uptime : %s' % functions_general.time_format(start_delta, style=2))
session.msg('Server load (1 min) : %.2f' % loadavg[0])

View file

@ -1,640 +0,0 @@
import os
import resource
import functions_db
import functions_general
import commands_general
import commands_unloggedin
import cmdhandler
import session_mgr
import ansi
import defines_global
from django.contrib.auth.models import User
from apps.objects.models import Object
"""
Any command here is prefixed by an '@' sign, usually denoting a
builder, staff or otherwise manipulative command that doesn't fall within
the scope of normal gameplay.
"""
def cmd_destroy(cdat):
"""
Destroy an object.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
switches = cdat['uinput']['root_chunk'][1:]
switch_override = False
if "override" in switches:
switch_override = True
if len(args) == 0:
session.msg("Destroy what?")
return
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
elif results[0].is_player():
if pobject.id == results[0].id:
session.msg("You can't destroy yourself.")
return
if not switch_override:
session.msg("You must use @destroy/override on players.")
return
if results[0].is_superuser():
session.msg("You can't destroy a superuser.")
return
target_obj = results[0]
elif results[0].is_going():
session.msg("That object is already destroyed.")
return
elif results[0].is_garbage():
session.msg("That object is already destroyed.")
return
else:
target_obj = results[0]
session.msg("You destroy %s." % (target_obj,))
target_obj.destroy()
def cmd_list(cdat):
"""
Shows some game related information.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
argstr = ''.join(args)
msg_invalid = "Unknown option. Use one of: commands, flags, process"
if len(argstr) == 0:
session.msg(msg_invalid)
elif argstr == "commands":
session.msg('Commands: '+' '.join(functions_general.command_list()))
elif argstr == "process":
loadvg = os.getloadavg()
psize = resource.getpagesize()
rusage = resource.getrusage(resource.RUSAGE_SELF)
session.msg("Process ID: %10d %10d bytes per page" % (os.getpid(), psize))
session.msg("Time used: %10d user %10d sys" % (rusage[0],rusage[1]))
session.msg("Integral mem:%10d shared %10d private%10d stack" % (rusage[3], rusage[4], rusage[5]))
session.msg("Max res mem: %10d pages %10d bytes" % (rusage[2],rusage[2] * psize))
session.msg("Page faults: %10d hard %10d soft %10d swapouts" % (rusage[7], rusage[6], rusage[8]))
session.msg("Disk I/O: %10d reads %10d writes" % (rusage[9], rusage[10]))
session.msg("Network I/O: %10d in %10d out" % (rusage[12], rusage[11]))
session.msg("Context swi: %10d vol %10d forced %10d sigs" % (rusage[14], rusage[15], rusage[13]))
elif argstr == "flags":
session.msg("Flags: "+" ".join(defines_global.SERVER_FLAGS))
else:
session.msg(msg_invalid)
def cmd_description(cdat):
"""
Set an object's description.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
eq_args = ' '.join(args).split('=')
searchstring = ''.join(eq_args[0])
if len(args) == 0:
session.msg("What do you want to describe?")
elif len(eq_args) < 2:
session.msg("How would you like to describe that object?")
else:
results = functions_db.local_and_global_search(pobject, searchstring)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
new_desc = '='.join(eq_args[1:])
target_obj = results[0]
session.msg("%s - DESCRIPTION set." % (target_obj,))
target_obj.set_description(new_desc)
def cmd_newpassword(cdat):
"""
Set a player's password.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
eq_args = ' '.join(args).split('=')
searchstring = ''.join(eq_args[0])
newpass = ''.join(eq_args[1:])
if len(args) == 0:
session.msg("What player's password do you want to change")
return
if len(newpass) == 0:
session.msg("You must supply a new password.")
return
results = functions_db.local_and_global_search(pobject, searchstring)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
elif len(results) == 0:
session.msg("I don't see that here.")
elif not pobject.controls_other(results[0]):
session.msg("You do not control %s." % (results[0],))
else:
uaccount = results[0].get_user_account()
if len(newpass) == 0:
uaccount.set_password()
else:
uaccount.set_password(newpass)
uaccount.save()
session.msg("%s - PASSWORD set." % (results[0],))
results[0].emit_to("%s has changed your password." % (pobject,))
def cmd_password(cdat):
"""
Changes your own password.
@newpass <Oldpass>=<Newpass>
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
eq_args = ' '.join(args).split('=')
oldpass = ''.join(eq_args[0])
newpass = ''.join(eq_args[1:])
if len(oldpass) == 0:
session.msg("You must provide your old password.")
elif len(newpass) == 0:
session.msg("You must provide your new password.")
else:
uaccount = User.objects.get(id=pobject.id)
if not uaccount.check_password(oldpass):
session.msg("The specified old password isn't correct.")
elif len(newpass) < 3:
session.msg("Passwords must be at least three characters long.")
return
else:
uaccount.set_password(newpass)
uaccount.save()
session.msg("Password changed.")
def cmd_name(cdat):
"""
Handle naming an object.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
eq_args = ' '.join(args).split('=')
searchstring = ''.join(eq_args[0])
if len(args) == 0:
session.msg("What do you want to name?")
elif len(eq_args) < 2:
session.msg("What would you like to name that object?")
else:
results = functions_db.local_and_global_search(pobject, searchstring)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
elif len(eq_args[1]) == 0:
session.msg("What would you like to name that object?")
else:
newname = '='.join(eq_args[1:])
target_obj = results[0]
session.msg("You have renamed %s to %s." % (target_obj, ansi.parse_ansi(newname, strip_formatting=True)))
target_obj.set_name(newname)
def cmd_dig(cdat):
"""
Creates a new object of type 'ROOM'.
"""
session = cdat['session']
pobject = session.get_pobject()
uinput= cdat['uinput']['splitted']
roomname = ' '.join(uinput[1:])
if roomname == '':
session.msg("You must supply a name!")
else:
# Create and set the object up.
odat = {"name": roomname, "type": 2, "location": None, "owner": pobject}
new_object = functions_db.create_object(odat)
session.msg("You create a new room: %s" % (new_object,))
def cmd_emit(cdat):
"""
Emits something to your location.
"""
session = cdat['session']
pobject = session.get_pobject()
uinput= cdat['uinput']['splitted']
message = ' '.join(uinput[1:])
if message == '':
session.msg("Emit what?")
else:
pobject.get_location().emit_to_contents(message)
def cmd_create(cdat):
"""
Creates a new object of type 'THING'.
"""
session = cdat['session']
server = session.server
pobject = session.get_pobject()
uinput= cdat['uinput']['splitted']
thingname = ' '.join(uinput[1:])
if thingname == '':
session.msg("You must supply a name!")
else:
# Create and set the object up.
odat = {"name": thingname, "type": 3, "location": pobject, "owner": pobject}
new_object = functions_db.create_object(odat)
session.msg("You create a new thing: %s" % (new_object,))
def cmd_nextfree(cdat):
"""
Returns the next free object number.
"""
session = cdat['session']
nextfree = functions_db.get_nextfree_dbnum()
if str(nextfree).isdigit():
retval = "Next free object number: #%s" % (nextfree,)
else:
retval = "Next free object number: #%s (GARBAGE)" % (nextfree.id,)
session.msg(retval)
def cmd_open(cdat):
"""
Handle the opening of exits.
Forms:
@open <Name>
@open <Name>=<Dbref>
@open <Name>=<Dbref>,<Name>
"""
session = cdat['session']
pobject = session.get_pobject()
server = cdat['server']
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Open an exit to where?")
return
eq_args = args[0].split('=')
exit_name = eq_args[0]
if len(exit_name) == 0:
session.msg("You must supply an exit name.")
return
# If we have more than one entry in our '=' delimited argument list,
# then we're doing a @open <Name>=<Dbref>[,<Name>]. If not, we're doing
# an un-linked exit, @open <Name>.
if len(eq_args) > 1:
# Opening an exit to another location via @open <Name>=<Dbref>[,<Name>].
comma_split = eq_args[1].split(',')
destination = functions_db.local_and_global_search(pobject, comma_split[0])
if len(destination) == 0:
session.msg("I can't find the location to link to.")
return
elif len(destination) > 1:
session.msg("Multiple results returned for exit destination!")
else:
destination = destination[0]
if destination.is_exit():
session.msg("You can't open an exit to an exit!")
return
odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":destination}
new_object = functions_db.create_object(odat)
session.msg("You open the exit - %s" % (new_object,))
if len(comma_split) > 1:
second_exit_name = ','.join(comma_split[1:])
odat = {"name": second_exit_name, "type": 4, "location": destination, "owner": pobject, "home": pobject.get_location()}
new_object = functions_db.create_object(odat)
else:
# Create an un-linked exit.
odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":None}
new_object = functions_db.create_object(odat)
session.msg("You open an unlinked exit - %s" % (new_object,))
def cmd_link(cdat):
"""
Sets an object's home or an exit's destination.
Forms:
@link <Object>=<Target>
"""
session = cdat['session']
pobject = session.get_pobject()
server = cdat['server']
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Link what?")
return
eq_args = args[0].split('=')
target_name = eq_args[0]
dest_name = '='.join(eq_args[1:])
if len(target_name) == 0:
session.msg("What do you want to link?")
return
if len(eq_args) > 1:
target = functions_db.local_and_global_search(pobject, target_name)
if len(target) == 0:
session.msg("I can't find the object you want to link.")
return
elif len(target) > 1:
session.msg("Multiple results returned for link target.")
return
# We know we can get the first entry now.
target = target[0]
# If we do something like "@link blah=", we unlink the object.
if len(dest_name) == 0:
target.set_home(None)
session.msg("You have unlinked %s." % (target,))
return
destination = functions_db.local_and_global_search(pobject, dest_name)
if len(destination) == 0:
session.msg("I can't find the location to link to.")
return
elif len(destination) > 1:
session.msg("Multiple results returned for destination.")
return
destination = destination[0]
target.set_home(destination)
session.msg("You link %s to %s." % (target,destination))
else:
# We haven't provided a target.
session.msg("You must provide a destination to link to.")
return
def cmd_unlink(cdat):
"""
Unlinks an object.
"""
session = cdat['session']
pobject = session.get_pobject()
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Unlink what?")
return
else:
results = functions_db.local_and_global_search(pobject, ' '.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
return
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
results[0].set_home(None)
session.msg("You have unlinked %s." % (results[0],))
def cmd_teleport(cdat):
"""
Teleports an object somewhere.
"""
session = cdat['session']
pobject = session.get_pobject()
server = cdat['server']
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Teleport where/what?")
return
eq_args = args[0].split('=')
search_str = ''.join(args)
# If we have more than one entry in our '=' delimited argument list,
# then we're doing a @tel <victim>=<location>. If not, we're doing
# a direct teleport, @tel <destination>.
if len(eq_args) > 1:
# Equal sign teleport.
victim = functions_db.local_and_global_search(pobject, eq_args[0])
destination = functions_db.local_and_global_search(pobject, eq_args[1])
if len(victim) == 0:
session.msg("I can't find the victim to teleport.")
return
elif len(destination) == 0:
session.msg("I can't find the destination for the victim.")
return
elif len(victim) > 1:
session.msg("Multiple results returned for victim!")
return
elif len(destination) > 1:
session.msg("Multiple results returned for destination!")
else:
if victim == destination:
session.msg("You can't teleport an object inside of itself!")
return
session.msg("Teleported.")
victim[0].move_to(destination[0])
# This is somewhat kludgy right now, we'll have to find a better way
# to do it sometime else. If we can find a session in the server's
# session list matching the object we're teleporting, force it to
# look. This is going to typically be a player.
victim_session = session_mgr.session_from_object(victim[0])
if victim_session:
# We need to form up a new cdat dictionary to pass with the command.
# Kinda yucky I guess.
cdat2 = {"server": server, "uinput": 'look', "session": victim_session}
cmdhandler.handle(cdat2)
else:
# Direct teleport (no equal sign)
results = functions_db.local_and_global_search(pobject, search_str)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s" % (result.get_ansiname(),))
elif len(results) == 0:
session.msg("I don't see that here.")
return
else:
if results[0] == pobject:
session.msg("You can't teleport inside yourself!")
return
session.msg("Teleported.")
pobject.move_to(results[0])
commands_general.cmd_look(cdat)
def cmd_set(cdat):
"""
Sets flags or attributes on objects.
"""
session = cdat['session']
pobject = session.get_pobject()
server = cdat['server']
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Set what?")
return
# There's probably a better way to do this. Break the arguments (minus
# the root command) up so we have two items in the list, 0 being the victim,
# 1 being the list of flags or the attribute/value pair.
eq_args = ' '.join(args).split('=')
if len(eq_args) < 2:
session.msg("Set what?")
return
victim = functions_db.local_and_global_search(pobject, eq_args[0])
if len(victim) == 0:
session.msg("I don't see that here.")
return
elif len(victim) > 1:
session.msg("I don't know which one you mean!")
return
victim = victim[0]
attrib_args = eq_args[1].split(':')
if len(attrib_args) > 1:
# We're dealing with an attribute/value pair.
attrib_name = attrib_args[0].upper()
splicenum = eq_args[1].find(':') + 1
attrib_value = eq_args[1][splicenum:]
# In global_defines.py, see NOSET_ATTRIBS for protected attribute names.
if not functions_db.is_modifiable_attrib(attrib_name):
session.msg("You can't modify that attribute.")
return
if attrib_value:
# An attribute value was specified, create or set the attribute.
verb = 'set'
victim.set_attribute(attrib_name, attrib_value)
else:
# No value was given, this means we delete the attribute.
verb = 'cleared'
victim.clear_attribute(attrib_name)
session.msg("%s - %s %s." % (victim.get_name(), attrib_name, verb))
else:
# Flag manipulation form.
flag_list = eq_args[1].split()
for flag in flag_list:
flag = flag.upper()
if flag[0] == '!':
# We're un-setting the flag.
flag = flag[1:]
if not functions_db.is_modifiable_flag(flag):
session.msg("You can't set/unset the flag - %s." % (flag,))
else:
session.msg('%s - %s cleared.' % (victim.get_name(), flag.upper(),))
victim.set_flag(flag, False)
else:
# We're setting the flag.
if not functions_db.is_modifiable_flag(flag):
session.msg("You can't set/unset the flag - %s." % (flag,))
else:
session.msg('%s - %s set.' % (victim.get_name(), flag.upper(),))
victim.set_flag(flag, True)
def cmd_find(cdat):
"""
Searches for an object of a particular name.
"""
session = cdat['session']
server = cdat['server']
searchstring = ' '.join(cdat['uinput']['splitted'][1:])
if searchstring == '':
session.msg("No search pattern given.")
return
results = functions_db.global_object_name_search(searchstring)
if len(results) > 0:
session.msg("Name matches for: %s" % (searchstring,))
for result in results:
session.msg(" %s" % (result.get_ansiname(fullname=True),))
session.msg("%d matches returned." % (len(results),))
else:
session.msg("No name matches found for: %s" % (searchstring,))
def cmd_wall(cdat):
"""
Announces a message to all connected players.
"""
session = cdat['session']
wallstring = ' '.join(cdat['uinput']['splitted'][1:])
if wallstring == '':
session.msg("Announce what?")
return
message = "%s shouts \"%s\"" % (session.get_pobject().get_name(), wallstring)
functions_general.announce_all(message)
def cmd_shutdown(cdat):
"""
Shut the server down gracefully.
"""
session = cdat['session']
server = cdat['server']
session.msg('Shutting down...')
print 'Server shutdown by %s(#%d)' % (session.get_pobject().get_name(), session.get_pobject().id,)
server.shutdown()

View file

@ -1,63 +0,0 @@
from django.contrib.auth.models import User
import functions_db
"""
Commands that are available from the connect screen.
"""
def cmd_connect(cdat):
"""
This is the connect command at the connection screen. Fairly simple,
uses the Django database API and User model to make it extremely simple.
"""
session = cdat['session']
uname = cdat['uinput']['splitted'][1]
password = cdat['uinput']['splitted'][2]
account = User.objects.filter(username__iexact=uname)
autherror = "Invalid username or password!"
# No username match
if account.count() == 0:
session.msg(autherror)
return
# We have at least one result, so we can check hte password.
user = account[0]
if not user.check_password(password):
session.msg(autherror)
else:
user = account[0]
uname = user.username
session.login(user)
def cmd_create(cdat):
"""
Handle the creation of new accounts.
"""
session = cdat['session']
server = session.server
uname = cdat['uinput']['splitted'][1]
email = cdat['uinput']['splitted'][2]
password = cdat['uinput']['splitted'][3]
# Search for a user object with the specified username.
account = User.objects.filter(username=uname)
if not account.count() == 0:
session.msg("There is already a player with that name!")
elif len(password) < 3:
session.msg("Your password must be 3 characters or longer.")
else:
functions_db.create_user(cdat, uname, email, password)
def cmd_quit(cdat):
"""
We're going to maintain a different version of the quit command
here for unconnected users for the sake of simplicity. The logged in
version will be a bit more complicated.
"""
session = cdat['session']
session.msg("Disconnecting...")
session.handle_close()

View file

@ -1,26 +0,0 @@
# Do not mess with the default types (0-5).
OBJECT_TYPES = (
(0, 'NOTHING'),
(1, 'PLAYER'),
(2, 'ROOM'),
(3, 'THING'),
(4, 'EXIT'),
(5, 'GOING'),
(6, 'GARBAGE'),
)
# This is a list of flags that the server actually uses. Anything not in this
# list is a custom flag.
SERVER_FLAGS = ["CONNECTED", "DARK", "FLOATING", "GAGGED", "HAVEN", "OPAQUE", "SAFE", "SLAVE", "SUSPECT", "TRANSPARENT"]
# These flags are not saved.
NOSAVE_FLAGS = ["CONNECTED"]
# These flags can't be modified by players.
NOSET_FLAGS = ["CONNECTED"]
# These attribute names can't be modified by players.
NOSET_ATTRIBS = ["MONEY", "ALIAS"]
# Server version number.
EVENNIA_VERSION = 'Pre-Alpha'

Binary file not shown.

View file

@ -1,40 +0,0 @@
# Add this vhost file to your Apache sites-enabled directory, typically found
# at /etc/apache2/sites-enabled. You'll need to go through and change the
# /home/evennia to point to the correct home directory, and the evennia
# subdir must be under that home directory.
# A NOTE ON IMAGES/CSS: These files must be handled separately from the actual
# dynamic content which is interpreted by Python. You may host these static
# images/css from the same server or a different one. The static media
# is served from /home/evennia/evennia/media. The easiest way to serve
# this stuff is by either hosting them remotely or symlinking
# the media directory into an existing Apache site's directory.
# A NOTE ON ADMIN IMAGES/CSS: You'll need to create a symlink called
# 'amedia' under the media directory if you want to use the admin interface.
# This can be found in the Django package in your Python path. For example,
# the default is: /usr/lib/python2.4/site-packages/django/contrib/admin/media/
# although your location may vary.
<VirtualHost *>
# Set ServerName and ServerAdmin appropriately
ServerName evennia.somewhere.com
ServerAdmin someone@somewhere.com
DocumentRoot /home/evennia/evennia
<Directory "/home/evennia/evennia">
SetHandler python-program
PythonHandler django.core.handlers.modpython
PythonPath "['/home/evennia/evennia'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE settings
PythonDebug On
</Directory>
Alias /media/ "/home/evennia/evennia/media/"
<Directory "/home/evennia/evennia/media/">
SetHandler None
</Directory>
<LocationMatch "\.(jpg|gif|png|css)$">
SetHandler None
</LocationMatch>
</VirtualHost>

View file

@ -1,15 +0,0 @@
"""
Holds the events scheduled in scheduler.py.
"""
schedule = {
'event_example': 60,
}
lastrun = {}
def event_example():
"""
This is where the example event would be placed.
"""
pass

View file

@ -1,222 +0,0 @@
import sets
from django.db import connection
from django.contrib.auth.models import User
from apps.objects.models import Object
from apps.config.models import ConfigValue
import defines_global as global_defines
import gameconf
"""
Common database functions.
"""
def get_server_config(configname):
"""
Returns a server config value.
"""
return ConfigValue.objects.get(conf_key__iexact=configname).conf_value
def is_unsavable_flag(flagname):
"""
Returns TRUE if the flag is an unsavable flag.
"""
return flagname in global_defines.NOSAVE_FLAGS
def is_modifiable_flag(flagname):
"""
Check to see if a particular flag is modifiable.
"""
if flagname not in global_defines.NOSET_FLAGS:
return True
else:
return False
def is_modifiable_attrib(attribname):
"""
Check to see if a particular attribute is modifiable.
"""
if attribname not in global_defines.NOSET_ATTRIBS:
return True
else:
return False
def get_nextfree_dbnum():
"""
Figure out what our next free database reference number is.
If we need to recycle a GARBAGE object, return the object to recycle
Otherwise, return the first free dbref.
"""
# First we'll see if there's an object of type 6 (GARBAGE) that we
# can recycle.
nextfree = Object.objects.filter(type__exact=6)
if nextfree:
# We've got at least one garbage object to recycle.
return nextfree[0]
else:
# No garbage to recycle, find the highest dbnum and increment it
# for our next free.
return int(Object.objects.order_by('-id')[0].id + 1)
def global_object_name_search(ostring):
"""
Searches through all objects for a name match.
"""
return Object.objects.filter(name__icontains=ostring).exclude(type=6)
def list_search_object_namestr(searchlist, ostring, dbref_only=False):
"""
Iterates through a list of objects and returns a list of
name matches.
"""
if dbref_only:
return [prospect for prospect in searchlist if prospect.dbref_match(ostring)]
else:
return [prospect for prospect in searchlist if prospect.name_match(ostring)]
def local_and_global_search(searcher, ostring, search_contents=True, search_location=True, dbref_only=False):
"""
Searches an object's location then globally for a dbref or name match.
search_contents: (bool) While true, check the contents of the searcher.
search_location: (bool) While true, check the searcher's surroundings.
"""
search_query = ''.join(ostring)
# This is a global dbref search. Not applicable if we're only searching
# searcher's contents/locations, dbref comparisons for location/contents
# searches are handled by list_search_object_namestr() below.
if is_dbref(ostring) and search_contents and search_location:
search_num = search_query[1:]
dbref_match = list(Object.objects.filter(id=search_num).exclude(type=6))
if len(dbref_match) > 0:
return dbref_match
local_matches = []
# Handle our location/contents searches. list_search_object_namestr() does
# name and dbref comparisons against search_query.
if search_contents:
local_matches += list_search_object_namestr(searcher.get_contents(), search_query)
if search_location:
local_matches += list_search_object_namestr(searcher.get_location().get_contents(), search_query)
# If the object the invoker is in matches, add it as well.
if searcher.get_location().dbref_match(ostring) or ostring == 'here':
local_matches.append(searcher.get_location())
elif ostring == 'me' and searcher:
local_matches.append(searcher)
return local_matches
def is_dbref(dbstring):
"""
Is the input a well-formed dbref number?
"""
try:
number = int(dbstring[1:])
except ValueError:
return False
if dbstring[0] != '#':
return False
elif number < 1:
return False
else:
return True
def get_object_from_dbref(dbref):
"""
Returns an object when given a dbref.
"""
return Object.objects.get(id=dbref)
def create_object(odat):
"""
Create a new object. odat is a dictionary that contains the following keys.
REQUIRED KEYS:
* type: Integer representing the object's type.
* name: The name of the new object.
* location: Reference to another object for the new object to reside in.
* owner: The creator of the object.
OPTIONAL KEYS:
* home: Reference to another object to home to. If not specified, use
location key for home.
"""
next_dbref = get_nextfree_dbnum()
if not str(next_dbref).isdigit():
# Recycle a garbage object.
new_object = next_dbref
else:
new_object = Object()
new_object.type = odat["type"]
new_object.set_name(odat["name"])
# If this is a player, we don't want him owned by anyone.
# The get_owner() function will return that the player owns
# himself.
if odat["type"] == 1:
new_object.owner = None
new_object.zone = None
else:
new_object.owner = odat["owner"]
if new_object.get_owner().get_zone():
new_object.zone = new_object.get_owner().get_zone()
# If we have a 'home' key, use that for our home value. Otherwise use
# the location key.
if odat.has_key("home"):
new_object.home = odat["home"]
else:
if new_object.is_exit():
new_object.home = None
else:
new_object.home = odat["location"]
new_object.save()
new_object.move_to(odat['location'])
return new_object
def create_user(cdat, uname, email, password):
"""
Handles the creation of new users.
"""
session = cdat['session']
server = cdat['server']
start_room = int(gameconf.get_configvalue('player_dbnum_start'))
start_room_obj = get_object_from_dbref(start_room)
# The user's entry in the User table must match up to an object
# on the object table. The id's are the same, we need to figure out
# the next free unique ID to use and make sure the two entries are
# the same number.
uid = get_nextfree_dbnum()
print 'UID', uid
# If this is an object, we know to recycle it since it's garbage. We'll
# pluck the user ID from it.
if not str(uid).isdigit():
uid = uid.id
print 'UID2', uid
user = User.objects.create_user(uname, email, password)
# It stinks to have to do this but it's the only trivial way now.
user.save()
# We can't use the user model to change the id because of the way keys
# are handled, so we actually need to fall back to raw SQL. Boo hiss.
cursor = connection.cursor()
cursor.execute("UPDATE auth_user SET id=%d WHERE id=%d" % (uid, user.id))
# Grab the user object again since we've changed it and the old reference
# is no longer valid.
user = User.objects.get(id=uid)
# Create a player object of the same ID in the Objects table.
odat = {"id": uid, "name": uname, "type": 1, "location": start_room_obj, "owner": None}
user_object = create_object(odat)
# Activate the player's session and set them loose.
session.login(user)
print 'Registration: %s' % (session,)
session.push("Welcome to %s, %s.\n\r" % (gameconf.get_configvalue('site_name'), session.get_pobject().get_name(),))

View file

@ -1,122 +0,0 @@
import session_mgr
import commands_privileged
import commands_general
import commands_unloggedin
"""
General commonly used functions.
"""
def print_errmsg(errormsg):
"""
Prints/logs an error message. Pipe any errors to be logged through here.
For now we're just printing to standard out.
"""
print 'ERROR: %s' % (errormsg,)
def command_list():
"""
Return a list of all commands.
"""
commands = dir(commands_unloggedin) + dir(commands_general)
stf_commands = dir(commands_privileged)
filtered = [prospect for prospect in commands if "cmd_" in prospect]
stf_filtered = [prospect for prospect in stf_commands if "cmd_" in prospect]
processed = []
for cmd in filtered:
processed.append(cmd[4:])
for cmd in stf_filtered:
processed.append('@%s' %(cmd[4:],))
return processed
def time_format(seconds, style=0):
"""
Function to return a 'prettified' version of a value in seconds.
Style 0: 1d 08:30
Style 1: 1d
Style 2: 1 day, 8 hours, 30 minutes, 10 seconds
"""
if seconds < 0:
seconds = 0
else:
# We'll just use integer math, no need for decimal precision.
seconds = int(seconds)
days = seconds / 86400
seconds -= days * 86400
hours = seconds / 3600
seconds -= hours * 3600
minutes = seconds / 60
seconds -= minutes * 60
if style is 0:
"""
Standard colon-style output.
"""
if days > 0:
retval = '%id %02i:%02i' % (days, hours, minutes,)
else:
retval = '%02i:%02i' % (hours, minutes,)
return retval
elif style is 1:
"""
Simple, abbreviated form that only shows the highest time amount.
"""
if days > 0:
return '%id' % (days,)
elif hours > 0:
return '%ih' % (hours,)
elif minutes > 0:
return '%im' % (minutes,)
else:
return '%is' % (seconds,)
elif style is 2:
"""
Full-detailed, long-winded format.
"""
days_str = hours_str = minutes_str = ''
if days > 0:
days_str = '%i days, ' % (days,)
if days or hours > 0:
hours_str = '%i hours, ' % (hours,)
if hours or minutes > 0:
minutes_str = '%i minutes, ' % (minutes,)
seconds_str = '%i seconds' % (seconds,)
retval = '%s%s%s%s' % (days_str, hours_str, minutes_str, seconds_str,)
return retval
def announce_all(message, with_ann_prefix=True, with_nl=True):
"""
Announces something to all connected players.
"""
if with_ann_prefix:
prefix = 'Announcement:'
else:
prefix = ''
if with_nl:
newline = '\r\n'
else:
newline = ''
for session in session_mgr.get_session_list():
session.msg_no_nl('%s %s%s' % (prefix, message,newline,))
def word_wrap(text, width=78):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
Function originally by Mike Brown
"""
return reduce(lambda line, word, width=width: '%s%s%s' %
(line,
' \n'[(len(line)-line.rfind('\n')-1
+ len(word.split('\n',1)[0]
) >= width)],
word),
text.split(' ')
)

View file

@ -1,29 +0,0 @@
from apps.helpsys.models import HelpEntry
"""
Help system functions.
"""
def find_topicmatch(pobject, topicstr):
"""
Searches for matching topics based on player's input.
"""
is_staff = pobject.is_staff()
if topicstr.isdigit():
if is_staff:
return HelpEntry.objects.filter(id=topicstr)
else:
return HelpEntry.objects.filter(id=topicstr).exclude(staff_only=1)
else:
if is_staff:
return HelpEntry.objects.filter(topicname__istartswith=topicstr)
else:
return HelpEntry.objects.filter(topicname__istartswith=topicstr).exclude(staff_only=1)
def find_topicsuggestions(pobject, topicstr):
"""
Do a fuzzier "contains" match.
"""
is_staff = pobject.is_staff()
if is_staff:
return HelpEntry.objects.filter(topicname__icontains=topicstr)
else:
return HelpEntry.objects.filter(topicname__icontains=topicstr).exclude(staff_only=1)

View file

@ -1,10 +0,0 @@
from apps.config.models import ConfigValue
"""
Handle the setting/retrieving of server config directives.
"""
def get_configvalue(configname):
"""
Retrieve a configuration value.
"""
return ConfigValue.objects.get(conf_key=configname).conf_value

View file

@ -1,11 +0,0 @@
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)

View file

@ -1,4 +0,0 @@
#!/bin/bash
export DJANGO_SETTINGS_MODULE="settings"
#python2.5 -m cProfile -o profiler.log -s time server.py
python2.5 server.py

View file

@ -1,34 +0,0 @@
import time
import events
"""
A really simple scheduler. We can probably get a lot fancier with this
in the future, but it'll do for now.
ADDING AN EVENT:
* Add an entry to the 'schedule' dictionary.
* Add the proper event_ function here.
* Profit.
"""
# The timer method to be triggered by the main server loop.
def heartbeat():
"""
Handle one tic/heartbeat.
"""
tictime = time.time()
for event in events.schedule:
try:
events.lastrun[event]
except:
events.lastrun[event] = time.time()
diff = tictime - events.lastrun[event]
if diff >= events.schedule[event]:
event_func = getattr(events, event)
if callable(event_func):
event_func()
# We'll get a new reading for time for accuracy.
events.lastrun[event] = time.time()

View file

@ -1,108 +0,0 @@
from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore, time
from django.db import models
from django.db import connection
from apps.config.models import CommandAlias
import scheduler
import functions_general
import session_mgr
import gameconf
import settings
class Server(dispatcher):
"""
The main server class from which everything branches.
"""
def __init__(self):
self.cmd_alias_list = {}
self.game_running = True
# 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=''")
print '-'*50
# Load command aliases into memory for easy/quick access.
self.load_cmd_aliases()
self.port = gameconf.get_configvalue('site_port')
# Start accepting connections.
dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', int(self.port)))
self.listen(100)
self.start_time = time.time()
print ' %s started on port %s.' % (gameconf.get_configvalue('site_name'), self.port,)
print '-'*50
"""
BEGIN SERVER STARTUP METHODS
"""
def load_cmd_aliases(self):
"""
Load up our command aliases.
"""
alias_list = CommandAlias.objects.all()
for alias in alias_list:
self.cmd_alias_list[alias.user_input] = alias.equiv_command
print ' Command Aliases Loaded: %i' % (len(self.cmd_alias_list),)
def handle_accept(self):
"""
What to do when we get a connection.
"""
conn, addr = self.accept()
session = session_mgr.new_session(self, conn, addr)
session.game_connect_screen(session)
print 'Connection:', str(session)
print 'Sessions active:', len(session_mgr.get_session_list())
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")
"""
BEGIN GENERAL METHODS
"""
def shutdown(self, message='The server has been shutdown. Please check back soon.'):
functions_general.announce_all(message)
self.game_running = False
"""
END Server CLASS
"""
"""
BEGIN MAIN APPLICATION LOGIC
"""
if __name__ == '__main__':
server = Server()
try:
while server.game_running:
asyncore.loop(timeout=5, count=1)
scheduler.heartbeat()
except KeyboardInterrupt:
server.shutdown()
print '--> Server killed by keystroke.'
except:
server.shutdown(message="The server has encountered an error and has been shut down. Please check back soon.")
print '-!> Server crashed.'

View file

@ -1,135 +0,0 @@
from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore, time, sys
import cmdhandler
from apps.objects.models import Object
from django.contrib.auth.models import User
import commands_general
import functions_db
import session_mgr
class PlayerSession(async_chat):
"""
This class represents a player's sesssion. From here we branch down into
other various classes, please try to keep this one tidy!
"""
def __init__(self, server, sock, addr):
async_chat.__init__(self, sock)
self.server = server
self.address = addr
self.set_terminator("\n")
self.name = None
self.data = []
self.uid = None
self.sock = sock
self.logged_in = False
# The time the user last issued a command.
self.cmd_last = time.time()
# Total number of commands issued.
self.cmd_total = 0
# The time when the user connected.
self.conn_time = time.time()
def collect_incoming_data(self, data):
"""
Stuff any incoming data into our buffer, self.data
"""
self.data.append(data)
def found_terminator(self):
"""
Any line return indicates a command for the purpose of a MUD. So we take
the user input and pass it to our command handler.
"""
line = (''.join(self.data))
line = line.strip('\r')
uinput = line
self.data = []
# Increment our user's command counter.
self.cmd_total += 1
# Store the timestamp of the user's last command.
self.cmd_last = time.time()
# Stuff anything we need to pass in this dictionary.
cdat = {"server": self.server, "uinput": uinput, "session": self}
cmdhandler.handle(cdat)
def handle_close(self):
"""
Break the connection and do some accounting.
"""
pobject = self.get_pobject()
pobject.set_flag("CONNECTED", False)
pobject.get_location().emit_to_contents("%s has disconnected." % (pobject.get_name(),), exclude=pobject)
async_chat.handle_close(self)
self.logged_in = False
session_mgr.remove_session(self)
print 'Sessions active:', len(session_mgr.get_session_list())
def get_pobject(self):
"""
Returns the object associated with a session.
"""
try:
result = Object.objects.get(id=self.uid)
return result
except:
return False
def game_connect_screen(self, session):
"""
Show our banner screen.
"""
buffer = '-'*50
buffer += ' \n\rWelcome to Evennia!\n\r'
buffer += '-'*50 + '\n\r'
buffer += """Please type one of the following to begin:\n\r
connect <username> <password>\n\r
create <username> <email> <password>\n\r"""
buffer += '-'*50
session.msg(buffer)
def login(self, user):
"""
After the user has authenticated, handle logging him in.
"""
self.uid = user.id
self.name = user.username
self.logged_in = True
self.conn_time = time.time()
pobject = self.get_pobject()
pobject.set_flag("CONNECTED", True)
self.msg("You are now logged in as %s." % (self.name,))
pobject.get_location().emit_to_contents("%s has connected." % (pobject.get_name(),), exclude=pobject)
cdat = {"session": self, "uinput":'look', "server": self.server}
cmdhandler.handle(cdat)
print "Login: %s" % (self,)
def msg(self, message):
"""
Sends a message with the newline/return included. Use this instead of
directly calling push().
"""
self.push("%s\n\r" % (message,))
def msg_no_nl(self, message):
"""
Sends a message without the newline/return included. Use this instead of
directly calling push().
"""
self.push("%s" % (message,))
def __str__(self):
"""
String representation of the user session class. We use
this a lot in the server logs and stuff.
"""
if self.logged_in:
symbol = '#'
else:
symbol = '?'
return "<%s> %s@%s" % (symbol, self.name, self.address,)
# def handle_error(self):
# self.handle_close()

View file

@ -1,53 +0,0 @@
from session import PlayerSession
"""
Session manager, handles connected players.
"""
# Our list of connected sessions.
session_list = []
def new_session(server, conn, addr):
"""
Create and return a new session.
"""
session = PlayerSession(server, conn, addr)
session_list.insert(0, session)
return session
def get_session_list():
"""
Lists the connected session objects.
"""
return session_list
def remove_session(session):
"""
Removes a session from the session list.
"""
session_list.remove(session)
def session_from_object(targobject):
"""
Return the session object given a object (if there is one open).
session_list: (list) The server's session_list attribute.
targobject: (Object) The object to match.
"""
results = [prospect for prospect in session_list if prospect.get_pobject() == targobject]
if results:
return results[0]
else:
return False
def session_from_dbref(dbstring):
"""
Return the session object given a dbref (if there is one open).
dbstring: (int) The dbref number to match against.
"""
if is_dbref(dbstring):
results = [prospect for prospect in session_list if prospect.get_pobject().dbref_match(dbstring)]
if results:
return results[0]
else:
return False

View file

@ -1,81 +0,0 @@
# Django settings for evennia project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
DATABASE_NAME = '/home/evennia/evennia/evennia.sql' # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. All choices can be found here:
# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
TIME_ZONE = 'America/New_York'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = False
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = '/home/evennia/evennia/media'
# URL that handles the media served from MEDIA_ROOT.
# Example: "http://media.lawrence.com"
MEDIA_URL = '/media/'
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/amedia/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = 'fsd&lkj^LKJ8398200(@)(38919#23892(*$*#(981'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
# 'django.template.loaders.eggs.load_template_source',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.doc.XViewMiddleware',
)
ROOT_URLCONF = 'urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.admin',
'apps.config',
'apps.objects',
'apps.helpsys',
'apps.genperms',
)

View file

@ -1,9 +0,0 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('',
# Example:
# (r'^evennia/', include('evennia.apps.foo.urls.foo')),
# Uncomment this for admin:
(r'^admin/', include('django.contrib.admin.urls')),
)