added joining to room

This commit is contained in:
Wenszel 2023-11-28 18:51:50 +01:00
parent a1b39a3a45
commit f318afe071
16 changed files with 356 additions and 160 deletions

View File

@ -17,8 +17,9 @@ const getJoinableRoom = async () => {
return await Room.findOne({ full: false, started: false }).exec();
};
const createNewRoom = () => {
const room = new Room();
const createNewRoom = data => {
const room = new Room(data);
room.save();
return room;
};

View File

@ -1,17 +1,15 @@
const { getRoom, updateRoom, getJoinableRoom, createNewRoom, findPlayer } = require('../controllers/roomController');
const { getRoom, updateRoom } = require('../controllers/roomController');
const { colors } = require('../utils/constants');
module.exports = socket => {
const req = socket.request;
const handleLogin = async data => {
if (await findPlayer(req.sessionID)) return;
const room = await getJoinableRoom();
if (room) {
addPlayerToExistingRoom(room, data);
} else {
addNewRoom(data);
}
const room = await getRoom(data.roomId);
if (room.isFull()) return socket.emit('error:changeRoom');
if (room.started) return socket.emit('error:changeRoom');
if (room.private && room.password !== data.password) return socket.emit('error:wrongPassword');
addPlayerToExistingRoom(room, data);
};
const handleReady = async () => {
@ -23,13 +21,6 @@ module.exports = socket => {
await updateRoom(room);
};
const addNewRoom = async data => {
const room = createNewRoom();
room.addPlayer(data.name, req.sessionID);
await room.save();
reloadSession(room);
};
const addPlayerToExistingRoom = async (room, data) => {
room.addPlayer(data.name);
if (room.isFull()) {

View File

@ -1,10 +1,10 @@
const { getRooms, getRoom, updateRoom } = require('../controllers/roomController');
const { getRooms, getRoom, updateRoom, createNewRoom } = require('../controllers/roomController');
const { sendToOnePlayerRooms, sendToOnePlayerData, sendToPlayersData } = require('../socket/emits');
module.exports = socket => {
const req = socket.request;
const getData = async () => {
const handleGetData = async () => {
const room = await getRoom(req.session.roomId);
// Handle the situation when the server crashes and any player reconnects after the time has expired
// Typically, the responsibility for changing players is managed by gameHandler.js.
@ -15,23 +15,17 @@ module.exports = socket => {
sendToOnePlayerData(socket.id, room);
};
const getAllRooms = async () => {
const handleGetAllRooms = async () => {
let rooms = await getRooms();
const response = [];
rooms.forEach(room => {
if (!room.isStarted && !room.isFull()) {
response.push({
_id: room._id,
private: room.private,
name: room.name,
players: room.players,
isStarted: room.isStarted,
});
}
});
sendToOnePlayerRooms(socket.id, response);
sendToOnePlayerRooms(socket.id, rooms);
};
socket.on('room:data', getData);
socket.on('room:rooms', getAllRooms);
const handleCreateRoom = async data => {
createNewRoom(data);
socket.to(socket.id).emit('room:created');
};
socket.on('room:data', handleGetData);
socket.on('room:rooms', handleGetAllRooms);
socket.on('room:create', handleCreateRoom);
};

View File

@ -7,7 +7,7 @@ const PlayerSchema = require('./player');
const RoomSchema = new mongoose.Schema({
name: String,
private: { type: Boolean, default: true },
private: { type: Boolean, default: false },
password: String,
createDate: { type: Date, default: Date.now },
started: { type: Boolean, default: false },

View File

@ -0,0 +1,35 @@
.refresh {
display: flex;
margin-left: auto;
justify-content: center;
align-items: center;
width: 40px;
height: 100%;
border: 1px solid white;
}
.refresh > img {
width: 20px;
height: 20px;
cursor: pointer;
}
form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
}
.private-container {
margin-left: 10px;
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
}
input:disabled {
background-color: black;
color: #999;
border: 1px solid #ddd;
}

View File

@ -0,0 +1,58 @@
import React, { useState, useContext, useEffect } from 'react';
import './AddServer.css';
import Switch from '@material-ui/core/Switch';
import { SocketContext } from '../../../App';
const AddServer = () => {
const socket = useContext(SocketContext);
const [isPrivate, setIsPrivate] = useState(false);
const [serverName, setServerName] = useState('');
const [password, setPassword] = useState('');
useEffect(() => {
socket.on('room:created', () => {
console.log('ewa');
socket.emit('room:rooms');
});
}, []);
const handleButtonClick = e => {
e.preventDefault();
socket.emit('room:create', {
name: serverName,
private: isPrivate,
password: password,
});
};
return (
<div className='lp-container'>
<div className='title-container'>
<h1>Host A Server</h1>
</div>
<div className='content-container'>
<form>
<input
type='text'
value={serverName}
onChange={e => setServerName(e.target.value)}
placeholder='Server Name'
/>
<div className='private-container'>
<p>Private</p>
<Switch checked={isPrivate} color='primary' onChange={() => setIsPrivate(!isPrivate)} />
</div>
<input
type='text'
value={password}
onChange={e => setPassword(e.target.value)}
placeholder='password'
disabled={!isPrivate}
/>
<button onClick={handleButtonClick}>Host</button>
</form>
</div>
</div>
);
};
export default AddServer;

View File

@ -1,76 +1,53 @@
.login-page-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
height: 50%;
width: 100%;
}
.lp-container {
margin: 50px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 50vh;
width: 400px;
position: relative;
width: 500px;
padding: 20px;
border-radius: 5%;
border: 5px solid white;
background-color: rgba(0, 0, 0, 0.5);
}
h1 {
margin-right: 10px;
align-self: flex-start;
top: 0;
position: absolute;
color: white;
}
.rooms {
width: 98%;
height: 80%;
overflow-y: scroll;
overflow-x: hidden;
}
.room {
cursor: pointer;
justify-content: space-between;
.title-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: white;
width: 90%;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
.room-selected {
width: 100%;
height: 40px;
border: 1px solid white;
border-radius: 2px;
transform: scaleX(1.02);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
padding-left: 10px;
text-align: center;
}
.room-selected,
.room:hover {
background-color: rgba(0, 0, 0, 0.5);
.title-container > h1 {
width: 100%;
margin: 0;
padding: 0;
}
.number-of-players {
.content-container {
display: flex;
flex-direction: row;
align-items: center;
}
.number-of-players > img {
margin-right: 5px;
width: 20px;
height: 20px;
}
/* Firefox */
* {
scrollbar-width: auto;
scrollbar-color: #ffffff rgba(0, 0, 0, 0.1);
}
/* Chrome, Edge, and Safari */
*::-webkit-scrollbar {
width: 8px;
}
*::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0);
}
*::-webkit-scrollbar-thumb {
background-color: #ffffff;
border-radius: 10px;
border: 3px none #ffffff;
flex-direction: column;
width: 100%;
padding: 10px;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
border-left: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
}

View File

@ -1,54 +1,16 @@
import React, { useContext, useEffect, useState } from 'react';
import NameInput from './NameInput/NameInput';
import { SocketContext } from '../../App';
import './LoginPage.css';
import userImage from '../../images/login-page/user.png';
import AddServer from './AddServer/AddServer';
import ServerList from './ServerList/ServerList';
import NameInput from './NameInput/NameInput';
const LoginPage = () => {
const socket = useContext(SocketContext);
const [rooms, setRooms] = useState([]);
const [selectedRoom, setSelectedRoom] = useState(null);
useEffect(async () => {
socket.emit('room:rooms');
socket.on('room:rooms', data => {
data = JSON.parse(data);
console.log(data);
setRooms(data);
});
}, []);
return (
<div className='login-page-container'>
<h1>Select room:</h1>
<div className='rooms'>
{rooms.map(room => {
return (
<div
className={selectedRoom && selectedRoom == room._id ? 'room-selected room' : 'room'}
onClick={() => {
if (selectedRoom && selectedRoom == room._id) {
setSelectedRoom(null);
} else {
setSelectedRoom(room._id);
}
}}
key={room.id}
>
<div>
<p>{room.name}</p>
{room.players.map(player => player.name + ' ')}
</div>
<div className='number-of-players'>
<img src={userImage} alt='' />
<span> {room.players.length}/4 </span>
</div>
</div>
);
})}
<>
<div className='login-page-container'>
<ServerList />
<AddServer />
</div>
<NameInput />
</div>
</>
);
};
export default LoginPage;

View File

@ -1,11 +1,34 @@
.name-input-container {
display: flex;
position: absolute;
bottom: 0;
flex-direction: row;
width: 80%;
flex-direction: column;
padding: 10px 20px 60px 20px;
width: 300px;
background: radial-gradient(circle, rgba(0, 138, 255, 1) 5%, rgba(9, 9, 121, 1) 81%);
border: 1px solid white;
border-radius: 8px;
margin: 20px;
}
.name-input-container > button {
margin-top: 5px;
text-align: center;
width: 100px;
align-self: center;
}
.name-input-container > input {
margin-top: 10px;
}
.name-overlay {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
input,
button {
padding: 0;
@ -21,7 +44,7 @@ input {
border-radius: 8px;
color: white;
border: 1px solid #ccc;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgba(0, 0, 0, 0.2);
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
}
@ -37,7 +60,7 @@ button {
border-radius: 8px;
border: none;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgba(0, 0, 0, 0.4);
cursor: pointer;
transition: background-color 0.3s ease-in-out;
}

View File

@ -1,19 +1,44 @@
import React, { useState, useContext } from 'react';
import React, { useState, useContext, useEffect } from 'react';
import { SocketContext } from '../../../App';
import './NameInput.css';
const NameInput = () => {
const NameInput = ({ isRoomPrivate, roomId }) => {
const socket = useContext(SocketContext);
const [inputValue, setInputValue] = useState('');
const handleInputChange = e => {
setInputValue(e.target.value);
};
const [nickname, setNickname] = useState('');
const [password, setPassword] = useState('');
const [isPasswordWrong, setIsPasswordWrong] = useState(false);
const handleButtonClick = () => {
socket.emit('player:login', { name: inputValue });
socket.emit('player:login', { name: nickname, password: password, roomId: roomId });
};
useEffect(() => {
socket.on('error:wrongPassword', () => {
setIsPasswordWrong(true);
});
const keyDownHandler = event => {
if (event.key === 'Enter') {
event.preventDefault();
handleButtonClick();
}
};
document.addEventListener('keydown', keyDownHandler);
return () => {
document.removeEventListener('keydown', keyDownHandler);
};
}, []);
return (
<div className="name-input-container">
<input placeholder='Enter name' type='text' onChange={handleInputChange} />
<button onClick={handleButtonClick}>JOIN</button>
<div className='name-overlay'>
<div className='name-input-container' style={{ height: isRoomPrivate ? '100px' : '50px' }}>
<input placeholder='Nickname' type='text' onChange={e => setNickname(e.target.value)} />
{isRoomPrivate ? (
<input
placeholder='Room password'
type='text'
onChange={e => setPassword(e.target.value)}
style={{ backgroundColor: isPasswordWrong ? 'red' : null }}
/>
) : null}
<button onClick={handleButtonClick}>JOIN</button>
</div>
</div>
);
};

View File

@ -0,0 +1,51 @@
th {
text-align: left;
}
img {
margin-right: 5px;
width: 20px;
height: 20px;
}
th,
td {
padding: 8px;
text-align: left;
height: 50px;
}
tr {
max-height: 50px;
}
table {
border-collapse: collapse;
width: 100%;
}
.server-container {
display: flex;
height: 500px;
overflow: scroll;
}
.room-name {
max-width: 150px;
overflow: hidden;
}
/* Firefox */
* {
scrollbar-width: auto;
scrollbar-color: #ffffff rgba(0, 0, 0, 0.1);
}
/* Chrome, Edge, and Safari */
*::-webkit-scrollbar {
background: rgba(0, 0, 0, 0);
width: 10px;
}
*::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0);
}
*::-webkit-scrollbar-thumb {
background-color: #ffffff;
border-radius: 10px;
}

View File

@ -0,0 +1,79 @@
import React, { useContext, useEffect, useState } from 'react';
import { SocketContext } from '../../../App';
import lock from '../../../images/login-page/lock.png';
import refresh from '../../../images/login-page/refresh.png';
import ReactLoading from 'react-loading';
import './ServerList.css';
import NameInput from '../NameInput/NameInput';
const ServerList = () => {
const socket = useContext(SocketContext);
const [rooms, setRooms] = useState([]);
const [joining, setJoining] = useState(false);
const [clickedRoom, setClickedRoom] = useState(null);
useEffect(async () => {
socket.emit('room:rooms');
socket.on('room:rooms', data => {
data = JSON.parse(data);
setRooms(data);
});
}, []);
const getRooms = () => {
setRooms(null);
socket.emit('room:rooms');
};
const handleJoinClick = room => {
setClickedRoom(room);
setJoining(true);
};
return (
<div className='lp-container'>
<div className='title-container'>
<h1>Server List</h1>
<div className='refresh'>
<img src={refresh} onClick={getRooms}></img>
</div>
</div>
<div className='server-container content-container'>
{rooms ? (
<table className='rooms'>
<thead>
<tr>
<th></th>
<th>Server</th>
<th>#/#</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
{rooms.map((room, index) => (
<tr key={index}>
<td>{room.private ? <img src={lock} /> : null}</td>
<td className='room-name'>{room.name}</td>
<td>{`${room.players.length}/4`}</td>
<td>{room.isStarted ? 'started' : 'waiting'}</td>
<td>
<button onClick={() => handleJoinClick(room)}>Join</button>
</td>
</tr>
))}
</tbody>
</table>
) : (
<div style={{ alignSelf: 'center' }}>
<ReactLoading type='spinningBubbles' color='white' height={50} width={50} />
</div>
)}
</div>
{joining ? (
<NameInput roomId={clickedRoom._id} isRoomPrivate={clickedRoom.private} />
) : null}
</div>
);
};
export default ServerList;

View File

@ -14,7 +14,7 @@ const AnimatedOverlay = ({ time }) => {
in={true}
timeout={0}
classNames='overlay'
style={{ 'animation-delay': `-${animationDelay}s` }}
style={{ animationDelay: `-${animationDelay}s` }}
unmountOnExit
>
<div className='overlay'></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB