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)
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)
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)
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)
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)
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)
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))
def send_ai_entry(self, location): dg = Datagram() dg.add_server_header([location], self.do_id, STATESERVER_OBJECT_ENTER_AI_RECV) self.append_required_data(dg, False, False) if self.ram: self.append_other_data(dg, False, False) self.service.send_datagram(dg)
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()))
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)
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)
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)
def test_server_header(self): dg = Datagram() targets = [4200, 2878, 300, 1] dg.add_server_header(targets, 10000000, 1) dgi = dg.iterator() self.assertEqual(dgi.get_uint8(), 4) self.assertEqual(dgi.get_channel(), 4200) self.assertEqual(dgi.get_channel(), 2878) self.assertEqual(dgi.get_channel(), 300) self.assertEqual(dgi.get_channel(), 1) self.assertEqual(dgi.get_channel(), 10000000) self.assertEqual(dgi.get_uint16(), 1)
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()))
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)
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)
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.')
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)
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)
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)
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)
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)
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)
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
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)
def receive_client_location(self, dgi): do_id = dgi.get_uint32() parent_id = dgi.get_uint32() zone_id = dgi.get_uint32() self.service.log.debug( f'Client {self.channel} is setting their location to {parent_id} {zone_id}' ) if do_id in self.owned_objects: self.owned_objects[do_id].zone_id = zone_id self.owned_objects[do_id].parent_id = parent_id dg = Datagram() dg.add_server_header([do_id], self.channel, STATESERVER_OBJECT_SET_ZONE) dg.add_uint32(parent_id) dg.add_uint32(zone_id) self.service.send_datagram(dg) else: self.service.log.debug( f'Client {self.channel} tried setting location for unowned object {do_id}!' )
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)
def annihilate(self, sender, notify_parent=True): targets = list() if self.parent_id: targets.append(location_as_channel(self.parent_id, self.zone_id)) if notify_parent: dg = Datagram() dg.add_server_header([self.parent_id], sender, STATESERVER_OBJECT_CHANGE_ZONE) dg.add_uint32(self.do_id) dg.add_uint32(0) # New parent dg.add_uint32(0) # new zone dg.add_uint32(self.parent_id) # old parent dg.add_uint32(self.zone_id) # old zone self.service.send_datagram(dg) if self.owner_channel: targets.append(self.owner_channel) if self.ai_channel: targets.append(self.ai_channel) dg = Datagram() dg.add_server_header(targets, sender, STATESERVER_OBJECT_DELETE_RAM) dg.add_uint32(self.do_id) self.service.send_datagram(dg) self.delete_children(sender) del self.service.objects[self.do_id] self.service.remove_participant(self) if self.db: self.service.database_objects.remove(self.do_id) self.service.log.debug(f'Object {self.do_id} has been deleted.')
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)
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)