added game state base logic, minor changes

This commit is contained in:
Alexander Karpov 2022-07-02 00:05:05 +03:00
parent df3685b8fe
commit 73db40a4f7
8 changed files with 100 additions and 68 deletions

View File

@ -24,6 +24,11 @@ INSTALLED_APPS = [
"room", "room",
] ]
if DEBUG:
INSTALLED_APPS.append("django.contrib.staticfiles")
INSTALLED_APPS.append("drf_yasg")
MIDDLEWARE = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",

View File

@ -1,9 +1,46 @@
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.urls import path, include from django.template.defaulttags import url
from django.urls import path, include, re_path
urlpatterns = ( # openapi schema
[path("api/", include("game.urls"))] from rest_framework import permissions
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) from drf_yasg.views import get_schema_view
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version="v1",
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
) )
urlpatterns = [path("api/", include("game.urls"))] + static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
)
if settings.DEBUG:
urlpatterns += [
re_path(
r"^swagger(?P<format>\.json|\.yaml)$",
schema_view.without_ui(cache_timeout=0),
name="schema-json",
),
re_path(
r"^swagger/$",
schema_view.with_ui("swagger", cache_timeout=0),
name="schema-swagger-ui",
),
re_path(
r"^redoc/$",
schema_view.with_ui("redoc", cache_timeout=0),
name="schema-redoc",
),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

View File

@ -11,4 +11,4 @@ def generate_charset(length: int):
def gen_ton(): def gen_ton():
return "".join([str(randint(0, 9)) for _ in range(48)]) return int("".join([str(randint(0, 9)) for _ in range(48)]))

View File

@ -1,7 +1,6 @@
import random import random
import uuid import uuid
from django.core.files import File
from django.core.validators import ( from django.core.validators import (
MinValueValidator, MinValueValidator,
MaxValueValidator, MaxValueValidator,
@ -9,18 +8,16 @@ from django.core.validators import (
MaxLengthValidator, MaxLengthValidator,
) )
from django.db import models from django.db import models
from django.conf import settings
from common.generators import generate_charset from common.generators import generate_charset
from game.services.jwt import sign_jwt from game.services.jwt import sign_jwt
HER0_TYPES = [
("WIZARD", "wizard"), class HeroTypes(models.TextChoices):
("ARCHER", "archer"), wizard = "WIZARD", "wizard"
("WARRIOR", "warrior"), archer = "ARCHER", "archer"
("KING", "king"), warrior = "WARRIOR", "warrior"
] king = "KING", "king"
HER0_IMAGE_TYPES = [("DIE", "die"), ("IDLE", "idle"), ("ATTACK", "attack")]
class Player(models.Model): class Player(models.Model):
@ -47,7 +44,7 @@ class Player(models.Model):
+ ["ARCHER" for _ in range(4)] + ["ARCHER" for _ in range(4)]
+ ["WARRIOR" for _ in range(6)] + ["WARRIOR" for _ in range(6)]
+ ["WIZARD" for _ in range(2)] + ["WIZARD" for _ in range(2)]
+ [random.choice(HER0_TYPES[:3])[0] for _ in range(3)] + [random.choice(HeroTypes.choices[:3])[0] for _ in range(3)]
) )
for t in types: for t in types:
hero = Hero() hero = Hero()
@ -99,16 +96,8 @@ class Hero(models.Model):
) )
added = models.DateTimeField(auto_now_add=True) added = models.DateTimeField(auto_now_add=True)
type = models.CharField(blank=False, choices=HER0_TYPES, max_length=7) type = models.CharField(blank=False, choices=HeroTypes.choices, max_length=7)
idle_img_f = models.ForeignKey( model = models.ForeignKey("HeroModelSet", on_delete=models.CASCADE)
"HeroImageSet", on_delete=models.CASCADE, related_name="idle_image_fkey"
)
attack_img_f = models.ForeignKey(
"HeroImageSet", on_delete=models.CASCADE, related_name="attack_image_fkey"
)
die_img_f = models.ForeignKey(
"HeroImageSet", on_delete=models.CASCADE, related_name="die_image_fkey"
)
health = models.IntegerField( health = models.IntegerField(
validators=[MinValueValidator(1), MaxValueValidator(10)], blank=False validators=[MinValueValidator(1), MaxValueValidator(10)], blank=False
) )
@ -135,13 +124,13 @@ class Hero(models.Model):
self, force_insert=False, force_update=False, using=None, update_fields=None self, force_insert=False, force_update=False, using=None, update_fields=None
): ):
self.idle_img_f = random.choice( self.idle_img_f = random.choice(
[x for x in HeroImageSet.objects.filter(hero_type=self.type, type="IDLE")] [x for x in HeroModelSet.objects.filter(hero_type=self.type)]
) )
self.attack_img_f = random.choice( self.attack_img_f = random.choice(
[x for x in HeroImageSet.objects.filter(hero_type=self.type, type="ATTACK")] [x for x in HeroModelSet.objects.filter(hero_type=self.type)]
) )
self.die_img_f = random.choice( self.die_img_f = random.choice(
[x for x in HeroImageSet.objects.filter(hero_type=self.type, type="DIE")] [x for x in HeroModelSet.objects.filter(hero_type=self.type)]
) )
super(Hero, self).save() super(Hero, self).save()
@ -154,13 +143,12 @@ class Hero(models.Model):
verbose_name_plural = "heroes" verbose_name_plural = "heroes"
class HeroImageSet(models.Model): class HeroModelSet(models.Model):
type = models.CharField(max_length=10, choices=HER0_IMAGE_TYPES) hero_type = models.CharField(blank=False, choices=HeroTypes.choices, max_length=7)
hero_type = models.CharField(blank=False, choices=HER0_TYPES, max_length=7) model = models.ImageField(upload_to="uploads/")
image = models.ImageField(upload_to="uploads/")
def __str__(self): def __str__(self):
return f"{self.hero_type} {self.type} image" return f"{self.hero_type} model file"
class Deck(models.Model): class Deck(models.Model):

View File

@ -5,7 +5,7 @@ from channels.generic.websocket import AsyncWebsocketConsumer
from channels.layers import get_channel_layer from channels.layers import get_channel_layer
from game.models import Deck from game.models import Deck
from room.models import PlayerInQueue, Room, PlayerInRoom from room.models import PlayerInQueue, Room, PlayerInRoom, GameState
from room.services.room_create import create_room from room.services.room_create import create_room
channel_layer = get_channel_layer() channel_layer = get_channel_layer()
@ -208,15 +208,18 @@ class RoomConsumer(AsyncWebsocketConsumer):
if not await self.connect_to_room(): if not await self.connect_to_room():
await self.close() await self.close()
else: else:
message, round = await self.get_state()
await self.send( await self.send(
json.dumps( json.dumps(
{ {
"type": "INFO", "type": "INFO",
"message": f"welcome to room {self.room_name}",
"opponent_score": self.scope["opponent_score"], "opponent_score": self.scope["opponent_score"],
"opponent_deck": self.scope["opponent_deck"], "opponent_deck": self.scope["opponent_deck"],
"opponent_online": self.scope["opponent_online"], "opponent_online": self.scope["opponent_online"],
"first": self.scope["first"], "first": self.scope["first"],
"state": message,
"round": round,
}, },
) )
) )
@ -236,6 +239,11 @@ class RoomConsumer(AsyncWebsocketConsumer):
# Join room group # Join room group
await self.channel_layer.group_add(self.room_group_name, self.channel_name) await self.channel_layer.group_add(self.room_group_name, self.channel_name)
@sync_to_async
def get_state(self):
state = self.scope["player_in_room"].get_state()
return state.message, state.round
@sync_to_async @sync_to_async
def connect_to_room(self): def connect_to_room(self):
slug = self.scope["url_route"]["kwargs"]["room_name"] slug = self.scope["url_route"]["kwargs"]["room_name"]
@ -346,6 +354,12 @@ class RoomConsumer(AsyncWebsocketConsumer):
if "first" in event: if "first" in event:
msg["first"] = event["first"] msg["first"] = event["first"]
if "state" in event:
msg["state"] = event["state"]
if "round" in event:
msg["round"] = event["round"]
await self.send(text_data=json.dumps(msg)) await self.send(text_data=json.dumps(msg))
# Receive message from room group # Receive message from room group

View File

@ -9,38 +9,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('game', '0002_deck_heroimageset_heroindeck_playerauthsession_and_more'),
] ]
operations = [ operations = [
migrations.CreateModel(
name='Room',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slug', models.SlugField(max_length=16, unique=True)),
('created', models.DateTimeField(auto_now_add=True)),
('ended', models.BooleanField(default=False)),
],
),
migrations.CreateModel(
name='PlayerInRoom',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first', models.BooleanField()),
('score', models.IntegerField()),
('deck', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='decks', to='game.deck')),
('player', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='game.player')),
('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='players', to='room.room')),
],
),
migrations.CreateModel(
name='PlayerInQueue',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('channel_name', models.CharField(max_length=50)),
('score', models.IntegerField()),
('deck', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='game.deck')),
('player', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='game.player')),
],
),
] ]

View File

@ -33,5 +33,18 @@ class PlayerInRoom(models.Model):
online = models.BooleanField(default=False) online = models.BooleanField(default=False)
channel_name = models.CharField(max_length=50, blank=True, null=True) channel_name = models.CharField(max_length=50, blank=True, null=True)
def get_state(self):
return GameState.objects.filter(player=self.player, room=self.room).last()
def __str__(self): def __str__(self):
return f"{self.player.name} in room {self.room.slug}" return f"{self.player.name} in room {self.room.slug}"
class GameState(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
round = models.IntegerField(blank=False)
message = models.CharField(max_length=100, blank=False)
class Meta:
unique_together = ["room", "player", "round"]

View File

@ -3,7 +3,7 @@ from random import randint
from common.generators import generate_charset from common.generators import generate_charset
from game.models import Player from game.models import Player
from room.models import Room, PlayerInRoom from room.models import Room, PlayerInRoom, GameState
@sync_to_async @sync_to_async
@ -36,4 +36,10 @@ def create_room(
deck_id=deck_id_2, deck_id=deck_id_2,
first=first_player == 2, first=first_player == 2,
) )
GameState.objects.create(
room=room, player=player_1, round=0, message="Game started"
)
GameState.objects.create(
room=room, player=player_2, round=0, message="Game started"
)
return room.slug return room.slug