Merge branch 'v28'
@@ -69,13 +69,6 @@
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(139, 26, 26, 0.5),
|
||||
rgba(255, 255, 255, 0.5),
|
||||
rgba(39, 174, 96, 0.5)
|
||||
);
|
||||
}
|
||||
|
||||
.dark .bg-image {
|
||||
@@ -187,7 +180,6 @@
|
||||
<body
|
||||
class="h-full select-none font-sans min-h-screen bg-opacity-0 bg-cover bg-center bg-fixed transition-opacity duration-300 ease-in-out flex flex-col"
|
||||
>
|
||||
<div class="snow"></div>
|
||||
<header class="l-header">
|
||||
<div class="l-header__content">
|
||||
<svg
|
||||
@@ -206,10 +198,8 @@
|
||||
x2="100%"
|
||||
y2="0%"
|
||||
>
|
||||
<stop offset="0%" style="stop-color: #e53935" />
|
||||
<!-- Vibrant Red -->
|
||||
<stop offset="100%" style="stop-color: #388e3c" />
|
||||
<!-- Deep Green -->
|
||||
<stop offset="0%" style="stop-color: #2563eb" />
|
||||
<stop offset="100%" style="stop-color: #3b82f6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
@@ -332,7 +322,7 @@
|
||||
id="settings-button"
|
||||
title="Settings"
|
||||
class="fixed bottom-4 right-4 z-50 rounded-full p-2 shadow-lg transition-colors duration-300 flex items-center justify-center"
|
||||
style="width: 80px; height: 80px; background-color: var(--primaryColor)"
|
||||
style="width: 80px; height: 80px; background-color: #0075ff"
|
||||
>
|
||||
<img
|
||||
src="/images/SettingIconWhite.svg"
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"obscenity": "^0.4.3",
|
||||
"seedrandom": "^3.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.17.0",
|
||||
"uuid": "^11.1.0",
|
||||
"winston": "^3.17.0",
|
||||
"ws": "^8.18.0",
|
||||
@@ -89,7 +90,6 @@
|
||||
"sinon-chai": "^4.0.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.17.0",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.26.0",
|
||||
"vite": "^7.3.0",
|
||||
@@ -1300,7 +1300,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1317,7 +1316,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1334,7 +1332,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1351,7 +1348,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1368,7 +1364,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1385,7 +1380,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1402,7 +1396,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1419,7 +1412,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1436,7 +1428,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1453,7 +1444,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1470,7 +1460,6 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1487,7 +1476,6 @@
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1504,7 +1492,6 @@
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1521,7 +1508,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1538,7 +1524,6 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1555,7 +1540,6 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1572,7 +1556,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1589,7 +1572,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1606,7 +1588,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1623,7 +1604,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1640,7 +1620,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1674,7 +1653,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1691,7 +1669,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1708,7 +1685,6 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -1725,7 +1701,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -6956,7 +6931,6 @@
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
|
||||
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -7703,7 +7677,6 @@
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -7787,7 +7760,6 @@
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
|
||||
"integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
@@ -10406,7 +10378,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
@@ -11832,7 +11803,6 @@
|
||||
"version": "4.20.3",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz",
|
||||
"integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "~0.25.0",
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 240 B After Width: | Height: | Size: 126 B |
|
Before Width: | Height: | Size: 190 B |
|
Before Width: | Height: | Size: 411 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 573 B |
|
Before Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 140 B |
|
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 959 B |
|
After Width: | Height: | Size: 937 B |
|
After Width: | Height: | Size: 976 B |
@@ -379,7 +379,7 @@ export class AccountButton extends LitElement {
|
||||
<div class="fixed top-4 right-4 z-[9998]">
|
||||
<button
|
||||
@click="${this.open}"
|
||||
class="w-12 h-12 bg-red-600 hover:bg-red-700 text-white rounded-full shadow-2xl hover:shadow-2xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-red-500 focus:ring-offset-4"
|
||||
class="w-12 h-12 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-2xl hover:shadow-3xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-blue-500 focus:ring-offset-4"
|
||||
title="${buttonTitle}"
|
||||
>
|
||||
${this.renderIcon()}
|
||||
|
||||
@@ -43,7 +43,6 @@ import { UsernameInput } from "./UsernameInput";
|
||||
import { incrementGamesPlayed, isInIframe } from "./Utils";
|
||||
import "./components/baseComponents/Button";
|
||||
import "./components/baseComponents/Modal";
|
||||
import "./snow.css";
|
||||
import "./styles.css";
|
||||
import "./styles/components/button.css";
|
||||
import "./styles/components/controls.css";
|
||||
@@ -55,7 +54,6 @@ import "./styles/core/variables.css";
|
||||
import "./styles/layout/container.css";
|
||||
import "./styles/layout/header.css";
|
||||
import "./styles/modal/chat.css";
|
||||
import Snowflake3Png from "/images/Snowflake.webp?url";
|
||||
declare global {
|
||||
interface Window {
|
||||
turnstile: any;
|
||||
@@ -570,9 +568,6 @@ class Client {
|
||||
document.querySelectorAll(".ad").forEach((ad) => {
|
||||
(ad as HTMLElement).style.display = "none";
|
||||
});
|
||||
// Hide snowflakes when joining lobby
|
||||
document.documentElement.classList.add("in-game");
|
||||
removeSnowflakes(); // Stop snowflakes when joining a game
|
||||
|
||||
crazyGamesSDK.loadingStart();
|
||||
|
||||
@@ -618,9 +613,6 @@ class Client {
|
||||
|
||||
this.gutterAds.hide();
|
||||
this.publicLobby.leaveLobby();
|
||||
// Show snowflakes when leaving lobby (back to homepage)
|
||||
document.documentElement.classList.remove("in-game");
|
||||
enableSnowflakes(); // Restart snowflakes when leaving a game
|
||||
}
|
||||
|
||||
private handleKickPlayer(event: CustomEvent) {
|
||||
@@ -688,58 +680,12 @@ class Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
function enableSnowflakes() {
|
||||
// Respect user's motion preferences
|
||||
const prefersReducedMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)",
|
||||
).matches;
|
||||
if (prefersReducedMotion) {
|
||||
return;
|
||||
}
|
||||
|
||||
const snowContainer = document.querySelector(".snow") as HTMLElement;
|
||||
if (!snowContainer) {
|
||||
console.warn("Snow container element not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing snowflakes if any
|
||||
removeSnowflakes();
|
||||
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
const numberOfSnowflakes = isMobile ? 30 : 75; // Increased count
|
||||
|
||||
for (let i = 0; i < numberOfSnowflakes; i++) {
|
||||
const snowflake = document.createElement("div");
|
||||
snowflake.classList.add("snowflake");
|
||||
snowflake.style.left = `${Math.random() * 100}vw`; // Random horizontal position
|
||||
snowflake.style.animationDuration = `${Math.random() * 10 + 5}s`; // Random duration between 5-15s
|
||||
snowflake.style.animationDelay = `${Math.random() * -10}s`; // Random delay
|
||||
snowflake.style.opacity = `${Math.random() * 0.5 + 0.5}`; // Random opacity between 0.5-1
|
||||
const size = Math.random() * 20 + 10; // Random size between 10-30px
|
||||
snowflake.style.width = `${size}px`;
|
||||
snowflake.style.height = `${size}px`;
|
||||
snowflake.style.backgroundImage = `url(${Snowflake3Png})`;
|
||||
|
||||
snowContainer.appendChild(snowflake);
|
||||
}
|
||||
}
|
||||
|
||||
function removeSnowflakes() {
|
||||
const snowContainer = document.querySelector(".snow") as HTMLElement;
|
||||
if (snowContainer) {
|
||||
snowContainer.replaceChildren();
|
||||
}
|
||||
}
|
||||
// Initialize the client when the DOM is loaded
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
new Client().initialize();
|
||||
|
||||
// Initially enable snowflakes if not in-game
|
||||
if (!document.documentElement.classList.contains("in-game")) {
|
||||
enableSnowflakes();
|
||||
}
|
||||
});
|
||||
|
||||
async function getTurnstileToken(): Promise<{
|
||||
token: string;
|
||||
createdAt: number;
|
||||
|
||||
@@ -173,7 +173,7 @@ export class MatchmakingButton extends LitElement {
|
||||
<div class="z-[9999]">
|
||||
<button
|
||||
@click="${this.open}"
|
||||
class="w-full h-16 bg-red-600 hover:bg-red-700 text-white rounded-full shadow-2xl hover:shadow-2xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-red-500 focus:ring-offset-4"
|
||||
class="w-full h-16 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-2xl hover:shadow-3xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-blue-500 focus:ring-offset-4"
|
||||
title="${translateText("matchmaking_modal.title")}"
|
||||
>
|
||||
Matchmaking
|
||||
|
||||
@@ -7,7 +7,6 @@ import "./components/baseComponents/Button";
|
||||
import "./components/baseComponents/Modal";
|
||||
import changelog from "/changelog.md?url";
|
||||
import megaphone from "/images/Megaphone.svg?url";
|
||||
import santaHatIcon from "/images/SantaHat.webp?url";
|
||||
|
||||
@customElement("news-modal")
|
||||
export class NewsModal extends LitElement {
|
||||
@@ -167,10 +166,6 @@ export class NewsButton extends LitElement {
|
||||
src="${megaphone}"
|
||||
alt=${translateText("news.title")}
|
||||
/>
|
||||
<div
|
||||
class="santa-hat-overlay absolute bg-contain bg-no-repeat pointer-events-none"
|
||||
style="background-image: url('${santaHatIcon}')"
|
||||
></div>
|
||||
</button>
|
||||
</div>
|
||||
<news-modal></news-modal>
|
||||
|
||||
@@ -116,8 +116,8 @@ export class PublicLobby extends LitElement {
|
||||
?disabled=${this.isButtonDebounced}
|
||||
class="isolate grid h-40 grid-cols-[100%] grid-rows-[100%] place-content-stretch w-full overflow-hidden ${this
|
||||
.isLobbyHighlighted
|
||||
? "bg-gradient-to-r from-emerald-600 to-emerald-500"
|
||||
: "bg-gradient-to-r from-red-800 to-red-700"} text-white font-medium rounded-xl transition-opacity duration-200 hover:opacity-90 ${this
|
||||
? "bg-gradient-to-r from-green-600 to-green-500"
|
||||
: "bg-gradient-to-r from-blue-600 to-blue-500"} text-white font-medium rounded-xl transition-opacity duration-200 hover:opacity-90 ${this
|
||||
.isButtonDebounced
|
||||
? "opacity-70 cursor-not-allowed"
|
||||
: ""}"
|
||||
@@ -147,24 +147,27 @@ export class PublicLobby extends LitElement {
|
||||
: translateText("public_lobby.join")}
|
||||
</div>
|
||||
<div class="text-md font-medium text-white-400">
|
||||
<span class="text-sm text-red-800 bg-white rounded-sm px-1 mr-1">
|
||||
${fullModeLabel}
|
||||
</span>
|
||||
<span>
|
||||
${translateText(
|
||||
`map.${lobby.gameConfig.gameMap
|
||||
.toLowerCase()
|
||||
.replace(/[\s.]+/g, "")}`,
|
||||
)}
|
||||
</span>
|
||||
${fullModeLabel
|
||||
? html`<span
|
||||
class="text-sm ${this.isLobbyHighlighted
|
||||
? "text-green-600"
|
||||
: "text-blue-600"} bg-white rounded-sm px-1 ml-1"
|
||||
>${fullModeLabel}</span
|
||||
>`
|
||||
: ""}
|
||||
<span
|
||||
>${translateText(
|
||||
`map.${lobby.gameConfig.gameMap.toLowerCase().replace(/[\s.]+/g, "")}`,
|
||||
)}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-md font-medium text-white-400">
|
||||
<div class="text-md font-medium text-blue-100">
|
||||
${lobby.numClients} / ${lobby.gameConfig.maxPlayers}
|
||||
</div>
|
||||
<div class="text-md font-medium text-white-400">${timeDisplay}</div>
|
||||
<div class="text-md font-medium text-blue-100">${timeDisplay}</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -80,7 +80,7 @@ export class StatsModal extends LitElement {
|
||||
${translateText("stats_modal.loading")}
|
||||
</p>
|
||||
<div
|
||||
class="w-6 h-6 border-4 border-red-500 border-t-transparent rounded-full animate-spin"
|
||||
class="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"
|
||||
></div>
|
||||
</div>
|
||||
`;
|
||||
@@ -91,7 +91,7 @@ export class StatsModal extends LitElement {
|
||||
<div class="flex flex-col items-center justify-center p-6 text-white">
|
||||
<p class="mb-4 text-center">${this.error}</p>
|
||||
<button
|
||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 rounded text-sm font-medium"
|
||||
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded text-sm font-medium"
|
||||
@click=${() => this.loadLeaderboard()}
|
||||
>
|
||||
Retry
|
||||
@@ -225,7 +225,7 @@ export class StatsButton extends LitElement {
|
||||
<div class="fixed top-20 right-4 z-[9998]">
|
||||
<button
|
||||
@click="${this.open}"
|
||||
class="w-12 h-12 bg-red-600 hover:bg-red-700 text-white rounded-full shadow-2xl hover:shadow-2xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-red-500 focus:ring-offset-4"
|
||||
class="w-12 h-12 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-2xl hover:shadow-3xl transition-all duration-200 flex items-center justify-center text-xl focus:outline-none focus:ring-4 focus:ring-blue-500 focus:ring-offset-4"
|
||||
title="${translateText("stats_modal.title")}"
|
||||
>
|
||||
<img src="/icons/stats.svg" alt="Stats" class="w-6 h-6" />
|
||||
|
||||
@@ -71,10 +71,10 @@ export class OModal extends LitElement {
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
`;
|
||||
|
||||
public open() {
|
||||
this.isModalOpen = true;
|
||||
}
|
||||
|
||||
public close() {
|
||||
if (this.isModalOpen) {
|
||||
this.isModalOpen = false;
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import miniBigSmoke from "../../../resources/sprites/bigsmoke.png";
|
||||
import buildingExplosion from "../../../resources/sprites/buildingExplosion.png";
|
||||
import conquestSword from "../../../resources/sprites/conquestSword.png";
|
||||
import dust from "../../../resources/sprites/dust.png";
|
||||
import miniExplosion from "../../../resources/sprites/miniExplosion.png";
|
||||
import miniFire from "../../../resources/sprites/minifire.png";
|
||||
import nuke from "../../../resources/sprites/nukeExplosion.png";
|
||||
import conquestChampagne from "../../../resources/sprites/nyeve/conquest.png";
|
||||
import nukeEve from "../../../resources/sprites/nyeve/firework.png";
|
||||
import nukeEveCyan from "../../../resources/sprites/nyeve/firework_cyan.png";
|
||||
import nukeEveRed from "../../../resources/sprites/nyeve/firework_red.png";
|
||||
import nukeEveYellow from "../../../resources/sprites/nyeve/firework_yellow.png";
|
||||
import SAMExplosion from "../../../resources/sprites/samExplosion.png";
|
||||
import sinkingShip from "../../../resources/sprites/sinkingShip.png";
|
||||
import miniSmoke from "../../../resources/sprites/smoke.png";
|
||||
import miniSmokeAndFire from "../../../resources/sprites/smokeAndFire.png";
|
||||
import unitExplosion from "../../../resources/sprites/unitExplosion.png";
|
||||
import { Theme } from "../../core/configuration/Config";
|
||||
import { PlayerView } from "../../core/game/GameView";
|
||||
import { AnimatedSprite } from "./AnimatedSprite";
|
||||
import { FxType } from "./fx/Fx";
|
||||
import { colorizeCanvas } from "./SpriteLoader";
|
||||
import miniBigSmoke from "/sprites/bigsmoke.png?url";
|
||||
import buildingExplosion from "/sprites/buildingExplosion.png?url";
|
||||
import happyElf from "/sprites/christmas/happy_elf.png?url";
|
||||
import sadElf from "/sprites/christmas/sad_elf.png?url";
|
||||
import santa from "/sprites/christmas/santa.png?url";
|
||||
import snowman from "/sprites/christmas/snowman.png?url";
|
||||
import sparks from "/sprites/christmas/sparks.png?url";
|
||||
import conquestSword from "/sprites/conquestSword.png?url";
|
||||
import dust from "/sprites/dust.png?url";
|
||||
import miniExplosion from "/sprites/miniExplosion.png?url";
|
||||
import miniFire from "/sprites/minifire.png?url";
|
||||
import nuke from "/sprites/nukeExplosion.png?url";
|
||||
import SAMExplosion from "/sprites/samExplosion.png?url";
|
||||
import sinkingShip from "/sprites/sinkingShip.png?url";
|
||||
import miniSmoke from "/sprites/smoke.png?url";
|
||||
import miniSmokeAndFire from "/sprites/smokeAndFire.png?url";
|
||||
import unitExplosion from "/sprites/unitExplosion.png?url";
|
||||
|
||||
type AnimatedSpriteConfig = {
|
||||
url: string;
|
||||
@@ -140,50 +140,50 @@ const ANIMATED_SPRITE_CONFIG: Partial<Record<FxType, AnimatedSpriteConfig>> = {
|
||||
originX: 10,
|
||||
originY: 16,
|
||||
},
|
||||
[FxType.Santa]: {
|
||||
url: santa,
|
||||
frameWidth: 34,
|
||||
[FxType.ConquestChampagne]: {
|
||||
url: conquestChampagne,
|
||||
frameWidth: 28,
|
||||
frameCount: 8,
|
||||
frameDuration: 90,
|
||||
looping: true,
|
||||
originX: 16,
|
||||
originY: 15,
|
||||
},
|
||||
[FxType.Snowman]: {
|
||||
url: snowman,
|
||||
frameWidth: 16,
|
||||
frameCount: 19,
|
||||
frameDuration: 200,
|
||||
looping: false,
|
||||
originX: 8,
|
||||
originY: 12,
|
||||
originX: 14,
|
||||
originY: 23,
|
||||
},
|
||||
[FxType.HappyElf]: {
|
||||
url: happyElf,
|
||||
frameWidth: 7,
|
||||
frameCount: 5,
|
||||
[FxType.FireworkAll]: {
|
||||
url: nukeEve,
|
||||
frameWidth: 60,
|
||||
frameCount: 15,
|
||||
frameDuration: 90,
|
||||
looping: true,
|
||||
originX: 3,
|
||||
originY: 7,
|
||||
looping: false,
|
||||
originX: 30,
|
||||
originY: 30,
|
||||
},
|
||||
[FxType.SadElf]: {
|
||||
url: sadElf,
|
||||
frameWidth: 14,
|
||||
frameCount: 10,
|
||||
frameDuration: 90,
|
||||
looping: true,
|
||||
originX: 6,
|
||||
originY: 10,
|
||||
[FxType.FireworkRed]: {
|
||||
url: nukeEveRed,
|
||||
frameWidth: 30,
|
||||
frameCount: 9,
|
||||
frameDuration: 100,
|
||||
looping: false,
|
||||
originX: 15,
|
||||
originY: 20,
|
||||
},
|
||||
[FxType.Sparks]: {
|
||||
url: sparks,
|
||||
frameWidth: 13,
|
||||
[FxType.FireworkCyan]: {
|
||||
url: nukeEveCyan,
|
||||
frameWidth: 30,
|
||||
frameCount: 13,
|
||||
frameDuration: 60,
|
||||
frameDuration: 100,
|
||||
looping: false,
|
||||
originX: 6,
|
||||
originY: 6,
|
||||
originX: 15,
|
||||
originY: 20,
|
||||
},
|
||||
[FxType.FireworkYellow]: {
|
||||
url: nukeEveYellow,
|
||||
frameWidth: 30,
|
||||
frameCount: 15,
|
||||
frameDuration: 100,
|
||||
looping: false,
|
||||
originX: 15,
|
||||
originY: 20,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export function conquestFxFactory(
|
||||
animatedSpriteLoader,
|
||||
x,
|
||||
y,
|
||||
FxType.Conquest,
|
||||
FxType.ConquestChampagne,
|
||||
2500,
|
||||
);
|
||||
const fadeAnimation = new FadeFx(swordAnimation, 0.1, 0.6);
|
||||
|
||||
@@ -16,9 +16,9 @@ export enum FxType {
|
||||
UnderConstruction = "UnderConstruction",
|
||||
Dust = "Dust",
|
||||
Conquest = "Conquest",
|
||||
Santa = "Santa",
|
||||
Snowman = "Snowman",
|
||||
HappyElf = "HappyElf",
|
||||
SadElf = "SadElf",
|
||||
Sparks = "Sparks",
|
||||
FireworkAll = "FireworkAll",
|
||||
FireworkRed = "FireworkRed",
|
||||
FireworkYellow = "FireworkYellow",
|
||||
FireworkCyan = "FireworkCyan",
|
||||
ConquestChampagne = "ConquestChampagne",
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ function addSpriteInCircle(
|
||||
game.isLand(game.ref(spawnX, spawnY))
|
||||
) {
|
||||
const sprite = new FadeFx(
|
||||
new SpriteFx(animatedSpriteLoader, spawnX, spawnY, type, 6000),
|
||||
new SpriteFx(animatedSpriteLoader, spawnX, spawnY, type),
|
||||
0.1,
|
||||
0.8,
|
||||
);
|
||||
@@ -79,19 +79,16 @@ export function nukeFxFactory(
|
||||
): Fx[] {
|
||||
const nukeFx: Fx[] = [];
|
||||
// Explosion animation
|
||||
nukeFx.push(new SpriteFx(animatedSpriteLoader, x, y, FxType.Nuke));
|
||||
// Shockwave animation
|
||||
nukeFx.push(new ShockwaveFx(x, y, 1500, radius * 1.5));
|
||||
nukeFx.push(new SpriteFx(animatedSpriteLoader, x, y, FxType.FireworkAll));
|
||||
// Ruins and desolation sprites
|
||||
const debrisPlan: Array<{
|
||||
type: FxType;
|
||||
radiusFactor: number;
|
||||
density: number;
|
||||
}> = [
|
||||
{ type: FxType.HappyElf, radiusFactor: 1.0, density: 1 / 25 },
|
||||
{ type: FxType.SadElf, radiusFactor: 1.0, density: 1 / 28 },
|
||||
{ type: FxType.MiniBigSmoke, radiusFactor: 0.9, density: 1 / 70 },
|
||||
{ type: FxType.Snowman, radiusFactor: 0.9, density: 1 / 70 },
|
||||
{ type: FxType.FireworkRed, radiusFactor: 1.0, density: 1 / 28 },
|
||||
{ type: FxType.FireworkCyan, radiusFactor: 0.9, density: 1 / 70 },
|
||||
{ type: FxType.FireworkYellow, radiusFactor: 0.9, density: 1 / 70 },
|
||||
];
|
||||
|
||||
for (const { type, radiusFactor, density } of debrisPlan) {
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { Theme } from "../../../core/configuration/Config";
|
||||
import { PlayerView } from "../../../core/game/GameView";
|
||||
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
|
||||
import { Fx, FxType } from "./Fx";
|
||||
import { SpriteFx } from "./SpriteFx";
|
||||
|
||||
export class SantaFx implements Fx {
|
||||
private spriteFx: SpriteFx;
|
||||
private speed: number = 0.05; // px / ms
|
||||
|
||||
constructor(
|
||||
animatedSpriteLoader: AnimatedSpriteLoader,
|
||||
private startX: number,
|
||||
private startY: number,
|
||||
private endX: number,
|
||||
owner?: PlayerView,
|
||||
theme?: Theme,
|
||||
) {
|
||||
const distance = Math.abs(endX - startX);
|
||||
const duration = Math.max(distance / this.speed, 1);
|
||||
|
||||
this.spriteFx = new SpriteFx(
|
||||
animatedSpriteLoader,
|
||||
startX,
|
||||
startY,
|
||||
FxType.Santa,
|
||||
duration,
|
||||
owner,
|
||||
theme,
|
||||
);
|
||||
}
|
||||
|
||||
renderTick(frameTime: number, ctx: CanvasRenderingContext2D): boolean {
|
||||
const elapsed = this.spriteFx.getElapsedTime();
|
||||
const duration = this.spriteFx.getDuration();
|
||||
|
||||
const t = elapsed / duration;
|
||||
if (t >= 1) return false;
|
||||
|
||||
const x = this.startX + Math.floor((this.endX - this.startX) * t);
|
||||
const y = this.startY;
|
||||
this.spriteFx.setPosition(x, y);
|
||||
|
||||
return this.spriteFx.renderTick(frameTime, ctx);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import { conquestFxFactory } from "../fx/ConquestFx";
|
||||
import { Fx, FxType } from "../fx/Fx";
|
||||
import { NukeAreaFx } from "../fx/NukeAreaFx";
|
||||
import { nukeFxFactory, ShockwaveFx } from "../fx/NukeFx";
|
||||
import { SantaFx } from "../fx/SantaFx";
|
||||
import { SpriteFx } from "../fx/SpriteFx";
|
||||
import { TargetFx } from "../fx/TargetFx";
|
||||
import { TextFx } from "../fx/TextFx";
|
||||
@@ -34,9 +33,6 @@ export class FxLayer implements Layer {
|
||||
private boatTargetFxByUnitId: Map<number, TargetFx> = new Map();
|
||||
private nukeTargetFxByUnitId: Map<number, NukeAreaFx> = new Map();
|
||||
|
||||
private lastSantaTick = 0;
|
||||
private santaIntervalTicks = 60 * 10; // one each minute
|
||||
|
||||
constructor(private game: GameView) {
|
||||
this.theme = this.game.config().theme();
|
||||
}
|
||||
@@ -47,7 +43,6 @@ export class FxLayer implements Layer {
|
||||
|
||||
tick() {
|
||||
this.manageBoatTargetFx();
|
||||
this.spawnSantaIfNeeded();
|
||||
this.game
|
||||
.updatesSinceLastTick()
|
||||
?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id))
|
||||
@@ -76,24 +71,6 @@ export class FxLayer implements Layer {
|
||||
});
|
||||
}
|
||||
|
||||
private spawnSantaIfNeeded() {
|
||||
const currentTick = this.game.ticks();
|
||||
if (currentTick - this.lastSantaTick < this.santaIntervalTicks) {
|
||||
return;
|
||||
}
|
||||
this.lastSantaTick = currentTick;
|
||||
// Santa enters left side, exits right
|
||||
const margin = 50;
|
||||
const startX = -margin;
|
||||
const endX = this.game.width() + margin;
|
||||
const startY = Math.floor(
|
||||
margin + Math.random() * (this.game.height() - 2 * margin),
|
||||
);
|
||||
const santa = new SantaFx(this.animatedSpriteLoader, startX, startY, endX);
|
||||
|
||||
this.allFx.push(santa);
|
||||
}
|
||||
|
||||
private manageBoatTargetFx() {
|
||||
// End markers for boats that arrived or retreated
|
||||
for (const [unitId, fx] of Array.from(
|
||||
@@ -191,9 +168,6 @@ export class FxLayer implements Layer {
|
||||
this.onNukeEvent(unit, 70);
|
||||
break;
|
||||
}
|
||||
case UnitType.MIRV:
|
||||
this.addSparks(unit);
|
||||
break;
|
||||
case UnitType.MIRVWarhead:
|
||||
this.onNukeEvent(unit, 70);
|
||||
break;
|
||||
@@ -328,20 +302,6 @@ export class FxLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
addSparks(unit: UnitView) {
|
||||
if (unit.isActive()) {
|
||||
const x = this.game.x(unit.lastTile());
|
||||
const y = this.game.y(unit.lastTile());
|
||||
const sparks = new SpriteFx(
|
||||
this.animatedSpriteLoader,
|
||||
x,
|
||||
y,
|
||||
FxType.Sparks,
|
||||
);
|
||||
this.allFx.push(sparks);
|
||||
}
|
||||
}
|
||||
|
||||
onNukeEvent(unit: UnitView, radius: number) {
|
||||
if (!unit.isActive()) {
|
||||
const fx = this.nukeTargetFxByUnitId.get(unit.id());
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
.snow {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.snowflake {
|
||||
position: absolute;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
pointer-events: none;
|
||||
animation-name: snowflake-fall;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 10s; /* Adjust duration to taste */
|
||||
z-index: 10;
|
||||
opacity: 0.8; /* Default opacity */
|
||||
filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.5)); /* Subtle glow */
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
.santa-hat-overlay {
|
||||
position: absolute;
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
background-image: url("/resources/images/SantaHat.webp"); /* Use direct path for CSS background */
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@keyframes snowflake-fall {
|
||||
from {
|
||||
transform: translateY(-100%) rotate(0deg); /* Start off-screen */
|
||||
}
|
||||
to {
|
||||
transform: translateY(105vh) rotate(360deg); /* Fall completely out of view */
|
||||
}
|
||||
}
|
||||
|
||||
html.in-game .santa-hat-overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html.modal-active .santa-hat-overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.snowflake {
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
padding: 15px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: var(--primaryColor);
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
|
||||
.start-game-button:not(:disabled):hover {
|
||||
background-color: var(--primaryColorHover);
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.start-game-button:disabled {
|
||||
@@ -98,8 +98,8 @@
|
||||
}
|
||||
|
||||
.option-card.selected {
|
||||
border-color: var(--primaryColor);
|
||||
background: rgba(229, 57, 53, 0.1);
|
||||
border-color: #4a9eff;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.option-card-title {
|
||||
@@ -143,8 +143,8 @@ label.option-card:hover {
|
||||
}
|
||||
|
||||
.option-card.selected .checkbox-icon {
|
||||
border-color: var(--primaryColor);
|
||||
background: var(--primaryColor);
|
||||
border-color: #4a9eff;
|
||||
background: #4a9eff;
|
||||
}
|
||||
|
||||
.option-card.selected .checkbox-icon::after {
|
||||
@@ -242,14 +242,14 @@ label.option-card:hover {
|
||||
#bots-count::-moz-range-progress,
|
||||
#private-lobby-bots-count::-moz-range-progress {
|
||||
height: 8px;
|
||||
background-color: var(--primaryColor);
|
||||
background-color: #0075ff;
|
||||
}
|
||||
|
||||
#bots-count::-moz-range-thumb,
|
||||
#private-lobby-bots-count::-moz-range-thumb {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background: var(--primaryColor);
|
||||
background: #0075ff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@@ -260,7 +260,7 @@ label.option-card:hover {
|
||||
height: 8px;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
var(--primaryColor) var(--progress, 0%),
|
||||
#0075ff var(--progress, 0%),
|
||||
white var(--progress, 0%)
|
||||
);
|
||||
}
|
||||
@@ -270,7 +270,7 @@ label.option-card:hover {
|
||||
-webkit-appearance: none;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background: var(--primaryColor);
|
||||
background: #0075ff;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
margin-top: -4px;
|
||||
@@ -282,8 +282,8 @@ label.option-card:hover {
|
||||
}
|
||||
|
||||
.random-map.selected {
|
||||
border: 2px solid var(--primaryColor);
|
||||
background: rgba(229, 57, 53, 0.1);
|
||||
border: 2px solid #4a9eff;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
#helpModal table {
|
||||
@@ -592,11 +592,11 @@ label.option-card:hover {
|
||||
/* News Button Notification */
|
||||
news-button .active button {
|
||||
position: relative;
|
||||
border-color: var(--primaryColor) !important;
|
||||
border-color: #2563eb !important;
|
||||
border-width: 2px !important;
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(139, 26, 26, 0.5),
|
||||
0 0 8px rgba(139, 26, 26, 0.4);
|
||||
0 0 0 1px rgba(37, 99, 235, 0.5),
|
||||
0 0 8px rgba(37, 99, 235, 0.4);
|
||||
}
|
||||
|
||||
news-button .active button::after {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
.c-button--secondary {
|
||||
background: var(--secondaryColor);
|
||||
color: var(--fontColorLight);
|
||||
color: var(--fontColor);
|
||||
}
|
||||
|
||||
.c-button--secondary:hover,
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
--boxBackgroundColor: #111827cc;
|
||||
--fontColor: #202020;
|
||||
--fontColorLight: #fff;
|
||||
--primaryColor: #8b1a1a;
|
||||
--primaryColorHover: #6b1515;
|
||||
--primaryColor: #2563eb;
|
||||
--primaryColorHover: #1d4ed8;
|
||||
--primaryColorDisabled: linear-gradient(
|
||||
to right,
|
||||
rgba(139, 26, 26, 0.7),
|
||||
rgba(107, 21, 21, 0.7)
|
||||
rgb(74, 74, 74),
|
||||
rgb(61, 61, 61)
|
||||
);
|
||||
--secondaryColor: #27ae60;
|
||||
--secondaryColorHover: #1e8449;
|
||||
--secondaryColor: #dbeafe;
|
||||
--secondaryColorHover: #bfdbfe;
|
||||
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
--primaryColorDark: #8b1a1a;
|
||||
--primaryColorHoverDark: #6b1515;
|
||||
--primaryColorDisabledDark: rgba(139, 26, 26, 0.5);
|
||||
--secondaryColorDark: #27ae60;
|
||||
--secondaryColorHoverDark: #1e8449;
|
||||
--primaryColorDark: #3b82f6;
|
||||
--primaryColorHoverDark: #2563eb;
|
||||
--primaryColorDisabledDark: #4b5563;
|
||||
--secondaryColorDark: #374151;
|
||||
--secondaryColorHoverDark: #4b5563;
|
||||
--fontColorDark: #f3f4f6;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
.l-header__highlightText {
|
||||
color: var(--primaryColor);
|
||||
color: #2563eb;
|
||||
font-weight: 700;
|
||||
filter: drop-shadow(1px 1px 0px rgb(255, 255, 255))
|
||||
drop-shadow(-1px -1px 0px rgb(255, 255, 255))
|
||||
|
||||
@@ -94,6 +94,14 @@ export class GameManager {
|
||||
return totalClients;
|
||||
}
|
||||
|
||||
desyncCount(): number {
|
||||
let totalDesyncs = 0;
|
||||
this.games.forEach((game: GameServer) => {
|
||||
totalDesyncs += game.desyncCount;
|
||||
});
|
||||
return totalDesyncs;
|
||||
}
|
||||
|
||||
tick() {
|
||||
const active = new Map<GameID, GameServer>();
|
||||
for (const [id, game] of this.games) {
|
||||
|
||||
@@ -71,6 +71,8 @@ export class GameServer {
|
||||
{ winner: ClientSendWinnerMessage; ips: Set<string> }
|
||||
> = new Map();
|
||||
|
||||
public desyncCount = 0;
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
readonly log_: Logger,
|
||||
@@ -831,6 +833,8 @@ export class GameServer {
|
||||
const { mostCommonHash, outOfSyncClients } =
|
||||
this.findOutOfSyncClients(lastHashTurn);
|
||||
|
||||
this.desyncCount += outOfSyncClients.length;
|
||||
|
||||
if (outOfSyncClients.length === 0) {
|
||||
this.turns[lastHashTurn].hash = mostCommonHash;
|
||||
return;
|
||||
|
||||
@@ -59,6 +59,10 @@ export function initWorkerMetrics(gameManager: GameManager): void {
|
||||
},
|
||||
);
|
||||
|
||||
const desyncsGauge = meter.createObservableGauge("openfront.desyncs.gauge", {
|
||||
description: "Number of detected desyncs on active games on this worker",
|
||||
});
|
||||
|
||||
const memoryUsageGauge = meter.createObservableGauge(
|
||||
"openfront.memory_usage.bytes",
|
||||
{
|
||||
@@ -66,19 +70,21 @@ export function initWorkerMetrics(gameManager: GameManager): void {
|
||||
},
|
||||
);
|
||||
|
||||
// Register callback for active games metric
|
||||
activeGamesGauge.addCallback((result) => {
|
||||
const count = gameManager.activeGames();
|
||||
result.observe(count, getPromLabels());
|
||||
});
|
||||
|
||||
// Register callback for connected clients metric
|
||||
connectedClientsGauge.addCallback((result) => {
|
||||
const count = gameManager.activeClients();
|
||||
result.observe(count, getPromLabels());
|
||||
});
|
||||
|
||||
// Register callback for memory usage metric
|
||||
desyncsGauge.addCallback((result) => {
|
||||
const count = gameManager.desyncCount();
|
||||
result.observe(count, getPromLabels());
|
||||
});
|
||||
|
||||
memoryUsageGauge.addCallback((result) => {
|
||||
const memoryUsage = process.memoryUsage();
|
||||
result.observe(memoryUsage.heapUsed, getPromLabels());
|
||||
|
||||