This commit is contained in:
Waylon Walker 2023-06-29 16:38:05 -05:00
parent f0f1ce5018
commit d0b3712f17
No known key found for this signature in database
GPG key ID: 66E2BF2B4190EFE4
18 changed files with 568 additions and 23 deletions

View file

@ -1,13 +1,13 @@
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from rich.console import Console from rich.console import Console
from sqlmodel import Session from sqlmodel import Session, select
from websockets.exceptions import ConnectionClosed from websockets.exceptions import ConnectionClosed
from learn_sql_model.api.websocket_connection_manager import manager from learn_sql_model.api.websocket_connection_manager import manager
from learn_sql_model.config import get_session from learn_sql_model.config import get_session
from learn_sql_model.console import console from learn_sql_model.console import console
from learn_sql_model.models.hero import HeroDelete, HeroUpdate, Heros from learn_sql_model.models.hero import Hero, HeroDelete, HeroUpdate, Heros
web_socket_router = APIRouter() web_socket_router = APIRouter()
@ -46,7 +46,9 @@ async def websocket_endpoint_connect(
): ):
Console().log(f"Client #{id} connecting") Console().log(f"Client #{id} connecting")
await manager.connect(websocket, channel) await manager.connect(websocket, channel)
heros = Heros.list(session=session) statement = select(Hero)
heros = session.exec(statement).all()
heros = Heros(__root__=heros)
await websocket.send_text(heros.json()) await websocket.send_text(heros.json())
try: try:
@ -83,11 +85,18 @@ async def websocket_endpoint_hero_echo(
while True: while True:
data = await websocket.receive_text() data = await websocket.receive_text()
hero = HeroUpdate.parse_raw(data) hero = HeroUpdate.parse_raw(data)
heros = Heros.list(session=session) statement = select(Hero)
heros = session.exec(statement).all()
heros = Heros(__root__=heros)
if heros != last_heros: if heros != last_heros:
await manager.broadcast(heros.json(), "heros") await manager.broadcast(heros.json(), "heros")
last_heros = heros last_heros = heros
hero.update(session=session) db_hero = session.get(Hero, hero.id)
for key, value in hero.dict(exclude_unset=True).items():
setattr(db_hero, key, value)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
console.print(heros) console.print(heros)
await websocket.send_text(heros.json()) await websocket.send_text(heros.json())
@ -96,7 +105,9 @@ async def websocket_endpoint_hero_echo(
HeroDelete(id=hero.id).delete(session=session) HeroDelete(id=hero.id).delete(session=session)
except Exception: except Exception:
... ...
heros = Heros.list(session=session) statement = select(Hero)
heros = session.exec(statement).all()
heros = Heros(__root__=heros)
await manager.broadcast(heros.json(), "heros") await manager.broadcast(heros.json(), "heros")
print("disconnected") print("disconnected")
except ConnectionClosed: except ConnectionClosed:
@ -104,6 +115,8 @@ async def websocket_endpoint_hero_echo(
HeroDelete(id=hero.id).delete(session=session) HeroDelete(id=hero.id).delete(session=session)
except Exception: except Exception:
... ...
heros = Heros.list(session=session) statement = select(Hero)
heros = session.exec(statement).all()
heros = Heros(__root__=heros)
await manager.broadcast(heros.json(), "heros") await manager.broadcast(heros.json(), "heros")
print("connection closed") print("connection closed")

View file

@ -29,8 +29,6 @@ def run(
help="show the log messages", help="show the log messages",
), ),
): ):
import uvicorn
uvicorn.run(**get_config().api_server.dict()) uvicorn.run(**get_config().api_server.dict())

View file

@ -5,10 +5,10 @@ from websocket import create_connection
from learn_sql_model.config import get_config from learn_sql_model.config import get_config
from learn_sql_model.console import console from learn_sql_model.console import console
from learn_sql_model.game.light import Light
from learn_sql_model.game.map import Map from learn_sql_model.game.map import Map
from learn_sql_model.game.menu import Menu from learn_sql_model.game.menu import Menu
from learn_sql_model.game.player import Player from learn_sql_model.game.player import Player
from learn_sql_model.game.light import Light
from learn_sql_model.optional import _optional_import_ from learn_sql_model.optional import _optional_import_
pygame = _optional_import_("pygame", group="game") pygame = _optional_import_("pygame", group="game")
@ -37,15 +37,22 @@ class Client:
self.light = Light(self) self.light = Light(self)
self.font = pygame.font.SysFont("", 50) self.font = pygame.font.SysFont("", 50)
self.joysticks = {} self.joysticks = {}
self.darkness = pygame.Surface(
(self.screen.get_width(), self.screen.get_height())
)
atexit.register(self.quit) atexit.register(self.quit)
@property @property
def ws(self): def ws(self):
def connect(): def connect():
self._ws = create_connection( if "https" in config.api_client.url:
f"wss://{config.api_client.url.replace('https://', '')}/wsecho" url = f"wss://{config.api_client.url.replace('https://', '')}/wsecho"
) elif "http" in config.api_client.url:
url = f"ws://{config.api_client.url.replace('http://', '')}/wsecho"
else:
url = f"ws://{config.api_client.url}/wsecho"
self._ws = create_connection(url)
if not hasattr(self, "_ws"): if not hasattr(self, "_ws"):
connect() connect()
@ -80,6 +87,19 @@ class Client:
self.screen.fill((0, 0, 0)) self.screen.fill((0, 0, 0))
self.map.render() self.map.render()
self.player.render() self.player.render()
light_level = 0
self.darkness.fill((light_level, light_level, light_level))
# self.darkness.blit(
# pygame.transform.smoothscale(
# self.spot, [self.light_power, self.light_power]
# ),
# (self.x - self.light_power / 2, self.y - self.light_power / 2),
# )
self.screen.blit(
pygame.transform.scale(self.darkness, self.screen.get_size()).convert(),
(0, 0),
special_flags=pygame.BLEND_MULT,
)
self.light.render() self.light.render()
# update the screen # update the screen

View file

@ -6,15 +6,41 @@ pygame = _optional_import_("pygame", group="game")
class Light: class Light:
def __init__(self, game): def __init__(self, game):
self.game = game self.game = game
self.surf = pygame.Surface((1000, 100))
# pil_image = Image.new("RGBA", (1000, 500))
# pil_draw = ImageDraw.Draw(pil_image)
# pil_draw.pieslice((-1500, -100, 1000, 600), 340, 20, fill=(255, 250, 205))
# pil_image = pil_image.filter(ImageFilter.GaussianBlur(radius=5))
# mode = pil_image.mode
# size = pil_image.size
# data = pil_image.tobytes()
# self.image = pygame.image.fromstring(data, size, mode)
# for r in range(-25, 25):
# _v = v.rotate(r)
# pygame.draw.line(
# self.game.screen,
# (255, 250, 205),
# (0, 50),
# (0 + _v.x, self.game.player.hero.y + _v.y),
# 50,
# )
def render(self): def render(self):
mx, my = pygame.mouse.get_pos() mx, my = pygame.mouse.get_pos()
v = pygame.math.Vector2( v = pygame.math.Vector2(
mx - self.game.player.hero.x, my - self.game.player.hero.y mx - self.game.player.hero.x, my - self.game.player.hero.y
) )
v.scale_to_length(1000) v.scale_to_length(self.game.player.hero.flashlight_strength)
self.game.player.hero.flashlight_angle = v.angle_to(pygame.math.Vector2(0, 0))
# self.game.screen.blit(
# pygame.transform.rotate(self.image, pygame.math.Vector2(0, 0).angle_to(v)),
# (self.game.player.hero.x, self.game.player.hero.y - 250),
# )
for r in range(0, 360): for r in range(-25, 25):
_v = v.rotate(r) _v = v.rotate(r)
pygame.draw.line( pygame.draw.line(
self.game.screen, self.game.screen,
@ -23,3 +49,29 @@ class Light:
(self.game.player.hero.x + _v.x, self.game.player.hero.y + _v.y), (self.game.player.hero.x + _v.x, self.game.player.hero.y + _v.y),
50, 50,
) )
# draw a circle
pygame.draw.circle(
self.game.screen,
(255, 250, 205),
(self.game.player.hero.x, self.game.player.hero.y),
self.game.player.hero.lanturn_strength,
)
def render_flashlight(light, strength, angle):
# self.darkness.blit(
# pygame.transform.smoothscale(
# self.spot, [self.light_power, self.light_power]
# ),
# (self.x - self.light_power / 2, self.y - self.light_power / 2),
# )
for r in range(-25, 25):
_v = v.rotate(r)
pygame.draw.line(
light,
(255, 250, 205),
(self.game.player.hero.x, self.game.player.hero.y),
(self.game.player.hero.x + _v.x, self.game.player.hero.y + _v.y),
50,
)

View file

@ -1,5 +1,6 @@
from learn_sql_model.config import get_config
from learn_sql_model.console import console from learn_sql_model.console import console
from learn_sql_model.models.hero import HeroCreate, HeroDelete, HeroUpdate, Heros from learn_sql_model.models.hero import Hero, HeroCreate, HeroUpdate, Heros
from learn_sql_model.optional import _optional_import_ from learn_sql_model.optional import _optional_import_
pygame = _optional_import_("pygame", group="game") pygame = _optional_import_("pygame", group="game")
@ -12,11 +13,18 @@ HeroFactory = _optional_import_(
class Player: class Player:
def __init__(self, game): def __init__(self, game):
hero = HeroFactory().build(size=25, x=100, y=100) hero = HeroFactory().build(
size=25,
x=100,
y=100,
flashlight_strength=1000,
lanturn_strength=100,
flashlight_angle=0,
)
self.hero = HeroCreate(**hero.dict()).post() self.hero = HeroCreate(**hero.dict()).post()
self.game = game self.game = game
self.others = [] #Heros(heros=[]) self.others = [] # Heros(heros=[])
self.width = 16 self.width = 16
self.height = 16 self.height = 16
self.white = (255, 255, 255) self.white = (255, 255, 255)
@ -42,13 +50,21 @@ class Player:
def rename_hero(self): def rename_hero(self):
old_hero = self.hero old_hero = self.hero
hero = HeroFactory().build( hero = HeroFactory().build(
size=self.hero.size, x=self.hero.x, y=self.hero.y, id=old_hero.id size=self.hero.size,
x=self.hero.x,
y=self.hero.y,
id=old_hero.id,
flashlight_strength=self.hero.flashlight_strength,
lanturn_strength=self.hero.lanturn_strength,
) )
self.hero = HeroCreate(**hero.dict()).post() self.hero = HeroCreate(**hero.dict()).post()
def quit(self): def quit(self):
try: try:
HeroDelete(id=self.hero.id).delete() session = get_config().database.session
hero = session.get(Hero, self.hero.id)
session.delete(hero)
session.commit()
except RuntimeError: except RuntimeError:
pass pass
@ -158,6 +174,10 @@ class Player:
movement_vector = end_pos - start_pos movement_vector = end_pos - start_pos
try: try:
movement_direction = movement_vector.normalize() movement_direction = movement_vector.normalize()
except ValueError:
end_pos = pygame.math.Vector2(self.hero.x + 128, self.hero.y + 128)
movement_vector = end_pos - start_pos
movement_direction = movement_vector.normalize()
except ZeroDivisionError: except ZeroDivisionError:
end_pos = pygame.math.Vector2(self.hero.x + 128, self.hero.y + 128) end_pos = pygame.math.Vector2(self.hero.x + 128, self.hero.y + 128)
movement_vector = end_pos - start_pos movement_vector = end_pos - start_pos
@ -200,7 +220,7 @@ class Player:
) )
def render(self): def render(self):
for other in self.others.heros: for other in self.others.__root__:
if other.id != self.hero.id: if other.id != self.hero.id:
pygame.draw.circle( pygame.draw.circle(
self.game.screen, (255, 0, 0), (other.x, other.y), other.size self.game.screen, (255, 0, 0), (other.x, other.y), other.size

View file

@ -1,6 +1,7 @@
from typing import Dict from typing import Dict, Optional
import httpx import httpx
import pydantic
from pydantic import BaseModel from pydantic import BaseModel
from sqlmodel import Field, SQLModel from sqlmodel import Field, SQLModel
@ -13,13 +14,24 @@ class HeroBase(SQLModel, table=False):
secret_name: str secret_name: str
x: int x: int
y: int y: int
# size: int size: Optional[int]
flashlight_strength: Optional[int] = 1000
flashlight_angle: Optional[int] = 0
lanturn_strength: Optional[int] = 100
# age: Optional[int] = None # age: Optional[int] = None
# shoe_size: Optional[int] = None # shoe_size: Optional[int] = None
# pet_id: Optional[int] = Field(default=None, foreign_key="pet.id") # pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
# pet: Optional[Pet] = Relationship(back_populates="hero") # pet: Optional[Pet] = Relationship(back_populates="hero")
@pydantic.validator("size", pre=True, always=True)
def validate_size(cls, v):
if v is None:
return 50
if v <= 0:
raise ValueError("size must be > 0")
return v
class Hero(HeroBase, table=True): class Hero(HeroBase, table=True):
id: int = Field(default=None, primary_key=True) id: int = Field(default=None, primary_key=True)

View file

@ -0,0 +1,36 @@
"""add hero.lighting
Revision ID: a1cd0a1947be
Revises: c79214cdc7b3
Create Date: 2023-06-28 19:43:47.108749
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel
from learn_sql_model.er_diagram import generate_er_diagram, generate_er_markdown
from learn_sql_model.config import get_config
# revision identifiers, used by Alembic.
revision = 'a1cd0a1947be'
down_revision = 'c79214cdc7b3'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('hero', sa.Column('flashlight_strength', sa.Integer(), nullable=True))
op.add_column('hero', sa.Column('lanturn_strength', sa.Integer(), nullable=True))
# ### end Alembic commands ###
generate_er_diagram(f'migrations/versions/{revision}_er_diagram.png')
generate_er_markdown(f'migrations/versions/{revision}_er_diagram.md', f'migrations/versions/er_diagram_{revision}.png')
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('hero', 'lanturn_strength')
op.drop_column('hero', 'flashlight_strength')
# ### end Alembic commands ###

View file

@ -0,0 +1,75 @@
![ER Diagram](migrations/versions/er_diagram_a1cd0a1947be.png)
---
## Table: learn_sql_model_alembic_version
### First 5 rows
| version_num |
|-------------|
| c79214cdc7b3 |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| version_num | VARCHAR(32) | | | |
### Records Count
The table learn_sql_model_alembic_version contains 1 records.
---
## Table: hero
### First 5 rows
| name | secret_name | id | x | y | size | flashlight_strength | lanturn_strength |
|------|-------------|----|---|---|------|---------------------|------------------|
| deep-insect | unusual-inspection | 1 | 100 | 100 | 25 | None | None |
| flat-foundation | personal-incident | 2 | 100 | 100 | 25 | None | None |
| formal-cap | mental-substance | 3 | 100 | 100 | 25 | None | None |
| political-routine | low-engineer | 4 | 100 | 100 | 25 | None | None |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| secret_name | VARCHAR | | | |
| id | INTEGER | | | |
| x | INTEGER | | | |
| y | INTEGER | | | |
| size | INTEGER | | | |
| flashlight_strength | INTEGER | | | |
| lanturn_strength | INTEGER | | | |
### Records Count
The table hero contains 4 records.
---
## Table: pet
### First 5 rows
| name | birthday | id |
|------|----------|----|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| birthday | DATETIME | | | |
| id | INTEGER | | | |
### Records Count
The table pet contains 0 records.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View file

@ -0,0 +1,34 @@
"""add hero.size
Revision ID: c79214cdc7b3
Revises: 3555f61aaa79
Create Date: 2023-06-28 11:39:02.606001
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel
from learn_sql_model.er_diagram import generate_er_diagram, generate_er_markdown
from learn_sql_model.config import get_config
# revision identifiers, used by Alembic.
revision = 'c79214cdc7b3'
down_revision = '3555f61aaa79'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('hero', sa.Column('size', sa.Integer(), nullable=True))
# ### end Alembic commands ###
generate_er_diagram(f'migrations/versions/{revision}_er_diagram.png')
generate_er_markdown(f'migrations/versions/{revision}_er_diagram.md', f'migrations/versions/er_diagram_{revision}.png')
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('hero', 'size')
# ### end Alembic commands ###

View file

@ -0,0 +1,74 @@
![ER Diagram](migrations/versions/er_diagram_c79214cdc7b3.png)
---
## Table: learn_sql_model_alembic_version
### First 5 rows
| version_num |
|-------------|
| 3555f61aaa79 |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| version_num | VARCHAR(32) | | | |
### Records Count
The table learn_sql_model_alembic_version contains 1 records.
---
## Table: hero
### First 5 rows
| name | secret_name | id | x | y | size |
|------|-------------|----|---|---|------|
| tight-gold | successful-health | 1 | 6430 | 6231 | None |
| hard-rope | green-research | 2 | 1395 | 2865 | None |
| sure-priority | pretty-series | 3 | 2770 | 7835 | None |
| huge-library | adult-body | 4 | 656 | 2377 | None |
| specific-courage | suspicious-delivery | 5 | 4193 | 9011 | None |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| secret_name | VARCHAR | | | |
| id | INTEGER | | | |
| x | INTEGER | | | |
| y | INTEGER | | | |
| size | INTEGER | | | |
### Records Count
The table hero contains 1572 records.
---
## Table: pet
### First 5 rows
| name | birthday | id |
|------|----------|----|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| birthday | DATETIME | | | |
| id | INTEGER | | | |
### Records Count
The table pet contains 0 records.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -0,0 +1,34 @@
"""add hero.flashlight_angle
Revision ID: d79dd8e699d1
Revises: e1af975310a1
Create Date: 2023-06-28 19:54:19.322431
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel
from learn_sql_model.er_diagram import generate_er_diagram, generate_er_markdown
from learn_sql_model.config import get_config
# revision identifiers, used by Alembic.
revision = 'd79dd8e699d1'
down_revision = 'e1af975310a1'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('hero', sa.Column('flashlight_angle', sa.Integer(), nullable=True))
# ### end Alembic commands ###
generate_er_diagram(f'migrations/versions/{revision}_er_diagram.png')
generate_er_markdown(f'migrations/versions/{revision}_er_diagram.md', f'migrations/versions/er_diagram_{revision}.png')
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('hero', 'flashlight_angle')
# ### end Alembic commands ###

View file

@ -0,0 +1,72 @@
![ER Diagram](migrations/versions/er_diagram_d79dd8e699d1.png)
---
## Table: learn_sql_model_alembic_version
### First 5 rows
| version_num |
|-------------|
| e1af975310a1 |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| version_num | VARCHAR(32) | | | |
### Records Count
The table learn_sql_model_alembic_version contains 1 records.
---
## Table: hero
### First 5 rows
| name | secret_name | id | x | y | size | flashlight_strength | lanturn_strength | flashlight_angle |
|------|-------------|----|---|---|------|---------------------|------------------|------------------|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| secret_name | VARCHAR | | | |
| id | INTEGER | | | |
| x | INTEGER | | | |
| y | INTEGER | | | |
| size | INTEGER | | | |
| flashlight_strength | INTEGER | | | |
| lanturn_strength | INTEGER | | | |
| flashlight_angle | INTEGER | | | |
### Records Count
The table hero contains 0 records.
---
## Table: pet
### First 5 rows
| name | birthday | id |
|------|----------|----|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| birthday | DATETIME | | | |
| id | INTEGER | | | |
### Records Count
The table pet contains 0 records.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View file

@ -0,0 +1,34 @@
"""add hero.flashlight_angle
Revision ID: e1af975310a1
Revises: a1cd0a1947be
Create Date: 2023-06-28 19:53:18.068873
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel
from learn_sql_model.er_diagram import generate_er_diagram, generate_er_markdown
from learn_sql_model.config import get_config
# revision identifiers, used by Alembic.
revision = 'e1af975310a1'
down_revision = 'a1cd0a1947be'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
generate_er_diagram(f'migrations/versions/{revision}_er_diagram.png')
generate_er_markdown(f'migrations/versions/{revision}_er_diagram.md', f'migrations/versions/er_diagram_{revision}.png')
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View file

@ -0,0 +1,71 @@
![ER Diagram](migrations/versions/er_diagram_e1af975310a1.png)
---
## Table: learn_sql_model_alembic_version
### First 5 rows
| version_num |
|-------------|
| a1cd0a1947be |
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| version_num | VARCHAR(32) | | | |
### Records Count
The table learn_sql_model_alembic_version contains 1 records.
---
## Table: hero
### First 5 rows
| name | secret_name | id | x | y | size | flashlight_strength | lanturn_strength |
|------|-------------|----|---|---|------|---------------------|------------------|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| secret_name | VARCHAR | | | |
| id | INTEGER | | | |
| x | INTEGER | | | |
| y | INTEGER | | | |
| size | INTEGER | | | |
| flashlight_strength | INTEGER | | | |
| lanturn_strength | INTEGER | | | |
### Records Count
The table hero contains 0 records.
---
## Table: pet
### First 5 rows
| name | birthday | id |
|------|----------|----|
### Columns
| Column Name | Type | Foreign Key | Example Value |
|-------------|------|-------------|---------------|
| name | VARCHAR | | | |
| birthday | DATETIME | | | |
| id | INTEGER | | | |
### Records Count
The table pet contains 0 records.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB