Beispiel #1
0
    async def init_DB(self):
        """Initialize the database."""
        self.logger.debug("data: preparing to initialize the database.")
        file_path = (Path() / "talismud.db").absolute()
        db.bind(provider='sqlite', filename=str(file_path),
                create_db=True)
        set_sql_debug(True)
        db.generate_mapping(create_tables=True)
        self.logger.debug("data: database initialized.")
        self.init_task = None
        #Session.service = self
        #kredh = await Account.create(username="******", password=b"i", email="*****@*****.**")
        #kredh = await Account.get(id=1).prefetch_related("session")
        #session = await Session.first().prefetch_related("account")

        # Open a DBSession and cached, to be persisted during all the
        # project lifetime.
        db_session._enter()

        # Create the START_ROOM and RETURN_ROOM if they don't exist
        start_room = return_room = None
        if db.Room.get(barcode=settings.START_ROOM) is None:
            start_room = db.Room(barcode=settings.START_ROOM,
                    title="Welcome to TalisMUD!")
            self.logger.info(f"The start room was created.")

        if db.Room.get(barcode=settings.RETURN_ROOM) is None:
            return_room = db.Room(barcode=settings.RETURN_ROOM,
                    title="A grey void")
            self.logger.info(f"The return room was created.")

        if start_room or return_room:
            commit()
        db.Delay.restore()
        db.BlueprintRecord.apply_all()
Beispiel #2
0
    def test_moving_character(self):
        """Move a character inside and outside of a room."""
        character = db.Character(name="test")
        room1 = db.Room(title="here", barcode="1")
        self.assertIsNone(character.location)
        self.assertEqual(room1.contents, [])

        # Move che character in the room
        character.location = room1
        self.assertIs(character.location, room1)

        # Check that the room contents contains the character
        self.assertEqual(room1.contents, [character])

        # Move the character in a different room
        room2 = db.Room(title="there", barcode="2")
        self.assertEqual(room2.contents, [])
        character.location = room2
        self.assertIs(character.location, room2)
        self.assertEqual(room1.contents, [])
        self.assertEqual(room2.contents, [character])

        # Finally move the character outside of any room
        character.location = None
        self.assertIsNone(character.location)
        self.assertEqual(room1.contents, [])
        self.assertEqual(room2.contents, [])
Beispiel #3
0
    def test_recursion(self):
        """Test the recursion exception when moving inconsistently."""
        character1 = db.Character(name="test")
        character2 = db.Character(name="test2")
        character2.location = character1

        # Moving character1 into character1 should definitely not work
        with self.assertRaises(RecursionError):
            character1.location = character1
        self.assertIsNone(character1.location)

        with self.assertRaises(RecursionError):
            character1.location = character2 # Should be fobidden
        self.assertIsNone(character1.location)

        # Now try to create several objects and a more complicated loop
        room1 = db.Room(title="There", barcode="1")
        room2 = db.Room(title="Somewhere else", barcode="2")
        character2.location = character1
        character1.location = room2
        room2.location = room1

        # room1 contains room2 contains character1 contains character2
        # So moving room1 in character2 should now fail
        with self.assertRaises(RecursionError):
            room1.location = character2
        self.assertIsNone(room1.location)
Beispiel #4
0
    def apply(self):
        """Apply the document, create a room."""
        room = self.object
        add_tags = False
        if room is None:
            room = db.Room(barcode=self.cleaned.barcode,
                    title=self.cleaned.title)
            add_tags = True
        elif room.barcode in (settings.START_ROOM, settings.RETURN_ROOM):
            # These rooms have already been created automatically,
            # but make sure we add their blueprint tags
            add_tags = True
        else:
            room.title = self.cleaned.title

        if add_tags:
            room.blueprints.add(self.blueprint.name)

        self.blueprint.objects[room] = self
        room.x = self.cleaned.x
        room.y = self.cleaned.y
        room.z = self.cleaned.z

        description = self.cleaned.description
        if description:
            room.description.set(description)

        # Add the exits, if possible
        for exit in list(self.cleaned.exits):
            try:
                exit.apply()
            except DelayMe:
                self.cleaned.exits.remove(exit)
                raise DelayDocument(exit)
Beispiel #5
0
    def test_order(self):
        """Test that the ordering in content is accurate."""
        rooms = []
        characters = []

        for i in range(5):
            rooms.append(db.Room(title=f"here_{i}", barcode=str(i)))

        for i in range(20):
            characters.append(db.Character(name=f"character_{i}"))

        # Move characters in rooms
        for character, room in zip(characters, cycle(rooms)):
            character.location = room

        for i, room in enumerate(rooms):
            present = [character for pos, character in enumerate(
                    characters) if pos % 5 == i]
            self.assertEqual(room.contents, present)
Beispiel #6
0
class ExitHandler:
    """Exit handler, to interact with room exits."""
    def __init__(self, room):
        self.room = room

    def __repr__(self):
        """Return the repr for the room exits."""
        exits = Exit.of(self.room)
        reprs = []
        for exit in exits:
            if exit.origin is self.room:
                reprs.append(f"<Exit({exit.name})>")
            else:
                reprs.append(f"<BackExit({exit.back})>")

        return repr(reprs)

    def __iter__(self):
        return iter(tuple(Exit.of(self.room)))

    def all(self):
        """Return all exits."""
        return list(Exit.of(self.room))

    def has(self, name: str) -> bool:
        """
        Return whether the current room has an exit named like this.

        Args:
            name (str): name of the exit to check.

        The comparison is performed case-insensitive.

        Returns:
            exist (bool): whether an exit with this name exists.

        """
        name = name.lower()
        for exit in self:
            if exit.name == name:
                return True

        return False

    def link_to(
        self,
        destination: 'db.Room',
        name: str,
        back: ty.Optional[str] = None,
        barcode: ty.Optional[str] = "",
    ) -> ty.Optional['db.Exit']:
        """
        Link the owner room to the specified destination.

        Both rooms have to exist for this method to work.  Neither
        room should be connected, it would break the exit system
        if more than one exit linked two rooms.

        Args:
            destination (Room): the exit destination.
            name (str): the exit name.
            back (str, optional): the name of the back exit, if any.
            barcode (str, optional): the exit barcode, if any.

        Returns:
            exit (Exit or None): the exit if created, None if error.

        """
        origin = self.room
        if Exit.between(origin, destination):
            return

        # Create an exit connected origin to destination
        return db.Exit(origin=origin,
                       to=destination,
                       name=name,
                       back=back,
                       barcode=barcode)

    def create_room(self,
                    direction: 'Direction',
                    name: str,
                    destination: str,
                    title: str,
                    back: ty.Optional[str] = None,
                    barcode: ty.Optional[str] = "") -> 'db.Exit':
        """
        Create a room in the specified direction, linking it with an exit.

        This method is usually the one called to add rooms
        and exits with no real difficulty.  This would fail for several
        reasons, raise as a `NewRoomError` subclass.

        Args:
            direction (DIRECTION): a member of DIRECTION, like
                    DIRECTION.SOUTH or DIRECTION.UP.  This is
                    the exit direction and the name of the exit
                    is specified in the next argument.
            name (str): the exit name.
            destination (str): the destination's future barcode.
                    This will be the new room's barcode and thus,
                    shouldn't be used already.
            title (str): the new room's title.
            back (str, optional): the name of the exit
                    from destination to origin (the back exit).
                    If not set, don't create a back exit.
            barcode (str, optional): the exit's barcode, a way
                    to uniquely identify the exit.  It shouldn't be
                    used by another exit.

        Returns:
            exit (Exit): the newly-created exit, if successful.

        Raises:
            A subclass of `NewRoomError` to inform the user of several
            possible errors.  This should be intercepted (in a
            command, probably) and handled to display the error
            in a user-friendlier way.

            Possible errors:
                CoordinatesInUse(x, y, z, room): these coordinates are
                        in use, can't create the destination room.
                ExitNameInUse(room, name): this exit name is already
                        in use in this room, cannot create it.

        """
        origin = self.room
        x, y, z = origin.x, origin.y, origin.z

        # If the coordinates are valid, check the new coordinates
        if all(value is not None for value in (x, y, z)):
            x, y, z = direction.shift(x, y, z)

        # Check fthat the coordinates are free
        if (dest := db.Room.get(x=x, y=y, z=z)):
            raise CoordinatesInUse(x, y, z, dest)

        # Check whether there is no exit of this name yet
        if self.has(name):
            raise ExitNameInUse(room, name)

        # Create a room with these coordinates
        destination = db.Room(barcode=destination, title=title, x=x, y=y, z=z)

        # Copy the current blueprints to the new room
        for blueprint in origin.blueprints.get():
            destination.blueprints.add(blueprint.name)

        exit = self.link_to(destination, name=name, back=back, barcode=barcode)
        origin.blueprints.save(destination)
        return exit
Beispiel #7
0
 def create_room(self, title=None, barcode=None):
     """Create and return a room."""
     title = title or f"room {next(ROOM_TITLE)}"
     barcode = barcode or f"code {next(ROOM_BARCODE)}"
     return db.Room(title=title, barcode=barcode)