-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cc5c805
commit e52c669
Showing
22 changed files
with
646 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Backend | ||
NEXT_PUBLIC_GRAPHQL_URI="https://dev.api.marathon.perimetre.co/graphql" | ||
|
||
# Unity | ||
NEXT_PUBLIC_UNITY_PUBLIC_FOLDER="unity" | ||
NEXT_PUBLIC_UNITY_BUILD_NAME="build-0.11" | ||
NEXT_PUBLIC_UNITY_COMPANY_NAME="Marathon" | ||
NEXT_PUBLIC_UNITY_PRODUCT_NAME="Space Planner" | ||
NEXT_PUBLIC_UNITY_PRODUCT_VERSION="0.11" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
{ | ||
"locale": "en" | ||
"locale": "en", | ||
"title": "Space Planner", | ||
"description": "Marathon space planner", | ||
"build": { | ||
"title": "Build" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Head from 'next/head'; | ||
import React from 'react'; | ||
import { useIntl } from 'react-intl'; | ||
|
||
const DefaultPageTitle: React.FC = () => { | ||
const intl = useIntl(); | ||
return ( | ||
<Head> | ||
<title>{intl.formatMessage({ id: 'title' })}</title> | ||
<meta name="description" content={intl.formatMessage({ id: 'description' })} /> | ||
</Head> | ||
); | ||
}; | ||
|
||
export default DefaultPageTitle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Explicitly disable because we're dealing with unity objects and we don't have their type | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; | ||
import classnames from 'classnames'; | ||
|
||
import Script from 'next/script'; | ||
import env from '../../../env'; | ||
import { useUnityPlayerContext } from '../../Providers/UnityPlayerProvider'; | ||
|
||
export type UnityPlayerRef = { | ||
sendMessage: (gameObjectName: string, methodName: string, value: number | string) => void; | ||
}; | ||
|
||
export type UnityPlayerProps = { | ||
className?: string; | ||
}; | ||
|
||
const UnityPlayer = forwardRef<UnityPlayerRef, UnityPlayerProps>(function UnityPlayer({ className }, ref) { | ||
const { hasProvider, setErrorMessage, setLoadingProgress, state, setState, unityInstance } = useUnityPlayerContext(); | ||
|
||
if (!hasProvider) { | ||
throw 'Called UnityPlayer. But no UnityPlayerProvider was found. Wrap your UnityPlayer with the UnityPlayerProvider component'; | ||
} | ||
|
||
const { buildName, buildUrl, loaderUrl, companyName, productName, productVersion } = useMemo(() => { | ||
const { | ||
NEXT_PUBLIC_UNITY_BUILD_NAME, | ||
NEXT_PUBLIC_UNITY_COMPANY_NAME, | ||
NEXT_PUBLIC_UNITY_PRODUCT_NAME, | ||
NEXT_PUBLIC_UNITY_PRODUCT_VERSION, | ||
NEXT_PUBLIC_UNITY_PUBLIC_FOLDER | ||
} = env(); | ||
// Unity folder inside /public folder. | ||
const unityPublicServePath = NEXT_PUBLIC_UNITY_PUBLIC_FOLDER; | ||
const buildName = NEXT_PUBLIC_UNITY_BUILD_NAME; | ||
|
||
const buildUrl = `${unityPublicServePath}/Build`; | ||
const loaderUrl = `${buildUrl}/${buildName}.loader.js`; | ||
|
||
return { | ||
unityPublicServePath, | ||
buildName, | ||
buildUrl, | ||
loaderUrl, | ||
companyName: NEXT_PUBLIC_UNITY_COMPANY_NAME, | ||
productName: NEXT_PUBLIC_UNITY_PRODUCT_NAME, | ||
productVersion: NEXT_PUBLIC_UNITY_PRODUCT_VERSION | ||
}; | ||
}, []); | ||
|
||
/* | ||
* Initialization | ||
* */ | ||
const [isScriptLoaded, setIsScriptLoaded] = useState(false); | ||
const unityCanvas = useRef<HTMLCanvasElement>(null); | ||
|
||
//! This has not been converted from plain js to react yet | ||
// const showBanner = useCallback((msg, type) => { | ||
// function updateBannerVisibility() { | ||
// warningBanner.style.display = warningBanner.children.length ? 'block' : 'none'; | ||
// } | ||
// var div = document.createElement('div'); | ||
// div.innerHTML = msg; | ||
// warningBanner.appendChild(div); | ||
// if (type == 'error') div.style = 'background: red; padding: 10px;'; | ||
// else { | ||
// if (type == 'warning') div.style = 'background: yellow; padding: 10px;'; | ||
// setTimeout(function() { | ||
// warningBanner.removeChild(div); | ||
// updateBannerVisibility(); | ||
// }, 5000); | ||
// } | ||
// updateBannerVisibility(); | ||
// }, []); | ||
|
||
useEffect(() => { | ||
const setup = async () => { | ||
if (isScriptLoaded && unityCanvas.current && state === 'initializing') { | ||
// Initial unity config | ||
const config: any = { | ||
dataUrl: `${buildUrl}/${buildName}.data`, | ||
frameworkUrl: `${buildUrl}/${buildName}.framework.js`, | ||
codeUrl: `${buildUrl}/${buildName}.wasm`, | ||
streamingAssetsUrl: 'StreamingAssets', | ||
companyName, | ||
productName, | ||
productVersion | ||
// showBanner: unityShowBanner, | ||
// By default Unity keeps WebGL canvas render target size matched with | ||
// the DOM size of the canvas element (scaled by window.devicePixelRatio) | ||
// Set this to false if you want to decouple this synchronization from | ||
// happening inside the engine, and you would instead like to size up | ||
// the canvas DOM size and WebGL render target sizes yourself. | ||
//matchWebGLToCanvasSize: false | ||
}; | ||
|
||
// Test if mobile | ||
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) { | ||
config.devicePixelRatio = 1; | ||
} | ||
|
||
unityCanvas.current.style.width = '100%'; | ||
unityCanvas.current.style.height = '100%'; | ||
|
||
// Let's setup unity | ||
try { | ||
// Copy the method created by the script | ||
const createUnityInstance = (window as any).createUnityInstance; | ||
|
||
setState('loading'); | ||
|
||
// Setup | ||
const localUnityInstance = await createUnityInstance(unityCanvas.current, config, (progress: number) => { | ||
setLoadingProgress(progress); | ||
}); | ||
|
||
// Store unity instance for later use | ||
unityInstance.current = localUnityInstance; | ||
|
||
setState('complete'); | ||
} catch (error: any) { | ||
setState('error'); | ||
setErrorMessage(error as string); | ||
} | ||
} | ||
}; | ||
|
||
setup(); | ||
// We really only want this to run once | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [isScriptLoaded]); | ||
|
||
/* | ||
* External ref | ||
* */ | ||
useImperativeHandle( | ||
ref, | ||
() => ({ | ||
sendMessage: (gameObjectName, methodName, value) => | ||
unityInstance.current?.SendMessage(gameObjectName, methodName, value) | ||
}), | ||
[unityInstance] | ||
); | ||
|
||
return ( | ||
<div className={classnames('w-full h-full', className)}> | ||
<canvas ref={unityCanvas} width={960} height={600} /> | ||
<Script src={loaderUrl} strategy="afterInteractive" onLoad={() => setIsScriptLoaded(true)} /> | ||
</div> | ||
); | ||
}); | ||
|
||
export default UnityPlayer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import Head from 'next/head'; | ||
import React, { useState } from 'react'; | ||
import { FormattedMessage, useIntl } from 'react-intl'; | ||
import BuilderSidebar from '../../UI/BuilderSidebar'; | ||
import UnityPlayer from '../../Elements/UnityPlayer'; | ||
import Image from 'next/image'; | ||
import classnames from 'classnames'; | ||
import ProgressBar from '../../UI/ProgressBar'; | ||
import Spinner from '../../UI/Spinner'; | ||
import { UnityPlayerProvider, useUnityPlayerContext } from '../../Providers/UnityPlayerProvider'; | ||
|
||
const LoadingState: React.FC = () => { | ||
const [imageLoaded, setImageLoaded] = useState(false); | ||
const { loadingProgress } = useUnityPlayerContext(); | ||
|
||
return ( | ||
<div | ||
className={classnames('w-full h-full flex flex-col justify-center items-center', { | ||
'opacity-0 animate-fade-in': loadingProgress < 1, // Animate in when progress starts | ||
'animate-fade-out': loadingProgress >= 1 // Fade out when loading is finished | ||
})} | ||
> | ||
<div | ||
className={classnames('h-28 w-28 relative translate-y-2 opacity-0', { | ||
'animate-fade-into': imageLoaded // Animate up when image gets loaded | ||
})} | ||
> | ||
<Image | ||
layout="fill" | ||
src="/images/logo.webp" | ||
alt={'marathon'} | ||
sizes="50vw" | ||
objectFit="cover" | ||
onLoadingComplete={() => setImageLoaded(true)} | ||
/> | ||
</div> | ||
<div className="flex items-center justify-center gap-4 my-6"> | ||
<p className="text-2xl font-semibold uppercase text-mui-dark"> | ||
<FormattedMessage id="title" /> | ||
</p> | ||
<Spinner className="h-6 w-6" /> | ||
</div> | ||
<ProgressBar color="mui-color-mui-dark" className="max-w-xs" progress={loadingProgress * 100} /> | ||
</div> | ||
); | ||
}; | ||
|
||
type DrawerBuilderProps = {}; | ||
|
||
const DrawerBuilder: React.FC<DrawerBuilderProps> = () => { | ||
const { loadingProgress, state } = useUnityPlayerContext(); | ||
|
||
return ( | ||
<div className="flex min-h-screen"> | ||
{/* Left sidebar, fixed width */} | ||
<BuilderSidebar /> | ||
{/* Right section, takes remaining space(flex-grow) */} | ||
<div className="flex-grow relative"> | ||
<UnityPlayer className={classnames('opacity-0', { 'animate-fade-in': loadingProgress >= 1 })} /> | ||
{/* Content on top of unity player */} | ||
<div className="absolute inset-0 pointer-events-none">{state === 'loading' && <LoadingState />}</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
type BuildTemplateProps = {}; | ||
|
||
const BuildTemplate: React.FC<BuildTemplateProps> = () => { | ||
const intl = useIntl(); | ||
|
||
return ( | ||
<> | ||
<Head> | ||
{/*TODO: display project name*/} | ||
<title> | ||
{intl.formatMessage({ id: 'build.title' })} | {intl.formatMessage({ id: 'title' })} | ||
</title> | ||
{/*TODO: display project description*/} | ||
{/*<meta name="description" content="Generated by create next app" />*/} | ||
</Head> | ||
<div id="build-template"> | ||
<UnityPlayerProvider> | ||
<DrawerBuilder /> | ||
</UnityPlayerProvider> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default BuildTemplate; |
Oops, something went wrong.