OBS- need to run migrations! Refactored attributes to use a slightly different internal storage format for faster access. Also set up caching of all attribute data, so subsequent reads of an attribute will not hit the database anymore, and writes will re-cache.

This commit is contained in:
Griatch 2012-02-14 23:40:16 +01:00
parent 8b5f3628ab
commit a32aebaa0e
12 changed files with 560 additions and 152 deletions

View file

@ -224,8 +224,8 @@ start
@create/drop The sea (in the distance);sea;ocean
#
@desc sea =
The grey sea stretches as far as the eye can se to the east, and far below you its waves crash
against the foot of the cliff. The vast inland moors meets the ocean along a high and uninviting
The grey sea stretches as far as the eye can see to the east. Far below you its waves crash
against the foot of the cliff. The vast inland moor meets the ocean along a high and uninviting
coastline of ragged vertical stone.
Once this part of the world might have been beautiful, but now the eternal winds and storms have
@ -287,16 +287,15 @@ north
: tutorial_world.rooms.TutorialRoom
= enter;in,leave;out
#
@desc The Evennia Inn consist mainly of one large room filled with tables. The bardisk extends
@desc The Evennia Inn consists of one large room filled with tables. The bardisk extends
along the east wall, where multiple barrels and bottles line the shelves. The barkeep seems busy
handing out ale and chatting with the patrons, which are a rowdy and cheerful lot, keeping the sound
level only just below thunderous.
level only just below thunderous. This is a rare spot of warmth and mirth on this dread moor.
Soon you have a beer in hand and is chatting with the locals. Your eye fall on a {wbarrel{n in a corner with a few
old rusty weapons sticking out. There is a sign next to it: {wFree to take{n.
A patron tells you cheerfully that it's the leftovers from those foolish adventurers that challenged the old ruin before you ...
old rusty weapons sticking out. There is a sign next to it: {wFree to take{n. A patron tells you cheerfully that
it's the leftovers from those foolish adventurers that challenged the old ruin before you ...
#
@set here/tutorial_info =
Nothing special about this room, only a bonus place to go for chatting

View file

@ -319,6 +319,7 @@ class Msg(SharedMemoryModel):
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del)
db_model_name = "msg" # used by attributes to safely store objects
#
# Msg class methods
@ -513,6 +514,8 @@ class Channel(SharedMemoryModel):
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del)
db_model_name = "channel" # used by attributes to safely store objects
class Meta:
"Define Django meta options"
verbose_name = "Channel"

View file

@ -0,0 +1,112 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orm.ObjAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.alias': {
'Meta': {'object_name': 'Alias'},
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objattribute': {
'Meta': {'object_name': 'ObjAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objectnick': {
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'db_real': ('django.db.models.fields.TextField', [], {}),
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
}
}
complete_apps = ['objects']

View file

@ -425,6 +425,7 @@ class ObjectDB(TypedObject):
#attribute_model_name = "ObjAttribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = ObjAttribute
db_model_name = "objectdb" # used by attributes to safely store objects
# this is used by all typedobjects as a fallback
try:

View file

@ -0,0 +1,106 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orb.PlayerAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerattribute': {
'Meta': {'object_name': 'PlayerAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'players.playernick': {
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'},
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
'db_real': ('django.db.models.fields.TextField', [], {}),
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['players']

View file

@ -269,6 +269,7 @@ class PlayerDB(TypedObject):
#attribute_model_name = "PlayerAttribute"
typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
attribute_class = PlayerAttribute
db_model_name = "playerdb" # used by attributes to safely store objects
# name property (wraps self.user.username)
#@property

View file

@ -0,0 +1,114 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orm.ScriptAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'scripts.scriptattribute': {
'Meta': {'object_name': 'ScriptAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['scripts.ScriptDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'scripts.scriptdb': {
'Meta': {'object_name': 'ScriptDB'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_interval': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'db_is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_persistent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_repeats': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'db_start_delay': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['scripts']

View file

@ -249,6 +249,7 @@ class ScriptDB(TypedObject):
#attribute_model_name = "ScriptAttribute"
typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
attribute_class = ScriptAttribute
db_model_name = "scriptdb" # used by attributes to safely store objects
# this is used by all typedobjects as a fallback
try:

View file

@ -7,7 +7,11 @@ import and inherit from these classes.
Attributes are database objects stored on other objects. The implementing
class needs to supply a ForeignKey field attr_object pointing to the kind
of object being mapped.
of object being mapped. Attributes storing iterables actually store special
types of iterables named PackedList/PackedDict respectively. These make
sure to save changes to them to database - this is criticial in order to
allow for obj.db.mylist[2] = data. Also, all dbobjects are saved as
dbrefs but are also aggressively cached.
TypedObjects are objects 'decorated' with a typeclass - that is, the typeclass
(which is a normal Python class implementing some special tricks with its
@ -37,7 +41,7 @@ from src.server.models import ServerConfig
from src.typeclasses import managers
from src.locks.lockhandler import LockHandler
from src.utils import logger, utils
from src.utils.utils import is_iter, has_parent
from src.utils.utils import is_iter, has_parent, to_unicode, to_str
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
@ -45,17 +49,20 @@ CTYPEGET = ContentType.objects.get
GA = object.__getattribute__
SA = object.__setattr__
DA = object.__delattr__
PLOADS = pickle.loads
PDUMPS = pickle.dumps
# used by Attribute to efficiently identify stored object types.
# Note that these have to be updated if directory structure changes.
PARENTS = {
"typeclass":"src.typeclasses.typeclass.TypeClass",
"objectdb":"src.objects.models.ObjectDB",
"playerdb":"src.players.models.PlayerDB",
"scriptdb":"src.scripts.models.ScriptDB",
"msg":"src.comms.models.Msg",
"channel":"src.comms.models.Channel",
"helpentry":"src.help.models.HelpEntry"}
# # used by Attribute to efficiently identify stored object types.
# # Note that these have to be updated if directory structure changes.
# PARENTS = {
# "typeclass":"src.typeclasses.typeclass.TypeClass",
# "objectdb":"src.objects.models.ObjectDB",
# "playerdb":"src.players.models.PlayerDB",
# "scriptdb":"src.scripts.models.ScriptDB",
# "msg":"src.comms.models.Msg",
# "channel":"src.comms.models.Channel",
# "helpentry":"src.help.models.HelpEntry"}
#------------------------------------------------------------
#
@ -63,15 +70,20 @@ PARENTS = {
#
#------------------------------------------------------------
class PackedDBobject(object):
class PackedDBobject(dict):
"""
Attribute helper class.
A container for storing and easily identifying database objects in
the database (which doesn't suppport storing db_objects directly).
"""
def __init__(self, ID, db_model):
self.id = ID
self.db_model = db_model
def __init__(self, ID, db_model, db_key):
self['id'] = ID
self['db_model'] = db_model
self['key'] = db_key
def __str__(self):
return "%s(#%s)" % (self['key'], self['id'])
def __unicode__(self):
return u"%s(#%s)" % (self['key'], self['id'])
class PackedDict(dict):
"""
@ -87,37 +99,32 @@ class PackedDict(dict):
order to allow custom updates to the dict.
db_obj - the Attribute object storing this dict.
"""
self.db_obj = db_obj
self.db_store = False
super(PackedDict, self).__init__(*args, **kwargs)
def db_save(self):
"save data to Attribute, if db_store is active"
if self.db_store:
self.db_obj.value = self
def __str__(self):
return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items())
def __setitem__(self, *args, **kwargs):
"Custom setitem that stores changed dict to database."
"assign item to this dict"
super(PackedDict, self).__setitem__(*args, **kwargs)
self.db_save()
def __getitem__(self, *args, **kwargs):
return super(PackedDict, self).__getitem__(*args, **kwargs)
self.db_obj.value = self
def clear(self, *args, **kwargs):
"Custom clear"
super(PackedDict, self).clear(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def pop(self, *args, **kwargs):
"Custom pop"
super(PackedDict, self).pop(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def popitem(self, *args, **kwargs):
"Custom popitem"
super(PackedDict, self).popitem(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def update(self, *args, **kwargs):
"Custom update"
super(PackedDict, self).update(*args, **kwargs)
self.db_save()
self.db_obj.value = self
class PackedList(list):
"""
@ -128,54 +135,45 @@ class PackedList(list):
"""
def __init__(self, db_obj, *args, **kwargs):
"""
Sets up the packing list. The db_store variable
is set by Attribute.validate_data() when returned in
order to allow custom updates to the list.
Sets up the packing list.
db_obj - the Attribute object storing this dict.
"""
self.db_obj = db_obj
self.db_store = False
super(PackedList, self).__init__(*args, **kwargs)
def db_save(self):
"save data to Attribute, if db_store is active"
if self.db_store:
self.db_obj.value = self
def __str__(self):
return "[%s]" % ", ".join(str(val) for val in self)
def __setitem__(self, *args, **kwargs):
"Custom setitem that stores changed dict to database."
super(PackedList, self).__setitem__(*args, **kwargs)
self.db_save()
"Custom setitem that stores changed list to database."
super(PackedList, self).__setitem__(*args, **kwargs)
self.db_obj.value = self
def append(self, *args, **kwargs):
"Custom append"
super(PackedList, self).append(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def extend(self, *args, **kwargs):
"Custom extend"
super(PackedList, self).extend(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def insert(self, *args, **kwargs):
"Custom insert"
super(PackedList, self).insert(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def remove(self, *args, **kwargs):
"Custom remove"
super(PackedList, self).remove(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def pop(self, *args, **kwargs):
"Custom pop"
super(PackedList, self).pop(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def reverse(self, *args, **kwargs):
"Custom reverse"
super(PackedList, self).reverse(*args, **kwargs)
self.db_save()
self.db_obj.value = self
def sort(self, *args, **kwargs):
"Custom sort"
super(PackedList, self).sort(*args, **kwargs)
self.db_save()
self.db_obj.value = self
class Attribute(SharedMemoryModel):
"""
@ -195,7 +193,15 @@ class Attribute(SharedMemoryModel):
obj - which object the attribute is defined on
date_created - when the attribute was created
value - the data stored in the attribute
what is actually stored in the field is a dict
{type : nodb|dbobj|dbiter,
data : <data>}
where type is info for the loader, telling it if holds a single
dbobject (dbobj), have to do a full scan for dbrefs (dbiter) or
if it is a normal Python structure without any dbobjs inside it
and can thus return it without further action (nodb).
"""
#
@ -214,7 +220,7 @@ class Attribute(SharedMemoryModel):
# by each child class to this abstact class)
db_obj = None # models.ForeignKey("RefencedObject")
# time stamp
db_date_created = models.DateTimeField('date_created',editable=False, auto_now_add=True)
db_date_created = models.DateTimeField('date_created', editable=False, auto_now_add=True)
# Database manager
objects = managers.AttributeManager()
@ -224,13 +230,14 @@ class Attribute(SharedMemoryModel):
"Initializes the parent first -important!"
SharedMemoryModel.__init__(self, *args, **kwargs)
self.locks = LockHandler(self)
self.value_cache = None
self.no_cache = True
self.cached_value = None
class Meta:
"Define Django meta options"
abstract = True
verbose_name = "Evennia Attribute"
verbose_name = "Evennia Attribute"
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
@ -291,17 +298,30 @@ class Attribute(SharedMemoryModel):
#@property
def value_get(self):
"""
Getter. Allows for value = self.value.
"""
try:
return utils.to_unicode(self.validate_data(pickle.loads(utils.to_str(self.db_value))))
except pickle.UnpicklingError:
return self.db_value
Getter. Allows for value = self.value. Reads from cache if possible.
"""
if self.no_cache:
# re-create data from database and cache it
try:
value = self.from_attr(PLOADS(to_str(self.db_value)))
except pickle.UnpicklingError:
value = self.db_value
self.cached_value = value
self.no_cache = False
return value
else:
# normally the memory cache holds the latest data so no db access is needed.
return self.cached_value
#@value.setter
def value_set(self, new_value):
"Setter. Allows for self.value = value"
self.db_value = utils.to_unicode(pickle.dumps(utils.to_str(self.validate_data(new_value, setmode=True))))
#self.db_value = utils.to_unicode(pickle.dumps(utils.to_str(self.validate_data(new_value))))
"""
Setter. Allows for self.value = value. We make sure to cache everything.
"""
new_value = self.to_attr(new_value)
self.cached_value = self.from_attr(new_value)
self.no_cache = False
self.db_value = to_unicode(PDUMPS(to_str(new_value)))
self.save()
#@value.deleter
def value_del(self):
@ -338,8 +358,12 @@ class Attribute(SharedMemoryModel):
def __unicode__(self):
return u"%s(%s)" % (self.key, self.id)
def validate_data(self, item, niter=0, setmode=False):
# operators on various data
def to_attr(self, data):
"""
Convert data to proper attr data format before saving
We have to make sure to not store database objects raw, since
this will crash the system. Instead we must store their IDs
and make sure to convert back when the attribute is read back
@ -351,75 +375,120 @@ class Attribute(SharedMemoryModel):
(and any nested combination of them) this way, all other
iterables are stored and returned as lists.
setmode - used for iterables; when first assigning, this settings makes
sure that it's a normal built-in python object that is stored in the db,
not the custom one. This will then just be updated later, assuring the
pickling works as it should.
niter - iteration counter for recursive iterable search.
"""
if isinstance(item, basestring):
# a string is unmodified
ret = item
elif type(item) == PackedDBobject:
# unpack a previously packed db_object
try:
#print "unpack:", item.id, item.db_model
mclass = CTYPEGET(model=item.db_model).model_class()
try:
ret = mclass.objects.dbref_search(item.id)
except AttributeError:
ret = mclass.objects.get(id=item.id)
except Exception:
logger.log_trace("Attribute error: %s, %s" % (item.db_model, item.id)) #TODO: Remove when stable?
ret = None
elif type(item) == tuple:
# handle tuples
ret = []
for it in item:
ret.append(self.validate_data(it))
ret = tuple(ret)
elif type(item) == dict or type(item) == PackedDict:
# handle dictionaries
if setmode:
ret = {}
for key, it in item.items():
ret[key] = self.validate_data(it, niter=niter+1, setmode=True)
data storage format:
(simple|dbobj|iter, <data>)
where
simple - a single non-db object, like a string or number
dbobj - a single dbobj
iter - any iterable object - will be looped over recursively
to convert dbobj->id.
"""
def iter_db2id(item):
"""
recursively looping through stored iterables, replacing objects with ids.
(Python only builds nested functions once, so there is no overhead for nesting)
"""
dtype = type(item)
if dtype in (basestring, int, float): # check the most common types first, for speed
return item
elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"):
db_model_name = item.db_model_name
if db_model_name == "typeclass":
db_model_name = GA(item.dbobj, "db_model_name")
return PackedDBobject(item.id, db_model_name, item.db_key)
elif dtype == tuple:
return tuple(iter_db2id(val) for val in item)
elif dtype in (dict, PackedDict):
return dict((key, iter_db2id(val)) for key, val in item.items())
elif hasattr(item, '__iter__'):
return list(iter_db2id(val) for val in item)
else:
ret = PackedDict(self)
for key, it in item.items():
ret[key] = self.validate_data(it, niter=niter+1)
if niter == 0:
ret.db_store = True
elif is_iter(item):
# Note: ALL other iterables except dicts and tuples are stored&retrieved as lists!
if setmode:
ret = []
for it in item:
ret.append(self.validate_data(it, niter=niter+1,setmode=True))
else:
ret = PackedList(self)
for it in item:
ret.append(self.validate_data(it, niter=niter+1))
if niter == 0:
ret.db_store = True
elif has_parent('django.db.models.base.Model', item) or has_parent(PARENTS['typeclass'], item):
# db models must be stored as dbrefs
db_model = [parent for parent, path in PARENTS.items() if has_parent(path, item)]
#print "db_model", db_model
if db_model and db_model[0] == 'typeclass':
# the typeclass alone can't help us, we have to know the db object.
db_model = [parent for parent, path in PARENTS.items()
if has_parent(path, item.dbobj)]
#print "db_model2", db_model
if db_model:
# store the object in an easily identifiable container
ret = PackedDBobject(str(item.id), db_model[0])
else:
# not a valid object - some third-party class or primitive?
ret = item
return item
dtype = type(data)
if dtype in (basestring, int, float):
return ("simple",data)
elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'):
# all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass)
# have the protected property db_model_name hardcoded on themselves for speed.
db_model_name = data.db_model_name
if db_model_name == "typeclass":
# typeclass cannot help us, we want the actual child object model name
db_model_name = GA(data.dbobj, "db_model_name")
return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key))
elif hasattr(data, "__iter__"):
return ("iter", iter_db2id(data))
else:
ret = item
return ret
return ("simple", data)
def from_attr(self, datatuple):
"""
Retrieve data from a previously stored attribute. This
is always a dict with keys type and data.
datatuple comes from the database storage and has
the following format:
(simple|dbobj|iter, <data>)
where
simple - a single non-db object, like a string. is returned as-is.
dbobj - a single dbobj-id. This id is retrieved back from the database.
iter - an iterable. This is traversed iteratively, converting all found
dbobj-ids back to objects. Also, all lists and dictionaries are
returned as their PackedList/PackedDict counterparts in order to
allow in-place assignment such as obj.db.mylist[3] = val. Mylist
is then a PackedList that saves the data on the fly.
"""
# nested functions
def id2db(data):
"""
Convert db-stored dbref back to object
"""
mclass = CTYPEGET(model=data["db_model"]).model_class()
try:
return mclass.objects.dbref_search(data['id'])
except AttributeError:
try:
return mclass.objects.get(id=data['id'])
except mclass.DoesNotExist: # could happen if object was deleted in the interim.
return None
def iter_id2db(item):
"""
Recursively looping through stored iterables, replacing ids with actual objects.
We return PackedDict and PackedLists instead of normal lists; this is needed in order for
the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is
stored in the database are however always normal python primitives.
"""
dtype = type(item)
if dtype in (basestring, int, float): # check the most common types first, for speed
return item
elif dtype == PackedDBobject:
return id2db(item)
elif dtype == tuple:
return tuple([iter_id2db(val) for val in item])
elif dtype in (dict, PackedDict):
return PackedDict(self, dict(zip([key for key in item.keys()],
[iter_id2db(val) for val in item.values()])))
elif hasattr(item, '__iter__'):
return PackedList(self, list(iter_id2db(val) for val in item))
else:
return item
typ, data = datatuple
if typ == 'simple':
# single non-db objects
return data
elif typ == 'dbobj':
# a single stored dbobj
return id2db(data)
elif typ == 'iter':
# all types of iterables
return iter_id2db(data)
def access(self, accessing_obj, access_type='read', default=False):
"""
@ -706,7 +775,8 @@ class TypedObject(SharedMemoryModel):
#attribute_model_path = "src.typeclasses.models"
#attribute_model_name = "Attribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = Attribute # replaced by relevant attribute class for child
attribute_class = Attribute # replaced by relevant attribute class for child
db_model_name = "typeclass" # used by attributes to safely store objects
def __eq__(self, other):
return other and hasattr(other, 'id') and self.id == other.id
@ -870,7 +940,7 @@ class TypedObject(SharedMemoryModel):
# no mudinfo channel is found. Log instead.
cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')])
logger.log_errmsg(cmessage)
except Exception, e:
except Exception:
if ServerConfig.objects.conf("server_starting_mode"):
print cmessage
else:
@ -1054,15 +1124,14 @@ class TypedObject(SharedMemoryModel):
attrib_obj = None
attrclass = self.attribute_class
try:
# use old attribute
attrib_obj = attrclass.objects.filter(
db_obj=self).filter(db_key__iexact=attribute_name)[0]
except IndexError:
# no match; create new attribute
new_attrib = attrclass(db_key=attribute_name, db_obj=self)
new_attrib.value = new_value
return
attrib_obj = attrclass(db_key=attribute_name, db_obj=self)
# re-set an old attribute value
attrib_obj.value = new_value
attrib_obj.value = new_value
def get_attribute(self, attribute_name, default=None):
"""

View file

@ -25,7 +25,8 @@ DA = object.__delattr__
# full access anyway), so no protection against changing
# e.g. 'locks' or 'permissions' should go here.
PROTECTED = ('id', 'dbobj', 'db', 'ndb', 'objects', 'typeclass',
'attr', 'save', 'delete')
'attr', 'save', 'delete', 'db_model_name','attribute_class',
'typeclass_paths')
# If this is true, all non-protected property assignments
# are directly stored to a database attribute
@ -207,3 +208,5 @@ class TypeClass(object):
def __str__(self):
"represent the object"
return self.key
def __unicode__(self):
return u"%s" % self.key

View file

@ -399,7 +399,7 @@ def create_player(name, email, password,
from src.players.models import PlayerDB
from src.players.player import Player
if not email:
email = "dummy@dummy.com"
if user:
@ -410,7 +410,6 @@ def create_player(name, email, password,
new_user = User.objects.create_superuser(name, email, password)
else:
new_user = User.objects.create_user(name, email, password)
try:
if not typeclass:
typeclass = settings.BASE_PLAYER_TYPECLASS
@ -464,7 +463,7 @@ def create_player(name, email, password,
player=new_player)
return new_character
return new_player
except Exception:
except Exception,e:
# a failure in creating the character
if not user:
# in there was a failure we clean up everything we can

View file

@ -55,7 +55,7 @@ class GameTime(Script):
self.persistent = True
self.start_delay = True
self.attr("game_time", 0.0) #IC time
self.attr("run_time", 0.0) #OOC time
self.attr("run_time", 0.0) #OOC time
self.attr("up_time", 0.0) #OOC time
def at_repeat(self):