Make houdini.penguin.Penguin inherit houdini.data.penguin.Penguin

This allows for much clearer syntax
This commit is contained in:
Ben 2019-12-02 23:04:59 +00:00
parent 15e8035d26
commit 3e7943c6db
21 changed files with 438 additions and 481 deletions

View File

@ -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'),

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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,11 +317,11 @@ 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:')
@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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'))

View File

@ -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)

View File

@ -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}')

View File

@ -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)

View File

@ -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__()