Пример #1
0
async def set_initiative_value(sid: str, data: ServerSetInitiativeValue):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data)

    if shape is not None and not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to remove initiative of an asset it does not own"
        )
        return

    with db.atomic():
        location_data = Initiative.get(location=pr.active_location)
        json_data = json.loads(location_data.data)

        for initiative in json_data:
            if initiative["shape"] == data["shape"]:
                initiative["initiative"] = data["value"]
                break

        json_data = sort_initiative(json_data, location_data.sort)

        location_data.data = json.dumps(json_data)
        location_data.save()

    await sio.emit(
        "Initiative.Set",
        location_data.as_dict(),
        room=pr.active_location.get_path(),
        namespace=GAME_NS,
    )
Пример #2
0
def get_owner_sids(pr: PlayerRoom,
                   shape: Shape,
                   skip_sid=None) -> Generator[str, None, None]:
    for psid in game_state.get_sids(active_location=pr.active_location,
                                    skip_sid=skip_sid):
        if has_ownership(shape, game_state.get(psid)):
            yield psid
Пример #3
0
async def remove_initiative(sid: str, data: str):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data)

    if shape is not None and not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to remove initiative of an asset it does not own"
        )
        return

    with db.atomic():
        location_data = Initiative.get(location=pr.active_location)
        json_data = json.loads(location_data.data)
        location_data.data = json.dumps([
            initiative for initiative in json_data
            if initiative["shape"] != data
        ])
        location_data.save()

    await sio.emit(
        "Initiative.Remove",
        data,
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #4
0
async def update_initiative_round(sid: str, data: int):
    pr: PlayerRoom = game_state.get(sid)

    location_data = Initiative.get(location=pr.active_location)

    if pr.role != Role.DM:
        json_data = json.loads(location_data.data)
        if not has_ownership(
                Shape.get_or_none(uuid=json_data[location_data.turn]["shape"]),
                pr):
            logger.warning(
                f"{pr.player.name} attempted to advance the initiative tracker"
            )
            return

    with db.atomic():
        location_data.round = data
        location_data.save()

    await sio.emit(
        "Initiative.Round.Update",
        data,
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #5
0
async def update_shape_options(sid: str, data: OptionUpdateList):
    pr: PlayerRoom = game_state.get(sid)

    shapes: List[Tuple[Shape, OptionUpdate]] = []

    for sh in data["options"]:
        shape = Shape.get_or_none(Shape.uuid == sh["uuid"])
        if shape is not None and not has_ownership(shape, pr, movement=True):
            logger.warning(
                f"User {pr.player.name} attempted to change options for a shape it does not own."
            )
            return
        shapes.append((shape, sh))

    if not data["temporary"]:
        with db.atomic():
            for db_shape, data_shape in shapes:
                db_shape.options = data_shape["option"]
                db_shape.save()

    await sio.emit(
        "Shapes.Options.Update",
        data["options"],
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #6
0
async def update_shape_position(sid: str, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    if data["temporary"] and not has_ownership_temp(data["shape"], pr):
        logger.warning(
            f"User {pr.player.name} attempted to move a shape it does not own."
        )
        return

    shape, layer = await _get_shape(data, pr)

    # Overwrite the old data with the new data
    if not data["temporary"]:
        if not has_ownership(shape, pr):
            logger.warning(
                f"User {pr.player.name} attempted to move a shape it does not own."
            )
            return

        with db.atomic():
            # Shape
            update_model_from_dict(shape,
                                   reduce_data_to_model(Shape, data["shape"]))
            shape.save()
            if shape.type_ == "polygon":
                # Subshape
                type_instance = shape.subtype
                # no backrefs on these tables
                type_instance.update_from_dict(data["shape"],
                                               ignore_unknown=True)
                type_instance.save()

    await sync_shape_update(layer, pr, data, sid, shape)
Пример #7
0
async def remove_initiative_effect(sid: str,
                                   data: ServerRemoveInitiativeEffectActor):
    pr: PlayerRoom = game_state.get(sid)

    if not has_ownership(Shape.get_or_none(uuid=data["shape"]), pr):
        logger.warning(
            f"{pr.player.name} attempted to remove an initiative effect")
        return

    location_data = Initiative.get(location=pr.active_location)
    with db.atomic():
        json_data = json.loads(location_data.data)

        for initiative in json_data:
            if initiative["shape"] == data["shape"]:
                initiative["effects"].pop(data["index"])

        location_data.data = json.dumps(json_data)
        location_data.save()

    await sio.emit(
        "Initiative.Effect.Remove",
        data,
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #8
0
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,
    )
Пример #9
0
async def update_shape_positions(sid: str, data: PositionUpdateList):
    pr: PlayerRoom = game_state.get(sid)

    shapes: List[Tuple[Shape, PositionUpdate]] = []

    for sh in data["shapes"]:
        shape = Shape.get_or_none(Shape.uuid == sh["uuid"])
        if shape is not None and not has_ownership(shape, pr, movement=True):
            logger.warning(
                f"User {pr.player.name} attempted to move a shape it does not own."
            )
            return
        shapes.append((shape, sh))

    if not data["temporary"]:
        with db.atomic():
            for db_shape, data_shape in shapes:
                points = data_shape["position"]["points"]
                db_shape.x = points[0][0]
                db_shape.y = points[0][1]
                db_shape.angle = data_shape["position"]["angle"]
                db_shape.save()

                if len(points) > 1:
                    # Subshape
                    type_instance = db_shape.subtype
                    type_instance.set_location(points[1:])

    await sio.emit(
        "Shapes.Position.Update",
        data["shapes"],
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #10
0
async def update_initiative_option(sid: str, data: ServerInitiativeOption):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data["shape"])

    if not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to change initiative of an asset it does not own"
        )
        return

    location_data = Initiative.get_or_none(location=pr.active_location)
    if location_data is None:
        logger.error(
            "Initiative updated for location without initiative tracking")
        return

    json_data = json.loads(location_data.data)

    with db.atomic():
        for i, initiative_data in enumerate(json_data):
            if initiative_data["shape"] == data["shape"]:
                json_data[i][data["option"]] = data["value"]
                break

        location_data.data = json.dumps(json_data)
        location_data.save()

    await sio.emit(
        "Initiative.Option.Set",
        data,
        skip_sid=sid,
        room=pr.active_location.get_path(),
        namespace=GAME_NS,
    )
Пример #11
0
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)
Пример #12
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,
            )
Пример #13
0
async def remove_shapes(sid: str, data: TemporaryShapesList):
    pr: PlayerRoom = game_state.get(sid)

    if data["temporary"]:
        # This stuff is not stored so we cannot do any server side validation /shrug
        for shape in data["uuids"]:
            game_state.remove_temp(sid, shape)
    else:
        # Use the server version of the shapes.
        try:
            shapes: List[Shape] = [
                s for s in Shape.select().where(Shape.uuid << data["uuids"])
            ]
        except Shape.DoesNotExist:
            logger.warning(
                f"Attempt to update unknown shape by {pr.player.name}")
            return

        layer = shapes[0].layer

        group_ids = set()

        for shape in shapes:
            if not has_ownership(shape, pr):
                logger.warning(
                    f"User {pr.player.name} tried to update a shape it does not own."
                )
                return

            if shape.group:
                group_ids.add(shape.group)

            old_index = shape.index
            shape.delete_instance(True)
            Shape.update(index=Shape.index -
                         1).where((Shape.layer == layer)
                                  & (Shape.index >= old_index)).execute()

        for group_id in group_ids:
            await remove_group_if_empty(group_id)

    await sio.emit(
        "Shapes.Remove",
        data["uuids"],
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #14
0
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,
    )
Пример #15
0
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
Пример #16
0
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",
            )
Пример #17
0
async def remove_initiative_effect(sid: str,
                                   data: ServerInitiativeEffectActor):
    pr: PlayerRoom = game_state.get(sid)

    if not has_ownership(Shape.get_or_none(uuid=data["actor"]), pr):
        logger.warning(
            f"{pr.player.name} attempted to remove an initiative effect")
        return

    with db.atomic():
        effect = InitiativeEffect.get(uuid=data["effect"]["uuid"])
        effect.delete_instance()

    await sio.emit(
        "Initiative.Effect.Remove",
        data,
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #18
0
async def update_initiative_turn(sid: str, turn: int):
    pr: PlayerRoom = game_state.get(sid)

    location_data: Initiative = Initiative.get(location=pr.active_location)
    json_data = json.loads(location_data.data)

    if pr.role != Role.DM and not has_ownership(
            Shape.get_or_none(uuid=json_data[location_data.turn]["shape"]),
            pr):
        logger.warning(
            f"{pr.player.name} attempted to advance the initiative tracker")
        return

    with db.atomic():
        nextTurn = turn > location_data.turn
        location_data.turn = turn

        for i, effect in enumerate(json_data[turn]["effects"][-1:]):
            try:
                turns = int(effect["turns"])
                if turns <= 0 and nextTurn:
                    json_data[turn]["effects"].pop(i)
                elif turns > 0 and nextTurn:
                    effect["turns"] = str(turns - 1)
                else:
                    effect["turns"] = str(turns + 1)
            except ValueError:
                # For non-number inputs do not update the effect
                pass

        location_data.data = json.dumps(json_data)

        location_data.save()

    await sio.emit(
        "Initiative.Turn.Update",
        turn,
        room=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #19
0
async def update_initiative_effect(sid: int, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    if not has_ownership(Shape.get_or_none(uuid=data["actor"]), pr):
        logger.warning(
            f"{pr.player.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=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #20
0
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)
Пример #21
0
async def new_initiative_effect(sid: int, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    if not has_ownership(Shape.get_or_none(uuid=data["actor"]), pr):
        logger.warning(
            f"{pr.player.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=pr.active_location.get_path(),
        skip_sid=sid,
        namespace=GAME_NS,
    )
Пример #22
0
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",
    )
Пример #23
0
async def add_initiative(sid: str, data: ServerInitiativeData):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data)

    if shape is not None and not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to add initiative to an asset it does not own"
        )
        return

    with db.atomic():
        location_data, _ = Initiative.get_or_create(
            location=pr.active_location,
            defaults={
                "round": 0,
                "turn": 0,
                "data": "[]"
            })
        json_data = json.loads(location_data.data)

        for initiative in json_data:
            if initiative["shape"] == data["shape"]:
                initiative.update(**data)
                break
        else:
            json_data.append(data)

        location_data.data = json.dumps(json_data)
        location_data.save()

    await sio.emit(
        "Initiative.Set",
        location_data.as_dict(),
        room=pr.active_location.get_path(),
        namespace=GAME_NS,
    )
Пример #24
0
async def remove_initiative(sid: int, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data)

    if shape is not None and not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to remove initiative of an asset it does not own"
        )
        return

    initiative = Initiative.get_or_none(uuid=data)
    location_data = InitiativeLocationData.get_or_none(
        location=pr.active_location)

    if initiative:
        with db.atomic():
            Initiative.update(
                index=Initiative.index -
                1).where((Initiative.location_data == location_data)
                         & (Initiative.index >= initiative.index))
            initiative.delete_instance(True)

        await send_client_initiatives(pr)
Пример #25
0
async def update_shape(sid: int, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    if data["temporary"] and not has_ownership_temp(data["shape"], pr):
        logger.warning(
            f"User {pr.player.name} tried to update a shape it does not own.")
        return

    # todo clean up this mess that deals with both temporary and non temporary shapes
    shape, layer = await _get_shape(data, pr)

    # Overwrite the old data with the new data
    if not data["temporary"]:
        if not has_ownership(shape, pr):
            logger.warning(
                f"User {pr.player.name} tried to update a shape it does not own."
            )
            return
        with db.atomic():
            # Shape
            update_model_from_dict(shape,
                                   reduce_data_to_model(Shape, data["shape"]))
            shape.save()
            # Subshape
            type_instance = shape.subtype
            # no backrefs on these tables
            type_instance.update_from_dict(data["shape"], ignore_unknown=True)
            type_instance.save()
            # Trackers
            old_trackers = {tracker.uuid for tracker in shape.trackers}
            new_trackers = {
                tracker["uuid"]
                for tracker in data["shape"]["trackers"]
            }
            for tracker_id in old_trackers | new_trackers:
                remove = tracker_id in old_trackers - new_trackers
                if not remove:
                    tracker = next(tr for tr in data["shape"]["trackers"]
                                   if tr["uuid"] == tracker_id)
                    reduced = reduce_data_to_model(Tracker, tracker)
                    reduced["shape"] = shape
                if tracker_id in new_trackers - old_trackers:
                    Tracker.create(**reduced)
                    continue
                tracker_db = Tracker.get(uuid=tracker_id)
                if remove:
                    tracker_db.delete_instance(True)
                else:
                    update_model_from_dict(tracker_db, reduced)
                    tracker_db.save()

            # Auras
            old_auras = {aura.uuid for aura in shape.auras}
            new_auras = {aura["uuid"] for aura in data["shape"]["auras"]}
            for aura_id in old_auras | new_auras:
                remove = aura_id in old_auras - new_auras
                if not remove:
                    aura = next(au for au in data["shape"]["auras"]
                                if au["uuid"] == aura_id)
                    reduced = reduce_data_to_model(Aura, aura)
                    reduced["shape"] = shape
                if aura_id in new_auras - old_auras:
                    Aura.create(**reduced)
                    continue
                aura_db = Aura.get_or_none(uuid=aura_id)
                if remove:
                    aura_db.delete_instance(True)
                else:
                    update_model_from_dict(aura_db, reduced)
                    aura_db.save()
            # Labels
            for label in data["shape"]["labels"]:
                label_db = Label.get_or_none(uuid=label["uuid"])
                reduced = reduce_data_to_model(Label, label)
                reduced["user"] = User.by_name(reduced["user"])
                if label_db:
                    update_model_from_dict(label_db, reduced)
                    label_db.save()
                else:
                    Label.create(**reduced)
            old_labels = {
                shape_label.label.uuid
                for shape_label in shape.labels
            }
            new_labels = set(label["uuid"]
                             for label in data["shape"]["labels"])
            for label in old_labels ^ new_labels:
                if label == "":
                    continue
                if label in new_labels:
                    ShapeLabel.create(shape=shape, label=Label.get(uuid=label))
                else:
                    ShapeLabel.get(label=Label.get(uuid=label),
                                   shape=shape).delete_instance(True)

    await sync_shape_update(layer, pr, data, sid, shape)
Пример #26
0
async def update_initiative(sid: int, data: Dict[str, Any]):
    pr: PlayerRoom = game_state.get(sid)

    shape = Shape.get_or_none(uuid=data["uuid"])

    if not has_ownership(shape, pr):
        logger.warning(
            f"{pr.player.name} attempted to change initiative of an asset it does not own"
        )
        return

    location_data = InitiativeLocationData.get_or_none(
        location=pr.active_location)
    if location_data is None:
        location_data = InitiativeLocationData.create(
            location=pr.active_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)
    # Update initiative
    else:
        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(pr)