async def claim_invite(request): user = await check_authorized(request) data = await request.json() room = Room.get_or_none(invitation_code=data["code"]) if room is None: return web.HTTPNotFound() else: if user != room.creator and not PlayerRoom.get_or_none(player=user, room=room): query = PlayerRoom.select().where(PlayerRoom.room == room) try: loc = query.where( PlayerRoom.role == Role.PLAYER)[0].active_location except IndexError: loc = query.where( PlayerRoom.role == Role.DM)[0].active_location PlayerRoom.create(player=user, room=room, role=Role.PLAYER, active_location=loc) for csid in game_state.get_sids(player=room.creator, room=room): await sio.emit( "Room.Info.Players.Add", { "id": user.id, "name": user.name }, room=csid, namespace="/planarally", ) return web.json_response({ "sessionUrl": f"/game/{urllib.parse.quote(room.creator.name, safe='')}/{urllib.parse.quote(room.name, safe='')}" })
async def create(request): allow_new_sessions = config.getboolean("Access control", "allow_new_sessions") if not allow_new_sessions: return web.HTTPConflict( reason="This feature is disabled by administrator") user = await check_authorized(request) data = await request.json() roomname = data["name"] if not roomname: return web.HTTPBadRequest() else: with db.atomic(): default_options = LocationOptions.create() room = Room.create(name=roomname, creator=user, default_options=default_options) loc = Location.create(room=room, name="start", index=1) loc.create_floor() PlayerRoom.create(player=user, room=room, role=Role.DM, active_location=loc) room.save() return web.HTTPOk()
async def claim_invite(request): user = await check_authorized(request) data = await request.json() room = Room.get_or_none(invitation_code=data["code"]) if room is None: return web.HTTPNotFound() else: if user.name != room.creator and not PlayerRoom.get_or_none( player=user, room=room): PlayerRoom.create(player=user, room=room) for csid in state.get_sids(user=room.creator, room=room): await sio.emit( "Room.Info.Players.Add", { "id": user.id, "name": user.name }, room=csid, namespace="/planarally", ) return web.json_response({ "sessionUrl": f"/game/{urllib.parse.quote(room.creator.name, safe='')}/{urllib.parse.quote(room.name, safe='')}" })
async def create(request: web.Request): user: User = await check_authorized(request) data = await request.json() roomname = data["name"] logo = data["logo"] if not roomname: return web.HTTPBadRequest() else: if Room.get_or_none(name=roomname, creator=user): return web.HTTPConflict() with db.atomic(): default_options = LocationOptions.create() room = Room.create( name=roomname, creator=user, default_options=default_options, ) if logo >= 0: room.logo_id = logo loc = Location.create(room=room, name="start", index=1) loc.create_floor() PlayerRoom.create(player=user, room=room, role=Role.DM, active_location=loc) room.save() return web.HTTPOk()
async def claim_invite(request): user = await check_authorized(request) room = Room.get_or_none(invitation_code=request.match_info["code"]) if room is None: return web.HTTPNotFound() else: if user.name != room.creator and not PlayerRoom.get_or_none( player=user, room=room): PlayerRoom.create(player=user, room=room) return web.HTTPFound(f"/rooms/{room.creator.name}/{room.name}")
async def claim_invite(request): user = await check_authorized(request) data = await request.json() room = Room.get_or_none(invitation_code=data["code"]) if room is None: return web.HTTPNotFound() else: if user.name != room.creator and not PlayerRoom.get_or_none( player=user, room=room): PlayerRoom.create(player=user, room=room) return web.json_response( {"sessionUrl": f"/game/{room.creator.name}/{room.name}"})
async def connect(sid, environ): user = await authorized_userid(environ["aiohttp.request"]) if user is None: await sio.emit("redirect", "/", room=sid, namespace=GAME_NS) return ref = { k.split("=")[0]: k.split("=")[1] for k in unquote(environ["QUERY_STRING"]).strip().split("&") } try: room = ( Room.select().join(User).where((Room.name == ref["room"]) & (User.name == ref["user"]))[0]) except IndexError: return False else: for pr in room.players: if pr.player == user: if pr.role != Role.DM and room.is_locked: return False break else: return False pr = PlayerRoom.get(room=room, player=user) await game_state.add_sid(sid, pr) logger.info(f"User {user.name} connected with identifier {sid}") sio.enter_room(sid, pr.active_location.get_path(), namespace=GAME_NS)
async def set_player_role(sid: str, data: PlayerRoleChange): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning( f"{pr.player.name} attempted to change the role of a player") return new_role = Role(data["role"]) player_pr: PlayerRoom = PlayerRoom.get(player=data["player"], room=pr.room) creator: User = player_pr.room.creator if pr.player != creator and creator == player_pr.player: logger.warning( f"{pr.player.name} attempted to change the role of the campaign creator" ) return player_pr.role = new_role player_pr.save() for sid in game_state.get_sids(player=player_pr.player, room=pr.room): await sio.disconnect(sid, namespace=GAME_NS) for psid in game_state.get_sids(room=pr.room): if game_state.get(psid).role == Role.DM: await sio.emit("Player.Role.Set", data, room=psid, namespace=GAME_NS)
async def set_info(request: web.Request): user: User = await check_authorized(request) creator = request.match_info["creator"] roomname = request.match_info["roomname"] data = await request.json() rooms = ( PlayerRoom.select() .join(Room) .join(User) .filter(player=user) .where((User.name == creator) & (Room.name == roomname)) ) if len(rooms) != 1: return web.HTTPNotFound() room = rooms[0] if "notes" in data: room.notes = data["notes"] room.save() return web.HTTPOk()
async def get_info(request: web.Request): user: User = await check_authorized(request) creator = request.match_info["creator"] roomname = request.match_info["roomname"] room = ( PlayerRoom.select() .join(Room) .join(User) .filter(player=user) .where((User.name == creator) & (Room.name == roomname)) ) if len(room) != 1: return web.HTTPNotFound() return web.json_response( { "notes": room[0].notes, "last_played": None if room[0].last_played is None else room[0].last_played.strftime("%Y/%m/%d"), } )
async def delete(request: web.Request): user: User = await check_authorized(request) creator = request.match_info["creator"] roomname = request.match_info["roomname"] if creator == user.name: room: Room = Room.get_or_none(name=roomname, creator=user) if room is None: return web.HTTPBadRequest() room.delete_instance(True) return web.HTTPOk() else: pr = ( PlayerRoom.select() .join(Room) .join(User) .filter(player=user) .where((User.name == creator) & (Room.name == roomname)) ) if len(pr) == 1: pr[0].delete_instance(True) return web.HTTPOk() return web.HTTPUnauthorized()
async def create(request): user = await check_authorized(request) data = await request.json() roomname = data["name"] if not roomname: return web.HTTPBadRequest() else: with db.atomic(): default_options = LocationOptions.create() room = Room.create(name=roomname, creator=user, default_options=default_options) loc = Location.create(room=room, name="start", index=1) loc.create_floor() PlayerRoom.create(player=user, room=room, role=Role.DM, active_location=loc) room.save() return web.HTTPOk()
async def add_shape_owner(sid: str, data: ServerShapeOwner): pr: PlayerRoom = game_state.get(sid) try: shape = Shape.get(uuid=data["shape"]) except Shape.DoesNotExist as exc: logger.warning( f"Attempt to add owner to 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 target_user = User.by_name(data["user"]) if target_user is None: logger.warning( f"Attempt to add unknown user as owner to shape by {pr.player.name} [{data['user']}]" ) return # Adding the DM as user is redundant and can only lead to confusion if PlayerRoom.get(room=pr.room, player=target_user).role == Role.DM: return if not ShapeOwner.get_or_none(shape=shape, user=target_user): ShapeOwner.create( shape=shape, user=target_user, edit_access=data["edit_access"], movement_access=data["movement_access"], vision_access=data["vision_access"], ) await send_client_initiatives(pr, target_user) await sio.emit( "Shape.Owner.Add", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, ) if not (shape.default_vision_access or shape.default_edit_access): for sid in game_state.get_sids(player=target_user, active_location=pr.active_location): await sio.emit( "Shape.Set", shape.as_dict(target_user, False), room=sid, namespace=GAME_NS, )
async def kick_player(sid: int, player_id: int): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to refresh the invitation code.") return pr = PlayerRoom.get_or_none(player=player_id, room=pr.room) if pr: for psid in game_state.get_sids(player=pr.player, room=pr.room): await sio.disconnect(psid, namespace=GAME_NS) pr.delete_instance(True)
async def kick_player(sid, playerId): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] if room.creator != user: logger.warning( f"{user.name} attempted to refresh the invitation code.") return pr = PlayerRoom.get_or_none(player=playerId, room=room) if pr: for psid in state.get_sids(user=pr.player, room=room): await sio.disconnect(psid, namespace="/planarally") pr.delete_instance(True)
async def kick_player(sid: str, player_id: int): pr: PlayerRoom = game_state.get(sid) if pr.role != Role.DM: logger.warning(f"{pr.player.name} attempted to refresh the invitation code.") return pr = PlayerRoom.get_or_none(player=player_id, room=pr.room) if pr is None: return creator: User = pr.room.creator if pr.player != creator and creator == pr.player: logger.warning(f"{pr.player.name} attempted to kick the campaign creator") return for psid in game_state.get_sids(player=pr.player, room=pr.room): await sio.disconnect(psid, namespace=GAME_NS) pr.delete_instance(True)
async def update_client_location(player: int, room: int, sid: str, data: LocationOptions): pr = PlayerRoom.get(player=player, room=room) LocationUserOption.update( pan_x=data["pan_x"], pan_y=data["pan_y"], zoom_display=data["zoom_display"], ).where((LocationUserOption.location == pr.active_location) & (LocationUserOption.user == pr.player)).execute() if pr.role != Role.DM: for p_sid, p_player in game_state.get_t(skip_sid=sid): if p_player.role == Role.DM or p_player.player.id == player: await sio.emit( "Client.Move", { "player": pr.player.id, **data }, room=p_sid, namespace=GAME_NS, )
async def connect(sid, environ): user = await authorized_userid(environ["aiohttp.request"]) if user is None: await sio.emit("redirect", "/", room=sid, namespace="/planarally") else: ref = { k.split("=")[0]: k.split("=")[1] for k in unquote(environ["QUERY_STRING"]).strip().split("&") } try: room = ( Room.select() .join(User) .where((Room.name == ref["room"]) & (User.name == ref["user"]))[0] ) except IndexError: return False else: for pr in room.players: if pr.player == user: if pr.role != Role.DM and room.is_locked: return False break else: return False pr = PlayerRoom.get(room=room, player=user) # todo: just store PlayerRoom as it has all the info await game_state.add_sid(sid, pr) logger.info(f"User {user.name} connected with identifier {sid}") labels = Label.select().where((Label.user == user) | (Label.visible == True)) label_filters = LabelSelection.select().where( (LabelSelection.user == user) & (LabelSelection.room == room) ) sio.enter_room(sid, pr.active_location.get_path(), namespace="/planarally") await sio.emit("Username.Set", user.name, room=sid, namespace="/planarally") await sio.emit( "Labels.Set", [l.as_dict() for l in labels], room=sid, namespace="/planarally", ) await sio.emit( "Labels.Filters.Set", [l.label.uuid for l in label_filters], room=sid, namespace="/planarally", ) await sio.emit( "Room.Info.Set", { "name": room.name, "creator": room.creator.name, "invitationCode": str(room.invitation_code), "isLocked": room.is_locked, "default_options": room.default_options.as_dict(), "players": [ { "id": rp.player.id, "name": rp.player.name, "location": rp.active_location.id, } for rp in room.players ], }, room=sid, namespace="/planarally", ) await sio.emit( "Asset.List.Set", Asset.get_user_structure(user), room=sid, namespace="/planarally", ) if pr.role == Role.DM: await sio.emit( "Locations.Settings.Set", { l.name: {} if l.options is None else l.options.as_dict() for l in pr.room.locations }, room=sid, namespace="/planarally", ) await load_location(sid, pr.active_location)