11import React , { useCallback , useEffect , useMemo } from 'react'
22import cx from 'classnames'
3- import { IoGridOutline as SquaresGridIcon , IoAlertCircleOutline as AlertIcon } from 'react-icons/io5'
3+ import { IoGridOutline as SquaresGridIcon } from 'react-icons/io5'
4+ import { FiAlertTriangle as WarningIcon } from 'react-icons/fi'
5+
46import { Material } from '@babylonjs/core'
57import { CrdtMessageType } from '@dcl/ecs'
68
79import { withSdk , WithSdkProps } from '../../../hoc/withSdk'
810import { useChange } from '../../../hooks/sdk/useChange'
911import { useOutsideClick } from '../../../hooks/useOutsideClick'
1012import { useAppDispatch , useAppSelector } from '../../../redux/hooks'
11- import { getMetrics , getLimits , setEntitiesOutOfBoundaries , setMetrics , setLimits } from '../../../redux/scene-metrics'
13+ import {
14+ getMetrics ,
15+ getLimits ,
16+ getEntitiesOutOfBoundaries ,
17+ setEntitiesOutOfBoundaries ,
18+ setMetrics ,
19+ setLimits
20+ } from '../../../redux/scene-metrics'
1221import { SceneMetrics } from '../../../redux/scene-metrics/types'
1322import type { Layout } from '../../../lib/utils/layout'
1423import { GROUND_MESH_PREFIX , PARCEL_SIZE } from '../../../lib/utils/scene'
24+ import { getLayoutManager } from '../../../lib/babylon/decentraland/layout-manager'
1525import { Button } from '../../Button'
1626import { getSceneLimits } from './utils'
1727
@@ -55,6 +65,7 @@ const Metrics = withSdk<WithSdkProps>(({ sdk }) => {
5565 const dispatch = useAppDispatch ( )
5666 const metrics = useAppSelector ( getMetrics )
5767 const limits = useAppSelector ( getLimits )
68+ const entitiesOutOfBoundaries = useAppSelector ( getEntitiesOutOfBoundaries )
5869 const [ showMetrics , setShowMetrics ] = React . useState ( false )
5970 const [ sceneLayout , setSceneLayout ] = React . useState < Layout > ( {
6071 base : { x : 0 , y : 0 } ,
@@ -107,12 +118,21 @@ const Metrics = withSdk<WithSdkProps>(({ sdk }) => {
107118
108119 const handleSceneChange = useCallback ( ( ) => {
109120 const nodes = getNodes ( )
110- const entitiesOutOfBoundaries = nodes . reduce ( ( count , node ) => {
121+ const { isEntityOutsideLayout } = getLayoutManager ( sdk . scene )
122+
123+ const entitiesOutOfBoundariesArray : number [ ] = [ ]
124+
125+ nodes . forEach ( ( node ) => {
111126 const entity = sdk . sceneContext . getEntityOrNull ( node . entity )
112- return entity && entity . isOutOfBoundaries ( ) ? count + 1 : count
113- } , 0 )
127+ if ( entity && entity . boundingInfoMesh ) {
128+ const isOutside = isEntityOutsideLayout ( entity . boundingInfoMesh )
129+ if ( isOutside ) {
130+ entitiesOutOfBoundariesArray . push ( node . entity )
131+ }
132+ }
133+ } )
114134
115- dispatch ( setEntitiesOutOfBoundaries ( entitiesOutOfBoundaries ) )
135+ dispatch ( setEntitiesOutOfBoundaries ( entitiesOutOfBoundariesArray ) )
116136 } , [ sdk , dispatch , getNodes , setEntitiesOutOfBoundaries ] )
117137
118138 useEffect ( ( ) => {
@@ -155,6 +175,10 @@ const Metrics = withSdk<WithSdkProps>(({ sdk }) => {
155175 )
156176 } , [ metrics , limits ] )
157177
178+ const isAnyLimitExceeded = ( limitsExceeded : Record < string , any > ) : boolean => {
179+ return Object . values ( limitsExceeded ) . length > 0 || entitiesOutOfBoundaries . length > 0
180+ }
181+
158182 const handleToggleMetricsOverlay = useCallback (
159183 ( e : React . MouseEvent < HTMLButtonElement > | MouseEvent ) => {
160184 e . preventDefault ( )
@@ -166,30 +190,49 @@ const Metrics = withSdk<WithSdkProps>(({ sdk }) => {
166190
167191 const overlayRef = useOutsideClick ( handleToggleMetricsOverlay )
168192
193+ const getWarningMessages = ( ) : string [ ] => {
194+ const baseMessage = 'Your scene contains too many'
195+ const warnings : string [ ] = [ ]
196+
197+ Object . entries ( limitsExceeded ) . forEach ( ( [ key , isExceeded ] ) => {
198+ if ( isExceeded ) {
199+ warnings . push ( `${ baseMessage } ${ key } ` )
200+ }
201+ } )
202+
203+ if ( entitiesOutOfBoundaries . length > 0 ) {
204+ warnings . push (
205+ `${ entitiesOutOfBoundaries . length } entit${
206+ entitiesOutOfBoundaries . length === 1 ? 'y is' : 'ies are'
207+ } out of bounds and may not display correctly in-world.`
208+ )
209+ }
210+
211+ return warnings
212+ }
213+
214+ const warningMessages = getWarningMessages ( )
215+
169216 return (
170217 < div className = "Metrics" >
171218 < div className = "Buttons" >
172219 < Button
173- className = { cx ( { Active : showMetrics , LimitExceeded : Object . values ( limitsExceeded ) . length > 0 } ) }
220+ className = { cx ( { Active : showMetrics , LimitExceeded : isAnyLimitExceeded ( limitsExceeded ) } ) }
174221 onClick = { handleToggleMetricsOverlay }
175222 >
176223 < SquaresGridIcon size = { ICON_SIZE } />
177224 </ Button >
178225 </ div >
179- { Object . values ( limitsExceeded ) . length > 0 && (
180- < div className = "LimitExceeded" >
181- < AlertIcon />
182- Too many { Object . keys ( limitsExceeded ) [ 0 ] . toUpperCase ( ) }
183- </ div >
184- ) }
185226 { showMetrics && (
186227 < div ref = { overlayRef } className = "Overlay" >
187- < h2 className = "Header" >
188- { sceneLayout . parcels . length } Parcels
189- < span className = "secondary" >
190- { sceneLayout . parcels . length * PARCEL_SIZE } m< sup > 2</ sup >
191- </ span >
192- </ h2 >
228+ < h2 className = "Header" > Scene Optimization</ h2 >
229+ < div className = "Description" > Suggested Specs per Parcel</ div >
230+ < div className = "Description" >
231+ { sceneLayout . parcels . length } Parcels = { sceneLayout . parcels . length * PARCEL_SIZE }
232+ < div >
233+ m< sup > 2</ sup >
234+ </ div >
235+ </ div >
193236 < div className = "Items" >
194237 { Object . entries ( metrics ) . map ( ( [ key , value ] ) => (
195238 < div className = "Item" key = { key } >
@@ -202,6 +245,17 @@ const Metrics = withSdk<WithSdkProps>(({ sdk }) => {
202245 </ div >
203246 ) ) }
204247 </ div >
248+ { warningMessages . length > 0 && (
249+ < div className = "WarningsContainer" >
250+ < div className = "Description" > WARNINGS</ div >
251+ { warningMessages . map ( ( message , index ) => (
252+ < div className = "WarningItem" key = { index } >
253+ < WarningIcon className = "WarningIcon" />
254+ < span className = "WarningText" > { message } </ span >
255+ </ div >
256+ ) ) }
257+ </ div >
258+ ) }
205259 </ div >
206260 ) }
207261 </ div >
0 commit comments