mirror of
				https://github.com/solero/houdini.git
				synced 2025-11-04 14:41:56 +00:00 
			
		
		
		
	Make houdini.penguin.Penguin inherit houdini.data.penguin.Penguin
This allows for much clearer syntax
This commit is contained in:
		@@ -65,27 +65,21 @@ class PenguinStringCompiler(OrderedDict):
 | 
				
			|||||||
            return getattr(p, attribute_name) or 0
 | 
					            return getattr(p, attribute_name) or 0
 | 
				
			||||||
        return attribute_method
 | 
					        return attribute_method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def data_attribute_by_name(cls, attribute_name):
 | 
					 | 
				
			||||||
        async def attribute_method(p):
 | 
					 | 
				
			||||||
            return getattr(p.data, attribute_name) or 0
 | 
					 | 
				
			||||||
        return attribute_method
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def setup_default_builder(cls, string_builder):
 | 
					    def setup_default_builder(cls, string_builder):
 | 
				
			||||||
        string_builder.update({
 | 
					        string_builder.update({
 | 
				
			||||||
            'ID': PenguinStringCompiler.data_attribute_by_name('id'),
 | 
					            'ID': PenguinStringCompiler.attribute_by_name('id'),
 | 
				
			||||||
            'Nickname': PenguinStringCompiler.data_attribute_by_name('nickname'),
 | 
					            'Nickname': PenguinStringCompiler.attribute_by_name('nickname'),
 | 
				
			||||||
            'Approval': PenguinStringCompiler.data_attribute_by_name('approval'),
 | 
					            'Approval': PenguinStringCompiler.attribute_by_name('approval'),
 | 
				
			||||||
            'Color': PenguinStringCompiler.data_attribute_by_name('color'),
 | 
					            'Color': PenguinStringCompiler.attribute_by_name('color'),
 | 
				
			||||||
            'Head': PenguinStringCompiler.data_attribute_by_name('head'),
 | 
					            'Head': PenguinStringCompiler.attribute_by_name('head'),
 | 
				
			||||||
            'Face': PenguinStringCompiler.data_attribute_by_name('face'),
 | 
					            'Face': PenguinStringCompiler.attribute_by_name('face'),
 | 
				
			||||||
            'Neck': PenguinStringCompiler.data_attribute_by_name('neck'),
 | 
					            'Neck': PenguinStringCompiler.attribute_by_name('neck'),
 | 
				
			||||||
            'Body': PenguinStringCompiler.data_attribute_by_name('body'),
 | 
					            'Body': PenguinStringCompiler.attribute_by_name('body'),
 | 
				
			||||||
            'Hand': PenguinStringCompiler.data_attribute_by_name('hand'),
 | 
					            'Hand': PenguinStringCompiler.attribute_by_name('hand'),
 | 
				
			||||||
            'Feet': PenguinStringCompiler.data_attribute_by_name('feet'),
 | 
					            'Feet': PenguinStringCompiler.attribute_by_name('feet'),
 | 
				
			||||||
            'Flag': PenguinStringCompiler.data_attribute_by_name('flag'),
 | 
					            'Flag': PenguinStringCompiler.attribute_by_name('flag'),
 | 
				
			||||||
            'Photo': PenguinStringCompiler.data_attribute_by_name('photo'),
 | 
					            'Photo': PenguinStringCompiler.attribute_by_name('photo'),
 | 
				
			||||||
            'X': PenguinStringCompiler.attribute_by_name('x'),
 | 
					            'X': PenguinStringCompiler.attribute_by_name('x'),
 | 
				
			||||||
            'Y': PenguinStringCompiler.attribute_by_name('y'),
 | 
					            'Y': PenguinStringCompiler.attribute_by_name('y'),
 | 
				
			||||||
            'Frame': PenguinStringCompiler.attribute_by_name('frame'),
 | 
					            'Frame': PenguinStringCompiler.attribute_by_name('frame'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,16 +2,7 @@ from datetime import datetime, date
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from houdini.data import db
 | 
					from houdini.data import db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from houdini.data.permission import PenguinPermissionCollection
 | 
					from functools import lru_cache
 | 
				
			||||||
from houdini.data.item import PenguinItemCollection
 | 
					 | 
				
			||||||
from houdini.data.igloo import PenguinIglooCollection, PenguinFurnitureCollection, \
 | 
					 | 
				
			||||||
    PenguinFlooringCollection, PenguinLocationCollection
 | 
					 | 
				
			||||||
from houdini.data.stamp import PenguinStampCollection
 | 
					 | 
				
			||||||
from houdini.data.ninja import PenguinCardCollection
 | 
					 | 
				
			||||||
from houdini.data.pet import PenguinPuffleCollection, PenguinPuffleItemCollection
 | 
					 | 
				
			||||||
from houdini.data.buddy import BuddyListCollection, BuddyRequestCollection, \
 | 
					 | 
				
			||||||
    CharacterBuddyCollection, IgnoreListCollection
 | 
					 | 
				
			||||||
from houdini.data.room import PenguinIglooRoomCollection
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Penguin(db.Model):
 | 
					class Penguin(db.Model):
 | 
				
			||||||
@@ -107,23 +98,7 @@ class Penguin(db.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def load_inventories(self):
 | 
					    @lru_cache()
 | 
				
			||||||
        self.inventory = await PenguinItemCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.permissions = await PenguinPermissionCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.igloos = await PenguinIglooCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.igloo_rooms = await PenguinIglooRoomCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.furniture = await PenguinFurnitureCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.flooring = await PenguinFlooringCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.locations = await PenguinLocationCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.stamps = await PenguinStampCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.cards = await PenguinCardCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.puffles = await PenguinPuffleCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.puffle_items = await PenguinPuffleItemCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.buddies = await BuddyListCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.buddy_requests = await BuddyRequestCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.character_buddies = await CharacterBuddyCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
        self.ignore = await IgnoreListCollection.get_collection(self.id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def safe_nickname(self, language_bitmask):
 | 
					    def safe_nickname(self, language_bitmask):
 | 
				
			||||||
        return self.nickname if self.approval & language_bitmask else "P" + str(self.id)
 | 
					        return self.nickname if self.approval & language_bitmask else "P" + str(self.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,23 +17,23 @@ class RoomMixin:
 | 
				
			|||||||
    async def add_penguin(self, p):
 | 
					    async def add_penguin(self, p):
 | 
				
			||||||
        if p.room:
 | 
					        if p.room:
 | 
				
			||||||
            await p.room.remove_penguin(p)
 | 
					            await p.room.remove_penguin(p)
 | 
				
			||||||
        self.penguins_by_id[p.data.id] = p
 | 
					        self.penguins_by_id[p.id] = p
 | 
				
			||||||
        self.penguins_by_username[p.data.username] = p
 | 
					        self.penguins_by_username[p.username] = p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.data.character:
 | 
					        if p.character:
 | 
				
			||||||
            self.penguins_by_character_id[p.data.character] = p
 | 
					            self.penguins_by_character_id[p.character] = p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p.room = self
 | 
					        p.room = self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def remove_penguin(self, p):
 | 
					    async def remove_penguin(self, p):
 | 
				
			||||||
        if not (p.is_vanilla_client and p.data.stealth_moderator):
 | 
					        if not (p.is_vanilla_client and p.stealth_moderator):
 | 
				
			||||||
            await self.send_xt('rp', p.data.id)
 | 
					            await self.send_xt('rp', p.id, f=lambda penguin: penguin.id != p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        del self.penguins_by_id[p.data.id]
 | 
					        del self.penguins_by_id[p.id]
 | 
				
			||||||
        del self.penguins_by_username[p.data.username]
 | 
					        del self.penguins_by_username[p.username]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.data.character:
 | 
					        if p.character:
 | 
				
			||||||
            del self.penguins_by_character_id[p.data.character]
 | 
					            del self.penguins_by_character_id[p.character]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p.room = None
 | 
					        p.room = None
 | 
				
			||||||
        p.frame = 1
 | 
					        p.frame = 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -232,15 +232,6 @@ def player_attribute(**attrs):
 | 
				
			|||||||
    return check(check_for_attributes)
 | 
					    return check(check_for_attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def player_data_attribute(**attrs):
 | 
					 | 
				
			||||||
    def check_for_attributes(_, p):
 | 
					 | 
				
			||||||
        for attr, value in attrs.items():
 | 
					 | 
				
			||||||
            if not getattr(p.data, attr) == value:
 | 
					 | 
				
			||||||
                return False
 | 
					 | 
				
			||||||
        return True
 | 
					 | 
				
			||||||
    return check(check_for_attributes)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def player_in_room(*room_ids):
 | 
					def player_in_room(*room_ids):
 | 
				
			||||||
    def check_room_id(_, p):
 | 
					    def check_room_id(_, p):
 | 
				
			||||||
        return p.room.id in room_ids
 | 
					        return p.room.id in room_ids
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,8 +35,7 @@ async def world_login(p, data):
 | 
				
			|||||||
        await p.server.penguins_by_id[data.id].close()
 | 
					        await p.server.penguins_by_id[data.id].close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.logger.info(f'{data.username} logged in successfully')
 | 
					    p.logger.info(f'{data.username} logged in successfully')
 | 
				
			||||||
 | 
					    p.update(**data.to_dict())
 | 
				
			||||||
    p.data = data
 | 
					 | 
				
			||||||
    await p.send_xt('l')
 | 
					    await p.send_xt('l')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,21 +8,21 @@ from houdini.constants import ClientType
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def update_player_presence(p):
 | 
					async def update_player_presence(p):
 | 
				
			||||||
    for buddy_id in p.data.buddies.keys():
 | 
					    for buddy_id in p.buddies.keys():
 | 
				
			||||||
        if buddy_id in p.server.penguins_by_id:
 | 
					        if buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
            buddy = p.server.penguins_by_id[buddy_id]
 | 
					            buddy = p.server.penguins_by_id[buddy_id]
 | 
				
			||||||
            await p.send_xt('bon', buddy.data.id, p.server.server_config['Id'], buddy.room.id)
 | 
					            await p.send_xt('bon', buddy.id, p.server.config.id, buddy.room.id)
 | 
				
			||||||
            await buddy.send_xt('bon', p.data.id, p.server.server_config['Id'], p.room.id)
 | 
					            await buddy.send_xt('bon', p.id, p.server.config.id, p.room.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for character_id in p.data.character_buddies.keys():
 | 
					    for character_id in p.character_buddies.keys():
 | 
				
			||||||
        if character_id in p.server.penguins_by_character_id:
 | 
					        if character_id in p.server.penguins_by_character_id:
 | 
				
			||||||
            character = p.server.penguins_by_character_id[character_id]
 | 
					            character = p.server.penguins_by_character_id[character_id]
 | 
				
			||||||
            await p.send_xt('caon', character_id, p.server.server_config['Id'], character.room.id)
 | 
					            await p.send_xt('caon', character_id, p.server.config.id, character.room.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.character is not None:
 | 
					    if p.character is not None:
 | 
				
			||||||
        for penguin in p.server.penguins_by_id.values():
 | 
					        for penguin in p.server.penguins_by_id.values():
 | 
				
			||||||
            if p.data.character in penguin.data.character_buddies:
 | 
					            if p.character in penguin.character_buddies:
 | 
				
			||||||
                await penguin.send_xt('caon', p.data.character, p.server.server_config['Id'], p.room.id)
 | 
					                await penguin.send_xt('caon', p.character, p.server.config.id, p.room.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('j', 'jr'), after=handle_join_room, client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('j', 'jr'), after=handle_join_room, client=ClientType.Vanilla)
 | 
				
			||||||
@@ -34,9 +34,9 @@ async def handle_send_room_presence(p):
 | 
				
			|||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_buddies(p):
 | 
					async def handle_get_buddies(p):
 | 
				
			||||||
    buddies_query = BuddyList.load(parent=Penguin.on(Penguin.id == BuddyList.buddy_id)).where(
 | 
					    buddies_query = BuddyList.load(parent=Penguin.on(Penguin.id == BuddyList.buddy_id)).where(
 | 
				
			||||||
        BuddyList.penguin_id == p.data.id)
 | 
					        BuddyList.penguin_id == p.id)
 | 
				
			||||||
    request_query = BuddyRequest.load(parent=Penguin.on(Penguin.id == BuddyRequest.requester_id)).where(
 | 
					    request_query = BuddyRequest.load(parent=Penguin.on(Penguin.id == BuddyRequest.requester_id)).where(
 | 
				
			||||||
        BuddyRequest.penguin_id == p.data.id)
 | 
					        BuddyRequest.penguin_id == p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buddies = []
 | 
					    buddies = []
 | 
				
			||||||
    best_buddies = []
 | 
					    best_buddies = []
 | 
				
			||||||
@@ -54,7 +54,7 @@ async def handle_get_buddies(p):
 | 
				
			|||||||
            if buddy.best_buddy:
 | 
					            if buddy.best_buddy:
 | 
				
			||||||
                best_buddies.append(str(buddy.buddy_id))
 | 
					                best_buddies.append(str(buddy.buddy_id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for character in p.data.character_buddies.values():
 | 
					        for character in p.character_buddies.values():
 | 
				
			||||||
            character_presence = int(character.character_id in p.server.penguins_by_character_id)
 | 
					            character_presence = int(character.character_id in p.server.penguins_by_character_id)
 | 
				
			||||||
            characters.append(f'{character.character_id}|{character_presence}')
 | 
					            characters.append(f'{character.character_id}|{character_presence}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,7 +66,7 @@ async def handle_get_buddies(p):
 | 
				
			|||||||
    best_friend_count = len(best_buddies) + len(best_characters)
 | 
					    best_friend_count = len(best_buddies) + len(best_characters)
 | 
				
			||||||
    notification_aware = int(best_friend_count >= 1)
 | 
					    notification_aware = int(best_friend_count >= 1)
 | 
				
			||||||
    best_friends_enabled = int((len(buddies) + len(characters)) >= 6)
 | 
					    best_friends_enabled = int((len(buddies) + len(characters)) >= 6)
 | 
				
			||||||
    await p.send_xt('gs', best_friend_count, notification_aware, int(p.data.active), best_friends_enabled)
 | 
					    await p.send_xt('gs', best_friend_count, notification_aware, int(p.active), best_friends_enabled)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('gb', *buddies)
 | 
					    await p.send_xt('gb', *buddies)
 | 
				
			||||||
    await p.send_xt('pr', *requests)
 | 
					    await p.send_xt('pr', *requests)
 | 
				
			||||||
@@ -83,7 +83,7 @@ async def handle_get_buddies(p):
 | 
				
			|||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_buddies_legacy(p):
 | 
					async def handle_get_buddies_legacy(p):
 | 
				
			||||||
    buddies_query = BuddyList.load(parent=Penguin.on(Penguin.id == BuddyList.buddy_id)).where(
 | 
					    buddies_query = BuddyList.load(parent=Penguin.on(Penguin.id == BuddyList.buddy_id)).where(
 | 
				
			||||||
        BuddyList.penguin_id == p.data.id)
 | 
					        BuddyList.penguin_id == p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buddies = []
 | 
					    buddies = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,7 +100,7 @@ async def handle_get_buddies_legacy(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'bf'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('b', 'bf'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_find_buddy(p, buddy_id: int):
 | 
					async def handle_find_buddy(p, buddy_id: int):
 | 
				
			||||||
    if buddy_id in p.data.buddies and buddy_id in p.server.penguins_by_id:
 | 
					    if buddy_id in p.buddies and buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
        buddy = p.server.penguins_by_id[buddy_id]
 | 
					        buddy = p.server.penguins_by_id[buddy_id]
 | 
				
			||||||
        await p.send_xt('bf', buddy.room.external_id if buddy.room.igloo else buddy.room.id)
 | 
					        await p.send_xt('bf', buddy.room.external_id if buddy.room.igloo else buddy.room.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,101 +108,100 @@ async def handle_find_buddy(p, buddy_id: int):
 | 
				
			|||||||
@handlers.handler(XTPacket('b', 'br'))
 | 
					@handlers.handler(XTPacket('b', 'br'))
 | 
				
			||||||
@handlers.cooldown(.5)
 | 
					@handlers.cooldown(.5)
 | 
				
			||||||
async def handle_buddy_request(p, buddy_id: int):
 | 
					async def handle_buddy_request(p, buddy_id: int):
 | 
				
			||||||
    if buddy_id not in p.data.buddies:
 | 
					    if buddy_id not in p.buddies:
 | 
				
			||||||
        if buddy_id in p.server.penguins_by_id:
 | 
					        if buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
            buddy = p.server.penguins_by_id[buddy_id]
 | 
					            buddy = p.server.penguins_by_id[buddy_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if buddy.client_type == ClientType.Vanilla and p.data.id not in buddy.data.buddy_requests:
 | 
					            if buddy.client_type == ClientType.Vanilla and p.id not in buddy.buddy_requests:
 | 
				
			||||||
                await buddy.data.buddy_requests.insert(buddy_id=p.data.id)
 | 
					                await buddy.buddy_requests.insert(buddy_id=p.id)
 | 
				
			||||||
            elif p.data.id not in buddy.buddy_requests:
 | 
					            elif p.id not in buddy.buddy_requests:
 | 
				
			||||||
                buddy.buddy_requests.add(p.data.id)
 | 
					                buddy.buddy_requests.add(p.id)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await buddy.send_xt('br', p.data.id, p.data.nickname)
 | 
					            await buddy.send_xt('br', p.id, p.safe_name)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await BuddyRequest.create(penguin_id=buddy_id, requester_id=p.data.id)
 | 
					            await BuddyRequest.create(penguin_id=buddy_id, requester_id=p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'ba'))
 | 
					@handlers.handler(XTPacket('b', 'ba'))
 | 
				
			||||||
async def handle_buddy_accept(p, buddy_id: int):
 | 
					async def handle_buddy_accept(p, buddy_id: int):
 | 
				
			||||||
    if buddy_id in p.data.buddy_requests:
 | 
					    if buddy_id in p.buddy_requests:
 | 
				
			||||||
        await p.data.buddy_requests.delete(buddy_id)
 | 
					        await p.buddy_requests.delete(buddy_id)
 | 
				
			||||||
    elif buddy_id in p.buddy_requests:
 | 
					    elif buddy_id in p.buddy_requests:
 | 
				
			||||||
        p.buddy_requests.remove(buddy_id)
 | 
					        p.buddy_requests.remove(buddy_id)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.data.buddies.insert(buddy_id=buddy_id)
 | 
					    await p.buddies.insert(buddy_id=buddy_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if buddy_id in p.server.penguins_by_id:
 | 
					    if buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
        buddy = p.server.penguins_by_id[buddy_id]
 | 
					        buddy = p.server.penguins_by_id[buddy_id]
 | 
				
			||||||
        await buddy.data.buddies.insert(buddy_id=p.data.id)
 | 
					        await buddy.buddies.insert(buddy_id=p.id)
 | 
				
			||||||
        await buddy.send_xt('ba', p.data.id, p.data.nickname, 1)
 | 
					        await buddy.send_xt('ba', p.id, p.safe_name, 1)
 | 
				
			||||||
        await p.send_xt('ba', buddy.data.id, buddy.data.nickname, 1)
 | 
					        await p.send_xt('ba', buddy.id, buddy.safe_name, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.client_type == ClientType.Vanilla:
 | 
					        if p.client_type == ClientType.Vanilla:
 | 
				
			||||||
            await p.send_xt('bon', buddy.data.id, p.server.server_config['Id'], buddy.room.id)
 | 
					            await p.send_xt('bon', buddy.id, p.server.config.id, buddy.room.id)
 | 
				
			||||||
        if buddy.client_type == ClientType.Vanilla:
 | 
					        if buddy.client_type == ClientType.Vanilla:
 | 
				
			||||||
            await buddy.send_xt('bon', p.data.id, p.server.server_config['Id'], p.room.id)
 | 
					            await buddy.send_xt('bon', p.id, p.server.config.id, p.room.id)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        await BuddyList.create(penguin_id=buddy_id, buddy_id=p.data.id)
 | 
					        await BuddyList.create(penguin_id=buddy_id, buddy_id=p.id)
 | 
				
			||||||
        nickname = await Penguin.select('nickname').where(Penguin.id == buddy_id).gino.scalar()
 | 
					        nickname = await Penguin.select('nickname').where(Penguin.id == buddy_id).gino.scalar()
 | 
				
			||||||
        await p.send_xt('ba', buddy_id, nickname, 0)
 | 
					        await p.send_xt('ba', buddy_id, nickname, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'rb'))
 | 
					@handlers.handler(XTPacket('b', 'rb'))
 | 
				
			||||||
async def handle_buddy_remove(p, buddy_id: int):
 | 
					async def handle_buddy_remove(p, buddy_id: int):
 | 
				
			||||||
    if buddy_id in p.data.buddies:
 | 
					    if buddy_id in p.buddies:
 | 
				
			||||||
        await p.data.buddies.delete(buddy_id)
 | 
					        await p.buddies.delete(buddy_id)
 | 
				
			||||||
        await p.send_xt('rb', buddy_id)
 | 
					        await p.send_xt('rb', buddy_id)
 | 
				
			||||||
        if buddy_id in p.server.penguins_by_id:
 | 
					        if buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
            buddy = p.server.penguins_by_id[buddy_id]
 | 
					            buddy = p.server.penguins_by_id[buddy_id]
 | 
				
			||||||
            await buddy.send_xt('rb', p.data.id)
 | 
					            await buddy.send_xt('rb', p.id)
 | 
				
			||||||
            await buddy.data.buddies.delete(p.data.id)
 | 
					            await buddy.buddies.delete(p.id)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await BuddyList.delete.where((BuddyList.penguin_id == buddy_id) &
 | 
					            await BuddyList.delete.where((BuddyList.penguin_id == buddy_id) &
 | 
				
			||||||
                                         (BuddyList.buddy_id == p.data.id)).gino.status()
 | 
					                                         (BuddyList.buddy_id == p.id)).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'cr'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('b', 'cr'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_character_request(p, character_id: int):
 | 
					async def handle_character_request(p, character_id: int):
 | 
				
			||||||
    if character_id in p.server.characters and character_id not in p.data.character_buddies:
 | 
					    if character_id in p.server.characters and character_id not in p.character_buddies:
 | 
				
			||||||
        character = p.server.characters[character_id]
 | 
					        await p.character_buddies.insert(character_id=character_id)
 | 
				
			||||||
        await p.data.character_buddies.insert(character_id=character_id)
 | 
					 | 
				
			||||||
        await p.send_xt('cr', character_id, 0)
 | 
					        await p.send_xt('cr', character_id, 0)
 | 
				
			||||||
        await p.send_xt('caon', character_id, p.server.server_config['Id'], p.room.id)
 | 
					        await p.send_xt('caon', character_id, p.server.config.id, p.room.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'rr'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('b', 'rr'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_buddy_reject(p, buddy_id: int):
 | 
					async def handle_buddy_reject(p, buddy_id: int):
 | 
				
			||||||
    await p.data.buddy_requests.delete(buddy_id)
 | 
					    await p.buddy_requests.delete(buddy_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'tbf'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('b', 'tbf'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_toggle_best_friend(p, buddy_id: int):
 | 
					async def handle_toggle_best_friend(p, buddy_id: int):
 | 
				
			||||||
    if buddy_id in p.data.buddies:
 | 
					    if buddy_id in p.buddies:
 | 
				
			||||||
        buddy_record = p.data.buddies[buddy_id]
 | 
					        buddy_record = p.buddies[buddy_id]
 | 
				
			||||||
        await buddy_record.update(best_buddy=not buddy_record.best_buddy).apply()
 | 
					        await buddy_record.update(best_buddy=not buddy_record.best_buddy).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('b', 'tbc'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('b', 'tbc'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_toggle_best_character(p, character_id: int):
 | 
					async def handle_toggle_best_character(p, character_id: int):
 | 
				
			||||||
    if character_id in p.data.character_buddies:
 | 
					    if character_id in p.character_buddies:
 | 
				
			||||||
        character_buddy_record = p.data.character_buddies[character_id]
 | 
					        character_buddy_record = p.character_buddies[character_id]
 | 
				
			||||||
        await character_buddy_record.update(best_buddy=not character_buddy_record.best_buddy).apply()
 | 
					        await character_buddy_record.update(best_buddy=not character_buddy_record.best_buddy).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.disconnected
 | 
					@handlers.disconnected
 | 
				
			||||||
@handlers.player_attribute(joined_world=True)
 | 
					@handlers.player_attribute(joined_world=True)
 | 
				
			||||||
async def handle_disconnect_buddy(p):
 | 
					async def handle_disconnect_buddy(p):
 | 
				
			||||||
    if p.data.character is not None:
 | 
					    if p.character is not None:
 | 
				
			||||||
        del p.server.penguins_by_character_id[p.data.character]
 | 
					        del p.server.penguins_by_character_id[p.character]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for penguin in p.server.penguins_by_id.values():
 | 
					        for penguin in p.server.penguins_by_id.values():
 | 
				
			||||||
            if p.data.character in penguin.data.character_buddies:
 | 
					            if p.character in penguin.character_buddies:
 | 
				
			||||||
                await penguin.send_xt('caof', p.data.character)
 | 
					                await penguin.send_xt('caof', p.character)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for buddy_id in p.data.buddies:
 | 
					    for buddy_id in p.buddies:
 | 
				
			||||||
        if buddy_id in p.server.penguins_by_id:
 | 
					        if buddy_id in p.server.penguins_by_id:
 | 
				
			||||||
            await p.server.penguins_by_id[buddy_id].send_xt('bof', p.data.id)
 | 
					            await p.server.penguins_by_id[buddy_id].send_xt('bof', p.id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,40 +12,40 @@ import random
 | 
				
			|||||||
@handlers.handler(XTPacket('l', 'mst'), before=handle_start_mail_engine)
 | 
					@handlers.handler(XTPacket('l', 'mst'), before=handle_start_mail_engine)
 | 
				
			||||||
async def handle_send_job_mail(p):
 | 
					async def handle_send_job_mail(p):
 | 
				
			||||||
    postcards = []
 | 
					    postcards = []
 | 
				
			||||||
    if not p.data.agent_status and random.random() < 0.4:
 | 
					    if not p.agent_status and random.random() < 0.4:
 | 
				
			||||||
        epf_invited = await PenguinPostcard.query.where(
 | 
					        epf_invited = await PenguinPostcard.query.where(
 | 
				
			||||||
            (PenguinPostcard.penguin_id == p.data.id) & ((PenguinPostcard.postcard_id == 112)
 | 
					            (PenguinPostcard.penguin_id == p.id) & ((PenguinPostcard.postcard_id == 112)
 | 
				
			||||||
                                                         | (PenguinPostcard.postcard_id == 47))).gino.scalar()
 | 
					                                                    | (PenguinPostcard.postcard_id == 47))).gino.scalar()
 | 
				
			||||||
        if not epf_invited:
 | 
					        if not epf_invited:
 | 
				
			||||||
            postcards.append({
 | 
					            postcards.append({
 | 
				
			||||||
                'penguin_id': p.data.id,
 | 
					                'penguin_id': p.id,
 | 
				
			||||||
                'postcard_id': 112
 | 
					                'postcard_id': 112
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    last_paycheck = p.data.last_paycheck.date()
 | 
					    last_paycheck = p.last_paycheck.date()
 | 
				
			||||||
    today = datetime.date.today()
 | 
					    today = datetime.date.today()
 | 
				
			||||||
    first_day_of_month = today.replace(day=1)
 | 
					    first_day_of_month = today.replace(day=1)
 | 
				
			||||||
    last_paycheck = last_paycheck.replace(day=1)
 | 
					    last_paycheck = last_paycheck.replace(day=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    player_data = p.data
 | 
					    player_data = p.update()
 | 
				
			||||||
    while last_paycheck < first_day_of_month:
 | 
					    while last_paycheck < first_day_of_month:
 | 
				
			||||||
        last_paycheck = last_paycheck + datetime.timedelta(days=32)
 | 
					        last_paycheck = last_paycheck + datetime.timedelta(days=32)
 | 
				
			||||||
        last_paycheck = last_paycheck.replace(day=1)
 | 
					        last_paycheck = last_paycheck.replace(day=1)
 | 
				
			||||||
        send_date = last_paycheck + datetime.timedelta(days=1)
 | 
					        send_date = last_paycheck + datetime.timedelta(days=1)
 | 
				
			||||||
        if 428 in p.data.inventory:
 | 
					        if 428 in p.inventory:
 | 
				
			||||||
            postcards.append({
 | 
					            postcards.append({
 | 
				
			||||||
                'penguin_id': p.data.id,
 | 
					                'penguin_id': p.id,
 | 
				
			||||||
                'postcard_id': 172,
 | 
					                'postcard_id': 172,
 | 
				
			||||||
                'send_date': send_date
 | 
					                'send_date': send_date
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            player_data.update(coins=p.data.coins + 250)
 | 
					            player_data.update(coins=p.coins + 250)
 | 
				
			||||||
        if p.data.agent_status:
 | 
					        if p.agent_status:
 | 
				
			||||||
            postcards.append({
 | 
					            postcards.append({
 | 
				
			||||||
                'penguin_id': p.data.id,
 | 
					                'penguin_id': p.id,
 | 
				
			||||||
                'postcard_id': 184,
 | 
					                'postcard_id': 184,
 | 
				
			||||||
                'send_date': send_date
 | 
					                'send_date': send_date
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            player_data.update(coins=p.data.coins + 350)
 | 
					            player_data.update(coins=p.coins + 350)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await player_data.update(last_paycheck=last_paycheck).apply()
 | 
					    await player_data.update(last_paycheck=last_paycheck).apply()
 | 
				
			||||||
    if postcards:
 | 
					    if postcards:
 | 
				
			||||||
@@ -54,51 +54,51 @@ async def handle_send_job_mail(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfga'))
 | 
					@handlers.handler(XTPacket('f', 'epfga'))
 | 
				
			||||||
async def handle_get_agent_status(p):
 | 
					async def handle_get_agent_status(p):
 | 
				
			||||||
    await p.send_xt('epfga', int(p.data.agent_status))
 | 
					    await p.send_xt('epfga', int(p.agent_status))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfsa'))
 | 
					@handlers.handler(XTPacket('f', 'epfsa'))
 | 
				
			||||||
@handlers.player_data_attribute(agent_status=False)
 | 
					@handlers.player_attribute(agent_status=False)
 | 
				
			||||||
async def handle_set_agent_status(p):
 | 
					async def handle_set_agent_status(p):
 | 
				
			||||||
    await p.data.update(agent_status=True).apply()
 | 
					    await p.update(agent_status=True).apply()
 | 
				
			||||||
    await p.send_xt('epfsa', int(p.data.agent_status))
 | 
					    await p.send_xt('epfsa', int(p.agent_status))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfgf'))
 | 
					@handlers.handler(XTPacket('f', 'epfgf'))
 | 
				
			||||||
async def handle_get_field_op_status(p):
 | 
					async def handle_get_field_op_status(p):
 | 
				
			||||||
    today = datetime.date.today()
 | 
					    today = datetime.date.today()
 | 
				
			||||||
    monday = today - datetime.timedelta(days=today.weekday())
 | 
					    monday = today - datetime.timedelta(days=today.weekday())
 | 
				
			||||||
    if p.data.last_field_op.date() < monday:
 | 
					    if p.last_field_op.date() < monday:
 | 
				
			||||||
        await p.data.update(field_op_status=0).apply()
 | 
					        await p.update(field_op_status=0).apply()
 | 
				
			||||||
    await p.send_xt('epfgf', p.data.field_op_status)
 | 
					    await p.send_xt('epfgf', p.field_op_status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfsf'))
 | 
					@handlers.handler(XTPacket('f', 'epfsf'))
 | 
				
			||||||
@handlers.player_data_attribute(agent_status=True)
 | 
					@handlers.player_attribute(agent_status=True)
 | 
				
			||||||
async def handle_set_field_op_status(p, field_op_status: int):
 | 
					async def handle_set_field_op_status(p, field_op_status: int):
 | 
				
			||||||
    if 2 >= field_op_status == p.data.field_op_status + 1:
 | 
					    if 2 >= field_op_status == p.field_op_status + 1:
 | 
				
			||||||
        player_data = p.data.update(field_op_status=p.data.field_op_status + 1)
 | 
					        player_data = p.update(field_op_status=p.field_op_status + 1)
 | 
				
			||||||
        if p.data.field_op_status == 2:
 | 
					        if p.field_op_status == 2:
 | 
				
			||||||
            player_data.update(career_medals=p.data.career_medals + 2)
 | 
					            player_data.update(career_medals=p.career_medals + 2)
 | 
				
			||||||
            player_data.update(agent_medals=p.data.agent_medals + 2)
 | 
					            player_data.update(agent_medals=p.agent_medals + 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.send_xt('epfsf', p.data.field_op_status)
 | 
					        await p.send_xt('epfsf', p.field_op_status)
 | 
				
			||||||
        await player_data.update(last_field_op=datetime.datetime.now()).apply()
 | 
					        await player_data.update(last_field_op=datetime.datetime.now()).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfgr'))
 | 
					@handlers.handler(XTPacket('f', 'epfgr'))
 | 
				
			||||||
async def handle_get_epf_points(p):
 | 
					async def handle_get_epf_points(p):
 | 
				
			||||||
    await p.send_xt('epfgr', p.data.career_medals, p.data.agent_medals)
 | 
					    await p.send_xt('epfgr', p.career_medals, p.agent_medals)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('f', 'epfai'))
 | 
					@handlers.handler(XTPacket('f', 'epfai'))
 | 
				
			||||||
@handlers.player_data_attribute(agent_status=True)
 | 
					@handlers.player_attribute(agent_status=True)
 | 
				
			||||||
async def handle_buy_epf_item(p, item: Item):
 | 
					async def handle_buy_epf_item(p, item: Item):
 | 
				
			||||||
    if item.epf:
 | 
					    if item.epf:
 | 
				
			||||||
        if item.id in p.data.inventory:
 | 
					        if item.id in p.inventory:
 | 
				
			||||||
            return await p.send_error(400)
 | 
					            return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.data.agent_medals < item.cost:
 | 
					        if p.agent_medals < item.cost:
 | 
				
			||||||
            return await p.send_error(401)
 | 
					            return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.add_epf_inventory(item)
 | 
					        await p.add_epf_inventory(item)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ from aiocache import cached
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_status_key(_, p):
 | 
					def get_status_key(_, p):
 | 
				
			||||||
    return f'quest.status.{p.data.id}'
 | 
					    return f'quest.status.{p.id}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_settings_key(_, p):
 | 
					def get_settings_key(_, p):
 | 
				
			||||||
@@ -24,18 +24,18 @@ async def get_player_quest_status(p):
 | 
				
			|||||||
                       items=QuestAwardItem,
 | 
					                       items=QuestAwardItem,
 | 
				
			||||||
                       furniture=QuestAwardFurniture,
 | 
					                       furniture=QuestAwardFurniture,
 | 
				
			||||||
                       pet=QuestAwardPuffleItem,
 | 
					                       pet=QuestAwardPuffleItem,
 | 
				
			||||||
                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.data.id) &
 | 
					                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.id) &
 | 
				
			||||||
                                                    (QuestTask.id == PenguinQuestTask.task_id))).gino
 | 
					                                                    (QuestTask.id == PenguinQuestTask.task_id))).gino
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_award(quest):
 | 
					    def has_award(quest):
 | 
				
			||||||
        for award in quest.items:
 | 
					        for award in quest.items:
 | 
				
			||||||
            if award.item_id not in p.data.inventory:
 | 
					            if award.item_id not in p.inventory:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
        for award in quest.furniture:
 | 
					        for award in quest.furniture:
 | 
				
			||||||
            if award.furniture_id not in p.data.furniture:
 | 
					            if award.furniture_id not in p.furniture:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
        for award in quest.pet:
 | 
					        for award in quest.pet:
 | 
				
			||||||
            if award.puffle_item_id not in p.data.puffle_items:
 | 
					            if award.puffle_item_id not in p.puffle_items:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,14 +103,14 @@ async def get_quest_settings(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
async def init_all_quests(p):
 | 
					async def init_all_quests(p):
 | 
				
			||||||
    query = Quest.load(tasks=QuestTask,
 | 
					    query = Quest.load(tasks=QuestTask,
 | 
				
			||||||
                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.data.id) &
 | 
					                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.id) &
 | 
				
			||||||
                                                    (QuestTask.id == PenguinQuestTask.task_id))).gino
 | 
					                                                    (QuestTask.id == PenguinQuestTask.task_id))).gino
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async with db.transaction():
 | 
					    async with db.transaction():
 | 
				
			||||||
        async for quest in query.iterate():
 | 
					        async for quest in query.iterate():
 | 
				
			||||||
            for task in quest.tasks:
 | 
					            for task in quest.tasks:
 | 
				
			||||||
                if task.id not in quest.in_progress.union(quest.complete):
 | 
					                if task.id not in quest.in_progress.union(quest.complete):
 | 
				
			||||||
                    await PenguinQuestTask.create(task_id=task.id, penguin_id=p.data.id)
 | 
					                    await PenguinQuestTask.create(task_id=task.id, penguin_id=p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await load_active_quests(p)
 | 
					    await load_active_quests(p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -120,7 +120,7 @@ async def load_active_quests(p):
 | 
				
			|||||||
                                       items=QuestAwardItem,
 | 
					                                       items=QuestAwardItem,
 | 
				
			||||||
                                       furniture=QuestAwardFurniture,
 | 
					                                       furniture=QuestAwardFurniture,
 | 
				
			||||||
                                       pet=QuestAwardPuffleItem,
 | 
					                                       pet=QuestAwardPuffleItem,
 | 
				
			||||||
                                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.data.id) &
 | 
					                                       complete=PenguinQuestTask.on((PenguinQuestTask.penguin_id == p.id) &
 | 
				
			||||||
                                                                    (PenguinQuestTask.task_id == QuestTask.id) &
 | 
					                                                                    (PenguinQuestTask.task_id == QuestTask.id) &
 | 
				
			||||||
                                                                    (PenguinQuestTask.complete == False))).gino.all()
 | 
					                                                                    (PenguinQuestTask.complete == False))).gino.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,7 +128,7 @@ async def load_active_quests(p):
 | 
				
			|||||||
@handlers.handler(XTPacket('j', 'js'), after=handle_join_server)
 | 
					@handlers.handler(XTPacket('j', 'js'), after=handle_join_server)
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_quest_join_server(p):
 | 
					async def handle_quest_join_server(p):
 | 
				
			||||||
    await p.server.cache.delete(f'quest.status.{p.data.id}')
 | 
					    await p.server.cache.delete(f'quest.status.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await load_active_quests(p)
 | 
					    await load_active_quests(p)
 | 
				
			||||||
    await p.send_xt('nxquestsettings', await get_quest_settings(p))
 | 
					    await p.send_xt('nxquestsettings', await get_quest_settings(p))
 | 
				
			||||||
@@ -136,11 +136,11 @@ async def handle_quest_join_server(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def set_task_cleared(p, task_id):
 | 
					async def set_task_cleared(p, task_id):
 | 
				
			||||||
    await p.server.cache.delete(f'quest.status.{p.data.id}')
 | 
					    await p.server.cache.delete(f'quest.status.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await PenguinQuestTask.update.values(complete=True) \
 | 
					    await PenguinQuestTask.update.values(complete=True) \
 | 
				
			||||||
        .where((PenguinQuestTask.task_id == task_id) &
 | 
					        .where((PenguinQuestTask.task_id == task_id) &
 | 
				
			||||||
               (PenguinQuestTask.penguin_id == p.data.id)).gino.status()
 | 
					               (PenguinQuestTask.penguin_id == p.id)).gino.status()
 | 
				
			||||||
    return await p.send_xt('nxquestdata', await get_player_quest_status(p))
 | 
					    return await p.send_xt('nxquestdata', await get_player_quest_status(p))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -159,7 +159,7 @@ async def handle_quest_join_room(p):
 | 
				
			|||||||
    if p.active_quests is not None:
 | 
					    if p.active_quests is not None:
 | 
				
			||||||
        for quest in p.active_quests:
 | 
					        for quest in p.active_quests:
 | 
				
			||||||
            for task in quest.tasks:
 | 
					            for task in quest.tasks:
 | 
				
			||||||
                igloo_quest_completed = task.id == 3 and p.room.igloo and p.room.penguin_id == p.data.id
 | 
					                igloo_quest_completed = task.id == 3 and p.room.igloo and p.room.penguin_id == p.id
 | 
				
			||||||
                if task.id in quest.in_progress and igloo_quest_completed:
 | 
					                if task.id in quest.in_progress and igloo_quest_completed:
 | 
				
			||||||
                    await set_task_cleared(p, task.id)
 | 
					                    await set_task_cleared(p, task.id)
 | 
				
			||||||
                    p.active_quests.remove(quest)
 | 
					                    p.active_quests.remove(quest)
 | 
				
			||||||
@@ -167,7 +167,7 @@ async def handle_quest_join_room(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'nxquestaward'))
 | 
					@handlers.handler(XTPacket('nx', 'nxquestaward'))
 | 
				
			||||||
async def handle_quest_award(p, quest_id: int):
 | 
					async def handle_quest_award(p, quest_id: int):
 | 
				
			||||||
    await p.server.cache.delete(f'quest.status.{p.data.id}')
 | 
					    await p.server.cache.delete(f'quest.status.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quest = await Quest.load(items=QuestAwardItem,
 | 
					    quest = await Quest.load(items=QuestAwardItem,
 | 
				
			||||||
                             furniture=QuestAwardFurniture,
 | 
					                             furniture=QuestAwardFurniture,
 | 
				
			||||||
@@ -184,7 +184,7 @@ async def handle_quest_award(p, quest_id: int):
 | 
				
			|||||||
@handlers.handler(XTPacket('nx', 'nxquestactivate'))
 | 
					@handlers.handler(XTPacket('nx', 'nxquestactivate'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_quest_activate(p):
 | 
					async def handle_quest_activate(p):
 | 
				
			||||||
    await p.server.cache.delete(f'quest.status.{p.data.id}')
 | 
					    await p.server.cache.delete(f'quest.status.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await init_all_quests(p)
 | 
					    await init_all_quests(p)
 | 
				
			||||||
    await p.send_xt('nxquestdata', await get_player_quest_status(p))
 | 
					    await p.send_xt('nxquestdata', await get_player_quest_status(p))
 | 
				
			||||||
@@ -193,39 +193,39 @@ async def handle_quest_activate(p):
 | 
				
			|||||||
@handlers.handler(XTPacket('nx', 'gas'))
 | 
					@handlers.handler(XTPacket('nx', 'gas'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_action_status(p):
 | 
					async def handle_get_action_status(p):
 | 
				
			||||||
    await p.send_xt('gas', int(p.data.special_dance), int(p.data.special_wave),
 | 
					    await p.send_xt('gas', int(p.special_dance), int(p.special_wave),
 | 
				
			||||||
                    int(p.data.special_snowball))
 | 
					                    int(p.special_snowball))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'mcs'))
 | 
					@handlers.handler(XTPacket('nx', 'mcs'))
 | 
				
			||||||
async def handle_map_category_setting(p, map_category: int):
 | 
					async def handle_map_category_setting(p, map_category: int):
 | 
				
			||||||
    if 0 <= map_category <= 4:
 | 
					    if 0 <= map_category <= 4:
 | 
				
			||||||
        await p.data.update(map_category=map_category).apply()
 | 
					        await p.update(map_category=map_category).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'pcos'))
 | 
					@handlers.handler(XTPacket('nx', 'pcos'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
@handlers.player_data_attribute(opened_playercard=False)
 | 
					@handlers.player_attribute(opened_playercard=False)
 | 
				
			||||||
async def handle_playercard_opened_setting(p):
 | 
					async def handle_playercard_opened_setting(p):
 | 
				
			||||||
    await p.data.update(opened_playercard=True).apply()
 | 
					    await p.update(opened_playercard=True).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'swave'))
 | 
					@handlers.handler(XTPacket('nx', 'swave'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
@handlers.player_data_attribute(special_wave=False)
 | 
					@handlers.player_attribute(special_wave=False)
 | 
				
			||||||
async def handle_special_wave(p):
 | 
					async def handle_special_wave(p):
 | 
				
			||||||
    await p.data.update(special_wave=True).apply()
 | 
					    await p.update(special_wave=True).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'sdance'))
 | 
					@handlers.handler(XTPacket('nx', 'sdance'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
@handlers.player_data_attribute(special_dance=False)
 | 
					@handlers.player_attribute(special_dance=False)
 | 
				
			||||||
async def handle_special_dance(p):
 | 
					async def handle_special_dance(p):
 | 
				
			||||||
    await p.data.update(special_dance=True).apply()
 | 
					    await p.update(special_dance=True).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('nx', 'ssnowball'))
 | 
					@handlers.handler(XTPacket('nx', 'ssnowball'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
@handlers.player_data_attribute(special_snowball=False)
 | 
					@handlers.player_attribute(special_snowball=False)
 | 
				
			||||||
async def handle_special_snowball(p):
 | 
					async def handle_special_snowball(p):
 | 
				
			||||||
    await p.data.update(special_snowball=True).apply()
 | 
					    await p.update(special_snowball=True).apply()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ def get_legacy_igloo_string_key(_, p, penguin_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_igloo_layouts_key(_, p):
 | 
					def get_igloo_layouts_key(_, p):
 | 
				
			||||||
    return f'igloo_layouts.{p.data.id}'
 | 
					    return f'igloo_layouts.{p.id}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_layout_like_count_key(_, igloo_id):
 | 
					def get_layout_like_count_key(_, igloo_id):
 | 
				
			||||||
@@ -73,7 +73,7 @@ async def get_legacy_igloo_string(p, penguin_id):
 | 
				
			|||||||
async def get_all_igloo_layouts(p):
 | 
					async def get_all_igloo_layouts(p):
 | 
				
			||||||
    layout_details = []
 | 
					    layout_details = []
 | 
				
			||||||
    slot = 0
 | 
					    slot = 0
 | 
				
			||||||
    for igloo in p.data.igloo_rooms.values():
 | 
					    for igloo in p.igloo_rooms.values():
 | 
				
			||||||
        slot += 1
 | 
					        slot += 1
 | 
				
			||||||
        furniture_string = await get_layout_furniture(p, igloo.id)
 | 
					        furniture_string = await get_layout_furniture(p, igloo.id)
 | 
				
			||||||
        like_count = await get_layout_like_count(igloo.id)
 | 
					        like_count = await get_layout_like_count(igloo.id)
 | 
				
			||||||
@@ -95,8 +95,8 @@ async def create_first_igloo(p, penguin_id):
 | 
				
			|||||||
    if igloo is None:
 | 
					    if igloo is None:
 | 
				
			||||||
        if penguin_id in p.server.penguins_by_id:
 | 
					        if penguin_id in p.server.penguins_by_id:
 | 
				
			||||||
            penguin = p.server.penguins_by_id[penguin_id]
 | 
					            penguin = p.server.penguins_by_id[penguin_id]
 | 
				
			||||||
            igloo = await penguin.data.igloo_rooms.insert(penguin_id=penguin_id, type=1, flooring=0, location=1)
 | 
					            igloo = await penguin.igloo_rooms.insert(penguin_id=penguin_id, type=1, flooring=0, location=1)
 | 
				
			||||||
            await penguin.data.update(igloo=igloo.id).apply()
 | 
					            await penguin.update(igloo=igloo.id).apply()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            igloo = await PenguinIglooRoom.create(penguin_id=penguin_id, type=1, flooring=0, location=1)
 | 
					            igloo = await PenguinIglooRoom.create(penguin_id=penguin_id, type=1, flooring=0, location=1)
 | 
				
			||||||
            await Penguin.update.values(igloo=igloo.id)\
 | 
					            await Penguin.update.values(igloo=igloo.id)\
 | 
				
			||||||
@@ -104,7 +104,7 @@ async def create_first_igloo(p, penguin_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def save_igloo_furniture(p, furniture_list=None):
 | 
					async def save_igloo_furniture(p, furniture_list=None):
 | 
				
			||||||
    await IglooFurniture.delete.where(IglooFurniture.igloo_id == p.data.igloo).gino.status()
 | 
					    await IglooFurniture.delete.where(IglooFurniture.igloo_id == p.igloo).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if furniture_list:
 | 
					    if furniture_list:
 | 
				
			||||||
        furniture_tracker = {}
 | 
					        furniture_tracker = {}
 | 
				
			||||||
@@ -112,7 +112,7 @@ async def save_igloo_furniture(p, furniture_list=None):
 | 
				
			|||||||
        for furniture_string in itertools.islice(furniture_list, 0, 100):
 | 
					        for furniture_string in itertools.islice(furniture_list, 0, 100):
 | 
				
			||||||
            furniture_id, x, y, rotation, frame = map(int, furniture_string.split('|'))
 | 
					            furniture_id, x, y, rotation, frame = map(int, furniture_string.split('|'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if furniture_id not in p.data.furniture:
 | 
					            if furniture_id not in p.furniture:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if furniture_id not in furniture_tracker:
 | 
					            if furniture_id not in furniture_tracker:
 | 
				
			||||||
@@ -120,14 +120,14 @@ async def save_igloo_furniture(p, furniture_list=None):
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                furniture_tracker[furniture_id] += 1
 | 
					                furniture_tracker[furniture_id] += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if furniture_tracker[furniture_id] > p.data.furniture[furniture_id].quantity:
 | 
					            if furniture_tracker[furniture_id] > p.furniture[furniture_id].quantity:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if not (0 <= x <= 700 and 0 <= y <= 700 and 1 <= rotation <= 8 and 1 <= frame <= 10):
 | 
					            if not (0 <= x <= 700 and 0 <= y <= 700 and 1 <= rotation <= 8 and 1 <= frame <= 10):
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            furniture.append({
 | 
					            furniture.append({
 | 
				
			||||||
                'igloo_id': p.data.igloo,
 | 
					                'igloo_id': p.igloo,
 | 
				
			||||||
                'furniture_id': furniture_id,
 | 
					                'furniture_id': furniture_id,
 | 
				
			||||||
                'x': x, 'y': y,
 | 
					                'x': x, 'y': y,
 | 
				
			||||||
                'frame': frame,
 | 
					                'frame': frame,
 | 
				
			||||||
@@ -156,24 +156,24 @@ async def handle_buy_flooring(p, flooring: Flooring):
 | 
				
			|||||||
        return await p.send_error(402)
 | 
					        return await p.send_error(402)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.is_vanilla_client:
 | 
					    if p.is_vanilla_client:
 | 
				
			||||||
        if flooring.id in p.data.flooring:
 | 
					        if flooring.id in p.flooring:
 | 
				
			||||||
            return await p.send_error(400)
 | 
					            return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.data.coins < flooring.cost:
 | 
					        if p.coins < flooring.cost:
 | 
				
			||||||
            return await p.send_error(401)
 | 
					            return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.add_flooring(flooring)
 | 
					        await p.add_flooring(flooring)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        igloo = p.data.igloo_rooms[p.data.igloo]
 | 
					        igloo = p.igloo_rooms[p.igloo]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await igloo.update(flooring=flooring.id).apply()
 | 
					        await igloo.update(flooring=flooring.id).apply()
 | 
				
			||||||
        await p.data.update(coins=p.data.coins - flooring.cost).apply()
 | 
					        await p.update(coins=p.coins - flooring.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.send_xt('ag', flooring.id, p.data.coins)
 | 
					        await p.send_xt('ag', flooring.id, p.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.server.cache.delete(f'active_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'active_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'igloo_layouts.{p.data.id}')
 | 
					        await p.server.cache.delete(f'igloo_layouts.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'aloc'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'aloc'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -181,10 +181,10 @@ async def handle_buy_igloo_location(p, location: Location):
 | 
				
			|||||||
    if location is None:
 | 
					    if location is None:
 | 
				
			||||||
        return await p.send_error(402)
 | 
					        return await p.send_error(402)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if location.id in p.data.locations:
 | 
					    if location.id in p.locations:
 | 
				
			||||||
        return await p.send_error(400)
 | 
					        return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.coins < location.cost:
 | 
					    if p.coins < location.cost:
 | 
				
			||||||
        return await p.send_error(401)
 | 
					        return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.add_location(location)
 | 
					    await p.add_location(location)
 | 
				
			||||||
@@ -195,10 +195,10 @@ async def handle_buy_igloo_type(p, igloo: Igloo):
 | 
				
			|||||||
    if igloo is None:
 | 
					    if igloo is None:
 | 
				
			||||||
        return await p.send_error(402)
 | 
					        return await p.send_error(402)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if igloo.id in p.data.igloos:
 | 
					    if igloo.id in p.igloos:
 | 
				
			||||||
        return await p.send_error(400)
 | 
					        return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.coins < igloo.cost:
 | 
					    if p.coins < igloo.cost:
 | 
				
			||||||
        return await p.send_error(401)
 | 
					        return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.add_igloo(igloo)
 | 
					    await p.add_igloo(igloo)
 | 
				
			||||||
@@ -209,10 +209,10 @@ async def handle_buy_furniture(p, furniture: Furniture):
 | 
				
			|||||||
    if furniture is None:
 | 
					    if furniture is None:
 | 
				
			||||||
        return await p.send_error(402)
 | 
					        return await p.send_error(402)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if furniture.id in p.data.igloos:
 | 
					    if furniture.id in p.igloos:
 | 
				
			||||||
        return await p.send_error(400)
 | 
					        return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.coins < furniture.cost:
 | 
					    if p.coins < furniture.cost:
 | 
				
			||||||
        return await p.send_error(401)
 | 
					        return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.add_furniture(furniture)
 | 
					    await p.add_furniture(furniture)
 | 
				
			||||||
@@ -222,18 +222,18 @@ async def handle_buy_furniture(p, furniture: Furniture):
 | 
				
			|||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_update_igloo_configuration(p, igloo_id: int, igloo_type_id: int, flooring_id: int, location_id: int,
 | 
					async def handle_update_igloo_configuration(p, igloo_id: int, igloo_type_id: int, flooring_id: int, location_id: int,
 | 
				
			||||||
                                            music_id: int, furniture_data):
 | 
					                                            music_id: int, furniture_data):
 | 
				
			||||||
    if p.room.igloo and p.room.penguin_id == p.data.id and igloo_id in p.data.igloo_rooms:
 | 
					    if p.room.igloo and p.room.penguin_id == p.id and igloo_id in p.igloo_rooms:
 | 
				
			||||||
        igloo = p.data.igloo_rooms[igloo_id]
 | 
					        igloo = p.igloo_rooms[igloo_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.data.update(igloo=igloo_id).apply()
 | 
					        await p.update(igloo=igloo_id).apply()
 | 
				
			||||||
        p.server.igloos_by_penguin_id[p.data.id] = igloo
 | 
					        p.server.igloos_by_penguin_id[p.id] = igloo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        furniture_list = furniture_data.split(',') if furniture_data else None
 | 
					        furniture_list = furniture_data.split(',') if furniture_data else None
 | 
				
			||||||
        await save_igloo_furniture(p, furniture_list)
 | 
					        await save_igloo_furniture(p, furniture_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not igloo_type_id or igloo_type_id in p.data.igloos\
 | 
					        if not igloo_type_id or igloo_type_id in p.igloos\
 | 
				
			||||||
                and not flooring_id or flooring_id in p.data.flooring\
 | 
					                and not flooring_id or flooring_id in p.flooring\
 | 
				
			||||||
                and not location_id or location_id in p.data.locations:
 | 
					                and not location_id or location_id in p.locations:
 | 
				
			||||||
            await igloo.update(
 | 
					            await igloo.update(
 | 
				
			||||||
                type=igloo_type_id,
 | 
					                type=igloo_type_id,
 | 
				
			||||||
                flooring=flooring_id,
 | 
					                flooring=flooring_id,
 | 
				
			||||||
@@ -244,12 +244,12 @@ async def handle_update_igloo_configuration(p, igloo_id: int, igloo_type_id: int
 | 
				
			|||||||
        like_count = await get_layout_like_count(igloo.id)
 | 
					        like_count = await get_layout_like_count(igloo.id)
 | 
				
			||||||
        active_igloo_string = f'{igloo.id}:1:0:{int(igloo.locked)}:{igloo.music}:{igloo.flooring}:' \
 | 
					        active_igloo_string = f'{igloo.id}:1:0:{int(igloo.locked)}:{igloo.music}:{igloo.flooring}:' \
 | 
				
			||||||
                              f'{igloo.location}:{igloo.type}:{like_count}:{furniture_data}'
 | 
					                              f'{igloo.location}:{igloo.type}:{like_count}:{furniture_data}'
 | 
				
			||||||
        await p.room.send_xt('uvi', p.data.id, active_igloo_string)
 | 
					        await p.room.send_xt('uvi', p.id, active_igloo_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.server.cache.set(f'layout_furniture.{igloo.id}', furniture_data)
 | 
					        await p.server.cache.set(f'layout_furniture.{igloo.id}', furniture_data)
 | 
				
			||||||
        await p.server.cache.set(f'active_igloo.{p.data.id}', active_igloo_string)
 | 
					        await p.server.cache.set(f'active_igloo.{p.id}', active_igloo_string)
 | 
				
			||||||
        await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'igloo_layouts.{p.data.id}')
 | 
					        await p.server.cache.delete(f'igloo_layouts.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'ur'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'ur'), client=ClientType.Legacy)
 | 
				
			||||||
@@ -257,8 +257,8 @@ async def handle_update_igloo_configuration(p, igloo_id: int, igloo_type_id: int
 | 
				
			|||||||
async def handle_save_igloo_furniture(p, *furniture_data):
 | 
					async def handle_save_igloo_furniture(p, *furniture_data):
 | 
				
			||||||
    await save_igloo_furniture(p, furniture_data)
 | 
					    await save_igloo_furniture(p, furniture_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.server.cache.set(f'layout_furniture.{p.data.igloo}', ','.join(furniture_data))
 | 
					    await p.server.cache.set(f'layout_furniture.{p.igloo}', ','.join(furniture_data))
 | 
				
			||||||
    await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					    await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_slot_converter = SeparatorConverter(separator=',', mapper=str)
 | 
					_slot_converter = SeparatorConverter(separator=',', mapper=str)
 | 
				
			||||||
@@ -267,47 +267,47 @@ _slot_converter = SeparatorConverter(separator=',', mapper=str)
 | 
				
			|||||||
@handlers.handler(XTPacket('g', 'uiss'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'uiss'), client=ClientType.Vanilla)
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_update_igloo_slot_summary(p, igloo_id: int, slot_summary: _slot_converter):
 | 
					async def handle_update_igloo_slot_summary(p, igloo_id: int, slot_summary: _slot_converter):
 | 
				
			||||||
    if p.room.igloo and p.room.penguin_id == p.data.id and igloo_id in p.data.igloo_rooms:
 | 
					    if p.room.igloo and p.room.penguin_id == p.id and igloo_id in p.igloo_rooms:
 | 
				
			||||||
        igloo = p.data.igloo_rooms[igloo_id]
 | 
					        igloo = p.igloo_rooms[igloo_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.data.update(igloo=igloo_id).apply()
 | 
					        if p.id in p.server.open_igloos_by_penguin_id:
 | 
				
			||||||
        p.server.igloos_by_penguin_id[p.data.id] = igloo
 | 
					            del p.server.open_igloos_by_penguin_id[p.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if p.data.id in p.server.open_igloos_by_penguin_id:
 | 
					        if igloo_id != p.room.id:
 | 
				
			||||||
            del p.server.open_igloos_by_penguin_id[p.data.id]
 | 
					            await p.update(igloo=igloo_id).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for slot in slot_summary:
 | 
					        for slot in slot_summary:
 | 
				
			||||||
            igloo_id, locked = map(int, slot.split('|'))
 | 
					            igloo_id, locked = map(int, slot.split('|'))
 | 
				
			||||||
            igloo = p.data.igloo_rooms[igloo_id]
 | 
					            igloo = p.igloo_rooms[igloo_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if igloo_id == p.data.igloo:
 | 
					            if igloo_id == p.igloo:
 | 
				
			||||||
                if not locked:
 | 
					                if not locked:
 | 
				
			||||||
                    p.server.open_igloos_by_penguin_id[p.data.id] = igloo
 | 
					                    p.server.open_igloos_by_penguin_id[p.data.id] = igloo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if igloo.locked != bool(locked):
 | 
					                if igloo.locked != bool(locked):
 | 
				
			||||||
                    await igloo.update(locked=bool(locked)).apply()
 | 
					                    await igloo.update(locked=bool(locked)).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.server.cache.delete(f'active_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'active_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'igloo_layouts.{p.data.id}')
 | 
					        await p.server.cache.delete(f'igloo_layouts.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        active_igloo_string = await get_active_igloo_string(p, p.data.id)
 | 
					        active_igloo_string = await get_active_igloo_string(p, p.id)
 | 
				
			||||||
        await p.room.send_xt('uvi', p.data.id, active_igloo_string)
 | 
					        await p.room.send_xt('uvi', p.id, active_igloo_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('j', 'js'), after=handle_join_server, client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('j', 'js'), after=handle_join_server, client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_add_igloo_map(p):
 | 
					async def handle_add_igloo_map(p):
 | 
				
			||||||
    if p.data.igloo is not None:
 | 
					    if p.igloo is not None:
 | 
				
			||||||
        igloo = p.data.igloo_rooms[p.data.igloo]
 | 
					        igloo = p.igloo_rooms[p.igloo]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not igloo.locked:
 | 
					        if not igloo.locked:
 | 
				
			||||||
            p.server.open_igloos_by_penguin_id[p.data.id] = igloo
 | 
					            p.server.open_igloos_by_penguin_id[p.id] = igloo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.disconnected
 | 
					@handlers.disconnected
 | 
				
			||||||
async def handle_remove_igloo_map(p):
 | 
					async def handle_remove_igloo_map(p):
 | 
				
			||||||
    if p.data.id in p.server.open_igloos_by_penguin_id:
 | 
					    if p.id in p.server.open_igloos_by_penguin_id:
 | 
				
			||||||
        del p.server.open_igloos_by_penguin_id[p.data.id]
 | 
					        del p.server.open_igloos_by_penguin_id[p.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'pio'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'pio'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -317,12 +317,12 @@ async def handle_is_player_igloo_open(p, penguin_id: int):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'al'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'al'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_add_igloo_layout(p):
 | 
					async def handle_add_igloo_layout(p):
 | 
				
			||||||
    if len(p.data.igloo_rooms) < 4:
 | 
					    if len(p.igloo_rooms) < 4:
 | 
				
			||||||
        igloo = await p.data.igloo_rooms.insert(penguin_id=p.data.id, type=1, flooring=0, location=1)
 | 
					        igloo = await p.igloo_rooms.insert(penguin_id=p.id, type=1, flooring=0, location=1)
 | 
				
			||||||
        slot_id = len(p.data.igloo_rooms)
 | 
					        slot_id = len(p.igloo_rooms)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.send_xt('al', p.data.id, f'{igloo.id}:{slot_id}:0:{int(igloo.locked)}:{igloo.music}:{igloo.flooring}:'
 | 
					        await p.send_xt('al', p.id, f'{igloo.id}:{slot_id}:0:{int(igloo.locked)}:{igloo.music}:{igloo.flooring}:'
 | 
				
			||||||
                                         f'{igloo.location}:{igloo.type}:0:')
 | 
					                                    f'{igloo.location}:{igloo.type}:0:')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'gili'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'gili'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -347,7 +347,7 @@ async def handle_get_igloo_like_by(p, pagination_start: int, pagination_end: int
 | 
				
			|||||||
                            'id': like.player_id,
 | 
					                            'id': like.player_id,
 | 
				
			||||||
                            'time': int(time.mktime(like.date.timetuple())),
 | 
					                            'time': int(time.mktime(like.date.timetuple())),
 | 
				
			||||||
                            'count': like.count,
 | 
					                            'count': like.count,
 | 
				
			||||||
                            'isFriend': like.player_id in p.data.buddies
 | 
					                            'isFriend': like.player_id in p.buddies
 | 
				
			||||||
                        } async for like in liked_by.iterate()
 | 
					                        } async for like in liked_by.iterate()
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -359,7 +359,7 @@ async def handle_get_igloo_like_by(p, pagination_start: int, pagination_end: int
 | 
				
			|||||||
@handlers.handler(XTPacket('g', 'cli'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'cli'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_can_like_igloo(p):
 | 
					async def handle_can_like_igloo(p):
 | 
				
			||||||
    last_like = await db.select([IglooLike.date]).where((IglooLike.igloo_id == p.room.id)
 | 
					    last_like = await db.select([IglooLike.date]).where((IglooLike.igloo_id == p.room.id)
 | 
				
			||||||
                                                        & (IglooLike.player_id == p.data.id)).gino.scalar()
 | 
					                                                        & (IglooLike.player_id == p.id)).gino.scalar()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    time_elapsed = datetime.now()
 | 
					    time_elapsed = datetime.now()
 | 
				
			||||||
    if last_like is not None:
 | 
					    if last_like is not None:
 | 
				
			||||||
@@ -385,7 +385,7 @@ async def handle_get_open_igloo_list(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    open_igloos = [await get_igloo_string(igloo) for igloo in p.server.open_igloos_by_penguin_id.values()]
 | 
					    open_igloos = [await get_igloo_string(igloo) for igloo in p.server.open_igloos_by_penguin_id.values()]
 | 
				
			||||||
    local_room_population = 0
 | 
					    local_room_population = 0
 | 
				
			||||||
    own_layout_like_count = 0 if p.data.igloo is None else await get_layout_like_count(p.data.igloo)
 | 
					    own_layout_like_count = 0 if p.igloo is None else await get_layout_like_count(p.igloo)
 | 
				
			||||||
    await p.send_xt('gr', own_layout_like_count, local_room_population, *open_igloos)
 | 
					    await p.send_xt('gr', own_layout_like_count, local_room_population, *open_igloos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -404,56 +404,56 @@ async def handle_get_open_igloo_list_legacy(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'or'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'or'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_unlock_igloo(p):
 | 
					async def handle_unlock_igloo(p):
 | 
				
			||||||
    igloo = p.data.igloo_rooms[p.data.igloo]
 | 
					    igloo = p.igloo_rooms[p.igloo]
 | 
				
			||||||
    p.server.open_igloos_by_penguin_id[p.data.id] = igloo
 | 
					    p.server.open_igloos_by_penguin_id[p.id] = igloo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'cr'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'cr'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_lock_igloo(p):
 | 
					async def handle_lock_igloo(p):
 | 
				
			||||||
    del p.server.open_igloos_by_penguin_id[p.data.id]
 | 
					    del p.server.open_igloos_by_penguin_id[p.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'go'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'go'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_get_owned_igloos(p):
 | 
					async def handle_get_owned_igloos(p):
 | 
				
			||||||
    await p.send_xt('go', '|'.join(str(igloo_id) for igloo_id in p.data.igloos.keys()))
 | 
					    await p.send_xt('go', '|'.join(str(igloo_id) for igloo_id in p.igloos.keys()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'gf'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'gf'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_get_furniture(p):
 | 
					async def handle_get_furniture(p):
 | 
				
			||||||
    furniture_string = '%'.join(f'{furniture.furniture_id}|{furniture.quantity}'
 | 
					    furniture_string = '%'.join(f'{furniture.furniture_id}|{furniture.quantity}'
 | 
				
			||||||
                                for furniture in p.data.furniture.values())
 | 
					                                for furniture in p.furniture.values())
 | 
				
			||||||
    await p.send_xt('gf', furniture_string)
 | 
					    await p.send_xt('gf', furniture_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'um'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'um'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_update_igloo_music(p, music_id: int):
 | 
					async def handle_update_igloo_music(p, music_id: int):
 | 
				
			||||||
    if p.room.igloo and p.room.penguin_id == p.data.id and p.room.music != music_id:
 | 
					    if p.room.igloo and p.room.penguin_id == p.id and p.room.music != music_id:
 | 
				
			||||||
        await p.room.update(music=music_id).apply()
 | 
					        await p.room.update(music=music_id).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.server.cache.delete(f'active_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'active_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'igloo_layouts.{p.data.id}')
 | 
					        await p.server.cache.delete(f'igloo_layouts.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'ao'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('g', 'ao'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_activate_igloo_type(p, igloo_type_id: int):
 | 
					async def handle_activate_igloo_type(p, igloo_type_id: int):
 | 
				
			||||||
    if p.room.igloo and p.room.penguin_id == p.data.id and p.room.type != igloo_type_id \
 | 
					    if p.room.igloo and p.room.penguin_id == p.id and p.room.type != igloo_type_id \
 | 
				
			||||||
            and igloo_type_id in p.data.igloos:
 | 
					            and igloo_type_id in p.igloos:
 | 
				
			||||||
        await p.room.update(type=igloo_type_id, flooring=0).apply()
 | 
					        await p.room.update(type=igloo_type_id, flooring=0).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await p.server.cache.delete(f'active_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'active_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'legacy_igloo.{p.data.id}')
 | 
					        await p.server.cache.delete(f'legacy_igloo.{p.id}')
 | 
				
			||||||
        await p.server.cache.delete(f'igloo_layouts.{p.data.id}')
 | 
					        await p.server.cache.delete(f'igloo_layouts.{p.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('g', 'grf'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'grf'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_get_friends_igloo_list(p):
 | 
					async def handle_get_friends_igloo_list(p):
 | 
				
			||||||
    async def get_friend_igloo_string(penguin):
 | 
					    async def get_friend_igloo_string(penguin):
 | 
				
			||||||
        like_count = 0 if penguin.data.igloo is None else await get_layout_like_count(penguin.data.igloo)
 | 
					        like_count = 0 if penguin.igloo is None else await get_layout_like_count(penguin.igloo)
 | 
				
			||||||
        return f'{penguin.data.id}|{like_count}'
 | 
					        return f'{penguin.id}|{like_count}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    friend_igloos = [await get_friend_igloo_string(penguin) for penguin in p.server.penguins_by_id.values()
 | 
					    friend_igloos = [await get_friend_igloo_string(penguin) for penguin in p.server.penguins_by_id.values()
 | 
				
			||||||
                     if penguin.data.id in p.data.buddies]
 | 
					                     if penguin.id in p.buddies]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('grf', *friend_igloos)
 | 
					    await p.send_xt('grf', *friend_igloos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -462,7 +462,7 @@ async def handle_get_friends_igloo_list(p):
 | 
				
			|||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_like_igloo(p):
 | 
					async def handle_like_igloo(p):
 | 
				
			||||||
    if p.room.igloo:
 | 
					    if p.room.igloo:
 | 
				
			||||||
        like_insert = insert(IglooLike).values(igloo_id=p.room.id, player_id=p.data.id)
 | 
					        like_insert = insert(IglooLike).returning(IglooLike.count).values(igloo_id=p.room.id, player_id=p.id)
 | 
				
			||||||
        like_insert = like_insert.on_conflict_do_update(
 | 
					        like_insert = like_insert.on_conflict_do_update(
 | 
				
			||||||
            constraint='igloo_like_pkey',
 | 
					            constraint='igloo_like_pkey',
 | 
				
			||||||
            set_=dict(count=IglooLike.count + 1, date=datetime.now()),
 | 
					            set_=dict(count=IglooLike.count + 1, date=datetime.now()),
 | 
				
			||||||
@@ -482,9 +482,9 @@ async def handle_like_igloo(p):
 | 
				
			|||||||
@handlers.handler(XTPacket('g', 'gii'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('g', 'gii'), client=ClientType.Vanilla)
 | 
				
			||||||
async def handle_get_furniture_inventory(p):
 | 
					async def handle_get_furniture_inventory(p):
 | 
				
			||||||
    furniture = ','.join(f'{furniture_id}|0000000000|{furniture_item.quantity}'
 | 
					    furniture = ','.join(f'{furniture_id}|0000000000|{furniture_item.quantity}'
 | 
				
			||||||
                         for furniture_id, furniture_item in p.data.furniture.items())
 | 
					                         for furniture_id, furniture_item in p.furniture.items())
 | 
				
			||||||
    flooring = ','.join(f'{flooring_id}|0000000000' for flooring_id in p.data.flooring.keys())
 | 
					    flooring = ','.join(f'{flooring_id}|0000000000' for flooring_id in p.flooring.keys())
 | 
				
			||||||
    igloos = ','.join(f'{igloo_id}|0000000000' for igloo_id in p.data.igloos.keys())
 | 
					    igloos = ','.join(f'{igloo_id}|0000000000' for igloo_id in p.igloos.keys())
 | 
				
			||||||
    locations = ','.join(f'{location_id}|0000000000' for location_id in p.data.locations.keys())
 | 
					    locations = ','.join(f'{location_id}|0000000000' for location_id in p.locations.keys())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('gii', furniture, flooring, igloos, locations)
 | 
					    await p.send_xt('gii', furniture, flooring, igloos, locations)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ from houdini.data.buddy import IgnoreList
 | 
				
			|||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_ignore_list(p):
 | 
					async def handle_get_ignore_list(p):
 | 
				
			||||||
    ignore_query = IgnoreList.load(parent=Penguin.on(Penguin.id == IgnoreList.ignore_id)).where(
 | 
					    ignore_query = IgnoreList.load(parent=Penguin.on(Penguin.id == IgnoreList.ignore_id)).where(
 | 
				
			||||||
        IgnoreList.penguin_id == p.data.id)
 | 
					        IgnoreList.penguin_id == p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async with p.server.db.transaction():
 | 
					    async with p.server.db.transaction():
 | 
				
			||||||
        ignore_list = ignore_query.gino.iterate()
 | 
					        ignore_list = ignore_query.gino.iterate()
 | 
				
			||||||
@@ -20,17 +20,17 @@ async def handle_get_ignore_list(p):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('n', 'rn'))
 | 
					@handlers.handler(XTPacket('n', 'rn'))
 | 
				
			||||||
async def handle_ignore_remove(p, ignored_id: int):
 | 
					async def handle_ignore_remove(p, ignored_id: int):
 | 
				
			||||||
    if ignored_id in p.data.ignore:
 | 
					    if ignored_id in p.ignore:
 | 
				
			||||||
        await p.data.ignore.delete(ignored_id)
 | 
					        await p.ignore.delete(ignored_id)
 | 
				
			||||||
        await p.send_xt('rn', ignored_id)
 | 
					        await p.send_xt('rn', ignored_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('n', 'an'))
 | 
					@handlers.handler(XTPacket('n', 'an'))
 | 
				
			||||||
async def handle_ignore_add(p, ignored_id: int):
 | 
					async def handle_ignore_add(p, ignored_id: int):
 | 
				
			||||||
    if ignored_id not in p.data.ignore:
 | 
					    if ignored_id not in p.ignore:
 | 
				
			||||||
        if ignored_id in p.server.penguins_by_id:
 | 
					        if ignored_id in p.server.penguins_by_id:
 | 
				
			||||||
            nickname = p.server.penguins_by_id[ignored_id].data.nickname
 | 
					            nickname = p.server.penguins_by_id[ignored_id].safe_name
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            nickname = await Penguin.select('nickname').where(Penguin.id == ignored_id).gino.scalar()
 | 
					            nickname = await Penguin.select('nickname').where(Penguin.id == ignored_id).gino.scalar()
 | 
				
			||||||
        await p.data.ignore.insert(ignore_id=ignored_id)
 | 
					        await p.ignore.insert(ignore_id=ignored_id)
 | 
				
			||||||
        await p.send_xt('an', ignored_id, nickname)
 | 
					        await p.send_xt('an', ignored_id, nickname)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ def get_awards_string_key(_, p, player_id):
 | 
				
			|||||||
@cached(alias='default', key_builder=get_pin_string_key)
 | 
					@cached(alias='default', key_builder=get_pin_string_key)
 | 
				
			||||||
async def get_pin_string(p, player_id):
 | 
					async def get_pin_string(p, player_id):
 | 
				
			||||||
    if player_id in p.server.penguins_by_id:
 | 
					    if player_id in p.server.penguins_by_id:
 | 
				
			||||||
        inventory = p.server.penguins_by_id[player_id].data.inventory
 | 
					        inventory = p.server.penguins_by_id[player_id].inventory
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        inventory = await PenguinItemCollection.get_collection(player_id)
 | 
					        inventory = await PenguinItemCollection.get_collection(player_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +35,7 @@ async def get_pin_string(p, player_id):
 | 
				
			|||||||
@cached(alias='default', key_builder=get_awards_string_key)
 | 
					@cached(alias='default', key_builder=get_awards_string_key)
 | 
				
			||||||
async def get_awards_string(p, player_id):
 | 
					async def get_awards_string(p, player_id):
 | 
				
			||||||
    if player_id in p.server.penguins_by_id:
 | 
					    if player_id in p.server.penguins_by_id:
 | 
				
			||||||
        inventory = p.server.penguins_by_id[player_id].data.inventory
 | 
					        inventory = p.server.penguins_by_id[player_id].inventory
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        inventory = await PenguinItemCollection.get_collection(player_id)
 | 
					        inventory = await PenguinItemCollection.get_collection(player_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,7 +46,7 @@ async def get_awards_string(p, player_id):
 | 
				
			|||||||
@handlers.handler(XTPacket('i', 'gi'))
 | 
					@handlers.handler(XTPacket('i', 'gi'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_inventory(p):
 | 
					async def handle_get_inventory(p):
 | 
				
			||||||
    await p.send_xt('gi', *p.data.inventory.keys())
 | 
					    await p.send_xt('gi', *p.inventory.keys())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('i', 'ai'))
 | 
					@handlers.handler(XTPacket('i', 'ai'))
 | 
				
			||||||
@@ -55,13 +55,13 @@ async def handle_buy_inventory(p, item: Item):
 | 
				
			|||||||
    if item is None:
 | 
					    if item is None:
 | 
				
			||||||
        return await p.send_error(402)
 | 
					        return await p.send_error(402)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if item.id in p.data.inventory:
 | 
					    if item.id in p.inventory:
 | 
				
			||||||
        return await p.send_error(400)
 | 
					        return await p.send_error(400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if item.tour:
 | 
					    if item.tour:
 | 
				
			||||||
        return await p.add_inbox(p.server.postcards[126])
 | 
					        return await p.add_inbox(p.server.postcards[126])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.coins < item.cost:
 | 
					    if p.coins < item.cost:
 | 
				
			||||||
        return await p.send_error(401)
 | 
					        return await p.send_error(401)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.add_inventory(item)
 | 
					    await p.add_inventory(item)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,9 +13,9 @@ import time
 | 
				
			|||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_start_mail_engine(p):
 | 
					async def handle_start_mail_engine(p):
 | 
				
			||||||
    mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
					    mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
				
			||||||
        PenguinPostcard.penguin_id == p.data.id).gino.scalar()
 | 
					        PenguinPostcard.penguin_id == p.id).gino.scalar()
 | 
				
			||||||
    unread_mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
					    unread_mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
				
			||||||
        (PenguinPostcard.penguin_id == p.data.id)
 | 
					        (PenguinPostcard.penguin_id == p.id)
 | 
				
			||||||
        & (PenguinPostcard.has_read == False)).gino.scalar()
 | 
					        & (PenguinPostcard.has_read == False)).gino.scalar()
 | 
				
			||||||
    await p.send_xt('mst', unread_mail_count, mail_count)
 | 
					    await p.send_xt('mst', unread_mail_count, mail_count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +24,7 @@ async def handle_start_mail_engine(p):
 | 
				
			|||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_mail(p):
 | 
					async def handle_get_mail(p):
 | 
				
			||||||
    mail_query = PenguinPostcard.load(parent=Penguin.on(Penguin.id == PenguinPostcard.sender_id)).where(
 | 
					    mail_query = PenguinPostcard.load(parent=Penguin.on(Penguin.id == PenguinPostcard.sender_id)).where(
 | 
				
			||||||
        PenguinPostcard.penguin_id == p.data.id).order_by(
 | 
					        PenguinPostcard.penguin_id == p.id).order_by(
 | 
				
			||||||
        PenguinPostcard.send_date.desc())
 | 
					        PenguinPostcard.send_date.desc())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    postcards = []
 | 
					    postcards = []
 | 
				
			||||||
@@ -41,49 +41,49 @@ async def handle_get_mail(p):
 | 
				
			|||||||
@handlers.handler(XTPacket('l', 'ms'))
 | 
					@handlers.handler(XTPacket('l', 'ms'))
 | 
				
			||||||
@handlers.cooldown(2)
 | 
					@handlers.cooldown(2)
 | 
				
			||||||
async def handle_send_mail(p, recipient_id: int, postcard_id: int):
 | 
					async def handle_send_mail(p, recipient_id: int, postcard_id: int):
 | 
				
			||||||
    if p.data.coins < 10:
 | 
					    if p.coins < 10:
 | 
				
			||||||
        return await p.send_xt('ms', p.data.coins, 0)
 | 
					        return await p.send_xt('ms', p.coins, 0)
 | 
				
			||||||
 | 
					    mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
				
			||||||
 | 
					        PenguinPostcard.penguin_id == recipient_id).gino.scalar()
 | 
				
			||||||
    if recipient_id in p.server.penguins_by_id:
 | 
					    if recipient_id in p.server.penguins_by_id:
 | 
				
			||||||
        recipient = p.server.penguins_by_id[recipient_id]
 | 
					        recipient = p.server.penguins_by_id[recipient_id]
 | 
				
			||||||
        if p.data.id in recipient.data.ignore:
 | 
					        if p.id in recipient.ignore:
 | 
				
			||||||
            return await p.send_xt('ms', p.data.coins, 1)
 | 
					            return await p.send_xt('ms', p.coins, 1)
 | 
				
			||||||
        if len(recipient.data.postcards) >= 100:
 | 
					        if mail_count >= 100:
 | 
				
			||||||
            return await p.send_xt('ms', p.data.coins, 0)
 | 
					            return await p.send_xt('ms', p.coins, 0)
 | 
				
			||||||
        postcard = await PenguinPostcard.create(penguin_id=recipient_id, sender_id=p.data.id,
 | 
					        postcard = await PenguinPostcard.create(penguin_id=recipient_id, sender_id=p.id,
 | 
				
			||||||
                                                postcard_id=postcard_id)
 | 
					                                                postcard_id=postcard_id)
 | 
				
			||||||
        sent_timestamp = int(time.mktime(postcard.send_date.timetuple()))
 | 
					        sent_timestamp = int(time.mktime(postcard.send_date.timetuple()))
 | 
				
			||||||
        await recipient.send_xt('mr', p.data.nickname, p.data.id, postcard_id, '', sent_timestamp, postcard.id)
 | 
					        await recipient.send_xt('mr', p.data.nickname, p.data.id, postcard_id, '', sent_timestamp, postcard.id)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        ignored = await IgnoreList.query.where((IgnoreList.penguin_id == recipient_id)
 | 
					        ignored = await IgnoreList.query.where((IgnoreList.penguin_id == recipient_id)
 | 
				
			||||||
                                               & (IgnoreList.ignore_id == p.data.id)).gino.scalar()
 | 
					                                               & (IgnoreList.ignore_id == p.id)).gino.scalar()
 | 
				
			||||||
        if ignored is not None:
 | 
					        if ignored is not None:
 | 
				
			||||||
            return await p.send_xt('ms', p.data.coins, 1)
 | 
					            return await p.send_xt('ms', p.coins, 1)
 | 
				
			||||||
        mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
					 | 
				
			||||||
            PenguinPostcard.penguin_id == recipient_id).gino.scalar()
 | 
					 | 
				
			||||||
        if mail_count >= 100:
 | 
					        if mail_count >= 100:
 | 
				
			||||||
            return await p.send_xt('ms', p.data.coins, 0)
 | 
					            return await p.send_xt('ms', p.coins, 0)
 | 
				
			||||||
        await PenguinPostcard.create(penguin_id=recipient_id, sender_id=p.data.id, postcard_id=postcard_id)
 | 
					        await PenguinPostcard.create(penguin_id=recipient_id, sender_id=p.id, postcard_id=postcard_id)
 | 
				
			||||||
    await p.data.update(coins=p.data.coins - 10).apply()
 | 
					    await p.update(coins=p.coins - 10).apply()
 | 
				
			||||||
    return await p.send_xt('ms', p.data.coins, 1)
 | 
					    return await p.send_xt('ms', p.coins, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('l', 'mc'))
 | 
					@handlers.handler(XTPacket('l', 'mc'))
 | 
				
			||||||
async def handle_mail_checked(p):
 | 
					async def handle_mail_checked(p):
 | 
				
			||||||
    await PenguinPostcard.update.values(has_read=True).where(
 | 
					    await PenguinPostcard.update.values(has_read=True).where(
 | 
				
			||||||
        PenguinPostcard.penguin_id == p.data.id).gino.status()
 | 
					        PenguinPostcard.penguin_id == p.id).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('l', 'md'))
 | 
					@handlers.handler(XTPacket('l', 'md'))
 | 
				
			||||||
async def handle_delete_mail(p, postcard_id: int):
 | 
					async def handle_delete_mail(p, postcard_id: int):
 | 
				
			||||||
    await PenguinPostcard.delete.where((PenguinPostcard.penguin_id == p.data.id)
 | 
					    await PenguinPostcard.delete.where((PenguinPostcard.penguin_id == p.id)
 | 
				
			||||||
                                       & (PenguinPostcard.id == postcard_id)).gino.status()
 | 
					                                       & (PenguinPostcard.id == postcard_id)).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('l', 'mdp'))
 | 
					@handlers.handler(XTPacket('l', 'mdp'))
 | 
				
			||||||
async def handle_delete_mail_from_user(p, sender_id: int):
 | 
					async def handle_delete_mail_from_user(p, sender_id: int):
 | 
				
			||||||
    sender_id = None if sender_id == 0 else sender_id
 | 
					    sender_id = None if sender_id == 0 else sender_id
 | 
				
			||||||
    await PenguinPostcard.delete.where((PenguinPostcard.penguin_id == p.data.id)
 | 
					    await PenguinPostcard.delete.where((PenguinPostcard.penguin_id == p.id)
 | 
				
			||||||
                                       & (PenguinPostcard.sender_id == sender_id)).gino.status()
 | 
					                                       & (PenguinPostcard.sender_id == sender_id)).gino.status()
 | 
				
			||||||
    mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
					    mail_count = await db.select([db.func.count(PenguinPostcard.id)]).where(
 | 
				
			||||||
        PenguinPostcard.penguin_id == p.data.id).gino.scalar()
 | 
					        PenguinPostcard.penguin_id == p.id).gino.scalar()
 | 
				
			||||||
    await p.send_xt('mdp', mail_count)
 | 
					    await p.send_xt('mdp', mail_count)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,16 +6,16 @@ from houdini.commands import invoke_command_string, has_command_prefix
 | 
				
			|||||||
@handlers.handler(XTPacket('m', 'sm'))
 | 
					@handlers.handler(XTPacket('m', 'sm'))
 | 
				
			||||||
@handlers.cooldown(.5)
 | 
					@handlers.cooldown(.5)
 | 
				
			||||||
async def handle_send_message(p, penguin_id: int, message: str):
 | 
					async def handle_send_message(p, penguin_id: int, message: str):
 | 
				
			||||||
    if penguin_id != p.data.id:
 | 
					    if penguin_id != p.id:
 | 
				
			||||||
        return await p.close()
 | 
					        return await p.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.muted:
 | 
					    if p.muted:
 | 
				
			||||||
        for penguin in p.room.penguins_by_id.values():
 | 
					        for penguin in p.room.penguins_by_id.values():
 | 
				
			||||||
            if penguin.data.moderator:
 | 
					            if penguin.moderator:
 | 
				
			||||||
                await penguin.send_xt("mm", message, penguin_id)
 | 
					                await penguin.send_xt("mm", message, penguin_id)
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if has_command_prefix(message):
 | 
					    if has_command_prefix(message):
 | 
				
			||||||
        await invoke_command_string(p.server.commands, p, message)
 | 
					        await invoke_command_string(p.server.commands, p, message)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        await p.room.send_xt('sm', p.data.id, message)
 | 
					        await p.room.send_xt('sm', p.id, message)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,7 +95,7 @@ async def get_player_tracks(p):
 | 
				
			|||||||
    likes = db.func.count(TrackLike.track_id)
 | 
					    likes = db.func.count(TrackLike.track_id)
 | 
				
			||||||
    tracks_query = db.select([PenguinTrack, likes])\
 | 
					    tracks_query = db.select([PenguinTrack, likes])\
 | 
				
			||||||
        .select_from(PenguinTrack.outerjoin(TrackLike))\
 | 
					        .select_from(PenguinTrack.outerjoin(TrackLike))\
 | 
				
			||||||
        .where(PenguinTrack.owner_id == p.data.id)\
 | 
					        .where(PenguinTrack.owner_id == p.id)\
 | 
				
			||||||
        .group_by(PenguinTrack.id).gino.load(PenguinTrack.load(likes=ColumnLoader(likes)))
 | 
					        .group_by(PenguinTrack.id).gino.load(PenguinTrack.load(likes=ColumnLoader(likes)))
 | 
				
			||||||
    async with db.transaction():
 | 
					    async with db.transaction():
 | 
				
			||||||
        async for track in tracks_query.iterate():
 | 
					        async for track in tracks_query.iterate():
 | 
				
			||||||
@@ -131,7 +131,7 @@ async def can_like_track(p, owner_id: int, track_id: int):
 | 
				
			|||||||
    like = await db.select(TrackLike) \
 | 
					    like = await db.select(TrackLike) \
 | 
				
			||||||
        .select_from(TrackLike.outerjoin(PenguinTrack)) \
 | 
					        .select_from(TrackLike.outerjoin(PenguinTrack)) \
 | 
				
			||||||
        .where((PenguinTrack.owner_id == owner_id)
 | 
					        .where((PenguinTrack.owner_id == owner_id)
 | 
				
			||||||
               & (TrackLike.penguin_id == p.data.id)
 | 
					               & (TrackLike.penguin_id == p.id)
 | 
				
			||||||
               & (TrackLike.track_id == track_id)
 | 
					               & (TrackLike.track_id == track_id)
 | 
				
			||||||
               & (TrackLike.date > yesterday)).gino.first()
 | 
					               & (TrackLike.date > yesterday)).gino.first()
 | 
				
			||||||
    return like is None
 | 
					    return like is None
 | 
				
			||||||
@@ -139,7 +139,7 @@ async def can_like_track(p, owner_id: int, track_id: int):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def get_playlist_position(p):
 | 
					def get_playlist_position(p):
 | 
				
			||||||
    for position, track in enumerate(p.server.music.playlist):
 | 
					    for position, track in enumerate(p.server.music.playlist):
 | 
				
			||||||
        if track.owner_id == p.data.id:
 | 
					        if track.owner_id == p.id:
 | 
				
			||||||
            return position + 1
 | 
					            return position + 1
 | 
				
			||||||
    return -1
 | 
					    return -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,10 +206,10 @@ async def handle_save_my_music_track(p, track_name, track_pattern, track_hash):
 | 
				
			|||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    track_count = await db.select([db.func.count(PenguinTrack.id)])\
 | 
					    track_count = await db.select([db.func.count(PenguinTrack.id)])\
 | 
				
			||||||
        .where(PenguinTrack.owner_id == p.data.id).gino.scalar()
 | 
					        .where(PenguinTrack.owner_id == p.id).gino.scalar()
 | 
				
			||||||
    if track_count >= 12:
 | 
					    if track_count >= 12:
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    track = await PenguinTrack.create(owner_id=p.data.id, name=track_name, pattern=track_pattern)
 | 
					    track = await PenguinTrack.create(owner_id=p.id, name=track_name, pattern=track_pattern)
 | 
				
			||||||
    await p.send_xt('savemymusictrack', track.id)
 | 
					    await p.send_xt('savemymusictrack', track.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -219,11 +219,11 @@ async def handle_refresh_my_track_likes(p):
 | 
				
			|||||||
    likes = db.func.count(TrackLike.track_id)
 | 
					    likes = db.func.count(TrackLike.track_id)
 | 
				
			||||||
    track_likes_query = db.select([PenguinTrack.id, likes])\
 | 
					    track_likes_query = db.select([PenguinTrack.id, likes])\
 | 
				
			||||||
        .select_from(PenguinTrack.outerjoin(TrackLike))\
 | 
					        .select_from(PenguinTrack.outerjoin(TrackLike))\
 | 
				
			||||||
        .where(PenguinTrack.owner_id == p.data.id)\
 | 
					        .where(PenguinTrack.owner_id == p.id)\
 | 
				
			||||||
        .group_by(PenguinTrack.id).gino.load(PenguinTrack.load(likes=ColumnLoader(likes)))
 | 
					        .group_by(PenguinTrack.id).gino.load(PenguinTrack.load(likes=ColumnLoader(likes)))
 | 
				
			||||||
    async with db.transaction():
 | 
					    async with db.transaction():
 | 
				
			||||||
        async for track in track_likes_query.iterate():
 | 
					        async for track in track_likes_query.iterate():
 | 
				
			||||||
            await p.send_xt('getlikecountfortrack', p.data.id, track.id, track.likes)
 | 
					            await p.send_xt('getlikecountfortrack', p.id, track.id, track.likes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('musictrack', 'sharemymusictrack'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('musictrack', 'sharemymusictrack'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -232,10 +232,10 @@ async def handle_refresh_my_track_likes(p):
 | 
				
			|||||||
async def handle_share_my_music_track(p, track_id: int, sharing: int):
 | 
					async def handle_share_my_music_track(p, track_id: int, sharing: int):
 | 
				
			||||||
    if sharing:
 | 
					    if sharing:
 | 
				
			||||||
        await PenguinTrack.update.values(sharing=False)\
 | 
					        await PenguinTrack.update.values(sharing=False)\
 | 
				
			||||||
            .where(PenguinTrack.owner_id == p.data.id).gino.status()
 | 
					            .where(PenguinTrack.owner_id == p.id).gino.status()
 | 
				
			||||||
    await PenguinTrack.update.values(sharing=bool(sharing))\
 | 
					    await PenguinTrack.update.values(sharing=bool(sharing))\
 | 
				
			||||||
        .where((PenguinTrack.id == track_id)
 | 
					        .where((PenguinTrack.id == track_id)
 | 
				
			||||||
               & (PenguinTrack.owner_id == p.data.id)).gino.status()
 | 
					               & (PenguinTrack.owner_id == p.id)).gino.status()
 | 
				
			||||||
    await p.send_xt('sharemymusictrack', 1)
 | 
					    await p.send_xt('sharemymusictrack', 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -243,7 +243,7 @@ async def handle_share_my_music_track(p, track_id: int, sharing: int):
 | 
				
			|||||||
@handlers.player_in_room(SoundStudio.StudioRoomId, SoundStudio.DeckRoomId)
 | 
					@handlers.player_in_room(SoundStudio.StudioRoomId, SoundStudio.DeckRoomId)
 | 
				
			||||||
async def handle_delete_track(p, track_id: int):
 | 
					async def handle_delete_track(p, track_id: int):
 | 
				
			||||||
    await PenguinTrack.delete.where((PenguinTrack.id == track_id)
 | 
					    await PenguinTrack.delete.where((PenguinTrack.id == track_id)
 | 
				
			||||||
                                    & (PenguinTrack.owner_id == p.data.id)).gino.status()
 | 
					                                    & (PenguinTrack.owner_id == p.id)).gino.status()
 | 
				
			||||||
    await p.send_xt('deletetrack', 1)
 | 
					    await p.send_xt('deletetrack', 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,7 +260,7 @@ async def handle_can_like_track(p, owner_id: int, track_id: int):
 | 
				
			|||||||
async def handle_like_track(p, owner_id: int, track_id: int):
 | 
					async def handle_like_track(p, owner_id: int, track_id: int):
 | 
				
			||||||
    can_like = await can_like_track(p, owner_id, track_id)
 | 
					    can_like = await can_like_track(p, owner_id, track_id)
 | 
				
			||||||
    if can_like:
 | 
					    if can_like:
 | 
				
			||||||
        await TrackLike.create(penguin_id=p.data.id, track_id=track_id)
 | 
					        await TrackLike.create(penguin_id=p.id, track_id=track_id)
 | 
				
			||||||
        like_count = await db.select([db.func.count(TrackLike.track_id)])\
 | 
					        like_count = await db.select([db.func.count(TrackLike.track_id)])\
 | 
				
			||||||
            .where(TrackLike.track_id == track_id).gino.scalar()
 | 
					            .where(TrackLike.track_id == track_id).gino.scalar()
 | 
				
			||||||
        await p.room.send_xt('liketrack', owner_id, track_id, like_count)
 | 
					        await p.room.send_xt('liketrack', owner_id, track_id, like_count)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ from datetime import datetime
 | 
				
			|||||||
@handlers.handler(XTPacket('j', 'js'), pre_login=True)
 | 
					@handlers.handler(XTPacket('j', 'js'), pre_login=True)
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_join_server(p, penguin_id: int, login_key: str):
 | 
					async def handle_join_server(p, penguin_id: int, login_key: str):
 | 
				
			||||||
    if penguin_id != p.data.id:
 | 
					    if penguin_id != p.id:
 | 
				
			||||||
        return await p.close()
 | 
					        return await p.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if login_key != p.login_key:
 | 
					    if login_key != p.login_key:
 | 
				
			||||||
@@ -22,40 +22,38 @@ async def handle_join_server(p, penguin_id: int, login_key: str):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('activefeatures')
 | 
					    await p.send_xt('activefeatures')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    moderator_status = 3 if p.data.character else 2 if p.data.stealth_moderator else 1 if p.data.moderator else 0
 | 
					    moderator_status = 3 if p.character else 2 if p.stealth_moderator else 1 if p.moderator else 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('js', int(p.data.agent_status), int(0),
 | 
					    await p.send_xt('js', int(p.agent_status), int(0),
 | 
				
			||||||
                    moderator_status, int(p.data.book_modified))
 | 
					                    moderator_status, int(p.book_modified))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    current_time = int(time.time())
 | 
					    current_time = int(time.time())
 | 
				
			||||||
    penguin_standard_time = current_time * 1000
 | 
					    penguin_standard_time = current_time * 1000
 | 
				
			||||||
    server_time_offset = 7
 | 
					    server_time_offset = 7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if p.data.timer_active:
 | 
					    if p.timer_active:
 | 
				
			||||||
        minutes_until_timer_end = datetime.combine(datetime.today(), p.data.timer_end) - datetime.now()
 | 
					        minutes_until_timer_end = datetime.combine(datetime.today(), p.timer_end) - datetime.now()
 | 
				
			||||||
        minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
 | 
					        minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        minutes_played_today = await p.data.minutes_played_today
 | 
					        minutes_played_today = await p.minutes_played_today
 | 
				
			||||||
        minutes_left_today = (p.data.timer_total.total_seconds() // 60) - minutes_played_today
 | 
					        minutes_left_today = (p.timer_total.total_seconds() // 60) - minutes_played_today
 | 
				
			||||||
        p.egg_timer_minutes = int(min(minutes_until_timer_end, minutes_left_today))
 | 
					        p.egg_timer_minutes = int(min(minutes_until_timer_end, minutes_left_today))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        p.egg_timer_minutes = 24 * 60
 | 
					        p.egg_timer_minutes = 24 * 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.send_xt('lp', await p.string, p.data.coins, int(p.data.safe_chat), p.egg_timer_minutes,
 | 
					    await p.send_xt('lp', await p.string, p.coins, int(p.safe_chat), p.egg_timer_minutes,
 | 
				
			||||||
                    penguin_standard_time, p.data.age, 0, p.data.minutes_played,
 | 
					                    penguin_standard_time, p.age, 0, p.minutes_played,
 | 
				
			||||||
                    "membership_days", server_time_offset, int(p.data.opened_playercard),
 | 
					                    "membership_days", server_time_offset, int(p.opened_playercard),
 | 
				
			||||||
                    p.data.map_category, p.data.status_field)
 | 
					                    p.map_category, p.status_field)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spawn = random.choice(p.server.spawn_rooms)
 | 
					    spawn = random.choice(p.server.spawn_rooms)
 | 
				
			||||||
    await p.join_room(spawn)
 | 
					    await p.join_room(spawn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.data.load_inventories()
 | 
					    p.server.penguins_by_id[p.id] = p
 | 
				
			||||||
 | 
					    p.server.penguins_by_username[p.username] = p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.server.penguins_by_id[p.data.id] = p
 | 
					    if p.character is not None:
 | 
				
			||||||
    p.server.penguins_by_username[p.data.username] = p
 | 
					        p.server.penguins_by_character_id[p.character] = p
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if p.data.character is not None:
 | 
					 | 
				
			||||||
        p.server.penguins_by_character_id[p.data.character] = p
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.login_timestamp = datetime.now()
 | 
					    p.login_timestamp = datetime.now()
 | 
				
			||||||
    p.joined_world = True
 | 
					    p.joined_world = True
 | 
				
			||||||
@@ -76,7 +74,7 @@ async def create_temporary_room(p, penguin_id):
 | 
				
			|||||||
    igloo = None
 | 
					    igloo = None
 | 
				
			||||||
    if penguin_id in p.server.penguins_by_id:
 | 
					    if penguin_id in p.server.penguins_by_id:
 | 
				
			||||||
        igloo_owner = p.server.penguins_by_id[penguin_id]
 | 
					        igloo_owner = p.server.penguins_by_id[penguin_id]
 | 
				
			||||||
        igloo = igloo_owner.data.igloo_rooms[igloo_owner.data.igloo]
 | 
					        igloo = igloo_owner.igloo_rooms[igloo_owner.igloo]
 | 
				
			||||||
        p.server.igloos_by_penguin_id[penguin_id] = igloo
 | 
					        p.server.igloos_by_penguin_id[penguin_id] = igloo
 | 
				
			||||||
    elif penguin_id not in p.server.igloos_by_penguin_id:
 | 
					    elif penguin_id not in p.server.igloos_by_penguin_id:
 | 
				
			||||||
        igloo = await PenguinIglooRoom.load(parent=Penguin.on(Penguin.igloo == PenguinIglooRoom.id)) \
 | 
					        igloo = await PenguinIglooRoom.load(parent=Penguin.on(Penguin.igloo == PenguinIglooRoom.id)) \
 | 
				
			||||||
@@ -89,7 +87,7 @@ async def create_temporary_room(p, penguin_id):
 | 
				
			|||||||
@handlers.handler(XTPacket('j', 'jp'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('j', 'jp'), client=ClientType.Vanilla)
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_join_player_room(p, penguin_id: int, room_type: str):
 | 
					async def handle_join_player_room(p, penguin_id: int, room_type: str):
 | 
				
			||||||
    if room_type == 'backyard' and p.room.igloo and p.room.penguin_id == p.data.id:
 | 
					    if room_type == 'backyard' and p.room.igloo and p.room.penguin_id == p.id:
 | 
				
			||||||
        backyard = PenguinBackyardRoom()
 | 
					        backyard = PenguinBackyardRoom()
 | 
				
			||||||
        await p.send_xt('jp', backyard.id, backyard.id, room_type)
 | 
					        await p.send_xt('jp', backyard.id, backyard.id, room_type)
 | 
				
			||||||
        await p.join_room(backyard)
 | 
					        await p.join_room(backyard)
 | 
				
			||||||
@@ -119,15 +117,15 @@ async def handle_disconnect_room(p):
 | 
				
			|||||||
    await p.room.remove_penguin(p)
 | 
					    await p.room.remove_penguin(p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    minutes_played = (datetime.now() - p.login_timestamp).total_seconds() / 60.0
 | 
					    minutes_played = (datetime.now() - p.login_timestamp).total_seconds() / 60.0
 | 
				
			||||||
    await Login.create(penguin_id=p.data.id,
 | 
					    await Login.create(penguin_id=p.id,
 | 
				
			||||||
                       date=p.login_timestamp,
 | 
					                       date=p.login_timestamp,
 | 
				
			||||||
                       ip_address=p.peer_name[0],
 | 
					                       ip_address=p.peer_name[0],
 | 
				
			||||||
                       minutes_played=minutes_played)
 | 
					                       minutes_played=minutes_played)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.data.update(minutes_played=p.data.minutes_played + minutes_played).apply()
 | 
					    await p.update(minutes_played=p.minutes_played + minutes_played).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    del p.server.penguins_by_id[p.data.id]
 | 
					    del p.server.penguins_by_id[p.id]
 | 
				
			||||||
    del p.server.penguins_by_username[p.data.username]
 | 
					    del p.server.penguins_by_username[p.username]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    server_key = f'houdini.players.{p.server.server_config["Id"]}'
 | 
					    server_key = f'houdini.players.{p.server.server_config["Id"]}'
 | 
				
			||||||
    await p.server.redis.srem(server_key, p.data.id)
 | 
					    await p.server.redis.srem(server_key, p.data.id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,10 @@ DefaultPartyCookie = {
 | 
				
			|||||||
@handlers.handler(XTPacket('party', 'partycookie'))
 | 
					@handlers.handler(XTPacket('party', 'partycookie'))
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_party_cookie(p):
 | 
					async def handle_party_cookie(p):
 | 
				
			||||||
    cookie = await p.server.redis.hget('partycookie', p.data.id)
 | 
					    cookie = await p.server.redis.hget('partycookie', p.id)
 | 
				
			||||||
    if cookie is None:
 | 
					    if cookie is None:
 | 
				
			||||||
        cookie = ujson.dumps(DefaultPartyCookie)
 | 
					        cookie = ujson.dumps(DefaultPartyCookie)
 | 
				
			||||||
        await p.server.redis.hset('partycookie', p.data.id, cookie)
 | 
					        await p.server.redis.hset('partycookie', p.id, cookie)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        cookie = cookie.decode('utf-8')
 | 
					        cookie = cookie.decode('utf-8')
 | 
				
			||||||
    await p.send_xt('partycookie', cookie)
 | 
					    await p.send_xt('partycookie', cookie)
 | 
				
			||||||
@@ -27,34 +27,34 @@ async def handle_party_cookie(p):
 | 
				
			|||||||
@handlers.handler(XTPacket('party', 'msgviewed'))
 | 
					@handlers.handler(XTPacket('party', 'msgviewed'))
 | 
				
			||||||
@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
					@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
				
			||||||
async def handle_party_message_viewed(p, message_index: int):
 | 
					async def handle_party_message_viewed(p, message_index: int):
 | 
				
			||||||
    cookie = await p.server.redis.hget('partycookie', p.data.id)
 | 
					    cookie = await p.server.redis.hget('partycookie', p.id)
 | 
				
			||||||
    cookie = ujson.loads(cookie)
 | 
					    cookie = ujson.loads(cookie)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cookie['msgViewedArray'][message_index] = 1
 | 
					    cookie['msgViewedArray'][message_index] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.server.redis.hset('partycookie', p.data.id, ujson.dumps(cookie))
 | 
					    await p.server.redis.hset('partycookie', p.id, ujson.dumps(cookie))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('party', 'qcmsgviewed'))
 | 
					@handlers.handler(XTPacket('party', 'qcmsgviewed'))
 | 
				
			||||||
@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
					@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
				
			||||||
async def handle_party_communicator_message_viewed(p, message_index: int):
 | 
					async def handle_party_communicator_message_viewed(p, message_index: int):
 | 
				
			||||||
    cookie = await p.server.redis.hget('partycookie', p.data.id)
 | 
					    cookie = await p.server.redis.hget('partycookie', p.id)
 | 
				
			||||||
    cookie = ujson.loads(cookie)
 | 
					    cookie = ujson.loads(cookie)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cookie['communicatorMsgArray'][message_index] = 1
 | 
					    cookie['communicatorMsgArray'][message_index] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.server.redis.hset('partycookie', p.data.id, ujson.dumps(cookie))
 | 
					    await p.server.redis.hset('partycookie', p.id, ujson.dumps(cookie))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('party', 'qtaskcomplete'))
 | 
					@handlers.handler(XTPacket('party', 'qtaskcomplete'))
 | 
				
			||||||
@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
					@handlers.depends_on_packet(XTPacket('party', 'partycookie'))
 | 
				
			||||||
async def handle_party_task_complete(p, task_index: int):
 | 
					async def handle_party_task_complete(p, task_index: int):
 | 
				
			||||||
    cookie = await p.server.redis.hget('partycookie', p.data.id)
 | 
					    cookie = await p.server.redis.hget('partycookie', p.id)
 | 
				
			||||||
    cookie = ujson.loads(cookie)
 | 
					    cookie = ujson.loads(cookie)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cookie['questTaskStatus'][task_index] = 1
 | 
					    cookie['questTaskStatus'][task_index] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.server.redis.hset('partycookie', p.data.id, ujson.dumps(cookie))
 | 
					    await p.server.redis.hset('partycookie', p.id, ujson.dumps(cookie))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('party', 'qtupdate'))
 | 
					@handlers.handler(XTPacket('party', 'qtupdate'))
 | 
				
			||||||
@@ -62,5 +62,5 @@ async def handle_party_task_complete(p, task_index: int):
 | 
				
			|||||||
@handlers.cooldown(5)
 | 
					@handlers.cooldown(5)
 | 
				
			||||||
async def handle_party_task_update(p, coins: int):
 | 
					async def handle_party_task_update(p, coins: int):
 | 
				
			||||||
    coins = min(coins, 10)
 | 
					    coins = min(coins, 10)
 | 
				
			||||||
    await p.data.update(coins=p.data.coins + coins).apply()
 | 
					    await p.update(coins=p.coins + coins).apply()
 | 
				
			||||||
    await p.send_xt('qtupdate', p.data.coins)
 | 
					    await p.send_xt('qtupdate', p.coins)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,28 +51,28 @@ async def server_egg_timer(server):
 | 
				
			|||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
        await asyncio.sleep(60)
 | 
					        await asyncio.sleep(60)
 | 
				
			||||||
        for p in server.penguins_by_id.values():
 | 
					        for p in server.penguins_by_id.values():
 | 
				
			||||||
            if p.data.timer_active:
 | 
					            if p.timer_active:
 | 
				
			||||||
                p.egg_timer_minutes -= 1
 | 
					                p.egg_timer_minutes -= 1
 | 
				
			||||||
                if p.client_type == ClientType.Vanilla:
 | 
					                if p.is_vanilla_client:
 | 
				
			||||||
                    minutes_until_timer_end = datetime.combine(datetime.today(), p.data.timer_end) - datetime.now()
 | 
					                    minutes_until_timer_end = datetime.combine(datetime.today(), p.timer_end) - datetime.now()
 | 
				
			||||||
                    minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
 | 
					                    minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if minutes_until_timer_end <= p.egg_timer_minutes + 1:
 | 
					                    if minutes_until_timer_end <= p.egg_timer_minutes + 1:
 | 
				
			||||||
                        if p.egg_timer_minutes == 7:
 | 
					                        if p.egg_timer_minutes == 7:
 | 
				
			||||||
                            await p.send_error(915, p.egg_timer_minutes, p.data.timer_start, p.data.timer_end)
 | 
					                            await p.send_error(915, p.egg_timer_minutes, p.timer_start, p.timer_end)
 | 
				
			||||||
                        elif p.egg_timer_minutes == 5:
 | 
					                        elif p.egg_timer_minutes == 5:
 | 
				
			||||||
                            await p.send_error(915, p.egg_timer_minutes, p.data.timer_start, p.data.timer_end)
 | 
					                            await p.send_error(915, p.egg_timer_minutes, p.timer_start, p.timer_end)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        if p.egg_timer_minutes == 7:
 | 
					                        if p.egg_timer_minutes == 7:
 | 
				
			||||||
                            await p.send_error(914, p.egg_timer_minutes, p.data.timer_total)
 | 
					                            await p.send_error(914, p.egg_timer_minutes, p.timer_total)
 | 
				
			||||||
                        elif p.egg_timer_minutes == 5:
 | 
					                        elif p.egg_timer_minutes == 5:
 | 
				
			||||||
                            await p.send_error(914, p.egg_timer_minutes, p.data.timer_total)
 | 
					                            await p.send_error(914, p.egg_timer_minutes, p.timer_total)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    await p.send_xt('uet', p.egg_timer_minutes)
 | 
					                    await p.send_xt('uet', max(0, p.egg_timer_minutes))
 | 
				
			||||||
                    if p.egg_timer_minutes <= 0:
 | 
					                    if p.egg_timer_minutes < 0:
 | 
				
			||||||
                        await p.send_error_and_disconnect(916, p.data.timer_start, p.data.timer_end)
 | 
					                        await p.send_error_and_disconnect(916, p.timer_start, p.timer_end)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    if p.egg_timer_minutes <= 0:
 | 
					                    if p.egg_timer_minutes < 0:
 | 
				
			||||||
                        await p.send_error_and_disconnect(910)
 | 
					                        await p.send_error_and_disconnect(910)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,7 +117,7 @@ async def handle_get_player_by_name(p, player_name: str):
 | 
				
			|||||||
    player_name = player_name.lower()
 | 
					    player_name = player_name.lower()
 | 
				
			||||||
    if player_name in p.server.penguins_by_username:
 | 
					    if player_name in p.server.penguins_by_username:
 | 
				
			||||||
        player = p.server.penguins_by_username[player_name]
 | 
					        player = p.server.penguins_by_username[player_name]
 | 
				
			||||||
        await p.send_xt('pbn', player.data.id, player.data.id, player.data.nickname)
 | 
					        await p.send_xt('pbn', player.id, player.id, player.safe_name)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        result = await Penguin.select('id', 'nickname').where(
 | 
					        result = await Penguin.select('id', 'nickname').where(
 | 
				
			||||||
            Penguin.username == player_name).gino.first()
 | 
					            Penguin.username == player_name).gino.first()
 | 
				
			||||||
@@ -131,9 +131,9 @@ async def handle_get_player_by_name(p, player_name: str):
 | 
				
			|||||||
@handlers.handler(XTPacket('u', 'smi'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('u', 'smi'), client=ClientType.Vanilla)
 | 
				
			||||||
@handlers.cooldown(10)
 | 
					@handlers.cooldown(10)
 | 
				
			||||||
async def handle_send_mascot_invite(p, num_invites: int, character_id: int):
 | 
					async def handle_send_mascot_invite(p, num_invites: int, character_id: int):
 | 
				
			||||||
    if character_id in p.server.characters and p.data.character is not None:
 | 
					    if character_id in p.server.characters and p.character is not None:
 | 
				
			||||||
        for _ in range(min(num_invites, len(p.server.penguins_by_id))):
 | 
					        players = random.sample(list(p.server.penguins_by_id.values()), min(num_invites, len(p.server.penguins_by_id)))
 | 
				
			||||||
            player = random.choice(list(p.server.penguins_by_id.values()))
 | 
					        for player in players:
 | 
				
			||||||
            await player.send_xt('smi', character_id)
 | 
					            await player.send_xt('smi', character_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -151,7 +151,7 @@ async def handle_find_player(p, player_id: int):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'gbffl'))
 | 
					@handlers.handler(XTPacket('u', 'gbffl'))
 | 
				
			||||||
async def handle_get_best_friends(p):
 | 
					async def handle_get_best_friends(p):
 | 
				
			||||||
    await p.send_xt('gbffl', ','.join((str(buddy.buddy_id) for buddy in p.data.buddies.values() if buddy.best_buddy)))
 | 
					    await p.send_xt('gbffl', ','.join((str(buddy.buddy_id) for buddy in p.buddies.values() if buddy.best_buddy)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'pbsms'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('u', 'pbsms'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -174,49 +174,49 @@ async def handle_set_player_position(p, x: int, y: int):
 | 
				
			|||||||
    p.x, p.y = x, y
 | 
					    p.x, p.y = x, y
 | 
				
			||||||
    p.frame = 1
 | 
					    p.frame = 1
 | 
				
			||||||
    p.toy = None
 | 
					    p.toy = None
 | 
				
			||||||
    await p.room.send_xt('sp', p.data.id, x, y)
 | 
					    await p.room.send_xt('sp', p.id, x, y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'sf'))
 | 
					@handlers.handler(XTPacket('u', 'sf'))
 | 
				
			||||||
@handlers.cooldown(.5)
 | 
					@handlers.cooldown(.5)
 | 
				
			||||||
async def handle_set_player_frame(p, frame: int):
 | 
					async def handle_set_player_frame(p, frame: int):
 | 
				
			||||||
    p.frame = frame
 | 
					    p.frame = frame
 | 
				
			||||||
    await p.room.send_xt('sf', p.data.id, frame)
 | 
					    await p.room.send_xt('sf', p.id, frame)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'sb'))
 | 
					@handlers.handler(XTPacket('u', 'sb'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_throw_ball(p, x: int, y: int):
 | 
					async def handle_send_throw_ball(p, x: int, y: int):
 | 
				
			||||||
    await p.room.send_xt('sb', p.data.id, x, y)
 | 
					    await p.room.send_xt('sb', p.id, x, y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'se'))
 | 
					@handlers.handler(XTPacket('u', 'se'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_emote(p, emote: int):
 | 
					async def handle_send_emote(p, emote: int):
 | 
				
			||||||
    await p.room.send_xt('se', p.data.id, emote)
 | 
					    await p.room.send_xt('se', p.id, emote)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'sa'))
 | 
					@handlers.handler(XTPacket('u', 'sa'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_action(p, action: int):
 | 
					async def handle_send_action(p, action: int):
 | 
				
			||||||
    await p.room.send_xt('sa', p.data.id, action)
 | 
					    await p.room.send_xt('sa', p.id, action)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'followpath'))
 | 
					@handlers.handler(XTPacket('u', 'followpath'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_follow_path(p, path: int):
 | 
					async def handle_follow_path(p, path: int):
 | 
				
			||||||
    await p.room.send_xt('followpath', p.data.id, path)
 | 
					    await p.room.send_xt('followpath', p.id, path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'ss'))
 | 
					@handlers.handler(XTPacket('u', 'ss'))
 | 
				
			||||||
async def handle_send_safe_message(p, message_id: int):
 | 
					async def handle_send_safe_message(p, message_id: int):
 | 
				
			||||||
    await p.room.send_xt('ss', p.data.id, message_id)
 | 
					    await p.room.send_xt('ss', p.id, message_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'sma'))
 | 
					@handlers.handler(XTPacket('u', 'sma'))
 | 
				
			||||||
async def handle_send_mascot_message(p, message_id: int):
 | 
					async def handle_send_mascot_message(p, message_id: int):
 | 
				
			||||||
    if p.data.character:
 | 
					    if p.character:
 | 
				
			||||||
        await p.room.send_xt('sma', p.data.id, message_id)
 | 
					        await p.room.send_xt('sma', p.id, message_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('u', 'glr'))
 | 
					@handlers.handler(XTPacket('u', 'glr'))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,61 +7,61 @@ from houdini.data.item import Item
 | 
				
			|||||||
@handlers.handler(XTPacket('s', 'upc'))
 | 
					@handlers.handler(XTPacket('s', 'upc'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_colour(p, item: Item):
 | 
					async def handle_send_update_player_colour(p, item: Item):
 | 
				
			||||||
    if item.id in p.data.inventory and item.is_color():
 | 
					    if item.id in p.inventory and item.is_color():
 | 
				
			||||||
        await p.set_color(item)
 | 
					        await p.set_color(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'uph'))
 | 
					@handlers.handler(XTPacket('s', 'uph'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_head(p, item: Item):
 | 
					async def handle_send_update_player_head(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_head()):
 | 
					    if item is None or (item.id in p.inventory and item.is_head()):
 | 
				
			||||||
        await p.set_head(item)
 | 
					        await p.set_head(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upf'))
 | 
					@handlers.handler(XTPacket('s', 'upf'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_face(p, item: Item):
 | 
					async def handle_send_update_player_face(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_face()):
 | 
					    if item is None or (item.id in p.inventory and item.is_face()):
 | 
				
			||||||
        await p.set_face(item)
 | 
					        await p.set_face(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upn'))
 | 
					@handlers.handler(XTPacket('s', 'upn'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_neck(p, item: Item):
 | 
					async def handle_send_update_player_neck(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_neck()):
 | 
					    if item is None or (item.id in p.inventory and item.is_neck()):
 | 
				
			||||||
        await p.set_neck(item)
 | 
					        await p.set_neck(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upb'))
 | 
					@handlers.handler(XTPacket('s', 'upb'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_body(p, item: Item):
 | 
					async def handle_send_update_player_body(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_body()):
 | 
					    if item is None or (item.id in p.inventory and item.is_body()):
 | 
				
			||||||
        await p.set_body(item)
 | 
					        await p.set_body(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upa'))
 | 
					@handlers.handler(XTPacket('s', 'upa'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_hand(p, item: Item):
 | 
					async def handle_send_update_player_hand(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_hand()):
 | 
					    if item is None or (item.id in p.inventory and item.is_hand()):
 | 
				
			||||||
        await p.set_hand(item)
 | 
					        await p.set_hand(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upe'))
 | 
					@handlers.handler(XTPacket('s', 'upe'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_feet(p, item: Item):
 | 
					async def handle_send_update_player_feet(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_feet()):
 | 
					    if item is None or (item.id in p.inventory and item.is_feet()):
 | 
				
			||||||
        await p.set_feet(item)
 | 
					        await p.set_feet(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upl'))
 | 
					@handlers.handler(XTPacket('s', 'upl'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_flag(p, item: Item):
 | 
					async def handle_send_update_player_flag(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_flag()):
 | 
					    if item is None or (item.id in p.inventory and item.is_flag()):
 | 
				
			||||||
        await p.set_flag(item)
 | 
					        await p.set_flag(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('s', 'upp'))
 | 
					@handlers.handler(XTPacket('s', 'upp'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_send_update_player_photo(p, item: Item):
 | 
					async def handle_send_update_player_photo(p, item: Item):
 | 
				
			||||||
    if item is None or (item.id in p.data.inventory and item.is_photo()):
 | 
					    if item is None or (item.id in p.inventory and item.is_photo()):
 | 
				
			||||||
        await p.set_photo(item)
 | 
					        await p.set_photo(item)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,8 @@ def get_player_stamps_key(_, p, player_id):
 | 
				
			|||||||
async def get_book_cover_string(p, player_id):
 | 
					async def get_book_cover_string(p, player_id):
 | 
				
			||||||
    if player_id in p.server.penguins_by_id:
 | 
					    if player_id in p.server.penguins_by_id:
 | 
				
			||||||
        player = p.server.penguins_by_id[player_id]
 | 
					        player = p.server.penguins_by_id[player_id]
 | 
				
			||||||
        cover_details = [player.data.book_color, player.data.book_highlight, player.data.book_pattern,
 | 
					        cover_details = [player.book_color, player.book_highlight, player.book_pattern,
 | 
				
			||||||
                         player.data.book_icon]
 | 
					                         player.book_icon]
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        cover_details = list(await Penguin.select('book_color', 'book_highlight', 'book_pattern', 'book_icon')
 | 
					        cover_details = list(await Penguin.select('book_color', 'book_highlight', 'book_pattern', 'book_icon')
 | 
				
			||||||
                             .where(Penguin.id == player_id).gino.first())
 | 
					                             .where(Penguin.id == player_id).gino.first())
 | 
				
			||||||
@@ -41,7 +41,7 @@ async def get_book_cover_string(p, player_id):
 | 
				
			|||||||
@cached(alias='default', key_builder=get_player_stamps_key)
 | 
					@cached(alias='default', key_builder=get_player_stamps_key)
 | 
				
			||||||
async def get_player_stamps_string(p, player_id):
 | 
					async def get_player_stamps_string(p, player_id):
 | 
				
			||||||
    if player_id in p.server.penguins_by_id:
 | 
					    if player_id in p.server.penguins_by_id:
 | 
				
			||||||
        stamp_inventory = p.server.penguins_by_id[player_id].data.stamps
 | 
					        stamp_inventory = p.server.penguins_by_id[player_id].stamps
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        stamp_inventory = await PenguinStampCollection.get_collection(player_id)
 | 
					        stamp_inventory = await PenguinStampCollection.get_collection(player_id)
 | 
				
			||||||
    return '|'.join(map(str, stamp_inventory.keys()))
 | 
					    return '|'.join(map(str, stamp_inventory.keys()))
 | 
				
			||||||
@@ -50,20 +50,20 @@ async def get_player_stamps_string(p, player_id):
 | 
				
			|||||||
@handlers.handler(XTPacket('j', 'js'), after=handle_join_server)
 | 
					@handlers.handler(XTPacket('j', 'js'), after=handle_join_server)
 | 
				
			||||||
@handlers.allow_once
 | 
					@handlers.allow_once
 | 
				
			||||||
async def handle_get_stamps(p):
 | 
					async def handle_get_stamps(p):
 | 
				
			||||||
    await p.send_xt('gps', p.data.id, await get_player_stamps_string(p, p.data.id))
 | 
					    await p.send_xt('gps', p.id, await get_player_stamps_string(p, p.id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('st', 'gps'))
 | 
					@handlers.handler(XTPacket('st', 'gps'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_get_player_stamps(p, player_id: int):
 | 
					async def handle_get_player_stamps(p, player_id: int):
 | 
				
			||||||
    await p.send_xt('gps', p.data.id, await get_player_stamps_string(p, player_id))
 | 
					    await p.send_xt('gps', p.id, await get_player_stamps_string(p, player_id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('st', 'gmres'))
 | 
					@handlers.handler(XTPacket('st', 'gmres'))
 | 
				
			||||||
@handlers.cooldown(1)
 | 
					@handlers.cooldown(1)
 | 
				
			||||||
async def handle_get_recent_stamps(p):
 | 
					async def handle_get_recent_stamps(p):
 | 
				
			||||||
    recent_stamps = []
 | 
					    recent_stamps = []
 | 
				
			||||||
    for stamp in p.data.stamps.values():
 | 
					    for stamp in p.stamps.values():
 | 
				
			||||||
        if stamp.recent:
 | 
					        if stamp.recent:
 | 
				
			||||||
            recent_stamps.append(stamp.stamp_id)
 | 
					            recent_stamps.append(stamp.stamp_id)
 | 
				
			||||||
            await stamp.update(recent=False).apply()
 | 
					            await stamp.update(recent=False).apply()
 | 
				
			||||||
@@ -88,8 +88,8 @@ async def handle_update_book_cover(p, color: int, highlight: int, pattern: int,
 | 
				
			|||||||
           and len(cover) <= 10):
 | 
					           and len(cover) <= 10):
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await CoverItem.delete.where(CoverItem.penguin_id == p.data.id).gino.status()
 | 
					    await CoverItem.delete.where(CoverItem.penguin_id == p.id).gino.status()
 | 
				
			||||||
    await CoverStamp.delete.where(CoverStamp.penguin_id == p.data.id).gino.status()
 | 
					    await CoverStamp.delete.where(CoverStamp.penguin_id == p.id).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stamp_tracker = set()
 | 
					    stamp_tracker = set()
 | 
				
			||||||
    inventory_tracker = set()
 | 
					    inventory_tracker = set()
 | 
				
			||||||
@@ -106,19 +106,19 @@ async def handle_update_book_cover(p, color: int, highlight: int, pattern: int,
 | 
				
			|||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if stamp_type == 0:
 | 
					        if stamp_type == 0:
 | 
				
			||||||
            if stamp_id in stamp_tracker or stamp_id not in p.data.stamps:
 | 
					            if stamp_id in stamp_tracker or stamp_id not in p.stamps:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
            stamp_tracker.add(stamp_id)
 | 
					            stamp_tracker.add(stamp_id)
 | 
				
			||||||
            cover_stamps.append({'penguin_id': p.data.id, 'stamp_id': stamp_id, 'x': pos_x, 'y': pos_y,
 | 
					            cover_stamps.append({'penguin_id': p.id, 'stamp_id': stamp_id, 'x': pos_x, 'y': pos_y,
 | 
				
			||||||
                                 'rotation': rotation, 'depth': depth})
 | 
					                                 'rotation': rotation, 'depth': depth})
 | 
				
			||||||
        elif stamp_type == 1 or stamp_type == 2:
 | 
					        elif stamp_type == 1 or stamp_type == 2:
 | 
				
			||||||
            cover_item = p.server.items[stamp_id]
 | 
					            cover_item = p.server.items[stamp_id]
 | 
				
			||||||
            if stamp_id in inventory_tracker or stamp_id not in p.data.inventory or \
 | 
					            if stamp_id in inventory_tracker or stamp_id not in p.inventory or \
 | 
				
			||||||
                    (stamp_type == 1 and not cover_item.is_flag()) or \
 | 
					                    (stamp_type == 1 and not cover_item.is_flag()) or \
 | 
				
			||||||
                    (stamp_type == 2 and not cover_item.is_award()):
 | 
					                    (stamp_type == 2 and not cover_item.is_award()):
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
            inventory_tracker.add(stamp_id)
 | 
					            inventory_tracker.add(stamp_id)
 | 
				
			||||||
            cover_items.append({'penguin_id': p.data.id, 'item_id': stamp_id, 'x': pos_x, 'y': pos_y,
 | 
					            cover_items.append({'penguin_id': p.id, 'item_id': stamp_id, 'x': pos_x, 'y': pos_y,
 | 
				
			||||||
                               'rotation': rotation, 'depth': depth})
 | 
					                               'rotation': rotation, 'depth': depth})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if cover_items:
 | 
					    if cover_items:
 | 
				
			||||||
@@ -126,11 +126,11 @@ async def handle_update_book_cover(p, color: int, highlight: int, pattern: int,
 | 
				
			|||||||
    if cover_stamps:
 | 
					    if cover_stamps:
 | 
				
			||||||
        await CoverStamp.insert().values(cover_stamps).gino.status()
 | 
					        await CoverStamp.insert().values(cover_stamps).gino.status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await p.data.update(book_color=color,
 | 
					    await p.update(book_color=color,
 | 
				
			||||||
                        book_highlight=highlight,
 | 
					                   book_highlight=highlight,
 | 
				
			||||||
                        book_pattern=pattern,
 | 
					                   book_pattern=pattern,
 | 
				
			||||||
                        book_icon=icon,
 | 
					                   book_icon=icon,
 | 
				
			||||||
                        book_modified=1).apply()
 | 
					                   book_modified=1).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stringified_cover = '%'.join(cover)
 | 
					    stringified_cover = '%'.join(cover)
 | 
				
			||||||
    await p.server.cache.set(f'book.{p.data.id}', f'{color}%{highlight}%{pattern}%{icon}%{stringified_cover}')
 | 
					    await p.server.cache.set(f'book.{p.id}', f'{color}%{highlight}%{pattern}%{icon}%{stringified_cover}')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,20 +6,20 @@ from houdini.constants import ClientType
 | 
				
			|||||||
@handlers.handler(XTPacket('t', 'at'))
 | 
					@handlers.handler(XTPacket('t', 'at'))
 | 
				
			||||||
async def handle_open_book(p, toy_id: int):
 | 
					async def handle_open_book(p, toy_id: int):
 | 
				
			||||||
    p.toy = toy_id
 | 
					    p.toy = toy_id
 | 
				
			||||||
    await p.room.send_xt('at', p.data.id, toy_id)
 | 
					    await p.room.send_xt('at', p.id, toy_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('t', 'rt'))
 | 
					@handlers.handler(XTPacket('t', 'rt'))
 | 
				
			||||||
async def handle_close_book(p):
 | 
					async def handle_close_book(p):
 | 
				
			||||||
    p.toy = None
 | 
					    p.toy = None
 | 
				
			||||||
    await p.room.send_xt('rt', p.data.id)
 | 
					    await p.room.send_xt('rt', p.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('j', 'jr'), client=ClientType.Legacy)
 | 
					@handlers.handler(XTPacket('j', 'jr'), client=ClientType.Legacy)
 | 
				
			||||||
async def handle_join_room_toy(p):
 | 
					async def handle_join_room_toy(p):
 | 
				
			||||||
    for penguin in p.room.penguins_by_id.values():
 | 
					    for penguin in p.room.penguins_by_id.values():
 | 
				
			||||||
        if penguin.toy is not None:
 | 
					        if penguin.toy is not None:
 | 
				
			||||||
            await p.send_xt('at', penguin.data.id, penguin.toy)
 | 
					            await p.send_xt('at', penguin.id, penguin.toy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@handlers.handler(XTPacket('j', 'crl'), client=ClientType.Vanilla)
 | 
					@handlers.handler(XTPacket('j', 'crl'), client=ClientType.Vanilla)
 | 
				
			||||||
@@ -27,4 +27,4 @@ async def handle_join_room_toy(p):
 | 
				
			|||||||
async def handle_client_room_loaded_toy(p):
 | 
					async def handle_client_room_loaded_toy(p):
 | 
				
			||||||
    for penguin in p.room.penguins_by_id.values():
 | 
					    for penguin in p.room.penguins_by_id.values():
 | 
				
			||||||
        if penguin.toy is not None:
 | 
					        if penguin.toy is not None:
 | 
				
			||||||
            await p.send_xt('at', penguin.data.id, penguin.toy)
 | 
					            await p.send_xt('at', penguin.id, penguin.toy)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from houdini.spheniscidae import Spheniscidae
 | 
					from houdini.spheniscidae import Spheniscidae
 | 
				
			||||||
 | 
					from houdini.data import penguin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Penguin(Spheniscidae):
 | 
					class Penguin(Spheniscidae, penguin.Penguin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __slots__ = ['x', 'y', 'frame', 'toy', 'room', 'waddle', 'table',
 | 
					    __slots__ = ['x', 'y', 'frame', 'toy', 'room', 'waddle', 'table',
 | 
				
			||||||
                 'data', 'muted', 'login_key', 'member', 'membership_days',
 | 
					                 'data', 'muted', 'login_key', 'member', 'membership_days',
 | 
				
			||||||
@@ -22,7 +23,6 @@ class Penguin(Spheniscidae):
 | 
				
			|||||||
        self.table = None
 | 
					        self.table = None
 | 
				
			||||||
        self.muted = False
 | 
					        self.muted = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.data = None
 | 
					 | 
				
			||||||
        self.login_key = None
 | 
					        self.login_key = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.member = 1
 | 
					        self.member = 1
 | 
				
			||||||
@@ -61,22 +61,22 @@ class Penguin(Spheniscidae):
 | 
				
			|||||||
    async def join_room(self, room):
 | 
					    async def join_room(self, room):
 | 
				
			||||||
        await room.add_penguin(self)
 | 
					        await room.add_penguin(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} joined room \'{room.name}\'')
 | 
					        self.logger.info(f'{self.username} joined room \'{room.name}\'')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_inventory(self, item, notify=True):
 | 
					    async def add_inventory(self, item, notify=True):
 | 
				
			||||||
        if item.id in self.data.inventory:
 | 
					        if item.id in self.inventory:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.inventory.insert(item_id=item.id)
 | 
					        await self.inventory.insert(item_id=item.id)
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - item.cost).apply()
 | 
					        await self.update(coins=self.coins - item.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('ai', item.id, self.data.coins)
 | 
					            await self.send_xt('ai', item.id, self.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{item.name}\' to their clothing inventory')
 | 
					        self.logger.info(f'{self.username} added \'{item.name}\' to their clothing inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.server.cache.delete(f'pins.{self.data.id}')
 | 
					        await self.server.cache.delete(f'pins.{self.id}')
 | 
				
			||||||
        await self.server.cache.delete(f'awards.{self.data.id}')
 | 
					        await self.server.cache.delete(f'awards.{self.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -84,209 +84,210 @@ class Penguin(Spheniscidae):
 | 
				
			|||||||
        if not item.epf:
 | 
					        if not item.epf:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if item.id in self.data.inventory:
 | 
					        if item.id in self.inventory:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.inventory.insert(item_id=item.id)
 | 
					        await self.inventory.insert(item_id=item.id)
 | 
				
			||||||
        await self.data.update(agent_medals=self.data.agent_medals - item.cost).apply()
 | 
					        await self.update(agent_medals=self.agent_medals - item.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('epfai', self.data.agent_medals)
 | 
					            await self.send_xt('epfai', self.agent_medals)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_igloo(self, igloo, notify=True):
 | 
					    async def add_igloo(self, igloo, notify=True):
 | 
				
			||||||
        if igloo.id in self.data.igloos:
 | 
					        if igloo.id in self.igloos:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.igloos.insert(igloo_id=igloo.id)
 | 
					        await self.igloos.insert(igloo_id=igloo.id)
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - igloo.cost).apply()
 | 
					        await self.update(coins=self.coins - igloo.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('au', igloo.id, self.data.coins)
 | 
					            await self.send_xt('au', igloo.id, self.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{igloo.name}\' to their igloos inventory')
 | 
					        self.logger.info(f'{self.username} added \'{igloo.name}\' to their igloos inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_puffle_item(self, care_item, quantity=1, notify=True):
 | 
					    async def add_puffle_item(self, care_item, quantity=1, notify=True):
 | 
				
			||||||
        if care_item.id in self.data.puffle_items:
 | 
					        if care_item.id in self.puffle_items:
 | 
				
			||||||
            penguin_care_item = self.data.puffle_items[care_item.id]
 | 
					            penguin_care_item = self.puffle_items[care_item.id]
 | 
				
			||||||
            if penguin_care_item.quantity >= 100:
 | 
					            if penguin_care_item.quantity >= 100:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await penguin_care_item.update(
 | 
					            await penguin_care_item.update(
 | 
				
			||||||
                quantity=penguin_care_item.quantity + quantity).apply()
 | 
					                quantity=penguin_care_item.quantity + quantity).apply()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await self.data.puffle_items.insert(item_id=care_item.id)
 | 
					            await self.puffle_items.insert(item_id=care_item.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - care_item.cost).apply()
 | 
					        await self.update(coins=self.coins - care_item.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('papi', self.data.coins, care_item.id, quantity)
 | 
					            await self.send_xt('papi', self.coins, care_item.id, quantity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{care_item.name}\' to their puffle care inventory')
 | 
					        self.logger.info(f'{self.username} added \'{care_item.name}\' to their puffle care inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_furniture(self, furniture, quantity=1, notify=True):
 | 
					    async def add_furniture(self, furniture, quantity=1, notify=True):
 | 
				
			||||||
        if furniture.id in self.data.furniture:
 | 
					        if furniture.id in self.furniture:
 | 
				
			||||||
            penguin_furniture = self.data.furniture[furniture.id]
 | 
					            penguin_furniture = self.furniture[furniture.id]
 | 
				
			||||||
            if penguin_furniture.quantity >= furniture.max_quantity:
 | 
					            if penguin_furniture.quantity >= furniture.max_quantity:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await penguin_furniture.update(
 | 
					            await penguin_furniture.update(
 | 
				
			||||||
                quantity=penguin_furniture.quantity + quantity).apply()
 | 
					                quantity=penguin_furniture.quantity + quantity).apply()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await self.data.furniture.insert(furniture_id=furniture.id)
 | 
					            await self.furniture.insert(furniture_id=furniture.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - furniture.cost).apply()
 | 
					        await self.update(coins=self.coins - furniture.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('af', furniture.id, self.data.coins)
 | 
					            await self.send_xt('af', furniture.id, self.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{furniture.name}\' to their furniture inventory')
 | 
					        self.logger.info(f'{self.username} added \'{furniture.name}\' to their furniture inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_card(self, card, quantity=1):
 | 
					    async def add_card(self, card, quantity=1):
 | 
				
			||||||
        if card.id in self.data.cards:
 | 
					        if card.id in self.cards:
 | 
				
			||||||
            penguin_card = self.data.cards[card.id]
 | 
					            penguin_card = self.cards[card.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await penguin_card.update(
 | 
					            await penguin_card.update(
 | 
				
			||||||
                quantity=penguin_card.quantity + quantity).apply()
 | 
					                quantity=penguin_card.quantity + quantity).apply()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await self.data.cards.insert(card_id=card.id)
 | 
					            await self.cards.insert(card_id=card.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{card.name}\' to their ninja deck')
 | 
					        self.logger.info(f'{self.username} added \'{card.name}\' to their ninja deck')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_flooring(self, flooring, notify=True):
 | 
					    async def add_flooring(self, flooring, notify=True):
 | 
				
			||||||
        if flooring.id in self.data.flooring:
 | 
					        if flooring.id in self.flooring:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.flooring.insert(flooring_id=flooring.id)
 | 
					        await self.flooring.insert(flooring_id=flooring.id)
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - flooring.cost).apply()
 | 
					        await self.update(coins=self.coins - flooring.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('ag', flooring.id, self.data.coins)
 | 
					            await self.send_xt('ag', flooring.id, self.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{flooring.name}\' to their flooring inventory')
 | 
					        self.logger.info(f'{self.username} added \'{flooring.name}\' to their flooring inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_location(self, location, notify=True):
 | 
					    async def add_location(self, location, notify=True):
 | 
				
			||||||
        if location.id in self.data.locations:
 | 
					        if location.id in self.locations:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.locations.insert(location_id=location.id)
 | 
					        await self.locations.insert(location_id=location.id)
 | 
				
			||||||
        await self.data.update(coins=self.data.coins - location.cost).apply()
 | 
					        await self.update(coins=self.coins - location.cost).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('aloc', location.id, self.data.coins)
 | 
					            await self.send_xt('aloc', location.id, self.coins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} added \'{location.name}\' to their location inventory')
 | 
					        self.logger.info(f'{self.username} added \'{location.name}\' to their location inventory')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_stamp(self, stamp, notify=True):
 | 
					    async def add_stamp(self, stamp, notify=True):
 | 
				
			||||||
        if stamp.id in self.data.stamps:
 | 
					        if stamp.id in self.stamps:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.data.stamps.insert(stamp_id=stamp.id)
 | 
					        await self.stamps.insert(stamp_id=stamp.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if notify:
 | 
					        if notify:
 | 
				
			||||||
            await self.send_xt('aabs', stamp.id)
 | 
					            await self.send_xt('aabs', stamp.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} earned stamp \'{stamp.name}\'')
 | 
					        self.logger.info(f'{self.username} earned stamp \'{stamp.name}\'')
 | 
				
			||||||
        await self.server.cache.delete(f'stamps.{self.data.id}')
 | 
					        await self.server.cache.delete(f'stamps.{self.id}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_inbox(self, postcard, sender_name="sys", sender_id=None, details=""):
 | 
					    async def add_inbox(self, postcard, sender_name="sys", sender_id=None, details=""):
 | 
				
			||||||
        penguin_postcard = await self.data.postcards.insert(penguin_id=self.data.id, sender_id=sender_id, postcard_id=postcard.id, details=details)
 | 
					        penguin_postcard = await self.postcards.insert(penguin_id=self.id, sender_id=sender_id,
 | 
				
			||||||
 | 
					                                                       postcard_id=postcard.id, details=details)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await self.send_xt('mr', sender_name, 0, postcard.id, details, int(time.time()), penguin_postcard.id)
 | 
					        await self.send_xt('mr', sender_name, 0, postcard.id, details, int(time.time()), penguin_postcard.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def add_permission(self, permission):
 | 
					    async def add_permission(self, permission):
 | 
				
			||||||
        if permission not in self.data.permissions:
 | 
					        if permission not in self.permissions:
 | 
				
			||||||
            await self.data.permissions.insert(name=permission)
 | 
					            await self.permissions.insert(name=permission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} was assigned permission \'{permission}\'')
 | 
					        self.logger.info(f'{self.username} was assigned permission \'{permission}\'')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_color(self, item):
 | 
					    async def set_color(self, item):
 | 
				
			||||||
        await self.data.update(color=item.id).apply()
 | 
					        await self.update(color=item.id).apply()
 | 
				
			||||||
        await self.room.send_xt('upc', self.data.id, item.id)
 | 
					        await self.room.send_xt('upc', self.id, item.id)
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their color to \'{item.name}\' ')
 | 
					        self.logger.info(f'{self.username} updated their color to \'{item.name}\' ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_head(self, item):
 | 
					    async def set_head(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(head=item_id).apply()
 | 
					        await self.update(head=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('uph', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('uph', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their head item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their head item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their head item')
 | 
					                         f'{self.username} removed their head item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_face(self, item):
 | 
					    async def set_face(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(face=item_id).apply()
 | 
					        await self.update(face=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upf', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upf', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their face item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their face item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their face item')
 | 
					                         f'{self.username} removed their face item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_neck(self, item):
 | 
					    async def set_neck(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(neck=item_id).apply()
 | 
					        await self.update(neck=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upn', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upn', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their neck item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their neck item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their neck item')
 | 
					                         f'{self.username} removed their neck item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_body(self, item):
 | 
					    async def set_body(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(body=item_id).apply()
 | 
					        await self.update(body=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upb', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upb', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their body item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their body item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their body item')
 | 
					                         f'{self.username} removed their body item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_hand(self, item):
 | 
					    async def set_hand(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(hand=item_id).apply()
 | 
					        await self.update(hand=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upa', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upa', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their hand item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their hand item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their hand item')
 | 
					                         f'{self.username} removed their hand item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_feet(self, item):
 | 
					    async def set_feet(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(feet=item_id).apply()
 | 
					        await self.update(feet=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upe', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upe', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their feet item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their feet item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their feet item')
 | 
					                         f'{self.username} removed their feet item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_flag(self, item):
 | 
					    async def set_flag(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(flag=item_id).apply()
 | 
					        await self.update(flag=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upl', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upl', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their flag item to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their flag item to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their flag item')
 | 
					                         f'{self.username} removed their flag item')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def set_photo(self, item):
 | 
					    async def set_photo(self, item):
 | 
				
			||||||
        item_id = None if item is None else item.id
 | 
					        item_id = None if item is None else item.id
 | 
				
			||||||
        await self.data.update(photo=item_id).apply()
 | 
					        await self.update(photo=item_id).apply()
 | 
				
			||||||
        await self.room.send_xt('upp', self.data.id, item_id or 0)
 | 
					        await self.room.send_xt('upp', self.id, item_id or 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.info(f'{self.data.username} updated their background to \'{item.name}\' ' if item else
 | 
					        self.logger.info(f'{self.username} updated their background to \'{item.name}\' ' if item else
 | 
				
			||||||
                         f'{self.data.username} removed their background item')
 | 
					                         f'{self.username} removed their background item')
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self):
 | 
				
			||||||
        if self.data is not None:
 | 
					        if self.id is not None:
 | 
				
			||||||
            return f'<Penguin ID=\'{self.data.id}\' Username=\'{self.data.username}\'>'
 | 
					            return f'<Penguin ID=\'{self.id}\' Username=\'{self.username}\'>'
 | 
				
			||||||
        return super().__repr__()
 | 
					        return super().__repr__()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user