async def joinChannel(self, name, permanent=True): """|coro| Join a #channel. The event 'on_channel_joined' is dispatched when the client has successfully joined a channel. :param name: :class:`str` the channel's name :param permanent: Optional[:class:`bool`] if True (default) the server will automatically reconnect the user to this channel when logged in. """ await self.sendCP(54, Packet().writeString(name).writeBool(permanent))
async def use(self): """|coro| Uses this item.""" if self.inventory is None or self.inventory.client is None: raise TypeError( "InventoryItem doesn't have the inventory variable or Inventory doesn't have the client variable." ) await self.inventory.client.main.send( Packet.new(31, 3).write16(self.id))
async def sendRoomMessage(self, message): """|coro| Send a message to the room. :param message: :class:`str` the content of the message. """ packet = Packet.new(6, 6).writeString(message) await self.bulle.send(packet, cipher=True)
async def lock(self): """|coro| Locks (confirms) the trade.""" if self.state != TradeState.TRADING: raise TradeOnWrongState('lock', self.state) if self.locked[1]: raise TypeError("Can not lock a trade that is already locked by the client.") await self.client.main.send(Packet.new(31, 9).writeBool(True))
async def unlock(self): """|coro| Unlocks (cancels the confirmation) the trade.""" if self.state != TradeState.TRADING: raise TradeOnWrongState('lock', self.state) if not self.locked[1]: raise TypeError("Can not unlock a trade that is not locked by the client.") await self.client.main.send(Packet.new(31, 9).writeBool(False))
def data_received(self, data, connection): """|coro| Dispatches the received data. :param data: :class:`bytes` the received data. :param connection: :class:`aiotfm.Connection` the connection that received the data. """ # :desc: Called when a socket receives a packet. Does not interfere # with :meth:`Client.handle_packet`. # :param connection: :class:`aiotfm.Connection` the connection that received # the packet. # :param packet: :class:`aiotfm.Packet` a copy of the packet. self.dispatch('raw_socket', connection, Packet(data)) try: self.loop.create_task(self.handle_packet(connection, Packet(data))) except Exception: traceback.print_exc()
async def sendCommand(self, command): """|coro| Send a command to the game. :param command: :class:`str` the command to send. """ packet = Packet.new(6, 26).writeString(command[:255]) await self.main.send(packet, cipher=True)
async def cancel(self): """|coro| Cancels the trade.""" if not self.alive: raise TypeError("Can not cancel a dead trade.") self._close() self.canceled = True await self._client.main.send( Packet.new(31, 6).writeString(self._other.username).write8(2)) self._client.dispatch('trade_close', self)
async def sendChannelMessage(self, channel, message): """|coro| Send a message to a public channel. :param channel: :class:`str` the channel's name. :param message: :class:`str` the content of the message. """ if isinstance(channel, Channel): channel = channel.name return await self.sendCP(48, Packet().writeString(channel).writeString(message))
async def unlock(self): """|coro| Unlocks (cancels the confirmation) the trade.""" if not self.alive: raise TypeError("Can not lock a dead trade.") if self.on_invite: raise TypeError( "Can not lock a trade when it is on the invite state.") if not self.locked_me: raise TypeError( "Can not lock a trade that is already unlocked by me.") await self._client.main.send(Packet.new(31, 9).writeBool(False))
async def loadLua(self, lua_code): """|coro| Load a lua code in the room. :param lua_code: :class:`str` or :class:`bytes` the lua code to send. """ if isinstance(lua_code, str): lua_code = lua_code.encode() packet = Packet.new(29, 1).write24(len(lua_code)).writeBytes(lua_code) await self.bulle.send(packet)
async def sendSmiley(self, smiley): """|coro| Makes the client showing a smiley above it's head. :param smiley: :class:`int` the smiley's id. (from 0 to 9) """ if smiley < 0 or smiley > 9: raise AiotfmException('Invalid smiley id') packet = Packet.new(8, 5).write8(smiley).write32(0) await self.bulle.send(packet)
async def joinRoom(self, room_name, community=None, auto=False): """|coro| Join a room. The event 'on_joined_room' is dispatched when the client has successfully joined the room. :param room_name: :class:`str` the room's name. :param community: Optional[:class:`int`] the room's community. :param auto: Optional[:class:`bool`] joins a random room (I think). """ packet = Packet.new(5, 38).write8(community or self.community) packet.writeString(room_name).writeBool(auto) await self.main.send(packet)
async def playEmote(self, emote, flag='be'): """|coro| Play an emote. :param emote: :class:`int` the emote's id. :param flag: Optional[:class:`str`] the flag for the emote id 10. Defaults to 'be'. """ packet = Packet.new(8, 1).write8(id).write32(0) if emote == 10: packet.writeString(flag) await self.bulle.send(packet)
async def removeItem(self, item_id, quantity): """|coro| Removes an item from the trade. :param item_id: :class:`int` The item id. :param quantity: :class:`int` The quantity of item to remove.""" if self.state != TradeState.TRADING: raise TradeOnWrongState('removeItem', self.state) quantity = min(max(quantity, 0), 200) packet = Packet.new(31, 8).write16(item_id).writeBool(False).buffer ten = packet + b'\x01' for i in range(quantity // 10): await self.client.main.send(Packet(ten)) await asyncio.sleep(.05) unit = packet + b'\x00' for i in range(quantity % 10): await self.client.main.send(Packet(unit)) await asyncio.sleep(.05)
def from_packet(cls, packet: Packet): """Read the inventory from a packet. :param packet: :class:`aiotfm.Packet` the packet. :return: :class:`aiotfm.inventory.Inventory` the inventory. """ items = {} for item in range(packet.read16()): item = InventoryItem.from_packet(packet) items[item.id] = item return cls(items=items)
async def leaveChannel(self, channel): """|coro| Leaves a #channel. :param channel: :class:`aiotfm.message.Channel` channel to leave. """ if isinstance(channel, Channel): name = channel.name else: name = channel await self.sendCP(56, Packet().writeString(name))
def from_packet(cls, packet: Packet): """Reads a ShamanObject from a packet. :param packet: :class:`aiotfm.Packet` :return: :class:`aiotfm.shop.ShamanObject` """ return cls(packet.read32(), packet.read8(), packet.readBool(), packet.read8(), packet.read32(), packet.read16())
async def accept(self): """|coro| Accepts the trade.""" if not self.alive: raise TypeError("Can not accept a dead trade.") if not self.on_invite: raise TypeError( "Can not accept a trade when it is not on the invite state.") if self.accepted: raise TypeError("Can not accept an already accepted trade.") self.accepted = True await self._client.main.send( Packet.new(31, 5).writeString(self._other.username))
async def addItem(self, id, ten=False): """|coro| Adds an item to the trade. :param id: :class:`int` The item id. :param ten: Optional[:class:`bool`] Whether to add ten items or only one.""" if not self.alive: raise TypeError("Can not add items to a dead trade.") if self.on_invite: raise TypeError( "Can not add items to a trade when it is on the invite state.") await self._client.main.send( Packet.new(31, 8).write16(id).writeBool(True).writeBool(ten))
def from_packet(cls, packet: Packet): """Reads an Item from a packet. :param packet: :class:`aiotfm.Packet` :return: :class:`aiotfm.shop.Item` """ nbr_colors = packet.read8() uid = packet.read32() cat = (uid - 10000) // 10000 if uid > 9999 else uid // 100 if uid < 99: id_ = uid elif uid < 999: id_ = uid % (100 * cat) elif uid < 9999: id_ = uid % 100 else: id_ = uid % 1000 colors = [] if nbr_colors > 0: colors = [packet.read32() for i in range(nbr_colors - 1)] return cls(cat, id_, colors)
async def sendHandshake(self): """|coro| Sends the handshake packet so the server recognizes this socket as a player. """ packet = Packet.new(28, 1).write16(self.keys.version).writeString(self.keys.connection) packet.writeString('Desktop').writeString('-').write32(0x1fbd).writeString('') packet.writeString('74696720697320676f6e6e61206b696c6c206d7920626f742e20736f20736164') packet.writeString( "A=t&SA=t&SV=t&EV=t&MP3=t&AE=t&VE=t&ACC=t&PR=t&SP=f&SB=f&DEB=f&V=LNX 29,0,0,140&M=Adobe" " Linux&R=1920x1080&COL=color&AR=1.0&OS=Linux&ARCH=x86&L=en&IME=t&PR32=t&PR64=t&LS=en-U" "S&PT=Desktop&AVD=f&LFD=f&WD=f&TLS=t&ML=5.1&DP=72") packet.write32(0).write32(0x6257).writeString('') await self.main.send(packet)
async def sendCP(self, code, data=b''): """|coro| Send a packet to the community platform. :param code: :class:`int` the community platform code. :param data: :class:`aiotfm.Packet` or :class:`bytes` the data. """ self.cp_fingerprint = fp = (self.cp_fingerprint + 1) % 0XFFFFFFFF packet = Packet.new(60, 3).write16(code) packet.write32(self.cp_fingerprint).writeBytes(data) await self.main.send(packet, cipher=True) return fp
async def removeItem(self, id, ten=False): """|coro| Removes an item from the trade. :param id: :class:`int` The item id. :param ten: Optional[:class:`bool`] Whether to remove ten items or only one.""" if not self.alive: raise TypeError("Can not remove items from a dead trade.") if self.on_invite: raise TypeError( "Can not remove items from a trade when it is on the invite state." ) await self._client.main.send( Packet.new(31, 8).write16(id).writeBool(False).writeBool(ten))
def __init__(self, packet:Packet): self.cheese = packet.read32() self.fraise = packet.read32() self.look = packet.readUTF() self.owned_items = set(Item.from_packet(packet) for i in range(packet.read32())) self.items = set(ShopItem.from_packet(packet) for i in range(packet.read32())) self.full_outfits = set(Outfit.from_fashion(packet) for i in range(packet.read8())) self.outfits = set(Outfit.from_packet(packet, i) for i in range(packet.read16())) self.owned_shaman_objects = set(OwnedShamanObject.from_packet(packet) for i in range(packet.read16())) self.shaman_objects = set(ShamanObject.from_packet(packet) for i in range(packet.read16()))
async def joinRoom(self, room_name, password=None, community=None, auto=False): """|coro| Join a room. The event 'on_joined_room' is dispatched when the client has successfully joined the room. :param password: :class:`str` if given the client will ignore `community` and `auto` parameters and will connect to the room with the given password. :param room_name: :class:`str` the room's name. :param community: Optional[:class:`int`] the room's community. :param auto: Optional[:class:`bool`] joins a random room (I think). """ if password is not None: packet = Packet.new( 5, 39).writeString(password).writeString(room_name) else: packet = Packet.new(5, 38).writeString( Community(community or self.community).name) packet.writeString(room_name).writeBool(auto) await self.main.send(packet)
async def who(self): """|coro| Sends the command /who to the channel and returns the list of players. :throws: :class:`asyncio.TimeoutError` :return: List[:class:`aiotfm.Player`]""" def check(idseq, players): return idseq == idSequence idSequence = await self._client.sendCP(58, Packet().writeString(self.name)) _, players = await self._client.wait_for('on_channel_who', check, timeout=3) return players
async def getRoomList(self, gamemode=0, timeout=3): """|coro| Get the room list :param gamemode: Optional[:class:`aiotfm.enums.GameMode`] the room's gamemode. :param timeout: Optional[:class:`int`] timeout in seconds. Defaults to 3 seconds. :return: :class:`aiotfm.room.RoomList` the room list for the given gamemode or None """ await self.main.send(Packet.new(26, 35).write8(int(gamemode))) def predicate(roomlist): return gamemode == 0 or roomlist.gamemode == gamemode try: return await self.wait_for('on_room_list', predicate, timeout=timeout) except asyncio.TimeoutError: return None
async def login(self, username, password, encrypted=True, room='1'): """|coro| Log in the game. :param username: :class:`str` the client username. :param password: :class:`str` the client password. :param encrypted: Optional[:class:`bool`] whether the password is already encrypted or not. :param room: Optional[:class:`str`] the room where the client will be logged in. """ if not encrypted: password = shakikoo(password) packet = Packet.new(26, 8).writeString(username).writeString(password) packet.writeString("app:/TransformiceAIR.swf/[[DYNAMIC]]/2/[[DYNAMIC]]/4") packet.writeString(room).write32(self.authkey ^ self.keys.auth).write8(0).writeString('') packet.cipher(self.keys.identification).write8(0) await self.main.send(packet)
def __init__(self, packet: Packet): self.id: int = packet.read32() self.name: str = packet.readUTF() self.welcomeMessage: str = packet.readUTF() self.mapcode: int = packet.read32() self.members: List[Member] = [] self.ranks: List[Rank] = [] for i in range(packet.read16()): self.members.append(Member(self, packet)) for i in range(packet.read16()): self.ranks.append(Rank.from_packet(i, packet))