Skip to content

Commit

Permalink
33.0.2
Browse files Browse the repository at this point in the history
- SquadCalc now attempt to connect to SquadMortarOverlay regulary (no need to refresh squadcalc if SMO is launched after squadcalc)
- Moved websockets code for SMO to its own file
  • Loading branch information
sh4rkman authored Nov 14, 2024
2 parents 7f3ccba + 9fa5cb6 commit 81e5861
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 282 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@

# <img src="https://img.shields.io/badge/-minor%20release-cd6f68?style=for-the-badge"> **33.0.2** *(2024-11-14)*

<img src="https://img.shields.io/badge/-%20improv%20-orange"> SquadCalc now attempt to connect to SquadMortarOverlay regulary (no need to refresh squadcalc if SMO is launched after squadcalc) - [#219](https://github.com/sh4rkman/SquadCalc/pull/219)

<img src="https://img.shields.io/badge/-%20dev%20-grey"> Moved websockets code for SMO to its own file - [#219](https://github.com/sh4rkman/SquadCalc/pull/219)


</br></br><!-- CHANGELOG SPLIT MARKER -->




# <img src="https://img.shields.io/badge/-minor%20release-cd6f68?style=for-the-badge"> **33.0.1** *(2024-11-04)*
Expand Down
338 changes: 190 additions & 148 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "squadcalc",
"version": "33.0.1",
"version": "33.0.2",
"description": "A Complete Mortar Calculator for Squad",
"author": "Maxime 'sharkman' Boussard",
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions public/locales/en/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"focusMode": "Focus Mode",
"enterToExit": "Press 'ENTER' to exit",
"squadMortarOverlay": "SquadMortarOverlay detected",
"mapUpdated": "Map Updated",
"connectedTo": "Connected !",
"error": "Error!",
"apiError": "API isn't connected..",
Expand Down
1 change: 1 addition & 0 deletions public/locales/fr/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"focusMode": "Mode Focus",
"enterToExit": "Appuyez sur 'ENTRÉE' pour quitter",
"squadMortarOverlay": "SquadMortarOverlay détecté",
"mapUpdated": "Carte mise à jour",
"connectedTo": "Connecté !",
"error": "Erreur !",
"apiError": "L'API n'est pas connectée..",
Expand Down
1 change: 1 addition & 0 deletions public/locales/ru/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"focusMode": "Режим фокуса",
"enterToExit": "Нажмите 'Enter', чтобы выйти",
"squadMortarOverlay": "SquadMortarOverlay detected",
"mapUpdated": "Карта обновлена",
"connectedTo": "Connected !",
"error": "Ошибка!",
"apiError": "API не подключен..",
Expand Down
1 change: 1 addition & 0 deletions public/locales/uk/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"focusMode": "Режим фокусу",
"enterToExit": "Натисніть 'Enter', щоб вийти",
"squadMortarOverlay": "SquadMortarOverlay detected",
"Карту оновлено": "Карту оновлено",
"connectedTo": "Connected !",
"error": "Помилка!",
"apiError": "API не підключено..",
Expand Down
1 change: 1 addition & 0 deletions public/locales/zh/tooltips.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"focusMode": "专注模式",
"enterToExit": "按 'Enter' 退出",
"squadMortarOverlay": "SquadMortarOverlay detected",
"mapUpdated": "地图已更新",
"connectedTo": "Connected !",
"error": "错误!",
"apiError": "API 未连接..",
Expand Down
124 changes: 124 additions & 0 deletions src/js/smcConnector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { App } from "../app.js";

/**
* Initializes WebSocket connections for map and coordinate data communication
* Creates two WebSocket connections - one for map data and one for coordinates
* Handles connection events and data transfer between client and SquadMortarOverlay.exe
* @returns {Promise<void>} A promise that resolves when initialization is complete
*/
export async function initWebSocket() {
// Disable WebSockets if not activated
if (process.env.WEBSOCKET != "true") { return; }
while (!await checkServerAvailability()) {
await sleep(5000);
}
console.log('Trying to connect to SquadMortarOverlay')
const socketMap = new WebSocket("ws://127.0.0.1:12345");
const socketCoordinates = new WebSocket("ws://127.0.0.1:12346");
setInterval(() => checkCoordinates(socketCoordinates), 1000);

socketMap.addEventListener("open", () => {
console.log("Connected to SquadMortarOverlay.exe");
App.openToast("success", "connectedTo", "squadMortarOverlay");
});

socketMap.addEventListener("message", async (event) => {
if (event.data === "Map") {
if (socketMap.readyState === WebSocket.OPEN) {
let imageUrl = "maps" + App.minimap.activeMap.mapURL + "basemap.webp";
// Fetch the image and send its binary data
const response = await fetch(imageUrl);
const imageBlob = await response.blob();
const reader = new FileReader();
reader.onload = function () {
const arrayBuffer = this.result;
socketMap.send(arrayBuffer);
};
reader.readAsArrayBuffer(imageBlob);
App.minimap.changeLayer();
}
}
});

socketMap.addEventListener("message", (event) => {
if (event.data instanceof Blob) {
const url = URL.createObjectURL(event.data);
App.minimap.activeLayer.setUrl(url);
App.openToast("success", "mapUpdated", "");
}
});
}

/**
* Utility function to create a promise that resolves after specified milliseconds
* @param {number} ms - The number of milliseconds to sleep
* @returns {Promise<void>} A promise that resolves after the specified delay
*/
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

/**
* Checks and sends updated coordinate information through WebSocket
* Processes each target marker to extract bearing and elevation data
* Formats the data as a string and sends it if changed from previous update
* @param {WebSocket} socketCoordinates - WebSocket connection for sending coordinates
*/
function checkCoordinates(socketCoordinates) {
let coorArray = "";
let prevCoorArray = "";
if (App.minimap.activeTargetsMarkers) {
App.minimap.activeTargetsMarkers.eachLayer(function (target) {
const BEARING = target.firingSolution1.bearing;
let elevation;
if (App.minimap.activeWeaponsMarkers.getLayers()[0].angleType === "high") {
elevation = target.firingSolution1.elevation.high;
}
else {
elevation = target.firingSolution1.elevation.low;
}

if (isNaN(elevation)) {
elevation = "---";
} else {
if (App.activeWeapon.unit === "mil") {
elevation = elevation.mil.toFixed(0);
} else {
elevation = elevation.deg.toFixed(1);
}
}
if (coorArray !== "") {
coorArray = coorArray + "\n";
}
coorArray = coorArray + `${elevation} | ${BEARING.toFixed(1)}°`;
});
}
if (coorArray !== prevCoorArray) {
prevCoorArray = coorArray;
if (socketCoordinates.readyState === WebSocket.OPEN) {
socketCoordinates.send(coorArray);
}
}
}

/**
* Checks the availability of a SquadMortarOverlay.exe by attempting to load a fake image from it
* @param {number} [timeout] - The maximum time to wait for response
* @returns {Promise<boolean>} A promise that resolves to `true` if the SquadMortarOverlay.exe is running
*/
async function checkServerAvailability(timeout = 2000) {
return new Promise((resolve) => {
const img = new Image();
const timer = setTimeout(() => {
img.src = "";
resolve(false);
}, timeout);

img.onload = img.onerror = () => {
clearTimeout(timer);
resolve(true);
};

img.src = "http://127.0.0.1:12345";
});
}
3 changes: 2 additions & 1 deletion src/js/squadCalc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { loadSettings } from "./settings.js";
import { loadLanguage } from "./localization.js";
import { animateCSS, animateCalc } from "./animations.js";
import { tooltip_save, tooltip_copied } from "./tooltips.js";
import { checkApiHealth, initWebSocket } from "./squadCalcAPI.js";
import { checkApiHealth } from "./squadCalcAPI.js";
import { initWebSocket } from "./smcConnector.js";
import SquadFiringSolution from "./squadFiringSolution.js";
import packageInfo from "../../package.json";
import i18next from "i18next";
Expand Down
132 changes: 0 additions & 132 deletions src/js/squadCalcAPI.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import packageInfo from "../../package.json";
import { App } from "../app.js";


/**
* Sends marker data to the API via a POST request.
Expand Down Expand Up @@ -98,133 +96,3 @@ export async function fetchMarkersByMap(mapName, weapon) {
throw error;
}
}



export async function initWebSocket() {

// Disable WebSockets if not activated
if (process.env.WEBSOCKET != "true") { return; }
if (!await checkServerAvailability()) { return; }

const socketMap = new WebSocket("ws://127.0.0.1:12345");
const socketCoordinates = new WebSocket("ws://127.0.0.1:12346");
setInterval(() => checkCoordinates(socketCoordinates), 1000);

socketMap.addEventListener("open", () => {
console.log("Connected to SquadMortarOverlay.exe");
App.openToast("success", "connectedTo", "squadMortarOverlay");
});

socketMap.addEventListener("message", async (event) => {
if (event.data === "Map") {
if (socketMap.readyState === WebSocket.OPEN) {
let imageUrl = "maps" + App.minimap.activeMap.mapURL + "basemap.webp";
// Fetch the image and send its binary data
const response = await fetch(imageUrl);
const imageBlob = await response.blob();
const reader = new FileReader();
reader.onload = function() {
const arrayBuffer = this.result;
socketMap.send(arrayBuffer);
};
reader.readAsArrayBuffer(imageBlob);
App.minimap.changeLayer();
}
}
});

socketMap.addEventListener("message", (event) => {
if (event.data instanceof Blob) {
const url = URL.createObjectURL(event.data);
App.minimap.activeLayer.setUrl(url);
const notification = document.createElement("div");
notification.innerText = "Map Updated!";
notification.style.position = "fixed";
notification.style.top = "15px";
notification.style.left = "50%";
notification.style.transform = "translateX(-50%)";
notification.style.backgroundColor = "green";
notification.style.padding = "10px";
notification.style.borderRadius = "5px";
notification.style.zIndex = "1000";
notification.style.opacity = "0";
notification.style.transition = "opacity 0.5s";
document.body.appendChild(notification);

// Fade in
setTimeout(() => {
notification.style.opacity = "1";
}, 10); // Delay to ensure the element is rendered before starting the fade-in

// Fade out after 3 seconds
setTimeout(() => {
notification.style.opacity = "0";
// Remove the notification after fade out
setTimeout(() => {
document.body.removeChild(notification);
}, 500); // Match the duration of the opacity transition
}, 2500);
}
});
}


function checkCoordinates(socketCoordinates) {
let coorArray = "";
let prevCoorArray = "";
if (App.minimap.activeTargetsMarkers) {
App.minimap.activeTargetsMarkers.eachLayer(function (target) {
const BEARING = target.firingSolution1.bearing;
let elevation;
if (App.minimap.activeWeaponsMarkers.getLayers()[0].angleType === "high"){
elevation = target.firingSolution1.elevation.high;
}
else {
elevation = target.firingSolution1.elevation.low;
}

if (isNaN(elevation)) {
elevation = "---";
} else {
if (App.activeWeapon.unit === "mil") {
elevation = elevation.mil.toFixed(0);
} else {
elevation = elevation.deg.toFixed(1);
}
}
if (coorArray !== "") {
coorArray = coorArray + "\n";
}
coorArray = coorArray + `${elevation} | ${BEARING.toFixed(1)}°`;
});
}
if (coorArray !== prevCoorArray) {
prevCoorArray = coorArray;
if (socketCoordinates.readyState === WebSocket.OPEN) {
socketCoordinates.send(coorArray);
}
}
}

/**
* Checks the availability of a SquadMortarOverlay.exe by attempting to load a fake image from it
* @param {number} [timeout] - The maximum time to wait for response
* @returns {Promise<boolean>} A promise that resolves to `true` if the SquadMortarOverlay.exe is running
*/
function checkServerAvailability(timeout = 2000) {
return new Promise((resolve) => {
const img = new Image();
const timer = setTimeout(() => {
img.src = "";
resolve(false);
}, timeout);

img.onload = img.onerror = () => {
clearTimeout(timer);
resolve(true);
};

img.src = "http://127.0.0.1:12345";
});
}

0 comments on commit 81e5861

Please sign in to comment.