Beispiel #1
0
    def handle_query_zone(self, dgi, sender):
        # STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE
        handle = dgi.get_uint16()
        context_id = dgi.get_uint32()
        parent_id = dgi.get_uint32()

        if parent_id != self.do_id:
            return

        num_zones = dgi.remaining() // 4

        zones = []

        for i in range(num_zones):
            zones.append(dgi.get_uint32())

        object_ids = []

        for zone in zones:
            if zone not in self.zone_objects:
                continue

            object_ids.extend(self.zone_objects[zone])

        resp = Datagram()
        resp.add_server_header([sender], self.do_id, STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE)
        resp.add_uint16(handle)
        resp.add_uint32(context_id)

        if not len(object_ids):
            self.service.send_datagram(resp)
            return

        self.send_location_entry(sender)

        for do_id in object_ids:
            self.service.objects[do_id].send_location_entry(sender)

        self.service.send_datagram(resp)
Beispiel #2
0
    def append_other_data(self, dg, client_only, also_owner):
        if client_only:
            fields_dg = Datagram()

            count = 0
            for field_name, raw_data in self.ram.items():
                field = self.dclass.fields_by_name[field_name]
                if field.is_broadcast or field.is_clrecv or (also_owner and field.is_ownrecv):
                    fields_dg.add_uint16(field.number)
                    fields_dg.add_bytes(raw_data)
                    count += 1

            dg.add_uint16(count)
            if count:
                dg.add_bytes(fields_dg.bytes())

        else:
            dg.add_uint16(len(self.ram))
            for field_name, raw_data in self.ram.items():
                field = self.dclass.fields_by_name[field_name]
                dg.add_uint16(field.number)
                dg.add_bytes(raw_data)
Beispiel #3
0
    async def get_stored_values(self, sender, context, do_id, fields):
        try:
            field_dict = await self.backend.query_object_fields(
                do_id, [field.name for field in fields])
        except OTPQueryNotFound:
            field_dict = None

        self.log.debug(
            f'Received query request from {sender} with context {context} for do_id: {do_id}.'
        )

        dg = Datagram()
        dg.add_server_header([sender], DBSERVERS_CHANNEL,
                             DBSERVER_GET_STORED_VALUES_RESP)
        dg.add_uint32(context)
        dg.add_uint32(do_id)
        pos = dg.tell()
        dg.add_uint16(0)

        if field_dict is None:
            print('object not found... %s' % do_id, sender, context)
            self.send_datagram(dg)
            return

        counter = 0
        for field in fields:
            if field.name not in field_dict:
                continue
            if field_dict[field.name] is None:
                continue
            dg.add_uint16(field.number)
            dg.add_bytes(field_dict[field.name])
            counter += 1

        dg.seek(pos)
        dg.add_uint16(counter)
        self.send_datagram(dg)
Beispiel #4
0
 def send_datagram(self, data: Datagram):
     loop = self.service.loop
     loop.call_soon_threadsafe(self.outgoing_q.put_nowait, data.bytes())
Beispiel #5
0
 def setInterest(self, client_channel, handle, context, parent_id, zones):
     dg = Datagram()
     dg.add_server_header([client_channel], self.ourChannel,
                          CLIENT_AGENT_SET_INTEREST)
     dg.add_uint16(handle)
     dg.add_uint32(context)
     dg.add_uint32(parent_id)
     for zone in zones:
         dg.add_uint32(zone)
     self.send(dg)
Beispiel #6
0
 def send_datagram(self, data: Datagram):
     self.outgoing_q.put_nowait(data.bytes())
Beispiel #7
0
 def fromBytes(data):
     return Experience.fromNetString(Datagram(data).iterator())
Beispiel #8
0
    def handle_datagram(self, dg, dgi):
        pos = dgi.tell()
        sender = dgi.get_channel()

        if sender == self.channel:
            return

        msgtype = dgi.get_uint16()

        self.check_futures(dgi, msgtype, sender)

        if msgtype == STATESERVER_OBJECT_ENTERZONE_WITH_REQUIRED_OTHER:
            self.handle_object_entrance(dgi, sender)
        elif msgtype == STATESERVER_OBJECT_ENTER_OWNER_RECV:
            self.handle_owned_object_entrance(dgi, sender)
        elif msgtype == STATESERVER_OBJECT_CHANGE_ZONE:
            do_id = dgi.get_uint32()

            if self.queue_pending(do_id, dgi, pos):
                self.service.log.debug(
                    f'Queued location change for pending object {do_id}.')
                return

            self.handle_location_change(dgi, sender, do_id)
        elif msgtype == STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE:
            self.handle_interest_done(dgi)
        elif msgtype == STATESERVER_OBJECT_UPDATE_FIELD:
            do_id = dgi.get_uint32()

            if not self.object_exists(do_id):
                queued = self.queue_pending(do_id, dgi, pos)
                if queued:
                    self.service.log.debug(
                        f'Queued field update for pending object {do_id}.')
                else:
                    self.service.log.debug(
                        f'Got update for unknown object {do_id}.')
                return

            self.handle_update_field(dgi, sender, do_id)
        elif msgtype == STATESERVER_OBJECT_DELETE_RAM:
            do_id = dgi.get_uint32()

            if do_id == self.avatar_id:
                if sender == self.account.disl_id << 32:
                    self.disconnect(ClientDisconnect.RELOGGED,
                                    'redundant login')
                else:
                    self.disconnect(ClientDisconnect.SHARD_DISCONNECT,
                                    'district reset')
            elif not self.object_exists(do_id):
                self.service.log.debug(
                    f'Queued deletion for pending object {do_id}.')
                self.queue_pending(do_id, dgi, pos)
                return
            else:
                self.send_remove_object(do_id)
                del self.visible_objects[do_id]
        elif msgtype == CLIENT_AGENT_SET_INTEREST:
            self.receive_add_interest(dgi, ai=True)
        elif msgtype == CLIENT_AGENT_REMOVE_INTEREST:
            self.receive_remove_interest(dgi, ai=True)
        elif msgtype in {
                CLIENT_FRIEND_ONLINE, CLIENT_FRIEND_OFFLINE,
                CLIENT_GET_FRIEND_LIST_RESP
        }:
            dg = Datagram()
            dg.add_uint16(msgtype)
            dg.add_bytes(dgi.remaining_bytes())
            self.send_datagram(dg)
        else:
            self.service.log.debug(
                f'Client {self.channel} received unhandled upstream msg {msgtype}.'
            )
Beispiel #9
0
 def send_go_get_lost(self, booted_index, booted_text):
     resp = Datagram()
     resp.add_uint16(CLIENT_GO_GET_LOST)
     resp.add_uint16(booted_index)
     resp.add_string16(booted_text.encode('utf-8'))
     self.send_datagram(resp)
Beispiel #10
0
 def send_object_entrance(self, parent_id, zone_id, dc_id, do_id, dgi,
                          has_other):
     resp = Datagram()
     resp.add_uint16(CLIENT_CREATE_OBJECT_REQUIRED_OTHER
                     if has_other else CLIENT_CREATE_OBJECT_REQUIRED)
     resp.add_uint32(parent_id)
     resp.add_uint32(zone_id)
     resp.add_uint16(dc_id)
     resp.add_uint32(do_id)
     resp.add_bytes(dgi.remaining_bytes())
     self.send_datagram(resp)
Beispiel #11
0
 def send_remove_object(self, do_id):
     self.service.log.debug(f'Sending removal of {do_id}.')
     resp = Datagram()
     resp.add_uint16(CLIENT_OBJECT_DISABLE)
     resp.add_uint32(do_id)
     self.send_datagram(resp)
Beispiel #12
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)
Beispiel #13
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)
Beispiel #14
0
    def test_add_data(self):
        s = 'hello_world'.encode('utf-8')

        dg = Datagram()
        dg.add_string16(s)
        other = struct.pack(f'<H{len(s)}b', len(s), *s)
        self.assertEqual(dg.bytes(), other)

        s = 'abcdefghijklmnop'.encode('utf-8')
        dg = Datagram()
        dg.add_string32(s)
        other = struct.pack(f'<I{len(s)}b', len(s), *s)
        self.assertEqual(dg.bytes(), other)

        dg.add_bytes(b'')
        self.assertEqual(dg.bytes(), other)

        dg = Datagram()
        dg.add_string16(b'')
        self.assertEqual(dg.bytes(), b'\x00\x00')

        dg = Datagram()

        random.seed('pydc')

        s = bytes(random.randint(0, 255) for _ in range((1 << 16)))

        with self.assertRaises(OverflowError):
            dg.add_string16(s)

        dg = Datagram()
        s = bytes(random.randint(0, 255) for _ in range((1 << 16)))
        dg.add_string32(s)
        s = b''.join((struct.pack('<I', len(s)), s))
        self.assertEqual(dg.bytes(), s)

        dg = Datagram()
        dg.add_string32(b'')
        self.assertEqual(dg.bytes(), struct.pack('<I', 0))

        dg = Datagram()
        c = chr(0x1F600).encode('utf-8')
        dg.add_bytes(c)
        self.assertEqual(dg.bytes(), c)
Beispiel #15
0
    def test_add_int8(self):
        dg = Datagram()
        dg.add_int8(-127)
        dg.add_int8(127)
        other = struct.pack('<bb', -127, 127)

        self.assertEqual(dg.bytes(), other)

        with self.assertRaises(OverflowError):
            dg.add_int8(-128)
            dg.add_int8(128)
Beispiel #16
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)
Beispiel #17
0
    def receive_add_interest(self, dgi, ai=False):
        handle = dgi.get_uint16()
        context_id = dgi.get_uint32()
        parent_id = dgi.get_uint32()

        num_zones = dgi.remaining() // 4

        zones = []

        for i in range(num_zones):
            zones.append(dgi.get_uint32())

        self.service.log.debug(
            f'Client {self.channel} is requesting interest with handle {handle} and context {context_id} '
            f'for location {parent_id} {zones}')

        if self.state <= ClientState.AUTHENTICATED and parent_id != 4618:
            self.service.log.debug(
                f'Client {self.channel} requested unexpected interest in state {self.state}. Ignoring.'
            )
            return

        previous_interest = None

        for _interest in self.interests:
            if _interest.handle == handle:
                previous_interest = _interest
                break

        if previous_interest is None:
            interest = Interest(self.channel, handle, context_id, parent_id,
                                zones)
            self.interests.append(interest)
        else:
            self.service.log.debug(
                f'Altering interest {handle} (done: {previous_interest.done}): {previous_interest.zones} -> {zones}'
            )
            self.interests.remove(previous_interest)

            if previous_interest.parent_id != parent_id:
                killed_zones = previous_interest.zones
            else:
                killed_zones = set(previous_interest.zones).difference(
                    set(zones))

            for _interest in self.interests:
                killed_zones = killed_zones.difference(set(_interest.zones))
                if not killed_zones:
                    break

            self.service.log.debug(
                f'Zones killed by altering interest: {killed_zones}')

            if killed_zones:
                for do_id in list(self.visible_objects.keys()):
                    obj = self.visible_objects[do_id]
                    if obj.parent_id == parent_id and obj.zone_id in killed_zones:
                        self.service.log.debug(
                            f'Object {obj.do_id}, location ({obj.parent_id}, {obj.zone_id}), killed by altered interest: {zones}'
                        )
                        self.send_remove_object(obj.do_id)
                        del self.visible_objects[do_id]

            for zone in killed_zones:
                self.unsubscribe_channel(
                    location_as_channel(previous_interest.parent_id, zone))

            interest = Interest(self.channel, handle, context_id, parent_id,
                                zones)
            self.interests.append(interest)

            for do_id in list(self.pending_objects.keys()):
                if not self.pending_object_needed(do_id):
                    del self.pending_objects[do_id]

        interest.ai = ai

        if not zones:
            interest.done = True
            if not ai:
                resp = Datagram()
                resp.add_uint16(CLIENT_DONE_INTEREST_RESP)
                resp.add_uint16(handle)
                resp.add_uint32(context_id)
                self.send_datagram(resp)
                return

        query_request = Datagram()
        query_request.add_server_header([parent_id], self.channel,
                                        STATESERVER_QUERY_ZONE_OBJECT_ALL)
        query_request.add_uint16(handle)
        query_request.add_uint32(context_id)
        query_request.add_uint32(parent_id)

        for zone in zones:
            query_request.add_uint32(zone)
            self.subscribe_channel(location_as_channel(parent_id, zone))

        self.service.send_datagram(query_request)
Beispiel #18
0
 def delete_avatar_ram(self):
     dg = Datagram()
     dg.add_server_header([self.avatar_id], self.channel,
                          STATESERVER_OBJECT_DELETE_RAM)
     dg.add_uint32(self.avatar_id)
     self.service.send_datagram(dg)
Beispiel #19
0
 def fromBytes(data):
     return Inventory.fromNetString(Datagram(data).iterator())
Beispiel #20
0
    def receive_update_field(self, dgi, do_id=None):
        if do_id is None:
            do_id = dgi.get_uint32()

        field_number = dgi.get_uint16()

        field = self.service.dc_file.fields[field_number]()

        sendable = False

        if field.is_ownsend and do_id in self.owned_objects:
            sendable = True
        elif field.is_clsend:
            sendable = True

        if not sendable:
            self.disconnect(ClientDisconnect.INTERNAL_ERROR,
                            'Tried to send nonsendable field to object.')
            self.service.log.warn(
                f'Client {self.channel} tried to update {do_id} with nonsendable field {field.name}. '
                f'DCField keywords: {field.keywords}')
            return

        pos = dgi.tell()
        field.unpack_bytes(dgi)
        dgi.seek(pos)

        resp = Datagram()
        resp.add_server_header([do_id], self.channel,
                               STATESERVER_OBJECT_UPDATE_FIELD)
        resp.add_uint32(do_id)
        resp.add_uint16(field_number)
        resp.add_bytes(dgi.remaining_bytes())
        self.service.send_datagram(resp)

        if field.name == 'setTalk':
            # TODO: filtering
            resp = Datagram()
            resp.add_uint16(CLIENT_OBJECT_UPDATE_FIELD)
            resp.add_uint32(do_id)
            resp.add_uint16(field_number)
            resp.add_bytes(dgi.remaining_bytes())
            self.send_datagram(resp)
Beispiel #21
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()
Beispiel #22
0
    def receive_set_avatar(self, dgi):
        av_id = dgi.get_uint32()

        self.service.log.debug(
            f'client {self.channel} is setting their avatar to {av_id}')

        if not av_id:
            if self.avatar_id:
                # Client is logging out of their avatar.
                self.delete_avatar_ram()
                self.owned_objects.clear()
                self.visible_objects.clear()

                self.unsubscribe_channel(
                    getClientSenderChannel(self.account.disl_id,
                                           self.avatar_id))
                self.unsubscribe_channel(getPuppetChannel(self.avatar_id))
                self.channel = getClientSenderChannel(self.account.disl_id, 0)
                self.subscribe_channel(self.channel)

                self.state = ClientState.AUTHENTICATED
                self.avatar_id = 0
                return
            else:
                # Do nothing.
                return
        elif self.state == ClientState.PLAY_GAME:
            self.service.log.debug(
                f'Client {self.channel} tried to set their avatar {av_id} while avatar is already set to {self.avatar_id}.'
            )
            return

        pot_av = None

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

        if pot_av is None:
            self.disconnect(ClientDisconnect.INTERNAL_ERROR,
                            'Could not find avatar on account.')
            return

        self.avatar_id = av_id
        self.created_av_id = 0

        self.state = ClientState.SETTING_AVATAR

        self.channel = getClientSenderChannel(self.account.disl_id,
                                              self.avatar_id)
        self.subscribe_channel(self.channel)
        self.subscribe_channel(getPuppetChannel(self.avatar_id))

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

        access = 2 if self.account.access == b'FULL' else 1

        # These Fields are REQUIRED but not stored in db.
        other_fields = [(dclass['setAccess'], (access, )),
                        (dclass['setPreviousAccess'], (access, )),
                        (dclass['setAsGM'], (False, )),
                        (dclass['setBattleId'], (0, ))]

        if pot_av.approved_name:
            other_fields.append((dclass['setName'], (pot_av.approved_name, )))
            pot_av.approved_name = ''

        dg = Datagram()
        dg.add_server_header(
            [STATESERVERS_CHANNEL], self.channel,
            STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT)
        dg.add_uint32(av_id)
        dg.add_uint32(0)
        dg.add_uint32(0)
        dg.add_channel(self.channel)
        dg.add_uint16(dclass.number)
        dg.add_uint16(len(other_fields))

        for f, arg in other_fields:
            dg.add_uint16(f.number)
            f.pack_value(dg, arg)

        self.service.send_datagram(dg)
Beispiel #23
0
 def sendLocation(self, do_id, old_parent: int, old_zone: int,
                  new_parent: int, new_zone: int):
     dg = Datagram()
     dg.add_server_header([do_id], self.ourChannel,
                          STATESERVER_OBJECT_SET_ZONE)
     dg.add_uint32(new_parent)
     dg.add_uint32(new_zone)
     dg.add_uint32(old_parent)
     dg.add_uint32(old_zone)
     self.send(dg)
Beispiel #24
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()))
Beispiel #25
0
    def createObjects(self):
        self.registerForChannel(self.ourChannel)

        from .Objects import ToontownDistrictAI, ToontownDistrictStatsAI, DistributedInGameNewsMgrAI, NewsManagerAI, FriendManagerAI
        from .TimeManagerAI import TimeManagerAI

        self.district = ToontownDistrictAI(self)
        self.district.name = 'Nutty River'
        self.generateWithRequired(self.district, OTP_DO_ID_TOONTOWN,
                                  OTP_ZONE_ID_DISTRICTS)

        post_remove = Datagram()
        post_remove.add_server_control_header(CONTROL_ADD_POST_REMOVE)
        post_remove.add_server_header([
            STATESERVERS_CHANNEL,
        ], self.ourChannel, STATESERVER_SHARD_REST)
        post_remove.add_channel(self.ourChannel)
        self.send(post_remove)

        dg = Datagram()
        dg.add_server_header([STATESERVERS_CHANNEL], self.ourChannel,
                             STATESERVER_ADD_AI_RECV)
        dg.add_uint32(self.district.do_id)
        dg.add_channel(self.ourChannel)
        self.send(dg)

        stats = ToontownDistrictStatsAI(self)
        stats.settoontownDistrictId(self.district.do_id)
        self.generateWithRequired(stats, OTP_DO_ID_TOONTOWN,
                                  OTP_ZONE_ID_DISTRICTS_STATS)

        dg = Datagram()
        dg.add_server_header([STATESERVERS_CHANNEL], self.ourChannel,
                             STATESERVER_ADD_AI_RECV)
        dg.add_uint32(stats.do_id)
        dg.add_channel(self.ourChannel)
        self.send(dg)

        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        self.ingameNewsMgr = DistributedInGameNewsMgrAI(self)
        self.ingameNewsMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateGlobalObject(OTP_ZONE_ID_MANAGEMENT)

        self.loadZones()

        self.district.b_setAvailable(True)
Beispiel #26
0
    def receive_set_wishname(self, dgi):
        av_id = dgi.get_uint32()
        name = dgi.get_string16()

        av = self.get_potential_avatar(av_id)

        self.service.log.debug(
            f'Received wishname request from {self.channel} for avatar {av_id} for name "{name}".'
        )

        pending = name.encode('utf-8')
        approved = b''
        rejected = b''

        failed = False

        resp = Datagram()
        resp.add_uint16(CLIENT_SET_WISHNAME_RESP)
        resp.add_uint32(av_id)
        resp.add_uint16(failed)
        resp.add_string16(pending)
        resp.add_string16(approved)
        resp.add_string16(rejected)

        self.send_datagram(resp)

        if av_id and av:
            dclass = self.service.dc_file.namespace['DistributedToon']
            wishname_field = dclass['WishName']
            wishname_state_field = dclass['WishNameState']

            resp = Datagram()
            resp.add_server_header([DBSERVERS_CHANNEL], self.channel,
                                   DBSERVER_SET_STORED_VALUES)
            resp.add_uint32(av_id)
            resp.add_uint16(2)
            resp.add_uint16(wishname_state_field.number)
            wishname_state_field.pack_value(resp, ('PENDING', ))
            resp.add_uint16(wishname_field.number)
            wishname_field.pack_value(resp, (name, ))
            self.service.send_datagram(resp)
Beispiel #27
0
 def requestDelete(self, do):
     dg = Datagram()
     dg.add_server_header([do.do_id], self.ourChannel,
                          STATESERVER_OBJECT_DELETE_RAM)
     dg.add_uint32(do.do_id)
     self.send(dg)
Beispiel #28
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)
Beispiel #29
0
    def test_legacy_arrays(self):
        dc = parse_dc(TEST1_DC)
        field = dc.fields[0]()  # type: AtomicField
        field2 = dc.fields[1]()  # type: AtomicField
        field3 = dc.fields[2]()  # type: AtomicField

        arg1 = [2, 4, 8, 16, 32]
        dg = Datagram()
        field.pack_value(dg, [arg1])
        self.assertEqual(field.unpack_value(dg.iterator())[0], [2, 4, 8, 16, 32])

        dg2 = Datagram()
        field2.pack_value(dg2, [arg1])
        self.assertEqual(field2.unpack_value(dg2.iterator())[0], [2, 4, 8, 16, 32])

        self.assertEqual(dg.get_message().tobytes(), dg2.get_message().tobytes())

        arg1 = [[1, 2], [3, 4], [5, 6]]
        dg3 = Datagram()
        field3.pack_value(dg3, [arg1])
        self.assertEqual(dg3.get_message().tobytes(),
                         b'\x0f\x00\x01\x00\x00\x00\x02\x03\x00\x00\x00\x04\x05\x00\x00\x00\x06')

        self.assertEqual(field3.unpack_value(dg3.iterator())[0], [[1, 2], [3, 4], [5, 6]])
Beispiel #30
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)