Errors only appearing on my laptop

Hello,

I am a strange situation in which our project is only crashing on my laptop, no one elses on our team. This effects both the ability to run the game from within studio, the simulator, and the generated QR codes. I have restarted my computer, cleared caches/cookies and more, tried a different browser, and even created a new 8th wall account to test the project from but it does not work. We have verified multiple times that I am on the same version as everyone else and have made sure I have abandoned all local changes. I have attached some screenshots.


The errors are always these two same ones:
Uncaught Error: Cannot get component data if not attached.
Unhandled promise rejection: Error: Cannot get component data if not attached.

Tracing back the commits, they start for me after this version of the project:
bde8813 12-14-2024 Ben: Begin manager component, start moving global state to it. Create animation helper

I am lost! Thank you for your help :pray:

Can you share your UFO component? Seems like that’s where the error is coming from. :open_mouth:

This magically stopped happening but then started again like 45min ago.

Here is the code for ufo.ts

Thank you!

import * as ecs from '@8thwall/ecs'
import {UFOAnimations, CowAnimations, getRandomOffset} from './helpers/animations'
import {cloneComponents} from './helpers/clone'
import {getRandInt} from './helpers/math'
import {addCleanup, doCleanup} from './helpers/cleanup'
import {newBeam} from './beam'

const UFOStates = {
  SPAWN: 'spawn',
  ROAM: 'roam',
  SEEKING: 'seeking',
  BEAMING: 'beaming',
  ZAPPED: 'zapped',
  END: 'end',
}

const UFO = ecs.registerComponent({
  name: 'UFO',
  schema: {
    roamingAnimationTiming: ecs.ui32,
    roamingAnimationIdleTiming: ecs.ui32,
    roamingCycles: ecs.ui32,
    seekDuration: ecs.ui32,
    beamDuration: ecs.ui32,
    zappedRespawnDuration: ecs.ui32,
    dropDuration: ecs.ui32,
    spawnDuration: ecs.ui32,
    baseBeamEid: ecs.eid,
  },
  schemaDefaults: {
    roamingAnimationTiming: 2000,
    roamingAnimationIdleTiming: 1000,
    roamingCycles: 4,
    seekDuration: 2000,
    beamDuration: 5000,
    zappedRespawnDuration: 7000,
    dropDuration: 1500,
    spawnDuration: 1500,
  },
  data: {
    currentRoamingCycle: ecs.ui32,
    currentIdleTimeout: ecs.ui32,
    currentAnimationTimeout: ecs.ui32,
    currentTarget: ecs.eid,
  },
  add: (world, component) => {
    const {eid, dataAttribute} = component

    ecs.Collider.set(world, eid, {
      shape: ecs.ColliderShape.Cylinder,
      radius: 3,
      height: 2.5,
      mass: 1,
      gravityFactor: 0,
      friction: 0.5,
    })

    function setNewTarget(e) {
      if (e.data.eid) dataAttribute.set(eid, {currentTarget: e.data.eid})
    }

    function resetCurrentCycle() {
      dataAttribute.set(eid, {currentRoamingCycle: 0})
    }

    async function handleCollision(e) {
      UFOAnimations.COLLISION(world, eid, 500)
    }

    function handleCleanup() {
      world.events.removeListener(eid, 'seek', setNewTarget)
      world.events.removeListener(eid, 'noCows', resetCurrentCycle)
      world.events.removeListener(eid, ecs.physics.COLLISION_START_EVENT, handleCollision)
    }

    world.three.entityToObject.get(eid).name = 'ufo'

    world.events.addListener(eid, 'seek', setNewTarget)
    world.events.addListener(eid, 'noCows', resetCurrentCycle)
    world.events.addListener(eid, ecs.physics.COLLISION_START_EVENT, handleCollision)
    addCleanup(component, handleCleanup)
  },
  remove: (world, component) => {
    doCleanup(component)
  },
  stateMachine: (component) => {
    const {eid, world, schemaAttribute, dataAttribute} = component
    const {seekDuration, beamDuration, zappedRespawnDuration, dropDuration, spawnDuration} = schemaAttribute.get(eid)
    const roamTrigger = ecs.defineTrigger()
    const managerComponent = world.getParent(eid)

    ecs.defineState(UFOStates.SPAWN)
      .initial()
      .onEnter(() => {
        UFOAnimations.SPAWN(world, eid, spawnDuration)
      })
      .wait(spawnDuration, UFOStates.ROAM)

    ecs.defineState(UFOStates.ROAM)
      // .initial()
      .onEnter(() => {
        const {currentRoamingCycle} = dataAttribute.get(eid)
        const {
          roamingCycles,
          roamingAnimationIdleTiming,
          roamingAnimationTiming,
        } = schemaAttribute.get(eid)

        // Done roaming, begin to seek
        if (currentRoamingCycle === roamingCycles) {
          world.events.dispatch(managerComponent, 'getCow', {eid})
          return
        }

        const pos = ecs.Position.get(world, eid)
        if (
          pos && roamingCycles &&
          roamingAnimationTiming && roamingAnimationIdleTiming
        ) {
          // Wait for idle, then move, then toggle roam trigger
          // which will loop this onEnter function

          // We save these timeouts so that we can clean them up
          // on exit. shouldn't be needed unless interupted by a
          // 'zap' event, but we'll just clean them up by default anyway
          const cursor = dataAttribute.cursor(eid)
          const idleTimeout = setTimeout(() => {
            UFOAnimations.ROAM(
              world, eid,
              ecs.Position.get(world, eid),
              roamingAnimationTiming
            )

            const animationTimeout = setTimeout(() => {
              if (roamTrigger) {
                roamTrigger.trigger()
              }
            }, roamingAnimationTiming)
            if (cursor) {
              cursor.currentAnimationTimeout = animationTimeout
            }
          }, roamingAnimationIdleTiming)
          if (cursor) {
            cursor.currentRoamingCycle = (dataAttribute.get(eid)?.currentRoamingCycle || 0) + 1
            cursor.currentIdleTimeout = idleTimeout
          }
        }
      })
      .onExit(() => {
        const {currentIdleTimeout, currentAnimationTimeout} = dataAttribute.get(eid)

        currentIdleTimeout ?? clearTimeout(currentIdleTimeout)
        currentAnimationTimeout ?? clearTimeout(currentAnimationTimeout)

        dataAttribute.set(eid, {
          currentAnimationTimeout: null,
          currentIdleTimeout: null,
        })
      })
      .onTrigger(roamTrigger, UFOStates.ROAM)
      .onEvent('seek', UFOStates.SEEKING)
      .onEvent('noCows', UFOStates.ROAM)

    ecs.defineState(UFOStates.SEEKING)
      .onEnter(() => {
        const {currentTarget} = dataAttribute.get(eid)

        // Start following assigned cow
        const targetPos = ecs.Position.get(world, currentTarget)
        UFOAnimations.SEEK_TARGET(world, targetPos, eid, seekDuration)
      })
      .wait(seekDuration, UFOStates.BEAMING)

    ecs.defineState(UFOStates.BEAMING)
      .onEnter(() => {
        const {baseBeamEid} = schemaAttribute.get(eid)
        const {currentTarget} = dataAttribute.get(eid)

        const ufoPos = ecs.Position.get(world, eid)
        const cowPos = ecs.Position.get(world, currentTarget)

        CowAnimations.BEAM_UP(world, currentTarget, cowPos, ufoPos, beamDuration)
        // create beam under ufo
        const beamEid = newBeam(world, eid, baseBeamEid)

        // Called if beaming animation is not interrupted
        const beamTimeout = setTimeout(() => {
          // tell manager that cow is abducted
          world.events.dispatch(managerComponent, 'cowAbducted', {cowEid: currentTarget})
          ecs.Hidden.set(world, currentTarget)
          // hide cow
        }, beamDuration)

        function cleanupBeamState() {
          clearTimeout(beamTimeout)
          world.deleteEntity(beamEid)
        }

        addCleanup(component, cleanupBeamState)
      })
      .wait(beamDuration + 500, UFOStates.ROAM)
      .onExit(() => {
        // Clean up beamTimeout in case ufo is zapped before finishing
        doCleanup(component)
      })

    ecs.defineState(UFOStates.ZAPPED)
      .onEnter(() => {
        const {currentTarget} = dataAttribute.get(eid)
        if (currentTarget) {
          CowAnimations.DROP(world, currentTarget, dropDuration)
          world.events.dispatch(managerComponent, 'removeCowTarget', {cowEid: currentTarget})
        }
        dataAttribute.set(eid, {currentRoamingCycle: 0, currentTarget: BigInt(0)})

        // Fly away and respawn
        UFOAnimations.FLY_AWAY_AND_RESPAWN(
          world, eid,
          ecs.Position.get(world, eid),
          zappedRespawnDuration
        )
      })
      .wait(zappedRespawnDuration, UFOStates.ROAM)

    ecs.defineState(UFOStates.END)
      .onEnter(() => {
        world.deleteEntity(eid)
      })

    // All states other than ZAPPED need a handler for the zap event
    ecs.defineStateGroup([UFOStates.ROAM, UFOStates.SEEKING, UFOStates.BEAMING, UFOStates.SPAWN])
      .onEvent('zap', UFOStates.ZAPPED)

    ecs.defineStateGroup([...Object.values(UFOStates)])
      .onEvent('game-over', UFOStates.END, {
        target: world.events.globalId,
      })
  },
})

// Helper function to spawn a new UFO
export function spawnUfo(
  world: ecs.World, managerEid: BigInt,
  baseUfoId: BigInt, baseBeamEid: BigInt
) {
  // Create a new entity
  const newEid = world.createEntity()
  world.setParent(newEid, managerEid)
  // Copy attributes from baseUFO in UI
  cloneComponents(baseUfoId, newEid, world)

  UFO.set(world, newEid, {
    roamingAnimationTiming: getRandInt(1000, 2500),
    roamingAnimationIdleTiming: getRandInt(300, 1000),
    roamingCycles: getRandInt(3, 12),
    baseBeamEid,
  })

  // Get random offset for new entity
  // ecs.Position.set(world, newEid, {
  //   x: getRandomOffset(10, 20) * -1,
  //   y: getRandomOffset(10, 20) * -1,
  //   z: getRandomOffset(10, 20) * -1,
  // })
  ecs.Position.set(world, newEid, {
    x: 0,
    y: 40,
    z: 20,
  })

  return newEid
}

export {UFO}

And sometimes the error is not thrown but the effect is just the same. The UI will not disappear and this happens both in the simulator and on my phone from QR codes I generate in Studio. But if someone else from my team sends me a QR code from their laptop it works fine. Also, the published version of the game (same version/code as what I have loaded in Studio) works fine on my phone. If I clone the project from the public page it also gives me the same issues on my laptop.