Skip to content

Commit 1af8694

Browse files
committed
crazygames
1 parent e1d31ef commit 1af8694

16 files changed

+280
-101
lines changed

src/client/CrazyGamesSDK.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ declare global {
33
CrazyGames?: {
44
SDK: {
55
init: () => Promise<void>;
6+
user: {
7+
getUser(): Promise<{
8+
username: string;
9+
} | null>;
10+
addAuthListener: (
11+
listener: (
12+
user: {
13+
username: string;
14+
} | null,
15+
) => void,
16+
) => void;
17+
};
18+
ad: {
19+
requestAd: (
20+
adType: string,
21+
callbacks: {
22+
adStarted: () => void;
23+
adFinished: () => void;
24+
adError: (error: any) => void;
25+
},
26+
) => void;
27+
};
628
game: {
729
gameplayStart: () => Promise<void>;
830
gameplayStop: () => Promise<void>;
@@ -14,7 +36,9 @@ declare global {
1436
[key: string]: string | number;
1537
}) => string;
1638
hideInviteButton: () => void;
39+
inviteLink: (params: { [key: string]: string | number }) => string;
1740
getInviteParam: (paramName: string) => string | null;
41+
isInstantMultiplayer?: boolean;
1842
};
1943
};
2044
};
@@ -24,8 +48,27 @@ declare global {
2448
export class CrazyGamesSDK {
2549
private initialized = false;
2650
private isGameplayActive = false;
51+
private readyPromise: Promise<void>;
52+
private resolveReady!: () => void;
53+
54+
constructor() {
55+
this.readyPromise = new Promise((resolve) => {
56+
this.resolveReady = resolve;
57+
});
58+
}
59+
60+
async ready(): Promise<boolean> {
61+
const timeout = new Promise<boolean>((resolve) => {
62+
setTimeout(() => resolve(false), 3000);
63+
});
64+
65+
const ready = this.readyPromise.then(() => true);
66+
67+
return Promise.race([ready, timeout]);
68+
}
2769

2870
isOnCrazyGames(): boolean {
71+
return true;
2972
try {
3073
// Check if we're in an iframe
3174
if (window.self !== window.top) {
@@ -70,12 +113,49 @@ export class CrazyGamesSDK {
70113
try {
71114
await window.CrazyGames.SDK.init();
72115
this.initialized = true;
116+
this.resolveReady();
73117
console.log("CrazyGames SDK initialized");
74118
} catch (error) {
75119
console.error("Failed to initialize CrazyGames SDK:", error);
76120
}
77121
}
78122

123+
async getUsername(): Promise<string | null> {
124+
const isReady = await this.ready();
125+
if (!isReady) {
126+
return null;
127+
}
128+
return (await window.CrazyGames!.SDK.user.getUser())?.username ?? null;
129+
}
130+
131+
addAuthListener(
132+
listener: (
133+
user: {
134+
username: string;
135+
} | null,
136+
) => void,
137+
): void {
138+
if (!this.isReady()) {
139+
console.warn("CrazyGames SDK not ready, auth listener will not be added");
140+
return;
141+
}
142+
143+
try {
144+
window.CrazyGames!.SDK.user.addAuthListener(listener);
145+
console.log("CrazyGames: auth listener added");
146+
} catch (error) {
147+
console.error("Failed to add auth listener:", error);
148+
}
149+
}
150+
151+
async isInstantMultiplayer(): Promise<boolean> {
152+
const isReady = await this.ready();
153+
if (!isReady) {
154+
return false;
155+
}
156+
return window.CrazyGames!.SDK.game.isInstantMultiplayer ?? false;
157+
}
158+
79159
async gameplayStart(): Promise<void> {
80160
if (!this.isReady()) {
81161
return;
@@ -186,6 +266,22 @@ export class CrazyGamesSDK {
186266
}
187267
}
188268

269+
createInviteLink(gameId: string): string | null {
270+
if (!this.isReady()) {
271+
console.warn("CrazyGames SDK not ready, cannot create invite link");
272+
return null;
273+
}
274+
275+
try {
276+
const link = window.CrazyGames!.SDK.game.inviteLink({ gameId });
277+
console.log("CrazyGames: created invite link:", link);
278+
return link;
279+
} catch (error) {
280+
console.error("Failed to create invite link:", error);
281+
return null;
282+
}
283+
}
284+
189285
getInviteGameId(): string | null {
190286
if (!this.isReady()) {
191287
return null;
@@ -200,6 +296,33 @@ export class CrazyGamesSDK {
200296
return null;
201297
}
202298
}
299+
300+
requestMidgameAd(): Promise<void> {
301+
return new Promise((resolve) => {
302+
if (!this.isReady()) {
303+
resolve();
304+
return;
305+
}
306+
307+
try {
308+
const callbacks = {
309+
adFinished: () => {
310+
console.log("End midgame ad");
311+
resolve();
312+
},
313+
adError: (error: any) => {
314+
console.log("Error midgame ad", error);
315+
resolve();
316+
},
317+
adStarted: () => console.log("Start midgame ad"),
318+
};
319+
window.CrazyGames!.SDK.ad.requestAd("midgame", callbacks);
320+
} catch (error) {
321+
console.error("Failed to request midgame ad:", error);
322+
resolve();
323+
}
324+
});
325+
}
203326
}
204327

205328
export const crazyGamesSDK = new CrazyGamesSDK();

src/client/HostLobbyModal.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ export class HostLobbyModal extends BaseModal {
113113
}
114114

115115
private async buildLobbyUrl(): Promise<string> {
116+
if (crazyGamesSDK.isOnCrazyGames()) {
117+
const link = crazyGamesSDK.createInviteLink(this.lobbyId);
118+
if (link !== null) {
119+
return link;
120+
}
121+
}
116122
const config = await getServerConfigFromClient();
117123
return `${window.location.origin}/${config.workerPath(this.lobbyId)}/game/${this.lobbyId}?lobby&s=${encodeURIComponent(this.lobbyUrlSuffix)}`;
118124
}

src/client/LangSelector.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export class LangSelector extends LitElement {
228228
"stats-modal",
229229
"flag-input-modal",
230230
"flag-input",
231+
"matchmaking-button",
231232
];
232233

233234
document.title = this.translateText("main.title") ?? document.title;

src/client/Main.ts

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ class Client {
214214
private usernameInput: UsernameInput | null = null;
215215
private flagInput: FlagInput | null = null;
216216

217+
private hostModal: HostPrivateLobbyModal;
217218
private joinModal: JoinPrivateLobbyModal;
218219
private publicLobby: PublicLobby;
219220
private userSettings: UserSettings = new UserSettings();
@@ -431,56 +432,8 @@ class Client {
431432
) {
432433
console.warn("Matchmaking modal element not found");
433434
}
434-
const matchmakingButton = document.getElementById("matchmaking-button");
435-
const matchmakingButtonLoggedOut = document.getElementById(
436-
"matchmaking-button-logged-out",
437-
);
438-
439-
const updateMatchmakingButton = (loggedIn: boolean) => {
440-
if (!loggedIn) {
441-
matchmakingButton?.classList.add("hidden");
442-
matchmakingButtonLoggedOut?.classList.remove("hidden");
443-
} else {
444-
matchmakingButton?.classList.remove("hidden");
445-
matchmakingButtonLoggedOut?.classList.add("hidden");
446-
}
447-
};
448-
449-
if (matchmakingButton) {
450-
matchmakingButton.addEventListener("click", () => {
451-
if (this.usernameInput?.isValid()) {
452-
window.showPage?.("page-matchmaking");
453-
this.publicLobby.leaveLobby();
454-
} else {
455-
window.dispatchEvent(
456-
new CustomEvent("show-message", {
457-
detail: {
458-
message: this.usernameInput?.validationError,
459-
color: "red",
460-
duration: 3000,
461-
},
462-
}),
463-
);
464-
}
465-
});
466-
}
467-
468-
if (matchmakingButtonLoggedOut) {
469-
matchmakingButtonLoggedOut.addEventListener("click", () => {
470-
window.showPage?.("page-account");
471-
});
472-
}
473435

474436
const onUserMe = async (userMeResponse: UserMeResponse | false) => {
475-
// Check if user has actual authentication (discord or email), not just a publicId
476-
const loggedIn =
477-
userMeResponse !== false &&
478-
userMeResponse !== null &&
479-
typeof userMeResponse === "object" &&
480-
userMeResponse.user &&
481-
(userMeResponse.user.discord !== undefined ||
482-
userMeResponse.user.email !== undefined);
483-
updateMatchmakingButton(loggedIn);
484437
updateAccountNavButton(userMeResponse);
485438
document.dispatchEvent(
486439
new CustomEvent("userMeResponse", {
@@ -522,10 +475,10 @@ class Client {
522475
}
523476
});
524477

525-
const hostModal = document.querySelector(
478+
this.hostModal = document.querySelector(
526479
"host-lobby-modal",
527480
) as HostPrivateLobbyModal;
528-
if (!hostModal || !(hostModal instanceof HostPrivateLobbyModal)) {
481+
if (!this.hostModal || !(this.hostModal instanceof HostPrivateLobbyModal)) {
529482
console.warn("Host private lobby modal element not found");
530483
}
531484
const hostLobbyButton = document.getElementById("host-lobby-button");
@@ -633,14 +586,22 @@ class Client {
633586
private handleUrl() {
634587
// Check if CrazyGames SDK is enabled first (no hash needed in CrazyGames)
635588
if (crazyGamesSDK.isOnCrazyGames()) {
636-
const lobbyId = crazyGamesSDK.getInviteGameId();
589+
const lobbyId = crazyGamesSDK.createInviteLink();
637590
if (lobbyId && GAME_ID_REGEX.test(lobbyId)) {
638591
window.showPage?.("page-join-private-lobby");
639592
this.joinModal?.open(lobbyId);
640593
console.log(`CrazyGames: joining lobby ${lobbyId} from invite param`);
641594
return;
642595
}
643596
}
597+
crazyGamesSDK.isInstantMultiplayer().then((isInstant) => {
598+
if (isInstant) {
599+
console.log(
600+
`CrazyGames: joining instant multiplayer lobby from CrazyGames`,
601+
);
602+
this.hostModal.open();
603+
}
604+
});
644605

645606
const strip = () =>
646607
history.replaceState(
@@ -951,11 +912,27 @@ class Client {
951912
}
952913
}
953914

915+
// Hide elements with no-crazygames class if on CrazyGames
916+
const hideCrazyGamesElements = () => {
917+
if (crazyGamesSDK.isOnCrazyGames()) {
918+
document.querySelectorAll(".no-crazygames").forEach((el) => {
919+
(el as HTMLElement).style.display = "none";
920+
});
921+
}
922+
};
923+
954924
// Initialize the client when the DOM is loaded
955925
const bootstrap = () => {
956926
initLayout();
957927
new Client().initialize();
958928
initNavigation();
929+
930+
// Hide elements immediately
931+
hideCrazyGamesElements();
932+
933+
// Also hide elements after a short delay to catch late-rendered components
934+
setTimeout(hideCrazyGamesElements, 100);
935+
setTimeout(hideCrazyGamesElements, 500);
959936
};
960937

961938
if (document.readyState === "loading") {

0 commit comments

Comments
 (0)