Fix audio not playing
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import "./styles.sass";
|
import "./styles.sass";
|
||||||
import {SocketContext} from "@/common/contexts/SocketContext";
|
import {SocketContext} from "@/common/contexts/SocketContext";
|
||||||
import {useContext, useState, useEffect, useRef} from "react";
|
import {useContext, useState, useEffect, useRef, useCallback} from "react";
|
||||||
import MusicSlider from "@/pages/Game/components/MusicSlider";
|
import MusicSlider from "@/pages/Game/components/MusicSlider";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
import {faMessage, faMusic, faHeadphones, faClock, faCrown} from "@fortawesome/free-solid-svg-icons";
|
import {faMessage, faMusic, faHeadphones, faClock, faCrown} from "@fortawesome/free-solid-svg-icons";
|
||||||
@ -8,9 +8,9 @@ import {faMessage, faMusic, faHeadphones, faClock, faCrown} from "@fortawesome/f
|
|||||||
export const Game = () => {
|
export const Game = () => {
|
||||||
const {send, on, socket} = useContext(SocketContext);
|
const {send, on, socket} = useContext(SocketContext);
|
||||||
|
|
||||||
const [role, setRole] = useState(null); // 'composer' or 'guesser'
|
const [role, setRole] = useState(null);
|
||||||
const [round, setRound] = useState(1);
|
const [round, setRound] = useState(1);
|
||||||
const [phase, setPhase] = useState("waiting"); // waiting, composing, guessing, results
|
const [phase, setPhase] = useState("waiting");
|
||||||
const [timeLeft, setTimeLeft] = useState(30);
|
const [timeLeft, setTimeLeft] = useState(30);
|
||||||
const [frequency, setFrequency] = useState(440);
|
const [frequency, setFrequency] = useState(440);
|
||||||
const [currentSong, setCurrentSong] = useState(null);
|
const [currentSong, setCurrentSong] = useState(null);
|
||||||
@ -20,7 +20,6 @@ export const Game = () => {
|
|||||||
const [guessResult, setGuessResult] = useState(null);
|
const [guessResult, setGuessResult] = useState(null);
|
||||||
const [isHost, setIsHost] = useState(false);
|
const [isHost, setIsHost] = useState(false);
|
||||||
|
|
||||||
// Chat state
|
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState("");
|
||||||
const [connectedUsers, setConnectedUsers] = useState([]);
|
const [connectedUsers, setConnectedUsers] = useState([]);
|
||||||
@ -29,103 +28,87 @@ export const Game = () => {
|
|||||||
const timerIntervalRef = useRef(null);
|
const timerIntervalRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPhase("waiting");
|
const eventHandlers = {
|
||||||
|
"roles-assigned": (roles) => {
|
||||||
const handleRolesAssigned = (roles) => {
|
const myRole = roles[socket?.id];
|
||||||
console.log("Roles assigned:", roles);
|
if (myRole) {
|
||||||
const myRole = roles[socket?.id];
|
setRole(myRole);
|
||||||
|
setMessages(prev => [...prev, {
|
||||||
if (myRole) {
|
system: true,
|
||||||
setRole(myRole);
|
text: myRole === "composer"
|
||||||
|
? "Du bist der Komponist! Spiele den Song mit dem Tonregler."
|
||||||
|
: "Du bist ein Rater! Höre die Frequenzen und versuche, den Song zu erkennen."
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"song-selected": setCurrentSong,
|
||||||
|
"round-started": (data) => {
|
||||||
|
setRound(data.round);
|
||||||
|
setPhase("composing");
|
||||||
|
setTimeLeft(data.timeRemaining);
|
||||||
|
},
|
||||||
|
"guessing-phase-started": (data) => {
|
||||||
|
setPhase("guessing");
|
||||||
|
setTimeLeft(data.timeRemaining);
|
||||||
|
setSongOptions(data.songOptions);
|
||||||
|
},
|
||||||
|
"guess-result": (result) => {
|
||||||
|
setGuessResult(result.isCorrect);
|
||||||
|
setCurrentSong(result.correctSong);
|
||||||
|
},
|
||||||
|
"round-results": (results) => {
|
||||||
|
setPhase("results");
|
||||||
|
setScores(results.scores);
|
||||||
|
if (!currentSong) {
|
||||||
|
setCurrentSong(results.selectedSong);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"room-users-update": (users) => {
|
||||||
|
setConnectedUsers(users);
|
||||||
|
const currentUser = users.find(u => u.id === socket?.id);
|
||||||
|
if (currentUser) setUsername(currentUser.name);
|
||||||
|
},
|
||||||
|
"host-status": (status) => setIsHost(status.isHost),
|
||||||
|
"chat-message": (msg) => setMessages(prev => [...prev, msg]),
|
||||||
|
"user-connected": (userData) => {
|
||||||
setMessages(prev => [...prev, {
|
setMessages(prev => [...prev, {
|
||||||
system: true,
|
system: true,
|
||||||
text: myRole === "composer"
|
text: `${userData.name} ist beigetreten`
|
||||||
? "Du bist der Komponist! Spiele den Song mit dem Tonregler."
|
|
||||||
: "Du bist ein Rater! Höre die Frequenzen und versuche, den Song zu erkennen."
|
|
||||||
}]);
|
}]);
|
||||||
} else {
|
setConnectedUsers(prev => [...prev, userData]);
|
||||||
console.error("No role assigned to this player!");
|
},
|
||||||
|
"user-disconnected": (userId) => {
|
||||||
|
setConnectedUsers(prev => {
|
||||||
|
const user = prev.find(u => u.id === userId);
|
||||||
|
if (user) {
|
||||||
|
setMessages(prevMsgs => [...prevMsgs, {
|
||||||
|
system: true,
|
||||||
|
text: `${user.name} hat den Raum verlassen`
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
return prev.filter(u => u.id !== userId);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"frequency-update": (data) => {
|
||||||
|
if (phase === "composing") {
|
||||||
|
console.log("Received frequency update:", data.frequency);
|
||||||
|
setFrequency(data.frequency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSongSelected = (song) => {
|
const cleanupFunctions = Object.entries(eventHandlers).map(
|
||||||
console.log("Song selected:", song);
|
([event, handler]) => on(event, handler)
|
||||||
setCurrentSong(song);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoundStarted = (data) => {
|
|
||||||
console.log("Round started:", data);
|
|
||||||
setRound(data.round);
|
|
||||||
setPhase("composing");
|
|
||||||
setTimeLeft(data.timeRemaining);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleGuessingPhaseStarted = (data) => {
|
|
||||||
console.log("Guessing phase started:", data);
|
|
||||||
setPhase("guessing");
|
|
||||||
setTimeLeft(data.timeRemaining);
|
|
||||||
setSongOptions(data.songOptions);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleGuessResult = (result) => {
|
|
||||||
console.log("Guess result:", result);
|
|
||||||
setGuessResult(result.isCorrect);
|
|
||||||
setCurrentSong(result.correctSong);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoundResults = (results) => {
|
|
||||||
console.log("Round results:", results);
|
|
||||||
setPhase("results");
|
|
||||||
setScores(results.scores);
|
|
||||||
if (!currentSong) {
|
|
||||||
setCurrentSong(results.selectedSong);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomUsers = (users) => {
|
|
||||||
console.log("Room users:", users);
|
|
||||||
setConnectedUsers(users);
|
|
||||||
|
|
||||||
const currentUser = users.find(u => u.id === socket?.id);
|
|
||||||
if (currentUser) {
|
|
||||||
setUsername(currentUser.name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleHostStatus = (status) => {
|
|
||||||
setIsHost(status.isHost);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanupRolesAssigned = on("roles-assigned", handleRolesAssigned);
|
|
||||||
const cleanupSongSelected = on("song-selected", handleSongSelected);
|
|
||||||
const cleanupRoundStarted = on("round-started", handleRoundStarted);
|
|
||||||
const cleanupGuessingPhaseStarted = on("guessing-phase-started", handleGuessingPhaseStarted);
|
|
||||||
const cleanupGuessResult = on("guess-result", handleGuessResult);
|
|
||||||
const cleanupRoundResults = on("round-results", handleRoundResults);
|
|
||||||
const cleanupRoomUsers = on("room-users-update", handleRoomUsers);
|
|
||||||
const cleanupHostStatus = on("host-status", handleHostStatus);
|
|
||||||
|
|
||||||
send("get-room-users");
|
send("get-room-users");
|
||||||
|
|
||||||
send("check-host-status");
|
send("check-host-status");
|
||||||
|
|
||||||
return () => {
|
return () => cleanupFunctions.forEach(cleanup => cleanup());
|
||||||
cleanupRolesAssigned();
|
}, [socket, on, send, role, currentSong, phase]);
|
||||||
cleanupSongSelected();
|
|
||||||
cleanupRoundStarted();
|
|
||||||
cleanupGuessingPhaseStarted();
|
|
||||||
cleanupGuessResult();
|
|
||||||
cleanupRoundResults();
|
|
||||||
cleanupRoomUsers();
|
|
||||||
cleanupHostStatus();
|
|
||||||
};
|
|
||||||
}, [socket, on, send]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (timerIntervalRef.current) {
|
if (timerIntervalRef.current) clearInterval(timerIntervalRef.current);
|
||||||
clearInterval(timerIntervalRef.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phase !== "waiting" && phase !== "results") {
|
if (phase !== "waiting" && phase !== "results") {
|
||||||
timerIntervalRef.current = setInterval(() => {
|
timerIntervalRef.current = setInterval(() => {
|
||||||
@ -134,92 +117,43 @@ export const Game = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (timerIntervalRef.current) {
|
if (timerIntervalRef.current) clearInterval(timerIntervalRef.current);
|
||||||
clearInterval(timerIntervalRef.current);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}, [phase]);
|
}, [phase]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleChatMessage = (messageData) => {
|
|
||||||
setMessages(prev => [...prev, messageData]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserConnected = (userData) => {
|
|
||||||
setMessages(prev => [...prev, {
|
|
||||||
system: true,
|
|
||||||
text: `${userData.name} ist beigetreten`
|
|
||||||
}]);
|
|
||||||
setConnectedUsers(prev => [...prev, userData]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserDisconnected = (userId) => {
|
|
||||||
setConnectedUsers(prev => {
|
|
||||||
const user = prev.find(u => u.id === userId);
|
|
||||||
if (user) {
|
|
||||||
setMessages(prevMsgs => [...prevMsgs, {
|
|
||||||
system: true,
|
|
||||||
text: `${user.name} hat den Raum verlassen`
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
return prev.filter(u => u.id !== userId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFrequencyUpdate = (data) => {
|
|
||||||
if (role === "guesser") {
|
|
||||||
setFrequency(data.frequency);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanupChatMessage = on("chat-message", handleChatMessage);
|
|
||||||
const cleanupUserConnected = on("user-connected", handleUserConnected);
|
|
||||||
const cleanupUserDisconnected = on("user-disconnected", handleUserDisconnected);
|
|
||||||
const cleanupFrequencyUpdate = on("frequency-update", handleFrequencyUpdate);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cleanupChatMessage();
|
|
||||||
cleanupUserConnected();
|
|
||||||
cleanupUserDisconnected();
|
|
||||||
cleanupFrequencyUpdate();
|
|
||||||
};
|
|
||||||
}, [on, role]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messageEndRef.current?.scrollIntoView({behavior: "smooth"});
|
messageEndRef.current?.scrollIntoView({behavior: "smooth"});
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const handleFrequencyChange = (newFrequency) => {
|
const handleFrequencyChange = useCallback((newFrequency) => {
|
||||||
setFrequency(newFrequency);
|
setFrequency(newFrequency);
|
||||||
if (role === "composer") {
|
if (role === "composer") {
|
||||||
send("submit-frequency", { frequency: newFrequency });
|
send("submit-frequency", { frequency: newFrequency });
|
||||||
}
|
}
|
||||||
};
|
}, [role, send]);
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
const handleSendMessage = useCallback(() => {
|
||||||
if (inputValue.trim()) {
|
if (inputValue.trim()) {
|
||||||
const messageData = {
|
const messageData = { text: inputValue, sender: username };
|
||||||
text: inputValue,
|
|
||||||
sender: username
|
|
||||||
};
|
|
||||||
send("send-message", messageData);
|
send("send-message", messageData);
|
||||||
setMessages(prev => [...prev, messageData]);
|
setMessages(prev => [...prev, messageData]);
|
||||||
setInputValue("");
|
setInputValue("");
|
||||||
}
|
}
|
||||||
};
|
}, [inputValue, username, send]);
|
||||||
|
|
||||||
const handleSongSelect = (song) => {
|
const handleSongSelect = useCallback((song) => {
|
||||||
setSelectedSong(song);
|
setSelectedSong(song);
|
||||||
};
|
send("submit-guess", { songId: song.id });
|
||||||
|
}, [send]);
|
||||||
|
|
||||||
const handleNextRound = () => {
|
const handleNextRound = useCallback(() => {
|
||||||
send("next-round");
|
send("next-round");
|
||||||
|
|
||||||
setSelectedSong(null);
|
setSelectedSong(null);
|
||||||
setGuessResult(null);
|
setGuessResult(null);
|
||||||
setTimeLeft(0);
|
setTimeLeft(0);
|
||||||
};
|
}, [send]);
|
||||||
|
|
||||||
|
// Phase-specific content rendering
|
||||||
const renderPhaseContent = () => {
|
const renderPhaseContent = () => {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case "waiting":
|
case "waiting":
|
||||||
@ -273,13 +207,11 @@ export const Game = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{role === "composer" && (
|
{role === "composer" ? (
|
||||||
<div className="waiting-for-guessers">
|
<div className="waiting-for-guessers">
|
||||||
<p>Die Rater versuchen nun, deinen Song zu erraten...</p>
|
<p>Die Rater versuchen nun, deinen Song zu erraten...</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
|
|
||||||
{role === "guesser" && (
|
|
||||||
<div className="song-options">
|
<div className="song-options">
|
||||||
<p className="instruction">Welchen Song hat der Komponist gespielt?</p>
|
<p className="instruction">Welchen Song hat der Komponist gespielt?</p>
|
||||||
<div className="song-grid">
|
<div className="song-grid">
|
||||||
@ -308,13 +240,11 @@ export const Game = () => {
|
|||||||
<h3>Runde {round}: Ergebnisse</h3>
|
<h3>Runde {round}: Ergebnisse</h3>
|
||||||
|
|
||||||
<div className="round-results">
|
<div className="round-results">
|
||||||
{role === "composer" && (
|
{role === "composer" ? (
|
||||||
<div className="composer-results">
|
<div className="composer-results">
|
||||||
<p>Die Rater haben versucht, deinen Song zu erraten.</p>
|
<p>Die Rater haben versucht, deinen Song zu erraten.</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
|
|
||||||
{role === "guesser" && (
|
|
||||||
<div className="guesser-results">
|
<div className="guesser-results">
|
||||||
{currentSong && (
|
{currentSong && (
|
||||||
<div className="correct-song">
|
<div className="correct-song">
|
||||||
@ -360,12 +290,13 @@ export const Game = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isHost && (
|
{isHost ? (
|
||||||
<button className="next-round-button" onClick={handleNextRound}>
|
<button className="next-round-button" onClick={handleNextRound}>
|
||||||
Nächste Runde
|
Nächste Runde
|
||||||
</button>
|
</button>
|
||||||
|
) : (
|
||||||
|
<p className="waiting-message">Warten auf Rundenwechsel durch Host...</p>
|
||||||
)}
|
)}
|
||||||
{!isHost && <p className="waiting-message">Warten auf Rundenwechsel durch Host...</p>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -424,11 +355,16 @@ export const Game = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MusicSlider
|
{/* Only render MusicSlider during composing phase */}
|
||||||
isReadOnly={role !== "composer" || phase !== "composing"}
|
{phase === "composing" && (
|
||||||
onFrequencyChange={handleFrequencyChange}
|
<MusicSlider
|
||||||
frequency={frequency}
|
isReadOnly={role !== "composer"}
|
||||||
/>
|
onFrequencyChange={handleFrequencyChange}
|
||||||
|
frequency={frequency}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default Game;
|
@ -9,30 +9,67 @@ export const MusicSlider = ({ isReadOnly = false, onFrequencyChange, frequency:
|
|||||||
const oscillatorRef = useRef(null);
|
const oscillatorRef = useRef(null);
|
||||||
const gainNodeRef = useRef(null);
|
const gainNodeRef = useRef(null);
|
||||||
const sliderRef = useRef(null);
|
const sliderRef = useRef(null);
|
||||||
|
const hasInteractedRef = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initAudioContext = () => {
|
||||||
|
if (!audioContextRef.current && !hasInteractedRef.current) {
|
||||||
|
hasInteractedRef.current = true;
|
||||||
|
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
if (!oscillatorRef.current) {
|
||||||
|
startAudio();
|
||||||
|
}
|
||||||
|
document.removeEventListener('click', initAudioContext);
|
||||||
|
document.removeEventListener('touchstart', initAudioContext);
|
||||||
|
document.removeEventListener('keydown', initAudioContext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', initAudioContext);
|
||||||
|
document.addEventListener('touchstart', initAudioContext);
|
||||||
|
document.addEventListener('keydown', initAudioContext);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', initAudioContext);
|
||||||
|
document.removeEventListener('touchstart', initAudioContext);
|
||||||
|
document.removeEventListener('keydown', initAudioContext);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (externalFrequency !== undefined && !dragging) {
|
if (externalFrequency !== undefined && !dragging) {
|
||||||
setFrequency(externalFrequency);
|
setFrequency(externalFrequency);
|
||||||
|
|
||||||
if (!isPlaying && !isReadOnly) {
|
if (audioContextRef.current) {
|
||||||
startAudio();
|
if (!isPlaying) {
|
||||||
|
startAudio();
|
||||||
|
} else if (oscillatorRef.current) {
|
||||||
|
oscillatorRef.current.frequency.setValueAtTime(
|
||||||
|
externalFrequency,
|
||||||
|
audioContextRef.current.currentTime
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [externalFrequency, dragging, isPlaying, isReadOnly]);
|
}, [externalFrequency, dragging, isPlaying]);
|
||||||
|
|
||||||
const handleMouseDown = (e) => {
|
const handleMouseDown = (e) => {
|
||||||
if (isReadOnly) return;
|
if (isReadOnly) return;
|
||||||
|
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
startAudio();
|
|
||||||
handleFrequencyChange(e);
|
handleFrequencyChange(e);
|
||||||
|
|
||||||
|
if (!audioContextRef.current) {
|
||||||
|
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPlaying) {
|
||||||
|
startAudio();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
if (!isReadOnly) {
|
|
||||||
stopAudio();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFrequencyChange = (e) => {
|
const handleFrequencyChange = (e) => {
|
||||||
@ -63,51 +100,89 @@ export const MusicSlider = ({ isReadOnly = false, onFrequencyChange, frequency:
|
|||||||
}, [dragging]);
|
}, [dragging]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying && oscillatorRef.current && audioContextRef.current) {
|
||||||
if (oscillatorRef.current) {
|
oscillatorRef.current.frequency.setValueAtTime(
|
||||||
oscillatorRef.current.frequency.setValueAtTime(frequency, audioContextRef.current.currentTime);
|
frequency,
|
||||||
}
|
audioContextRef.current.currentTime
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [frequency, isPlaying]);
|
}, [frequency, isPlaying]);
|
||||||
|
|
||||||
const startAudio = () => {
|
const startAudio = () => {
|
||||||
if (!audioContextRef.current) {
|
if (!audioContextRef.current) {
|
||||||
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
|
try {
|
||||||
|
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("AudioContext could not be created:", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!oscillatorRef.current) {
|
|
||||||
oscillatorRef.current = audioContextRef.current.createOscillator();
|
|
||||||
oscillatorRef.current.type = 'sine';
|
|
||||||
oscillatorRef.current.frequency.setValueAtTime(frequency, audioContextRef.current.currentTime);
|
|
||||||
|
|
||||||
gainNodeRef.current = audioContextRef.current.createGain();
|
if (audioContextRef.current.state === 'suspended') {
|
||||||
gainNodeRef.current.gain.setValueAtTime(0.5, audioContextRef.current.currentTime);
|
audioContextRef.current.resume().catch(err => {
|
||||||
|
console.error("Could not resume AudioContext:", err);
|
||||||
oscillatorRef.current.connect(gainNodeRef.current);
|
});
|
||||||
gainNodeRef.current.connect(audioContextRef.current.destination);
|
}
|
||||||
oscillatorRef.current.start();
|
|
||||||
} else {
|
try {
|
||||||
oscillatorRef.current.frequency.setValueAtTime(frequency, audioContextRef.current.currentTime);
|
if (!oscillatorRef.current) {
|
||||||
|
oscillatorRef.current = audioContextRef.current.createOscillator();
|
||||||
|
oscillatorRef.current.type = 'sine';
|
||||||
|
oscillatorRef.current.frequency.setValueAtTime(
|
||||||
|
frequency,
|
||||||
|
audioContextRef.current.currentTime
|
||||||
|
);
|
||||||
|
|
||||||
|
gainNodeRef.current = audioContextRef.current.createGain();
|
||||||
|
gainNodeRef.current.gain.setValueAtTime(0.5, audioContextRef.current.currentTime);
|
||||||
|
|
||||||
|
oscillatorRef.current.connect(gainNodeRef.current);
|
||||||
|
gainNodeRef.current.connect(audioContextRef.current.destination);
|
||||||
|
oscillatorRef.current.start();
|
||||||
|
console.log("Audio started successfully");
|
||||||
|
} else {
|
||||||
|
oscillatorRef.current.frequency.setValueAtTime(
|
||||||
|
frequency,
|
||||||
|
audioContextRef.current.currentTime
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setIsPlaying(true);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error starting audio:", e);
|
||||||
}
|
}
|
||||||
setIsPlaying(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopAudio = () => {
|
const stopAudio = () => {
|
||||||
if (oscillatorRef.current) {
|
if (oscillatorRef.current) {
|
||||||
oscillatorRef.current.stop();
|
try {
|
||||||
oscillatorRef.current.disconnect();
|
oscillatorRef.current.stop();
|
||||||
oscillatorRef.current = null;
|
oscillatorRef.current.disconnect();
|
||||||
|
oscillatorRef.current = null;
|
||||||
|
setIsPlaying(false);
|
||||||
|
console.log("Audio stopped");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error stopping audio:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsPlaying(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (oscillatorRef.current) {
|
if (oscillatorRef.current) {
|
||||||
oscillatorRef.current.stop();
|
try {
|
||||||
oscillatorRef.current.disconnect();
|
oscillatorRef.current.stop();
|
||||||
|
oscillatorRef.current.disconnect();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error cleaning up oscillator:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
|
if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
|
||||||
audioContextRef.current.close();
|
try {
|
||||||
|
audioContextRef.current.close();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error closing AudioContext:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
@ -137,5 +212,5 @@ export const MusicSlider = ({ isReadOnly = false, onFrequencyChange, frequency:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
@ -1,12 +1,17 @@
|
|||||||
const roomController = require('./room');
|
const roomController = require('./room');
|
||||||
|
|
||||||
const SONGS = [
|
const SONGS = [
|
||||||
{ id: 1, title: "Black Steam", artist: "Carrot Quest GmbH", coverUrl: "https://mir-s3-cdn-cf.behance.net/project_modules/1400/fe529a64193929.5aca8500ba9ab.jpg" },
|
{
|
||||||
{ id: 2, title: "Sunset Dreams", artist: "Ocean Waves", coverUrl: "https://place-hold.it/500x500/" },
|
id: 1,
|
||||||
{ id: 3, title: "Neon Nights", artist: "Electric Avenue", coverUrl: "https://place-hold.it/500x500/" },
|
title: "Black Steam",
|
||||||
{ id: 4, title: "Mountain Echo", artist: "Wild Terrain", coverUrl: "https://place-hold.it/500x500/" },
|
artist: "Carrot Quest GmbH",
|
||||||
{ id: 5, title: "Urban Jungle", artist: "City Dwellers", coverUrl: "https://place-hold.it/500x500/" },
|
coverUrl: "https://mir-s3-cdn-cf.behance.net/project_modules/1400/fe529a64193929.5aca8500ba9ab.jpg"
|
||||||
{ id: 6, title: "Cosmic Journey", artist: "Stargazers", coverUrl: "https://place-hold.it/500x500/" }
|
},
|
||||||
|
{id: 2, title: "Sunset Dreams", artist: "Ocean Waves", coverUrl: "https://place-hold.it/500x500/"},
|
||||||
|
{id: 3, title: "Neon Nights", artist: "Electric Avenue", coverUrl: "https://place-hold.it/500x500/"},
|
||||||
|
{id: 4, title: "Mountain Echo", artist: "Wild Terrain", coverUrl: "https://place-hold.it/500x500/"},
|
||||||
|
{id: 5, title: "Urban Jungle", artist: "City Dwellers", coverUrl: "https://place-hold.it/500x500/"},
|
||||||
|
{id: 6, title: "Cosmic Journey", artist: "Stargazers", coverUrl: "https://place-hold.it/500x500/"}
|
||||||
];
|
];
|
||||||
|
|
||||||
const gameStates = {};
|
const gameStates = {};
|
||||||
@ -43,47 +48,50 @@ const startNewRound = (roomId) => {
|
|||||||
const gameState = gameStates[roomId];
|
const gameState = gameStates[roomId];
|
||||||
if (!gameState) return false;
|
if (!gameState) return false;
|
||||||
|
|
||||||
|
const users = roomController.getRoomUsers(roomId);
|
||||||
|
if (users.length < 2) return false;
|
||||||
|
|
||||||
gameState.round += 1;
|
gameState.round += 1;
|
||||||
gameState.phase = 'composing';
|
gameState.phase = 'composing';
|
||||||
gameState.guessResults = {};
|
gameState.guessResults = {};
|
||||||
gameState.roundStartTime = Date.now();
|
gameState.roundStartTime = Date.now();
|
||||||
|
|
||||||
const users = roomController.getRoomUsers(roomId);
|
|
||||||
if (users.length < 2) return false;
|
|
||||||
|
|
||||||
console.log(`Starting round ${gameState.round} in room ${roomId} with ${users.length} users`);
|
|
||||||
|
|
||||||
gameState.roles = {};
|
gameState.roles = {};
|
||||||
|
|
||||||
if (gameState.round === 1 || !gameState.currentComposer) {
|
gameState.currentComposer = determineNextComposer(roomId, gameState, users);
|
||||||
const composerIndex = Math.floor(Math.random() * users.length);
|
|
||||||
gameState.currentComposer = users[composerIndex].id;
|
|
||||||
} else {
|
|
||||||
const currentIndex = users.findIndex(user => user.id === gameState.currentComposer);
|
|
||||||
|
|
||||||
if (currentIndex === -1) {
|
|
||||||
const composerIndex = Math.floor(Math.random() * users.length);
|
|
||||||
gameState.currentComposer = users[composerIndex].id;
|
|
||||||
} else {
|
|
||||||
const nextIndex = (currentIndex + 1) % users.length;
|
|
||||||
gameState.currentComposer = users[nextIndex].id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
users.forEach(user => {
|
users.forEach(user => {
|
||||||
gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser';
|
gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser';
|
||||||
console.log(`User ${user.name} (${user.id}) assigned role: ${gameState.roles[user.id]}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
selectSongAndOptions(gameState);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const determineNextComposer = (roomId, gameState, users) => {
|
||||||
|
if (gameState.round === 1 || !gameState.currentComposer) {
|
||||||
|
return users[Math.floor(Math.random() * users.length)].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentIndex = users.findIndex(user => user.id === gameState.currentComposer);
|
||||||
|
|
||||||
|
if (currentIndex === -1) {
|
||||||
|
return users[Math.floor(Math.random() * users.length)].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return users[(currentIndex + 1) % users.length].id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectSongAndOptions = (gameState) => {
|
||||||
gameState.selectedSong = SONGS[Math.floor(Math.random() * SONGS.length)];
|
gameState.selectedSong = SONGS[Math.floor(Math.random() * SONGS.length)];
|
||||||
|
|
||||||
const songOptions = [...SONGS].sort(() => Math.random() - 0.5).slice(0, 5);
|
const songOptions = [...SONGS].sort(() => Math.random() - 0.5).slice(0, 5);
|
||||||
|
|
||||||
if (!songOptions.includes(gameState.selectedSong)) {
|
if (!songOptions.includes(gameState.selectedSong)) {
|
||||||
songOptions[Math.floor(Math.random() * songOptions.length)] = gameState.selectedSong;
|
songOptions[Math.floor(Math.random() * songOptions.length)] = gameState.selectedSong;
|
||||||
}
|
}
|
||||||
gameState.songOptions = songOptions;
|
|
||||||
|
|
||||||
return true;
|
gameState.songOptions = songOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTimeRemaining = (roomId) => {
|
const getTimeRemaining = (roomId) => {
|
||||||
@ -121,37 +129,36 @@ const updateFrequency = (roomId, frequency) => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCurrentFrequency = (roomId) => {
|
|
||||||
return gameStates[roomId]?.lastFrequency || 440;
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitGuess = (roomId, userId, songId) => {
|
const submitGuess = (roomId, userId, songId) => {
|
||||||
const gameState = gameStates[roomId];
|
const gameState = gameStates[roomId];
|
||||||
if (!gameState || gameState.phase !== 'guessing' || gameState.roles[userId] !== 'guesser') {
|
if (!gameState || gameState.phase !== 'guessing' || gameState.roles[userId] !== 'guesser') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCorrect = gameState.selectedSong.id === songId;
|
const isCorrect = gameState.selectedSong.id === parseInt(songId);
|
||||||
gameState.guessResults[userId] = {
|
const points = isCorrect ? 10 : 0;
|
||||||
songId,
|
|
||||||
isCorrect,
|
gameState.guessResults[userId] = {songId, isCorrect, points};
|
||||||
points: isCorrect ? 10 : 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isCorrect) {
|
if (isCorrect) {
|
||||||
gameState.scores[userId] = (gameState.scores[userId] || 0) + 10;
|
gameState.scores[userId] = (gameState.scores[userId] || 0) + points;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isCorrect,
|
isCorrect,
|
||||||
correctSong: gameState.selectedSong,
|
correctSong: gameState.selectedSong,
|
||||||
points: isCorrect ? 10 : 0
|
points
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCurrentFrequency = (roomId) => gameStates[roomId]?.lastFrequency || 440;
|
||||||
|
const getRoles = (roomId) => gameStates[roomId]?.roles || {};
|
||||||
|
const getUserRole = (roomId, userId) => gameStates[roomId]?.roles[userId] || null;
|
||||||
|
const getSongOptions = (roomId) => gameStates[roomId]?.songOptions || [];
|
||||||
|
const getSelectedSong = (roomId) => gameStates[roomId]?.selectedSong || null;
|
||||||
const getRoundResults = (roomId) => {
|
const getRoundResults = (roomId) => {
|
||||||
const gameState = gameStates[roomId];
|
const gameState = gameStates[roomId];
|
||||||
if (!gameState) return null;
|
if (!gameState) return {round: 0, scores: {}, guessResults: {}, selectedSong: null};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
round: gameState.round,
|
round: gameState.round,
|
||||||
@ -161,22 +168,6 @@ const getRoundResults = (roomId) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRoles = (roomId) => {
|
|
||||||
return gameStates[roomId]?.roles || {};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUserRole = (roomId, userId) => {
|
|
||||||
return gameStates[roomId]?.roles[userId] || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSongOptions = (roomId) => {
|
|
||||||
return gameStates[roomId]?.songOptions || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSelectedSong = (roomId) => {
|
|
||||||
return gameStates[roomId]?.selectedSong || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanupGameState = (roomId) => {
|
const cleanupGameState = (roomId) => {
|
||||||
delete gameStates[roomId];
|
delete gameStates[roomId];
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,6 @@ const gameController = require("../controller/game");
|
|||||||
module.exports = (io) => (socket) => {
|
module.exports = (io) => (socket) => {
|
||||||
let currentRoomId = null;
|
let currentRoomId = null;
|
||||||
let currentUser = null;
|
let currentUser = null;
|
||||||
|
|
||||||
let phaseTimers = {};
|
let phaseTimers = {};
|
||||||
|
|
||||||
const clearRoomTimers = (roomId) => {
|
const clearRoomTimers = (roomId) => {
|
||||||
@ -22,58 +21,71 @@ module.exports = (io) => (socket) => {
|
|||||||
phaseTimers[roomId] = setTimeout(() => {
|
phaseTimers[roomId] = setTimeout(() => {
|
||||||
const advanced = gameController.advancePhase(roomId);
|
const advanced = gameController.advancePhase(roomId);
|
||||||
|
|
||||||
if (advanced) {
|
if (!advanced) return;
|
||||||
|
|
||||||
|
if (typeof advanced === 'boolean') {
|
||||||
|
handleRoundStart(roomId);
|
||||||
|
} else {
|
||||||
const currentPhase = advanced.phase || 'results';
|
const currentPhase = advanced.phase || 'results';
|
||||||
|
|
||||||
if (currentPhase === 'guessing') {
|
if (currentPhase === 'guessing') {
|
||||||
const roles = gameController.getRoles(roomId);
|
handleGuessingPhaseStart(roomId);
|
||||||
const songOptions = gameController.getSongOptions(roomId);
|
} else if (currentPhase === 'results') {
|
||||||
const timeLeft = gameController.getTimeRemaining(roomId);
|
handleResultsPhaseStart(roomId);
|
||||||
|
|
||||||
Object.entries(roles).forEach(([userId, role]) => {
|
|
||||||
if (role === 'guesser') {
|
|
||||||
io.to(userId).emit('guessing-phase-started', {
|
|
||||||
timeRemaining: timeLeft,
|
|
||||||
songOptions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
startPhaseTimer(roomId);
|
|
||||||
}
|
|
||||||
else if (currentPhase === 'results') {
|
|
||||||
const results = gameController.getRoundResults(roomId);
|
|
||||||
io.to(roomId).emit('round-results', results);
|
|
||||||
}
|
|
||||||
else if (typeof advanced === 'boolean' && advanced) {
|
|
||||||
const roles = gameController.getRoles(roomId);
|
|
||||||
const selectedSong = gameController.getSelectedSong(roomId);
|
|
||||||
const timeLeft = gameController.getTimeRemaining(roomId);
|
|
||||||
|
|
||||||
io.to(roomId).emit('roles-assigned', roles);
|
|
||||||
|
|
||||||
Object.entries(roles).forEach(([userId, role]) => {
|
|
||||||
if (role === 'composer') {
|
|
||||||
io.to(userId).emit('song-selected', selectedSong);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
io.to(roomId).emit('round-started', {
|
|
||||||
round: gameController.getRoundResults(roomId).round,
|
|
||||||
timeRemaining: timeLeft
|
|
||||||
});
|
|
||||||
|
|
||||||
startPhaseTimer(roomId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, timeRemaining);
|
}, timeRemaining);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRoundStart = (roomId) => {
|
||||||
|
const roles = gameController.getRoles(roomId);
|
||||||
|
const selectedSong = gameController.getSelectedSong(roomId);
|
||||||
|
const timeLeft = gameController.getTimeRemaining(roomId);
|
||||||
|
|
||||||
|
io.to(roomId).emit('roles-assigned', roles);
|
||||||
|
|
||||||
|
Object.entries(roles).forEach(([userId, role]) => {
|
||||||
|
if (role === 'composer') {
|
||||||
|
io.to(userId).emit('song-selected', selectedSong);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io.to(roomId).emit('round-started', {
|
||||||
|
round: gameController.getRoundResults(roomId).round,
|
||||||
|
timeRemaining: timeLeft
|
||||||
|
});
|
||||||
|
|
||||||
|
startPhaseTimer(roomId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGuessingPhaseStart = (roomId) => {
|
||||||
|
const roles = gameController.getRoles(roomId);
|
||||||
|
const songOptions = gameController.getSongOptions(roomId);
|
||||||
|
const timeLeft = gameController.getTimeRemaining(roomId);
|
||||||
|
|
||||||
|
Object.entries(roles).forEach(([userId, role]) => {
|
||||||
|
if (role === 'guesser') {
|
||||||
|
io.to(userId).emit('guessing-phase-started', {
|
||||||
|
timeRemaining: timeLeft,
|
||||||
|
songOptions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
startPhaseTimer(roomId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResultsPhaseStart = (roomId) => {
|
||||||
|
const results = gameController.getRoundResults(roomId);
|
||||||
|
io.to(roomId).emit('round-results', results);
|
||||||
|
};
|
||||||
|
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
const roomId = roomController.getUserRoom(socket.id);
|
const roomId = roomController.getUserRoom(socket.id);
|
||||||
if (roomId) socket.to(roomId).emit("user-disconnected", socket.id);
|
if (roomId) {
|
||||||
|
socket.to(roomId).emit("user-disconnected", socket.id);
|
||||||
roomController.disconnectUser(socket.id);
|
roomController.disconnectUser(socket.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("join-room", ({roomId, name}) => {
|
socket.on("join-room", ({roomId, name}) => {
|
||||||
@ -92,7 +104,6 @@ module.exports = (io) => (socket) => {
|
|||||||
|
|
||||||
const users = roomController.getRoomUsers(roomId);
|
const users = roomController.getRoomUsers(roomId);
|
||||||
io.to(roomId).emit("room-users-update", users);
|
io.to(roomId).emit("room-users-update", users);
|
||||||
|
|
||||||
socket.to(roomId).emit("user-connected", currentUser);
|
socket.to(roomId).emit("user-connected", currentUser);
|
||||||
|
|
||||||
socket.emit("room-joined", roomId);
|
socket.emit("room-joined", roomId);
|
||||||
@ -104,6 +115,7 @@ module.exports = (io) => (socket) => {
|
|||||||
|
|
||||||
socket.on("create-room", ({name}) => {
|
socket.on("create-room", ({name}) => {
|
||||||
if (!name) return socket.emit("room-name-required");
|
if (!name) return socket.emit("room-name-required");
|
||||||
|
|
||||||
const roomId = Math.random().toString(36).substring(7).toUpperCase();
|
const roomId = Math.random().toString(36).substring(7).toUpperCase();
|
||||||
currentUser = {id: socket.id, name: name?.toString(), creator: true};
|
currentUser = {id: socket.id, name: name?.toString(), creator: true};
|
||||||
roomController.connectUserToRoom(roomId, currentUser);
|
roomController.connectUserToRoom(roomId, currentUser);
|
||||||
@ -114,51 +126,32 @@ module.exports = (io) => (socket) => {
|
|||||||
|
|
||||||
socket.on("start-game", () => {
|
socket.on("start-game", () => {
|
||||||
const roomId = roomController.getUserRoom(socket.id);
|
const roomId = roomController.getUserRoom(socket.id);
|
||||||
if (roomId && roomController.isUserHost(socket.id)) {
|
if (!roomId || !roomController.isUserHost(socket.id)) {
|
||||||
roomController.validateRoomMembers(io, roomId);
|
return socket.emit("not-authorized");
|
||||||
const roomUsers = roomController.getRoomUsers(roomId);
|
|
||||||
|
|
||||||
if (roomController.startGame(roomId)) {
|
|
||||||
gameController.initializeGameState(roomId);
|
|
||||||
|
|
||||||
if (gameController.startNewRound(roomId)) {
|
|
||||||
const roles = gameController.getRoles(roomId);
|
|
||||||
const selectedSong = gameController.getSelectedSong(roomId);
|
|
||||||
|
|
||||||
io.to(roomId).emit("game-started");
|
|
||||||
|
|
||||||
io.to(roomId).emit("roles-assigned", roles);
|
|
||||||
|
|
||||||
Object.entries(roles).forEach(([userId, role]) => {
|
|
||||||
if (role === 'composer') {
|
|
||||||
io.to(userId).emit("song-selected", selectedSong);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
io.to(roomId).emit("round-started", {
|
|
||||||
round: 1,
|
|
||||||
timeRemaining: gameController.getTimeRemaining(roomId)
|
|
||||||
});
|
|
||||||
|
|
||||||
startPhaseTimer(roomId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
socket.emit("not-authorized");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roomController.validateRoomMembers(io, roomId);
|
||||||
|
const users = roomController.getRoomUsers(roomId);
|
||||||
|
|
||||||
|
if (users.length < 2) {
|
||||||
|
return socket.emit("error", { message: "At least 2 players are required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!roomController.startGame(roomId)) return;
|
||||||
|
gameController.initializeGameState(roomId);
|
||||||
|
if (!gameController.startNewRound(roomId)) return;
|
||||||
|
|
||||||
|
io.to(roomId).emit("game-started");
|
||||||
|
handleRoundStart(roomId);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("send-message", (messageData) => {
|
socket.on("send-message", (messageData) => {
|
||||||
const roomId = roomController.getUserRoom(socket.id);
|
const roomId = roomController.getUserRoom(socket.id);
|
||||||
if (roomId) {
|
if (roomId) socket.to(roomId).emit("chat-message", messageData);
|
||||||
socket.to(roomId).emit("chat-message", messageData);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("get-user-info", () => {
|
socket.on("get-user-info", () => {
|
||||||
if (currentUser) {
|
if (currentUser) socket.emit("user-info", currentUser);
|
||||||
socket.emit("user-info", currentUser);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("get-room-users", () => {
|
socket.on("get-room-users", () => {
|
||||||
@ -170,14 +163,11 @@ module.exports = (io) => (socket) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("check-host-status", () => {
|
socket.on("check-host-status", () => {
|
||||||
const isHost = roomController.isUserHost(socket.id);
|
socket.emit("host-status", { isHost: roomController.isUserHost(socket.id) });
|
||||||
socket.emit("host-status", { isHost });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("get-room-code", () => {
|
socket.on("get-room-code", () => {
|
||||||
if (currentRoomId) {
|
if (currentRoomId) socket.emit("room-code", currentRoomId);
|
||||||
socket.emit("room-code", currentRoomId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("submit-frequency", ({ frequency }) => {
|
socket.on("submit-frequency", ({ frequency }) => {
|
||||||
@ -185,10 +175,10 @@ module.exports = (io) => (socket) => {
|
|||||||
if (!roomId) return;
|
if (!roomId) return;
|
||||||
|
|
||||||
const userRole = gameController.getUserRole(roomId, socket.id);
|
const userRole = gameController.getUserRole(roomId, socket.id);
|
||||||
if (userRole === 'composer') {
|
if (userRole !== 'composer') return;
|
||||||
if (gameController.updateFrequency(roomId, frequency)) {
|
|
||||||
socket.to(roomId).emit("frequency-update", { frequency });
|
if (gameController.updateFrequency(roomId, frequency)) {
|
||||||
}
|
socket.to(roomId).emit("frequency-update", { frequency });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -197,9 +187,7 @@ module.exports = (io) => (socket) => {
|
|||||||
if (!roomId) return;
|
if (!roomId) return;
|
||||||
|
|
||||||
const result = gameController.submitGuess(roomId, socket.id, songId);
|
const result = gameController.submitGuess(roomId, socket.id, songId);
|
||||||
if (result) {
|
if (result) socket.emit("guess-result", result);
|
||||||
socket.emit("guess-result", result);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("next-round", () => {
|
socket.on("next-round", () => {
|
||||||
@ -207,35 +195,23 @@ module.exports = (io) => (socket) => {
|
|||||||
if (!roomId || !roomController.isUserHost(socket.id)) return;
|
if (!roomId || !roomController.isUserHost(socket.id)) return;
|
||||||
|
|
||||||
roomController.validateRoomMembers(io, roomId);
|
roomController.validateRoomMembers(io, roomId);
|
||||||
const roomUsers = roomController.getRoomUsers(roomId);
|
const users = roomController.getRoomUsers(roomId);
|
||||||
|
|
||||||
|
if (users.length < 2) {
|
||||||
|
return socket.emit("error", { message: "At least 2 players are required" });
|
||||||
|
}
|
||||||
|
|
||||||
if (gameController.startNewRound(roomId)) {
|
if (gameController.startNewRound(roomId)) {
|
||||||
const roles = gameController.getRoles(roomId);
|
handleRoundStart(roomId);
|
||||||
const selectedSong = gameController.getSelectedSong(roomId);
|
|
||||||
const timeLeft = gameController.getTimeRemaining(roomId);
|
|
||||||
|
|
||||||
io.to(roomId).emit("roles-assigned", roles);
|
|
||||||
|
|
||||||
Object.entries(roles).forEach(([userId, role]) => {
|
|
||||||
if (role === 'composer') {
|
|
||||||
io.to(userId).emit("song-selected", selectedSong);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
io.to(roomId).emit("round-started", {
|
|
||||||
round: gameController.getRoundResults(roomId).round,
|
|
||||||
timeRemaining: timeLeft
|
|
||||||
});
|
|
||||||
|
|
||||||
startPhaseTimer(roomId);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("get-current-frequency", () => {
|
socket.on("get-current-frequency", () => {
|
||||||
const roomId = roomController.getUserRoom(socket.id);
|
const roomId = roomController.getUserRoom(socket.id);
|
||||||
if (!roomId) return;
|
if (roomId) {
|
||||||
|
socket.emit("current-frequency", {
|
||||||
const frequency = gameController.getCurrentFrequency(roomId);
|
frequency: gameController.getCurrentFrequency(roomId)
|
||||||
socket.emit("current-frequency", { frequency });
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
Reference in New Issue
Block a user