diff --git a/src/client/CrazyGamesSDK.ts b/src/client/CrazyGamesSDK.ts index b00cfe7de..7caf54de8 100644 --- a/src/client/CrazyGamesSDK.ts +++ b/src/client/CrazyGamesSDK.ts @@ -3,6 +3,22 @@ declare global { CrazyGames?: { SDK: { init: () => Promise; + user: { + getUser(): Promise<{ + username: string; + profilePictureUrl: string; + } | null>; + }; + ad: { + requestAd: ( + adType: string, + callbacks: { + adStarted: () => void; + adFinished: () => void; + adError: (error: any) => void; + }, + ) => void; + }; game: { gameplayStart: () => Promise; gameplayStop: () => Promise; @@ -15,6 +31,7 @@ declare global { }) => string; hideInviteButton: () => void; getInviteParam: (paramName: string) => string | null; + isInstantMultiplayer?: boolean; }; }; }; @@ -24,6 +41,24 @@ declare global { export class CrazyGamesSDK { private initialized = false; private isGameplayActive = false; + private readyPromise: Promise; + private resolveReady!: () => void; + + constructor() { + this.readyPromise = new Promise((resolve) => { + this.resolveReady = resolve; + }); + } + + async ready(): Promise { + const timeout = new Promise((resolve) => { + setTimeout(() => resolve(false), 3000); + }); + + const ready = this.readyPromise.then(() => true); + + return Promise.race([ready, timeout]); + } isOnCrazyGames(): boolean { try { @@ -70,12 +105,29 @@ export class CrazyGamesSDK { try { await window.CrazyGames.SDK.init(); this.initialized = true; + this.resolveReady(); console.log("CrazyGames SDK initialized"); } catch (error) { console.error("Failed to initialize CrazyGames SDK:", error); } } + async getUsername(): Promise { + const isReady = await this.ready(); + if (!isReady) { + return null; + } + return (await window.CrazyGames!.SDK.user.getUser())?.username ?? null; + } + + async isInstantMultiplayer(): Promise { + const isReady = await this.ready(); + if (!isReady) { + return false; + } + return window.CrazyGames!.SDK.game.isInstantMultiplayer ?? false; + } + async gameplayStart(): Promise { if (!this.isReady()) { return; @@ -200,6 +252,33 @@ export class CrazyGamesSDK { return null; } } + + requestMidgameAd(): Promise { + return new Promise((resolve) => { + if (!this.isReady()) { + resolve(); + return; + } + + try { + const callbacks = { + adFinished: () => { + console.log("End midgame ad"); + resolve(); + }, + adError: (error: any) => { + console.log("Error midgame ad", error); + resolve(); + }, + adStarted: () => console.log("Start midgame ad"), + }; + window.CrazyGames!.SDK.ad.requestAd("midgame", callbacks); + } catch (error) { + console.error("Failed to request midgame ad:", error); + resolve(); + } + }); + } } export const crazyGamesSDK = new CrazyGamesSDK(); diff --git a/src/client/Main.ts b/src/client/Main.ts index f2cdae39d..378ce78d3 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -214,6 +214,7 @@ class Client { private usernameInput: UsernameInput | null = null; private flagInput: FlagInput | null = null; + private hostModal: HostPrivateLobbyModal; private joinModal: JoinPrivateLobbyModal; private publicLobby: PublicLobby; private userSettings: UserSettings = new UserSettings(); @@ -522,10 +523,10 @@ class Client { } }); - const hostModal = document.querySelector( + this.hostModal = document.querySelector( "host-lobby-modal", ) as HostPrivateLobbyModal; - if (!hostModal || !(hostModal instanceof HostPrivateLobbyModal)) { + if (!this.hostModal || !(this.hostModal instanceof HostPrivateLobbyModal)) { console.warn("Host private lobby modal element not found"); } const hostLobbyButton = document.getElementById("host-lobby-button"); @@ -641,6 +642,14 @@ class Client { return; } } + crazyGamesSDK.isInstantMultiplayer().then((isInstant) => { + if (isInstant) { + console.log( + `CrazyGames: joining instant multiplayer lobby from CrazyGames`, + ); + this.hostModal.open(); + } + }); const strip = () => history.replaceState( diff --git a/src/client/SinglePlayerModal.ts b/src/client/SinglePlayerModal.ts index 12c805751..cf6b146f8 100644 --- a/src/client/SinglePlayerModal.ts +++ b/src/client/SinglePlayerModal.ts @@ -27,6 +27,7 @@ import "./components/FluentSlider"; import "./components/Maps"; import { modalHeader } from "./components/ui/ModalHeader"; import { fetchCosmetics } from "./Cosmetics"; +import { crazyGamesSDK } from "./CrazyGamesSDK"; import { FlagInput } from "./FlagInput"; import { JoinLobbyEvent } from "./Main"; import { UsernameInput } from "./UsernameInput"; @@ -839,6 +840,8 @@ export class SinglePlayerModal extends BaseModal { const selectedColor = this.userSettings.getSelectedColor(); + await crazyGamesSDK.requestMidgameAd(); + this.dispatchEvent( new CustomEvent("join-lobby", { detail: { diff --git a/src/client/UsernameInput.ts b/src/client/UsernameInput.ts index 20b2bb372..f7ea3f511 100644 --- a/src/client/UsernameInput.ts +++ b/src/client/UsernameInput.ts @@ -8,6 +8,7 @@ import { MIN_USERNAME_LENGTH, validateUsername, } from "../core/validations/username"; +import { crazyGamesSDK } from "./CrazyGamesSDK"; const usernameKey: string = "username"; @@ -39,7 +40,7 @@ export class UsernameInput extends LitElement { connectedCallback() { super.connectedCallback(); - const stored = this.getStoredUsername(); + const stored = this.getUsername(); this.parseAndSetUsername(stored); } @@ -161,7 +162,14 @@ export class UsernameInput extends LitElement { } } - private getStoredUsername(): string { + private getUsername(): string { + crazyGamesSDK.getUsername().then((username) => { + if (username) { + this.baseUsername = username; + this.requestUpdate(); + } + return null; + }); const storedUsername = localStorage.getItem(usernameKey); if (storedUsername) { return storedUsername; diff --git a/src/client/graphics/layers/GameRightSidebar.ts b/src/client/graphics/layers/GameRightSidebar.ts index e86317a7c..2ee9ee276 100644 --- a/src/client/graphics/layers/GameRightSidebar.ts +++ b/src/client/graphics/layers/GameRightSidebar.ts @@ -105,10 +105,15 @@ export class GameRightSidebar extends LitElement implements Layer { private onPauseButtonClick() { this.isPaused = !this.isPaused; + if (this.isPaused) { + crazyGamesSDK.gameplayStop(); + } else { + crazyGamesSDK.gameplayStart(); + } this.eventBus.emit(new PauseGameIntentEvent(this.isPaused)); } - private onExitButtonClick() { + private async onExitButtonClick() { const isAlive = this.game.myPlayer()?.isAlive(); if (isAlive) { const isConfirmed = confirm( @@ -116,10 +121,10 @@ export class GameRightSidebar extends LitElement implements Layer { ); if (!isConfirmed) return; } - crazyGamesSDK.gameplayStop().then(() => { - // redirect to the home page - window.location.href = "/"; - }); + await crazyGamesSDK.requestMidgameAd(); + await crazyGamesSDK.gameplayStop(); + // redirect to the home page + window.location.href = "/"; } private onSettingsButtonClick() { diff --git a/src/client/graphics/layers/SettingsModal.ts b/src/client/graphics/layers/SettingsModal.ts index 92d8f1fe4..0a5b184bf 100644 --- a/src/client/graphics/layers/SettingsModal.ts +++ b/src/client/graphics/layers/SettingsModal.ts @@ -1,9 +1,10 @@ import { html, LitElement } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; +import { crazyGamesSDK } from "src/client/CrazyGamesSDK"; +import { PauseGameIntentEvent } from "src/client/Transport"; import { EventBus } from "../../../core/EventBus"; import { UserSettings } from "../../../core/game/UserSettings"; import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler"; -import { PauseGameIntentEvent } from "../../Transport"; import { translateText } from "../../Utils"; import SoundManager from "../../sound/SoundManager"; import { Layer } from "./Layer"; @@ -105,8 +106,14 @@ export class SettingsModal extends LitElement implements Layer { } private pauseGame(pause: boolean) { - if (this.shouldPause && !this.wasPausedWhenOpened) + if (this.shouldPause && !this.wasPausedWhenOpened) { + if (pause) { + crazyGamesSDK.gameplayStop(); + } else { + crazyGamesSDK.gameplayStart(); + } this.eventBus.emit(new PauseGameIntentEvent(pause)); + } } private onTerrainButtonClick() { diff --git a/src/client/graphics/layers/UnitDisplay.ts b/src/client/graphics/layers/UnitDisplay.ts index 4b9a5d60c..c08bcb183 100644 --- a/src/client/graphics/layers/UnitDisplay.ts +++ b/src/client/graphics/layers/UnitDisplay.ts @@ -130,7 +130,7 @@ export class UnitDisplay extends LitElement implements Layer { return html`