async def get_rooms_on_y(self, y: int, from_x: int, to_x: int, z: int, get_content=True): assert to_x > from_x redis = await self.redis() pipeline = redis.pipeline() if z: packed_coordinates = (self._pack_coords(x, y, z) for x in range(from_x, to_x)) pipeline.hmget(self.z_valued_rooms_data_key, *packed_coordinates) else: k = self._coords_to_int(from_x, y) pipeline.getrange(self.terrains_bitmap_key, k, k + ((to_x - from_x) - 1)) get_content and [ self._get_room_content(pipeline, x, y, z) for x in range(from_x, to_x) ] response = [] i = 0 result = await pipeline.execute() if z: res = result[0] d = 0 for key, value in res[0].items(): terrain = int(value) response.append( Room( position=PositionComponent().set_list_coordinates( [from_x + d, y, z]), terrain=TerrainEnum(terrain), )) d += 1 for res in result[i + 1]: response[i].add_entity_ids(list(res)) else: terrains = struct.unpack('B' * (to_x - from_x), result[0]) for d in range(0, to_x - from_x): response.append( Room(position=PositionComponent().set_list_coordinates( [from_x + d, y, z]), terrain=TerrainEnum(terrains[d]), entity_ids=get_content and [int(x) for x in result[d + 1]] or [])) return response
async def asyncio_test(self): sut = RedisMapRepository(get_redis_factory(RedisType.DATA)) await (await sut.redis()).flushdb() max_x, max_y, max_z = 500, 500, 1 sut.max_y = max_y sut.max_x = max_x start = time.time() i = 0 print('\nBaking {}x{} map'.format(max_x, max_y)) for x in range(max_x, -1, -1): roomz = OrderedDict() for y in range(max_y, -1, -1): for z in range(0, max_z): i += 1 position = PositionComponent( coord='{},{},{}'.format(x, y, z)) roomz['{}.{}.{}'.format(x, y, z)] = Room( position=position, terrain=random.choice( [TerrainEnum.WALL_OF_BRICKS, TerrainEnum.PATH]), ) print(i, ' rooms saved') await sut.set_rooms(*roomz.values()) print('\n{}x{} map baked in {}'.format(max_x, max_y, time.time() - start)) start = time.time() print('\nFetching {}x{} map'.format(max_x, max_y)) tot = 0 for x in range(0, max_x): res = await sut.get_rooms(*(PositionComponent( coord='{},{},{}'.format(x, y, 0)) for y in range(0, max_y))) tot += len(res) print('\n{}x{} map fetched in {} - total: {}'.format( max_x, max_y, time.time() - start, tot))
async def get_room(self, position: PositionComponent, populate=True) -> typing.Optional[Room]: if (self.min_y > position.y) or (self.max_y < position.y): raise exceptions.RoomError if (self.min_x > position.x) or (self.max_x < position.x): raise exceptions.RoomError redis = await self.redis() pipeline = redis.pipeline() if position.z: pipeline.hget( self.z_valued_rooms_data_key, '{}.{}.{}'.format(position.x, position.y, position.z), ) else: k = self._coords_to_int(position.x, position.y) pipeline.getrange(self.terrains_bitmap_key, k, k) populate and self._get_room_content(pipeline, position.x, position.y, position.z) result = await pipeline.execute() if not result or not result[0]: LOGGER.core.error('Room Error. Request: %s, Result: %s', position, result) raise exceptions.RoomError if position.z: terrain = int(result[0]) else: terrain = int(struct.unpack('B', result[0])[0]) content = populate and [int(x) for x in result[1]] or [] return Room(position=position, terrain=TerrainEnum(terrain), entity_ids=content)
async def get_rooms(self, *positions: PositionComponent, get_content=True): redis = await self.redis() pipeline = redis.pipeline() for position in positions: if position.z: pipeline.hget( self.z_valued_rooms_data_key, '{}.{}.{}'.format(position.x, position.y, position.z)) else: k = self._coords_to_int(position.x, position.y) pipeline.getrange(self.terrains_bitmap_key, k, k) get_content and self._get_room_content(pipeline, position.x, position.y, position.z) result = await pipeline.execute() i = 0 response = [] for position in positions: if position.z: terrain = int(result[i]) else: terrain = int(struct.unpack('B', result[i])[0]) i += 1 if get_content: content = [int(x) for x in result[i]] i += 1 else: content = [] response.append( Room(position=position, terrain=TerrainEnum(terrain), entity_ids=content)) return response
async def cast_entity( entity: Entity, position: PositionComponent, update=True, on_connect=False, reason=None ): assert isinstance(position, PositionComponent) from core.src.world.builder import events_subscriber_service, events_publisher_service loop = asyncio.get_event_loop() if update: current_position = await get_components_for_entity(entity, (PositionComponent, 'coord')) position.add_previous_position(current_position) entity = entity.set_for_update(position).set_room(Room(position)) update_response = await update_entities(entity.set_for_update(position)) if not update_response: LOGGER.core.error( 'Impossible to cast entity {}'.format(entity.entity_id)) return area = Area(position).make_coordinates() listeners = await get_eligible_listeners_for_area(area) entity.entity_id in listeners and listeners.remove(entity.entity_id) if on_connect: await events_publisher_service.on_entity_appear_position(entity, position, reason, targets=listeners) loop.create_task(events_subscriber_service.subscribe_events(entity)) else: pass await events_publisher_service.on_entity_change_position(entity, position, reason, targets=listeners) entity.set_component(position) return True
async def do(self) -> bool: from core.src.world.actions.movement.move import do_move_entity if not self.entity.get_room(): position = self.entity.get_component(PositionComponent) assert position self.entity.set_room(Room(PositionComponent)) if not self.target_room: self.target_room = await get_room_at_direction(self.entity, self.direction, populate=False) if not await self.target_room.walkable_by(self.entity): new_target = self.escape_corners and await self.find_escape() if new_target: self.target_room = new_target else: await emit_msg(self.entity, messages.invalid_direction()) return False await do_move_entity(self.entity, self.target_room, self.direction, "movement", self_emit_message=self._sem) self._sem = False self.target_room = None return True
def parse_lines(lines): lines = [l.strip() for l in lines] max_y = len(lines) - 1 max_x = max([len(line) for line in lines]) - 1 rooms = [] for y in range(max_y, -1, -1): for x in range(0, max_x + 1): room_enum = terrains[lines[y][x]] if room_enum: rooms.append( Room(position=PositionComponent().set_list_coordinates( [x, max_y - y, 0]), terrain=room_enum)) return rooms
async def _do_follow(self, follower_id: int, event: typing.Dict): current_followed_id = self._follow_by_follower.get(follower_id) if current_followed_id != event['entity']['id']: LOGGER.core.error('Error on follow system') return entity = await load_components(Entity(follower_id), SystemComponent, PositionComponent) if entity.get_component(PositionComponent).list_coordinates != event['from']: LOGGER.core.error('Error on follow system') return await do_move_entity( entity, Room(PositionComponent().set_list_coordinates(event['to'])), None, reason="movement", emit_message=False )
async def asyncio_test(self): sut = RedisMapRepository(get_redis_factory(RedisType.DATA)) await (await sut.redis()).flushdb() max_x, max_y = 50, 50 sut.max_y = max_y sut.max_x = max_x start = time.time() print('\nBaking {}x{} map'.format(max_x, max_y)) roomz = OrderedDict() for x in range(0, max_x): for y in range(0, max_y): position = PositionComponent(coord='{},{},{}'.format(x, y, 0)) roomz['{}.{}.{}'.format(x, y, 0)] = Room( position=position, terrain=random.choice( [TerrainEnum.WALL_OF_BRICKS, TerrainEnum.PATH])) await sut.set_rooms(*roomz.values()) print('\n{}x{} map baked in {}'.format(max_x, max_y, time.time() - start)) from_x, to_x = 0, 9 for yy in range(0, 210, 10): futures = [ sut.get_rooms_on_y(0, from_x, to_x, 0) for _ in range(0, yy) ] s = time.time() res = await asyncio.gather(*futures) print('Get line of {} rooms. Concurrency: '.format(to_x - from_x), yy, ' users. Time: {:.8f}'.format(time.time() - s)) for r in res: for req in range(0, to_x): k = '{}.{}.{}'.format(from_x + req, 0, 0) self.assertEqual([ r[req].position.x, r[req].position.y, r[req].position.z ], [ roomz[k].position.x, roomz[k].position.y, roomz[k].position.z ])
async def async_test(self): sut = RedisMapRepository(get_redis_factory(RedisType.DATA)) await (await sut.redis()).flushdb() futures = [] d = {} i = 0 max_x, max_y, max_z = 25, 25, 5 sut.max_y = max_y sut.max_x = max_x start = time.time() for x in range(0, max_x): for y in range(0, max_y): for z in range(0, max_z): i += 1 d['{}.{}.{}'.format(x, y, z)] = [ random.randint(0, 65530), random.randint(0, 65530) ] futures.append( sut.set_room( Room(position=PositionComponent( coord='{},{},{}'.format(x, y, z)), terrain=TerrainEnum.WALL_OF_BRICKS))) await asyncio.gather(*futures) for x in range(0, max_x): for y in range(0, max_y): for z in range(0, max_z): room = await sut.get_room( PositionComponent(coord='{},{},{}'.format(x, y, z))) self.assertEqual( [room.position.x, room.position.y, room.position.z], [x, y, z]) print( '\n', i, ' rooms tested NO pipeline in {:.10f}'.format(time.time() - start)) await (await sut.redis()).flushdb() _start = time.time() roomz = OrderedDict() positions = [] for x in range(0, max_x): for y in range(0, max_y): for z in range(0, max_z): position = PositionComponent( coord='{},{},{}'.format(x, y, z)) positions.append(position) roomz['{}.{}.{}'.format(x, y, z)] = Room( position=position, terrain=TerrainEnum.WALL_OF_BRICKS, ) await sut.set_rooms(*roomz.values()) rooms = await sut.get_rooms(*positions) for i, room in enumerate(rooms): self.assertEqual([ room.position.x, room.position.y, room.position.z, ], [ positions[i].x, positions[i].y, positions[i].z, ]) print( '\n', i + 1, ' rooms tested WITH pipeline in {:.10f}'.format(time.time() - _start)) positions = [] i = 0 for x in range(0, 9): for y in range(0, 9): positions.append( PositionComponent(coord='{},{},{}'.format(x, y, 0))) i += 1 print('\n Starting benchmarks: \n') for x in range(1, 110, 10): futures = [sut.get_rooms(*positions) for _ in range(0, x)] s = time.time() await asyncio.gather(*futures) print('Rooms: ', i, '. Concurrency: ', x, ' users. Time: {:.8f}'.format(time.time() - s)) positions = [] i = 0 for x in range(0, 9): y = 1 positions.append( PositionComponent(coord='{},{},{}'.format(x, y, 0))) i += 1 for x in range(1, 110, 10): futures = [sut.get_rooms(*positions) for _ in range(0, x)] s = time.time() await asyncio.gather(*futures) print('Rooms: ', i, '. Concurrency: ', x, ' users. Time: {:.8f}'.format(time.time() - s))