felt/static/socket.js

236 lines
6.5 KiB
JavaScript
Raw Normal View History

let tableKey = {
name: "",
passcode: ""
}
let table = null;
let conn = null;
const secondaryPreviewZone = document.getElementById("tokenPreview_alt");
const secondaryPreviewIdInput = document.getElementById("tokenPreview_alt_id");
const dismissPreviewBtn = document.getElementById("tokenPreview_alt_clear");
function showTableModal(show) {
const modal = document.getElementById("table_modal");
if (modal) {
modal.style.display = show ? "block" : "none";
}
}
function fmtLeading(n) {
return n < 10 ? "0" + n : String(n);
}
2023-02-20 17:40:25 +00:00
function formatDice(r) {
const date = new Date(r.timestamp)
const p = document.createElement("p");
2023-07-08 05:56:41 +00:00
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
2023-07-08 05:56:41 +00:00
p.innerHTML = `${date.getFullYear()}-${fmtLeading(month)}-${fmtLeading(day)} ${fmtLeading(hours)}:${fmtLeading(minutes)}:${fmtLeading(seconds)} ${r.player} rolled ${r.roll.length}d${r.faces} ${(r.note ? "(" + r.note + ")" : "")}<br>[${r.roll}] (total ${r.roll.reduce((a,c)=>a+c,0)})`;
2023-07-08 05:56:41 +00:00
return p;
2023-02-20 17:40:25 +00:00
}
2023-07-09 06:48:19 +00:00
function logDice(dice) {
2023-02-20 17:40:25 +00:00
const diceLog = document.getElementById("dice_log");
2023-07-09 06:48:19 +00:00
if (!Array.isArray(dice)) {
dice = [ dice ];
} else {
if (diceLog) {
diceLog.innerHTML = "";
}
}
2023-02-20 17:40:25 +00:00
if (diceLog) {
for(const r of dice) {
const p = formatDice(r);
diceLog.append(p);
p.scrollIntoView();
2023-02-20 17:40:25 +00:00
}
}
}
2023-05-13 04:33:14 +00:00
function setAuxMsg(msg) {
const auxDiv = document.getElementById("aux");
if (auxDiv) {
auxDiv.innerText = msg;
}
}
2023-07-09 06:48:19 +00:00
function updateTokens(tokens) {
// update internal token array and map
processTokens(tokens);
// update token select window
renderTokenSelect();
// if admin, update token master list
renderTokenMasterList();
}
function renderTokenSelect() {
const tokenSelect = document.getElementById("token_select");
let tokenSelectHTML = "<ul class='single_btn_list'>";
for (const t of tokens) {
tokenSelectHTML += `<li><a href="#" onclick="initSpritePreviewById('${t.t.id}')">${t.t.name}</a><button onclick="toggleActive('${t.t.id}')">${(t.t.active ? "Deactivate" : "Activate")}</button></li>\n`;
2023-07-09 06:48:19 +00:00
}
tokenSelectHTML += "</ul>";
tokenSelect.innerHTML = tokenSelectHTML;
}
// the following few functions aren't socket related but they directly relate to the previous function
function initSpritePreviewById(id) {
const img = document.createElement("img");
const token = tokens.find(t=>t.t.id == id);
if (token && id) {
img.src = token.t.sprite;
secondaryPreviewIdInput.value = id;
img.onload = () => {
scaleAltSpritePreview();
}
}
dismissPreviewBtn.style.display = (token && id) ? "block" : "none";
secondaryPreviewZone.innerHTML = "";
secondaryPreviewZone.appendChild(img);
}
function dismissPreview() {
initSpritePreviewById(null);
}
function scaleAltSpritePreview() {
if (mapImg && mapImg._image) {
const id = secondaryPreviewIdInput.value;
const scaleFactor = mapImg._image.clientWidth / mapImg._image.naturalWidth;
const img = secondaryPreviewZone.children[0];
const token = tokens.find(t=>t.t.id == id);
if (img && token) {
img.width = token.t.w * scaleFactor;
img.height = token.t.h * scaleFactor;
}
}
}
2023-02-20 17:40:25 +00:00
function makeUpToDate(table) {
if (table) {
2023-07-09 06:48:19 +00:00
// map image has to be set before tokens can be handled!
2023-05-13 04:33:14 +00:00
if (table.mapImg) {
setMapImg(table.mapImg);
}
if (table.auxMsg) {
setAuxMsg(table.auxMsg);
}
2023-07-09 06:48:19 +00:00
if (table.diceRolls) {
logDice(table.diceRolls);
} else if (table.diceRoll) {
logDice(table.diceRoll);
2023-07-09 06:48:19 +00:00
}
if (table.tokens) {
updateTokens(table.tokens);
} else if (table.token) {
updateTokens([table.token]);
}
2023-02-20 17:40:25 +00:00
}
}
function setMapImg(url) {
2023-07-03 05:10:58 +00:00
initializeMap(url);
}
function isTableKeyValid(name, passcode) {
const r = /^[a-zA-Z0-9_]+$/;
return r.test(name) && r.test(passcode);
}
function dial() {
// get tableKey from UI
const tblNameInput = document.getElementById("input_table_name");
const tblPassInput = document.getElementById("input_table_pass");
if (tblNameInput && tblPassInput && tblNameInput.value && tblPassInput.value) {
if (isTableKeyValid(tblNameInput.value, tblPassInput.value)) {
tableKey.name = tblNameInput.value;
tableKey.passcode = tblPassInput.value;
if (conn) {
conn.close(1000);
}
2023-07-12 07:34:50 +00:00
const wsProto = location.protocol == "https:" ? "wss" : "ws";
conn = new WebSocket(`${wsProto}://${location.host}/subscribe`, `${tableKey.name}.${tableKey.passcode}`);
conn.addEventListener("close", e => {
2023-07-12 07:34:50 +00:00
if (e.code == 1006 && e.wasClean) {
setErr("Table not found - check the name and passcode are correct");
} else if (e.code > 1001) {
setErr("Websocket error: trying to reconnect");
setTimeout(dial, 1000)
} else {
tabletop = document.getElementById("tabletop");
if (tabletop) {
tabletop.style.display = "none";
}
table = null;
while (tokens.some(t=>t)) {
tokens[0].m.removeFrom(map);
tokens.shift();
}
mapImg.removeFrom(map);
mapImg = null;
}
});
conn.addEventListener("open", e => {
2023-07-12 07:34:50 +00:00
closeErr();
2023-02-20 17:40:25 +00:00
tabletop = document.getElementById("tabletop");
if (tabletop) {
tabletop.style.display = "block";
2023-02-20 17:40:25 +00:00
}
});
conn.addEventListener("error", e => {
setErr(`${e.name}: ${e.message}`);
conn.close(3000);
})
2023-05-13 04:33:14 +00:00
conn.addEventListener("message", e => {
const data = JSON.parse(e.data);
if (table == null) {
2023-07-09 06:48:19 +00:00
// dicerolls are treated as a byte array when marshalling to json, so we have to decode them
data.diceRolls.forEach(r=>{
r.roll = Uint8Array.from(atob(r.roll), c => c.charCodeAt(0))
})
table = data;
makeUpToDate(table);
} else {
if (data.diceRoll) {
data.diceRoll.roll = Uint8Array.from(atob(data.diceRoll.roll), c => c.charCodeAt(0));
}
makeUpToDate(data);
}
console.log(data);
});
} else {
setErr("Table name and passcode can only be alphanumeric and underscores");
}
}else {
setErr("Table name and passcode required");
}
2023-02-13 04:25:14 +00:00
}
async function publish(msg) {
msg.key = tableKey;
const res = await fetch('/publish', {
method: 'POST',
body: JSON.stringify(msg)
});
if (!res.ok) {
setErr("Failed to publish message");
}
}