Skip to content

Commit

Permalink
[Feat] Add Room class and fix WebSocket consumer connection and recon…
Browse files Browse the repository at this point in the history
…nection issues
  • Loading branch information
ael-mouz committed May 2, 2024
1 parent 19bc81d commit fe12064
Show file tree
Hide file tree
Showing 2 changed files with 330 additions and 11 deletions.
88 changes: 77 additions & 11 deletions app/back-end/game/consumers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from channels.generic.websocket import AsyncWebsocketConsumer
import json
import sys
from .room import RoomObject

from django.contrib.auth import get_user_model

Expand All @@ -33,22 +34,69 @@ async def validate_token(token):


class GameConsumer(AsyncWebsocketConsumer):
Rooms_index = 0
rooms = {}

def get_room(self):
return self.rooms[self.room_name]

# -----------------------> 1. broadcast_message <-----------------------
async def broadcast_message(self, message):
try:
print(f"Broadcasting message: {message}", file=sys.stderr)
await self.channel_layer.group_send(
self.room_name, {"type": "bmessage", "message": message}
)
except Exception as e:
print(f"An error occurred in broadcast_message: {e}")

async def bmessage(self, event):
try:
print(f"Received message: {event['message']}", file=sys.stderr)
message = event["message"]
await self.send(text_data=json.dumps({"message": message}))
except Exception as e:
print(f"An error occurred in bmessage: {e}")

# -----------------------> 2. broadcast_message <-----------------------

async def connect(self):
query_string = parse_qs(self.scope["query_string"].decode())
token = query_string.get("token")
if not token:
await self.close()
else:
user_id = await validate_token(token[0])
if user_id is None:
try:
query_string = parse_qs(self.scope["query_string"].decode())
token = query_string.get("token")
if not token:
await self.close()
else:
self.scope["user"] = await get_user(user_id=user_id)
print("-" * 50, file=sys.stderr)
print(f"User: {self.scope['user']}", file=sys.stderr)
await self.accept()
user_id = await validate_token(token[0])
if user_id is None:
await self.close()
else:
await self.accept()
print("-" * 50, file=sys.stderr)
self.scope["user"] = await get_user(user_id=user_id)
print(f"->User: {self.scope['user']}", file=sys.stderr)
self.room_name, self.room = await self.find_or_create_room(
self.scope["user"]
)
print(f"->Room: {self.room_name}", file=sys.stderr)
await self.channel_layer.group_add(
self.room_name, self.channel_name
)
index = self.room.get_user_index(self.scope["user"])
user1, user2 = self.room.get_original_users()
message = (
f"index:{index}, User1:->[ {user1} ]<-, User2:->[{user2}]<-"
)
await self.send(text_data=json.dumps({"message": message}))
if self.room.is_ready():
self.room.start_game()
print(f"Room {self.room_name} is full", file=sys.stderr)
await self.broadcast_message("Game started")
except Exception as e:
print(f"An error occurred in connect: {e}")

async def disconnect(self, close_code):
# await self.channel_layer.group_discard(self.room_name, self.channel_name)
pass

async def receive(self, text_data):
Expand All @@ -60,3 +108,21 @@ async def receive(self, text_data):
message = text_data

await self.send(text_data=json.dumps({"message": message}))

async def find_or_create_room(self, user_id):
for room_name, room in self.rooms.items():
if room.get_game_state() == True and room.is_user_joined(user_id):
room.reconecting_user(self.channel_name, user_id)
await self.send(text_data=json.dumps({"message": "reconected"}))
return room_name, room
elif room.get_game_state() == False and not room.is_user_joined(user_id):
room.add_user(self.channel_name, user_id)
await self.send(text_data=json.dumps({"message": "joined"}))
return room_name, room
self.Rooms_index += 1
new_room_name = f"room_{self.Rooms_index}"
new_room = RoomObject()
new_room.add_user(self.channel_name, user_id)
await self.send(text_data=json.dumps({"message": "created + joined"}))
self.rooms[new_room_name] = new_room
return new_room_name, new_room
253 changes: 253 additions & 0 deletions app/back-end/game/room.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
import sys


class RoomObject:
def __init__(self):
self.game_started = False
self.game_state = "waiting"
self.ball_radius = 0.1
self.paddle_width = 0.2
self.paddle_height = 0.2
self.paddle_depth = 1
self.paddle1_speed = 0
self.paddle2_speed = 0
self.paddle1_position = {"x": -4.8, "z": 0}
self.paddle2_position = {"x": 4.8, "z": 0}
self.ball_position = {"x": 0, "z": 0}
self.ball_velocity = {"velocity_x": 0, "velocity_z": 0}
self.Original_users = {
"user1": {"joined": 0, "user_id": "", "index": 1, "channel_name": ""},
"user2": {"joined": 0, "user_id": "", "index": 2, "channel_name": ""},
}
# self.users = []
self.index = 1
self.score = {"user1": 0, "user2": 0}

def start_game(self):
self.game_started = True

def get_user_index(self, user_id):
if self.Original_users["user1"]["user_id"] == user_id:
return 1
elif self.Original_users["user2"]["user_id"] == user_id:
return 2

def get_original_users(self):
return (
self.Original_users["user1"]["user_id"],
self.Original_users["user2"]["user_id"],
)

def get_game_state(self):
return self.game_started

def is_user_joined(self, user_id):
if (
self.Original_users["user1"]["user_id"] == user_id
or self.Original_users["user2"]["user_id"] == user_id
):
return True
return False

def reconecting_user(self, channel_name, user_id):
if self.Original_users["user1"]["user_id"] == user_id:
self.Original_users["user1"]["channel_name"] = channel_name
elif self.Original_users["user2"]["user_id"] == user_id:
self.Original_users["user2"]["channel_name"] = channel_name

def add_user(self, channel_name, user_id):
if self.Original_users["user1"]["joined"] == 0:
self.Original_users["user1"]["channel_name"] = channel_name
self.Original_users["user1"]["user_id"] = user_id
self.Original_users["user1"]["joined"] = 1
elif self.Original_users["user2"]["joined"] == 0:
self.Original_users["user2"]["channel_name"] = channel_name
self.Original_users["user2"]["user_id"] = user_id
self.Original_users["user2"]["joined"] = 1

def set_ball_position(self, x, z):
self.ball_position["x"] = x
self.ball_position["z"] = z

def set_ball_velocity(self, velocity_x, velocity_z):
self.ball_velocity["velocity_x"] = velocity_x
self.ball_velocity["velocity_z"] = velocity_z

def ball_update(self):
self.ball_position["x"] += self.ball_velocity["velocity_x"]
self.ball_position["z"] += self.ball_velocity["velocity_z"]
self.ball_velocity["velocity_x"] *= 1.0005
self.ball_velocity["velocity_z"] *= 1.0005
# self.ball_velocity["velocity_x"] *= 1.00005
# self.ball_velocity["velocity_z"] *= 1.00005

def ball_reset(self):
self.ball_position["x"] = 0
self.ball_position["z"] = 0
self.ball_velocity["velocity_x"] = 0
self.ball_velocity["velocity_z"] = 0

def get_updated_ball(self):
return self.ball_position, self.ball_velocity

def remove_user(self, channel_name):
self.users = [
user for user in self.users if user["channel_name"] != channel_name
]

def paddle_update(self):
newPosition1 = self.paddle1_position["z"] + self.paddle1_speed
if newPosition1 < -2.5 + self.paddle_depth / 2:
self.paddle1_position["z"] = -2.5 + self.paddle_depth / 2
self.paddle1_speed = 0
elif newPosition1 > 2.5 - self.paddle_depth / 2:
self.paddle1_position["z"] = 2.5 - self.paddle_depth / 2
self.paddle1_speed = 0
else:
self.paddle1_position["z"] = newPosition1
newPosition2 = self.paddle2_position["z"] + self.paddle2_speed
if newPosition2 < -2.5 + self.paddle_depth / 2:
self.paddle2_position["z"] = -2.5 + self.paddle_depth / 2
self.paddle1_speed = 0
elif newPosition2 > 2.5 - self.paddle_depth / 2:
self.paddle2_position["z"] = 2.5 - self.paddle_depth / 2
self.paddle1_speed = 0
else:
self.paddle2_position["z"] = newPosition2

def paddle_reset(self):
self.paddle1_position["z"] = 0
self.paddle2_position["z"] = 0
self.paddle1_speed = 0
self.paddle2_speed = 0

def is_paddle_move(self, paddle):
if paddle == 1:
return self.paddle1_speed != 0
elif paddle == 2:
return self.paddle2_speed != 0

def set_paddle_speed(self, paddle, speed):
if paddle == 1:
self.paddle1_speed = speed
elif paddle == 2:
self.paddle2_speed = speed

def ball_intersect(self):
if (
self.ball_position["z"] - self.ball_radius
<= self.paddle1_position["z"] + self.paddle_depth / 2
and self.ball_position["z"] + self.ball_radius
>= self.paddle1_position["z"] - self.paddle_depth / 2
and self.ball_position["x"] - self.ball_radius
<= self.paddle1_position["x"] + self.paddle_width / 2
):
if (
self.ball_position["z"] + self.ball_radius
> self.paddle1_position["z"] + self.paddle_depth / 2
and self.ball_position["x"]
< self.paddle1_position["x"] + self.paddle_width / 2
):
self.ball_position["z"] = (
self.paddle1_position["z"]
+ self.paddle_depth / 2
+ self.ball_radius
+ 0.05
)
self.ball_velocity["velocity_z"] *= -1
elif (
self.ball_position["z"] - self.ball_radius
< self.paddle1_position["z"] - self.paddle_depth / 2
and self.ball_position["x"]
< self.paddle1_position["x"] + self.paddle_width / 2
):
self.ball_position["z"] = (
self.paddle1_position["z"]
- self.paddle_depth / 2
- self.ball_radius
- 0.05
)
self.ball_velocity["velocity_z"] *= -1
else:
self.ball_position["x"] = (
self.paddle1_position["x"]
+ self.paddle_width / 2
+ self.ball_radius
+ 0.05
)
self.ball_velocity["velocity_x"] *= -1
# Check collision with paddle 2
if (
self.ball_position["z"] - self.ball_radius
<= self.paddle2_position["z"] + self.paddle_depth / 2
and self.ball_position["z"] + self.ball_radius
>= self.paddle2_position["z"] - self.paddle_depth / 2
and self.ball_position["x"] + self.ball_radius
>= self.paddle2_position["x"] - self.paddle_width / 2
):
if (
self.ball_position["z"] + self.ball_radius
> self.paddle2_position["z"] + self.paddle_depth / 2
and self.ball_position["x"]
> self.paddle2_position["x"] - self.paddle_width / 2
):
self.ball_position["z"] = (
self.paddle2_position["z"]
+ self.paddle_depth / 2
+ self.ball_radius
+ 0.05
)
self.ball_velocity["velocity_z"] *= -1
elif (
self.ball_position["z"] - self.ball_radius
< self.paddle2_position["z"] - self.paddle_depth / 2
and self.ball_position["x"]
> self.paddle2_position["x"] - self.paddle_width / 2
): # error maybe here
self.ball_position["z"] = (
self.paddle2_position["z"]
- self.paddle_depth / 2
- self.ball_radius
- 0.05
)
self.ball_velocity["velocity_z"] *= -1
else:
self.ball_position["x"] = (
self.paddle2_position["x"]
- self.paddle_width / 2
- self.ball_radius
- 0.05
)
self.ball_velocity["velocity_x"] *= -1
if (
self.ball_position["z"] - self.ball_radius >= 2.3
or self.ball_position["z"] + self.ball_radius <= -2.3
):
self.ball_velocity["velocity_z"] *= -1

def is_out_of_bounds(self):
return self.ball_position["x"] < -5 or self.ball_position["x"] > 5

def update_score(self):
if self.ball_position["x"] < -5:
self.score["user1"] += 1
elif self.ball_position["x"] > 5:
self.score["user2"] += 1

def getScores(self):
return self.score

def is_ready(self):
return (
self.Original_users["user1"]["joined"] == 1
and self.Original_users["user2"]["joined"] == 1
)

def is_empty(self):
return not self.users

def start_game(self):
self.game_started = True

def is_started(self):
return self.game_started

0 comments on commit fe12064

Please sign in to comment.