Track dead players and remember selected
This commit is contained in:
parent
2df1b5a560
commit
d8982ead59
webradar
@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>radarflow</title>
|
<title>radar</title>
|
||||||
<link href="styles.css" rel="stylesheet" type="text/css" />
|
<link href="styles.css" rel="stylesheet" type="text/css" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -51,15 +51,21 @@ let currentFps = 0;
|
|||||||
let temporarilyDisableRotation = false;
|
let temporarilyDisableRotation = false;
|
||||||
let rotationDisabledUntilRespawn = false;
|
let rotationDisabledUntilRespawn = false;
|
||||||
let lastKnownPositions = {};
|
let lastKnownPositions = {};
|
||||||
|
let deadPlayers = {};
|
||||||
let entityInterpolationData = {};
|
let entityInterpolationData = {};
|
||||||
let lastUpdateTime = 0;
|
let lastUpdateTime = 0;
|
||||||
let networkLatencyHistory = [];
|
let networkLatencyHistory = [];
|
||||||
let lastPingSent = 0;
|
let lastPingSent = 0;
|
||||||
|
|
||||||
|
// Special values for spectator mode
|
||||||
|
const FULL_MAP_VIEW = "FULL_MAP";
|
||||||
|
const LOCAL_PLAYER_VIEW = "YOU";
|
||||||
|
|
||||||
let focusedPlayerYaw = 0;
|
let focusedPlayerYaw = 0;
|
||||||
let focusedPlayerName = "YOU";
|
let focusedPlayerName = localStorage.getItem('selectedPlayer') || LOCAL_PLAYER_VIEW;
|
||||||
let focusedPlayerPos = null;
|
let focusedPlayerPos = null;
|
||||||
let playerList = {};
|
let playerList = {};
|
||||||
|
let lastFocusedPlayer = localStorage.getItem('lastFocusedPlayer') || null;
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
let canvas = null;
|
let canvas = null;
|
||||||
@ -323,7 +329,8 @@ function processPlayerPositions() {
|
|||||||
focusedPlayerPos = null;
|
focusedPlayerPos = null;
|
||||||
focusedPlayerYaw = 0;
|
focusedPlayerYaw = 0;
|
||||||
let oldPlayerList = { ...playerList };
|
let oldPlayerList = { ...playerList };
|
||||||
playerList = {};
|
let newPlayerList = {};
|
||||||
|
let wasPlayerAlive = oldPlayerList[focusedPlayerName] && !oldPlayerList[focusedPlayerName].isDead;
|
||||||
|
|
||||||
entityData.forEach((data, index) => {
|
entityData.forEach((data, index) => {
|
||||||
const entityId = `entity_${index}`;
|
const entityId = `entity_${index}`;
|
||||||
@ -337,23 +344,25 @@ function processPlayerPositions() {
|
|||||||
if (player.playerType === "Local") {
|
if (player.playerType === "Local") {
|
||||||
localYaw = player.yaw;
|
localYaw = player.yaw;
|
||||||
localPlayerPos = player.pos;
|
localPlayerPos = player.pos;
|
||||||
playerList["YOU"] = {
|
newPlayerList[LOCAL_PLAYER_VIEW] = {
|
||||||
pos: player.pos,
|
pos: player.pos,
|
||||||
yaw: player.yaw
|
yaw: player.yaw
|
||||||
};
|
};
|
||||||
|
|
||||||
lastKnownPositions["YOU"] = player.pos;
|
lastKnownPositions[LOCAL_PLAYER_VIEW] = player.pos;
|
||||||
|
if (deadPlayers[LOCAL_PLAYER_VIEW]) delete deadPlayers[LOCAL_PLAYER_VIEW];
|
||||||
} else {
|
} else {
|
||||||
playerList[player.playerName] = {
|
newPlayerList[player.playerName] = {
|
||||||
pos: player.pos,
|
pos: player.pos,
|
||||||
yaw: player.yaw
|
yaw: player.yaw
|
||||||
};
|
};
|
||||||
|
|
||||||
lastKnownPositions[player.playerName] = player.pos;
|
lastKnownPositions[player.playerName] = player.pos;
|
||||||
|
if (deadPlayers[player.playerName]) delete deadPlayers[player.playerName];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.playerName === focusedPlayerName ||
|
if (player.playerName === focusedPlayerName ||
|
||||||
(focusedPlayerName === "YOU" && player.playerType === "Local")) {
|
(focusedPlayerName === LOCAL_PLAYER_VIEW && player.playerType === "Local")) {
|
||||||
focusedPlayerPos = player.pos;
|
focusedPlayerPos = player.pos;
|
||||||
focusedPlayerYaw = player.yaw;
|
focusedPlayerYaw = player.yaw;
|
||||||
|
|
||||||
@ -365,10 +374,91 @@ function processPlayerPositions() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (focusedPlayerPos === null) {
|
for (const playerName in oldPlayerList) {
|
||||||
if (oldPlayerList[focusedPlayerName] && oldPlayerList[focusedPlayerName].pos) {
|
if (!newPlayerList[playerName] && playerName !== FULL_MAP_VIEW) {
|
||||||
console.log("[radarflow] Focused player disappeared, disabling rotation until respawn");
|
deadPlayers[playerName] = {
|
||||||
rotationDisabledUntilRespawn = true;
|
pos: lastKnownPositions[playerName] || null,
|
||||||
|
yaw: oldPlayerList[playerName].yaw || 0,
|
||||||
|
lastSeen: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (playerName === focusedPlayerName && wasPlayerAlive) {
|
||||||
|
console.log(`[radarflow] Focused player ${playerName} died, switching to full map view`);
|
||||||
|
localStorage.setItem('lastFocusedPlayer', playerName);
|
||||||
|
lastFocusedPlayer = playerName;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
localStorage.setItem('selectedPlayer', FULL_MAP_VIEW);
|
||||||
|
playerCentered = false;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const playerName in deadPlayers) {
|
||||||
|
if (!newPlayerList[playerName] && playerName !== FULL_MAP_VIEW) {
|
||||||
|
if (Date.now() - deadPlayers[playerName].lastSeen < 60000) {
|
||||||
|
newPlayerList[playerName] = {
|
||||||
|
pos: deadPlayers[playerName].pos,
|
||||||
|
yaw: deadPlayers[playerName].yaw,
|
||||||
|
isDead: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newPlayerList[FULL_MAP_VIEW] = {
|
||||||
|
isFullMap: true
|
||||||
|
};
|
||||||
|
|
||||||
|
playerList = newPlayerList;
|
||||||
|
|
||||||
|
if (focusedPlayerName === FULL_MAP_VIEW && lastFocusedPlayer) {
|
||||||
|
const playerIsBackAlive = newPlayerList[lastFocusedPlayer] && !newPlayerList[lastFocusedPlayer].isDead;
|
||||||
|
|
||||||
|
if (playerIsBackAlive) {
|
||||||
|
console.log(`[radarflow] Last focused player ${lastFocusedPlayer} is back alive, reselecting them`);
|
||||||
|
focusedPlayerName = lastFocusedPlayer;
|
||||||
|
localStorage.setItem('selectedPlayer', lastFocusedPlayer);
|
||||||
|
|
||||||
|
if (document.getElementById('centerCheck').checked) {
|
||||||
|
playerCentered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
focusedPlayerPos = newPlayerList[lastFocusedPlayer].pos;
|
||||||
|
focusedPlayerYaw = newPlayerList[lastFocusedPlayer].yaw;
|
||||||
|
|
||||||
|
rotationDisabledUntilRespawn = false;
|
||||||
|
|
||||||
|
const dropdown = document.getElementById('playerSelect');
|
||||||
|
if (dropdown) {
|
||||||
|
dropdown.value = lastFocusedPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle focused player state
|
||||||
|
if (focusedPlayerName === FULL_MAP_VIEW) {
|
||||||
|
playerCentered = false;
|
||||||
|
} else if (focusedPlayerPos === null) {
|
||||||
|
if (playerList[focusedPlayerName]?.isDead) {
|
||||||
|
console.log(`[radarflow] Focused player ${focusedPlayerName} is dead, switching to full map view`);
|
||||||
|
localStorage.setItem('lastFocusedPlayer', focusedPlayerName);
|
||||||
|
lastFocusedPlayer = focusedPlayerName;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
localStorage.setItem('selectedPlayer', FULL_MAP_VIEW);
|
||||||
|
playerCentered = false;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
else if (lastKnownPositions[focusedPlayerName]) {
|
||||||
|
console.log("[radarflow] Focused player disappeared, switching to full map view");
|
||||||
|
localStorage.setItem('lastFocusedPlayer', focusedPlayerName);
|
||||||
|
lastFocusedPlayer = focusedPlayerName;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
localStorage.setItem('selectedPlayer', FULL_MAP_VIEW);
|
||||||
|
playerCentered = false;
|
||||||
|
update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +468,12 @@ function drawImage() {
|
|||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
if (playerCentered && focusedPlayerPos) {
|
if (focusedPlayerName === FULL_MAP_VIEW || !playerCentered) {
|
||||||
|
if (rotateMap && !temporarilyDisableRotation) {
|
||||||
|
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||||
|
ctx.translate(-canvas.width / 2, -canvas.height / 2);
|
||||||
|
}
|
||||||
|
} else if (playerCentered && focusedPlayerPos) {
|
||||||
if (playerCenteredZoom !== 1.0) {
|
if (playerCenteredZoom !== 1.0) {
|
||||||
ctx.translate(canvas.width / 2, canvas.height / 2);
|
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||||
ctx.scale(playerCenteredZoom, playerCenteredZoom);
|
ctx.scale(playerCenteredZoom, playerCenteredZoom);
|
||||||
@ -527,6 +622,10 @@ function updateZoomLevel(value) {
|
|||||||
function toggleCentered() {
|
function toggleCentered() {
|
||||||
playerCentered = !playerCentered;
|
playerCentered = !playerCentered;
|
||||||
updateZoomSliderVisibility();
|
updateZoomSliderVisibility();
|
||||||
|
if (focusedPlayerName === FULL_MAP_VIEW) {
|
||||||
|
playerCentered = false;
|
||||||
|
document.getElementById('centerCheck').checked = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateZoomSliderVisibility() {
|
function updateZoomSliderVisibility() {
|
||||||
@ -864,36 +963,99 @@ function updatePlayerDropdown() {
|
|||||||
if (!dropdown) return;
|
if (!dropdown) return;
|
||||||
|
|
||||||
const currentValue = dropdown.value;
|
const currentValue = dropdown.value;
|
||||||
|
const savedPlayer = localStorage.getItem('selectedPlayer');
|
||||||
|
|
||||||
while (dropdown.options.length > 1) {
|
while (dropdown.options.length > 0) {
|
||||||
dropdown.remove(1);
|
dropdown.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fullMapOption = document.createElement('option');
|
||||||
|
fullMapOption.value = FULL_MAP_VIEW;
|
||||||
|
fullMapOption.textContent = "FULL MAP";
|
||||||
|
dropdown.appendChild(fullMapOption);
|
||||||
|
|
||||||
|
const localOption = document.createElement('option');
|
||||||
|
localOption.value = "local";
|
||||||
|
localOption.textContent = "YOU";
|
||||||
|
dropdown.appendChild(localOption);
|
||||||
|
|
||||||
for (const playerName in playerList) {
|
for (const playerName in playerList) {
|
||||||
if (playerName !== "YOU") {
|
if (playerName !== LOCAL_PLAYER_VIEW && playerName !== FULL_MAP_VIEW) {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = playerName;
|
option.value = playerName;
|
||||||
option.textContent = playerName;
|
|
||||||
|
if (playerList[playerName].isDead) {
|
||||||
|
option.textContent = `${playerName} (DEAD)`;
|
||||||
|
option.style.color = "#777777";
|
||||||
|
} else {
|
||||||
|
option.textContent = playerName;
|
||||||
|
}
|
||||||
|
|
||||||
dropdown.appendChild(option);
|
dropdown.appendChild(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(playerList).includes(currentValue)) {
|
if (Object.keys(playerList).includes(currentValue) || currentValue === "local" || currentValue === FULL_MAP_VIEW) {
|
||||||
dropdown.value = currentValue;
|
dropdown.value = currentValue;
|
||||||
} else {
|
}
|
||||||
dropdown.value = "local";
|
else if (savedPlayer === FULL_MAP_VIEW) {
|
||||||
focusedPlayerName = "YOU";
|
dropdown.value = FULL_MAP_VIEW;
|
||||||
if (playerList["YOU"]) {
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
focusedPlayerPos = playerList["YOU"].pos;
|
playerCentered = false;
|
||||||
focusedPlayerYaw = playerList["YOU"].yaw;
|
}
|
||||||
|
else if (savedPlayer && Object.keys(playerList).includes(savedPlayer)) {
|
||||||
|
dropdown.value = savedPlayer;
|
||||||
|
focusedPlayerName = savedPlayer;
|
||||||
|
|
||||||
|
if (playerList[savedPlayer]?.isDead) {
|
||||||
|
dropdown.value = FULL_MAP_VIEW;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
localStorage.setItem('selectedPlayer', FULL_MAP_VIEW);
|
||||||
|
playerCentered = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dropdown.value = FULL_MAP_VIEW;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
localStorage.setItem('selectedPlayer', FULL_MAP_VIEW);
|
||||||
|
playerCentered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePlayerFocus() {
|
function changePlayerFocus() {
|
||||||
const dropdown = document.getElementById('playerSelect');
|
const dropdown = document.getElementById('playerSelect');
|
||||||
focusedPlayerName = dropdown.value === "local" ? "YOU" : dropdown.value;
|
|
||||||
rotationDisabledUntilRespawn = false;
|
if (dropdown.value !== "local" &&
|
||||||
|
dropdown.value !== FULL_MAP_VIEW &&
|
||||||
|
playerList[dropdown.value]?.isDead) {
|
||||||
|
|
||||||
|
console.log(`[radarflow] Attempted to focus on dead player ${dropdown.value}, switching to full map view`);
|
||||||
|
localStorage.setItem('lastFocusedPlayer', dropdown.value);
|
||||||
|
lastFocusedPlayer = dropdown.value;
|
||||||
|
dropdown.value = FULL_MAP_VIEW;
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
playerCentered = false;
|
||||||
|
}
|
||||||
|
else if (dropdown.value === FULL_MAP_VIEW) {
|
||||||
|
focusedPlayerName = FULL_MAP_VIEW;
|
||||||
|
playerCentered = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
localStorage.removeItem('lastFocusedPlayer');
|
||||||
|
lastFocusedPlayer = null;
|
||||||
|
focusedPlayerName = dropdown.value === "local" ? LOCAL_PLAYER_VIEW : dropdown.value;
|
||||||
|
|
||||||
|
playerCentered = document.getElementById('centerCheck').checked;
|
||||||
|
|
||||||
|
if (playerList[focusedPlayerName]) {
|
||||||
|
focusedPlayerPos = playerList[focusedPlayerName].pos;
|
||||||
|
focusedPlayerYaw = playerList[focusedPlayerName].yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotationDisabledUntilRespawn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('selectedPlayer', focusedPlayerName);
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,7 +1229,9 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i
|
|||||||
const arrowWidth = 35;
|
const arrowWidth = 35;
|
||||||
|
|
||||||
const isFocusedPlayer = playerName === focusedPlayerName ||
|
const isFocusedPlayer = playerName === focusedPlayerName ||
|
||||||
(focusedPlayerName === "YOU" && playerType === "Local");
|
(focusedPlayerName === LOCAL_PLAYER_VIEW && playerType === "Local");
|
||||||
|
|
||||||
|
const isDeadPlayer = playerList[playerName]?.isDead || false;
|
||||||
|
|
||||||
let adjustedYaw = yaw;
|
let adjustedYaw = yaw;
|
||||||
|
|
||||||
@ -1083,11 +1247,30 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dormant) {
|
if (dormant || isDeadPlayer) {
|
||||||
ctx.font = `bold ${transformed.textSize}px Arial`;
|
if (isDeadPlayer) {
|
||||||
ctx.textAlign = "center";
|
ctx.beginPath();
|
||||||
ctx.fillStyle = fillStyle;
|
ctx.arc(mapPos.x, mapPos.y, circleRadius, 0, 2 * Math.PI);
|
||||||
ctx.fillText("?", mapPos.x, mapPos.y);
|
ctx.fillStyle = "#777777";
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
|
||||||
|
const xSize = circleRadius * 0.7;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(mapPos.x - xSize, mapPos.y - xSize);
|
||||||
|
ctx.lineTo(mapPos.x + xSize, mapPos.y + xSize);
|
||||||
|
ctx.moveTo(mapPos.x + xSize, mapPos.y - xSize);
|
||||||
|
ctx.lineTo(mapPos.x - xSize, mapPos.y + xSize);
|
||||||
|
ctx.strokeStyle = "#000000";
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.closePath();
|
||||||
|
} else {
|
||||||
|
ctx.font = `bold ${transformed.textSize}px Arial`;
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
ctx.fillStyle = fillStyle;
|
||||||
|
ctx.fillText("?", mapPos.x, mapPos.y);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isFocusedPlayer) {
|
if (isFocusedPlayer) {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user