mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
5 Commits
v5.4.209
...
use-multip
Author | SHA1 | Date | |
---|---|---|---|
![]() |
96d33a7ab8 | ||
![]() |
15cb723af9 | ||
![]() |
f0899e45e7 | ||
![]() |
1be148d5ee | ||
![]() |
a383c1e896 |
@@ -104,6 +104,9 @@ namespace gdjs {
|
||||
'gameVersion',
|
||||
runtimeGame.getGameData().properties.version
|
||||
);
|
||||
if (runtimeGame.getAdditionalOptions().nativeMobileApp) {
|
||||
url.searchParams.set('nativeMobileApp', 'true');
|
||||
}
|
||||
url.searchParams.set(
|
||||
'isPreview',
|
||||
runtimeGame.isPreview() ? 'true' : 'false'
|
||||
|
@@ -222,6 +222,8 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
}
|
||||
runtimeGameOptions.AddChild("projectDataOnlyExport")
|
||||
.SetBoolValue(options.projectDataOnlyExport);
|
||||
runtimeGameOptions.AddChild("nativeMobileApp")
|
||||
.SetBoolValue(options.nativeMobileApp);
|
||||
runtimeGameOptions.AddChild("websocketDebuggerServerAddress")
|
||||
.SetStringValue(options.websocketDebuggerServerAddress);
|
||||
runtimeGameOptions.AddChild("websocketDebuggerServerPort")
|
||||
|
@@ -37,6 +37,7 @@ struct PreviewExportOptions {
|
||||
: project(project_),
|
||||
exportPath(exportPath_),
|
||||
useWindowMessageDebuggerClient(false),
|
||||
nativeMobileApp(false),
|
||||
projectDataOnlyExport(false),
|
||||
fullLoadingScreen(false),
|
||||
isDevelopmentEnvironment(false),
|
||||
@@ -76,6 +77,15 @@ struct PreviewExportOptions {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set that the preview is launched from a GDevelop native mobile app
|
||||
* (iOS or Android).
|
||||
*/
|
||||
PreviewExportOptions &SetNativeMobileApp(bool enable) {
|
||||
nativeMobileApp = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the layout to be run first in the previewed game
|
||||
*/
|
||||
@@ -186,6 +196,7 @@ struct PreviewExportOptions {
|
||||
gd::String externalLayoutName;
|
||||
gd::String fallbackAuthorUsername;
|
||||
gd::String fallbackAuthorId;
|
||||
bool nativeMobileApp;
|
||||
std::map<gd::String, int> includeFileHashes;
|
||||
bool projectDataOnlyExport;
|
||||
bool fullLoadingScreen;
|
||||
|
@@ -32,6 +32,8 @@ namespace gdjs {
|
||||
scriptFiles?: Array<RuntimeGameOptionsScriptFile>;
|
||||
/** if true, export is a partial preview without events. */
|
||||
projectDataOnlyExport?: boolean;
|
||||
/** if true, preview is launched from GDevelop native mobile app. */
|
||||
nativeMobileApp?: boolean;
|
||||
/** The address of the debugger server, to reach out using WebSocket. */
|
||||
websocketDebuggerServerAddress?: string;
|
||||
/** The port of the debugger server, to reach out using WebSocket. */
|
||||
@@ -267,7 +269,7 @@ namespace gdjs {
|
||||
* Return the additional options passed to the RuntimeGame when created.
|
||||
* @returns The additional options, if any.
|
||||
*/
|
||||
getAdditionalOptions(): RuntimeGameOptions | null {
|
||||
getAdditionalOptions(): RuntimeGameOptions {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
|
@@ -3569,6 +3569,7 @@ interface PreviewExportOptions {
|
||||
[Ref] PreviewExportOptions SetExternalLayoutName([Const] DOMString externalLayoutName);
|
||||
[Ref] PreviewExportOptions SetIncludeFileHash([Const] DOMString includeFile, long hash);
|
||||
[Ref] PreviewExportOptions SetProjectDataOnlyExport(boolean enable);
|
||||
[Ref] PreviewExportOptions SetNativeMobileApp(boolean enable);
|
||||
[Ref] PreviewExportOptions SetFullLoadingScreen(boolean enable);
|
||||
[Ref] PreviewExportOptions SetIsDevelopmentEnvironment(boolean enable);
|
||||
[Ref] PreviewExportOptions SetNonRuntimeScriptsCacheBurst(unsigned long value);
|
||||
|
1
GDevelop.js/types.d.ts
vendored
1
GDevelop.js/types.d.ts
vendored
@@ -2732,6 +2732,7 @@ export class PreviewExportOptions extends EmscriptenObject {
|
||||
setExternalLayoutName(externalLayoutName: string): PreviewExportOptions;
|
||||
setIncludeFileHash(includeFile: string, hash: number): PreviewExportOptions;
|
||||
setProjectDataOnlyExport(enable: boolean): PreviewExportOptions;
|
||||
setNativeMobileApp(enable: boolean): PreviewExportOptions;
|
||||
setFullLoadingScreen(enable: boolean): PreviewExportOptions;
|
||||
setIsDevelopmentEnvironment(enable: boolean): PreviewExportOptions;
|
||||
setNonRuntimeScriptsCacheBurst(value: number): PreviewExportOptions;
|
||||
|
@@ -8,6 +8,7 @@ declare class gdPreviewExportOptions {
|
||||
setExternalLayoutName(externalLayoutName: string): gdPreviewExportOptions;
|
||||
setIncludeFileHash(includeFile: string, hash: number): gdPreviewExportOptions;
|
||||
setProjectDataOnlyExport(enable: boolean): gdPreviewExportOptions;
|
||||
setNativeMobileApp(enable: boolean): gdPreviewExportOptions;
|
||||
setFullLoadingScreen(enable: boolean): gdPreviewExportOptions;
|
||||
setIsDevelopmentEnvironment(enable: boolean): gdPreviewExportOptions;
|
||||
setNonRuntimeScriptsCacheBurst(value: number): gdPreviewExportOptions;
|
||||
|
@@ -22,7 +22,7 @@ import { duplicateLeaderboard } from '../Utils/GDevelopServices/Play';
|
||||
import { registerGame } from '../Utils/GDevelopServices/Game';
|
||||
import { toNewGdMapStringString } from '../Utils/MapStringString';
|
||||
|
||||
const gd = global.gd;
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
type ReplacePromptDialogProps = {|
|
||||
leaderboardsToReplace: ?Array<string>,
|
||||
@@ -181,7 +181,7 @@ export const LeaderboardReplacerProgressDialog = ({
|
||||
|
||||
type RetryOrAbandonCallback = () => void;
|
||||
|
||||
type UseLeaderboardReplacerOutput = {
|
||||
type UseLeaderboardReplacerOutput = {|
|
||||
/**
|
||||
* Launch search through the whole project for leaderboard ids to replace.
|
||||
*/
|
||||
@@ -191,7 +191,7 @@ type UseLeaderboardReplacerOutput = {
|
||||
* Render, if needed, the dialog that will show the progress of leaderboard replacement.
|
||||
*/
|
||||
renderLeaderboardReplacerDialog: () => React.Node,
|
||||
};
|
||||
|};
|
||||
|
||||
type ErroredLeaderboard = {
|
||||
leaderboardId: string,
|
||||
@@ -319,6 +319,7 @@ export const useLeaderboardReplacer = (): UseLeaderboardReplacerOutput => {
|
||||
|
||||
gd.ProjectBrowserHelper.exposeProjectEvents(
|
||||
project,
|
||||
// $FlowIgnore - eventsLeaderboardReplacer inherits from ArbitraryEventsWorker
|
||||
eventsLeaderboardReplacer
|
||||
);
|
||||
eventsLeaderboardReplacer.delete();
|
||||
@@ -373,6 +374,7 @@ export const useLeaderboardReplacer = (): UseLeaderboardReplacerOutput => {
|
||||
setGameId(sourceGameId);
|
||||
|
||||
const leaderboardsLister = new gd.EventsLeaderboardsLister(project);
|
||||
// $FlowIgnore - leaderboardsLister inherits from ArbitraryEventsWorker
|
||||
gd.ProjectBrowserHelper.exposeProjectEvents(project, leaderboardsLister);
|
||||
const leaderboardIds = leaderboardsLister.getLeaderboardIds();
|
||||
setLeaderboardsToReplace(leaderboardIds.toNewVectorString().toJSArray());
|
60
newIDE/app/src/MainFrame/UseMultiplayerLobbyConfigurator.js
Normal file
60
newIDE/app/src/MainFrame/UseMultiplayerLobbyConfigurator.js
Normal file
@@ -0,0 +1,60 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import { duplicateLobbyConfiguration } from '../Utils/GDevelopServices/Play';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
type UseMultiplayerLobbyConfiguratorOutput = {|
|
||||
configureMultiplayerLobbiesIfNeeded: (
|
||||
project: gdProject,
|
||||
sourceGameId: string
|
||||
) => Promise<void>,
|
||||
|};
|
||||
|
||||
/**
|
||||
* Hook allowing to duplicate lobby configuration from another project, useful after
|
||||
* opening a project from an example.
|
||||
*/
|
||||
export const useMultiplayerLobbyConfigurator = (): UseMultiplayerLobbyConfiguratorOutput => {
|
||||
const { profile, getAuthorizationHeader } = React.useContext(
|
||||
AuthenticatedUserContext
|
||||
);
|
||||
const configureMultiplayerLobbiesIfNeeded = React.useCallback(
|
||||
async (project: gdProject, sourceGameId: string) => {
|
||||
const isMultiplayerExtensionUsed = gd.UsedExtensionsFinder.scanProject(
|
||||
project
|
||||
)
|
||||
.getUsedExtensions()
|
||||
.toNewVectorString()
|
||||
.toJSArray()
|
||||
.some(extensionName => extensionName === 'Multiplayer');
|
||||
if (!isMultiplayerExtensionUsed) return;
|
||||
|
||||
if (!profile) {
|
||||
console.warn(
|
||||
'User is not connected. Aborting multiplayer lobby configuration.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await duplicateLobbyConfiguration({
|
||||
userId: profile.id,
|
||||
getAuthorizationHeader,
|
||||
gameId: project.getProjectUuid(),
|
||||
sourceGameId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`An error occurred while copying lobby configuration from game with id ${sourceGameId}. Failing silently: `,
|
||||
error
|
||||
);
|
||||
}
|
||||
},
|
||||
[getAuthorizationHeader, profile]
|
||||
);
|
||||
return {
|
||||
configureMultiplayerLobbiesIfNeeded,
|
||||
};
|
||||
};
|
@@ -142,7 +142,7 @@ import {
|
||||
sendInAppTutorialStarted,
|
||||
sendEventsExtractedAsFunction,
|
||||
} from '../Utils/Analytics/EventSender';
|
||||
import { useLeaderboardReplacer } from '../Leaderboard/useLeaderboardReplacer';
|
||||
import { useLeaderboardReplacer } from '../Leaderboard/UseLeaderboardReplacer';
|
||||
import useAlertDialog from '../UI/Alert/useAlertDialog';
|
||||
import NewProjectSetupDialog from '../ProjectCreation/NewProjectSetupDialog';
|
||||
import {
|
||||
@@ -178,6 +178,7 @@ import useVersionHistory from '../VersionHistory/UseVersionHistory';
|
||||
import { ProjectManagerDrawer } from '../ProjectManager/ProjectManagerDrawer';
|
||||
import DiagnosticReportDialog from '../ExportAndShare/DiagnosticReportDialog';
|
||||
import useSaveReminder from './UseSaveReminder';
|
||||
import { useMultiplayerLobbyConfigurator } from './UseMultiplayerLobbyConfigurator';
|
||||
|
||||
const GD_STARTUP_TIMES = global.GD_STARTUP_TIMES || [];
|
||||
|
||||
@@ -410,6 +411,9 @@ const MainFrame = (props: Props) => {
|
||||
findLeaderboardsToReplace,
|
||||
renderLeaderboardReplacerDialog,
|
||||
} = useLeaderboardReplacer();
|
||||
const {
|
||||
configureMultiplayerLobbiesIfNeeded,
|
||||
} = useMultiplayerLobbyConfigurator();
|
||||
const eventsFunctionsExtensionsState = React.useContext(
|
||||
EventsFunctionsExtensionsContext
|
||||
);
|
||||
@@ -1148,6 +1152,7 @@ const MainFrame = (props: Props) => {
|
||||
setNewProjectSetupDialogOpen(false);
|
||||
closeExampleStoreDialog({ deselectExampleAndGameTemplate: true });
|
||||
findLeaderboardsToReplace(project, oldProjectId);
|
||||
configureMultiplayerLobbiesIfNeeded(project, oldProjectId);
|
||||
openSceneOrProjectManager({
|
||||
currentProject: project,
|
||||
editorTabs: editorTabs,
|
||||
|
@@ -502,3 +502,26 @@ export const updateLobbyConfiguration = async (
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const duplicateLobbyConfiguration = async ({
|
||||
getAuthorizationHeader,
|
||||
userId,
|
||||
gameId,
|
||||
sourceGameId,
|
||||
}: {|
|
||||
getAuthorizationHeader: () => Promise<string>,
|
||||
userId: string,
|
||||
gameId: string,
|
||||
sourceGameId: string,
|
||||
|}): Promise<LobbyConfiguration> => {
|
||||
const authorizationHeader = await getAuthorizationHeader();
|
||||
const response = await axios.post(
|
||||
`${GDevelopPlayApi.baseUrl}/game/${gameId}/lobby-configuration/action/copy`,
|
||||
{ sourceGameId },
|
||||
{
|
||||
headers: { Authorization: authorizationHeader },
|
||||
params: { userId },
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
@@ -6,7 +6,7 @@ import paperDecorator from '../../PaperDecorator';
|
||||
import {
|
||||
LeaderboardReplacerProgressDialog,
|
||||
ReplacePromptDialog,
|
||||
} from '../../../Leaderboard/useLeaderboardReplacer';
|
||||
} from '../../../Leaderboard/UseLeaderboardReplacer';
|
||||
import AuthenticatedUserContext from '../../../Profile/AuthenticatedUserContext';
|
||||
import { fakeSilverAuthenticatedUser } from '../../../fixtures/GDevelopServicesTestData';
|
||||
|
||||
|
Reference in New Issue
Block a user