diff --git a/editor/MapNodeEditor.tsx b/editor/MapNodeEditor.tsx index 901ddce..c08c828 100755 --- a/editor/MapNodeEditor.tsx +++ b/editor/MapNodeEditor.tsx @@ -6,46 +6,45 @@ import StringInput from '@etherealengine/editor/src/components/inputs/StringInpu import NodeEditor from '@etherealengine/editor/src/components/properties/NodeEditor' import { MapComponent } from '../engine/MapComponent' import { EditorComponentType, updateProperty } from '@etherealengine/editor/src/components/properties/Util' -import { getComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' +import { useComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' export const MapNodeEditor: EditorComponentType = (props) => { const { t } = useTranslation() - - const mapComponent = getComponent(props.node.entity, MapComponent) + const mapComponent = useComponent(props.entity, MapComponent) console.log('MapNodeEditor') return ( - + - + - + - + - + - + ) diff --git a/editor/index.ts b/editor/index.ts index c3481b4..8afbba1 100644 --- a/editor/index.ts +++ b/editor/index.ts @@ -1,14 +1,13 @@ +import { prefabIcons } from '@etherealengine/editor/src/functions/PrefabEditors' +import { startSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions' -import { EntityNodeEditor, prefabIcons } from '@etherealengine/editor/src/functions/PrefabEditors' -import { MapNodeEditor } from './MapNodeEditor' import MapIcon from '@mui/icons-material/Map' -import { map } from '../worldInjection' -import { World } from '@etherealengine/engine/src/ecs/classes/World' + import MapUpdateSystem from '../engine/MapUpdateSystem' +import { GEO_MAP } from '../worldInjection' -EntityNodeEditor[map] = MapNodeEditor -prefabIcons[map] = MapIcon +export default async () => { + prefabIcons[GEO_MAP] = MapIcon -export default async (world: World) => { - return await MapUpdateSystem(world) -} \ No newline at end of file + startSystem(MapUpdateSystem, {}) +} diff --git a/engine/MapComponent.ts b/engine/MapComponent.ts index 8f12a26..e0eea33 100644 --- a/engine/MapComponent.ts +++ b/engine/MapComponent.ts @@ -1,18 +1,69 @@ -import { createMappedComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' +import { useEffect } from 'react' import { Vector3 } from 'three' -export type MapComponentType = { - apiKey: string - name?: string - scale?: Vector3 - style?: any - useTimeOfDay?: number - useDirectionalShadows?: boolean - useDeviceGeolocation?: boolean - startLatitude?: string - startLongitude?: string - showRasterTiles?: boolean - enableDebug?: boolean -} +import { isClient } from '@etherealengine/engine/src/common/functions/getEnvironment' +import { ComponentType, defineComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' +import { useEntityContext } from '@etherealengine/engine/src/ecs/functions/EntityFunctions' -export const MapComponent = createMappedComponent('MapComponent') +import { _updateMap, deserializeMap, SCENE_COMPONENT_MAP } from './MapFunctions' + +export const MapComponent = defineComponent({ + name: 'EE_maps_scene_component', + jsonID: SCENE_COMPONENT_MAP, + onInit: (entity) => { + return { + apiKey: '', + name: '', + scale: new Vector3(), + style: {}, + useTimeOfDay: 0, + useDirectionalShadows: false, + useDeviceGeolocation: false, + startLatitude: '', + startLongitude: '', + showRasterTiles: false, + enableDebug: false + } + }, + onSet: (entity, component, json) => { + if (!json) return + component.apiKey.set(json.apiKey!) + component.name.set(json.name!) + component.scale.set(json.scale!) + component.style.set(json.style!) + component.useTimeOfDay.set(json.useTimeOfDay!) + component.useDirectionalShadows.set(json.useDirectionalShadows!) + component.useDeviceGeolocation.set(json.useDeviceGeolocation!) + component.startLatitude.set(json.startLatitude!) + component.startLongitude.set(json.startLongitude!) + component.showRasterTiles.set(json.showRasterTiles!) + component.enableDebug.set(json.enableDebug!) + deserializeMap(entity, component.value) + }, + toJSON: (entity, component) => { + return { + apiKey: component.apiKey, + name: component.name, + scale: component.scale, + useTimeOfDay: component.useTimeOfDay, + useDirectionalShadows: component.useDirectionalShadows, + useDeviceGeolocation: component.useDeviceGeolocation, + startLatitude: component.startLatitude, + startLongitude: component.startLongitude, + showRasterTiles: component.showRasterTiles, + enableDebug: component.enableDebug + } + }, + reactor: () => { + if (!isClient) return null + const entity = useEntityContext() + + useEffect(() => { + _updateMap(entity, {}) + }, [entity]) + + return null + } +}) + +export type MapComponentType = ComponentType diff --git a/engine/MapFunctions.ts b/engine/MapFunctions.ts index 7cd979c..3fc31a9 100755 --- a/engine/MapFunctions.ts +++ b/engine/MapFunctions.ts @@ -1,65 +1,85 @@ -import { getStartCoords } from './getStartCoords' -import { MapComponentType } from './MapComponent' -import { addComponent, getComponent, hasComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' -import { DebugNavMeshComponent } from '@etherealengine/engine/src/debug/DebugNavMeshComponent' -import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity' -import { Object3D, Group, Mesh } from 'three' -import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine' -import { NavMeshComponent } from '@etherealengine/engine/src/navigation/component/NavMeshComponent' -import { MapAction, mapReducer } from './MapReceptor' -import { MapComponent } from './MapComponent' -import { getPhases, startPhases } from './functions/PhaseFunctions' -import { LoadGLTF } from '@etherealengine/engine/src/assets/functions/LoadGLTF' -import { avatarHalfHeight } from '@etherealengine/engine/src/avatar/functions/createAvatar' +import { debounce } from 'lodash' +import { Group, Mesh, Object3D } from 'three' import { Text } from 'troika-three-text' -import { Object3DComponent } from '@etherealengine/engine/src/scene/components/Object3DComponent' + import { ComponentJson } from '@etherealengine/common/src/interfaces/SceneInterface' -import { isClient } from '@etherealengine/engine/src/common/functions/isClient' -import { registerSceneLoadPromise } from '@etherealengine/engine/src/scene/functions/SceneLoading' -import { EntityNodeComponent } from '@etherealengine/engine/src/scene/components/EntityNodeComponent' +import { defaultAvatarHalfHeight } from '@etherealengine/engine/src/avatar/functions/spawnAvatarReceptor' +import { isClient } from '@etherealengine/engine/src/common/functions/getEnvironment' +// import { DebugNavMeshComponent } from '@etherealengine/engine/src/debug/DebugNavMeshComponent' +import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine' +import { EngineState } from '@etherealengine/engine/src/ecs/classes/EngineState' +import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity' +import { + addComponent, + ComponentType, + defineQuery, + getAllComponents, + getComponent, + hasComponent, + setComponent +} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' +import { GroupComponent, Object3DWithEntity } from '@etherealengine/engine/src/scene/components/GroupComponent' +import { SceneAssetPendingTagComponent } from '@etherealengine/engine/src/scene/components/SceneAssetPendingTagComponent' +import { getMutableState, getState } from '@etherealengine/hyperflux' + +import { getPhases, startPhases } from './functions/PhaseFunctions' +import { getStartCoords } from './getStartCoords' +import { NavMeshComponent } from './helpers/NavMeshComponent' +import { MapComponent, MapComponentType } from './MapComponent' +import { MapState, MapStateService } from './MapReceptor' import { addChildFast, setPosition } from './util' -import { debounce } from 'lodash' export const SCENE_COMPONENT_MAP = 'map' export const SCENE_COMPONENT_MAP_DEFAULT_VALUES = {} -export const deserializeMap = (entity: Entity, json: ComponentJson) => { +export const deserializeMap = (entity: Entity, json: ComponentJson) => { + console.log('deserialize_map') + const sceneAssetPendingTagQuery = defineQuery([SceneAssetPendingTagComponent]) + console.log('sceneassetpending', sceneAssetPendingTagQuery.length) if (isClient) { - registerSceneLoadPromise(createMap(entity, json.props)) - if (Engine.isEditor) getComponent(entity, EntityNodeComponent)?.components.push(SCENE_COMPONENT_MAP) + // if (sceneAssetPendingTagQuery.length > 0) { + createMap(entity, json.props as MapComponentType) + // } + + // if (getState(EngineState).isEditor) { + // const components = getAllComponents(entity) + // components.push(SCENE_COMPONENT_MAP) + // } } } export const createMap = async (entity: Entity, args: MapComponentType) => { - if(Engine.isEditor && hasComponent(entity, MapComponent)) { + console.log('create_map_1') + if (getState(EngineState).isEditor && hasComponent(entity, MapComponent)) { _updateMap(entity, args) return } // TODO: handle "navigator.geolocation.getCurrentPosition" rejection? - addComponent(entity, MapComponent, args) const center = await getStartCoords(args) - const mapObject3D = new Group() + const mapObject3D = new Object3D() as Object3DWithEntity const navigationRaycastTarget = new Group() mapObject3D.name = '(Geographic) Map' - addComponent(entity, Object3DComponent, { - value: mapObject3D - }) + addComponent(entity, GroupComponent, [mapObject3D]) + if (args.enableDebug) { - addComponent(entity, DebugNavMeshComponent, { object3d: new Group() }) + // addComponent(entity, DebugNavMeshComponent, { object3d: new Group() }) } - const state = mapReducer(null, MapAction.initialize(center, args.scale?.x)) + console.log('map_functions_create_map') - // TODO fix hardcoded URL - const spinnerGLTF = await LoadGLTF(Engine.publicPath + '/projects/XREngine-Project-Maps/EarthLowPoly.glb') - const spinner = spinnerGLTF.scene as Mesh - spinner.position.y = avatarHalfHeight * 2 - spinner.position.z = -150 - state.updateSpinner = spinner + MapStateService.initializeMap(center, args.scale?.x) + + const state = getMutableState(MapState) + + // const spinnerGLTF = getState(EngineState).publicPath + '/projects/ee-maps/EarthLowPoly.glb' + // const spinner = spinnerGLTF as Mesh + // spinner.position.y = defaultAvatarHalfHeight * 2 + // spinner.position.z = -150 + // state.updateSpinner = spinner const updateTextContainer = new Text() @@ -76,12 +96,11 @@ export const createMap = async (entity: Entity, args: MapComponentType) => { updateTextContainer.sync() - state.updateTextContainer = updateTextContainer - - await startPhases(state, await getPhases({ exclude: ['navigation'] })) + const tempState = { ...state.value, updateTextContainer } + await startPhases(tempState, await getPhases({ exclude: ['navigation'] })) - navigationRaycastTarget.scale.setScalar(state.scale) - Engine.scene.add(navigationRaycastTarget) + navigationRaycastTarget.scale.setScalar(state.scale.value) + Engine.instance.scene.add(navigationRaycastTarget) addComponent(entity, NavMeshComponent, { /* @@ -93,30 +112,37 @@ export const createMap = async (entity: Entity, args: MapComponentType) => { } export const _updateMap = async (entity: Entity, props: any) => { - // only update on some property changes - if(!( - Object.keys(props).includes('startLatitude') - || Object.keys(props).includes('startLongitude') - || Object.keys(props).includes('useDeviceGeolocation')) - ) return + + // if ( + // !( + // Object.keys(props).includes('startLatitude') || + // Object.keys(props).includes('startLongitude') || + // Object.keys(props).includes('useDeviceGeolocation') + // ) + // ) + // return + + console.log('_updatemap') const args = getComponent(entity, MapComponent) const center = await getStartCoords(args) + console.log('center->', center) const subSceneChildren = [] const subScene = this as unknown as Object3D - const state = mapReducer(null, MapAction.initialize(center, args.scale?.x)) + MapStateService.initializeMap(center, args.scale?.x) + const state = getMutableState(MapState) - await startPhases(state, await getPhases({ exclude: ['navigation'] })) + await startPhases(state.value, await getPhases({ exclude: ['navigation'] })) - for (const object of state.completeObjects.values()) { + for (const object of state.completeObjects.value.values()) { if (object.mesh) { setPosition(object.mesh, object.centerPoint) addChildFast(subScene, object.mesh, subSceneChildren) } } - for (const object of state.labelCache.values()) { + for (const object of state.labelCache.value.values()) { if (object.mesh) { setPosition(object.mesh, object.centerPoint) addChildFast(subScene, object.mesh, subSceneChildren) @@ -125,23 +151,8 @@ export const _updateMap = async (entity: Entity, props: any) => { } subScene.children = subSceneChildren } -export const updateMap = debounce((entity, args) => _updateMap(entity, args), 500) as any as (entity: Entity, props: any) => void - -export const serializeMap = (entity: Entity) => { - const mapComponent = getComponent(entity, MapComponent) - return { - name: SCENE_COMPONENT_MAP, - props: { - apiKey: mapComponent.apiKey, - name: mapComponent.name, - scale: mapComponent.scale, - useTimeOfDay: mapComponent.useTimeOfDay, - useDirectionalShadows: mapComponent.useDirectionalShadows, - useDeviceGeolocation: mapComponent.useDeviceGeolocation, - startLatitude: mapComponent.startLatitude, - startLongitude: mapComponent.startLongitude, - showRasterTiles: mapComponent.showRasterTiles, - enableDebug: mapComponent.enableDebug - } - } -} \ No newline at end of file + +export const updateMap = debounce((entity, args) => _updateMap(entity, args), 500) as any as ( + entity: Entity, + props: any +) => void diff --git a/engine/MapReceptor.ts b/engine/MapReceptor.ts index 10cd2ee..a9507ff 100644 --- a/engine/MapReceptor.ts +++ b/engine/MapReceptor.ts @@ -1,7 +1,18 @@ -import { createState, Downgraded } from '@hookstate/core' +import { MultiPolygon } from 'polygon-clipping' +import { Mesh } from 'three' + +import { matches, Validator } from '@etherealengine/engine/src/common/functions/MatchesUtils' +import { defineAction, defineState, dispatchAction, getMutableState } from '@etherealengine/hyperflux' + +import FeatureCache from './classes/FeatureCache' import HashMap from './classes/HashMap' +import HashSet from './classes/HashSet' +import MutableNavMesh from './classes/MutableNavMesh' import TileCache from './classes/TileCache' +import { MAX_CACHED_FEATURES, MAX_CACHED_TILES } from './constants' +import { LongLat } from './functions/UnitConversionFunctions' import { + FeatureKey, MapDerivedFeatureComplete, MapDerivedFeatureGeometry, MapFeatureLabel, @@ -9,108 +20,111 @@ import { MapTransformedFeature, SupportedFeature, TaskStatus, - VectorTile, + Text3D, TileKey, - FeatureKey, - Text3D + VectorTile } from './types' -import { MAX_CACHED_TILES, MAX_CACHED_FEATURES } from './constants' -import FeatureCache from './classes/FeatureCache' -import { MultiPolygon } from 'polygon-clipping' -import MutableNavMesh from './classes/MutableNavMesh' -import { LongLat } from './functions/UnitConversionFunctions' -import HashSet from './classes/HashSet' -import { isClient } from '@etherealengine/engine/src/common/functions/isClient' -import { Mesh } from 'three' -const state = createState({ - center: [0, 0], - originalCenter: [0, 0], - viewerPosition: [0, 0], - triggerRefreshRadius: 160, - minimumSceneRadius: 800, - labelRadius: 400, - navMeshRadius: 400, - scale: 1, - fetchTilesTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - tileCache: new TileCache(MAX_CACHED_TILES), - extractTilesTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - featureCache: new FeatureCache(MAX_CACHED_FEATURES), - transformedFeatureTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - transformedFeatureCache: new FeatureCache(MAX_CACHED_FEATURES), - geometryTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - geometryCache: new FeatureCache(MAX_CACHED_FEATURES), - completeObjectsTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - completeObjects: new FeatureCache(MAX_CACHED_FEATURES), - labelTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - labelCache: new FeatureCache(MAX_CACHED_FEATURES), - tileNavMeshTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - tileNavMeshCache: new TileCache(MAX_CACHED_TILES), - helpersTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), - helpersCache: new TileCache(MAX_CACHED_TILES), - tileMeta: new HashMap }>([], { - defaultValue: { cachedFeatureKeys: new HashSet() } - }), - featureMeta: new HashMap(), - navMesh: new MutableNavMesh(), - activePhase: null as null | string, - updateSpinner: null as null | Mesh, - updateTextContainer: null as null | Text3D +interface IMapInitializeAction { + centerPoint: LongLat + triggerRefreshRadius: number + minimumSceneRadius: number + scale: number +} + +export const MapState = defineState({ + name: 'EE_Map_State', + initial: () => ({ + center: [0, 0], + originalCenter: [0, 0], + viewerPosition: [0, 0], + triggerRefreshRadius: 160, + minimumSceneRadius: 800, + labelRadius: 400, + navMeshRadius: 400, + scale: 1, + fetchTilesTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + tileCache: new TileCache(MAX_CACHED_TILES), + extractTilesTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + featureCache: new FeatureCache(MAX_CACHED_FEATURES), + transformedFeatureTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + transformedFeatureCache: new FeatureCache(MAX_CACHED_FEATURES), + geometryTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + geometryCache: new FeatureCache(MAX_CACHED_FEATURES), + completeObjectsTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + completeObjects: new FeatureCache(MAX_CACHED_FEATURES), + labelTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + labelCache: new FeatureCache(MAX_CACHED_FEATURES), + tileNavMeshTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + tileNavMeshCache: new TileCache(MAX_CACHED_TILES), + helpersTasks: new HashMap([], { defaultValue: TaskStatus.NOT_STARTED }), + helpersCache: new TileCache(MAX_CACHED_TILES), + tileMeta: new HashMap }>([], { + defaultValue: { cachedFeatureKeys: new HashSet() } + }), + featureMeta: new HashMap(), + navMesh: new MutableNavMesh(), + activePhase: null as null | string, + updateSpinner: null as null | Mesh, + updateTextContainer: null as null | Text3D + }) }) -export type _MapStateUnwrapped = ReturnType +// ACTIONS -export const MapAction = { - initialize: (centerPoint: LongLat, scale = 1, triggerRefreshRadius = 40, minimumSceneRadius = 800) => { - return { - type: 'map.INITIALIZE' as const, - centerPoint, - triggerRefreshRadius, - minimumSceneRadius, - scale - } - }, - setCenterPoint: (centerPoint: LongLat) => { - return { - type: 'map.SET_CENTER_POINT' as const, - centerPoint - } - } +export class MapStateActions { + static initialize = defineAction({ + type: 'ee.maps.MapState.INITIALIZE' as const, + data: matches.object as Validator + }) + static setProperty = defineAction({ + type: 'ee.maps.MapState.SET_PROPERTY' as const, + data: matches.object as Validator> + }) } -export type MapActionType = ReturnType +// RECEPTORS -export const mapReducer = (_, action: MapActionType) => { - mapReceptor(action) - return state.attach(Downgraded).value +const mapInitializeActionReceptor = (action: typeof MapStateActions.initialize.matches._TYPE) => { + const state = getMutableState(MapState) + return state.merge({ + center: action.data.centerPoint, + originalCenter: action.data.centerPoint, + triggerRefreshRadius: action.data.triggerRefreshRadius, + minimumSceneRadius: action.data.minimumSceneRadius, + labelRadius: action.data.minimumSceneRadius * 0.5, + navMeshRadius: action.data.minimumSceneRadius * 0.5, + scale: action.data.scale + }) } -export const mapReceptor = (action: MapActionType) => { - state.batch((s) => { - switch (action.type) { - case 'map.INITIALIZE': - return s.merge({ - center: action.centerPoint, - originalCenter: action.centerPoint, - triggerRefreshRadius: action.triggerRefreshRadius, - minimumSceneRadius: action.minimumSceneRadius, - labelRadius: action.minimumSceneRadius * 0.5, - navMeshRadius: action.minimumSceneRadius * 0.5, - scale: action.scale - }) - case 'map.SET_CENTER_POINT': - return s.merge({ - center: action.centerPoint, - originalCenter: action.centerPoint - }) - } - }) +const mapSetPropertyActionReceptor = (action: typeof MapStateActions.setProperty.matches._TYPE) => { + const state = getMutableState(MapState) + return state.merge(action.data) } -export const accessMapState = () => state +export const MapStateReceptor = { + mapInitializeActionReceptor, + mapSetPropertyActionReceptor +} -if (process.env.APP_ENV === 'development' && isClient) { - ;(window as any).mapReceptor = mapReceptor - ;(window as any).MapAction = MapAction - ;(window as any).accessMapState = accessMapState +// SERVICE + +export const MapStateService = { + initializeMap: (centerPoint: LongLat, scale = 1, triggerRefreshRadius = 40, minimumSceneRadius = 800) => + dispatchAction( + MapStateActions.initialize({ + data: { + centerPoint, + scale, + triggerRefreshRadius, + minimumSceneRadius + } + }) + ), + setProperty: (data: Partial) => { + dispatchAction(MapStateActions.setProperty({ data })) + } } + +MapStateService.setProperty({}) diff --git a/engine/MapUpdateSystem.ts b/engine/MapUpdateSystem.ts index 414a5a4..ec90f5a 100644 --- a/engine/MapUpdateSystem.ts +++ b/engine/MapUpdateSystem.ts @@ -1,20 +1,23 @@ -import { System } from '@etherealengine/engine/src/ecs/classes/System' -import { MapComponent } from './MapComponent' -import { TransformComponent } from '@etherealengine/engine/src/transform/components/TransformComponent' -import { fromMetersFromCenter, LongLat } from './functions/UnitConversionFunctions' -import { addChildFast, multiplyArray, setPosition, vectorToArray } from './util' import { Vector3 } from 'three' -import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity' -import { Object3DComponent } from '@etherealengine/engine/src/scene/components/Object3DComponent' -import { getComponent, defineQuery, addComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' -import { World } from '@etherealengine/engine/src/ecs/classes/World' -import isIntersectCircleCircle from './functions/isIntersectCircleCircle' + import { AvatarComponent } from '@etherealengine/engine/src/avatar/components/AvatarComponent' -import { NavMeshComponent } from '@etherealengine/engine/src/navigation/component/NavMeshComponent' -import { accessMapState } from './MapReceptor' -import { Downgraded } from '@hookstate/core' -import { getPhases, startPhases, resetPhases } from './functions/PhaseFunctions' import { TargetCameraRotationComponent } from '@etherealengine/engine/src/camera/components/TargetCameraRotationComponent' +import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine' +import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity' +import { addComponent, defineQuery, getComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' +import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions' +import { GroupComponent } from '@etherealengine/engine/src/scene/components/GroupComponent' +import { TransformComponent } from '@etherealengine/engine/src/transform/components/TransformComponent' +import { defineActionQueue, getMutableState } from '@etherealengine/hyperflux' + +import isIntersectCircleCircle from './functions/isIntersectCircleCircle' +import { getPhases, resetPhases, startPhases } from './functions/PhaseFunctions' +import { fromMetersFromCenter, LongLat } from './functions/UnitConversionFunctions' +import { NavMeshComponent } from './helpers/NavMeshComponent' +import { MapComponent } from './MapComponent' +import { MapState, MapStateActions, MapStateReceptor, MapStateService } from './MapReceptor' +import { IPhase } from './types' +import { addChildFast, multiplyArray, setPosition, vectorToArray } from './util' const PI2 = Math.PI * 2 const $vector3 = new Vector3() @@ -24,167 +27,185 @@ const $normalScaleViewerPositionDelta = new Array(2) as [number, number] const $previousViewerPosition = new Vector3() const $previousMapCenterPoint: LongLat = Array(2) -export default async function MapUpdateSystem(world: World): Promise { - const mapsQuery = defineQuery([MapComponent]) - const viewerQuery = defineQuery([AvatarComponent]) - const navMeshQuery = defineQuery([NavMeshComponent]) - const phases = await getPhases({ exclude: ['navigation'] }) - let previousViewerEntity: Entity - let spinnerAngle = 0 - - return () => { - const viewerEntity = viewerQuery(world)[0] - const mapEntities = mapsQuery(world) - const mapEntity = mapEntities[0] - const navPlaneEntity = navMeshQuery(world)[0] - // Sanity checks - if (!mapEntity || !viewerEntity) return world - if (mapEntities.length > 1) console.warn('Not supported: More than one map!') - const mapState = accessMapState().attach(Downgraded).get() - const mapScale = mapState.scale - const object3dComponent = getComponent(mapEntity, Object3DComponent) - const viewerTransform = getComponent(viewerEntity, TransformComponent) - const viewerPosition = vectorToArray(viewerTransform.position) - const viewerPositionScaled = multiplyArray(viewerPosition, 1 / mapScale) - const navigationRaycastTarget = getComponent(navPlaneEntity, NavMeshComponent).navTarget - const avatar = getComponent(viewerEntity, AvatarComponent) - - // Initialize on first pass or whenever the viewer changes - if (viewerEntity !== previousViewerEntity) { - $previousViewerPosition.copy(viewerTransform.position) - } +const mapsQuery = defineQuery([MapComponent]) +const viewerQuery = defineQuery([AvatarComponent]) +const navMeshQuery = defineQuery([NavMeshComponent]) +const mapStateInitializeActionQueue = defineActionQueue(MapStateActions.initialize.matches) +const mapStateSetPropertyActionQueue = defineActionQueue(MapStateActions.setProperty.matches) + +let previousViewerEntity: Entity | null = null +let spinnerAngle = 0 + +let phases: readonly IPhase[] +getPhases({ exclude: ['navigation'] }).then((phases_) => (phases = phases_)) + +const execute = () => { + if (!phases) return + + const viewerEntity = viewerQuery()[0] + const mapEntities = mapsQuery() + const mapEntity = mapEntities[0] + const navPlaneEntity = navMeshQuery()[0] + + // Sanity checks + if (!mapEntity || !viewerEntity) return + if (mapEntities.length > 1) console.warn('Not supported: More than one map!') + + // MAP STATE RECEPTORS + for (const action of mapStateInitializeActionQueue()) MapStateReceptor.mapInitializeActionReceptor(action) + for (const action of mapStateSetPropertyActionQueue()) MapStateReceptor.mapSetPropertyActionReceptor(action) + + const mapState = getMutableState(MapState) + const mapScale = mapState.scale.value + const object3dComponent = getComponent(mapEntity, GroupComponent) + const viewerTransform = getComponent(viewerEntity, TransformComponent) + const viewerPosition = vectorToArray(viewerTransform.position) + const viewerPositionScaled = multiplyArray(viewerPosition, 1 / mapScale) + const navigationRaycastTarget = getComponent(navPlaneEntity, NavMeshComponent).navTarget + const avatar = getComponent(viewerEntity, AvatarComponent) + + // Initialize on first pass or whenever the viewer changes + if (viewerEntity !== previousViewerEntity) { + $previousViewerPosition.copy(viewerTransform.position) + } - // Find how far the viewer has travelled since last update, in real-world scale (scale=1) - // TODO only compare x, z components of positions - $vector3.subVectors(viewerTransform.position, $previousViewerPosition).divideScalar(mapScale) - vectorToArray($vector3, $normalScaleViewerPositionDelta) - const viewerDistanceFromCenterSquared = - $normalScaleViewerPositionDelta[0] * $normalScaleViewerPositionDelta[0] + - $normalScaleViewerPositionDelta[1] * $normalScaleViewerPositionDelta[1] - - const wasRefreshTriggered = - viewerDistanceFromCenterSquared >= mapState.triggerRefreshRadius * mapState.triggerRefreshRadius - const wasMapCenterUpdated = - typeof $previousMapCenterPoint[0] !== 'undefined' && - typeof $previousMapCenterPoint[1] !== 'undefined' && - ($previousMapCenterPoint[0] !== mapState.center[0] || $previousMapCenterPoint[1] !== mapState.center[1]) - - if (wasMapCenterUpdated) { - mapState.viewerPosition[0] = $previousViewerPosition[0] = 0 - mapState.viewerPosition[1] = $previousViewerPosition[1] = 0 - viewerTransform.position.set(0, 0, 0) - resetPhases(mapState, phases) - } + // Find how far the viewer has travelled since last update, in real-world scale (scale=1) + // TODO only compare x, z components of positions + $vector3.subVectors(viewerTransform.position, $previousViewerPosition).divideScalar(mapScale) + vectorToArray($vector3, $normalScaleViewerPositionDelta) + const viewerDistanceFromCenterSquared = + $normalScaleViewerPositionDelta[0] * $normalScaleViewerPositionDelta[0] + + $normalScaleViewerPositionDelta[1] * $normalScaleViewerPositionDelta[1] + + const wasRefreshTriggered = + viewerDistanceFromCenterSquared >= mapState.triggerRefreshRadius.value * mapState.triggerRefreshRadius.value + const wasMapCenterUpdated = + typeof $previousMapCenterPoint[0] !== 'undefined' && + typeof $previousMapCenterPoint[1] !== 'undefined' && + ($previousMapCenterPoint[0] !== mapState.center.value[0] || $previousMapCenterPoint[1] !== mapState.center.value[1]) + + if (wasMapCenterUpdated) { + mapState.viewerPosition.value[0] = $previousViewerPosition[0] = 0 + mapState.viewerPosition.value[1] = $previousViewerPosition[1] = 0 + viewerTransform.position.set(0, 0, 0) + resetPhases(mapState.value, phases) + } - if (wasRefreshTriggered || wasMapCenterUpdated) { - mapState.center = fromMetersFromCenter($normalScaleViewerPositionDelta, mapState.center) - mapState.viewerPosition = viewerPosition - startPhases(mapState, phases) + if (wasRefreshTriggered || wasMapCenterUpdated) { + const tempMapState = { ...mapState.value } + tempMapState.center = fromMetersFromCenter($normalScaleViewerPositionDelta, tempMapState.center) + tempMapState.viewerPosition = viewerPosition + startPhases(tempMapState, phases) - $previousViewerPosition.copy(viewerTransform.position) - $previousViewerPosition.y = 0 - } + $previousViewerPosition.copy(viewerTransform.position) + $previousViewerPosition.y = 0 + } - $previousMapCenterPoint[0] = mapState.center[0] - $previousMapCenterPoint[1] = mapState.center[1] - - // Perf hack: Start with an empty array so that any children that have been purged or that do not meet the criteria for adding are implicitly removed. - if (mapState.updateSpinner && mapState.activePhase !== null && mapState.completeObjects.size === 0) { - const spinner = mapState.updateSpinner - spinner.rotation.y = spinnerAngle - spinnerAngle = (spinnerAngle + 0.01) % PI2 - - object3dComponent.value.children.length = 0 - navigationRaycastTarget.children.length = 0 - object3dComponent.value.children[0] = spinner - - object3dComponent.value.children[1] = mapState.updateTextContainer! - - avatar.modelContainer.visible = false - addComponent(viewerEntity, TargetCameraRotationComponent, { - time: 0, - phi: 0, - theta: 0, - phiVelocity: { value: Math.PI }, - thetaVelocity: { value: Math.PI } - }) - } else if (mapState.activePhase === 'UpdateScene') { - avatar.modelContainer.visible = true - object3dComponent.value.children.length = 0 - for (const key of mapState.completeObjects.keys()) { - const object = mapState.completeObjects.get(key) - if (object.mesh) { - if ( - isIntersectCircleCircle( - viewerPositionScaled, - mapState.minimumSceneRadius * mapState.scale, - object.centerPoint, - object.boundingCircleRadius - ) && - key[0] !== 'landuse_fallback' - ) { - setPosition(object.mesh, object.centerPoint) - addChildFast(object3dComponent.value, object.mesh) - } else { - object.mesh.parent = null - } + $previousMapCenterPoint[0] = mapState.center.value[0] + $previousMapCenterPoint[1] = mapState.center.value[1] + + // Perf hack: Start with an empty array so that any children that have been purged or that do not meet the criteria for adding are implicitly removed. + if (mapState.updateSpinner && mapState.activePhase !== null && mapState.completeObjects.value.size === 0) { + const spinner = mapState.updateSpinner.value! + spinner.rotation.y = spinnerAngle + spinnerAngle = (spinnerAngle + 0.01) % PI2 + + object3dComponent[0].children.length = 0 + navigationRaycastTarget.children.length = 0 + object3dComponent[0].children[0] = spinner + + object3dComponent[0].children[1] = mapState.updateTextContainer.value! + + avatar.model!.visible = false + addComponent(viewerEntity, TargetCameraRotationComponent, { + time: 0, + phi: 0, + theta: 0, + phiVelocity: { value: Math.PI }, + thetaVelocity: { value: Math.PI } + }) + } else if (mapState.activePhase.value === 'UpdateScene') { + avatar.model!.visible = true + object3dComponent[0].children.length = 0 + for (const key of mapState.completeObjects.value.keys()) { + const object = mapState.completeObjects.value.get(key) + if (object.mesh) { + if ( + isIntersectCircleCircle( + viewerPositionScaled, + mapState.minimumSceneRadius.value * mapState.scale.value, + object.centerPoint, + object.boundingCircleRadius + ) && + key[0] !== 'landuse_fallback' + ) { + setPosition(object.mesh, object.centerPoint) + addChildFast(object3dComponent[0], object.mesh) + } else { + object.mesh.parent = null } } - for (const label of mapState.labelCache.values()) { - if (label.mesh) { - if ( - isIntersectCircleCircle( - viewerPositionScaled, - mapState.labelRadius * mapState.scale, - label.centerPoint, - label.boundingCircleRadius - ) - ) { - setPosition(label.mesh, label.centerPoint) - addChildFast(object3dComponent.value, label.mesh) - } else { - label.mesh.parent = null - } + } + for (const label of mapState.labelCache.value.values()) { + if (label.mesh) { + if ( + isIntersectCircleCircle( + viewerPositionScaled, + mapState.labelRadius.value * mapState.scale.value, + label.centerPoint, + label.boundingCircleRadius + ) + ) { + setPosition(label.mesh, label.centerPoint) + addChildFast(object3dComponent[0], label.mesh) + } else { + label.mesh.parent = null } } - navigationRaycastTarget.children.length = 0 - for (const key of mapState.completeObjects.keys()) { - const layerName = key[0] - if (layerName === 'landuse_fallback') { - const { mesh, centerPoint } = mapState.completeObjects.get(key) - setPosition(mesh, centerPoint) - - addChildFast(navigationRaycastTarget, mesh) - } + } + // navigationRaycastTarget.children.length = 0 + for (const key of mapState.completeObjects.value.keys()) { + const layerName = key[0] + if (layerName === 'landuse_fallback') { + const { mesh, centerPoint } = mapState.completeObjects.value.get(key) + setPosition(mesh, centerPoint) + + addChildFast(navigationRaycastTarget, mesh) } - for (const helpers of mapState.helpersCache.values()) { - if (helpers.tileNavMesh) { - addChildFast(object3dComponent.value, helpers.tileNavMesh) - } + } + for (const helpers of mapState.helpersCache.value.values()) { + if (helpers.tileNavMesh) { + addChildFast(object3dComponent[0], helpers.tileNavMesh) } - - // Update (sub)scene - mapState.activePhase = null } - // Update labels - if (Math.round(world.fixedElapsedTime / world.fixedDelta) % 20 === 0) { - for (const label of mapState.labelCache.values()) { - if (label.mesh) { - if ( - isIntersectCircleCircle( - viewerPositionScaled, - mapState.labelRadius * mapState.scale, - label.centerPoint, - label.boundingCircleRadius - ) - ) { - label.mesh.update() - } + // Update (sub)scene + MapStateService.setProperty({ activePhase: null }) + } + + // Update labels + if (Math.round(Engine.instance.elapsedSeconds / Engine.instance.fixedDeltaSeconds) % 20 === 0) { + for (const label of mapState.labelCache.value.values()) { + if (label.mesh) { + if ( + isIntersectCircleCircle( + viewerPositionScaled, + mapState.labelRadius.value * mapState.scale.value, + label.centerPoint, + label.boundingCircleRadius + ) + ) { + label.mesh.update() } } } previousViewerEntity = viewerEntity - return world } } + +const MapUpdateSystem = defineSystem({ + uuid: 'ee.map.MapUpdateSystem', + execute +}) + +export default MapUpdateSystem diff --git a/engine/functions/PhaseFunctions.ts b/engine/functions/PhaseFunctions.ts index c9e8838..18200e2 100644 --- a/engine/functions/PhaseFunctions.ts +++ b/engine/functions/PhaseFunctions.ts @@ -1,6 +1,7 @@ +import { isClient } from '@etherealengine/engine/src/common/functions/getEnvironment' + import { TaskStatus } from '../types' import { ICachingPhase, IPhase, ISyncPhase, MapStateUnwrapped } from '../types' -import { isClient } from '@etherealengine/engine/src/common/functions/isClient' // Random Thought: Monads like https://github.com/monet/monet.js/blob/master/docs/FREE.md could be useful here. type FeatureId = 'navigation' @@ -55,11 +56,13 @@ Object.freeze(defaultPhases) Object.freeze(phasesNoNavigation) export async function getPhases(options: { exclude?: FeatureId[] } = {}): Promise[]> { + console.log('GETPHASES-PHASES-CALLED--->') const exclude = options.exclude || [] return Promise.all(exclude.includes('navigation') ? phasesNoNavigation : defaultPhases) } export function resetPhases(state: MapStateUnwrapped, phases: readonly IPhase[]) { + console.log('RESET-PHASES-CALLED--->') for (const phase of phases) { phase.reset(state) } @@ -67,30 +70,32 @@ export function resetPhases(state: MapStateUnwrapped, phases: readonly IPhase[]) { // TODO remove + console.log('START-PHASES-CALLED--->') const results = [] as any[] let result: any + const newState = { ...state } for (const phase of phases) { // console.log("starting phase", phase.name) const keys = phase.getTaskKeys(state) if (phase.isCachingPhase || phase.isAsyncPhase) { - state.activePhase = phase.name + newState.activePhase = phase.name // TODO remove const promises = [] as Promise[] let promise: Promise for (const key of keys) { - const taskStatus = phase.getTaskStatus(state, key) + const taskStatus = phase.getTaskStatus(newState, key) // console.log(`task key: ${key} status: ${taskStatus === TaskStatus.STARTED ? 'started' : 'not started'}`) if (taskStatus === TaskStatus.NOT_STARTED) { // console.log("starting task for", phase.name) if (phase.isAsyncPhase) { - promise = phase.startTask(state, key) + promise = phase.startTask(newState, key) promises.push(promise) } else { - result = (phase as ICachingPhase).execTask(state, key) + result = (phase as ICachingPhase).execTask(newState, key) results.push(result) } - ;(phase as ICachingPhase).setTaskStatus(state, key, TaskStatus.STARTED) + ;(phase as ICachingPhase).setTaskStatus(newState, key, TaskStatus.STARTED) } } results.push(...(await Promise.all(promises))) @@ -98,12 +103,12 @@ export async function startPhases(state: MapStateUnwrapped, phases: readonly IPh for (const key of keys) { // console.log(`task key: ${key}`) // console.log("starting task", phase.name) - result = (phase as ISyncPhase).execTask(state, key) + result = (phase as ISyncPhase).execTask(newState, key) results.push(result) } } - phase.cleanup(state) + phase.cleanup(newState) } - state.activePhase = 'UpdateScene' + newState.activePhase = 'UpdateScene' return results } diff --git a/engine/functions/checkKey.ts b/engine/functions/checkKey.ts index 7a86a4f..9822889 100644 --- a/engine/functions/checkKey.ts +++ b/engine/functions/checkKey.ts @@ -1,6 +1,7 @@ import matches from 'ts-matches' import { FeatureKey, TileKey } from '../types' export default function checkKey(key: FeatureKey | TileKey) { + console.log("CHECKKEY__FN") matches(key) .when(matches.tuple(matches.number, matches.number), () => {}) .when(matches.tuple(matches.string, matches.number, matches.number, matches.string), () => {}) diff --git a/engine/functions/computePolygonDifference.ts b/engine/functions/computePolygonDifference.ts index c12d29d..39dee1c 100644 --- a/engine/functions/computePolygonDifference.ts +++ b/engine/functions/computePolygonDifference.ts @@ -14,6 +14,7 @@ function roundEach(array: any[]) { } export default function computePolygonDifference(subjectGeometry: Polygon, ...clippingGeometries: Polygon[]) { + console.log("COMPUTEPOLYGONDIFF__FN") // Quick and dirty fix for polygon-clipping's floating point woes roundEach(clippingGeometries) return pc.difference([subjectGeometry], ...clippingGeometries) diff --git a/engine/functions/computeSquaredDistanceFromCircle.ts b/engine/functions/computeSquaredDistanceFromCircle.ts index 525fef1..be37132 100644 --- a/engine/functions/computeSquaredDistanceFromCircle.ts +++ b/engine/functions/computeSquaredDistanceFromCircle.ts @@ -1,7 +1,9 @@ export default function computeDistanceFromCircle( + point: [number, number], circleCenter: [number, number], circleRadius: number ) { + console.log("COMPUTEPSQUAREDIST__FN"); return Math.hypot(point[0] - circleCenter[0], point[1] - circleCenter[1]) - circleRadius } diff --git a/engine/functions/computeTileBoundingBox.ts b/engine/functions/computeTileBoundingBox.ts index 2e8a698..9f8e0e1 100644 --- a/engine/functions/computeTileBoundingBox.ts +++ b/engine/functions/computeTileBoundingBox.ts @@ -10,6 +10,7 @@ export default function computeTileBoundingBox( center: LongLat, target: BBox = Array(4) as any ): BBox { + console.log("COMPUTETILEBOUNDING__FN"); toMetersFromCenter([tileXToLong(x, TILE_ZOOM), tileYToLat(y, TILE_ZOOM)], center, $array2) const [x1, y1] = $array2 diff --git a/engine/functions/createCompleteObject.ts b/engine/functions/createCompleteObject.ts index 168f0b2..3a43b38 100644 --- a/engine/functions/createCompleteObject.ts +++ b/engine/functions/createCompleteObject.ts @@ -8,6 +8,7 @@ export default function createCompleteObject( geometryPhaseResult: MapDerivedFeatureGeometry, feature: SupportedFeature ): MapDerivedFeatureComplete { + console.log("CREATECOMPLETEOBJECT__FN"); const { color, extrude, zIndex = 0 } = getFeatureStyles(DEFAULT_FEATURE_STYLES, layerName, feature.properties.class) const materialParams = { diff --git a/engine/functions/createFeatureLabel.ts b/engine/functions/createFeatureLabel.ts index 2596d8d..5aa2a3f 100644 --- a/engine/functions/createFeatureLabel.ts +++ b/engine/functions/createFeatureLabel.ts @@ -37,7 +37,7 @@ function createText(textString: string): Text3D { const $cameraDirection = new Vector3() function createUpdateClosure(mesh: Text3D, middleSlice: Position[]) { return function updateFeatureLabel() { - const camera = Engine.camera + const camera = Engine.instance.camera const [[x1, y1]] = middleSlice const [x2, y2] = middleSlice[middleSlice.length - 1] @@ -53,7 +53,7 @@ function createUpdateClosure(mesh: Text3D, middleSlice: Position[]) { ) mesh.rotateX(-Math.PI / 2) - mesh.fontSize = Math.min(Math.max(Engine.camera.position.y / 4, MINIMUM_FONT_SIZE), MAXIMUM_FONT_SIZE) + mesh.fontSize = Math.min(Math.max(Engine.instance.camera.position.y / 4, MINIMUM_FONT_SIZE), MAXIMUM_FONT_SIZE) mesh.sync() } @@ -64,6 +64,7 @@ export default function createFeatureLabel( lineString: Feature, mapCenterPoint: LongLat ): MapFeatureLabel { + console.log("CREATEFEATURELABEL__FN"); const lineLen = turf.length(lineString) const middleSlice = turf.lineSliceAlong(lineString, lineLen * 0.48, lineLen * 0.52).geometry.coordinates diff --git a/engine/functions/createGeometry.ts b/engine/functions/createGeometry.ts index 7216d13..f1c5721 100644 --- a/engine/functions/createGeometry.ts +++ b/engine/functions/createGeometry.ts @@ -22,13 +22,13 @@ function getBuildingColor(feature: SupportedFeature) { } function colorVertices(geometry: BufferGeometry, baseColor: Color, light: Color, shadow: Color) { - const normals = geometry.attributes.normal + const normals = geometry.attributes.normal as BufferAttribute const topColor = baseColor.clone().multiply(light) const bottomColor = baseColor.clone().multiply(shadow) geometry.setAttribute('color', new BufferAttribute(new Float32Array(normals.count * 3), 3)) - const colors = geometry.attributes.color + const colors = geometry.attributes.color as BufferAttribute geometry.computeVertexNormals() geometry.computeBoundingBox() @@ -43,6 +43,7 @@ function colorVertices(geometry: BufferGeometry, baseColor: Color, light: Color, } export default function createGeometry(feature: SupportedFeature, style: IStyles): BufferGeometry { + console.log("CREATEGEOMETRY__FN"); const shape = new Shape() let coords: LongLat[] diff --git a/engine/functions/createIntersectionTestTileCircle.ts b/engine/functions/createIntersectionTestTileCircle.ts index cc83038..88699a1 100644 --- a/engine/functions/createIntersectionTestTileCircle.ts +++ b/engine/functions/createIntersectionTestTileCircle.ts @@ -1,5 +1,7 @@ export default function createIntersectTestTileCircle(centerX: number, centerY: number, radius: number) { + console.log("CREATEINTERESECT__FN"); return function isIntersectTileCircle(cellX: number, cellY: number): boolean { + const testEdgeX = centerX < cellX ? cellX : centerX > cellX + 1 ? cellX + 1 : centerX const testEdgeY = centerY < cellY ? cellY : centerY > cellY + 1 ? cellY + 1 : centerY const distanceFromCenter = Math.hypot(testEdgeX - centerX, testEdgeY - centerY) diff --git a/engine/functions/createSurroundingTileIterator.ts b/engine/functions/createSurroundingTileIterator.ts index 4b87465..5e2693b 100644 --- a/engine/functions/createSurroundingTileIterator.ts +++ b/engine/functions/createSurroundingTileIterator.ts @@ -12,6 +12,7 @@ export default function* createSurroundingTileIterator( minimumSceneRadius: number, zoomLevel: number ): Generator { + console.log("CREATESURROUNDING__FN"); const [startLong, startLat] = fromMetersFromCenter([-minimumSceneRadius, -minimumSceneRadius], center) const [endLong, endLat] = fromMetersFromCenter([minimumSceneRadius, minimumSceneRadius], center) diff --git a/engine/functions/createUsingCache.ts b/engine/functions/createUsingCache.ts index 59c0ed2..2967b72 100644 --- a/engine/functions/createUsingCache.ts +++ b/engine/functions/createUsingCache.ts @@ -4,6 +4,7 @@ import createUsingGetSet from './createUsingGetSet' export default function createUsingCache( create: (state: MapStateUnwrapped, key: CacheKey, ...extraArgs: any[]) => Value ) { + console.log("CREATEUSINGCACHE__FN"); const _createUsingCache = createUsingGetSet(create) return (cache: IParametricMap, state: MapStateUnwrapped, key: CacheKey, ...extraArgs: any[]) => { return _createUsingCache(cache.get.bind(cache), cache.set.bind(cache), state, key, ...extraArgs) diff --git a/engine/functions/createUsingGetSet.ts b/engine/functions/createUsingGetSet.ts index 7f4fd28..9087420 100644 --- a/engine/functions/createUsingGetSet.ts +++ b/engine/functions/createUsingGetSet.ts @@ -3,6 +3,7 @@ import { ITuple, MapStateUnwrapped } from '../types' export default function createUsingGetSet( create: (state: MapStateUnwrapped, key: CacheKey, ...args: any[]) => Value ) { + console.log("CREATEUSINGGETSET__FN"); return ( get: (key: CacheKey) => Value, set: (key: CacheKey, value: Value) => any, diff --git a/engine/functions/createWorkerFunction.ts b/engine/functions/createWorkerFunction.ts index f5cf6fb..8cdf1d4 100644 --- a/engine/functions/createWorkerFunction.ts +++ b/engine/functions/createWorkerFunction.ts @@ -8,7 +8,7 @@ export default function createWorkerFunction< worker: Worker ): (...args: { [I in keyof HandlerArgs]: Comlink.UnproxyOrClone }) => Promise { const api = Comlink.wrap(worker) - + console.log("CREATEWORKER__FN"); return async function workerFunction(...args: { [I in keyof HandlerArgs]: Comlink.UnproxyOrClone }) { return (await api.handle(...args)) as Promise } diff --git a/engine/functions/fetchUsingCache.ts b/engine/functions/fetchUsingCache.ts index 7f7e411..ca33424 100644 --- a/engine/functions/fetchUsingCache.ts +++ b/engine/functions/fetchUsingCache.ts @@ -3,8 +3,9 @@ import { ITuple, MapStateUnwrapped } from '../types' import createUsingGetSet from './createUsingGetSet' export default function fetchUsingCache( - fetch: (state: MapStateUnwrapped, key: CacheKey, ...args: any[]) => Promise + fetch: (state: MapStateUnwrapped, key: CacheKey, ...args: any[]) => Value ) { + console.log("FETCHCACHE__FN"); const _fetchUsingCache = createUsingGetSet(fetch) return async ( cache: ParametricCache, @@ -14,7 +15,7 @@ export default function fetchUsingCache( ) => { return await _fetchUsingCache( cache.get.bind(cache), - async function set(key: CacheKey, value: Promise) { + async function set(key: CacheKey, value: Value) { const resolvedValue = await value cache.set(key, resolvedValue) }, @@ -24,3 +25,21 @@ export default function fetchUsingCache( ) } } + +export function fetchUsingCacheAsync( + fetch: (state: MapStateUnwrapped, key: CacheKey, ...args: any[]) => Promise +) { + return async ( + cache: ParametricCache, + state: MapStateUnwrapped, + key: CacheKey, + ...extraArgs: any[] + ) => { + let value = cache.get(key) + if (!value) { + value = await fetch(state, key, ...extraArgs) + cache.set(key, value) + } + return value + } +} diff --git a/engine/functions/fetchVectorTile.ts b/engine/functions/fetchVectorTile.ts index 587b0e8..2813512 100644 --- a/engine/functions/fetchVectorTile.ts +++ b/engine/functions/fetchVectorTile.ts @@ -4,7 +4,7 @@ import { VectorTile } from '../types' import { vectors } from '../vectors' import getMapboxUrl from './getMapboxUrl' -export default async function fetchVectorTile(_: any, key: TileKey): Promise { +export default async function fetchVectorTile(_: any, key: TileKey): Promise { console.log("GETCHVECTOR__FN"); const [x, y] = key const url = getMapboxUrl( 'mapbox.mapbox-streets-v8', diff --git a/engine/functions/findSplitFeatures.ts b/engine/functions/findSplitFeatures.ts index dbb2e3f..a94d56f 100644 --- a/engine/functions/findSplitFeatures.ts +++ b/engine/functions/findSplitFeatures.ts @@ -7,12 +7,18 @@ type GroupKey = Feature['id'] type Group = [FeatureKey, Feature][] /** Useful for when a feature is split across multiple vector tiles */ + export default function* findSplitFeatures(keys: Iterator, features: Iterator): Generator { + console.log("FINDSPLIT__FN"); const zipped = zipIterators<[FeatureKey, Feature]>(keys, features) const groups = new Map() + const groupSetFunction = (groupKey: GroupKey, groupValue: Group) => { + groups.set(groupKey, groupValue) + return groupValue + } const addToGroup = updateKeyVal( groups.get.bind(groups), - groups.set.bind(groups), + groupSetFunction, (group: Group, newKey: FeatureKey, newFeature: Feature) => { return [...group, [newKey, newFeature]] }, diff --git a/engine/functions/getCachedMaterial.ts b/engine/functions/getCachedMaterial.ts index b9942f0..4f04f9e 100644 --- a/engine/functions/getCachedMaterial.ts +++ b/engine/functions/getCachedMaterial.ts @@ -6,6 +6,7 @@ const cache = new Map() // TODO re-implement using createUsingGetSet // TODO generalize this so it'll work even if params contain Textures export default function getCachedMaterial(Material: any, params: MeshLambertMaterialParameters): MeshLambertMaterial { + console.log("GETCACHED__FN"); const key = JSON.stringify(params) let material = cache.get(key) diff --git a/engine/functions/getFeaturesFromVectorTileLayer.ts b/engine/functions/getFeaturesFromVectorTileLayer.ts index 14272bf..1e89bcb 100644 --- a/engine/functions/getFeaturesFromVectorTileLayer.ts +++ b/engine/functions/getFeaturesFromVectorTileLayer.ts @@ -8,6 +8,7 @@ export default function* getFeaturesFromVectorTileLayer( y: number, zoom: number ): Generator { + console.log("GETFEATURES__FN"); const layer = tile.layers[layerName] for (let tileIndex = 0; tileIndex < layer.length; tileIndex++) { const feature = layer.feature(tileIndex).toGeoJSON(x, y, zoom) diff --git a/engine/functions/getMapboxUrl.ts b/engine/functions/getMapboxUrl.ts index c8209a4..191e1f3 100644 --- a/engine/functions/getMapboxUrl.ts +++ b/engine/functions/getMapboxUrl.ts @@ -7,9 +7,10 @@ export default function getMapboxUrl( tileY: number, tileZoom: number, format: string, - apiKey: string, + apiKey: "", highDpi = false ) { + console.log("GETMAPBOX__FN"); return `https://api.mapbox.com/v4/${layerId}/${tileZoom}/${tileX}/${tileY}${ highDpi ? '@2x' : '' }.${format}?access_token=${apiKey}` diff --git a/engine/functions/isIntersectCircleCircle.ts b/engine/functions/isIntersectCircleCircle.ts index d2d5523..d250104 100644 --- a/engine/functions/isIntersectCircleCircle.ts +++ b/engine/functions/isIntersectCircleCircle.ts @@ -6,6 +6,7 @@ export default function isIntersectCircleCircle( centerPointB: [number, number], radiusB: number ): boolean { + console.log("ISINTERSECT__FN"); const distanceSquared = computeSquared(centerPointA, centerPointB, radiusB) return distanceSquared < radiusA * radiusA } diff --git a/engine/functions/tesselatePolygon.ts b/engine/functions/tesselatePolygon.ts index 3d3bb94..2a031ea 100644 --- a/engine/functions/tesselatePolygon.ts +++ b/engine/functions/tesselatePolygon.ts @@ -19,6 +19,7 @@ export function indexedVerticesToGeoJSONTriangles(indexes: number[], vertices: n } export default function tesselatePolygon(polygon: Polygon) { + console.log("tesselatePolygon__FN"); const { vertices, holes } = earcut.flatten(polygon) const indexes = earcut(vertices, holes, 2) return indexedVerticesToGeoJSONTriangles(indexes, vertices) diff --git a/engine/functions/transformFeature.ts b/engine/functions/transformFeature.ts index d9f87af..ea0bc87 100644 --- a/engine/functions/transformFeature.ts +++ b/engine/functions/transformFeature.ts @@ -34,6 +34,7 @@ export default function transformFeature( feature: FeatureType, center: LongLat ): MapTransformedFeature { + console.log("transformFeature__FN"); const centerPointLongLat = turf.center(feature).geometry.coordinates const centerPoint = toMetersFromCenter(centerPointLongLat, center) as [number, number] let transformedFeature = feature diff --git a/engine/functions/transformGeometry.ts b/engine/functions/transformGeometry.ts index ad7ec34..e62d5f0 100644 --- a/engine/functions/transformGeometry.ts +++ b/engine/functions/transformGeometry.ts @@ -18,6 +18,7 @@ export default function transformGeometry) { + console.log("unifyCACHE__FN"); for (const splitFeature of findSplitFeatures(cache.keys(), cache.values())) { const firstKey = splitFeature[0][0] const features = splitFeature.map(([_, feature]) => feature) diff --git a/engine/functions/unifyFeatures.ts b/engine/functions/unifyFeatures.ts index a8184ef..28edddf 100644 --- a/engine/functions/unifyFeatures.ts +++ b/engine/functions/unifyFeatures.ts @@ -4,6 +4,7 @@ import { multiPolygon, polygon } from '@turf/turf' /** Useful for when a feature is split across multiple vector tiles */ export default function unifyFeatures(features: Feature[]): Feature { + console.log("unifyFeature__FN"); if (features.length > 1) { const allCoords = features.map(getCoords) diff --git a/engine/helpers/NavMeshComponent.ts b/engine/helpers/NavMeshComponent.ts new file mode 100644 index 0000000..a38829c --- /dev/null +++ b/engine/helpers/NavMeshComponent.ts @@ -0,0 +1,11 @@ +import { Object3D } from 'three' +import { NavMesh } from 'yuka' + +import { createMappedComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions' + +export type NavMeshComponentType = { + yukaNavMesh?: NavMesh + navTarget: Object3D +} + +export const NavMeshComponent = createMappedComponent('NavMeshComponent') \ No newline at end of file diff --git a/engine/helpers/PolygonHelpers.ts b/engine/helpers/PolygonHelpers.ts index ea61000..3fe031b 100644 --- a/engine/helpers/PolygonHelpers.ts +++ b/engine/helpers/PolygonHelpers.ts @@ -6,7 +6,7 @@ import { MeshBasicMaterial, Mesh, Shape, - ShapeBufferGeometry, + ShapeGeometry, Path } from 'three' @@ -34,7 +34,7 @@ export function createPolygonHelper(polygon: Polygon): Mesh { shape.holes[innerRingIndex - 1] = path } - const geometry = new ShapeBufferGeometry(shape) + const geometry = new ShapeGeometry(shape) const material = new MeshBasicMaterial({ color }) geometry.rotateX(-Math.PI / 2) diff --git a/engine/phases/CreateCompleteNavMeshPhase.ts b/engine/phases/CreateCompleteNavMeshPhase.ts index 83e9d0c..ea70a00 100644 --- a/engine/phases/CreateCompleteNavMeshPhase.ts +++ b/engine/phases/CreateCompleteNavMeshPhase.ts @@ -8,10 +8,12 @@ export const isCachingPhase = false const builder = new NavMeshBuilder() export function getTaskKeys(_: MapStateUnwrapped) { + console.log('CreateCompleteNavMesh-PHASE-CALLED--->') return [null] } export function execTask(state: MapStateUnwrapped, _: TileKey) { + console.log('CreateCompleteNavMesh-PHASE-CALLED_2--->') for (const value of state.tileNavMeshCache.values()) { builder.addGeometry({ type: 'MultiPolygon', coordinates: value }) } diff --git a/engine/phases/CreateCompleteObjectPhase.ts b/engine/phases/CreateCompleteObjectPhase.ts index e5708d1..8ecfa9c 100644 --- a/engine/phases/CreateCompleteObjectPhase.ts +++ b/engine/phases/CreateCompleteObjectPhase.ts @@ -7,6 +7,7 @@ export const isAsyncPhase = false export const isCachingPhase = true const createCompleteObjectUsingCache = createUsingCache((state: MapStateUnwrapped, key: FeatureKey) => { + console.log('CreateCompleteObjectPhase--->') const [layerName] = key const feature = state.featureCache.get(key) @@ -16,6 +17,7 @@ const createCompleteObjectUsingCache = createUsingCache((state: MapStateUnwrappe }) export function* getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateCompleteObjectPhase_2--->') for (const key of state.featureCache.keys()) { const geometry = state.geometryCache.get(key) if (geometry) { @@ -25,6 +27,7 @@ export function* getTaskKeys(state: MapStateUnwrapped) { } export function getTaskStatus(state: MapStateUnwrapped, key: FeatureKey) { + console.log('CreateCompleteObjectPhase_3--->') return state.completeObjectsTasks.get(key) } export function setTaskStatus(state: MapStateUnwrapped, key: FeatureKey, status: TaskStatus) { @@ -32,6 +35,7 @@ export function setTaskStatus(state: MapStateUnwrapped, key: FeatureKey, status: } export function execTask(state: MapStateUnwrapped, key: FeatureKey) { + console.log('CreateCompleteObjectPhase--->') return createCompleteObjectUsingCache(state.completeObjects, state, key) } diff --git a/engine/phases/CreateFallbackLanduseMeshPhase.ts b/engine/phases/CreateFallbackLanduseMeshPhase.ts index 8efd3cd..a8da103 100644 --- a/engine/phases/CreateFallbackLanduseMeshPhase.ts +++ b/engine/phases/CreateFallbackLanduseMeshPhase.ts @@ -1,7 +1,7 @@ import { TileKey, MapStateUnwrapped } from '../types' import { DEFAULT_FEATURE_STYLES, getFeatureStyles, MAX_Z_INDEX } from '../styles' import getCachedMaterial from '../functions/getCachedMaterial' -import { Mesh, MeshLambertMaterial, PlaneBufferGeometry } from 'three' +import { Mesh, MeshLambertMaterial, PlaneGeometry } from 'three' import computeTileBoundingBox from '../functions/computeTileBoundingBox' import FeatureKey from '../classes/FeatureKey' @@ -10,12 +10,14 @@ export const isAsyncPhase = false export const isCachingPhase = false export function getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateFallbackLand--->') return state.tileCache.keys() } const $tileBBox = Array(4) export function execTask(state: MapStateUnwrapped, key: TileKey) { + console.log('CreateFallbackLand_1--->') const [x, y] = key const [tileLeft, tileTop, tileRight, tileBottom] = computeTileBoundingBox( @@ -33,7 +35,7 @@ export function execTask(state: MapStateUnwrapped, key: TileKey) { const material = getCachedMaterial(MeshLambertMaterial, { color, depthTest: false }) - const geometry = new PlaneBufferGeometry(tileWidth, tileHeight) + const geometry = new PlaneGeometry(tileWidth, tileHeight) geometry.rotateX(-Math.PI / 2) const mesh = new Mesh(geometry, material) diff --git a/engine/phases/CreateGeometryPhase.ts b/engine/phases/CreateGeometryPhase.ts index ed70c5a..ab09f78 100644 --- a/engine/phases/CreateGeometryPhase.ts +++ b/engine/phases/CreateGeometryPhase.ts @@ -3,21 +3,21 @@ import fetchUsingCache from '../functions/fetchUsingCache' import isIntersectCircleCircle from '../functions/isIntersectCircleCircle' import { FeatureKey, TaskStatus, MapStateUnwrapped } from '../types' import { multiplyArray } from '../util' -// @ts-ignore -import createGeometryWorker from '../workers/geometryWorker.ts?worker' import { WorkerApi } from '../workers/geometryWorker' import { DEFAULT_FEATURE_STYLES, getFeatureStyles } from '../styles' import { BufferGeometryLoader } from 'three' import { getHumanFriendlyFeatureKey } from '../helpers/KeyHelpers' +import { createWorkerFromCrossOriginURL } from '@etherealengine/common/src/utils/createWorkerFromCrossOriginURL' const $array2 = Array(2) -const createGeometry = createWorkerFunction(createGeometryWorker()) +const createGeometry = createWorkerFunction(createWorkerFromCrossOriginURL(new URL('../workers/geometryWorker.ts', import.meta.url).href, true, {name: "Geometry Worker"})) const geometryLoader = new BufferGeometryLoader() /** using fetchUsingCache since createGeometry returns a promise */ const createGeometryUsingCache = fetchUsingCache(async (state: MapStateUnwrapped, key: FeatureKey) => { + console.log('CreateGeometryPhase--->') const { feature, centerPoint, boundingCircleRadius } = state.transformedFeatureCache.get(key) const [layerName] = key const styles = getFeatureStyles(DEFAULT_FEATURE_STYLES, layerName, feature.properties.class) @@ -45,6 +45,7 @@ export const isAsyncPhase = true export const isCachingPhase = true export function* getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateGeometryPhase_2--->') const viewerPositionScaled = multiplyArray(state.viewerPosition, 1 / state.scale, $array2) as [number, number] for (const key of state.transformedFeatureCache.keys()) { const { centerPoint, boundingCircleRadius } = state.transformedFeatureCache.get(key) @@ -63,7 +64,8 @@ export function setTaskStatus(state: MapStateUnwrapped, key: FeatureKey, status: } export function startTask(state: MapStateUnwrapped, key: FeatureKey) { - return createGeometryUsingCache(state.geometryCache, state, key) + console.log('CreateGeometryPhase_3--->') + return createGeometryUsingCache(state.geometryCache as any, state, key) } export function cleanup(state: MapStateUnwrapped) { diff --git a/engine/phases/CreateHelpersPhase.ts b/engine/phases/CreateHelpersPhase.ts index 6d34d24..742225b 100644 --- a/engine/phases/CreateHelpersPhase.ts +++ b/engine/phases/CreateHelpersPhase.ts @@ -7,6 +7,7 @@ export const isAsyncPhase = false export const isCachingPhase = true const createHelpersUsingCache = createUsingCache((state: MapStateUnwrapped, key: TileKey) => { + console.log('CreateHelpersUsingCache--->') const polygons = state.tileNavMeshCache.get(key) // const tileNavMesh = createPolygonHelper(polygons[0]) const tileNavMesh = createConvexMultiPolygonHelper(polygons) @@ -17,6 +18,7 @@ const createHelpersUsingCache = createUsingCache((state: MapStateUnwrapped, key: }) export function getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateHelpersUsingCache_2--->') return state.tileNavMeshCache.keys() } @@ -28,6 +30,7 @@ export function setTaskStatus(state: MapStateUnwrapped, key: TileKey, status: Ta } export function execTask(state: MapStateUnwrapped, key: TileKey) { + console.log('CreateHelpersUsingCache_3--->') return createHelpersUsingCache(state.helpersCache, state, key) } diff --git a/engine/phases/CreateLabelPhase.ts b/engine/phases/CreateLabelPhase.ts index 8efc1b3..8715a0c 100644 --- a/engine/phases/CreateLabelPhase.ts +++ b/engine/phases/CreateLabelPhase.ts @@ -8,6 +8,7 @@ export const isAsyncPhase = false export const isCachingPhase = true export function* getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateLabelPhase--->') for (const key of state.completeObjects.keys()) { const feature = state.featureCache.get(key) const transformed = state.transformedFeatureCache.get(key) @@ -38,6 +39,7 @@ const createLabelUsingCache = createUsingCache((state: MapStateUnwrapped, key: F }) export function execTask(state: MapStateUnwrapped, key: FeatureKey) { + console.log('CreateLabelPhase_2--->') return createLabelUsingCache(state.labelCache, state, key) } diff --git a/engine/phases/CreateTileNavMeshPhase.ts b/engine/phases/CreateTileNavMeshPhase.ts index 0217d62..9a08356 100644 --- a/engine/phases/CreateTileNavMeshPhase.ts +++ b/engine/phases/CreateTileNavMeshPhase.ts @@ -82,6 +82,7 @@ const createNavMeshUsingCache = createUsingCache((state: MapStateUnwrapped, key: }) export function getTaskKeys(state: MapStateUnwrapped) { + console.log('CreateNavMeshPhase--->') return createSurroundingTileIterator(state.center, state.navMeshRadius, TILE_ZOOM) } @@ -93,6 +94,7 @@ export function setTaskStatus(state: MapStateUnwrapped, key: TileKey, status: Ta } export function execTask(state: MapStateUnwrapped, key: TileKey) { + console.log('CreateNavMeshPhase_2--->') return createNavMeshUsingCache(state.tileNavMeshCache, state, key) } diff --git a/engine/phases/ExtractTileFeaturesPhase.ts b/engine/phases/ExtractTileFeaturesPhase.ts index c1aec5a..9d3f591 100644 --- a/engine/phases/ExtractTileFeaturesPhase.ts +++ b/engine/phases/ExtractTileFeaturesPhase.ts @@ -9,6 +9,7 @@ export const isAsyncPhase = false export const isCachingPhase = true export function getTaskKeys(state: MapStateUnwrapped) { + console.log('ExtractTileFeaturesPhase--->') console.log('tileCache size', state.tileCache.size) return state.tileCache.keys() } @@ -21,6 +22,7 @@ export function setTaskStatus(state: MapStateUnwrapped, key: TileKey, status: Ta } export function execTask(state: MapStateUnwrapped, tileKey: TileKey) { + console.log('ExtractTileFeaturesPhase_2--->') const vectorTile = state.tileCache.get(tileKey) const [x, y] = tileKey if (vectorTile) { diff --git a/engine/phases/FetchTilesPhase.ts b/engine/phases/FetchTilesPhase.ts index a6469e3..412b484 100644 --- a/engine/phases/FetchTilesPhase.ts +++ b/engine/phases/FetchTilesPhase.ts @@ -1,17 +1,18 @@ -import { MapStateUnwrapped, TaskStatus, TileKey } from '../types' -import { VectorTile } from '../types' -import createSurroundingTileIterator from '../functions/createSurroundingTileIterator' import { TILE_ZOOM } from '../constants' -import fetchUsingCache from '../functions/fetchUsingCache' +import createSurroundingTileIterator from '../functions/createSurroundingTileIterator' +import { fetchUsingCacheAsync } from '../functions/fetchUsingCache' import fetchVectorTile from '../functions/fetchVectorTile' +import { MapStateUnwrapped, TaskStatus, TileKey } from '../types' +import { VectorTile } from '../types' -const fetchVectorTileUsingCache = fetchUsingCache(fetchVectorTile) +const fetchVectorTileUsingCache = fetchUsingCacheAsync(fetchVectorTile) export const name = 'FetchTiles' export const isAsyncPhase = true export const isCachingPhase = true export function getTaskKeys(state: MapStateUnwrapped) { + console.log('FetchVector--->') return createSurroundingTileIterator(state.center, state.minimumSceneRadius, TILE_ZOOM) } @@ -23,6 +24,7 @@ export function setTaskStatus(state: MapStateUnwrapped, key: TileKey, status: Ta } export function startTask(state: MapStateUnwrapped, key: TileKey) { + console.log('FetchVector_2--->') return fetchVectorTileUsingCache(state.tileCache, state, key) } diff --git a/engine/phases/TransformFeaturePhase.ts b/engine/phases/TransformFeaturePhase.ts index 87fe992..491d248 100644 --- a/engine/phases/TransformFeaturePhase.ts +++ b/engine/phases/TransformFeaturePhase.ts @@ -1,11 +1,10 @@ import { MapStateUnwrapped, FeatureKey, TaskStatus } from '../types' import fetchUsingCache from '../functions/fetchUsingCache' -// @ts-ignore -import createWorker from '../workers/transformFeatureWorker.ts?worker' import { WorkerApi } from '../workers/transformFeatureWorker' import createWorkerFunction from '../functions/createWorkerFunction' +import { createWorkerFromCrossOriginURL } from '@etherealengine/common/src/utils/createWorkerFromCrossOriginURL' -const transformFeature = createWorkerFunction(createWorker()) +const transformFeature = createWorkerFunction(createWorkerFromCrossOriginURL(new URL('../workers/transformFeatureWorker.ts', import.meta.url).href, true, {name: 'Transform Feature Worker'})) export const name = 'TransformFeature' export const isAsyncPhase = true @@ -23,6 +22,7 @@ const transformFeatureUsingCache = fetchUsingCache((state: MapStateUnwrapped, ke }) export function getTaskKeys(state: MapStateUnwrapped) { + console.log('TransformPhase--->') return state.featureCache.keys() } @@ -34,7 +34,8 @@ export function setTaskStatus(state: MapStateUnwrapped, key: FeatureKey, status: } export function startTask(state: MapStateUnwrapped, key: FeatureKey) { - return transformFeatureUsingCache(state.transformedFeatureCache, state, key) + console.log('TransformPhase_2--->') + return transformFeatureUsingCache(state.transformedFeatureCache as any, state, key) } export function cleanup(state: MapStateUnwrapped) { diff --git a/engine/phases/UnifyFeaturesPhase.ts b/engine/phases/UnifyFeaturesPhase.ts index 4e7b008..882fa06 100644 --- a/engine/phases/UnifyFeaturesPhase.ts +++ b/engine/phases/UnifyFeaturesPhase.ts @@ -6,10 +6,12 @@ export const isAsyncPhase = false export const isCachingPhase = false export function* getTaskKeys() { + console.log('UnifyFeatures--->') yield null } export function execTask(state: MapStateUnwrapped) { + console.log('UnifyFeatures_2--->') unifyCachedFeatures(state.featureCache) } diff --git a/engine/types.ts b/engine/types.ts index 01898a2..b77541c 100644 --- a/engine/types.ts +++ b/engine/types.ts @@ -1,10 +1,12 @@ import { Feature, LineString, MultiLineString, MultiPolygon, Polygon } from 'geojson' import { BufferGeometry, InstancedBufferGeometry, Mesh } from 'three' -import { _MapStateUnwrapped } from './MapReceptor' +import type _FeatureKey from './classes/FeatureKey' import type _TileKey from './classes/TileKey' +import { MapState } from './MapReceptor' + export type TileKey = _TileKey -import type _FeatureKey from './classes/FeatureKey' + export type FeatureKey = _FeatureKey export interface ITuple { @@ -33,7 +35,7 @@ export interface IParametricMap { size: number } -export type MapStateUnwrapped = _MapStateUnwrapped +export type MapStateUnwrapped = typeof MapState._TYPE /** * @fileoverview a place for all types that are shared by multiple modules but not conceptually owned by any diff --git a/engine/workers/geometryWorker.ts b/engine/workers/geometryWorker.ts index fa03098..c44ab23 100644 --- a/engine/workers/geometryWorker.ts +++ b/engine/workers/geometryWorker.ts @@ -1,4 +1,5 @@ import * as Comlink from 'comlink' +import { BufferAttribute } from 'three' import createGeometry from '../functions/createGeometry' import { IStyles } from '../styles' import { SupportedFeature } from '../types' @@ -26,7 +27,7 @@ function createGeometryInWorker(feature: SupportedFeature, style: IStyles) { const attributes = {} for (let attributeName of Object.keys(geometry.attributes)) { - const attribute = geometry.getAttribute(attributeName) + const attribute = geometry.getAttribute(attributeName) as BufferAttribute const array = attribute.array as Float32Array Comlink.transfer(array, [array.buffer]) attributes[attributeName] = { diff --git a/package.json b/package.json index 2fad23e..f934042 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "scripts": { "test": "exit 0" }, - "peerDependencies": {}, "dependencies": { "@mapbox/vector-tile": "^1.3.1", "@turf/turf": "^6.5.0", @@ -18,10 +17,11 @@ "troika-three-text": "^0.44.0" }, "devDependencies": { - "mocha": "9.1.3", - "earcut": "^2.2.3", "@types/earcut": "2.1.1", "@types/geojson": "7946.0.8", + "@types/yuka": "^0.7.1", + "earcut": "^2.2.3", + "mocha": "9.1.3", "trace-unhandled": "2.0.1" }, "license": "ISC" diff --git a/tsconfig.json b/tsconfig.json index b621634..dd1aaa3 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "noEmit": true, - "module": "CommonJS", + "module": "ES2020", "strict": false, "strictNullChecks": true, "strictBindCallApply": true, diff --git a/worldInjection.ts b/worldInjection.ts index f7b9228..8eb6802 100644 --- a/worldInjection.ts +++ b/worldInjection.ts @@ -1,25 +1,29 @@ +import { prefabIcons } from '@etherealengine/editor/src/functions/PrefabEditors' +import { EntityNodeEditor } from '@etherealengine/editor/src/functions/PrefabEditors' +import { isClient } from '@etherealengine/engine/src/common/functions/getEnvironment' +import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine' +import { InputSystemGroup } from '@etherealengine/engine/src/ecs/functions/EngineFunctions' +import { startSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions' +import { defaultSpatialComponents } from '@etherealengine/engine/src/scene/systems/SceneObjectUpdateSystem' -import { World } from '@etherealengine/engine/src/ecs/classes/World' -import { deserializeMap, SCENE_COMPONENT_MAP, SCENE_COMPONENT_MAP_DEFAULT_VALUES, serializeMap, updateMap } from './engine/MapFunctions' -import { defaultSpatialComponents } from '@etherealengine/engine/src/scene/functions/registerPrefabs' -import { isNode } from '@etherealengine/engine/src/common/functions/getEnvironment' +import MapIcon from '@mui/icons-material/Map' -export const map = 'Geo Map' as const +import { MapNodeEditor } from './editor/MapNodeEditor' +import { MapComponent } from './engine/MapComponent' +import { _updateMap, SCENE_COMPONENT_MAP, SCENE_COMPONENT_MAP_DEFAULT_VALUES } from './engine/MapFunctions' +import MapUpdateSystem from './engine/MapUpdateSystem' -export default async (world: World) => { +export const GEO_MAP = 'Geo Map' as const - if(!isNode) { - (await import('./editor/index')).default(world) +export default async () => { + if (isClient) { + EntityNodeEditor.set(MapComponent, MapNodeEditor) + prefabIcons[GEO_MAP] = MapIcon + startSystem(MapUpdateSystem, { after: InputSystemGroup }) } - world.scenePrefabRegistry.set(map, [ + Engine.instance.scenePrefabRegistry.set(GEO_MAP, [ ...defaultSpatialComponents, { name: SCENE_COMPONENT_MAP, props: SCENE_COMPONENT_MAP_DEFAULT_VALUES } ]) - - world.sceneLoadingRegistry.set(SCENE_COMPONENT_MAP, { - deserialize: deserializeMap, - serialize: serializeMap, - update: updateMap - }) }