async def add_shape(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] if "temporary" not in data: data["temporary"] = False floor = location.floors.select().where( Floor.name == data["shape"]["floor"])[0] layer = floor.layers.where(Layer.name == data["shape"]["layer"])[0] if room.creator != user and not layer.player_editable: logger.warning(f"{user.name} attempted to add a shape to a dm layer") return if data["temporary"]: state.add_temp(sid, data["shape"]["uuid"]) else: with db.atomic(): data["shape"]["layer"] = layer data["shape"]["index"] = layer.shapes.count() # Shape itself shape = Shape.create(**reduce_data_to_model(Shape, data["shape"])) # Subshape type_table = get_table(shape.type_) type_table.create(shape=shape, **reduce_data_to_model(type_table, data["shape"])) # Owners ShapeOwner.create(shape=shape, user=user) # Trackers for tracker in data["shape"]["trackers"]: Tracker.create(**reduce_data_to_model(Tracker, tracker), shape=shape) # Auras for aura in data["shape"]["auras"]: Aura.create(**reduce_data_to_model(Aura, aura), shape=shape) if layer.player_visible: for room_player in room.players: for psid in state.get_sids(user=room_player.player, room=room): if psid == sid: continue if not data["temporary"]: data["shape"] = shape.as_dict(room_player.player, False) await sio.emit("Shape.Add", data["shape"], room=psid, namespace="/planarally") for csid in state.get_sids(user=room.creator, room=room): if csid == sid: continue if not data["temporary"]: data["shape"] = shape.as_dict(room.creator, True) await sio.emit("Shape.Add", data["shape"], room=csid, namespace="/planarally")
async def change_location(sid, location): 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 change location") return old_location = room.get_active_location(dm=True) sio.leave_room(sid, old_location.get_path(), namespace="/planarally") room.dm_location = location new_location = room.get_active_location(dm=True) sio.enter_room(sid, new_location.get_path(), namespace="/planarally") await load_location(sid, new_location) room.player_location = location for room_player in room.players: for psid in state.get_sids(user=room_player.player, room=room): sio.leave_room(psid, old_location.get_path(), namespace="/planarally") sio.enter_room(psid, new_location.get_path(), namespace="/planarally") await load_location(psid, new_location)
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 add(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] label = Label.get_or_none(uuid=data) if label is not None: logger.warn( f"{user.name} tried to add a label with an id that already exists." ) return if data["user"] != user.name: logger.warn(f"{user.name} tried to add a label for someone else.") return data["user"] = User.by_name(data["user"]) label = Label.create(**data) for psid in state.get_sids(skip_sid=sid, room=room): if state.get_user(psid) == user or label.visible: await sio.emit("Label.Add", label.as_dict(), room=psid, namespace="/planarally")
async def remove_shape(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] # We're first gonna retrieve the existing server side shape for some validation checks if data["temporary"]: # This stuff is not stored so we cannot do any server side validation /shrug shape = data["shape"] layer = location.layers.where(Layer.name == data["shape"]["layer"])[0] else: # Use the server version of the shape. try: shape = Shape.get(uuid=data["shape"]["uuid"]) except Shape.DoesNotExist: logger.warning(f"Attempt to update unknown shape by {user.name}") return layer = shape.layer # Ownership validatation if room.creator != user: if not layer.player_editable: logger.warning( f"{user.name} attempted to remove a shape on a dm layer") return if data["temporary"]: if user.name not in shape["owners"]: logger.warning( f"{user.name} attempted to remove asset it does not own") return else: if not ShapeOwner.get_or_none(shape=shape, user=user): logger.warning( f"{user.name} attempted to remove asset it does not own") return if data["temporary"]: state.remove_temp(sid, data["shape"]["uuid"]) else: shape.delete_instance() if layer.player_visible: await sio.emit( "Shape.Remove", data["shape"], room=location.get_path(), skip_sid=sid, namespace="/planarally", ) else: for csid in state.get_sids(user=room.creator, room=room): if csid == sid: continue await sio.emit("Shape.Remove", data["shape"], room=csid, namespace="/planarally")
async def send_client_initiatives(room, location, user=None, skip_sid=None): for room_player in room.players: if user is None or user == room_player.player: for psid in state.get_sids(user=room_player.player, room=room): if psid == skip_sid: continue await sio.emit( "Initiative.Set", get_client_initiatives(room_player.player, location), room=psid, namespace="/planarally", ) if user is None or user == room.creator: for csid in state.get_sids(user=room.creator, room=room): if csid == skip_sid: continue await sio.emit( "Initiative.Set", get_client_initiatives(room.creator, location), room=csid, namespace="/planarally", )
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 add_filter(sid, uuid): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] label = Label.get_or_none(uuid=uuid) LabelSelection.create(label=label, user=user, room=room) for psid in state.get_sids(skip_sid=sid, room=room): if state.get_user(psid) == user: await sio.emit("Labels.Filter.Add", uuid, room=psid, namespace="/planarally")
async def move_shape_order(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] shape = Shape.get(uuid=data["shape"]["uuid"]) layer = shape.layer if room.creator != user and not layer.player_editable: logger.warning( f"{user.name} attempted to move a shape order on a dm layer") return target = data["index"] + 1 sign = 1 if target <= 1 else -1 polarity = 1 if shape.index > 0 else -1 case = Case( None, ( (Shape.index == shape.index, target * (-polarity)), ( (polarity * sign * Shape.index) < (polarity * sign * shape.index), (Shape.index + (polarity * sign * 1)) * -1, ), ), Shape.index * -1, ) Shape.update(index=case).where(Shape.layer == layer).execute() if layer.player_visible: await sio.emit( "Shape.Order.Set", data, room=location.get_path(), skip_sid=sid, namespace="/planarally", ) else: for csid in state.get_sids(user=room.creator, room=room): if csid == sid: continue await sio.emit("Shape.Order.Set", data["shape"], room=csid, namespace="/planarally")
async def remove_filter(sid, uuid): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] label = Label.get_or_none(uuid=uuid) ls = LabelSelection.get_or_none(label=label, room=room, user=user) if ls: ls.delete_instance(True) for psid in state.get_sids(skip_sid=sid, room=room): if state.get_user(psid) == user: await sio.emit("Labels.Filter.Remove", uuid, room=psid, namespace="/planarally")
async def set_visibility(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] label = Label.get_or_none(uuid=data["uuid"]) if label is None: logger.warn(f"{user.name} tried to change a non-existing label.") return if label.user != user: logger.warn(f"{user.name} tried to change another user's label.") return label.visible = data["visible"] label.save() for psid in state.get_sids(skip_sid=sid, room=room): if state.get_user(psid) == user: await sio.emit( "Label.Visibility.Set", { "user": label.user.name, **data }, room=psid, namespace="/planarally", ) else: if data["visible"]: await sio.emit("Label.Add", label.as_dict(), room=psid, namespace="/planarally") else: await sio.emit("Label.Delete", { 'uuid': label.uuid, 'user': label.user.name }, room=psid, namespace="/planarally")
async def update_shape(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] # We're first gonna retrieve the existing server side shape for some validation checks if data["temporary"]: # This stuff is not stored so we cannot do any server side validation /shrug shape = data["shape"] layer = location.layers.where(Layer.name == data["shape"]["layer"])[0] else: # Use the server version of the shape. try: shape = Shape.get(uuid=data["shape"]["uuid"]) except Shape.DoesNotExist: logger.warning(f"Attempt to update unknown shape by {user.name}") return layer = shape.layer # Ownership validatation if room.creator != user: if not layer.player_editable: logger.warning( f"{user.name} attempted to move a shape on a dm layer") return if data["temporary"]: if user.name not in shape["owners"]: logger.warning( f"{user.name} attempted to move asset it does not own") return else: if not ShapeOwner.get_or_none(shape=shape, user=user): logger.warning( f"{user.name} attempted to move asset it does not own") return # Overwrite the old data with the new data if not data["temporary"]: with db.atomic(): data["shape"]["layer"] = Layer.get(location=location, name=data["shape"]["layer"]) # Otherwise backrefs can cause errors as they need to be handled separately update_model_from_dict(shape, reduce_data_to_model(Shape, data["shape"])) shape.save() type_table = get_table(shape.type_) type_instance = type_table.get(uuid=shape.uuid) # no backrefs on these tables update_model_from_dict(type_instance, data["shape"], ignore_unknown=True) type_instance.save() old_owners = {owner.user.name for owner in shape.owners} new_owners = set(data["shape"]["owners"]) for owner in old_owners ^ new_owners: if owner == "": continue delta_owner = User.by_name(owner) if owner in new_owners: ShapeOwner.create(shape=shape, user=delta_owner) else: ShapeOwner.get(shape=shape, user=delta_owner).delete_instance(True) await send_client_initiatives(room, location, delta_owner) # Send to players if layer.player_visible: for room_player in room.players: for psid in state.get_sids(user=room_player.player, room=room): if psid == sid: continue if not data["temporary"]: data["shape"] = shape.as_dict(room_player.player, False) await sio.emit("Shape.Update", data, room=psid, namespace="/planarally") # Send to DM for csid in state.get_sids(user=room.creator, room=room): if csid == sid: continue if not data["temporary"]: data["shape"] = shape.as_dict(room.creator, True) await sio.emit("Shape.Update", data, room=csid, namespace="/planarally")
async def change_shape_layer(sid, data): sid_data = state.sid_map[sid] user = sid_data["user"] room = sid_data["room"] location = sid_data["location"] if room.creator != user: logger.warning(f"{user.name} attempted to move the layer of a shape") return layer = Layer.get(location=location, name=data["layer"]) shape = Shape.get(uuid=data["uuid"]) old_layer = shape.layer old_index = shape.index if old_layer.player_visible and not layer.player_visible: for room_player in room.players: for psid in state.get_sids(user=room_player.player, room=room): if psid == sid: continue await sio.emit( "Shape.Remove", shape.as_dict(room_player.player, False), room=psid, namespace="/planarally", ) shape.layer = layer shape.index = layer.shapes.count() shape.save() Shape.update(index=Shape.index - 1).where((Shape.layer == old_layer) & (Shape.index >= old_index)).execute() if old_layer.player_visible and layer.player_visible: await sio.emit( "Shape.Layer.Change", data, room=location.get_path(), skip_sid=sid, namespace="/planarally", ) else: for csid in state.get_sids(user=room.creator, room=room): if csid == sid: continue await sio.emit( "Shape.Layer.Change", data, room=location.get_path(), skip_sid=sid, namespace="/planarally", ) if layer.player_visible: for room_player in room.players: for psid in state.get_sids(user=room_player.player, room=room): if psid == sid: continue await sio.emit( "Shape.Add", shape.as_dict(room_player.player, False), room=psid, namespace="/planarally", )