async def join_group(sid: str, group_join: GroupJoin): pr: PlayerRoom = game_state.get(sid) group_ids = set() for member in group_join["members"]: try: shape = Shape.get_by_id(member["uuid"]) except Shape.DoesNotExist: logger.exception( f"Could not update shape group for unknown shape {member['uuid']}" ) else: if shape.group is not None and shape.group != group_join[ "group_id"]: group_ids.add(shape.group) shape.group = group_join["group_id"] shape.badge = member["badge"] shape.save() # Group joining can be the result of a merge or a split and thus other groups might be empty now for group_id in group_ids: await remove_group_if_empty(group_id) for psid, _ in game_state.get_users(room=pr.room): await sio.emit( "Group.Join", group_join, room=psid, skip_sid=sid, namespace=GAME_NS, )
async def sync_shape_update(layer, pr: PlayerRoom, data, sid, shape): for psid, player in game_state.get_users( active_location=pr.active_location): if psid == sid: continue pdata = {el: data[el] for el in data if el != "shape"} if data["temporary"]: if player != pr.room.creator and not ( data["shape"]["default_edit_access"] or any(player.name == o["user"] for o in data["shape"]["owners"])): pdata["shape"] = deepcopy(data["shape"]) # Although we have no guarantees that the message is faked, we still would like to verify data as if it were legitimate. for element in ["auras", "labels", "trackers"]: pdata["shape"][element] = [ el for el in pdata["shape"][element] if el["visible"] ] if not pdata["shape"]["name_visible"]: pdata["shape"]["name"] = "?" else: pdata["shape"] = shape try: pdata["shape"]["layer"] = pdata["shape"]["layer"].name except AttributeError: pass # To solve this error, we need to clean this mess of shape functions else: pdata["shape"] = shape.as_dict(player, player == pr.room.creator) await sio.emit("Shape.Update", pdata, room=psid, namespace=GAME_NS)
async def leave_group(sid: str, client_shapes: List[LeaveGroup]): pr: PlayerRoom = game_state.get(sid) group_ids = set() for client_shape in client_shapes: try: shape = Shape.get_by_id(client_shape["uuid"]) except Shape.DoesNotExist: logger.exception( f"Could not remove shape group for unknown shape {client_shape['uuid']}" ) else: group_ids.add(client_shape["group_id"]) shape.group = None shape.show_badge = False shape.save() for group_id in group_ids: await remove_group_if_empty(group_id) for psid, _ in game_state.get_users(room=pr.room): await sio.emit( "Group.Leave", client_shapes, room=psid, skip_sid=sid, namespace=GAME_NS, )
async def move_shapes(sid: str, data: ServerShapeLocationMove): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to move shape locations") return location = Location.get_by_id(data["target"]["location"]) floor = location.floors.select().where(Floor.name == data["target"]["floor"])[0] x = data["target"]["x"] y = data["target"]["y"] shapes = [Shape.get_by_id(sh) for sh in data["shapes"]] await sio.emit( "Shapes.Remove", [sh.uuid for sh in shapes], room=pr.active_location.get_path(), namespace=GAME_NS, ) for shape in shapes: shape.layer = floor.layers.where(Layer.name == shape.layer.name)[0] shape.center_at(x, y) shape.save() for psid, player in game_state.get_users(active_location=location): await sio.emit( "Shapes.Add", [sh.as_dict(player, game_state.get(psid).role == Role.DM) for sh in shapes], room=psid, namespace=GAME_NS, )
async def set_locked_game_state(sid: int, is_locked: bool): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to set the locked game_state.") return pr.room.is_locked = is_locked pr.room.save() for psid, player in game_state.get_users(room=pr.room): if player != pr.room.creator: await sio.disconnect(psid, namespace=GAME_NS)
async def move_shapes(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to move shape locations") return location = Location[data["target"]["location"]] floor = location.floors.select().where( Floor.name == data["target"]["floor"])[0] x = data["target"]["x"] y = data["target"]["y"] shapes = [Shape[sh] for sh in data["shapes"]] for psid, player in game_state.get_users( active_location=pr.active_location): await sio.emit( "Shapes.Remove", [sh.as_dict(player, player == pr.room.creator) for sh in shapes], room=psid, namespace=GAME_NS, ) for shape in shapes: shape.layer = floor.layers.where(Layer.name == shape.layer.name)[0] shape.center_at(x, y) shape.save() for psid, player in game_state.get_users(active_location=location): await sio.emit( "Shapes.Add", [sh.as_dict(player, player == pr.room.creator) for sh in shapes], room=psid, namespace=GAME_NS, )
async def create_floor(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to create a new floor") return floor: Floor = pr.active_location.create_floor(data) for psid, player in game_state.get_users(room=pr.room): await sio.emit( "Floor.Create", floor.as_dict(player, player == pr.room.creator), room=psid, namespace="/planarally", )
async def create_group(sid: str, group_info: ServerGroup): pr: PlayerRoom = game_state.get(sid) try: Group.get_by_id(group_info["uuid"]) logger.exception(f"Group with {group_info['uuid']} already exists") return except Group.DoesNotExist: Group.create(**group_info) for psid, _ in game_state.get_users(room=pr.room): await sio.emit( "Group.Create", group_info, room=psid, skip_sid=sid, namespace=GAME_NS, )
async def remove_group(sid: str, group_id: str): pr: PlayerRoom = game_state.get(sid) for shape in Shape.filter(group_id=group_id).select(): shape.group = None shape.show_badge = False shape.save() # check if group still has members await remove_group_if_empty(group_id) for psid, _ in game_state.get_users(room=pr.room): await sio.emit( "Group.Remove", group_id, room=psid, skip_sid=sid, namespace=GAME_NS, )
async def update_default_shape_owner(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) try: shape: Shape = Shape.get(uuid=data["shape"]) except Shape.DoesNotExist as exc: logger.warning( f"Attempt to update owner of unknown shape by {pr.player.name} [{data['shape']}]" ) raise exc if not has_ownership(shape, pr): logger.warning( f"{pr.player.name} attempted to change asset ownership of a shape it does not own" ) return if "edit_access" in data: shape.default_edit_access = data["edit_access"] if "vision_access" in data: shape.default_vision_access = data["vision_access"] shape.save() await sio.emit( "Shape.Owner.Default.Update", data, room=pr.active_location.get_path(), skip_sid=sid, namespace="/planarally", ) if shape.default_vision_access or shape.default_edit_access: for sid, player in game_state.get_users( active_location=pr.active_location): await sio.emit( "Shape.Set", shape.as_dict(player, player.name == pr.room.creator), room=sid, namespace="/planarally", )
async def update_group(sid: str, group_info: ServerGroup): pr: PlayerRoom = game_state.get(sid) try: group = Group.get_by_id(group_info["uuid"]) except Group.DoesNotExist: logger.exception( f"Could not retrieve group information for {group_info['uuid']}") else: update_model_from_dict(group, group_info) group.save() for psid, _ in game_state.get_users(room=pr.room): await sio.emit( "Group.Update", group_info, room=psid, skip_sid=sid, namespace=GAME_NS, )
async def create_floor(sid: str, data: str): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to create a new floor") return floor: Floor = pr.active_location.create_floor(data) for psid, player in game_state.get_users( active_location=pr.active_location): await sio.emit( "Floor.Create", { "floor": floor.as_dict(player, player == pr.room.creator), "creator": pr.player.name, }, room=psid, namespace=GAME_NS, )
async def update_default_shape_owner(sid: str, data: ServerShapeDefaultOwner): pr: PlayerRoom = game_state.get(sid) try: shape: Shape = Shape.get(uuid=data["shape"]) except Shape.DoesNotExist as exc: logger.warning( f"Attempt to update owner of unknown shape by {pr.player.name} [{data['shape']}]" ) raise exc if not has_ownership(shape, pr): logger.warning( f"{pr.player.name} attempted to change asset ownership of a shape it does not own" ) return if "edit_access" in data: shape.default_edit_access = data["edit_access"] if "vision_access" in data: shape.default_vision_access = data["vision_access"] if "movement_access" in data: shape.default_movement_access = data["movement_access"] shape.save() # We need to send each player their new view of the shape which includes the default access fields, # so there is no use in sending those separately for sid, player in game_state.get_users(active_location=pr.active_location, skip_sid=sid): await sio.emit( "Shape.Set", shape.as_dict(player, game_state.get(sid).role == Role.DM), room=sid, namespace=GAME_NS, ) await send_client_initiatives(pr, player)
async def update_group_badges(sid: str, member_badges: List[MemberBadge]): pr: PlayerRoom = game_state.get(sid) for member in member_badges: try: shape = Shape.get_by_id(member["uuid"]) except Shape.DoesNotExist: logger.exception( f"Could not update shape badge for unknown shape {member['uuid']}" ) else: shape.badge = member["badge"] shape.save() for psid, player in game_state.get_users(room=pr.room): await sio.emit( "Group.Members.Update", member_badges, room=psid, skip_sid=sid, namespace=GAME_NS, )