diff --git a/src/commands/comsys.py b/src/commands/comsys.py index 12af7fdca8..67432c848f 100644 --- a/src/commands/comsys.py +++ b/src/commands/comsys.py @@ -8,6 +8,7 @@ from src.channels.models import CommChannelMembership, CommChannel from src import defines_global from src import ansi from src.util import functions_general +from src.objects.models import Object from src.cmdtable import GLOBAL_CMD_TABLE #from src.imc2.models import IMC2ChannelMapping #from src.imc2.packets import IMC2PacketIceMsgBroadcasted @@ -324,7 +325,7 @@ def cmd_cboot(command): if objname[0] == '*': player_boot = True objname = objname[1:] - bootobj = source_object.search_for_object(objname) + bootobj = Object.objects.player_name_search(objname) if not bootobj: source_object.emit_to("Object '%s' not found." % objname) return @@ -517,7 +518,7 @@ def cmd_cchown(command): source_object.emit_to("You don't control this channel.") return #find the new owner - new_owner = source_object.search_for_object(pname) + new_owner = Object.objects.player_name_search(pname) if not new_owner: source_object.emit_to("New owner '%s' not found." % pname) return diff --git a/src/imc2/connection.py b/src/imc2/connection.py index 77bf4fc8de..014d6a46c8 100644 --- a/src/imc2/connection.py +++ b/src/imc2/connection.py @@ -65,7 +65,7 @@ class IMC2Protocol(StatefulTelnetProtocol): packet.imc2_protocol = self packet_str = str(packet.assemble()) - logger.log_infomsg("IMC2: SENT> %s" % packet_str) + #logger.log_infomsg("IMC2: SENT> %s" % packet_str) self.sendLine(packet_str) def _parse_auth_response(self, line): diff --git a/src/objects/managers/object.py b/src/objects/managers/object.py index 73cc461021..87dd5b675f 100644 --- a/src/objects/managers/object.py +++ b/src/objects/managers/object.py @@ -16,6 +16,13 @@ from src.objects.util import object as util_object from src import defines_global from src import logger +class UniqueMatch(Exception): + """ + This allows a fuzzy match to give precedence to a perfect match. + """ + def __init__(self,matchobj): + self.matchobj = matchobj + class ObjectManager(models.Manager): def num_total_players(self): """ @@ -96,6 +103,12 @@ class ObjectManager(models.Manager): ostring: (string) The string to match against. dbref_only: (bool) Only compare dbrefs. limit_types: (list of int) A list of Object type numbers to filter by. + + Note that the fuzzy matching gives precedence to exact matches; so if your + search query matches an object in the list exactly, it will be the only result. + This means that if the list contains [box,box11,box12], the search string 'box' + will only match the first entry since it is exact. The search 'box1' will however + match both box11 and box12 since neither is an exact match. """ if dbref_only: if limit_types: @@ -103,10 +116,13 @@ class ObjectManager(models.Manager): else: return [prospect for prospect in searchlist if prospect.dbref_match(ostring)] else: - if limit_types: - return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type) and prospect.type in limit_types] - else: - return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type)] + try: + if limit_types: + return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type) and prospect.type in limit_types] + else: + return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type)] + except UniqueMatch, e: + return [e.matchobj] def object_totals(self): @@ -233,10 +249,11 @@ class ObjectManager(models.Manager): # name and dbref comparisons against search_query. if search_contents: local_matches += self.list_search_object_namestr(searcher.get_contents(), - search_query, limit_types) + search_query, limit_types) if search_location: - local_matches += self.list_search_object_namestr(searcher.get_location().get_contents(), - search_query, limit_types=limit_types) + local_matches += \ + self.list_search_object_namestr(searcher.get_location().get_contents(), + search_query, limit_types=limit_types) return local_matches def get_user_from_email(self, uemail): diff --git a/src/objects/models.py b/src/objects/models.py index 7f7c9d4c18..5f4c5c4759 100755 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -11,6 +11,7 @@ from django.contrib.auth.models import User, Group from django.conf import settings from src.objects.util import object as util_object from src.objects.managers.object import ObjectManager +from src.objects.managers.object import UniqueMatch from src.objects.managers.attribute import AttributeManager from src.config.models import ConfigValue from src.ansi import ANSITable, parse_ansi @@ -160,6 +161,8 @@ class Object(models.Model): source_object: (Object) The Object doing the searching ostring: (str) The string to match object names against. + Obs - To find a player + append * to the start of ostring. """ # This is the object that gets the duplicate/no match emits. if not emit_to_obj: @@ -950,20 +953,30 @@ class Object(models.Model): NOTE: A 'name' can be a dbref or the actual name of the object. See dbref_match for an exclusively name-based match. + + The fuzzy match gives precedence to exact matches by raising the + UniqueMatch Exception. """ + if util_object.is_dbref(oname): # First character is a pound sign, looks to be a dbref. return self.dbref_match(oname) - elif match_type == "exact": - # Exact matching - name_chunks = self.name.lower().split(';') - for chunk in name_chunks: - if oname.lower() == chunk: - return True - return False else: - # Fuzzy matching. - return oname.lower() in self.name.lower() + # Check if this is an exact match + oname = oname.lower() + name_chunks = self.name.lower().split(';') + # True=1, False=0, so if any hit, sum(result)>0. + exact_match = sum(map(lambda o: oname == o, name_chunks)) > 0 + if match_type == "exact": + #return result outright + return exact_match + if match_type == "fuzzy": + if exact_match: + #even if a fuzzy match, an exact match is worth more + raise UniqueMatch(self) + else: + #not an exact match; use fuzzy matching + return oname in self.name.lower() def filter_contents_from_str(self, oname): """