Trying to improve latency placing bombs while running

This commit is contained in:
Mike Müller 2026-03-08 14:16:17 +01:00
parent 21f9807482
commit e9306a2502

View File

@ -127,6 +127,7 @@ const network = {
inputStateAtClient: {
dir: null,
bomb: false,
bombCell: null,
},
lastInputSentAt: 0,
activeRoster: [],
@ -712,7 +713,7 @@ function handleSocketMessage(raw) {
if (!network.isHost || state.mode !== "multiplayer" || state.screen !== "game") {
return;
}
network.remoteInputs.set(msg.playerId, msg.input || { dir: null, bomb: false });
network.remoteInputs.set(msg.playerId, msg.input || { dir: null, bomb: false, bombCell: null });
return;
}
@ -779,7 +780,7 @@ function leaveLobbyInternals() {
network.activeRoster = [];
state.notification.text = "";
state.notification.expiresAt = 0;
network.inputStateAtClient = { dir: null, bomb: false };
network.inputStateAtClient = { dir: null, bomb: false, bombCell: null };
network.lastInputSentAt = 0;
network.hasReceivedSnapshot = false;
}
@ -975,22 +976,94 @@ function updateLobbyNetwork(dt) {
}
}
function sameBombCell(a, b) {
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
return a.x === b.x && a.y === b.y;
}
function resolveBombDropCell(player, preferredCell = null) {
const candidates = [];
if (player.moveProgress < 1) {
candidates.push({ x: player.moveFromX, y: player.moveFromY });
if (player.moveToX !== player.moveFromX || player.moveToY !== player.moveFromY) {
candidates.push({ x: player.moveToX, y: player.moveToY });
}
} else {
candidates.push({ x: player.x, y: player.y });
}
const canPlaceAt = (x, y) => {
if (!inBounds(x, y)) {
return false;
}
const tile = state.map[y]?.[x];
if (!tile || tile.type !== "floor") {
return false;
}
return !getBombAt(x, y);
};
const isCandidateCell = (cell) =>
candidates.some((candidate) => candidate.x === cell.x && candidate.y === cell.y);
if (preferredCell && Number.isInteger(preferredCell.x) && Number.isInteger(preferredCell.y)) {
if (isCandidateCell(preferredCell) && canPlaceAt(preferredCell.x, preferredCell.y)) {
return { x: preferredCell.x, y: preferredCell.y };
}
}
const primary =
player.moveProgress < 1 && player.moveProgress >= 0.5
? { x: player.moveToX, y: player.moveToY }
: candidates[0];
if (primary && canPlaceAt(primary.x, primary.y)) {
return { x: primary.x, y: primary.y };
}
for (const candidate of candidates) {
if (canPlaceAt(candidate.x, candidate.y)) {
return { x: candidate.x, y: candidate.y };
}
}
return null;
}
function sendLocalMultiplayerInput(force = false) {
if (state.mode !== "multiplayer" || state.screen !== "game" || network.isHost) {
return;
}
const t = now();
const localPlayer = state.players.find((player) => player.ownerId === network.clientId) || null;
const nextInput = {
dir: currentHumanDirection(),
bomb: inputState.bombHeld,
bombCell: null,
};
if (nextInput.bomb && localPlayer) {
nextInput.bombCell = resolveBombDropCell(localPlayer);
}
const changed =
nextInput.dir !== network.inputStateAtClient.dir || nextInput.bomb !== network.inputStateAtClient.bomb;
nextInput.dir !== network.inputStateAtClient.dir ||
nextInput.bomb !== network.inputStateAtClient.bomb ||
!sameBombCell(nextInput.bombCell, network.inputStateAtClient.bombCell);
const dueHeartbeat = t - network.lastInputSentAt > 0.12;
if (!changed && !force && !dueHeartbeat) {
return;
}
network.inputStateAtClient = nextInput;
network.inputStateAtClient = {
dir: nextInput.dir,
bomb: nextInput.bomb,
bombCell: nextInput.bombCell ? { ...nextInput.bombCell } : null,
};
network.lastInputSentAt = t;
sendSocketMessage("player_input", { input: nextInput, ts: t });
}
@ -1032,18 +1105,20 @@ function queueDetonation(bombId) {
state.pendingDetonations.push(bombId);
}
function dropBomb(player) {
function dropBomb(player, preferredCell = null) {
if (!player.alive || player.bombsPlaced >= player.bombCapacity) {
return false;
}
if (getBombAt(player.x, player.y)) {
const dropCell = resolveBombDropCell(player, preferredCell);
if (!dropCell) {
return false;
}
const bomb = {
id: state.nextBombId,
x: player.x,
y: player.y,
x: dropCell.x,
y: dropCell.y,
timer: CONFIG.bombFuse,
range: player.flameRange,
ownerId: player.id,
@ -1329,7 +1404,7 @@ function occupiedTiles(player) {
}
function getNetworkInput(ownerId) {
return network.remoteInputs.get(ownerId) || { dir: null, bomb: false };
return network.remoteInputs.get(ownerId) || { dir: null, bomb: false, bombCell: null };
}
function getDesiredDirection(player) {
@ -1371,8 +1446,9 @@ function updatePlayerMovement(player, dt) {
player.renderY = player.y;
}
const occupied = new Set(occupiedTiles(player));
for (const bomb of state.bombs) {
if (bomb.passThrough.has(player.id) && (player.x !== bomb.x || player.y !== bomb.y)) {
if (bomb.passThrough.has(player.id) && !occupied.has(tileKey(bomb.x, bomb.y))) {
bomb.passThrough.delete(player.id);
}
}
@ -1585,7 +1661,7 @@ function updateGame(dt) {
const remote = getNetworkInput(player.ownerId);
const prevBomb = network.remoteBombPrev.get(player.ownerId) || false;
if (remote.bomb && !prevBomb) {
dropBomb(player);
dropBomb(player, remote.bombCell || null);
}
network.remoteBombPrev.set(player.ownerId, remote.bomb);
}