diff --git a/cogs/gameplay.py b/cogs/gameplay.py index 05cb06a..e0772f7 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -13,7 +13,7 @@ from in_game import ai_manager from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check from in_game.data_cache import get_pd_team from in_game.gameplay_models import Lineup, Session, engine, get_player, player_description, select, Game, get_team -from in_game.gameplay_queries import get_channel_game_or_none, get_games_by_team_id +from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team class Gameplay(commands.Cog): @@ -86,7 +86,7 @@ class Gameplay(commands.Cog): ai_team = away_team if away_team.is_ai else home_team human_team = away_team if home_team.is_ai else away_team - conflict_games = get_games_by_team_id(session, team_id=human_team.id) + conflict_games = get_active_games_by_team(session, team_id=human_team.id) if len(conflict_games) > 0: await interaction.edit_original_response( content=f'Ope. The {human_team.sname} are already playing over in {interaction.guild.get_channel(conflict_games[0].channel_id).mention}' diff --git a/in_game/gameplay_models.py b/in_game/gameplay_models.py index 792fd65..5895634 100644 --- a/in_game/gameplay_models.py +++ b/in_game/gameplay_models.py @@ -1,10 +1,10 @@ import datetime import logging +import discord from sqlmodel import Session, SQLModel, create_engine, select, or_, Field, Relationship from sqlalchemy import func -from api_calls import db_get -from helpers import PD_SEASON +from api_calls import db_get, db_post sqlite_url = 'sqlite:///storage/gameplay.db' @@ -41,13 +41,25 @@ class Game(SQLModel, table=True): game_type: str | None = Field(default=None) cardset_links: list[GameCardsetLink] = Relationship(back_populates='game') - lineups: list['Lineup'] = Relationship(back_populates='game') + lineups: list['Lineup'] = Relationship(back_populates='game', cascade_delete=True) + + @property + def cardset_param_string(self) -> str: + pri_cardsets = '' + back_cardsets = '' + for link in self.cardset_links: + if link.priority == 1: + pri_cardsets += f'&cardset_id={link.cardset_id}' + else: + back_cardsets += f'&backup_cardset_id={link.cardset_id}' + return f'{pri_cardsets}{back_cardsets}' # @property # def game_prop(self) -> str: # return f'Game {self.id} / Week {self.week_num} / Type {self.game_type}' + class CardsetBase(SQLModel): id: int | None = Field(default=None, primary_key=True) name: str @@ -59,22 +71,6 @@ class Cardset(CardsetBase, table=True): players: list['Player'] = Relationship(back_populates='cardset') -class Lineup(SQLModel, table=True): - id: int | None = Field(default=None, primary_key=True) - team_id: int - player_id: int - card_id: int - position: str = Field(index=True) - batting_order: int = Field(index=True) - after_play: int | None = Field(default=0) - replacing_id: int | None = Field(default=None) - active: bool = Field(default=True, index=True) - is_fatigued: bool | None = Field(default=None) - - game_id: int = Field(foreign_key='game.id', index=True) - game: Game = Relationship(back_populates='lineups') - - class TeamBase(SQLModel): id: int = Field(primary_key=True) abbrev: str = Field(index=True) @@ -101,7 +97,8 @@ class TeamBase(SQLModel): class Team(TeamBase, table=True): - pass + cards: list['Card'] = Relationship(back_populates='team', cascade_delete=True) + lineups: list['Lineup'] = Relationship(back_populates='team', cascade_delete=True) async def get_team( @@ -148,13 +145,13 @@ async def get_team( return cache_team(t_query) elif gm_id is not None: - t_query = await db_get('teams', params=[('season', PD_SEASON), ('gm_id', gm_id)]) + t_query = await db_get('teams', params=[('gm_id', gm_id)]) if t_query['count'] != 0: for team in [x for x in t_query['teams'] if 'gauntlet' not in x['abbrev'].lower()]: return cache_team(team) elif team_abbrev is not None: - t_query = await db_get('teams', params=[('season', PD_SEASON), ('abbrev', team_abbrev)]) + t_query = await db_get('teams', params=[('abbrev', team_abbrev)]) if t_query['count'] != 0: for team in [x for x in t_query['teams'] if 'gauntlet' not in x['abbrev'].lower()]: return cache_team(team) @@ -196,6 +193,84 @@ class PlayerBase(SQLModel): class Player(PlayerBase, table=True): cardset: Cardset = Relationship(back_populates='players') + cards: list['Card'] = Relationship(back_populates='player', cascade_delete=True) + lineups: list['Lineup'] = Relationship(back_populates='player', cascade_delete=True) + + +class CardBase(SQLModel): + id: int | None = Field(default=None, primary_key=True) + player_id: int = Field(foreign_key='player.id', index=True, ondelete='CASCADE') + team_id: int = Field(foreign_key='team.id', index=True, ondelete='CASCADE') + variant: int | None = Field(default=0) + created: datetime.datetime | None = Field(default=datetime.datetime.now()) + +class Card(CardBase, table=True): + player: Player = Relationship(back_populates='cards') + team: Team = Relationship(back_populates='cards',) + lineups: list['Lineup'] = Relationship(back_populates='card', cascade_delete=True) + + +async def get_or_create_ai_card(session: Session, player: Player, team: Team) -> Card: + if not team.is_ai: + err = f'Cannot create AI cards for human teams' + logging.error(f'gameplay_models - get_or_create_ai_card: {err}') + raise TypeError(err) + + async def pull_card(player, team): + c_query = await db_get('cards', params=[('team_id', team.id), ('player_id', player.id)]) + if c_query['count'] > 0: + valid_card = CardBase.model_validate(c_query['cards'][0], from_attributes=True) + db_card = Card.model_validate(valid_card) + session.add(db_card) + session.commit() + session.refresh(db_card) + return db_card + else: + return None + + this_card = await pull_card(player, team) + if this_card is not None: + return this_card + + logging.info(f'gameplay_models - get_or_create_ai_card: creating {player.description} {player.name} card for {team.abbrev}') + + await db_post( + 'cards', + payload={'cards': [ + {'player_id': player.id, 'team_id': team.id, 'pack_id': 1} + ]} + ) + + this_card = await pull_card(player, team) + if this_card is not None: + return this_card + + err = f'Could not create {player.name} card for {team.abbrev}' + logging.error(f'gameplay_models - get_or_create_ai_card - {err}') + raise LookupError(err) + + + +class Lineup(SQLModel, table=True): + id: int | None = Field(default=None, primary_key=True) + position: str = Field(index=True) + batting_order: int = Field(index=True) + after_play: int | None = Field(default=0) + replacing_id: int | None = Field(default=None) + active: bool = Field(default=True, index=True) + is_fatigued: bool | None = Field(default=None) + + game_id: int = Field(foreign_key='game.id', index=True, ondelete='CASCADE') + game: Game = Relationship(back_populates='lineups') + + team_id: int = Field(foreign_key='team.id', index=True, ondelete='CASCADE') + team: Team = Relationship(back_populates='lineups') + + player_id: int = Field(foreign_key='player.id', index=True, ondelete='CASCADE') + player: Player = Relationship(back_populates='lineups') + + card_id: int = Field(foreign_key='card.id', index=True, ondelete='CASCADE') + card: Card = Relationship(back_populates='lineups') def player_description(player: Player = None, player_dict: dict = None) -> str: diff --git a/in_game/gameplay_queries.py b/in_game/gameplay_queries.py index 52732b3..48fe489 100644 --- a/in_game/gameplay_queries.py +++ b/in_game/gameplay_queries.py @@ -17,5 +17,5 @@ def get_channel_game_or_none(session: Session, channel_id: int) -> Game | None: return all_games[0] -def get_games_by_team_id(session: Session, team_id: int) -> list[Game]: +def get_active_games_by_team(session: Session, team_id: int) -> list[Game]: return session.exec(select(Game).where(Game.active, or_(Game.away_team_id == team_id, Game.home_team_id == team_id))).all() \ No newline at end of file diff --git a/tests/gameplay_models/factory.py b/tests/gameplay_models/factory.py index 0a71c9d..d0ca719 100644 --- a/tests/gameplay_models/factory.py +++ b/tests/gameplay_models/factory.py @@ -14,7 +14,51 @@ def session_fixture(): ) SQLModel.metadata.create_all(engine) with Session(engine) as session: - yield session + team_1 = Team( + id=31, abbrev='NCB', sname='CornBelters', lname='Normal CornBelters', gmid=1234, gmname='Cal', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='006900', season=7, event=False, career=1234, ranking=1337, has_guide=True, is_ai=False + ) + team_2 = Team( + id=400, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', gmid=5678, gmname='Evil Cal', gsheet='https://i.postimg.cc/HjDc8bBF/blackbears-transparent.png', wallet=350, team_value=420, collection_value=169, color='6699FF', season=7, event=False, career=2, ranking=969, has_guide=False, is_ai=False + ) + team_3 = Team( + id=69, abbrev='NCB3', sname='CornBelters', lname='Normal CornBelters', gmid=1234, gmname='Cal', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='006900', season=7, event=False, career=1234, ranking=1337, has_guide=True, is_ai=False + ) + team_4 = Team( + id=420, abbrev='WV4', sname='Black Bears', lname='West Virginia Black Bears', gmid=5678, gmname='Evil Cal', gsheet='https://i.postimg.cc/HjDc8bBF/blackbears-transparent.png', wallet=350, team_value=420, collection_value=169, color='6699FF', season=7, event=False, career=2, ranking=969, has_guide=False, is_ai=False + ) + incomplete_team = Team( + id=446, abbrev='CLS', sname='Macho Men', lname='Columbus Macho Men', gmid=181818, gmname='Mason Socc', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='https://i.postimg.cc/8kLZCYXh/S10CLS.png', season=7, event=False, career=0 + ) + old_cache_team = Team( + id=3, abbrev='BAL', sname='Orioles', lname='Baltimore Orioles', gmid=181818, gmname='Brandon Hyde', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='https://i.postimg.cc/8kLZCYXh/S10CLS.png', season=7, event=False, career=0, ranking=500, has_guide=False, is_ai=False, created=datetime.datetime.today() - datetime.timedelta(days=60) + ) + + session.add(team_1) + session.add(team_2) + session.add(team_3) + session.add(team_4) + # session.add(incomplete_team) + session.add(old_cache_team) + session.commit() + + game_1 = Game(away_team_id=1, home_team_id=2, channel_id=1234, season=9) + game_2 = Game(away_team_id=4, home_team_id=3, channel_id=5678, season=9, active=False, is_pd=True, ranked=True, week_num=6, game_num=9, away_roster_id=69, home_roster_id=420, first_message=12345678, ai_team='home', game_type='minor-league') + game_3 = Game(away_team_id=3, home_team_id=4, channel_id=5678, season=9, active=True, is_pd=True, ranked=True, week_num=6, game_num=10, away_roster_id=69, home_roster_id=420, first_message=34567890, ai_team='home', game_type='minor-league') + + session.add(game_1) + session.add(game_2) + session.add(game_3) + session.commit() + + # all_lineups = [] + # for team in [team_1, team_2]: + # for (order, pos) in [(1, 'C'), (2, '1B'), (3, '2B'), (4, '3B'), (5, 'SS'), (6, 'LF'), (7, 'CF'), (8, 'RF'), (9, 'DH'), (10, 'P')]: + # all_lineups.append(Lineup(team_id=team, card_id=order, player_id=68+order, position=pos, batting_order=order, game=game_1)) + # for team in [team_3, team_4]: + # for (order, pos) in [(1, 'C'), (2, '1B'), (3, '2B'), (4, '3B'), (5, 'SS'), (6, 'LF'), (7, 'CF'), (8, 'RF'), (9, 'DH'), (10, 'P')]: + # all_lineups.append(Lineup(team_id=team, card_id=order, player_id=100+order, position=pos, batting_order=order, game=game_3)) + + yield session @pytest.fixture(name='new_games') diff --git a/tests/gameplay_models/test_game_model.py b/tests/gameplay_models/test_game_model.py index ec48c55..acd1484 100644 --- a/tests/gameplay_models/test_game_model.py +++ b/tests/gameplay_models/test_game_model.py @@ -1,17 +1,15 @@ import pytest +from sqlalchemy import delete from sqlmodel import Session from in_game.gameplay_models import Game, select -from in_game.gameplay_queries import get_games_by_channel, get_channel_game_or_none, get_games_by_team_id +from in_game.gameplay_queries import get_games_by_channel, get_channel_game_or_none, get_active_games_by_team from factory import session_fixture, new_games_fixture def test_create_game(session: Session, new_games: list[Game]): - game_1 = new_games[0] - game_2 = new_games[1] - session.add(game_1) - session.add(game_2) - session.commit() + game_1 = session.get(Game, 1) + game_2 = session.get(Game, 2) assert game_1.away_team_id == 1 assert game_1.home_team_id == 2 @@ -39,25 +37,23 @@ def test_create_game(session: Session, new_games: list[Game]): assert game_2.game_type == 'minor-league' -def test_select_all_empty(session: Session): +def test_select_all(session: Session): games = session.exec(select(Game)).all() + assert len(games) == 3 + session.execute(delete(Game)) + session.commit() + + games = session.exec(select(Game)).all() assert len(games) == 0 def test_games_by_channel(session: Session, new_games: list[Game]): - game_1 = new_games[0] - game_2 = new_games[1] - game_3 = new_games[2] - session.add(game_1) - session.add(game_2) - session.add(game_3) - session.commit() - assert get_channel_game_or_none(session, 1234) is not None assert get_channel_game_or_none(session, 5678) is not None assert get_channel_game_or_none(session, 69) is None + game_2 = session.get(Game, 2) game_2.active = True session.add(game_2) session.commit() @@ -67,6 +63,7 @@ def test_games_by_channel(session: Session, new_games: list[Game]): assert str(exc_info) == "" + game_3 = session.get(Game, 3) game_2.active = False game_3.active = False session.add(game_2) @@ -77,24 +74,20 @@ def test_games_by_channel(session: Session, new_games: list[Game]): def test_games_by_team(session: Session, new_games: list[Game]): - game_1 = new_games[1] - game_2 = new_games[2] - session.add(game_1) - session.add(game_2) - session.commit() - - assert len(get_games_by_team_id(session, team_id=3)) == 1 + assert len(get_active_games_by_team(session, team_id=3)) == 1 - game_1.active = True - session.add(game_1) - session.commit() - - assert len(get_games_by_team_id(session, team_id=3)) == 2 - - game_1.active = False - game_2.active = False - session.add(game_1) + game_2 = session.get(Game, 2) + game_2.active = True session.add(game_2) session.commit() - assert len(get_games_by_team_id(session, team_id=3)) == 0 + assert len(get_active_games_by_team(session, team_id=3)) == 2 + + game_3 = session.get(Game, 3) + game_3.active = False + game_2.active = False + session.add(game_3) + session.add(game_2) + session.commit() + + assert len(get_active_games_by_team(session, team_id=3)) == 0