mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Improve Ask AI tab
Don't show in changelog
This commit is contained in:
@@ -25,6 +25,9 @@ import Like from '../../../UI/CustomSvgIcons/Like';
|
|||||||
import Dislike from '../../../UI/CustomSvgIcons/Dislike';
|
import Dislike from '../../../UI/CustomSvgIcons/Dislike';
|
||||||
import GDevelopThemeContext from '../../../UI/Theme/GDevelopThemeContext';
|
import GDevelopThemeContext from '../../../UI/Theme/GDevelopThemeContext';
|
||||||
import { type MessageDescriptor } from '../../../Utils/i18n/MessageDescriptor.flow';
|
import { type MessageDescriptor } from '../../../Utils/i18n/MessageDescriptor.flow';
|
||||||
|
import Link from '../../../UI/Link';
|
||||||
|
import { getHelpLink } from '../../../Utils/HelpLink';
|
||||||
|
import Window from '../../../Utils/Window';
|
||||||
|
|
||||||
const TOO_MANY_MESSAGES_WARNING_COUNT = 9;
|
const TOO_MANY_MESSAGES_WARNING_COUNT = 9;
|
||||||
const TOO_MANY_MESSAGES_ERROR_COUNT = 14;
|
const TOO_MANY_MESSAGES_ERROR_COUNT = 14;
|
||||||
@@ -200,66 +203,80 @@ export const AiRequestChat = React.forwardRef<Props, AiRequestChatInterface>(
|
|||||||
An error happened when sending your request, please try again.
|
An error happened when sending your request, please try again.
|
||||||
</Trans>
|
</Trans>
|
||||||
) : (
|
) : (
|
||||||
quotaOrCreditsExplanation
|
quotaOrCreditsExplanation || '\u00a0'
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!aiRequest) {
|
if (!aiRequest) {
|
||||||
const disclaimer = errorOrQuotaOrCreditsExplanation || (
|
|
||||||
<Text size="body2" color="secondary">
|
|
||||||
<Trans>
|
|
||||||
The AI will answer according to your game project. Always verify AI
|
|
||||||
answers before applying them.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.newChatContainer}>
|
<div className={classes.newChatContainer}>
|
||||||
<Line noMargin justifyContent="center">
|
<ColumnStackLayout justifyContent="center" expand>
|
||||||
<RobotIcon rotating size={40} />
|
<Line noMargin justifyContent="center">
|
||||||
</Line>
|
<RobotIcon rotating size={40} />
|
||||||
<Column noMargin alignItems="center">
|
</Line>
|
||||||
<Text size="bold-title">
|
<Column noMargin alignItems="center">
|
||||||
<Trans>What do you want to make?</Trans>
|
<Text size="bold-title">
|
||||||
|
<Trans>What do you want to make?</Trans>
|
||||||
|
</Text>
|
||||||
|
</Column>
|
||||||
|
<Column noMargin alignItems="stretch" justifyContent="stretch">
|
||||||
|
<CompactTextAreaField
|
||||||
|
maxLength={6000}
|
||||||
|
value={userRequestText}
|
||||||
|
disabled={isLaunchingAiRequest}
|
||||||
|
onChange={userRequestText =>
|
||||||
|
setUserRequestText(userRequestText)
|
||||||
|
}
|
||||||
|
placeholder={newChatPlaceholder}
|
||||||
|
rows={5}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
<Line noMargin>
|
||||||
|
<ResponsiveLineStackLayout
|
||||||
|
noMargin
|
||||||
|
alignItems="flex-start"
|
||||||
|
justifyContent="space-between"
|
||||||
|
expand
|
||||||
|
>
|
||||||
|
{!isMobile && errorOrQuotaOrCreditsExplanation}
|
||||||
|
<Line noMargin justifyContent="flex-end">
|
||||||
|
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
|
||||||
|
<RaisedButton
|
||||||
|
color="primary"
|
||||||
|
label={<Trans>Send</Trans>}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
|
disabled={isLaunchingAiRequest}
|
||||||
|
onClick={() => {
|
||||||
|
onSendUserRequest(userRequestText);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</LeftLoader>
|
||||||
|
</Line>
|
||||||
|
{isMobile && errorOrQuotaOrCreditsExplanation}
|
||||||
|
</ResponsiveLineStackLayout>
|
||||||
|
</Line>
|
||||||
|
{subscriptionBanner}
|
||||||
|
</ColumnStackLayout>
|
||||||
|
<Column justifyContent="center" noMargin>
|
||||||
|
<Text size="body-small" color="secondary" align="center" noMargin>
|
||||||
|
<Trans>
|
||||||
|
The AI is experimental and still being improved.{' '}
|
||||||
|
<Link
|
||||||
|
href={getHelpLink('/interface/ask-ai')}
|
||||||
|
color="secondary"
|
||||||
|
onClick={() =>
|
||||||
|
Window.openExternalURL(getHelpLink('/interface/ask-ai'))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
It has access to your game objects but not events.
|
||||||
|
</Link>
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text size="body-small" color="secondary" align="center" noMargin>
|
||||||
|
<Trans>Answers may have mistakes: always verify them.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
<Column noMargin alignItems="stretch" justifyContent="stretch">
|
|
||||||
<CompactTextAreaField
|
|
||||||
maxLength={6000}
|
|
||||||
value={userRequestText}
|
|
||||||
disabled={isLaunchingAiRequest}
|
|
||||||
onChange={userRequestText => setUserRequestText(userRequestText)}
|
|
||||||
placeholder={newChatPlaceholder}
|
|
||||||
rows={5}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
<Line noMargin>
|
|
||||||
<ResponsiveLineStackLayout
|
|
||||||
noMargin
|
|
||||||
alignItems="flex-start"
|
|
||||||
justifyContent="space-between"
|
|
||||||
expand
|
|
||||||
>
|
|
||||||
{!isMobile && disclaimer}
|
|
||||||
<Line noMargin justifyContent="flex-end">
|
|
||||||
<LeftLoader reserveSpace isLoading={isLaunchingAiRequest}>
|
|
||||||
<RaisedButton
|
|
||||||
color="primary"
|
|
||||||
label={<Trans>Send</Trans>}
|
|
||||||
style={{ flexShrink: 0 }}
|
|
||||||
disabled={isLaunchingAiRequest}
|
|
||||||
onClick={() => {
|
|
||||||
onSendUserRequest(userRequestText);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</LeftLoader>
|
|
||||||
</Line>
|
|
||||||
{isMobile && disclaimer}
|
|
||||||
</ResponsiveLineStackLayout>
|
|
||||||
</Line>
|
|
||||||
{subscriptionBanner}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -381,8 +398,8 @@ export const AiRequestChat = React.forwardRef<Props, AiRequestChatInterface>(
|
|||||||
<Line justifyContent="flex-start">
|
<Line justifyContent="flex-start">
|
||||||
<AlertMessage kind="error">
|
<AlertMessage kind="error">
|
||||||
<Trans>
|
<Trans>
|
||||||
The AI encountered an error while handling your request. Try
|
The AI encountered an error while handling your request - this
|
||||||
again later.
|
was request was not counted in your AI usage. Try again later.
|
||||||
</Trans>
|
</Trans>
|
||||||
</AlertMessage>
|
</AlertMessage>
|
||||||
</Line>
|
</Line>
|
||||||
|
@@ -51,11 +51,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
align-items: stretch;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 8px;
|
|
||||||
margin-left: 8px;
|
|
||||||
margin-right: 8px;
|
|
||||||
|
|
||||||
animation: new-chat-appear 0.5s;
|
animation: new-chat-appear 0.5s;
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,10 @@ a.conceptLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.noValidLink {
|
a.noValidLink {
|
||||||
|
color: inherit;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
text-decoration: none;
|
text-decoration: underline;
|
||||||
|
text-decoration-style: dotted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conceptLink span {
|
.conceptLink span {
|
||||||
|
@@ -151,10 +151,10 @@ export const ConceptLink = ({
|
|||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={[
|
title={[
|
||||||
<Text>
|
<Text color="inherit">
|
||||||
<b>{getConceptKindLabel(conceptMetadata.kind)}</b>
|
<b>{getConceptKindLabel(conceptMetadata.kind)}</b>
|
||||||
</Text>,
|
</Text>,
|
||||||
conceptParent ? <Text>{conceptParent}</Text> : null,
|
conceptParent ? <Text color="inherit">{conceptParent}</Text> : null,
|
||||||
<MarkdownText source={conceptMetadata.description} />,
|
<MarkdownText source={conceptMetadata.description} />,
|
||||||
]}
|
]}
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
|
@@ -23,6 +23,7 @@ export const Toolbar = ({
|
|||||||
<ToolbarGroup firstChild>
|
<ToolbarGroup firstChild>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
|
color="default"
|
||||||
tooltip={t`View history`}
|
tooltip={t`View history`}
|
||||||
onClick={onOpenHistory}
|
onClick={onOpenHistory}
|
||||||
>
|
>
|
||||||
|
@@ -257,10 +257,10 @@ export const buildMainMenuDeclarativeTemplate = ({
|
|||||||
label: i18n._(t`Help`),
|
label: i18n._(t`Help`),
|
||||||
role: 'help',
|
role: 'help',
|
||||||
submenu: [
|
submenu: [
|
||||||
// {
|
{
|
||||||
// label: i18n._(t`Ask AI (GDevelop chatbot)`),
|
label: i18n._(t`Ask AI (GDevelop chatbot)`),
|
||||||
// onClickSendEvent: 'main-menu-open-ask-ai',
|
onClickSendEvent: 'main-menu-open-ask-ai',
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
label: i18n._(t`GDevelop website`),
|
label: i18n._(t`GDevelop website`),
|
||||||
onClickOpenLink: 'http://gdevelop.io',
|
onClickOpenLink: 'http://gdevelop.io',
|
||||||
|
@@ -13,6 +13,11 @@ import { type EditorTab } from './EditorTabs/EditorTabsHandler';
|
|||||||
import { getTabId } from './EditorTabs/DraggableEditorTabs';
|
import { getTabId } from './EditorTabs/DraggableEditorTabs';
|
||||||
import { useScreenType } from '../UI/Responsive/ScreenTypeMeasurer';
|
import { useScreenType } from '../UI/Responsive/ScreenTypeMeasurer';
|
||||||
import TabsTitlebarTooltip from './TabsTitlebarTooltip';
|
import TabsTitlebarTooltip from './TabsTitlebarTooltip';
|
||||||
|
import RobotIcon from '../ProjectCreation/RobotIcon';
|
||||||
|
import PreferencesContext from './Preferences/PreferencesContext';
|
||||||
|
import TextButton from '../UI/TextButton';
|
||||||
|
import { useInterval } from '../Utils/UseInterval';
|
||||||
|
import { useIsMounted } from '../Utils/UseIsMounted';
|
||||||
|
|
||||||
const WINDOW_DRAGGABLE_PART_CLASS_NAME = 'title-bar-draggable-part';
|
const WINDOW_DRAGGABLE_PART_CLASS_NAME = 'title-bar-draggable-part';
|
||||||
const WINDOW_NON_DRAGGABLE_PART_CLASS_NAME = 'title-bar-non-draggable-part';
|
const WINDOW_NON_DRAGGABLE_PART_CLASS_NAME = 'title-bar-non-draggable-part';
|
||||||
@@ -34,7 +39,7 @@ const styles = {
|
|||||||
},
|
},
|
||||||
askAiContainer: {
|
askAiContainer: {
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
marginRight: 0,
|
marginRight: 1,
|
||||||
marginLeft: 2,
|
marginLeft: 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -50,6 +55,46 @@ type TabsTitlebarProps = {|
|
|||||||
onOpenAskAi: () => void,
|
onOpenAskAi: () => void,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
const useIsAskAiIconAnimated = (shouldDisplayAskAi: boolean) => {
|
||||||
|
const isMounted = useIsMounted();
|
||||||
|
|
||||||
|
const [isAskAiIconAnimated, setIsAskAiIconAnimated] = React.useState(true);
|
||||||
|
const animate = React.useCallback(
|
||||||
|
(animationDuration: number) => {
|
||||||
|
if (isMounted.current) {
|
||||||
|
setIsAskAiIconAnimated(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!isMounted.current) return;
|
||||||
|
|
||||||
|
setIsAskAiIconAnimated(false);
|
||||||
|
}, animationDuration);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isMounted]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(
|
||||||
|
() => {
|
||||||
|
// Animate the icon for a long time at the beginning.
|
||||||
|
animate(9000);
|
||||||
|
},
|
||||||
|
[animate]
|
||||||
|
);
|
||||||
|
|
||||||
|
useInterval(
|
||||||
|
() => {
|
||||||
|
setIsAskAiIconAnimated(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsAskAiIconAnimated(false);
|
||||||
|
}, 8000);
|
||||||
|
},
|
||||||
|
// Animate the icon every 20 minutes.
|
||||||
|
shouldDisplayAskAi ? 20 * 60 * 1000 : null
|
||||||
|
);
|
||||||
|
|
||||||
|
return isAskAiIconAnimated;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The titlebar containing a menu, the tabs and giving space for window controls.
|
* The titlebar containing a menu, the tabs and giving space for window controls.
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +108,7 @@ export default function TabsTitlebar({
|
|||||||
const isTouchscreen = useScreenType() === 'touch';
|
const isTouchscreen = useScreenType() === 'touch';
|
||||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||||
const backgroundColor = gdevelopTheme.titlebar.backgroundColor;
|
const backgroundColor = gdevelopTheme.titlebar.backgroundColor;
|
||||||
|
const preferences = React.useContext(PreferencesContext);
|
||||||
const [tooltipData, setTooltipData] = React.useState<?{|
|
const [tooltipData, setTooltipData] = React.useState<?{|
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
editorTab: EditorTab,
|
editorTab: EditorTab,
|
||||||
@@ -135,6 +181,10 @@ export default function TabsTitlebar({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const shouldDisplayAskAi =
|
||||||
|
preferences.values.showAiAskButtonInTitleBar && !hasAskAiOpened;
|
||||||
|
const isAskAiIconAnimated = useIsAskAiIconAnimated(shouldDisplayAskAi);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -160,17 +210,18 @@ export default function TabsTitlebar({
|
|||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{renderTabs(onEditorTabHovered, onEditorTabClosing)}
|
{renderTabs(onEditorTabHovered, onEditorTabClosing)}
|
||||||
{/* {!preferences.values.showAiAskButtonInTitleBar ||
|
{shouldDisplayAskAi ? (
|
||||||
hasAskAiOpened ? null : (
|
<div
|
||||||
<div style={styles.askAiContainer}>
|
style={styles.askAiContainer}
|
||||||
<RaisedButton
|
className={WINDOW_NON_DRAGGABLE_PART_CLASS_NAME}
|
||||||
icon={<RobotIcon size={16} />}
|
>
|
||||||
color="primary"
|
<TextButton
|
||||||
|
icon={<RobotIcon size={16} rotating={isAskAiIconAnimated} />}
|
||||||
label={'Ask AI'}
|
label={'Ask AI'}
|
||||||
onClick={onOpenAskAi}
|
onClick={onOpenAskAi}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)} */}
|
) : null}
|
||||||
<TitleBarRightSafeMargins />
|
<TitleBarRightSafeMargins />
|
||||||
{tooltipData && (
|
{tooltipData && (
|
||||||
<TabsTitlebarTooltip
|
<TabsTitlebarTooltip
|
||||||
|
@@ -3167,6 +3167,7 @@ const MainFrame = (props: Props) => {
|
|||||||
useOpenInitialDialog({
|
useOpenInitialDialog({
|
||||||
openInAppTutorialDialog: selectInAppTutorial,
|
openInAppTutorialDialog: selectInAppTutorial,
|
||||||
openProfileDialog: onOpenProfileDialog,
|
openProfileDialog: onOpenProfileDialog,
|
||||||
|
openAskAi,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onChangeProjectName = async (newName: string): Promise<void> => {
|
const onChangeProjectName = async (newName: string): Promise<void> => {
|
||||||
|
@@ -27,7 +27,8 @@ const useClasses = (rotating, size) =>
|
|||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
borderRadius: '100%',
|
borderRadius: '100%',
|
||||||
zIndex: 0,
|
zIndex: 0,
|
||||||
animation: rotating ? 'spin-background 3s linear infinite' : 'none',
|
animation: 'spin-background 3s linear infinite',
|
||||||
|
animationPlayState: rotating ? 'running' : 'paused',
|
||||||
},
|
},
|
||||||
'&::after': {
|
'&::after': {
|
||||||
content: "''",
|
content: "''",
|
||||||
|
@@ -10,26 +10,37 @@ type Props = {|
|
|||||||
href: string,
|
href: string,
|
||||||
onClick: () => void | Promise<void>,
|
onClick: () => void | Promise<void>,
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
|
color?: 'primary' | 'secondary',
|
||||||
|};
|
|};
|
||||||
|
|
||||||
const useLinkStyles = (theme: GDevelopTheme, disabled: boolean) =>
|
const useLinkStyles = (
|
||||||
|
theme: GDevelopTheme,
|
||||||
|
color: 'primary' | 'secondary',
|
||||||
|
disabled: boolean
|
||||||
|
) =>
|
||||||
makeStyles({
|
makeStyles({
|
||||||
root: {
|
root: {
|
||||||
color: theme.link.color.default,
|
color: color === 'primary' ? theme.link.color.default : undefined,
|
||||||
textDecoration: 'underline',
|
textDecoration: 'underline',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
color: !disabled ? theme.link.color.hover : undefined,
|
color:
|
||||||
|
color === 'primary' && !disabled ? theme.link.color.hover : undefined,
|
||||||
cursor: !disabled ? 'pointer' : 'default',
|
cursor: !disabled ? 'pointer' : 'default',
|
||||||
},
|
},
|
||||||
'&:focus': {
|
'&:focus': {
|
||||||
color: !disabled ? theme.link.color.hover : undefined,
|
color:
|
||||||
|
color === 'primary' && !disabled ? theme.link.color.hover : undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const Link = (props: Props) => {
|
const Link = (props: Props) => {
|
||||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||||
const linkStyles = useLinkStyles(gdevelopTheme, !!props.disabled);
|
const linkStyles = useLinkStyles(
|
||||||
|
gdevelopTheme,
|
||||||
|
props.color || 'primary',
|
||||||
|
!!props.disabled
|
||||||
|
);
|
||||||
const onClick = (event: MouseEvent) => {
|
const onClick = (event: MouseEvent) => {
|
||||||
event.preventDefault(); // Avoid triggering the href (avoids a warning on mobile in case of unsaved changes).
|
event.preventDefault(); // Avoid triggering the href (avoids a warning on mobile in case of unsaved changes).
|
||||||
if (!props.disabled) {
|
if (!props.disabled) {
|
||||||
|
@@ -1,25 +1,38 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { mapFor } from './MapFor';
|
import { mapFor } from './MapFor';
|
||||||
|
import { isCollectionVariable } from './VariablesUtils';
|
||||||
|
|
||||||
|
const gd: libGDevelop = global.gd;
|
||||||
|
|
||||||
type SimplifiedBehaviorJson = {|
|
type SimplifiedBehaviorJson = {|
|
||||||
behaviorName: string,
|
behaviorName: string,
|
||||||
behaviorType: string,
|
behaviorType: string,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
type SimplifiedVariableJson = {|
|
||||||
|
variableName: string,
|
||||||
|
type: string,
|
||||||
|
value?: string,
|
||||||
|
children: ?Array<SimplifiedVariableJson>,
|
||||||
|
|};
|
||||||
|
|
||||||
type SimplifiedObjectJson = {|
|
type SimplifiedObjectJson = {|
|
||||||
objectName: string,
|
objectName: string,
|
||||||
objectType: string,
|
objectType: string,
|
||||||
behaviors: Array<SimplifiedBehaviorJson>,
|
behaviors: Array<SimplifiedBehaviorJson>,
|
||||||
|
objectVariables: Array<SimplifiedVariableJson>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type SimplifiedSceneJson = {|
|
type SimplifiedSceneJson = {|
|
||||||
sceneName: string,
|
sceneName: string,
|
||||||
objects: Array<SimplifiedObjectJson>,
|
objects: Array<SimplifiedObjectJson>,
|
||||||
|
sceneVariables: Array<SimplifiedVariableJson>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type SimplifiedProjectJson = {|
|
type SimplifiedProjectJson = {|
|
||||||
globalObjects: Array<SimplifiedObjectJson>,
|
globalObjects: Array<SimplifiedObjectJson>,
|
||||||
scenes: Array<SimplifiedSceneJson>,
|
scenes: Array<SimplifiedSceneJson>,
|
||||||
|
globalVariables: Array<SimplifiedVariableJson>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
const getSimplifiedBehaviorJson = (behavior: gdBehavior) => {
|
const getSimplifiedBehaviorJson = (behavior: gdBehavior) => {
|
||||||
@@ -29,7 +42,83 @@ const getSimplifiedBehaviorJson = (behavior: gdBehavior) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSimplifiedObjectJson = (object: gdObject) => {
|
const getVariableType = (variable: gdVariable) => {
|
||||||
|
const type = variable.getType();
|
||||||
|
return type === gd.Variable.String
|
||||||
|
? 'String'
|
||||||
|
: type === gd.Variable.Number
|
||||||
|
? 'Number'
|
||||||
|
: type === gd.Variable.Boolean
|
||||||
|
? 'Boolean'
|
||||||
|
: type === gd.Variable.Structure
|
||||||
|
? 'Structure'
|
||||||
|
: type === gd.Variable.Array
|
||||||
|
? 'Array'
|
||||||
|
: 'unknown';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getVariableValueAsString = (variable: gdVariable) => {
|
||||||
|
const type = variable.getType();
|
||||||
|
return type === gd.Variable.Structure || type === gd.Variable.Array
|
||||||
|
? variable.getChildrenCount() === 0
|
||||||
|
? `No children`
|
||||||
|
: variable.getChildrenCount() === 1
|
||||||
|
? `1 child`
|
||||||
|
: `${variable.getChildrenCount()} children`
|
||||||
|
: type === gd.Variable.String
|
||||||
|
? variable.getString()
|
||||||
|
: type === gd.Variable.Number
|
||||||
|
? variable.getValue().toString()
|
||||||
|
: type === gd.Variable.Boolean
|
||||||
|
? variable.getBool()
|
||||||
|
? `True`
|
||||||
|
: `False`
|
||||||
|
: 'unknown';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSimplifiedVariableJson = (
|
||||||
|
name: string,
|
||||||
|
variable: gdVariable,
|
||||||
|
depth = 0
|
||||||
|
): SimplifiedVariableJson => {
|
||||||
|
const isCollection = isCollectionVariable(variable);
|
||||||
|
|
||||||
|
// Don't diplay children of arrays, and only display the first level of children of structures.
|
||||||
|
const shouldDisplayChildren =
|
||||||
|
variable.getType() === gd.Variable.Structure && depth === 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
variableName: name,
|
||||||
|
type: getVariableType(variable),
|
||||||
|
value: !isCollection ? getVariableValueAsString(variable) : undefined,
|
||||||
|
children: shouldDisplayChildren
|
||||||
|
? variable
|
||||||
|
.getAllChildrenNames()
|
||||||
|
.toJSArray()
|
||||||
|
.map(childName => {
|
||||||
|
const childVariable = variable.getChild(childName);
|
||||||
|
return getSimplifiedVariableJson(
|
||||||
|
childName,
|
||||||
|
childVariable,
|
||||||
|
depth + 1
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSimplifiedVariablesContainerJson = (
|
||||||
|
container: gdVariablesContainer
|
||||||
|
): Array<SimplifiedVariableJson> => {
|
||||||
|
return mapFor(0, Math.min(container.count(), 20), (index: number) => {
|
||||||
|
const name = container.getNameAt(index);
|
||||||
|
const variable = container.getAt(index);
|
||||||
|
return getSimplifiedVariableJson(name, variable);
|
||||||
|
}).filter(Boolean);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSimplifiedObjectJson = (object: gdObject): SimplifiedObjectJson => {
|
||||||
return {
|
return {
|
||||||
objectName: object.getName(),
|
objectName: object.getName(),
|
||||||
objectType: object.getType(),
|
objectType: object.getType(),
|
||||||
@@ -42,6 +131,7 @@ const getSimplifiedObjectJson = (object: gdObject) => {
|
|||||||
return getSimplifiedBehaviorJson(behavior);
|
return getSimplifiedBehaviorJson(behavior);
|
||||||
})
|
})
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
|
objectVariables: getSimplifiedVariablesContainerJson(object.getVariables()),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,6 +148,7 @@ const getSimplifiedSceneJson = (scene: gdLayout) => {
|
|||||||
return {
|
return {
|
||||||
sceneName: scene.getName(),
|
sceneName: scene.getName(),
|
||||||
objects: getSimplifiedObjectsJson(scene.getObjects()),
|
objects: getSimplifiedObjectsJson(scene.getObjects()),
|
||||||
|
sceneVariables: getSimplifiedVariablesContainerJson(scene.getVariables()),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,5 +164,8 @@ export const getSimplifiedProjectJson = (
|
|||||||
return {
|
return {
|
||||||
globalObjects,
|
globalObjects,
|
||||||
scenes,
|
scenes,
|
||||||
|
globalVariables: getSimplifiedVariablesContainerJson(
|
||||||
|
project.getVariables()
|
||||||
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -8,6 +8,7 @@ import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
|||||||
type Props = {|
|
type Props = {|
|
||||||
openInAppTutorialDialog: (tutorialId: string) => void,
|
openInAppTutorialDialog: (tutorialId: string) => void,
|
||||||
openProfileDialog: () => void,
|
openProfileDialog: () => void,
|
||||||
|
openAskAi: () => void,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,6 +18,7 @@ type Props = {|
|
|||||||
const useOpenInitialDialog = ({
|
const useOpenInitialDialog = ({
|
||||||
openInAppTutorialDialog,
|
openInAppTutorialDialog,
|
||||||
openProfileDialog,
|
openProfileDialog,
|
||||||
|
openAskAi,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { routeArguments, removeRouteArguments } = React.useContext(
|
const { routeArguments, removeRouteArguments } = React.useContext(
|
||||||
RouterContext
|
RouterContext
|
||||||
@@ -72,6 +74,9 @@ const useOpenInitialDialog = ({
|
|||||||
// Do nothing as it should open the games dashboard on the homepage
|
// Do nothing as it should open the games dashboard on the homepage
|
||||||
// in the manage tab. So the homepage handles the route arguments itself.
|
// in the manage tab. So the homepage handles the route arguments itself.
|
||||||
break;
|
break;
|
||||||
|
case 'ask-ai':
|
||||||
|
openAskAi();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -85,6 +90,7 @@ const useOpenInitialDialog = ({
|
|||||||
authenticated,
|
authenticated,
|
||||||
onOpenCreateAccountDialog,
|
onOpenCreateAccountDialog,
|
||||||
onOpenLoginDialog,
|
onOpenLoginDialog,
|
||||||
|
openAskAi,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user