Exemple #1
0
 def unsubscribe_channel(self, channel):
     dg = Datagram()
     dg.add_uint8(1)
     dg.add_channel(CONTROL_MESSAGE)
     dg.add_uint16(CONTROL_REMOVE_CHANNEL)
     dg.add_channel(channel)
     self.send_datagram(dg)
Exemple #2
0
    def ai_format_generate(self, obj, do_id, parent_id, zone_id, district_channel_id, from_channel_id, optional_fields):
        dg = Datagram()
        dg.add_uint8(1)
        dg.add_channel(district_channel_id)
        dg.add_channel(from_channel_id)
        if optional_fields:
            dg.add_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER)
        else:
            dg.add_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED)

        #if parent_id:
        dg.add_uint32(parent_id)

        dg.add_uint32(zone_id)
        dg.add_uint16(self.number)
        dg.add_uint32(do_id)

        for field in self.inherited_fields:
            if not isinstance(field, MolecularField) and field.is_required:
                self.pack_field(dg, obj, field)

        if optional_fields:
            dg.add_uint16(len(optional_fields))

            for field_name in optional_fields:
                field = self.fields_by_name[field_name]
                dg.add_uint16(field.number)
                self.pack_field(dg, obj, field)

        return dg
Exemple #3
0
    async def created_avatar(self):
        f = DatagramFuture(self.service.loop,
                           DBSERVER_CREATE_STORED_OBJECT_RESP)
        self.futures.append(f)
        sender, dgi = await f
        context = dgi.get_uint32()
        return_code = dgi.get_uint8()
        av_id = dgi.get_uint32()

        av = self.potential_avatar
        av.do_id = av_id
        self.potential_avatars[av.index] = av
        self.potential_avatar = None

        resp = Datagram()
        resp.add_uint16(CLIENT_CREATE_AVATAR_RESP)
        resp.add_uint16(0)  # Context
        resp.add_uint8(return_code)  # Return Code
        resp.add_uint32(av_id)  # av_id
        self.send_datagram(resp)

        self.created_av_id = av_id

        self.service.log.debug(
            f'New avatar {av_id} created for client {self.channel}.')
Exemple #4
0
 def send_location_entry(self, location):
     dg = Datagram()
     dg.add_server_header([location], self.do_id, STATESERVER_OBJECT_ENTERZONE_WITH_REQUIRED_OTHER)
     dg.add_uint8(bool(self.ram))
     self.append_required_data(dg, True, False)
     if self.ram:
         self.append_other_data(dg, True, False)
     self.service.send_datagram(dg)
Exemple #5
0
    def receive_create_avatar(self, dgi):
        _ = dgi.get_uint16()
        dna = dgi.get_blob16()
        pos = dgi.get_uint8()
        self.service.log.debug(
            f'Client {self.channel} requesting avatar creation with dna {dna} and pos {pos}.'
        )

        if not 0 <= pos < 6 or self.potential_avatars[pos] is not None:
            self.service.log.debug(
                f'Client {self.channel} tried creating avatar in invalid position.'
            )
            return

        self.potential_avatar = PotentialAvatar(do_id=0,
                                                name='Toon',
                                                wish_name='',
                                                approved_name='',
                                                rejected_name='',
                                                dna_string=dna,
                                                index=pos)

        dclass = self.service.dc_file.namespace['DistributedToon']

        dg = Datagram()
        dg.add_server_header([DBSERVERS_CHANNEL], self.channel,
                             DBSERVER_CREATE_STORED_OBJECT)
        dg.add_uint32(0)
        dg.add_uint16(dclass.number)
        dg.add_uint32(self.account.disl_id)
        dg.add_uint8(pos)
        pos = dg.tell()
        dg.add_uint16(0)

        default_toon = dict(DEFAULT_TOON)
        default_toon['setDNAString'] = (dna, )
        default_toon['setDISLid'] = (self.account.disl_id, )
        default_toon['WishName'] = ('', )
        default_toon['WishNameState'] = ('CLOSED', )

        count = 0
        for field in dclass.inherited_fields:
            if not isinstance(field, MolecularField) and field.is_db:
                if field.name == 'DcObjectType':
                    continue
                dg.add_uint16(field.number)
                field.pack_value(dg, default_toon[field.name])
                count += 1

        dg.seek(pos)
        dg.add_uint16(count)

        self.state = ClientState.CREATING_AVATAR

        self.service.send_datagram(dg)

        self.tasks.append(self.service.loop.create_task(self.created_avatar()))
Exemple #6
0
    def ai_format_update(self, do_id, to_id, from_id, args):
        dg = Datagram()

        dg.add_uint8(1)
        dg.add_channel(to_id)
        dg.add_channel(from_id)
        dg.add_uint16(STATESERVER_OBJECT_UPDATE_FIELD)
        dg.add_uint32(do_id)
        dg.add_uint16(self.number)
        self.pack_value(dg, args)
        return dg
Exemple #7
0
    async def create_object(self, sender, context, dclass, fields):
        try:
            do_id = await self.backend.create_object(dclass, fields)
        except OTPCreateFailed as e:
            print('creation failed', e)
            do_id = 0

        dg = Datagram()
        dg.add_server_header([sender], DBSERVERS_CHANNEL, DBSERVER_CREATE_STORED_OBJECT_RESP)
        dg.add_uint32(context)
        dg.add_uint8(do_id == 0)
        dg.add_uint32(do_id)
        self.send_datagram(dg)
Exemple #8
0
    def receive_delete_avatar(self, dgi):
        av_id = dgi.get_uint32()

        av = self.get_potential_avatar(av_id)

        if not av:
            return

        self.potential_avatars[av.index] = None
        avatars = [
            pot_av.do_id if pot_av else 0 for pot_av in self.potential_avatars
        ]
        self.avs_deleted.append((av_id, int(time.time())))

        field = self.service.dc_file.namespace['Account']['ACCOUNT_AV_SET']
        del_field = self.service.dc_file.namespace['Account'][
            'ACCOUNT_AV_SET_DEL']

        dg = Datagram()
        dg.add_server_header([DBSERVERS_CHANNEL], self.channel,
                             DBSERVER_SET_STORED_VALUES)
        dg.add_uint32(self.account.disl_id)
        dg.add_uint16(2)
        dg.add_uint16(field.number)
        field.pack_value(dg, avatars)
        dg.add_uint16(del_field.number)
        del_field.pack_value(dg, self.avs_deleted)
        self.service.send_datagram(dg)

        resp = Datagram()
        resp.add_uint16(CLIENT_DELETE_AVATAR_RESP)
        resp.add_uint8(0)  # Return code

        av_count = sum(
            (1 if pot_av else 0 for pot_av in self.potential_avatars))
        dg.add_uint16(av_count)

        for pot_av in self.potential_avatars:
            if not pot_av:
                continue
            dg.add_uint32(pot_av.do_id)
            dg.add_string16(pot_av.name.encode('utf-8'))
            dg.add_string16(pot_av.wish_name.encode('utf-8'))
            dg.add_string16(pot_av.approved_name.encode('utf-8'))
            dg.add_string16(pot_av.rejected_name.encode('utf-8'))
            dg.add_string16(pot_av.dna_string.encode('utf-8'))
            dg.add_uint8(pot_av.index)

        self.send_datagram(resp)
Exemple #9
0
    def handle_owned_object_entrance(self, dgi, sender):
        do_id = dgi.get_uint32()
        parent_id = dgi.get_uint32()
        zone_id = dgi.get_uint32()
        dc_id = dgi.get_uint16()

        self.owned_objects[do_id] = ObjectInfo(do_id, dc_id, parent_id,
                                               zone_id)

        resp = Datagram()
        resp.add_uint16(CLIENT_GET_AVATAR_DETAILS_RESP)
        resp.add_uint32(self.avatar_id)
        resp.add_uint8(0)  # Return code
        resp.add_bytes(dgi.remaining_bytes())
        self.send_datagram(resp)
Exemple #10
0
    async def query_account(self, sender, do_id):
        dclass = self.dc.namespace['Account']
        toon_dclass = self.dc.namespace['DistributedToon']
        field_dict = await self.backend.query_object_all(do_id, dclass.name)

        temp = Datagram()
        temp.add_bytes(field_dict['ACCOUNT_AV_SET'])
        av_ids = dclass['ACCOUNT_AV_SET'].unpack_value(temp.iterator())

        dg = Datagram()
        dg.add_server_header([sender], DBSERVERS_CHANNEL, DBSERVER_ACCOUNT_QUERY_RESP)
        dg.add_bytes(field_dict['ACCOUNT_AV_SET_DEL'])
        av_count = sum((1 if av_id else 0 for av_id in av_ids))
        self.log.debug(f'Account query for {do_id} from {sender}: {field_dict}')
        dg.add_uint16(av_count)  # Av count
        for av_id in av_ids:
            if not av_id:
                continue
            toon_fields = await self.backend.query_object_fields(av_id, ['setName', 'WishNameState', 'WishName', 'setDNAString'], 'DistributedToon')

            wish_name = toon_fields['WishName']

            temp = Datagram()
            temp.add_bytes(toon_fields['WishNameState'])
            name_state = toon_dclass['WishNameState'].unpack_value(temp.iterator())

            dg.add_uint32(av_id)
            dg.add_bytes(toon_fields['setName'])

            pending_name = b'\x00\x00'
            approved_name = b'\x00\x00'
            rejected_name = b'\x00\x00'

            if name_state == 'APPROVED':
                approved_name = wish_name
            elif name_state == 'REJECTED':
                rejected_name = wish_name
            else:
                pending_name = wish_name

            dg.add_bytes(pending_name)
            dg.add_bytes(approved_name)
            dg.add_bytes(rejected_name)
            dg.add_bytes(toon_fields['setDNAString'])
            dg.add_uint8(av_ids.index(av_id))

        self.send_datagram(dg)
Exemple #11
0
    def database_generate_context(self, obj, context_id, parent_id, zone_id, owner_channel, database_server_id, from_channel_id):
        dg = Datagram()
        dg.add_uint8(1)
        dg.add_channel(database_server_id)
        dg.add_channel(from_channel_id)
        dg.add_uint16(STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT)
        dg.add_uint32(parent_id)
        dg.add_uint32(zone_id)
        dg.add_channel(owner_channel)
        dg.add_uint16(self.number)
        dg.add_uint32(context_id)

        for field in self.inherited_fields:
            if not isinstance(field, MolecularField) and field.is_required:
                self.pack_required_field(dg, obj, field)

        return dg
Exemple #12
0
    def receive_get_friend_list(self, dgi):
        self.service.log.debug(
            f'Friend list query received from {self.channel}')
        error = 0

        count = 0

        # Friend Structure
        # uint32 do_id
        # string name
        # string dna_string
        # uint32 pet_id

        resp = Datagram()
        resp.add_uint16(CLIENT_GET_FRIEND_LIST_RESP)
        resp.add_uint8(error)
        resp.add_uint16(count)

        self.send_datagram(resp)
Exemple #13
0
    async def do_login(self):
        f = DatagramFuture(self.service.loop, DBSERVER_ACCOUNT_QUERY_RESP)
        self.futures.append(f)
        sender, dgi = await f

        av_del_field = self.service.dc_file.namespace['Account'][
            'ACCOUNT_AV_SET_DEL']
        self.service.log.debug('Begin unpack of deleted avatars.')
        try:
            self.avs_deleted = av_del_field.unpack_value(dgi)
        except Exception:
            import traceback
            traceback.print_exc()
            return
        self.service.log.debug(
            f'Avatars deleted list for {self.account.username}: {self.avs_deleted}'
        )

        pos = dgi.tell()

        avatar_info = [None] * 6

        for i in range(dgi.get_uint16()):
            pot_av = PotentialAvatar(do_id=dgi.get_uint32(),
                                     name=dgi.get_string16(),
                                     wish_name=dgi.get_string16(),
                                     approved_name=dgi.get_string16(),
                                     rejected_name=dgi.get_string16(),
                                     dna_string=dgi.get_blob16(),
                                     index=dgi.get_uint8())

            avatar_info[pot_av.index] = pot_av

        self.potential_avatars = avatar_info

        self.state = ClientState.AVATAR_CHOOSER

        resp = Datagram()
        resp.add_uint16(CLIENT_GET_AVATARS_RESP)
        dgi.seek(pos)
        resp.add_uint8(0)  # Return code
        resp.add_bytes(dgi.remaining_bytes())
        self.send_datagram(resp)
Exemple #14
0
    def handle_datagram(self, dg, dgi):
        sender = dgi.get_channel()
        msgtype = dgi.get_uint16()
        self.service.log.debug(f'State server directly received msgtype {MSG_TO_NAME_DICT[msgtype]} from {sender}.')

        if msgtype == STATESERVER_OBJECT_GENERATE_WITH_REQUIRED:
            self.handle_generate(dgi, sender, False)
        elif msgtype == STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER:
            self.handle_generate(dgi, sender, True)
        elif msgtype == STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT:  # DBSS msg
            self.handle_db_generate(dgi, sender, False)
        elif msgtype == STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT:  # DBSS msg
            self.handle_db_generate(dgi, sender, True)
        elif msgtype == STATESERVER_ADD_AI_RECV:
            self.handle_add_ai(dgi, sender)
        elif msgtype == STATESERVER_OBJECT_SET_OWNER_RECV:
            self.handle_set_owner(dgi, sender)
        elif msgtype == DBSERVER_GET_STORED_VALUES_RESP:
            self.activate_callback(dgi)
        elif msgtype == STATESERVER_SHARD_REST:
            self.handle_shard_rest(dgi)
        elif msgtype == STATESERVER_OBJECT_LOCATE:
            context = dgi.get_uint32()
            do_id = dgi.get_uint32()

            do = self.service.objects.get(do_id)

            resp = Datagram()
            resp.add_server_header([sender], do_id, STATESERVER_OBJECT_LOCATE_RESP)
            resp.add_uint32(context)
            resp.add_uint32(do_id)

            if do is None:
                resp.add_uint8(False)
                self.service.send_datagram(resp)
            else:
                resp.add_uint8(True)
                parent_id, zone_id = do.parent_id, do.zone_id
                resp.add_uint32(parent_id)
                resp.add_uint32(zone_id)
                ai_channel = do.ai_channel if do.ai_channel else 0
                resp.add_uint32(ai_channel)
                self.service.send_datagram(resp)
Exemple #15
0
    async def create_toon(self, sender, context, dclass, disl_id, pos, fields):
        try:
            do_id = await self.backend.create_object(dclass, fields)
            account = await self.backend.query_object_fields(disl_id, ['ACCOUNT_AV_SET'], 'Account')
            temp = Datagram()
            temp.add_bytes(account['ACCOUNT_AV_SET'])
            av_set = self.dc.namespace['Account']['ACCOUNT_AV_SET'].unpack_value(temp.iterator())
            print(do_id, disl_id, pos, av_set)
            av_set[pos] = do_id
            temp.seek(0)
            self.dc.namespace['Account']['ACCOUNT_AV_SET'].pack_value(temp, av_set)
            await self.backend.set_field(disl_id, 'ACCOUNT_AV_SET', temp.bytes(), 'Account')
        except OTPCreateFailed as e:
            print('creation failed', e)
            do_id = 0

        dg = Datagram()
        dg.add_server_header([sender], DBSERVERS_CHANNEL, DBSERVER_CREATE_STORED_OBJECT_RESP)
        dg.add_uint32(context)
        dg.add_uint8(do_id == 0)
        dg.add_uint32(do_id)
        self.send_datagram(dg)
Exemple #16
0
 def makeNetString(self):
     dg = Datagram()
     dg.add_bytes(self.type.encode('ascii'))
     if self.type == 't':
         dg.add_uint8(toonHeadTypes.index(self.head))
         dg.add_uint8(toonTorsoTypes.index(self.torso))
         dg.add_uint8(toonLegTypes.index(self.legs))
         if self.gender == 'm':
             dg.add_uint8(1)
         else:
             dg.add_uint8(0)
         dg.add_uint8(self.topTex)
         dg.add_uint8(self.topTexColor)
         dg.add_uint8(self.sleeveTex)
         dg.add_uint8(self.sleeveTexColor)
         dg.add_uint8(self.botTex)
         dg.add_uint8(self.botTexColor)
         dg.add_uint8(self.armColor)
         dg.add_uint8(self.gloveColor)
         dg.add_uint8(self.legColor)
         dg.add_uint8(self.headColor)
     else:
         raise Exception(f'unknown avatar type: {self.type}')
     return dg.bytes()
Exemple #17
0
    def receive_login(self, dgi):
        play_token = dgi.get_string16()
        server_version = dgi.get_string16()
        hash_val = dgi.get_uint32()
        want_magic_words = dgi.get_string16()

        self.service.log.debug(
            f'play_token:{play_token}, server_version:{server_version}, hash_val:{hash_val}, '
            f'want_magic_words:{want_magic_words}')

        try:
            play_token = bytes.fromhex(play_token)
            nonce, tag, play_token = play_token[:16], play_token[
                16:32], play_token[32:]
            cipher = AES.new(CLIENTAGENT_SECRET, AES.MODE_EAX, nonce)
            data = cipher.decrypt_and_verify(play_token, tag)
            self.service.log.debug(f'Login token data:{data}')
            data = json.loads(data)
            for key in list(data.keys()):
                value = data[key]
                if type(value) == str:
                    data[key] = value.encode('utf-8')
            self.account = DISLAccount(**data)
        except ValueError as e:
            self.disconnect(ClientDisconnect.LOGIN_ERROR, 'Invalid token')
            return

        self.channel = getClientSenderChannel(self.account.disl_id, 0)
        self.subscribe_channel(self.channel)
        self.subscribe_channel(getAccountChannel(self.account.disl_id))

        resp = Datagram()
        resp.add_uint16(CLIENT_LOGIN_TOONTOWN_RESP)

        return_code = 0  # -13 == period expired
        resp.add_uint8(return_code)

        error_string = b''  # 'Bad DC Version Compare'
        resp.add_string16(error_string)

        resp.add_uint32(self.account.disl_id)
        resp.add_string16(self.account.username)
        account_name_approved = True
        resp.add_uint8(account_name_approved)
        resp.add_string16(self.account.whitelist_chat_enabled)
        resp.add_string16(self.account.create_friends_with_chat)
        resp.add_string16(self.account.chat_code_creation_rule)

        t = time.time() * 10e6
        usecs = int(t % 10e6)
        secs = int(t / 10e6)
        resp.add_uint32(secs)
        resp.add_uint32(usecs)

        resp.add_string16(self.account.access)
        resp.add_string16(self.account.whitelist_chat_enabled)

        last_logged_in = time.strftime('%c')  # time.strftime('%c')
        resp.add_string16(last_logged_in.encode('utf-8'))

        account_days = 0
        resp.add_int32(account_days)
        resp.add_string16(self.account.account_type)
        resp.add_string16(self.account.username)

        self.send_datagram(resp)
Exemple #18
0
    def test_add_uint8(self):
        dg = Datagram()
        other = b''

        dg.add_uint8(12)
        other += pack_unsigned(12)
        self.assertEqual(dg.bytes(), other)

        dg.add_uint8(47)
        other += pack_unsigned(47)
        self.assertEqual(dg.bytes(), other)

        dg.add_uint8(255)
        other += pack_unsigned(255)
        self.assertEqual(dg.bytes(), other)

        dg.add_uint8(0)
        other += pack_unsigned(0)
        self.assertEqual(dg.bytes(), other)

        with self.assertRaises(OverflowError):
            dg.add_uint8(256)
            dg.add_uint8(-3)
Exemple #19
0
    def receive_set_name_pattern(self, dgi):
        av_id = dgi.get_uint32()

        self.service.log.debug(f'Got name pattern request for av_id {av_id}.')

        title_index, title_flag = dgi.get_int16(), dgi.get_int16()
        first_index, first_flag = dgi.get_int16(), dgi.get_int16()
        last_prefix_index, last_prefix_flag = dgi.get_int16(), dgi.get_int16()
        last_suffix_index, last_suffix_flag = dgi.get_int16(), dgi.get_int16()

        resp = Datagram()
        resp.add_uint16(CLIENT_SET_NAME_PATTERN_ANSWER)
        resp.add_uint32(av_id)

        if av_id != self.created_av_id:
            resp.add_uint8(1)
            self.send_datagram(resp)
            return

        if first_index <= 0 and last_prefix_index <= 0 and last_suffix_index <= 0:
            self.service.log.debug(
                f'Received request for empty name for {av_id}.')
            resp.add_uint8(2)
            self.send_datagram(resp)
            return

        if (last_prefix_index <= 0 <= last_suffix_index) or (
                last_suffix_index <= 0 <= last_prefix_index):
            self.service.log.debug(
                f'Received request for invalid last name for {av_id}.')
            resp.add_uint8(3)
            self.send_datagram(resp)
            return

        try:
            title = self.get_name_part(title_index, title_flag, {
                NamePart.BOY_TITLE, NamePart.GIRL_TITLE, NamePart.NEUTRAL_TITLE
            })
            first = self.get_name_part(first_index, first_flag, {
                NamePart.BOY_FIRST, NamePart.GIRL_FIRST, NamePart.NEUTRAL_FIRST
            })
            last_prefix = self.get_name_part(
                last_prefix_index, last_prefix_flag,
                {NamePart.CAP_PREFIX, NamePart.LAST_PREFIX})
            last_suffix = self.get_name_part(last_suffix_index,
                                             last_suffix_flag,
                                             {NamePart.LAST_SUFFIX})
        except KeyError as e:
            resp.add_uint8(4)
            self.send_datagram(resp)
            self.service.log.debug(
                f'Received invalid index for name part. {e.args}')
            return

        name = f'{title}{" " if title else ""}{first}{" " if first else ""}{last_prefix}{last_suffix}'

        for pot_av in self.potential_avatars:
            if pot_av and pot_av.do_id == av_id:
                pot_av.approved_name = name
                break

        resp.add_uint8(0)
        self.send_datagram(resp)