コード例 #1
0
ファイル: clientprotocol.py プロジェクト: alexanderr/OpenOTP
    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)
コード例 #2
0
ファイル: dbserver.py プロジェクト: loonaticx/OpenOTP
    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)
コード例 #3
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def handle_one_update(self, dgi, sender):
        field_id = dgi.get_uint16()
        field = self.dclass.dcfile().fields[field_id]()
        pos = dgi.tell()
        data = field.unpack_bytes(dgi)

        if isinstance(field, MolecularField):
            dgi.seek(pos)
            self.save_molecular(field, dgi)
        else:
            self.save_field(field, data)

        targets = []

        if field.is_broadcast:
            targets.append(location_as_channel(self.parent_id, self.zone_id))
        if field.is_airecv and self.ai_channel and self.ai_channel != sender:
            targets.append(self.ai_channel)
        if field.is_ownrecv and self.owner_channel and self.owner_channel != sender:
            targets.append(self.owner_channel)

        if targets:
            dg = Datagram()
            dg.add_server_header(targets, sender, STATESERVER_OBJECT_UPDATE_FIELD)
            dg.add_uint32(self.do_id)
            dg.add_uint16(field_id)
            dg.add_bytes(data)
            self.service.send_datagram(dg)
コード例 #4
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}.')
コード例 #5
0
ファイル: AIRepository.py プロジェクト: loonaticx/OpenOTP
 def removeInterest(self, client_channel, handle, context):
     dg = Datagram()
     dg.add_server_header([client_channel], self.ourChannel,
                          CLIENT_AGENT_REMOVE_INTEREST)
     dg.add_uint16(handle)
     dg.add_uint32(context)
     self.send(dg)
コード例 #6
0
    def test_get_remaining(self):
        dg = Datagram()
        dg.add_string16(b'test string')
        dg.add_uint32(2525)

        dgi = dg.iterator()
        self.assertEqual(dgi.remaining(), 2 + len('test string') + 4)
        self.assertEqual(dgi.get_remaining(), dg.get_message().tobytes())
コード例 #7
0
 def sendFriendOnline(self, avId, otherAvId):
     # Need this delay so that `setFriendsList` is set first to avoid
     # the online whisper message.
     dg = Datagram()
     dg.add_server_header([getPuppetChannel(avId)], self.air.ourChannel,
                          CLIENT_FRIEND_ONLINE)
     dg.add_uint32(otherAvId)
     self.air.send(dg)
コード例 #8
0
    def receive_remove_interest(self, dgi, ai=False):
        handle = dgi.get_uint16()

        if dgi.remaining():
            context = dgi.get_uint32()
        else:
            context = None

        interest = None

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

        if not interest:
            self.service.log.debug(
                f'Got unexpected interest removal from client {self.channel} for interest handle '
                f'{handle} with context {context}')
            return

        self.service.log.debug(
            f'Got remove interest request from client {self.channel} for interest handle '
            f'{handle} with context {context}')

        parent_id = interest.parent_id

        uninterested_zones = []

        for zone in interest.zones:
            if len(self.lookup_interest(parent_id, zone)) == 1:
                uninterested_zones.append(zone)

        to_remove = []

        for do_id in self.visible_objects:
            do = self.visible_objects[do_id]
            if do.parent_id == parent_id and do.zone_id in uninterested_zones:
                self.service.log.debug(
                    f'Object {do_id} killed by interest remove.')
                self.send_remove_object(do_id)

                to_remove.append(do_id)

        for do_id in to_remove:
            del self.visible_objects[do_id]

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

        self.interests.remove(interest)

        if not ai:
            resp = Datagram()
            resp.add_uint16(CLIENT_DONE_INTEREST_RESP)
            resp.add_uint16(handle)
            resp.add_uint32(context)
            self.send_datagram(resp)
コード例 #9
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()))
コード例 #10
0
    def test_add_uint32(self):
        dg = Datagram()
        dg.add_uint32(1 << 31)

        other = struct.pack('<I', 1 << 31)
        self.assertEqual(dg.bytes(), other)

        with self.assertRaises(OverflowError):
            dg.add_uint32(1 << 32)
コード例 #11
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def handle_query_all(self, dgi, sender):
        other = dgi.get_uint8()
        context = dgi.get_uint32()

        resp = Datagram()
        resp.add_server_header([sender], self.do_id, STATESERVER_QUERY_OBJECT_ALL_RESP)
        resp.add_uint32(self.do_id)
        resp.add_uint16(context)
        self.append_required_data(resp, False, True)
        self.service.send_datagram(resp)
コード例 #12
0
ファイル: objects.py プロジェクト: alexanderr/pydc
    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
コード例 #13
0
ファイル: AIRepository.py プロジェクト: loonaticx/OpenOTP
    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)
コード例 #14
0
    def receive_get_avatars(self, dgi):
        query = Datagram()
        query.add_server_header([
            DBSERVERS_CHANNEL,
        ], self.channel, DBSERVER_ACCOUNT_QUERY)

        disl_id = self.account.disl_id
        query.add_uint32(disl_id)
        field_number = self.service.avatars_field.number
        query.add_uint16(field_number)
        self.service.send_datagram(query)

        self.tasks.append(self.service.loop.create_task(self.do_login()))
コード例 #15
0
ファイル: dbserver.py プロジェクト: loonaticx/OpenOTP
    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)
コード例 #16
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)
コード例 #17
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)
コード例 #18
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def save_field(self, field: AtomicField, data):
        if field.is_required:
            self.required[field.name] = data
        elif field.is_ram:
            self.ram[field.name] = data

        if self.db and field.is_db:
            dg = Datagram()
            dg.add_server_header([DBSERVERS_CHANNEL], self.do_id, DBSERVER_SET_STORED_VALUES)
            dg.add_uint32(self.do_id)
            dg.add_uint16(1)
            dg.add_uint16(field.number)
            dg.add_bytes(data)
            self.service.send_datagram(dg)
            self.service.log.debug(f'Object {self.do_id} saved value {data} for field {field.name} to database.')
コード例 #19
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def handle_location_change(self, new_parent, new_zone, sender):
        old_parent = self.parent_id
        old_zone = self.zone_id

        targets = list()

        if self.ai_channel is not None:
            targets.append(self.ai_channel)

        if self.owner_channel is not None:
            targets.append(self.owner_channel)

        if new_parent == self.do_id:
            raise Exception('Object cannot be parented to itself.\n')

        if new_parent != old_parent:
            if old_parent:
                self.unsubscribe_channel(parent_to_children(old_parent))
                targets.append(old_parent)
                targets.append(location_as_channel(old_parent, old_zone))

            self.parent_id = new_parent
            self.zone_id = new_zone

            if new_parent:
                self.subscribe_channel(parent_to_children(new_parent))

                if not self.ai_explicitly_set:
                    new_ai_channel = self.service.resolve_ai_channel(new_parent)
                    if new_ai_channel != self.ai_channel:
                        self.ai_channel = new_ai_channel
                        self.send_ai_entry(new_ai_channel)

                targets.append(new_parent)

        elif new_zone != old_zone:
            self.zone_id = new_zone

            targets.append(self.parent_id)
            targets.append(location_as_channel(self.parent_id, old_zone))
        else:
            # Not changing zones.
            return

        dg = Datagram()
        dg.add_server_header(targets, sender, STATESERVER_OBJECT_CHANGE_ZONE)
        dg.add_uint32(self.do_id)
        dg.add_uint32(new_parent)
        dg.add_uint32(new_zone)
        dg.add_uint32(old_parent)
        dg.add_uint32(old_zone)

        self.service.send_datagram(dg)

        self.parent_synced = False

        if new_parent:
            self.send_location_entry(location_as_channel(new_parent, new_zone))
コード例 #20
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def activate_callback(self, dgi):
        context = dgi.get_uint32()
        do_id = dgi.get_uint32()

        state_server = self.service

        parent_id, zone_id, owner_channel, number, other_data = state_server.queries[do_id]
        dclass = state_server.dc_file.classes[number]

        del state_server.queries[do_id]

        required = {}
        ram = {}

        count = dgi.get_uint16()

        for i in range(count):
            field_number = dgi.get_uint16()
            field = state_server.dc_file.fields[field_number]()

            if field.is_required:
                required[field.name] = field.unpack_bytes(dgi)
            else:
                ram[field.name] = field.unpack_bytes(dgi)

        for field_number, data in other_data:
            field = state_server.dc_file.fields[field_number]()
            if field.is_required:
                required[field.name] = data
            else:
                ram[field.name] = data

            if field.is_db:
                dg = Datagram()
                dg.add_server_header([DBSERVERS_CHANNEL], do_id, DBSERVER_SET_STORED_VALUES)
                dg.add_uint32(do_id)
                dg.add_uint16(1)
                dg.add_uint16(field.number)
                dg.add_bytes(data)
                self.service.send_datagram(dg)

        self.service.log.debug(f'Activating {do_id} with required:{required}\nram:{ram}\n')

        obj = DistributedObject(state_server, STATESERVERS_CHANNEL, do_id, parent_id, zone_id, dclass, required, ram,
                                owner_channel=owner_channel, db=True)
        state_server.database_objects.add(do_id)
        state_server.objects[do_id] = obj
        obj.send_owner_entry(owner_channel)
コード例 #21
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    def handle_db_generate(self, dgi, sender, other=False):
        do_id = dgi.get_uint32()

        if do_id in self.service.queries or do_id in self.service.database_objects:
            self.service.log.debug(f'Got duplicate activate request for object {do_id} from {sender}')
            return

        parent_id = dgi.get_uint32()
        zone_id = dgi.get_uint32()
        owner_channel = dgi.get_channel()
        number = dgi.get_uint16()

        other_data = []

        state_server = self.service

        if other:
            field_count = dgi.get_uint16()

            for i in range(field_count):
                field_number = dgi.get_uint16()
                field = state_server.dc_file.fields[field_number]()
                data = field.unpack_bytes(dgi)
                other_data.append((field_number, data))

        dclass = state_server.dc_file.classes[number]

        query = Datagram()
        query.add_server_header([DBSERVERS_CHANNEL], STATESERVERS_CHANNEL, DBSERVER_GET_STORED_VALUES)
        query.add_uint32(1)
        query.add_uint32(do_id)

        pos = query.tell()
        query.add_uint16(0)
        count = 0
        for field in dclass:
            if not isinstance(field, MolecularField) and field.is_db:
                if field.name == 'DcObjectType':
                    continue
                query.add_uint16(field.number)
                count += 1
        query.seek(pos)
        query.add_uint16(count)

        self.service.log.debug(f'Querying {count} fields for {dclass.name} {do_id}. Other data: {other_data}')

        self.service.queries[do_id] = (parent_id, zone_id, owner_channel, number, other_data)
        self.service.send_datagram(query)
コード例 #22
0
ファイル: dbserver.py プロジェクト: loonaticx/OpenOTP
    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)
コード例 #23
0
    def handle_interest_done(self, dgi):
        handle = dgi.get_uint16()
        context = dgi.get_uint32()
        self.service.log.debug(
            f'sending interest done for handle {handle} context {context}')

        interest = None

        for _interest in self.interests:
            if _interest.handle == handle and _interest.context == context:
                interest = _interest
                break

        if not interest:
            self.service.log.debug(
                f'Got interest done for unknown interest: {handle} {context}')
            return

        if interest.done:
            self.service.log.debug('Received duplicate interest done...')
            return

        interest.done = True

        pending = [
            self.pending_objects.pop(do_id)
            for do_id in interest.pending_objects
            if do_id in self.pending_objects
        ]
        # Need this sorting.
        pending.sort(key=lambda p: p.dc_id)
        del interest.pending_objects[:]

        self.service.log.debug(
            f'Replaying datagrams for {[p.do_id for p in pending]}')

        for pending_object in pending:
            for datagram in pending_object.datagrams:
                self.handle_datagram(datagram, datagram.iterator())

        if not interest.ai:
            resp = Datagram()
            resp.add_uint16(CLIENT_DONE_INTEREST_RESP)
            resp.add_uint16(handle)
            resp.add_uint32(context)
            self.send_datagram(resp)
コード例 #24
0
ファイル: AIRepository.py プロジェクト: loonaticx/OpenOTP
 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)
コード例 #25
0
    def on_upstream_connect(self):
        self.subscribe_channel(self._client, self.GLOBAL_ID)
        self.log.debug('Uberdog online')

        dg = self.dclass.ai_format_generate(self,
                                            self.GLOBAL_ID,
                                            self.GAME_ID,
                                            OTP_ZONE_ID_MANAGEMENT,
                                            STATESERVERS_CHANNEL,
                                            self.GLOBAL_ID,
                                            optional_fields=None)
        self.send_datagram(dg)

        dg = Datagram()
        dg.add_server_control_header(CONTROL_ADD_POST_REMOVE)
        dg.add_server_header([self.GLOBAL_ID], self.GLOBAL_ID,
                             STATESERVER_OBJECT_DELETE_RAM)
        dg.add_uint32(self.GLOBAL_ID)
        self.send_datagram(dg)
コード例 #26
0
    def test_overwrite(self):
        dg = Datagram()
        dg.add_uint32(2828)

        pos = dg.tell()
        self.assertEqual(pos, 4)

        dg.add_uint16(24)
        dg.add_int64(-352793)
        dg.seek(pos)
        dg.add_uint16(5000)
        dg.seek(len(dg))
        dg.add_string32(b'overwrite')

        dgi = dg.iterator()
        self.assertEqual(dgi.get_uint32(), 2828)
        self.assertEqual(dgi.get_uint16(), 5000)
        self.assertEqual(dgi.get_int64(), -352793)
        self.assertEqual(dgi.get_string32(), 'overwrite')
コード例 #27
0
ファイル: stateserver.py プロジェクト: loonaticx/OpenOTP
    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)
コード例 #28
0
    def handle_update_field(self, dgi, sender, do_id):
        if sender == self.channel:
            return

        if not self.object_exists(do_id):
            self.service.log.debug(
                f'Got field update for unknown object {do_id}')

        pos = dgi.tell()

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

        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)
コード例 #29
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)
コード例 #30
0
    async def query_location(self, avId, context):
        dg = Datagram()
        dg.add_server_header([STATESERVERS_CHANNEL], self.GLOBAL_ID,
                             STATESERVER_OBJECT_LOCATE)
        dg.add_uint32(context)
        dg.add_uint32(avId)
        self.send_datagram(dg)

        f = self.register_future(STATESERVER_OBJECT_LOCATE_RESP, avId, context)

        try:
            sender, dgi = await asyncio.wait_for(f, timeout=10, loop=self.loop)
        except TimeoutError:
            return None, None
        dgi.get_uint32(), dgi.get_uint32()
        success = dgi.get_uint8()
        if not success:
            return None, None
        parent_id, zone_id = dgi.get_uint32(), dgi.get_uint32()

        return parent_id, zone_id