diff --git a/frontend/static/css/index.css b/frontend/static/css/index.css
deleted file mode 100644
index a3a39b6..0000000
--- a/frontend/static/css/index.css
+++ /dev/null
@@ -1,10 +0,0 @@
-
-body {
- margin: 0.5em;
- font-family: 'Quicksand', sans-serif;
- font-size: 30px;
-}
-
-a {
- color: #009579;
-}
diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js
index db5c608..4b7e01d 100644
--- a/frontend/static/js/index.js
+++ b/frontend/static/js/index.js
@@ -109,10 +109,15 @@ document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
+ document.querySelectorAll('[data-link]').forEach(e => {
+ e.classList.remove('active');
+ });
+ e.target.classList.add('active');
navigateTo(e.target.href.slice(location.origin.length));
}
});
router(location.pathname);
+ document.querySelector('a[href=\'' + location.pathname + '\']')?.classList.add('active');
});
export { client, navigateTo }
diff --git a/frontend/templates/index.html b/frontend/templates/index.html
index 70f227e..185a016 100644
--- a/frontend/templates/index.html
+++ b/frontend/templates/index.html
@@ -4,18 +4,23 @@
- Single Page App
-
+ Bozo Pong
+
-
-
-
+
+
+
+
diff --git a/games/config.py b/games/config.py
new file mode 100644
index 0000000..feed4aa
--- /dev/null
+++ b/games/config.py
@@ -0,0 +1,9 @@
+PADDLE_SPEED_MAX = 1
+PADDLE_SIZE_HEIGHT = 10
+PADDLE_SIZE_WIDTH = 100
+
+PADDLE_RAIL = PADDLE_SIZE_WIDTH * 5
+
+BALL_SPEED_INC = 1
+BALL_SPEED_START = 1
+BALL_SIZE = 4
diff --git a/games/consumers.py b/games/consumers.py
new file mode 100644
index 0000000..814fe93
--- /dev/null
+++ b/games/consumers.py
@@ -0,0 +1,42 @@
+from channels.generic.websocket import AsyncWebsocketConsumer
+
+from django.contrib.auth.models import User
+
+import json
+
+from .objects.GameRoomManager import GameRoomManager
+
+game_room_manager: GameRoomManager = GameRoomManager()
+
+class GameWebSocket(AsyncWebsocketConsumer):
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.channel_name = "games"
+ self.group_name = "games"
+
+ def connect(self):
+
+ self.user: User = self.scope["user"]
+ if (self.user.is_anonymous or not self.user.is_authenticated):
+ return
+
+ self.channel_layer.group_add(self.group_name, self.channel_name)
+
+ self.game_id = int(self.scope['url_route']['kwargs']['game_id'])
+
+ self.room = game_room_manager.get(self.game_id)
+
+ if (self.room is None):
+ self.member.send("Tournament not found")
+ self.disconnect(1017)
+
+ self.room.append(self.member)
+
+ def receive(self, text_data: str = None, bytes_data: bytes = None):
+ self.member.receive(text_data, bytes_data)
+
+ def disconnect(self, close_code):
+ member = self.room.get_member_by_socket(self)
+ if (member is not None):
+ self.room.remove(self.member, close_code)
\ No newline at end of file
diff --git a/games/models.py b/games/models.py
index 36d5394..3113eaf 100644
--- a/games/models.py
+++ b/games/models.py
@@ -1,5 +1,7 @@
from django.db import models
+from channels.generic.websocket import AsyncWebsocketConsumer
+
# Create your models here.
class GameModel(models.Model):
diff --git a/games/objects/GameMember.py b/games/objects/GameMember.py
new file mode 100644
index 0000000..a2cdcb9
--- /dev/null
+++ b/games/objects/GameMember.py
@@ -0,0 +1,17 @@
+from channels.generic.websocket import AsyncWebsocketConsumer
+
+from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
+
+class GameMember(AbstractRoomMember):
+
+ def __init__(self, user_id: int, socket: AsyncWebsocketConsumer):
+ super().__init__(user_id, socket)
+ self.is_a_player = False
+
+ def receive(self, data: dict):
+ if (not self.is_a_player):
+ self.send("You are not a player.")
+ return
+
+ def send_ball(self, ball):
+ pass
\ No newline at end of file
diff --git a/games/objects/GameRoom.py b/games/objects/GameRoom.py
new file mode 100644
index 0000000..2f76e4b
--- /dev/null
+++ b/games/objects/GameRoom.py
@@ -0,0 +1,7 @@
+from transcendence.abstract.AbstractRoom import AbstractRoom
+
+class GameRoom(AbstractRoom):
+
+ def __init__(self, game_room_manager, game_id: int):
+ super().__init__(game_room_manager)
+ self.game_id = game_id
\ No newline at end of file
diff --git a/games/objects/GameRoomManager.py b/games/objects/GameRoomManager.py
new file mode 100644
index 0000000..26a43b8
--- /dev/null
+++ b/games/objects/GameRoomManager.py
@@ -0,0 +1,19 @@
+from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
+
+from ..models import GameModel
+from . import GameRoom
+
+class GameRoomManager(AbstractRoomManager):
+
+ def get(self, game_id: int):
+
+ for room in self._room_list:
+ if (room.game_id == game_id):
+ return room
+
+ if (GameModel.objects.filter(pk = game_id).exists()):
+ room = GameRoom(self, game_id)
+ self.append(room)
+ return room
+
+ return None
\ No newline at end of file
diff --git a/games/routing.py b/games/routing.py
new file mode 100644
index 0000000..eed3b1c
--- /dev/null
+++ b/games/routing.py
@@ -0,0 +1,6 @@
+from django.urls import re_path
+from . import consumers
+
+websocket_urlpatterns = [
+ re_path(r'ws/games/(?P\d+)$', consumers.GameWebSocket.as_asgi())
+]
diff --git a/games/serializers.py b/games/serializers.py
index 5bd2fc6..0c19b0b 100644
--- a/games/serializers.py
+++ b/games/serializers.py
@@ -21,4 +21,5 @@ class GameSerializer(serializers.ModelSerializer):
return "waiting"
def get_players_id(self, instance: GameModel):
- players_id = [player_game.member_id for player_game in GameMembersModel.objects.filter(game_id=instance.pk)]
\ No newline at end of file
+ players_id = [player_game.player_id for player_game in GameMembersModel.objects.filter(game_id = instance.pk)]
+ return players_id
\ No newline at end of file
diff --git a/games/urls.py b/games/urls.py
new file mode 100644
index 0000000..8495b34
--- /dev/null
+++ b/games/urls.py
@@ -0,0 +1,11 @@
+from django.urls import path, re_path
+from django.conf import settings
+from django.conf.urls.static import static
+
+from .viewset import GameViewSet
+from .views import GameConfigView
+
+urlpatterns = [
+ path("", GameViewSet.as_view({"get": "retrieve"}), name="game_page"),
+ path("", GameConfigView.as_view(), name = "game_config")
+]
\ No newline at end of file
diff --git a/games/views.py b/games/views.py
index 91ea44a..2675031 100644
--- a/games/views.py
+++ b/games/views.py
@@ -1,3 +1,23 @@
-from django.shortcuts import render
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import permissions, status
-# Create your views here.
+from django.http import HttpRequest
+
+from . import config
+
+class GameConfigView(APIView):
+
+ permission_classes = (permissions.AllowAny,)
+
+ def get(self, request):
+ config_data = {
+ "BALL_SIZE": config.BALL_SIZE,
+ "PADDLE_SPEED_MAX": config.PADDLE_SPEED_MAX,
+ "PADDLE_SIZE_HEIGHT": config.PADDLE_SIZE_HEIGHT,
+ "PADDLE_SIZE_WIDTH": config.PADDLE_SIZE_WIDTH,
+ "PADDLE_RAIL": config.PADDLE_RAIL,
+ "BALL_SPEED_INC": config.BALL_SPEED_INC,
+ "BALL_SPEED_START": config.BALL_SPEED_START
+ }
+ return Response(config_data, status = status.HTTP_200_OK)
\ No newline at end of file
diff --git a/games/viewset.py b/games/viewset.py
new file mode 100644
index 0000000..17e25a1
--- /dev/null
+++ b/games/viewset.py
@@ -0,0 +1,27 @@
+from rest_framework import viewsets
+from rest_framework.response import Response
+from rest_framework import permissions, status
+from rest_framework.authentication import SessionAuthentication
+
+from django.http import HttpRequest
+from django.db.models import QuerySet
+
+from .models import GameModel
+from .serializers import GameSerializer
+
+# Create your views here.
+class GameViewSet(viewsets.ModelViewSet):
+
+ queryset = GameModel.objects
+ serializer_class = GameSerializer
+ permission_classes = (permissions.AllowAny,)
+ authentication_classes = (SessionAuthentication,)
+
+ def retrieve(self, request: HttpRequest, pk):
+
+ if (not self.queryset.filter(pk = pk).exists()):
+ return Response({"detail": "Game not found."}, status=status.HTTP_404_NOT_FOUND)
+
+ game = self.queryset.get(pk=pk)
+
+ return Response(self.serializer_class(game).data, status=status.HTTP_200_OK)
\ No newline at end of file
diff --git a/profiles/views.py b/profiles/views.py
index 702e94f..dbcbcab 100644
--- a/profiles/views.py
+++ b/profiles/views.py
@@ -12,7 +12,7 @@ class BlockView(APIView):
def get(self, request, pk):
block = BlockModel.objects.filter(pk=pk)
- if (block):
+ if (block.exists()):
return Response(serializers.serialize("json", block), status=status.HTTP_200_OK)
else:
return Response("Not Found", status=status.HTTP_404_NOT_FOUND)
diff --git a/tournament/routing.py b/tournament/routing.py
index 7271972..4434723 100644
--- a/tournament/routing.py
+++ b/tournament/routing.py
@@ -2,5 +2,5 @@ from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
- re_path(r'ws/tournaments/(?P\d+)$', consumers.TournamentWebConsumer.as_asgi())
+ re_path(r'ws/games/(?P\d+)$', consumers.TournamentWebConsumer.as_asgi())
]
diff --git a/transcendence/asgi.py b/transcendence/asgi.py
index 939a8ed..cb8ac86 100644
--- a/transcendence/asgi.py
+++ b/transcendence/asgi.py
@@ -14,6 +14,7 @@ from channels.auth import AuthMiddlewareStack
import chat.routing
import matchmaking.routing
import tournament.routing
+import games.routing
from django.core.asgi import get_asgi_application
@@ -25,7 +26,8 @@ application = ProtocolTypeRouter({
URLRouter(
chat.routing.websocket_urlpatterns +
matchmaking.routing.websocket_urlpatterns +
- tournament.routing.websocket_urlpatterns
+ tournament.routing.websocket_urlpatterns +
+ games.routing.websocket_urlpatterns
)
)
})
diff --git a/transcendence/urls.py b/transcendence/urls.py
index 38eb6d0..d0d06ad 100644
--- a/transcendence/urls.py
+++ b/transcendence/urls.py
@@ -23,5 +23,6 @@ urlpatterns = [
path('api/accounts/', include('accounts.urls')),
path('api/chat/', include('chat.urls')),
path('api/tournaments/', include('tournament.urls')),
+ path('api/games/', include('games.urls')),
path('', include('frontend.urls')),
]