From 9459178c43626008edef43da76c625e054c5331a Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 18 Oct 2010 21:07:26 +0000 Subject: [PATCH] Fixed character swap mechanisms. Created an example command @puppet for switching control between characters (note that it does not currently check permissions, nor make sure the target has the appropriate cmdsets). --- .../commands/default/cmdset_default.py | 1 + game/gamesrc/commands/default/objmanip.py | 32 +++++++++++ src/objects/manager.py | 55 ------------------- src/objects/models.py | 2 +- src/players/manager.py | 29 ++++++++++ src/players/models.py | 7 +++ src/utils/idmapper/MANIFEST.in | 2 + src/utils/idmapper/README.rst | 35 ++++++++++++ 8 files changed, 107 insertions(+), 56 deletions(-) create mode 100644 src/utils/idmapper/MANIFEST.in create mode 100644 src/utils/idmapper/README.rst diff --git a/game/gamesrc/commands/default/cmdset_default.py b/game/gamesrc/commands/default/cmdset_default.py index b5eb2b1a56..169e7e566f 100644 --- a/game/gamesrc/commands/default/cmdset_default.py +++ b/game/gamesrc/commands/default/cmdset_default.py @@ -75,6 +75,7 @@ class DefaultCmdSet(CmdSet): self.add(objmanip.CmdDestroy()) self.add(objmanip.CmdExamine()) self.add(objmanip.CmdTypeclass()) + self.add(objmanip.CmdPuppet()) # Comm commands self.add(comms.CmdAddCom()) diff --git a/game/gamesrc/commands/default/objmanip.py b/game/gamesrc/commands/default/objmanip.py index d5d9390a7a..e9de241f44 100644 --- a/game/gamesrc/commands/default/objmanip.py +++ b/game/gamesrc/commands/default/objmanip.py @@ -1635,3 +1635,35 @@ class CmdTypeclass(MuxCommand): string += "same-named attributes on the existing object." caller.msg(string) +class CmdPuppet(MuxCommand): + """ + Switch control to an object + + Usage: + @puppet + + This will attempt to "become" a different character. Note that this command does not check so that + the target object has the appropriate cmdset. You cannot puppet a character that is already "taken". + """ + + key = "@puppet" + permissions = "cmd:puppet" + help_category = "Admin" + + def func(self): + """ + Simple puppet method (does not check permissions) + """ + caller = self.caller + if not self.args: + caller.msg("Usage: @puppet ") + return + + player = caller.player + new_character = caller.search(self.args) + if not new_character: + return + if player.swap_character(new_character): + new_character.msg("You now control %s." % new_character.name) + else: + caller.msg("You couldn't control %s." % new_character.name) diff --git a/src/objects/manager.py b/src/objects/manager.py index 566576993f..7561dd0e6c 100644 --- a/src/objects/manager.py +++ b/src/objects/manager.py @@ -343,58 +343,3 @@ class ObjectManager(TypedObjectManager): new_object.attr(attr.attr_name, attr.value) return new_object - - - # - # ObjectManager User control - # - - def user_swap_object(self, uid, new_obj_id, delete_old_obj=False): - """ - This moves the user from one database object to another. - The new object must already exist. - delete_old_obj (bool) - Delete the user's old dbobject. - - This is different from ObjectDB.swap_type() since it actually - swaps the database object the user is connected to, rather - than change any typeclass on the same dbobject. This means - that the old object (typeclass and all) can remain unchanged - in-game except it is now not tied to any user. - - Note that the new object will be unchanged, the only - difference is that its 'user' property is set to the - user. No other initializations are done here, such as - setting the default cmdset - this has to be done - separately when calling this method. - - This method raises Exceptions instead of logging feedback - since this is a method which might be very useful to embed in - your own game implementation. - - Also note that this method don't check any permissions beyond - making sure no other user is connected to the object before - swapping. - """ - # get the objects. - try: - user = User.get(uid) - new_obj = self.get(new_obj_id) - except: - raise Exception("OBJ_FIND_ERROR") - - # check so the new object is not already controlled. - if new_obj.user: - if new_obj.user == user: - raise Exception("SELF_CONTROL_ERROR") - else: - raise Exception("CONTROL_ERROR") - # set user to new object. - new_obj.user = user - new_obj.save() - # get old object, sets its user to None and/or delete it - for old_obj in self.get_object_with_user(uid): - if delete_old_obj: - old_obj.delete() - else: - old_obj.user = None - old_obj.save() diff --git a/src/objects/models.py b/src/objects/models.py index 1a21514d5e..f37fe2ee33 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -76,7 +76,7 @@ class ObjectDB(TypedObject): typeclass - auto-linked typeclass date_created - time stamp of object creation permissions - perm strings - dbref - #id of object + Dbref - #id of object db - persistent attribute storage ndb - non-persistent attribute storage diff --git a/src/players/manager.py b/src/players/manager.py index 835a282811..e164d6810f 100644 --- a/src/players/manager.py +++ b/src/players/manager.py @@ -156,3 +156,32 @@ class PlayerManager(models.Manager): if not players: players = self.filter(user__username=ostring) return players + + + def swap_character(self, player, new_character, delete_old_character=False): + """ + This disconnects a player from the current character (if any) and connects + to a new character object. + + """ + + if new_character.player: + # the new character is already linked to a player! + return False + + # do the swap + old_character = player.character + if old_character: + old_character.player = None + try: + player.character = new_character + new_character.player = player + except Exception: + # recover old setup + old_character.player = player + player.character = old_character + return False + if delete_old_character: + old_character.delete() + return True + diff --git a/src/players/models.py b/src/players/models.py index d034faa171..510952084f 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -271,3 +271,10 @@ class PlayerDB(TypedObject): """ self.msg(message, from_obj) + + def swap_character(self, new_character, delete_old_character=False): + """ + Swaps character, if possible + """ + return self.__class__.objects.swap_character(self, new_character, delete_old_character=delete_old_character) + diff --git a/src/utils/idmapper/MANIFEST.in b/src/utils/idmapper/MANIFEST.in new file mode 100644 index 0000000000..ac9a0ea9fd --- /dev/null +++ b/src/utils/idmapper/MANIFEST.in @@ -0,0 +1,2 @@ +include setup.py README.rst LICENSE MANIFEST.in +global-exclude *~ \ No newline at end of file diff --git a/src/utils/idmapper/README.rst b/src/utils/idmapper/README.rst new file mode 100644 index 0000000000..0ab8662665 --- /dev/null +++ b/src/utils/idmapper/README.rst @@ -0,0 +1,35 @@ +Django Identity Mapper +====================== + +A pluggable Django application which allows you to explicitally mark your models to use an identity mapping pattern. This will share instances of the same model in memory throughout your interpreter. + +Please note, that deserialization (such as from the cache) will *not* use the identity mapper. + +Usage +----- +To use the shared memory model you simply need to inherit from it (instead of models.Model). This enable all queries (and relational queries) to this model to use the shared memory instance cache, effectively creating a single instance for each unique row (based on primary key) in the queryset. + +For example, if you want to simply mark all of your models as a SharedMemoryModel, you might as well just import it as models. +:: + + from idmapper import models + + class MyModel(models.SharedMemoryModel): + name = models.CharField(...) + +Because the system is isolated, you may mix and match SharedMemoryModel's with regular Model's. +:: + + from idmapper import models + + class MyModel(models.SharedMemoryModel): + name = models.CharField(...) + fkey = models.ForeignKey('Other') + + class Other(models.Model): + name = models.CharField(...) + +References +---------- + +Original code and concept: http://code.djangoproject.com/ticket/17 \ No newline at end of file