Merge branch 'main' into mac

This commit is contained in:
Christopher Mesona
2025-06-09 16:10:43 +02:00
committed by Christopher Mesona
14 changed files with 77 additions and 47 deletions
+7 -2
View File
@@ -59,8 +59,13 @@ COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY startup.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/startup.sh
RUN mkdir -p /tmp/.cloudflared && chmod 777 /tmp/.cloudflared
ENV CF_CONFIG_DIR=/tmp/.cloudflared
RUN mkdir -p /etc/cloudflared && \
chown -R node:node /etc/cloudflared && \
chmod -R 755 /etc/cloudflared
# Set Cloudflared config directory to a volume mount location
ENV CF_CONFIG_PATH=/etc/cloudflared/config.yml
ENV CF_CREDS_PATH=/etc/cloudflared/creds.json
# Use the startup script as the entrypoint
ENTRYPOINT ["/usr/local/bin/startup.sh"]
+4 -3
View File
@@ -1,6 +1,6 @@
import { LitElement, html } from "lit";
import { customElement, query } from "lit/decorators.js";
import { getEmojiKey, getModifierKey, translateText } from "../client/Utils";
import { getAltKey, getModifierKey, translateText } from "../client/Utils";
import "./components/Difficulties";
import "./components/Maps";
@@ -67,7 +67,7 @@ export class HelpModal extends LitElement {
<tr>
<td>
<div class="scroll-combo-horizontal">
<span class="key">${getEmojiKey()}</span>
<span class="key">${getAltKey()}</span>
<span class="plus">+</span>
<div class="mouse-shell alt-left-click">
<div class="mouse-left-corner"></div>
@@ -116,7 +116,8 @@ export class HelpModal extends LitElement {
</tr>
<tr>
<td>
<span class="key">ALT</span> + <span class="key">R</span>
<span class="key">${getAltKey()}</span> +
<span class="key">R</span>
</td>
<td>${translateText("help_modal.action_reset_gfx")}</td>
</tr>
+7 -8
View File
@@ -129,7 +129,7 @@ export class InputHandler {
attackRatioUp: "Digit2",
boatAttack: "KeyB",
modifierKey: "ControlLeft",
emojiKey: "AltLeft",
altKey: "AltLeft",
...JSON.parse(localStorage.getItem("settings.keybinds") ?? "{}"),
};
@@ -137,7 +137,6 @@ export class InputHandler {
const isMac = /Mac/.test(navigator.userAgent);
if (isMac) {
this.keybinds.modifierKey = "MetaLeft"; // Use Command key on Mac
this.keybinds.emojiKey = "AltLeft"; // Use Option key for emoji menu on Mac
}
this.canvas.addEventListener("pointerdown", (e) => this.onPointerDown(e));
@@ -312,7 +311,7 @@ export class InputHandler {
this.eventBus.emit(new ShowBuildMenuEvent(event.clientX, event.clientY));
return;
}
if (this.isEmojiKeyPressed(event)) {
if (this.isAltKeyPressed(event)) {
this.eventBus.emit(new ShowEmojiMenuEvent(event.clientX, event.clientY));
return;
}
@@ -421,12 +420,12 @@ export class InputHandler {
);
}
isEmojiKeyPressed(event: PointerEvent): boolean {
isAltKeyPressed(event: PointerEvent): boolean {
return (
(this.keybinds.emojiKey === "AltLeft" && event.altKey) ||
(this.keybinds.emojiKey === "ControlLeft" && event.ctrlKey) ||
(this.keybinds.emojiKey === "ShiftLeft" && event.shiftKey) ||
(this.keybinds.emojiKey === "MetaLeft" && event.metaKey)
(this.keybinds.altKey === "AltLeft" && event.altKey) ||
(this.keybinds.altKey === "ControlLeft" && event.ctrlKey) ||
(this.keybinds.altKey === "ShiftLeft" && event.shiftKey) ||
(this.keybinds.altKey === "MetaLeft" && event.metaKey)
);
}
}
+3
View File
@@ -290,6 +290,9 @@ class Client {
() => {
console.log("Closing modals");
document.getElementById("settings-button")?.classList.add("hidden");
document
.getElementById("username-validation-error")
?.classList.add("hidden");
[
"single-player-modal",
"host-lobby-modal",
+1
View File
@@ -47,6 +47,7 @@ export class UsernameInput extends LitElement {
/>
${this.validationError
? html`<div
id="username-validation-error"
class="absolute z-10 w-full mt-2 px-3 py-1 text-lg border rounded bg-white text-red-600 border-red-600 dark:bg-gray-700 dark:text-red-300 dark:border-red-300"
>
${this.validationError}
+2 -2
View File
@@ -160,11 +160,11 @@ export function getModifierKey(): string {
}
}
export function getEmojiKey(): string {
export function getAltKey(): string {
const isMac = /Mac/.test(navigator.userAgent);
if (isMac) {
return "⌥"; // Option key
} else {
return "Ctrl";
return "Alt";
}
}
-1
View File
@@ -63,7 +63,6 @@ export class TeamStats extends LitElement implements Layer {
let totalScoreSort = 0;
for (const p of teamPlayers) {
totalGold += p.gold();
if (p.isAlive()) {
totalTroops += p.troops();
totalGold += p.gold();
+2 -1
View File
@@ -60,7 +60,8 @@ export interface ServerConfig {
subdomain(): string;
cloudflareAccountId(): string;
cloudflareApiToken(): string;
cloudflareConfigDir(): string;
cloudflareConfigPath(): string;
cloudflareCredsPath(): string;
}
export interface NukeMagnitude {
+6 -2
View File
@@ -78,9 +78,13 @@ export abstract class DefaultServerConfig implements ServerConfig {
cloudflareApiToken(): string {
return process.env.CF_API_TOKEN ?? "";
}
cloudflareConfigDir(): string {
return process.env.CF_CONFIG_DIR ?? "";
cloudflareConfigPath(): string {
return process.env.CF_CONFIG_PATH ?? "";
}
cloudflareCredsPath(): string {
return process.env.CF_CREDS_PATH ?? "";
}
private publicKey: JWK;
abstract jwtAudience(): string;
jwtIssuer(): string {
+1
View File
@@ -470,6 +470,7 @@ export class FakeHumanExecution implements Execution {
this.mg.isOceanShore(t),
)
: Array.from(this.player.tiles());
if (tiles.length === 0) return null;
return this.random.randElement(tiles);
}
+23 -20
View File
@@ -1,7 +1,6 @@
import { spawn } from "child_process";
import { promises as fs } from "fs";
import yaml from "js-yaml";
import { join } from "path";
import { logger } from "./Logger";
const log = logger.child({
@@ -48,9 +47,11 @@ export class Cloudflare {
constructor(
private accountId: string,
private apiToken: string,
private configDir: string,
private configPath: string,
private credsPath: string,
) {
log.info(`Using config directory: ${this.configDir}`);
log.info(`Using config: ${this.configPath}`);
log.info(`Using credentials: ${this.credsPath}`);
}
private async makeRequest<T>(
@@ -77,11 +78,19 @@ export class Cloudflare {
return response.json() as Promise<T>;
}
public async configAlreadyExists(): Promise<boolean> {
try {
await fs.access(this.configPath);
return true;
} catch {
return false;
}
}
public async createTunnel(config: TunnelConfig): Promise<{
tunnelId: string;
tunnelToken: string;
tunnelUrl: string;
configPath: string;
}> {
const { domain, subdomain, subdomainToService } = config;
@@ -108,7 +117,7 @@ export class Cloudflare {
log.info(`Tunnel created with ID: ${tunnelId}`);
// Create local config file instead of using API configuration
const configPath = await this.writeTunnelConfig(
await this.writeTunnelConfig(
tunnelId,
tunnelToken,
subdomain,
@@ -136,7 +145,7 @@ export class Cloudflare {
const tunnelUrl = `https://${subdomain}.${domain}`;
log.info(`Tunnel is set up! Site will be available at: ${tunnelUrl}`);
return { tunnelId, tunnelToken, tunnelUrl, configPath };
return { tunnelId, tunnelToken, tunnelUrl };
}
private async writeTunnelConfig(
@@ -146,12 +155,8 @@ export class Cloudflare {
domain: string,
subdomainToService: Map<string, string>,
tunnelName: string,
): Promise<string> {
): Promise<void> {
log.info(`Creating local config for tunnel ${subdomain}.${domain}...`);
const configPath = join(this.configDir, `${tunnelName}.yml`);
const credentialsFile = join(this.configDir, `${tunnelId}.json`);
const tokenData = JSON.parse(
Buffer.from(tunnelToken, "base64").toString("utf8"),
);
@@ -164,15 +169,15 @@ export class Cloudflare {
};
await fs.writeFile(
credentialsFile,
this.credsPath,
JSON.stringify(credentials, null, 2),
"utf8",
);
log.info(`Created credentials file at: ${credentialsFile}`);
log.info(`Created credentials file at: ${this.credsPath}`);
const tunnelConfig: CloudflaredConfig = {
tunnel: tunnelId,
"credentials-file": credentialsFile,
"credentials-file": this.credsPath,
ingress: [
...Array.from(subdomainToService.entries()).map(
([subdomain, service]) => ({
@@ -187,10 +192,8 @@ export class Cloudflare {
};
// Write config file
await fs.writeFile(configPath, yaml.dump(tunnelConfig), "utf8");
log.info(`Created config file at: ${configPath}`);
return configPath;
await fs.writeFile(this.configPath, yaml.dump(tunnelConfig), "utf8");
log.info(`Created config file at: ${this.configPath}`);
}
private async updateDNSRecord(
@@ -229,10 +232,10 @@ export class Cloudflare {
}
}
public async startCloudflared(configPath: string) {
public async startCloudflared() {
const cloudflared = spawn(
"cloudflared",
["tunnel", "--config", configPath, "--loglevel", "error", "run"],
["tunnel", "--config", this.configPath, "--loglevel", "error", "run"],
{
detached: true,
stdio: ["ignore", "pipe", "pipe"],
+12 -7
View File
@@ -36,7 +36,8 @@ async function setupTunnels() {
const cloudflare = new Cloudflare(
config.cloudflareAccountId(),
config.cloudflareApiToken(),
config.cloudflareConfigDir(),
config.cloudflareConfigPath(),
config.cloudflareCredsPath(),
);
const domainToService = new Map<string, string>().set(
@@ -51,11 +52,15 @@ async function setupTunnels() {
);
}
const tunnel = await cloudflare.createTunnel({
subdomain: config.subdomain(),
domain: config.domain(),
subdomainToService: domainToService,
} as TunnelConfig);
if (!(await cloudflare.configAlreadyExists())) {
await cloudflare.createTunnel({
subdomain: config.subdomain(),
domain: config.domain(),
subdomainToService: domainToService,
} as TunnelConfig);
} else {
console.log("Config already exists, skipping tunnel creation");
}
await cloudflare.startCloudflared(tunnel.configPath);
await cloudflare.startCloudflared();
}
+4 -1
View File
@@ -4,7 +4,10 @@ import { GameMapType } from "../../src/core/game/Game";
import { GameID } from "../../src/core/Schemas";
export class TestServerConfig implements ServerConfig {
cloudflareConfigDir(): string {
cloudflareConfigPath(): string {
throw new Error("Method not implemented.");
}
cloudflareCredsPath(): string {
throw new Error("Method not implemented.");
}
domain(): string {
+5
View File
@@ -58,10 +58,15 @@ else
fi
echo "Starting new container for ${HOST} environment..."
# Remove any existing volume for this container if it exists
docker volume rm "cloudflared-${CONTAINER_NAME}" 2> /dev/null || true
docker run -d \
--restart="${RESTART}" \
--env-file "$ENV_FILE" \
--name "${CONTAINER_NAME}" \
-v "cloudflared-${CONTAINER_NAME}:/etc/cloudflared" \
"${DOCKER_IMAGE}"
if [ $? -eq 0 ]; then