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 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() await sio.emit( "Shape.Layer.Change", data, room=location.get_path(), skip_sid=sid, namespace="/planarally", )
async def change_shape_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 move the floor of a shape") return floor: Floor = Floor.get(location=pr.active_location, name=data["floor"]) shape: Shape = Shape.get(uuid=data["uuid"]) layer: Layer = Layer.get(floor=floor, name=shape.layer.name) old_layer = shape.layer old_index = shape.index 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() await sio.emit( "Shape.Floor.Change", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, )
async def move_shape_order(sid: str, data: ShapeOrder): pr: PlayerRoom = game_state.get(sid) if not data["temporary"]: shape = Shape.get(uuid=data["uuid"]) layer = shape.layer if pr.role != Role.DM and not layer.player_editable: logger.warning( f"{pr.player.name} attempted to move a shape order on a dm layer" ) return target = data["index"] sign = 1 if target < shape.index else -1 case = Case( None, ( (Shape.index == shape.index, target), ( (sign * Shape.index) < (sign * shape.index), (Shape.index + (sign * 1)), ), ), Shape.index, ) Shape.update(index=case).where(Shape.layer == layer).execute() await sio.emit( "Shape.Order.Set", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, )
async def set_locked(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 locked state 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 locked state of a shape it does not own" ) return shape.is_locked = data["is_locked"] shape.save() await sio.emit( "Shape.Options.Locked.Set", data, skip_sid=sid, room=pr.active_location.get_path(), namespace=GAME_NS, )
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 remove_shape(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) # We're first gonna retrieve the existing server side shape for some validation checks if data["temporary"]: if not has_ownership_temp(data["shape"], pr): logger.warning( f"User {pr.player.name} tried to update a shape it does not own." ) return # This stuff is not stored so we cannot do any server side validation /shrug shape = data["shape"] floor = pr.active_location.floors.select().where( Floor.name == data["shape"]["floor"])[0] layer = floor.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 {pr.player.name}") return layer = shape.layer if not has_ownership(shape, pr): logger.warning( f"User {pr.player.name} tried to update a shape it does not own." ) return if data["temporary"]: game_state.remove_temp(sid, data["shape"]["uuid"]) else: old_index = shape.index shape.delete_instance(True) Shape.update(index=Shape.index - 1).where((Shape.layer == layer) & (Shape.index >= old_index)).execute() if layer.player_visible: await sio.emit( "Shape.Remove", data["shape"], room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, ) else: for csid in game_state.get_sids(player=pr.room.creator, active_location=pr.active_location): if csid == sid: continue await sio.emit("Shape.Remove", data["shape"], room=csid, namespace=GAME_NS)
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 target_user == pr.room.creator: 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 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 update_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 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 target_user = User.by_name(data["user"]) if target_user is None: logger.warning( f"Attempt to update unknown user as owner to shape by {pr.player.name} [{data['user']}]" ) return try: so = ShapeOwner.get(shape=shape, user=target_user) except ShapeOwner.DoesNotExist as exc: logger.warning( f"Attempt to update unknown shape-owner relation by {pr.player.name}" ) return so.shape = shape so.user = target_user so.edit_access = data["edit_access"] so.movement_access = data["movement_access"] so.vision_access = data["vision_access"] so.save() await sio.emit( "Shape.Owner.Update", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, )
def get_shape_or_none(pr: PlayerRoom, shape_id: str, action: str) -> Union[Shape, None]: try: shape: Shape = Shape.get(uuid=shape_id) except Shape.DoesNotExist as exc: logger.warning( f"Attempt by {pr.player.name} on unknown shape. {{method: {action}, shape id: {shape_id}}}" ) raise exc if not has_ownership(shape, pr): logger.warning( f"Attempt by {pr.player.name} on shape they do not own. {{method: {action}, shape id: {shape_id}}}" ) return None return shape
async def _get_shape(data, location, user): # 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 as exc: logger.warning( f"Attempt to update unknown shape by {user.name} [{data['shape']['uuid']}]" ) raise exc layer = shape.layer return shape, layer
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_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 move_shape_order(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) shape = Shape.get(uuid=data["shape"]["uuid"]) layer = shape.layer if pr.role != Role.DM and not layer.player_editable: logger.warning( f"{pr.player.name} attempted to move a shape order on a dm layer") return target = data["index"] sign = 1 if target < shape.index else -1 case = Case( None, ( (Shape.index == shape.index, target), ((sign * Shape.index) < (sign * shape.index), (Shape.index + (sign * 1))), ), Shape.index, ) Shape.update(index=case).where(Shape.layer == layer).execute() if layer.player_visible: await sio.emit( "Shape.Order.Set", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, ) else: for csid in game_state.get_sids(player=pr.room.creator, room=pr.room): if csid == sid: continue await sio.emit("Shape.Order.Set", data["shape"], room=csid, namespace=GAME_NS)
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"]) shape.layer = layer shape.save() await sio.emit( "Shape.Layer.Change", data, room=location.get_path(), skip_sid=sid, namespace="/planarally", )
async def _get_shape(data: Dict[str, Any], pr: PlayerRoom): # 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"] floor = pr.active_location.floors.select().where( Floor.name == shape["floor"])[0] layer = floor.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 as exc: logger.warning( f"Attempt to update unknown shape by {pr.player.name} [{data['shape']['uuid']}]" ) raise exc layer = shape.layer data["shape"]["layer"] = layer return shape, layer
async def delete_shape_owner(sid: int, data: Dict[str, Any]): pr: PlayerRoom = game_state.get(sid) try: shape = Shape.get(uuid=data["shape"]) except Shape.DoesNotExist as exc: logger.warning( f"Attempt to delete 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 target_user = User.by_name(data["user"]) if target_user is None: logger.warning( f"Attempt to delete unknown user as owner to shape by {pr.player.name} [{data['user']}]" ) return try: so = (ShapeOwner.delete().where((ShapeOwner.shape == shape) & ( ShapeOwner.user == target_user)).execute()) except Exception as e: logger.warning( f"Could not delete shape-owner relation by {pr.player.name}") await sio.emit( "Shape.Owner.Delete", data, room=pr.active_location.get_path(), skip_sid=sid, 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", )
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: 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 the layer of a shape") return floor = Floor.get(location=pr.active_location, name=data["floor"]) layer = Layer.get(floor=floor, 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 pr.room.players: if room_player.role == Role.DM: continue for psid in game_state.get_sids( player=room_player.player, active_location=pr.active_location): if psid == sid: continue await sio.emit( "Shape.Remove", shape.as_dict(room_player.player, False), room=psid, namespace=GAME_NS, ) 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=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, ) else: for room_player in pr.room.players: is_dm = room_player.role == Role.DM for psid in game_state.get_sids( player=room_player.player, active_location=pr.active_location): if psid == sid: continue if is_dm: await sio.emit( "Shape.Layer.Change", data, room=pr.active_location.get_path(), skip_sid=sid, namespace=GAME_NS, ) elif layer.player_visible: await sio.emit( "Shape.Add", shape.as_dict(room_player.player, False), room=psid, namespace=GAME_NS, )