Esempio n. 1
0
async def new_initiative_effect(sid, data):
    sid_data = state.sid_map[sid]
    user = sid_data["user"]
    room = sid_data["room"]
    location = sid_data["location"]

    if room.creator != user and not ShapeOwner.get_or_none(shape=shape,
                                                           user=user):
        logger.warning(
            f"{user.name} attempted to create a new initiative effect")
        return

    InitiativeEffect.create(
        initiative=data["actor"],
        uuid=data["effect"]["uuid"],
        name=data["effect"]["name"],
        turns=data["effect"]["turns"],
    )

    await sio.emit(
        "Initiative.Effect.New",
        data,
        room=location.get_path(),
        skip_sid=sid,
        namespace="/planarally",
    )
Esempio n. 2
0
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")
Esempio n. 3
0
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,
            )
Esempio n. 4
0
async def update_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 update owner of unknown shape by {pr.player.name} [{data['shape']}]"
        )
        raise exc

    if not ShapeOwner.get_or_none(shape=shape, user=pr.player):
        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}"
        )

    so.shape = shape
    so.user = target_user
    so.edit_access = data["edit_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="/planarally",
    )
Esempio n. 5
0
async def has_ownership(layer, room, data, user, shape):
    # 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 False

        if data["temporary"]:
            if user.name not in shape["owners"]:
                logger.warning(
                    f"{user.name} attempted to move asset it does not own")
                return False
        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 False
    return True
Esempio n. 6
0
async def update_initiative_effect(sid, data):
    sid_data = state.sid_map[sid]
    user = sid_data["user"]
    room = sid_data["room"]
    location = sid_data["location"]

    if room.creator != user and not ShapeOwner.get_or_none(shape=shape,
                                                           user=user):
        logger.warning(f"{user.name} attempted to update an initiative effect")
        return

    with db.atomic():
        effect = InitiativeEffect.get(uuid=data["effect"]["uuid"])
        update_model_from_dict(
            effect, reduce_data_to_model(InitiativeEffect, data["effect"]))
        effect.save()

    await sio.emit(
        "Initiative.Effect.Update",
        data,
        room=location.get_path(),
        skip_sid=sid,
        namespace="/planarally",
    )
Esempio n. 7
0
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")
Esempio n. 8
0
async def update_initiative(sid, data):
    sid_data = state.sid_map[sid]
    user = sid_data["user"]
    room = sid_data["room"]
    location = sid_data["location"]

    shape = Shape.get_or_none(uuid=data["uuid"])
    owner = ShapeOwner.get_or_none(shape=shape, user=user) is not None

    if room.creator != user and not owner:
        logger.warning(
            f"{user.name} attempted to change initiative of an asset it does not own"
        )
        return

    used_to_be_visible = False

    location_data = InitiativeLocationData.get_or_none(location=location)
    if location_data is None:
        location_data = InitiativeLocationData.create(location=location,
                                                      turn=data["uuid"],
                                                      round=1)
    initiatives = Initiative.select().where(
        Initiative.location_data == location_data)

    initiative = Initiative.get_or_none(uuid=data["uuid"])

    # Create new initiative
    if initiative is None:
        with db.atomic():
            # Update indices
            try:
                index = (initiatives.where(
                    Initiative.initiative >= data["initiative"]).order_by(
                        -Initiative.index)[0].index + 1)
            except IndexError:
                index = 0
            else:
                Initiative.update(
                    index=Initiative.index +
                    1).where((Initiative.location_data == location_data)
                             & (Initiative.index >= index))
            # Create model instance
            initiative = dict_to_model(Initiative,
                                       reduce_data_to_model(Initiative, data))
            initiative.location_data = location_data
            initiative.index = index
            initiative.save(force_insert=True)
    # Remove initiative
    elif "initiative" not in data:
        with db.atomic():
            Initiative.update(
                index=Initiative.index -
                1).where((Initiative.location_data == location_data)
                         & (Initiative.index >= initiative.index))
            initiative.delete_instance(True)
    # Update initiative
    else:
        used_to_be_visible = initiative.visible

        with db.atomic():
            if data["initiative"] != initiative.initiative:
                # Update indices
                old_index = initiative.index
                try:
                    new_index = (initiatives.where(
                        Initiative.initiative >= data["initiative"]).order_by(
                            -Initiative.index)[0].index)
                except IndexError:
                    new_index = 0
                else:
                    if new_index < old_index:
                        new_index += 1
                if old_index != new_index:
                    # SIGN=1 IF old_index > new_index WHICH MEANS the initiative is increased
                    # SIGN=-1 IF old_index < new_index WHICH MEANS the initiative is decreased
                    sign = (old_index - new_index) // abs(old_index -
                                                          new_index)
                    indices = [0, old_index, new_index]
                    update = Initiative.update(
                        index=Initiative.index +
                        sign).where((Initiative.location_data == location_data)
                                    & (Initiative.index <= indices[sign])
                                    & (Initiative.index >= indices[-sign]))
                    update.execute()
                data["index"] = new_index
            # Update model instance
            update_model_from_dict(initiative,
                                   reduce_data_to_model(Initiative, data))
            initiative.save()

    data["index"] = initiative.index

    await send_client_initiatives(room, location)