fxghjnyxdf
This commit is contained in:
parent
583566c00d
commit
5940dfb01a
@ -1,6 +1,6 @@
|
|||||||
/* ============================================================
|
/* ============================================================
|
||||||
sockets/arena.js
|
sockets/arena.js
|
||||||
Alle Socket-Events rund um 1v1 Matchmaking, Spielfeld & Bereit-System
|
Alle Socket-Events rund um 1v1 Matchmaking & 2v2 Team-Lobby
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const waitingPool = new Map(); // socketId → { socket, player }
|
const waitingPool = new Map(); // socketId → { socket, player }
|
||||||
@ -11,11 +11,15 @@ const LEVEL_RANGE = 5;
|
|||||||
const teams2v2 = new Map();
|
const teams2v2 = new Map();
|
||||||
const readyTeams = new Map(); // teamId → team (fertige Teams warten auf Matchmaking)
|
const readyTeams = new Map(); // teamId → team (fertige Teams warten auf Matchmaking)
|
||||||
|
|
||||||
|
const READY_TIMEOUT = 30; // Sekunden bis Match abgebrochen wird
|
||||||
|
|
||||||
function generateId() {
|
function generateId() {
|
||||||
return `${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
return `${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── 2v2 Lobby-Liste an alle schicken ── */
|
/* ─────────────────────────────────────────────────
|
||||||
|
HELPER: 2v2 Lobby-Liste an alle senden
|
||||||
|
───────────────────────────────────────────────── */
|
||||||
function broadcastLobbies(io) {
|
function broadcastLobbies(io) {
|
||||||
const list = [];
|
const list = [];
|
||||||
for (const [teamId, team] of teams2v2) {
|
for (const [teamId, team] of teams2v2) {
|
||||||
@ -31,7 +35,9 @@ function broadcastLobbies(io) {
|
|||||||
io.emit("2v2_lobbies", list);
|
io.emit("2v2_lobbies", list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── 2v2 Team-Status an Teammitglieder senden ── */
|
/* ─────────────────────────────────────────────────
|
||||||
|
HELPER: 2v2 Team-Status an Teammitglieder senden
|
||||||
|
───────────────────────────────────────────────── */
|
||||||
function broadcastTeamStatus(io, teamId) {
|
function broadcastTeamStatus(io, teamId) {
|
||||||
const team = teams2v2.get(teamId);
|
const team = teams2v2.get(teamId);
|
||||||
if (!team) return;
|
if (!team) return;
|
||||||
@ -49,7 +55,9 @@ function broadcastTeamStatus(io, teamId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── 2v2 Matchmaking ── */
|
/* ─────────────────────────────────────────────────
|
||||||
|
HELPER: 2v2 Matchmaking
|
||||||
|
───────────────────────────────────────────────── */
|
||||||
function tryMatchmaking2v2(io) {
|
function tryMatchmaking2v2(io) {
|
||||||
const readyList = Array.from(readyTeams.values());
|
const readyList = Array.from(readyTeams.values());
|
||||||
if (readyList.length < 2) return;
|
if (readyList.length < 2) return;
|
||||||
@ -74,25 +82,64 @@ function tryMatchmaking2v2(io) {
|
|||||||
for (const p of allPlayers) {
|
for (const p of allPlayers) {
|
||||||
const opponents = allPlayers.filter(x => x.team !== p.team).map(x => x.player.name);
|
const opponents = allPlayers.filter(x => x.team !== p.team).map(x => x.player.name);
|
||||||
const teammates = allPlayers.filter(x => x.team === p.team && x.socketId !== p.socketId).map(x => x.player.name);
|
const teammates = allPlayers.filter(x => x.team === p.team && x.socketId !== p.socketId).map(x => x.player.name);
|
||||||
|
const teamRef = p.team === 1 ? team1 : team2;
|
||||||
|
const slotIndex = teamRef.players.findIndex(x => x.socketId === p.socketId) + 1;
|
||||||
|
|
||||||
io.to(p.socketId).emit("match_found_2v2", {
|
io.to(p.socketId).emit("match_found_2v2", {
|
||||||
matchId,
|
matchId,
|
||||||
myTeam: p.team,
|
myTeam: p.team,
|
||||||
teammates,
|
teammates,
|
||||||
opponents,
|
opponents,
|
||||||
mySlot: `team${p.team}_player${team1.players.indexOf(p) >= 0 ? team1.players.findIndex(x=>x.socketId===p.socketId)+1 : team2.players.findIndex(x=>x.socketId===p.socketId)+1}`,
|
mySlot: `team${p.team}_player${slotIndex}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[2v2] Match: Team1(${team1.players.map(p=>p.player.name)}) vs Team2(${team2.players.map(p=>p.player.name)}) | ${matchId}`);
|
console.log(
|
||||||
|
`[2v2] Match: Team1(${team1.players.map(p => p.player.name)})` +
|
||||||
|
` vs Team2(${team2.players.map(p => p.player.name)}) | ${matchId}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Werden beim ersten Event lazy initialisiert (auf io gespeichert)
|
/* ─────────────────────────────────────────────────
|
||||||
// io._arenaRooms → matchId → { sockets, names }
|
HELPER: 1v1 Matchmaking
|
||||||
// io._arenaReady → matchId → Set of ready slots
|
───────────────────────────────────────────────── */
|
||||||
// io._arenaTimers → matchId → intervalId
|
function tryMatchmaking(io, newSocketId) {
|
||||||
|
const challenger = waitingPool.get(newSocketId);
|
||||||
|
if (!challenger) return;
|
||||||
|
|
||||||
const READY_TIMEOUT = 30; // Sekunden bis Match abgebrochen wird
|
for (const [id, entry] of waitingPool) {
|
||||||
|
if (id === newSocketId) continue;
|
||||||
|
|
||||||
|
const levelDiff = Math.abs(entry.player.level - challenger.player.level);
|
||||||
|
if (levelDiff <= LEVEL_RANGE) {
|
||||||
|
waitingPool.delete(newSocketId);
|
||||||
|
waitingPool.delete(id);
|
||||||
|
|
||||||
|
const matchId = `match_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
||||||
|
|
||||||
|
challenger.socket.emit("match_found", {
|
||||||
|
matchId,
|
||||||
|
opponent: entry.player,
|
||||||
|
mySlot: "player1",
|
||||||
|
});
|
||||||
|
entry.socket.emit("match_found", {
|
||||||
|
matchId,
|
||||||
|
opponent: challenger.player,
|
||||||
|
mySlot: "player2",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`[1v1] Match: ${challenger.player.name} (Lvl ${challenger.player.level})` +
|
||||||
|
` vs ${entry.player.name} (Lvl ${entry.player.level}) | ${matchId}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─────────────────────────────────────────────────
|
||||||
|
HELPER: Bereit-Timer (1v1)
|
||||||
|
───────────────────────────────────────────────── */
|
||||||
function startReadyTimer(io, matchId) {
|
function startReadyTimer(io, matchId) {
|
||||||
if (!io._arenaTimers) io._arenaTimers = new Map();
|
if (!io._arenaTimers) io._arenaTimers = new Map();
|
||||||
if (io._arenaTimers.has(matchId)) return;
|
if (io._arenaTimers.has(matchId)) return;
|
||||||
@ -128,41 +175,37 @@ function stopReadyTimer(io, matchId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryMatchmaking(io, newSocketId) {
|
/* ─────────────────────────────────────────────────
|
||||||
const challenger = waitingPool.get(newSocketId);
|
HELPER: Spieler aus allen 2v2-Teams entfernen
|
||||||
if (!challenger) return;
|
───────────────────────────────────────────────── */
|
||||||
|
function leaveAllTeams(socketId, io) {
|
||||||
|
for (const [teamId, team] of teams2v2) {
|
||||||
|
const idx = team.players.findIndex(p => p.socketId === socketId);
|
||||||
|
if (idx === -1) continue;
|
||||||
|
|
||||||
for (const [id, entry] of waitingPool) {
|
const playerName = team.players[idx].player.name;
|
||||||
if (id === newSocketId) continue;
|
team.players.splice(idx, 1);
|
||||||
|
team.ready.delete(socketId);
|
||||||
|
readyTeams.delete(teamId);
|
||||||
|
|
||||||
const levelDiff = Math.abs(entry.player.level - challenger.player.level);
|
if (team.players.length === 0) {
|
||||||
if (levelDiff <= LEVEL_RANGE) {
|
teams2v2.delete(teamId);
|
||||||
waitingPool.delete(newSocketId);
|
console.log(`[2v2] Team ${teamId} aufgelöst.`);
|
||||||
waitingPool.delete(id);
|
} else {
|
||||||
|
broadcastTeamStatus(io, teamId);
|
||||||
const matchId = `match_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
for (const p of team.players) {
|
||||||
|
io.to(p.socketId).emit("2v2_partner_left", { name: playerName });
|
||||||
challenger.socket.emit("match_found", {
|
|
||||||
matchId,
|
|
||||||
opponent: entry.player,
|
|
||||||
mySlot: "player1",
|
|
||||||
});
|
|
||||||
|
|
||||||
entry.socket.emit("match_found", {
|
|
||||||
matchId,
|
|
||||||
opponent: challenger.player,
|
|
||||||
mySlot: "player2",
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`[1v1] Match: ${challenger.player.name} (Lvl ${challenger.player.level})` +
|
|
||||||
` vs ${entry.player.name} (Lvl ${entry.player.level}) | ${matchId}`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
console.log(`[2v2] ${playerName} hat Team ${teamId} verlassen.`);
|
||||||
|
}
|
||||||
|
broadcastLobbies(io);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════
|
||||||
|
HAUPT-HANDLER – wird einmal pro Socket-Verbindung gerufen
|
||||||
|
═══════════════════════════════════════════════════════════ */
|
||||||
function registerArenaHandlers(io, socket) {
|
function registerArenaHandlers(io, socket) {
|
||||||
|
|
||||||
/* ── 1v1: Queue beitreten ── */
|
/* ── 1v1: Queue beitreten ── */
|
||||||
@ -176,7 +219,6 @@ function registerArenaHandlers(io, socket) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
waitingPool.set(socket.id, { socket, player });
|
waitingPool.set(socket.id, { socket, player });
|
||||||
|
|
||||||
socket.emit("queue_status", {
|
socket.emit("queue_status", {
|
||||||
status: "waiting",
|
status: "waiting",
|
||||||
poolSize: waitingPool.size,
|
poolSize: waitingPool.size,
|
||||||
@ -195,9 +237,70 @@ function registerArenaHandlers(io, socket) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ══════════════════════════════════════════
|
/* ── 1v1: Spielfeld betreten ── */
|
||||||
|
socket.on("arena_join", (data) => {
|
||||||
|
const { matchId, slot } = data;
|
||||||
|
if (!matchId || !slot) return;
|
||||||
|
|
||||||
|
if (!io._arenaRooms) io._arenaRooms = new Map();
|
||||||
|
if (!io._arenaRooms.has(matchId)) {
|
||||||
|
io._arenaRooms.set(matchId, { sockets: {}, names: {} });
|
||||||
|
}
|
||||||
|
|
||||||
|
const room = io._arenaRooms.get(matchId);
|
||||||
|
room.sockets[slot] = socket.id;
|
||||||
|
room.names[slot] = socket.user || "Spieler";
|
||||||
|
socket.join("arena_" + matchId);
|
||||||
|
|
||||||
|
const otherSlot = slot === "player1" ? "player2" : "player1";
|
||||||
|
if (room.sockets[otherSlot]) {
|
||||||
|
io.to("arena_" + matchId).emit("arena_ready", {
|
||||||
|
player1: room.names["player1"] || "Spieler 1",
|
||||||
|
player2: room.names["player2"] || "Spieler 2",
|
||||||
|
});
|
||||||
|
console.log(`[Arena] Match ${matchId} bereit: ${room.names["player1"]} vs ${room.names["player2"]}`);
|
||||||
|
startReadyTimer(io, matchId);
|
||||||
|
} else {
|
||||||
|
socket.to("arena_" + matchId).emit("arena_opponent_joined", {
|
||||||
|
name: room.names[slot],
|
||||||
|
slot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 1v1: Bereit-System ── */
|
||||||
|
socket.on("player_ready", (data) => {
|
||||||
|
const { matchId, slot } = data;
|
||||||
|
if (!matchId || !slot) return;
|
||||||
|
|
||||||
|
if (!io._arenaReady) io._arenaReady = new Map();
|
||||||
|
if (!io._arenaReady.has(matchId)) io._arenaReady.set(matchId, new Set());
|
||||||
|
|
||||||
|
const readySet = io._arenaReady.get(matchId);
|
||||||
|
readySet.add(slot);
|
||||||
|
|
||||||
|
io.to("arena_" + matchId).emit("ready_status", {
|
||||||
|
readyCount: readySet.size,
|
||||||
|
readySlots: Array.from(readySet),
|
||||||
|
});
|
||||||
|
console.log(`[1v1] ${slot} bereit in ${matchId} (${readySet.size}/2)`);
|
||||||
|
|
||||||
|
if (readySet.size >= 2) {
|
||||||
|
stopReadyTimer(io, matchId);
|
||||||
|
io._arenaReady.delete(matchId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 1v1: Aufgeben ── */
|
||||||
|
socket.on("player_surrender", (data) => {
|
||||||
|
const { matchId, slot } = data;
|
||||||
|
console.log(`[1v1] ${slot} hat aufgegeben in Match ${matchId}`);
|
||||||
|
io.to("arena_" + matchId).emit("player_surrendered", { slot });
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ════════════════════════════════════════════
|
||||||
2v2 TEAM LOBBY
|
2v2 TEAM LOBBY
|
||||||
══════════════════════════════════════════ */
|
════════════════════════════════════════════ */
|
||||||
|
|
||||||
/* ── Lobby-Liste anfordern ── */
|
/* ── Lobby-Liste anfordern ── */
|
||||||
socket.on("get_2v2_lobbies", () => {
|
socket.on("get_2v2_lobbies", () => {
|
||||||
@ -217,10 +320,13 @@ function registerArenaHandlers(io, socket) {
|
|||||||
|
|
||||||
/* ── Neues Team erstellen ── */
|
/* ── Neues Team erstellen ── */
|
||||||
socket.on("create_2v2_team", (playerData) => {
|
socket.on("create_2v2_team", (playerData) => {
|
||||||
// Erst aus alten Teams entfernen
|
|
||||||
leaveAllTeams(socket.id, io);
|
leaveAllTeams(socket.id, io);
|
||||||
|
|
||||||
const player = { id: playerData.id, name: playerData.name, level: Number(playerData.level) || 1 };
|
const player = {
|
||||||
|
id: playerData.id,
|
||||||
|
name: playerData.name,
|
||||||
|
level: Number(playerData.level) || 1,
|
||||||
|
};
|
||||||
const teamId = `team_${generateId()}`;
|
const teamId = `team_${generateId()}`;
|
||||||
|
|
||||||
teams2v2.set(teamId, {
|
teams2v2.set(teamId, {
|
||||||
@ -246,12 +352,16 @@ function registerArenaHandlers(io, socket) {
|
|||||||
|
|
||||||
leaveAllTeams(socket.id, io);
|
leaveAllTeams(socket.id, io);
|
||||||
|
|
||||||
const player = { id: playerData.id, name: playerData.name, level: Number(playerData.level) || 1 };
|
const player = {
|
||||||
|
id: playerData.id,
|
||||||
|
name: playerData.name,
|
||||||
|
level: Number(playerData.level) || 1,
|
||||||
|
};
|
||||||
team.players.push({ socketId: socket.id, player });
|
team.players.push({ socketId: socket.id, player });
|
||||||
|
|
||||||
socket.emit("2v2_team_joined", { teamId, isLeader: false });
|
socket.emit("2v2_team_joined", { teamId, isLeader: false });
|
||||||
broadcastTeamStatus(io, teamId);
|
broadcastTeamStatus(io, teamId);
|
||||||
broadcastLobbies(io); // Team aus offener Liste entfernen
|
broadcastLobbies(io);
|
||||||
console.log(`[2v2] ${player.name} hat Team ${teamId} beigetreten`);
|
console.log(`[2v2] ${player.name} hat Team ${teamId} beigetreten`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -268,10 +378,8 @@ function registerArenaHandlers(io, socket) {
|
|||||||
|
|
||||||
team.ready.add(socket.id);
|
team.ready.add(socket.id);
|
||||||
broadcastTeamStatus(io, teamId);
|
broadcastTeamStatus(io, teamId);
|
||||||
|
|
||||||
console.log(`[2v2] Bereit in Team ${teamId}: ${team.ready.size}/2`);
|
console.log(`[2v2] Bereit in Team ${teamId}: ${team.ready.size}/2`);
|
||||||
|
|
||||||
// Beide bereit → Team in Matchmaking-Pool
|
|
||||||
if (team.ready.size >= 2) {
|
if (team.ready.size >= 2) {
|
||||||
readyTeams.set(teamId, team);
|
readyTeams.set(teamId, team);
|
||||||
for (const p of team.players) {
|
for (const p of team.players) {
|
||||||
@ -282,72 +390,6 @@ function registerArenaHandlers(io, socket) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ── Spielfeld: Spieler betritt Arena-Room ── */
|
|
||||||
socket.on("arena_join", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
if (!matchId || !slot) return;
|
|
||||||
|
|
||||||
if (!io._arenaRooms) io._arenaRooms = new Map();
|
|
||||||
if (!io._arenaRooms.has(matchId)) {
|
|
||||||
io._arenaRooms.set(matchId, { sockets: {}, names: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
const room = io._arenaRooms.get(matchId);
|
|
||||||
room.sockets[slot] = socket.id;
|
|
||||||
room.names[slot] = socket.user || "Spieler";
|
|
||||||
|
|
||||||
socket.join("arena_" + matchId);
|
|
||||||
|
|
||||||
const otherSlot = slot === "player1" ? "player2" : "player1";
|
|
||||||
|
|
||||||
if (room.sockets[otherSlot]) {
|
|
||||||
io.to("arena_" + matchId).emit("arena_ready", {
|
|
||||||
player1: room.names["player1"] || "Spieler 1",
|
|
||||||
player2: room.names["player2"] || "Spieler 2",
|
|
||||||
});
|
|
||||||
console.log(`[Arena] Match ${matchId} bereit: ${room.names["player1"]} vs ${room.names["player2"]}`);
|
|
||||||
startReadyTimer(io, matchId);
|
|
||||||
} else {
|
|
||||||
socket.to("arena_" + matchId).emit("arena_opponent_joined", {
|
|
||||||
name: room.names[slot],
|
|
||||||
slot,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Bereit-System ── */
|
|
||||||
socket.on("player_ready", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
if (!matchId || !slot) return;
|
|
||||||
|
|
||||||
if (!io._arenaReady) io._arenaReady = new Map();
|
|
||||||
if (!io._arenaReady.has(matchId)) {
|
|
||||||
io._arenaReady.set(matchId, new Set());
|
|
||||||
}
|
|
||||||
|
|
||||||
const readySet = io._arenaReady.get(matchId);
|
|
||||||
readySet.add(slot);
|
|
||||||
|
|
||||||
io.to("arena_" + matchId).emit("ready_status", {
|
|
||||||
readyCount: readySet.size,
|
|
||||||
readySlots: Array.from(readySet),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`[1v1] ${slot} bereit in ${matchId} (${readySet.size}/2)`);
|
|
||||||
|
|
||||||
if (readySet.size >= 2) {
|
|
||||||
stopReadyTimer(io, matchId);
|
|
||||||
io._arenaReady.delete(matchId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Aufgeben ── */
|
|
||||||
socket.on("player_surrender", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
console.log(`[1v1] ${slot} hat aufgegeben in Match ${matchId}`);
|
|
||||||
io.to("arena_" + matchId).emit("player_surrendered", { slot });
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Disconnect ── */
|
/* ── Disconnect ── */
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
if (waitingPool.delete(socket.id)) {
|
if (waitingPool.delete(socket.id)) {
|
||||||
@ -357,216 +399,4 @@ function registerArenaHandlers(io, socket) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Hilfsfunktion: Spieler aus allen 2v2-Teams entfernen ── */
|
|
||||||
function leaveAllTeams(socketId, io) {
|
|
||||||
for (const [teamId, team] of teams2v2) {
|
|
||||||
const idx = team.players.findIndex(p => p.socketId === socketId);
|
|
||||||
if (idx === -1) continue;
|
|
||||||
|
|
||||||
const playerName = team.players[idx].player.name;
|
|
||||||
team.players.splice(idx, 1);
|
|
||||||
team.ready.delete(socketId);
|
|
||||||
readyTeams.delete(teamId);
|
|
||||||
|
|
||||||
if (team.players.length === 0) {
|
|
||||||
teams2v2.delete(teamId);
|
|
||||||
console.log(`[2v2] Team ${teamId} aufgelöst.`);
|
|
||||||
} else {
|
|
||||||
// Verbleibenden Spieler informieren
|
|
||||||
broadcastTeamStatus(io, teamId);
|
|
||||||
for (const p of team.players) {
|
|
||||||
io.to(p.socketId).emit("2v2_partner_left", { name: playerName });
|
|
||||||
}
|
|
||||||
console.log(`[2v2] ${playerName} hat Team ${teamId} verlassen.`);
|
|
||||||
}
|
|
||||||
broadcastLobbies(io);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { registerArenaHandlers };
|
|
||||||
|
|
||||||
function startReadyTimer(io, matchId) {
|
|
||||||
if (!io._arenaTimers) io._arenaTimers = new Map();
|
|
||||||
if (io._arenaTimers.has(matchId)) return; // läuft bereits
|
|
||||||
|
|
||||||
let remaining = READY_TIMEOUT;
|
|
||||||
|
|
||||||
// Sofort ersten Tick senden
|
|
||||||
io.to("arena_" + matchId).emit("ready_timer", { remaining });
|
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
remaining--;
|
|
||||||
io.to("arena_" + matchId).emit("ready_timer", { remaining });
|
|
||||||
|
|
||||||
if (remaining <= 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
io._arenaTimers.delete(matchId);
|
|
||||||
|
|
||||||
// Match abbrechen – Funktion noch offen
|
|
||||||
console.log(`[1v1] Match ${matchId} abgebrochen – Zeit abgelaufen.`);
|
|
||||||
io.to("arena_" + matchId).emit("match_cancelled", {
|
|
||||||
reason: "timeout",
|
|
||||||
message: "Zeit abgelaufen – Match wird abgebrochen.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
io._arenaTimers.set(matchId, interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopReadyTimer(io, matchId) {
|
|
||||||
if (!io._arenaTimers) return;
|
|
||||||
const interval = io._arenaTimers.get(matchId);
|
|
||||||
if (interval) {
|
|
||||||
clearInterval(interval);
|
|
||||||
io._arenaTimers.delete(matchId);
|
|
||||||
console.log(`[1v1] Timer für Match ${matchId} gestoppt (beide bereit).`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryMatchmaking(io, newSocketId) {
|
|
||||||
const challenger = waitingPool.get(newSocketId);
|
|
||||||
if (!challenger) return;
|
|
||||||
|
|
||||||
for (const [id, entry] of waitingPool) {
|
|
||||||
if (id === newSocketId) continue;
|
|
||||||
|
|
||||||
const levelDiff = Math.abs(entry.player.level - challenger.player.level);
|
|
||||||
if (levelDiff <= LEVEL_RANGE) {
|
|
||||||
waitingPool.delete(newSocketId);
|
|
||||||
waitingPool.delete(id);
|
|
||||||
|
|
||||||
const matchId = `match_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
||||||
|
|
||||||
challenger.socket.emit("match_found", {
|
|
||||||
matchId,
|
|
||||||
opponent: entry.player,
|
|
||||||
mySlot: "player1",
|
|
||||||
});
|
|
||||||
|
|
||||||
entry.socket.emit("match_found", {
|
|
||||||
matchId,
|
|
||||||
opponent: challenger.player,
|
|
||||||
mySlot: "player2",
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`[1v1] Match: ${challenger.player.name} (Lvl ${challenger.player.level})` +
|
|
||||||
` vs ${entry.player.name} (Lvl ${entry.player.level}) | ${matchId}`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerArenaHandlers(io, socket) {
|
|
||||||
|
|
||||||
/* ── Queue beitreten ── */
|
|
||||||
socket.on("join_1v1", (playerData) => {
|
|
||||||
if (waitingPool.has(socket.id)) return;
|
|
||||||
|
|
||||||
const player = {
|
|
||||||
id: playerData.id,
|
|
||||||
name: playerData.name,
|
|
||||||
level: Number(playerData.level) || 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
waitingPool.set(socket.id, { socket, player });
|
|
||||||
|
|
||||||
socket.emit("queue_status", {
|
|
||||||
status: "waiting",
|
|
||||||
poolSize: waitingPool.size,
|
|
||||||
message: `Suche Gegner (Level ${player.level - LEVEL_RANGE}–${player.level + LEVEL_RANGE})…`,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`[1v1] ${player.name} (Lvl ${player.level}) im Pool. Größe: ${waitingPool.size}`);
|
|
||||||
tryMatchmaking(io, socket.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Queue verlassen ── */
|
|
||||||
socket.on("leave_1v1", () => {
|
|
||||||
if (waitingPool.delete(socket.id)) {
|
|
||||||
socket.emit("queue_status", { status: "left" });
|
|
||||||
console.log(`[1v1] ${socket.id} hat Pool verlassen.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Spielfeld: Spieler betritt Arena-Room ── */
|
|
||||||
socket.on("arena_join", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
if (!matchId || !slot) return;
|
|
||||||
|
|
||||||
if (!io._arenaRooms) io._arenaRooms = new Map();
|
|
||||||
if (!io._arenaRooms.has(matchId)) {
|
|
||||||
io._arenaRooms.set(matchId, { sockets: {}, names: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
const room = io._arenaRooms.get(matchId);
|
|
||||||
room.sockets[slot] = socket.id;
|
|
||||||
room.names[slot] = socket.user || "Spieler";
|
|
||||||
|
|
||||||
socket.join("arena_" + matchId);
|
|
||||||
|
|
||||||
const otherSlot = slot === "player1" ? "player2" : "player1";
|
|
||||||
|
|
||||||
if (room.sockets[otherSlot]) {
|
|
||||||
io.to("arena_" + matchId).emit("arena_ready", {
|
|
||||||
player1: room.names["player1"] || "Spieler 1",
|
|
||||||
player2: room.names["player2"] || "Spieler 2",
|
|
||||||
});
|
|
||||||
console.log(`[Arena] Match ${matchId} bereit: ${room.names["player1"]} vs ${room.names["player2"]}`);
|
|
||||||
|
|
||||||
// 30-Sekunden Bereit-Timer starten
|
|
||||||
startReadyTimer(io, matchId);
|
|
||||||
} else {
|
|
||||||
socket.to("arena_" + matchId).emit("arena_opponent_joined", {
|
|
||||||
name: room.names[slot],
|
|
||||||
slot,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Bereit-System ── */
|
|
||||||
socket.on("player_ready", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
if (!matchId || !slot) return;
|
|
||||||
|
|
||||||
if (!io._arenaReady) io._arenaReady = new Map();
|
|
||||||
if (!io._arenaReady.has(matchId)) {
|
|
||||||
io._arenaReady.set(matchId, new Set());
|
|
||||||
}
|
|
||||||
|
|
||||||
const readySet = io._arenaReady.get(matchId);
|
|
||||||
readySet.add(slot);
|
|
||||||
|
|
||||||
io.to("arena_" + matchId).emit("ready_status", {
|
|
||||||
readyCount: readySet.size,
|
|
||||||
readySlots: Array.from(readySet),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`[1v1] ${slot} bereit in ${matchId} (${readySet.size}/2)`);
|
|
||||||
|
|
||||||
if (readySet.size >= 2) {
|
|
||||||
stopReadyTimer(io, matchId);
|
|
||||||
io._arenaReady.delete(matchId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Aufgeben ── */
|
|
||||||
socket.on("player_surrender", (data) => {
|
|
||||||
const { matchId, slot } = data;
|
|
||||||
console.log(`[1v1] ${slot} hat aufgegeben in Match ${matchId}`);
|
|
||||||
// Aufgabe-Logik kommt hier rein
|
|
||||||
io.to("arena_" + matchId).emit("player_surrendered", { slot });
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ── Disconnect: aus Pool entfernen ── */
|
|
||||||
socket.on("disconnect", () => {
|
|
||||||
if (waitingPool.delete(socket.id)) {
|
|
||||||
console.log(`[1v1] ${socket.id} disconnected – aus Pool entfernt.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { registerArenaHandlers };
|
module.exports = { registerArenaHandlers };
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user