Skip to content

Commit

Permalink
Merge branch 'wip/game-backend' into backend
Browse files Browse the repository at this point in the history
  • Loading branch information
ael-mouz committed May 6, 2024
2 parents 534a97d + e287121 commit d2d181c
Show file tree
Hide file tree
Showing 3 changed files with 542 additions and 24 deletions.
271 changes: 248 additions & 23 deletions app/back-end/game/consumers.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,260 @@
# from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
# from rest_framework_simplejwt.tokens import UntypedToken
# from urllib.parse import parse_qs
import sys
# Standard library imports
import asyncio
import json
import random
import sys

# Third-party imports
from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.utils import timezone

# Local application/library specific imports
from .room import RoomObject

User = get_user_model()


def current_time():
current_time = timezone.localtime(timezone.now())
formatted_time = current_time.strftime("%H:%M:%S")
return formatted_time


@database_sync_to_async
def get_user(user_id):
try:
user = User.objects.get(id=user_id)
return user
except User.DoesNotExist:
return AnonymousUser()


Room_index = 0
Rooms = {}


def get_room(room_name):
global Rooms
try:
return Rooms[room_name]
except KeyError:
print(f"Room {room_name} does not exist", file=sys.stderr)
except Exception as e:
print(f"An error occurred in get_room: {e}", file=sys.stderr)


def delete_room(room_name):
global Rooms
try:
del Rooms[room_name]
except KeyError:
print(f"Room {room_name} does not exist", file=sys.stderr)
except Exception as e:
print(f"An error occurred in delete_room: {e}", file=sys.stderr)


def add_room(room_name, room):
global Rooms
try:
Rooms[room_name] = room
except Exception as e:
print(f"An error occurred in add_room: {e}", file=sys.stderr)


def get_rooms_items():
try:
return Rooms.items()
except Exception as e:
print(f"An error occurred in iterate_rooms: {e}", file=sys.stderr)


def get_room_index():
global Room_index
try:
return Room_index
except Exception as e:
print(f"An error occurred in get_room_index: {e}", file=sys.stderr)


def increment_room_index():
global Room_index
try:
Room_index += 1
except Exception as e:
print(f"An error occurred in increment_room_index: {e}", file=sys.stderr)


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

# -----------------------> 2. message <-----------------------
async def message(self, event):
try:
message = event["message"]
await self.send(
text_data=json.dumps({"message": message, "time": current_time()})
)
except Exception as e:
print(f"An error occurred in message: {e}", file=sys.stderr)

# -----------------------> 3. connect <-----------------------
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:
# try:
# UntypedToken(token[0])
# except (InvalidToken, TokenError) as e:
# await self.close()
# else:
await self.accept()
try:
if self.scope["user"].is_authenticated:
await self.accept()
self.user = await get_user(user_id=self.scope["user"].id)
self.room_name, self.room = await self.find_or_create_room(self.user)
await self.channel_layer.group_add(self.room_name, self.channel_name)
index = self.room.get_user_index(self.user)
message = f"action: connection_ack, index: {index}, User: {self.user}, Room_name: {self.room_name}"
await self.message({"message": message})
if self.room.is_ready():
user1, user2 = self.room.get_original_users()
message = f"action: opponents, user1: {user1}, user2: {user2}"
await self.broadcast_message(message)
if self.room.is_started() == False:
asyncio.ensure_future(self.start_game())
else:
await self.close()
except Exception as e:
print(f"An error occurred in connect: {e}", file=sys.stderr)

# -----------------------> 4. disconnect <-----------------------
async def disconnect(self, close_code):
pass
try:
room = get_room(self.room_name)
room.set_reconect(self.user)
# await self.channel_layer.group_discard(self.room_name, self.channel_name)
pass
except Exception as e:
print(f"An error occurred in disconnect: {e}", file=sys.stderr)

# -----------------------> 5. receive <-----------------------
async def receive(self, text_data):
print(f"Received message: {text_data}", file = sys.stderr)
try:
text_data_json = json.loads(text_data)
message = text_data_json['message']
except json.JSONDecodeError:
message = text_data
message = text_data_json["message"]
print(f"Received message: {message}")
except Exception as e:
print(f"An error occurred in receive: {e}", file=sys.stderr)

await self.send(text_data=json.dumps({
'message': message
}))
# -----------------------> 6. start_game <-----------------------
async def start_game(self):
try:
await asyncio.sleep(5)
await self.broadcast_message(f"action: load_game")
await asyncio.sleep(5)
await self.broadcast_message(f"action: start_game")
await self.init_pos()
room = get_room(self.room_name)
while True:
if room.is_reconecting():
message = f"action: reconecting, score: user1: {room.getScores()['user1']}, user2: {room.getScores()['user2']}"
await self.broadcast_message(message)
i = 0
while room.is_reconecting():
await asyncio.sleep(1)
message = f"action: reconecting"
await self.broadcast_message(message)
if (i := i + 1) > 10:
room.end_game()
room.make_user_winner(room.get_online_user())
# delete_room(self.room_name)
message = f"action: end_game, winner: {room.get_winner()[0]}, loser: {room.get_winner()[1]}"
await self.broadcast_message(message)
return
room.ball_update()
room.ball_intersect()
room.paddle_update()
if room.is_paddle_move(1):
message = f"action: paddle_update, paddle: 1, paddle_position_z : {room.paddle1_position['z']}"
await self.broadcast_message(message)
if room.is_paddle_move(2):
message = f"action: paddle_update, paddle: 2, paddle_position_z : {room.paddle2_position['z']}"
await self.broadcast_message(message)
if room.is_out_of_bounds():
room.update_score()
message = f"action: score, user1score: {room.getScores()['user1']}, user2score: {room.getScores()['user2']}"
await self.broadcast_message(message)
if room.is_winner():
room.end_game()
winner, loser = room.get_winner()
# delete_room(self.room_name)
message = f"action: end_game, winner: {winner}, loser: {loser}"
await self.broadcast_message(message)
break
room.paddle_reset()
ball_pos_z, ball_velo_x, ball_velo_z = await self.reset()
message = f"action: reset, ball_position_x: {0}, ball_position_z: {ball_pos_z}, ball_velocity_x: {ball_velo_x}, ball_velocity_z: {ball_velo_z}"
await self.broadcast_message(message)
else:
ball_position, ball_velocity = room.get_updated_ball()
message = f"action: update, ball_position_x: {ball_position['x']}, ball_position_z: {ball_position['z']}, ball_velocity_x: {ball_velocity['velocity_x']}, ball_velocity_z: {ball_velocity['velocity_x']}"
await self.broadcast_message(message)
await asyncio.sleep(1 / 60)
except Exception as e:
print(f"An error occurred in connect: {e}", file=sys.stderr)

# -----------------------> 7. init_pos <-----------------------
async def init_pos(self):
try:
room = get_room(self.room_name)
ball_position_z = random.uniform(-2.2, 2.2)
ball_velocity_x = 0.05 * random.choice([-1, 1])
ball_velocity_z = 0.05 * random.choice([-1, 1])
room.set_ball_position(0, ball_position_z)
room.set_ball_velocity(ball_velocity_x, ball_velocity_z)
room.start_game()
return ball_position_z, ball_velocity_x, ball_velocity_z
except Exception as e:
print(f"An error occurred in init_pos: {e}", file=sys.stderr)

# -----------------------> 8. reset <-----------------------
async def reset(self):
try:
room = get_room(self.room_name)
ball_position_z = random.uniform(-2.2, 2.2)
if room.ball_position["x"] < 0:
ball_velocity_x = 0.05
else:
ball_velocity_x = -0.05
ball_velocity_z = 0.05 * random.choice([-1, 1])
room.set_ball_position(0, ball_position_z)
room.set_ball_velocity(ball_velocity_x, ball_velocity_z)
return ball_position_z, ball_velocity_x, ball_velocity_z
except Exception as e:
print(f"An error occurred in reset: {e}", file=sys.stderr)

# -----------------------> 5. find_or_create_room <-----------------------
async def find_or_create_room(self, user_id):
try:
rooms_items = get_rooms_items()
for room_name, room in rooms_items:
if not room.is_ended():
if room.is_ready() and room.is_user_joined(user_id):
room.reconecting_user(self.channel_name, user_id)
await self.message({"message": "action: reconected"})
return room_name, room
elif not room.is_ready() and not room.is_user_joined(user_id):
room.add_user(self.channel_name, user_id)
await self.message({"message": "action : joined"})
return room_name, room
increment_room_index()
new_room = RoomObject()
new_room_name = f"room_{get_room_index()}"
add_room(new_room_name, new_room)
new_room.add_user(self.channel_name, user_id)
await self.message({"message": "action: created + joined"})
return new_room_name, new_room
except Exception as e:
print(f"An error occurred in find_or_create_room: {e}", file=sys.stderr)
Loading

0 comments on commit d2d181c

Please sign in to comment.