Beispiel #1
0
def _change_password(sio: ServerApp, session: GameSession, password: str):
    _verify_has_admin(sio, session.id, None)

    session.password = _hash_password(password)
    logger().info(f"{_describe_session(session)}: Changing password.")
    session.save()
    _add_audit_entry(sio, session, f"Changed password")
Beispiel #2
0
def _finish_session(sio: ServerApp, session: GameSession):
    _verify_has_admin(sio, session.id, None)
    if session.state != GameSessionState.IN_PROGRESS:
        raise InvalidAction("Session is not in progress")

    session.state = GameSessionState.FINISHED
    session.save()
Beispiel #3
0
def _finish_session(sio: ServerApp, session: GameSession):
    _verify_has_admin(sio, session.id, None)
    if session.state != GameSessionState.IN_PROGRESS:
        raise InvalidAction("Session is not in progress")

    session.state = GameSessionState.FINISHED
    logger().info(f"{_describe_session(session)}: Finishing session.")
    session.save()
    _add_audit_entry(sio, session, f"Finished session")
Beispiel #4
0
def _change_title(sio: ServerApp, session: GameSession, title: str):
    _verify_has_admin(sio, session.id, None)

    old_name = session.name
    session.name = title
    logger().info(
        f"{_describe_session(session)}: Changed name from {old_name}.")
    session.save()
    _add_audit_entry(sio, session, f"Changed name from {old_name} to {title}")
Beispiel #5
0
def _duplicate_session(sio: ServerApp, session: GameSession, new_title: str):
    _verify_has_admin(sio, session.id, None)

    current_user = sio.get_current_user()
    _add_audit_entry(sio, session, f"Duplicated session as {new_title}")

    with database.db.atomic():
        new_session: GameSession = GameSession.create(
            name=new_title,
            password=session.password,
            creator=current_user,
            layout_description_json=session.layout_description_json,
            seed_hash=session.seed_hash,
            dev_features=session.dev_features,
        )
        for preset in session.presets:
            assert isinstance(preset, GameSessionPreset)
            GameSessionPreset.create(
                session=new_session,
                row=preset.row,
                preset=preset.preset,
            )
        GameSessionMembership.create(
            user=current_user,
            session=new_session,
            row=None,
            admin=True,
            connection_state="Offline",
        )
        GameSessionAudit.create(
            session=new_session,
            user=current_user,
            message=f"Duplicated from {session.name}",
        )
Beispiel #6
0
def _update_layout_generation(sio: ServerApp, session: GameSession,
                              active: bool):
    _verify_has_admin(sio, session.id, None)
    _verify_in_setup(session)

    if active:
        if session.generation_in_progress is None:
            session.generation_in_progress = sio.get_current_user()
        else:
            raise InvalidAction(
                f"Generation already in progress by {session.generation_in_progress.name}."
            )
    else:
        session.generation_in_progress = None

    session.save()
Beispiel #7
0
def _start_session(sio: ServerApp, session: GameSession):
    _verify_has_admin(sio, session.id, None)
    _verify_in_setup(session)
    if session.layout_description_json is None:
        raise InvalidAction("Unable to start session, no game is available.")

    num_players = GameSessionMembership.select().where(
        GameSessionMembership.session == session,
        GameSessionMembership.row != None).count()
    expected_players = session.num_rows
    if num_players != expected_players:
        raise InvalidAction(
            f"Unable to start session, there are {num_players} but expected {expected_players} "
            f"({session.num_rows} x {session.num_teams}).")

    session.state = GameSessionState.IN_PROGRESS
    session.save()
Beispiel #8
0
def _change_layout_description(sio: ServerApp, session: GameSession,
                               description_json: Optional[dict]):
    _verify_has_admin(sio, session.id, None)
    _verify_in_setup(session)
    rows_to_update = []

    if description_json is None:
        description = None
    else:
        if session.generation_in_progress != sio.get_current_user():
            if session.generation_in_progress is None:
                raise InvalidAction(f"Not waiting for a layout.")
            else:
                raise InvalidAction(
                    f"Waiting for a layout from {session.generation_in_progress.name}."
                )

        _verify_no_layout_description(session)
        description = LayoutDescription.from_json_dict(description_json)
        if description.player_count != session.num_rows:
            raise InvalidAction(
                f"Description is for a {description.player_count} players,"
                f" while the session is for {session.num_rows}.")

        for permalink_preset, preset_row in zip(description.all_presets,
                                                session.presets):
            preset_row = typing.cast(GameSessionPreset, preset_row)
            if _get_preset(json.loads(
                    preset_row.preset)).get_preset() != permalink_preset:
                preset = VersionedPreset.with_preset(permalink_preset)
                if preset.game not in session.allowed_games:
                    raise InvalidAction(f"{preset.game} preset not allowed.")
                preset_row.preset = json.dumps(preset.as_json)
                rows_to_update.append(preset_row)

    with database.db.atomic():
        for preset_row in rows_to_update:
            preset_row.save()

        session.generation_in_progress = None
        session.layout_description = description
        session.save()
        _add_audit_entry(
            sio, session, "Removed generated game" if description is None else
            f"Set game to {description.shareable_word_hash}")
Beispiel #9
0
    def admin_session(user, session_id):
        session: GameSession = GameSession.get_by_id(session_id)

        rows = []
        presets = session.all_presets

        for player in session.players:
            player = typing.cast(GameSessionMembership, player)
            if player.is_observer:
                rows.append([
                    player.effective_name,
                    "Observer",
                    "",
                ])
            else:
                preset = presets[player.row]
                db = default_database.resource_database_for(preset.game)

                inventory = []
                if player.inventory is not None:
                    try:
                        parsed_inventory: list[dict] = BinaryInventory.parse(
                            player.inventory)
                    except construct.ConstructError:
                        # Handle old format in an adhoc way
                        # TODO 4.3: remove this code and purge all old inventory from the server db
                        items_by_id: dict[int, ItemResourceInfo] = {
                            item.extra["item_id"]: item
                            for item in db.item
                        }
                        parsed_inventory = [{
                            "name":
                            items_by_id[item["index"]].short_name,
                            **item,
                        } for item in OldBinaryInventory.parse(
                            player.inventory)]

                    for item in parsed_inventory:
                        if item["amount"] + item["capacity"] > 0:
                            inventory.append("{} x{}/{}".format(
                                db.get_item(item["name"]).long_name,
                                item["amount"], item["capacity"]))

                rows.append([
                    player.effective_name,
                    preset.name,
                    ", ".join(inventory),
                ])

        header = ["Name", "Preset", "Inventory"]

        return "<table border='1'><tr>{}</tr>{}</table>".format(
            "".join(f"<th>{h}</th>" for h in header),
            "".join("<tr>{}</tr>".format("".join(f"<td>{h}</td>" for h in r))
                    for r in rows),
        )
Beispiel #10
0
def _change_layout_description(sio: ServerApp, session: GameSession,
                               description_json: Optional[dict]):
    _verify_has_admin(sio, session.id, None)
    _verify_in_setup(session)
    rows_to_update = []

    if description_json is None:
        description = None
    else:
        if session.generation_in_progress != sio.get_current_user():
            if session.generation_in_progress is None:
                raise InvalidAction(f"Not waiting for a layout.")
            else:
                raise InvalidAction(
                    f"Waiting for a layout from {session.generation_in_progress.name}."
                )

        _verify_no_layout_description(session)
        description = LayoutDescription.from_json_dict(description_json)
        permalink = description.permalink
        if permalink.player_count != session.num_rows:
            raise InvalidAction(
                f"Description is for a {permalink.player_count} players,"
                f" while the session is for {session.num_rows}.")

        for permalink_preset, preset_row in zip(permalink.presets.values(),
                                                session.presets):
            preset_row = typing.cast(GameSessionPreset, preset_row)
            if _get_preset(json.loads(
                    preset_row.preset)).get_preset() != permalink_preset:
                preset = VersionedPreset.with_preset(permalink_preset)
                if preset.game != RandovaniaGame.PRIME2:
                    raise InvalidAction("Only Prime 2 presets allowed.")
                preset_row.preset = json.dumps(preset.as_json)
                rows_to_update.append(preset_row)

    with database.db.atomic():
        for preset_row in rows_to_update:
            preset_row.save()

        session.generation_in_progress = None
        session.layout_description = description
        session.save()
Beispiel #11
0
def game_session_request_update(sio: ServerApp, session_id: int):
    current_user = sio.get_current_user()
    session: GameSession = GameSession.get_by_id(session_id)
    membership = GameSessionMembership.get_by_ids(current_user.id, session_id)

    _emit_session_meta_update(session)
    if session.layout_description is not None:
        _emit_session_actions_update(session)

    if not membership.is_observer and session.state != GameSessionState.SETUP:
        _emit_game_session_pickups_update(sio, membership)

    _emit_session_audit_update(session)
Beispiel #12
0
    def admin_sessions(user):
        lines = []
        for session in GameSession.select().order_by(
                GameSession.creation_date):
            lines.append(
                "<tr><td><a href='{}'>{}</a></td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>"
                .format(
                    flask.url_for('admin_session', session_id=session.id),
                    session.name,
                    session.creator.name,
                    session.creation_date,
                    session.state,
                    len(session.players),
                ))

        return (
            "<table border='1'>"
            "<tr><th>Name</th><th>Creator</th><th>Creation Date</th><th>State</th><th>Num Players</th></tr>"
            "{}</table>").format("".join(lines))
Beispiel #13
0
    def admin_sessions(user):
        paginated_query = flask_utils.PaginatedQuery(
            GameSession.select().order_by(GameSession.creation_date.desc()),
            paginate_by=20,
            check_bounds=True,
        )

        lines = []
        for session in paginated_query.get_object_list():
            lines.append(
                "<tr><td><a href='{}'>{}</a></td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>"
                .format(
                    flask.url_for('admin_session', session_id=session.id),
                    session.name,
                    session.creator.name,
                    session.creation_date,
                    session.state,
                    len(session.players),
                ))

        page = paginated_query.get_page()
        previous = "Previous"
        if page > 1:
            previous = "<a href='{}'>Previous</a>".format(
                flask.url_for(".admin_sessions", page=page - 1))

        next_link = "Next"
        if page < paginated_query.get_page_count():
            next_link = "<a href='{}'>Next</a>".format(
                flask.url_for(".admin_sessions", page=page + 1))

        return (
            "<table border='1'>"
            "<tr><th>Name</th><th>Creator</th><th>Creation Date</th><th>State</th><th>Num Players</th></tr>"
            "{content}</table>Page {page} of {num_pages}. {previous} / {next}."
        ).format(
            content="".join(lines),
            page=page,
            num_pages=paginated_query.get_page_count(),
            previous=previous,
            next=next_link,
        )
Beispiel #14
0
def create_game_session(sio: ServerApp, session_name: str):
    current_user = sio.get_current_user()

    with database.db.atomic():
        new_session = GameSession.create(
            name=session_name,
            password=None,
            creator=current_user,
        )
        GameSessionPreset.create(
            session=new_session,
            row=0,
            preset=json.dumps(PresetManager(None).default_preset.as_json))
        membership = GameSessionMembership.create(user=sio.get_current_user(),
                                                  session=new_session,
                                                  row=0,
                                                  admin=True)

    sio.join_game_session(membership)
    return new_session.create_session_entry()
Beispiel #15
0
def join_game_session(sio: ServerApp, session_id: int,
                      password: Optional[str]):
    session = GameSession.get_by_id(session_id)

    if session.password is not None:
        if password is None or _hash_password(password) != session.password:
            raise WrongPassword()
    elif password is not None:
        raise WrongPassword()

    membership = GameSessionMembership.get_or_create(
        user=sio.get_current_user(),
        session=session,
        defaults={
            "row": None,
            "admin": False
        })[0]

    _emit_session_update(session)
    sio.join_game_session(membership)

    return session.create_session_entry()
Beispiel #16
0
    def admin_session(user, session_id):
        session: GameSession = GameSession.get_by_id(session_id)

        rows = []
        presets = session.all_presets

        for player in session.players:
            player = typing.cast(GameSessionMembership, player)
            if player.is_observer:
                rows.append([
                    player.effective_name,
                    "Observer",
                    "",
                ])
            else:
                preset = presets[player.row]
                db = default_database.resource_database_for(preset.game)

                inventory = []
                for item in json.loads(player.inventory):
                    if item["amount"] + item["capacity"] > 0:
                        inventory.append("{} x{}/{}".format(
                            db.get_item(item["index"]).long_name,
                            item["amount"], item["capacity"]))

                rows.append([
                    player.effective_name,
                    preset.name,
                    ", ".join(inventory),
                ])

        header = ["Name", "Preset", "Inventory"]

        return "<table border='1'><tr>{}</tr>{}</table>".format(
            "".join(f"<th>{h}</th>" for h in header),
            "".join("<tr>{}</tr>".format("".join(f"<td>{h}</td>" for h in r))
                    for r in rows),
        )
Beispiel #17
0
def _emit_session_meta_update(session: GameSession):
    flask_socketio.emit("game_session_meta_update",
                        session.create_session_entry(),
                        room=f"game-session-{session.id}",
                        namespace="/")
Beispiel #18
0
def list_game_sessions(sio: ServerApp, limit: Optional[int]):
    return [
        session.create_list_entry() for session in
        GameSession.select().order_by(GameSession.id.desc()).limit(limit)
    ]
Beispiel #19
0
def _change_password(sio: ServerApp, session: GameSession, password: str):
    _verify_has_admin(sio, session.id, None)

    session.password = _hash_password(password)
    session.save()
Beispiel #20
0
def _emit_session_audit_update(session: GameSession):
    flask_socketio.emit("game_session_audit_update",
                        session.get_audit_log(),
                        room=f"game-session-{session.id}",
                        namespace="/")
Beispiel #21
0
def _emit_session_actions_update(session: GameSession):
    flask_socketio.emit("game_session_actions_update",
                        session.describe_actions(),
                        room=f"game-session-{session.id}",
                        namespace="/")
Beispiel #22
0
def list_game_sessions(sio: ServerApp):
    return [session.create_list_entry() for session in GameSession.select()]
Beispiel #23
0
def _change_password(sio: ServerApp, session: GameSession, password: str):
    _verify_has_admin(sio, session.id, None)

    session.password = _hash_password(password)
    logger().info(f"Session {session.id}: Changing password.")
    session.save()