const pc = window.pc;
import { BaseSystem as T, registerModule as M, Debugger as y, PlayerNameTag as N, getBoundingBox as O, AvatarOpacityRenderer as B, AudioProcessor as k, createFallbackGripBone as x, updateFallbackGripBonePosition as D, calculateAvatarCapsule as L, BaseModule as H } from "./core.mjs";
import { SystemName as q, ModuleName as C, MessageType as R } from "./types.mjs";
const w = (d) => {
  let e;
  const t = /* @__PURE__ */ new Set(), s = (a, h) => {
    const o = typeof a == "function" ? a(e) : a;
    if (!Object.is(o, e)) {
      const v = e;
      e = h ?? (typeof o != "object" || o === null) ? o : Object.assign({}, e, o), t.forEach((p) => p(e, v));
    }
  }, i = () => e, n = { setState: s, getState: i, getInitialState: () => l, subscribe: (a) => (t.add(a), () => t.delete(a)) }, l = e = d(s, i, n);
  return n;
}, F = (d) => d ? w(d) : w;
function j(d) {
  return d && d.__esModule && Object.prototype.hasOwnProperty.call(d, "default") ? d.default : d;
}
const U = (d) => (e, t, s) => {
  const i = s.subscribe;
  return s.subscribe = (_, n, l) => {
    let a = _;
    if (n) {
      const h = l?.equalityFn || Object.is;
      let o = _(s.getState());
      a = (v) => {
        const p = _(v);
        if (!h(o, p)) {
          const u = o;
          n(o = p, u);
        }
      }, l?.fireImmediately && n(o, o);
    }
    return i(a);
  }, d(e, t, s);
}, G = U, z = {}, V = () => F()(
  G((d) => ({
    ...z
  }))
);
class de extends T {
  static systemName = q.Network;
  modules = {};
  store;
  _options;
  constructor(e, t) {
    super(e), this._options = t, this.store = V(), this.pcApp.on("update", this.update, this);
  }
  async start() {
    await this._setupMultiplayerModule();
  }
  async _setupMultiplayerModule() {
    const { modules: e = [] } = this._options || {}, t = e.find((_) => _.name === C.Multiplayer);
    if (!t) return;
    const { Module: s, options: i } = t, r = new s(this, i);
    await r.initialize(), M(this.modules, r.name, r);
  }
  update(e) {
    for (const t in this.modules) {
      const s = t, i = this.modules[s];
      i && i.update && i.update(e);
    }
  }
  destroy() {
    super.destroy(), this.pcApp.off("update", this.update, this), Object.values(this.modules).forEach((e) => {
      e.destroy && e.destroy(), delete this.modules[e.name];
    });
  }
}
class $ {
  _appId = null;
  _playSdk = null;
  _client = null;
  _connected = !1;
  _wasAudioEnabled = !1;
  _wasAudioMuted = !1;
  _onConnected = () => {
  };
  _onClientConnected = () => {
  };
  _onClientDisconnected = () => {
  };
  _onMessageReceived = () => {
  };
  _onCompetitionReceived = () => {
  };
  _onLocalAudioStreamCallback = null;
  _onRemoteAudioStreamCallback = null;
  async initialize(e) {
    await e.sdk.load(), this._appId = e.appId || null, this._playSdk = e.sdk.createPlaySdk();
  }
  get connected() {
    return this._connected;
  }
  checkIsMasterUser() {
    return this._client?.isMasterUser() ?? !1;
  }
  onConnected(e) {
    this._onConnected = () => {
      this._connected = !0, e(), this._restoreAudioState();
    };
  }
  async _restoreAudioState() {
    if (!(!this._wasAudioEnabled || !this._client))
      try {
        await this._client.enableAudio(), this._wasAudioMuted && await this._client.muteAudio();
      } catch (e) {
        y.error("Failed to restore audio state after room switch", e);
      } finally {
        this._wasAudioEnabled = !1, this._wasAudioMuted = !1;
      }
  }
  onClientConnected(e) {
    this._onClientConnected = e;
  }
  onClientDisconnected(e) {
    this._onClientDisconnected = e;
  }
  onMessageReceived(e) {
    this._onMessageReceived = e;
  }
  onCompetitionReceived(e) {
    this._onCompetitionReceived = (t) => {
      const s = this._convertCompetitionResponse(t);
      e(s);
    };
  }
  sendMessage(e) {
    if (!this._client) {
      y.warn("No multiplayer client connected. Cannot send message.");
      return;
    }
    this._client.general.sendMessage(e);
  }
  sendCompetition(e, t, s) {
    if (!this._client) {
      y.warn("No multiplayer client connected. Cannot send competition message.");
      return;
    }
    this._client.actionsync.competition(e, t, s);
  }
  _convertCompetitionResponse(e) {
    const t = e.competition;
    return {
      successor: t.successor,
      actionName: t.action_name,
      actionId: t.action_id,
      actionMsg: t.action_msg,
      updateTime: t.update_time
    };
  }
  _bindClientEvents(e) {
    e.onConnected(this._onConnected.bind(this)), e.onClientDisconnected(this._onClientDisconnected.bind(this)), e.onClientConnected(this._onClientConnected.bind(this)), e.general.onMessage(this._onMessageReceived.bind(this)), e.actionsync.onCompetition(this._onCompetitionReceived.bind(this)), this._onLocalAudioStreamCallback && e.onLocalAudioStream(this._onLocalAudioStreamCallback), this._onRemoteAudioStreamCallback && e.onRemoteAudioStream(this._onRemoteAudioStreamCallback);
  }
  async joinRoom(e, t, s) {
    if (!this._playSdk)
      return Promise.reject("VIVERSE Play SDK is not loaded.");
    if (!this._appId)
      return Promise.reject("App ID is not set. It's required for creating the VIVERSE Play SDK.");
    const i = await this._playSdk.newMultiplayerClient(e, this._appId, t);
    this._client = i, await i.init({
      modules: {
        actionSync: { enabled: !0 }
      },
      ...s || {}
    }), this._bindClientEvents(i);
  }
  async leaveRoom() {
    this._client && (this._wasAudioEnabled = this._client.isAudioEnabled(), this._wasAudioMuted = this._client.isAudioMuted(), this._onLocalAudioStreamCallback?.(null), this._connected = !1, this._client.disconnect(), this._client = null);
  }
  async switchRoom(e, t, s) {
    await this.leaveRoom(), await this.joinRoom(e, t, s);
  }
  async enableAudio(e) {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.enableAudio(e);
  }
  async disableAudio() {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.disableAudio();
  }
  async listAudioInputDevices() {
    return this._client ? this._client.listAudioInputDevices() : Promise.resolve([]);
  }
  async listAudioOutputDevices() {
    return this._client ? this._client.listAudioOutputDevices() : Promise.resolve([]);
  }
  async setAudioInputDevice(e) {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.setAudioInputDevice(e);
  }
  async setAudioOutputDevice(e) {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.setAudioOutputDevice(e);
  }
  async muteAudio() {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.muteAudio();
  }
  async unmuteAudio() {
    if (!this._client) return Promise.reject("No multiplayer client connected.");
    await this._client.unmuteAudio();
  }
  isAudioEnabled() {
    return this._client?.isAudioEnabled() ?? !1;
  }
  isAudioMuted() {
    return this._client?.isAudioMuted() ?? !1;
  }
  onLocalAudioStream(e) {
    this._onLocalAudioStreamCallback = e, this._client && this._client.onLocalAudioStream(e);
  }
  onRemoteAudioStream(e) {
    this._onRemoteAudioStreamCallback = e, this._client && this._client.onRemoteAudioStream(e);
  }
}
class J {
  _player;
  _viverseApp;
  _pcApp;
  _unsubscribes = [];
  _avatarName = "";
  _avatar = null;
  _boundingBox = null;
  _avatarRegistry;
  _latestAvatarRequestId = 0;
  _targetLocalRotation = new pc.Quat();
  _currentLocalRotation = new pc.Quat();
  _hasReceivedLRotation = !1;
  _lerpSpeed = 10;
  _isSitting = !1;
  _currentCustomAnim = null;
  _recordedStates = null;
  _sitFrameEndHandle = null;
  constructor(e, t, s) {
    this._viverseApp = t, this._pcApp = t.pcApp, this._player = e, this._avatarRegistry = s || {}, this._subscribeStore();
  }
  get avatar() {
    return this._avatar;
  }
  get boundingBox() {
    return this._boundingBox;
  }
  get isSitting() {
    return this._isSitting;
  }
  _subscribeStore() {
    const e = this._viverseApp.context.preference;
    this._unsubscribes.push(
      e.subscribe(
        (t) => t.vrmMtoonShading,
        this._onMtoonShadingChange.bind(this)
      )
    );
  }
  _onMtoonShadingChange() {
    this._avatar && this._setMtoonShading(this._avatar);
  }
  _handleAvatarLocalRotation(e) {
    const { localRotation: t } = e;
    if (t && (this._targetLocalRotation.set(...t), !this._hasReceivedLRotation)) {
      const s = this._player.avatarContainerEntity;
      s && (s.setLocalRotation(this._targetLocalRotation), this._hasReceivedLRotation = !0);
    }
  }
  async _loadAsset(e, t) {
    const s = new pc.Asset(e, "container", { url: t });
    return this._pcApp.assets.add(s), await new Promise((i, r) => {
      s.ready(() => i()), s.once("load", () => i()), s.once("error", (_) => r(_)), this._pcApp.assets.load(s);
    }), s;
  }
  _handleAvatarStates(e) {
    this._recordedStates = e, this._avatar && (this._avatar.setHorizontalDirection && this._avatar.setHorizontalDirection(e.horizontalDirection), this._avatar.setVerticalState && this._avatar.setVerticalState(e.verticalState), this._avatar.setGrounded && this._avatar.setGrounded(e.isGrounded), this._avatar.setFalling && this._avatar.setFalling(e.isFalling), this._avatar.setFlying && this._avatar.setFlying(e.isFlying), this._avatar.setSprinting && this._avatar.setSprinting(e.isSprinting), this._handleSittingState(e.isSitting), this._handleCustomAnimation(e.customAnim), e.triggerJump && this._avatar.jump?.());
  }
  _cleanupFrameEndHandle() {
    this._sitFrameEndHandle && (this._sitFrameEndHandle.off(), this._sitFrameEndHandle = null);
  }
  async _sit() {
    this._cleanupFrameEndHandle(), this._avatar && await this._avatar.sit?.(), await new Promise((e) => {
      this._sitFrameEndHandle = this._pcApp.once("frameend", () => {
        this._player.emit("remote-player:sitting", { isSitting: !0 }), e();
      });
    });
  }
  async _standUp() {
    this._cleanupFrameEndHandle(), this._avatar && await this._avatar.standUp?.(), this._player.emit("remote-player:sitting", { isSitting: !1 });
  }
  async _handleSittingState(e) {
    if (!this._avatar) return;
    const t = this._isSitting;
    this._isSitting = e, !t && e && await this._sit(), t && !e && await this._standUp();
  }
  async _handleCustomAnimation(e) {
    if (!this._avatar) return;
    const t = e?.stateName || null, s = this._currentCustomAnim;
    if (t === s)
      return;
    if (this._currentCustomAnim = t, !e) {
      this._avatar.exitCustomAnimation?.();
      return;
    }
    const { stateName: i, assetUrl: r, loadOptions: _, playOptions: n } = e;
    if (!this._avatar.customAnimationStates?.includes(i))
      try {
        const a = await this._loadAsset(i, r);
        await this._avatar.loadCustomAnimation?.(i, a, _);
      } catch (a) {
        y.error(`Failed to load custom animation "${i}":`, a);
        return;
      }
    this._currentCustomAnim === i && (n && (n.canBeInterrupted = !1), this._avatar.playCustomAnimation?.(i, n));
  }
  _updateBoundingBox(e) {
    let t = this._boundingBox;
    t || (t = new pc.BoundingBox(), this._boundingBox = t);
    const s = e.boundingBox;
    s && t.halfExtents.copy(s.halfExtents), this._updateBoundingBoxCenter(t);
  }
  _updateBoundingBoxCenter(e) {
    const s = (this._player.avatarContainerEntity || this._player.playerEntity).getPosition();
    e.center.set(s.x, s.y + e.halfExtents.y, s.z);
  }
  update(e) {
    const t = this._player.avatarContainerEntity;
    if (t) {
      const s = t.getLocalRotation(), i = this._currentLocalRotation;
      i.slerp(s, this._targetLocalRotation, this._lerpSpeed * e), t.setLocalRotation(i);
    }
    this._boundingBox && this._updateBoundingBoxCenter(this._boundingBox), this._avatar && this._avatar.update(e);
  }
  _resetBeforeChange() {
    this._isSitting = !1, this._currentCustomAnim = null;
  }
  _setMtoonShading(e) {
    const { vrmMtoonShading: t } = this._viverseApp.context.preference.getState();
    if (!("isVrmAvatar" in e && e.isVrmAvatar)) return;
    e.setMtoonShading(t);
  }
  async _handleCreateAvatar(e) {
    if (this._avatarName === e.name) return;
    const t = this._player.avatarContainerEntity;
    if (!t) {
      y.error("Avatar container entity is not available. No avatar module in use.");
      return;
    }
    const s = this._avatarRegistry[e.type];
    if (!s) {
      y.error(`No avatar class found for type: ${e.type}`);
      return;
    }
    const i = ++this._latestAvatarRequestId;
    try {
      const r = new s(e.config);
      this._setMtoonShading(r);
      const _ = await r.create?.(this._pcApp);
      if (i !== this._latestAvatarRequestId)
        return;
      const n = this._avatar;
      if (n) {
        n.deactivate?.();
        const l = n.entity;
        l && t.removeChild(l);
      }
      this._player.emit("remote-avatar:before-change", { previousAvatar: n, newAvatar: r }), r.activate?.(), t.addChild(_), this._avatar = r, this._avatarName = e.name, this._updateBoundingBox(r), this._resetBeforeChange(), this._recordedStates && this._handleAvatarStates(this._recordedStates), this._player.emit("remote-avatar:changed", { previousAvatar: n, newAvatar: r });
    } catch (r) {
      y.error(`Failed to create avatar: ${r}`);
    }
  }
  process(e) {
    this._handleCreateAvatar(e), this._handleAvatarLocalRotation(e), e.states && this._handleAvatarStates(e.states);
  }
  destroy() {
    this._cleanupFrameEndHandle(), this._latestAvatarRequestId++, this._avatarName = "", this._unsubscribes.forEach((e) => e()), this._unsubscribes = [], this._avatar && (this._avatar.deactivate?.(), this._avatar.destroy?.(), this._avatar = null);
  }
}
class W {
  _player;
  _hasReceivedPosition = !1;
  _hasReceivedRotation = !1;
  _targetPosition = new pc.Vec3();
  _targetRotation = new pc.Quat();
  _lerpSpeed = 10;
  _currentPosition = new pc.Vec3();
  _currentRotation = new pc.Quat();
  _cellId = "";
  _cellSize = 5;
  constructor(e) {
    this._player = e;
  }
  get cellId() {
    return this._cellId;
  }
  _handleTransform(e) {
    e.position && (this._targetPosition.set(...e.position), this._hasReceivedPosition || (this._player.playerEntity.setPosition(this._targetPosition), this._hasReceivedPosition = !0)), e.rotation && (this._targetRotation.set(...e.rotation), this._hasReceivedRotation || (this._player.playerEntity.setRotation(this._targetRotation), this._hasReceivedRotation = !0));
  }
  _getCellId(e, t) {
    const s = Math.floor(e.x / t) * t, i = Math.floor(e.y / t) * t, r = Math.floor(e.z / t) * t;
    return `${s.toFixed(0)}_${i.toFixed(0)}_${r.toFixed(0)}`;
  }
  update(e) {
    const t = this._player.playerEntity;
    if (t) {
      if (this._currentPosition) {
        const s = t.getPosition();
        this._currentPosition.lerp(s, this._targetPosition, this._lerpSpeed * e), t.setPosition(this._currentPosition);
        const i = this._getCellId(this._currentPosition, this._cellSize);
        if (this.cellId !== i) {
          const r = this._cellId;
          this._cellId = i, this._player.emit("remote-player:cell-changed", this._cellId, r);
        }
      }
      if (this._currentRotation) {
        const s = t.getRotation();
        this._currentRotation.slerp(s, this._targetRotation, this._lerpSpeed * e), t.setRotation(this._currentRotation);
      }
    }
  }
  process(e) {
    this._handleTransform(e);
  }
}
class Q {
  _player;
  _pcApp;
  _viverseApp;
  _displayName = "";
  _snapshot = "";
  _fullBodySnapshot = "";
  _nameTag = null;
  _isNameTagSetup = !1;
  _setupNameTagPromise = null;
  _defaultNameTagHeight = 0;
  _customNameTagOffset = null;
  _customNameTagScale = null;
  _isSceneHierarchyNameTagEnabled = !0;
  _destroyed = !1;
  constructor(e, t) {
    this._pcApp = t.pcApp, this._viverseApp = t, this._player = e, this._setupNameTag(), this._bindEvents();
  }
  get nameTag() {
    return this._nameTag;
  }
  get displayName() {
    return this._displayName;
  }
  get snapshot() {
    return this._snapshot;
  }
  get fullBodySnapshot() {
    return this._fullBodySnapshot;
  }
  _bindEvents() {
    this._player.on("remote-avatar:changed", this._handleAvatarChanged, this), this._player.on("remote-player:sitting", this._handleAvatarSittingChanged, this), this._player.on("remote-player:audio-talking", this._handleAudioTalkingChanged, this);
    const e = this._viverseApp.systems.localPlayer;
    e && (e.on("name-tag:custom-offset-changed", this._syncCustomNameTagOffset, this), e.on("name-tag:custom-scale-changed", this._syncCustomScale, this), e.on(
      "name-tag:scene-hierarchy-enabled-changed",
      this._syncSceneHierarchyEnabled,
      this
    ));
  }
  _unbindEvents() {
    this._player.off("remote-avatar:changed", this._handleAvatarChanged, this), this._player.off("remote-player:sitting", this._handleAvatarSittingChanged, this), this._player.off("remote-player:audio-talking", this._handleAudioTalkingChanged, this);
    const e = this._viverseApp.systems.localPlayer;
    e && (e.off("name-tag:custom-offset-changed", this._syncCustomNameTagOffset, this), e.off("name-tag:custom-scale-changed", this._syncCustomScale, this), e.off(
      "name-tag:scene-hierarchy-enabled-changed",
      this._syncSceneHierarchyEnabled,
      this
    ));
  }
  async _createNameTag() {
    const e = await N.create(this._pcApp, { text: this._displayName });
    if (this._destroyed) {
      e.destroy();
      return;
    }
    this._nameTag = e, this._nameTag.setup(this._player.playerEntity), this._isNameTagSetup = !0;
    const t = this._player.activeAvatar, s = this._viverseApp.systems.localPlayer;
    if (s) {
      const i = s.nameTag;
      if (i) {
        const r = i.isSceneHierarchyEnabled;
        if (r !== void 0 && (this._isSceneHierarchyNameTagEnabled = r), this._isSceneHierarchyNameTagEnabled) {
          const _ = i.customOffset;
          _ && (this._customNameTagOffset = _);
          const n = i.customScale;
          n && (this._customNameTagScale = n);
        }
      } else
        y.warn(
          "Local player name tag is not available when setting up remote player name tag."
        );
    }
    this._updateNameTagByAvatar(t), this._updateNameTagScale(), this._applySceneHierarchyNameTagDisplayCondition(this._isSceneHierarchyNameTagEnabled), this._updateDisplayName(this._displayName), this._setupNameTagPromise = null;
  }
  async _setupNameTag() {
    if (!this._isNameTagSetup)
      return this._setupNameTagPromise ? this._setupNameTagPromise : (this._setupNameTagPromise = this._createNameTag(), this._setupNameTagPromise);
  }
  _updateNameTagPosition() {
    if (!this._nameTag) {
      y.warn("Name tag is not set up in remote player.");
      return;
    }
    const e = this._customNameTagOffset ?? { x: 0, y: 0, z: 0 };
    this._nameTag.updateLocalPosition(e.x, this._defaultNameTagHeight + e.y, e.z);
  }
  _updateNameTagScale() {
    this._nameTag && (this._customNameTagScale ? this._nameTag.updateLocalScale(
      this._customNameTagScale.x,
      this._customNameTagScale.y,
      this._customNameTagScale.z
    ) : this._nameTag.updateLocalScale(1, 1, 1));
  }
  _applySceneHierarchyNameTagDisplayCondition(e) {
    this._nameTag && this._nameTag.updateDisplayCondition("isSceneHierarchyEntityEnabled", e);
  }
  _getNameTagHeight(e) {
    if (!e) return 1;
    const t = this._player.isSitting, s = e.entity;
    return t && s ? O(s).halfExtents.y * 2 : e.boundingBox.halfExtents.y * 2;
  }
  _updateNameTagByAvatar(e) {
    this._updateNameTagPositionByAvatar(e), this._updateNameTagVisibility(e);
  }
  _updateNameTagPositionByAvatar(e) {
    this._defaultNameTagHeight = this._getNameTagHeight(e), this._updateNameTagPosition();
  }
  _updateNameTagVisibility(e) {
    if (this._player.useAvatarModule) {
      if (!this._nameTag) {
        y.warn("Name tag is not set up in remote player.");
        return;
      }
      this._nameTag.updateDisplayCondition("isAvatarActive", !!e);
    }
  }
  _handleAvatarChanged({ newAvatar: e }) {
    this._updateNameTagByAvatar(e);
  }
  _handleAvatarSittingChanged() {
    const e = this._player.activeAvatar;
    this._updateNameTagByAvatar(e);
  }
  _updateNameTagViewPosition() {
    if (!this._nameTag) return;
    const e = this._viverseApp.systems.localPlayer;
    if (!e) return;
    const s = e.store.getState().viewPosition;
    this._nameTag.updateViewPosition(s);
  }
  _updateDisplayName(e) {
    this._nameTag && this._nameTag.setText(e);
  }
  _handleProfileUpdate(e) {
    const t = {}, s = {};
    e.displayName && e.displayName !== this._displayName && (s.displayName = this._displayName, t.displayName = e.displayName, this._displayName = e.displayName, this._updateDisplayName(e.displayName)), e.snapshot && e.snapshot !== this._snapshot && (s.snapshot = this._snapshot, t.snapshot = e.snapshot, this._snapshot = e.snapshot), e.fullBodySnapshot && e.fullBodySnapshot !== this._fullBodySnapshot && (s.fullBodySnapshot = this._fullBodySnapshot, t.fullBodySnapshot = e.fullBodySnapshot, this._fullBodySnapshot = e.fullBodySnapshot), Object.keys(t).length > 0 && this._player.emit("remote-profile:updated", {
      sessionId: this._player.sessionId,
      newProfile: t,
      previousProfile: s
    });
  }
  _syncCustomNameTagOffset(e) {
    this._customNameTagOffset = e, this._updateNameTagPosition();
  }
  _syncCustomScale(e) {
    this._customNameTagScale = e, this._updateNameTagScale();
  }
  _syncSceneHierarchyEnabled(e) {
    this._isSceneHierarchyNameTagEnabled = e, this._applySceneHierarchyNameTagDisplayCondition(e);
  }
  getFormattedProfile() {
    return {
      displayName: this._displayName,
      snapshot: this._snapshot,
      fullBodySnapshot: this._fullBodySnapshot
    };
  }
  process(e) {
    this._handleProfileUpdate(e);
  }
  update() {
    this._updateNameTagViewPosition();
  }
  _handleAudioTalkingChanged(e) {
    this._nameTag && this._nameTag.setSpeaking(e);
  }
  destroy() {
    this._destroyed = !0, this._unbindEvents(), this._nameTag && (this._nameTag.destroy(), this._nameTag = null);
  }
}
var b = { exports: {} }, P;
function K() {
  return P || (P = 1, (function(d) {
    var e = Object.prototype.hasOwnProperty, t = "~";
    function s() {
    }
    Object.create && (s.prototype = /* @__PURE__ */ Object.create(null), new s().__proto__ || (t = !1));
    function i(l, a, h) {
      this.fn = l, this.context = a, this.once = h || !1;
    }
    function r(l, a, h, o, v) {
      if (typeof h != "function")
        throw new TypeError("The listener must be a function");
      var p = new i(h, o || l, v), u = t ? t + a : a;
      return l._events[u] ? l._events[u].fn ? l._events[u] = [l._events[u], p] : l._events[u].push(p) : (l._events[u] = p, l._eventsCount++), l;
    }
    function _(l, a) {
      --l._eventsCount === 0 ? l._events = new s() : delete l._events[a];
    }
    function n() {
      this._events = new s(), this._eventsCount = 0;
    }
    n.prototype.eventNames = function() {
      var a = [], h, o;
      if (this._eventsCount === 0) return a;
      for (o in h = this._events)
        e.call(h, o) && a.push(t ? o.slice(1) : o);
      return Object.getOwnPropertySymbols ? a.concat(Object.getOwnPropertySymbols(h)) : a;
    }, n.prototype.listeners = function(a) {
      var h = t ? t + a : a, o = this._events[h];
      if (!o) return [];
      if (o.fn) return [o.fn];
      for (var v = 0, p = o.length, u = new Array(p); v < p; v++)
        u[v] = o[v].fn;
      return u;
    }, n.prototype.listenerCount = function(a) {
      var h = t ? t + a : a, o = this._events[h];
      return o ? o.fn ? 1 : o.length : 0;
    }, n.prototype.emit = function(a, h, o, v, p, u) {
      var f = t ? t + a : a;
      if (!this._events[f]) return !1;
      var c = this._events[f], g = arguments.length, A, m;
      if (c.fn) {
        switch (c.once && this.removeListener(a, c.fn, void 0, !0), g) {
          case 1:
            return c.fn.call(c.context), !0;
          case 2:
            return c.fn.call(c.context, h), !0;
          case 3:
            return c.fn.call(c.context, h, o), !0;
          case 4:
            return c.fn.call(c.context, h, o, v), !0;
          case 5:
            return c.fn.call(c.context, h, o, v, p), !0;
          case 6:
            return c.fn.call(c.context, h, o, v, p, u), !0;
        }
        for (m = 1, A = new Array(g - 1); m < g; m++)
          A[m - 1] = arguments[m];
        c.fn.apply(c.context, A);
      } else {
        var E = c.length, S;
        for (m = 0; m < E; m++)
          switch (c[m].once && this.removeListener(a, c[m].fn, void 0, !0), g) {
            case 1:
              c[m].fn.call(c[m].context);
              break;
            case 2:
              c[m].fn.call(c[m].context, h);
              break;
            case 3:
              c[m].fn.call(c[m].context, h, o);
              break;
            case 4:
              c[m].fn.call(c[m].context, h, o, v);
              break;
            default:
              if (!A) for (S = 1, A = new Array(g - 1); S < g; S++)
                A[S - 1] = arguments[S];
              c[m].fn.apply(c[m].context, A);
          }
      }
      return !0;
    }, n.prototype.on = function(a, h, o) {
      return r(this, a, h, o, !1);
    }, n.prototype.once = function(a, h, o) {
      return r(this, a, h, o, !0);
    }, n.prototype.removeListener = function(a, h, o, v) {
      var p = t ? t + a : a;
      if (!this._events[p]) return this;
      if (!h)
        return _(this, p), this;
      var u = this._events[p];
      if (u.fn)
        u.fn === h && (!v || u.once) && (!o || u.context === o) && _(this, p);
      else {
        for (var f = 0, c = [], g = u.length; f < g; f++)
          (u[f].fn !== h || v && !u[f].once || o && u[f].context !== o) && c.push(u[f]);
        c.length ? this._events[p] = c.length === 1 ? c[0] : c : _(this, p);
      }
      return this;
    }, n.prototype.removeAllListeners = function(a) {
      var h;
      return a ? (h = t ? t + a : a, this._events[h] && _(this, h)) : (this._events = new s(), this._eventsCount = 0), this;
    }, n.prototype.off = n.prototype.removeListener, n.prototype.addListener = n.prototype.on, n.prefixed = t, n.EventEmitter = n, d.exports = n;
  })(b)), b.exports;
}
var Y = K();
const X = /* @__PURE__ */ j(Y);
class Z {
  _viverseApp;
  _player;
  _isOverlapping = !1;
  _needOverlapCheck = !0;
  _renderer;
  constructor(e, t, s) {
    this._viverseApp = t, this._player = e, this._needOverlapCheck = s?.needOverlapCheck ?? !0, this._renderer = new B({
      smoothSpeed: 20
    });
    const i = this._player.activeAvatar;
    i && this._renderer.setAvatar(i), this._bindEvents();
  }
  _bindEvents() {
    this._player.on("remote-avatar:overlapping", this._onAvatarOverlapping, this), this._player.on("remote-avatar:changed", this._onAvatarChanged, this);
  }
  _unbindEvents() {
    this._player.off("remote-avatar:overlapping", this._onAvatarOverlapping, this), this._player.off("remote-avatar:changed", this._onAvatarChanged, this);
  }
  _getOpacityFromDistance() {
    const e = this._getViewPosition();
    if (!e) return 1;
    const t = this._player.avatarBoundingBox;
    return t ? this._renderer.getOpacityFromDistance(e, t) : 1;
  }
  _getViewPosition() {
    const e = this._viverseApp.systems.localPlayer;
    return e ? e.store.getState().viewPosition : null;
  }
  _getTargetOpacity() {
    const e = this._getOpacityFromDistance();
    return e < 1 ? e : this._needOverlapCheck && this._isOverlapping ? 0.5 : 1;
  }
  _onAvatarOverlapping(e) {
    this._isOverlapping = e;
  }
  _onAvatarChanged({ newAvatar: e }) {
    this._renderer.setAvatar(e);
  }
  update(e) {
    const t = this._getTargetOpacity();
    this._renderer.updateOpacity(e, t);
  }
  destroy() {
    this._unbindEvents();
  }
}
class ee extends X {
  sessionId;
  playerEntity;
  _avatarContainerEntity = null;
  _useAvatarModule = !1;
  _fallbackGripBone = null;
  _avatarProcessor;
  _transformProcessor;
  _profileProcessor;
  _audioProcessor;
  _opacityHandler;
  constructor(e, t, s) {
    super(), this.sessionId = t, this._useAvatarModule = !!e.systems?.localPlayer?.modules.localAvatar;
    const { avatarRegistry: i, needOverlapCheck: r } = s;
    this._avatarProcessor = new J(this, e, i), this._transformProcessor = new W(this), this._profileProcessor = new Q(this, e), this._audioProcessor = new k(this), this._opacityHandler = new Z(this, e, {
      needOverlapCheck: r
    }), this.playerEntity = new pc.Entity(`RemotePlayer_${t}`), e.pcApp.root.addChild(this.playerEntity);
  }
  get avatarContainerEntity() {
    return this._avatarContainerEntity;
  }
  get avatarBoundingBox() {
    return this._avatarProcessor.boundingBox;
  }
  get activeAvatar() {
    return this._avatarProcessor.avatar;
  }
  get isSitting() {
    return this._avatarProcessor.isSitting;
  }
  get cellId() {
    return this._transformProcessor.cellId;
  }
  get profile() {
    return this._profileProcessor.getFormattedProfile();
  }
  get useAvatarModule() {
    return this._useAvatarModule;
  }
  _handleAvatarData(e) {
    this._createAvatarContainer(), this._avatarProcessor.process(e);
  }
  _handleTransformData(e) {
    this._transformProcessor.process(e);
  }
  _handleProfileData(e) {
    this._profileProcessor.process(e);
  }
  handleMessage(e) {
    const { payload: t } = e, { avatar: s, transform: i, profile: r } = t.data;
    s && this._handleAvatarData(s), i && this._handleTransformData(i), r && this._handleProfileData(r);
  }
  update(e) {
    this._avatarProcessor.update(e), this._transformProcessor.update(e), this._profileProcessor.update(), this._audioProcessor.update(), this._opacityHandler.update(e);
  }
  _createAvatarContainer() {
    return this._avatarContainerEntity ? this._avatarContainerEntity : (this._avatarContainerEntity = new pc.Entity(`AvatarContainer_${this.sessionId}`), this.playerEntity.addChild(this._avatarContainerEntity), this._avatarContainerEntity);
  }
  _createFallbackGripBone() {
    const e = this._avatarContainerEntity || this.playerEntity;
    if (!e) return null;
    const t = this.activeAvatar?.boundingBox || null;
    return this._fallbackGripBone ? (this._fallbackGripBone.reparent(e), D(this._fallbackGripBone, t)) : this._fallbackGripBone = x(
      e,
      t,
      `RemotePlayerGripBone_${this.sessionId}`
    ), this._fallbackGripBone;
  }
  getGripBone() {
    if (!this._useAvatarModule)
      return this.playerEntity;
    const e = this.activeAvatar;
    return !e?.entity ? null : e.getBoneEntity?.("rightHand") || e.getBoneEntity?.("leftHand") || this._createFallbackGripBone();
  }
  setAudioStream(e) {
    this._audioProcessor.setStream(e);
  }
  onTalkingStateChanged(e) {
    this.emit("remote-player:audio-talking", e), this.activeAvatar?.setTalking?.(e);
  }
  destroy() {
    this._avatarProcessor.destroy(), this._profileProcessor.destroy(), this._audioProcessor.destroy(), this._opacityHandler.destroy(), this._fallbackGripBone && (this._fallbackGripBone.destroy(), this._fallbackGripBone = null), this.playerEntity.destroy();
  }
}
class te {
  _manager;
  _calcBoundingBoxA = new pc.BoundingBox();
  _calcBoundingBoxB = new pc.BoundingBox();
  _overlappingPlayerIds = /* @__PURE__ */ new Set();
  _prevOverlappingPlayerIds = /* @__PURE__ */ new Set();
  constructor(e) {
    this._manager = e;
  }
  _convertBoundingBox(e, t, s) {
    const i = e.playerEntity.getPosition(), { capsuleHeight: r, capsuleRadius: _ } = L(t, i), n = _ * 0.75;
    s.halfExtents.set(n, r / 2, n);
    const a = t.center.y - t.halfExtents.y + s.halfExtents.y;
    return s.center.set(t.center.x, a, t.center.z), s;
  }
  _getRemoteAvatarBox(e, t) {
    const s = e.avatarBoundingBox;
    return s ? this._convertBoundingBox(e, s, t) : null;
  }
  _notifyOverlapping(e, t) {
    const s = this._manager.players.get(e);
    s && s.emit("remote-avatar:overlapping", t);
  }
  _swapOverlappingSets() {
    this._prevOverlappingPlayerIds.clear(), this._overlappingPlayerIds.forEach((e) => this._prevOverlappingPlayerIds.add(e)), this._overlappingPlayerIds.clear();
  }
  _checkOverlapWithLocalPlayer(e) {
    const s = this._manager.system.viverseApp.systems.localPlayer;
    if (!s) return !1;
    const i = s.store, { boundingBox: r } = i.getState();
    return r ? e.intersects(r) : !1;
  }
  _checkCellForOverlaps(e) {
    for (let t = 0; t < e.length; t++) {
      const s = e[t];
      if (this._overlappingPlayerIds.has(s.sessionId)) continue;
      const i = this._getRemoteAvatarBox(s, this._calcBoundingBoxA);
      if (i === null) continue;
      if (this._checkOverlapWithLocalPlayer(i)) {
        this._overlappingPlayerIds.add(s.sessionId);
        continue;
      }
      for (let _ = t + 1; _ < e.length; _++) {
        const n = e[_];
        if (this._overlappingPlayerIds.has(n.sessionId) || s.sessionId === n.sessionId) continue;
        const l = this._getRemoteAvatarBox(n, this._calcBoundingBoxB);
        if (l === null) continue;
        if (i.intersects(l)) {
          this._overlappingPlayerIds.add(s.sessionId), this._overlappingPlayerIds.add(n.sessionId);
          break;
        }
      }
    }
  }
  _detectOverlaps() {
    this._manager.cellsMap.forEach((e) => {
      this._checkCellForOverlaps(e);
    });
  }
  _notifyOverlapChanges() {
    for (const e of this._overlappingPlayerIds)
      this._prevOverlappingPlayerIds.has(e) || this._notifyOverlapping(e, !0);
    for (const e of this._prevOverlappingPlayerIds)
      this._overlappingPlayerIds.has(e) || this._notifyOverlapping(e, !1);
  }
  update() {
    this._swapOverlappingSets(), this._detectOverlaps(), this._notifyOverlapChanges();
  }
}
class se {
  cellsMap = /* @__PURE__ */ new Map();
  _playerListeners = /* @__PURE__ */ new Map();
  constructor(e) {
  }
  setupPlayer(e) {
    this._addPlayerToCell(e, e.cellId);
    const t = (s, i) => {
      this._onPlayerCellChanged(e, s, i);
    };
    this._playerListeners.set(e, t), e.on("remote-player:cell-changed", t);
  }
  removePlayer(e) {
    this._removePlayerFromCell(e, e.cellId);
    const t = this._playerListeners.get(e);
    t && (e.off("remote-player:cell-changed", t), this._playerListeners.delete(e));
  }
  _addPlayerToCell(e, t) {
    let s = this.cellsMap.get(t);
    s || (s = [], this.cellsMap.set(t, s)), s.includes(e) || s.push(e);
  }
  _removePlayerFromCell(e, t) {
    const s = this.cellsMap.get(t);
    if (!s) return;
    const i = s.indexOf(e);
    i > -1 && s.splice(i, 1), s.length === 0 && this.cellsMap.delete(t);
  }
  _onPlayerCellChanged(e, t, s) {
    this._removePlayerFromCell(e, s), this._addPlayerToCell(e, t);
  }
}
class ie {
  players = /* @__PURE__ */ new Map();
  system;
  _avatarRegistry = {};
  _viverseApp;
  _avatarFadeOnOverlap;
  _pendingStreams = /* @__PURE__ */ new Map();
  _overlapHandler;
  _cellsMapHandler;
  constructor(e, t) {
    this.system = e, this._viverseApp = e.viverseApp, this._avatarFadeOnOverlap = t.avatarFadeOnOverlap, this._overlapHandler = new te(this), this._cellsMapHandler = new se(this), this._registerAvatars(t.avatarClasses), this.system.viverseApp.on(
      "multiplayer:remote-stream-updated",
      this._handleRemoteStreamUpdated,
      this
    );
  }
  get cellsMap() {
    return this._cellsMapHandler.cellsMap;
  }
  get profiles() {
    return Object.fromEntries(
      Array.from(this.players.entries()).map(([e, t]) => [e, t.profile])
    );
  }
  _registerAvatars(e) {
    e.forEach((t) => {
      this._avatarRegistry[t.avatarType] = t;
    });
  }
  _handleProfileUpdated(e) {
    this.system.emit("multiplayer:remote-profile-updated", e);
  }
  _createRemotePlayer(e) {
    const t = new ee(this._viverseApp, e, {
      avatarRegistry: this._avatarRegistry,
      needOverlapCheck: this._avatarFadeOnOverlap
    });
    this.players.set(e, t);
    const s = this._pendingStreams.get(e);
    return s && (t.setAudioStream(s), this._pendingStreams.delete(e)), this._cellsMapHandler.setupPlayer(t), t.on("remote-profile:updated", this._handleProfileUpdated, this), this.system.emit("multiplayer:remote-player-added", t), t;
  }
  handleMessageReceived(e) {
    const { userSessionId: t } = e;
    let s = this.players.get(t);
    s || (s = this._createRemotePlayer(t)), s.handleMessage(e);
  }
  removePlayer(e) {
    const t = this.players.get(e);
    t && (this.system.emit("multiplayer:before-remove-remote-player", t), t.off("remote-profile:updated", this._handleProfileUpdated, this), this._cellsMapHandler.removePlayer(t), t.destroy(), this.players.delete(e), this.system.emit("multiplayer:remote-player-removed", t)), this._pendingStreams.delete(e);
  }
  update(e) {
    this.players.forEach((t) => t.update(e)), this._overlapHandler.update();
  }
  destroy() {
    this.system.viverseApp.off(
      "multiplayer:remote-stream-updated",
      this._handleRemoteStreamUpdated,
      this
    ), this.players.forEach((e) => {
      e.destroy();
    }), this.players.clear(), this._pendingStreams.clear();
  }
  _handleRemoteStreamUpdated(e, t) {
    const s = this.players.get(e);
    s ? s.setAudioStream(t) : t ? this._pendingStreams.set(e, t) : this._pendingStreams.delete(e);
  }
}
class I {
  _system;
  _module;
  _mySessionId;
  _interactionType;
  _eventNames;
  _pendingRequest = null;
  _itemOwners = /* @__PURE__ */ new Map();
  _playerItems = /* @__PURE__ */ new Map();
  constructor(e, t, s, i) {
    this._system = e, this._module = t, this._mySessionId = t.sessionId, this._interactionType = s, this._eventNames = i, this._bindEvents();
  }
  _bindEvents() {
    const e = this._system.viverseApp;
    e.on(this._eventNames.request, this._handleRequest, this), e.on(this._eventNames.release, this._handleRelease, this);
  }
  _unbindEvents() {
    const e = this._system.viverseApp;
    e.off(this._eventNames.request, this._handleRequest, this), e.off(this._eventNames.release, this._handleRelease, this);
  }
  _releaseOwnedItems(e) {
    const t = this._playerItems.get(e);
    t && this._releaseItem(t), this._playerItems.delete(e);
  }
  handleRemotePlayerAdded(e) {
  }
  handleRemotePlayerRemoved(e) {
    this._releaseOwnedItems(e.sessionId);
  }
  _hasNoOwner(e) {
    return (this._itemOwners.get(e) ?? null) === null;
  }
  _acquireItem(e, t) {
    this._itemOwners.set(e, t), this._playerItems.set(t, e), this._pendingRequest === e && (this._pendingRequest = null), t === this._mySessionId ? this._emitLocalAcquired(e) : this._emitRemoteAcquired(e, t);
  }
  _releaseItem(e) {
    const t = this._itemOwners.get(e) ?? null, s = t === this._mySessionId;
    t && this._playerItems.delete(t), this._pendingRequest === e && (this._pendingRequest = null), this._itemOwners.set(e, null), s ? this._emitLocalReleased(e) : this._emitRemoteReleased(e, t);
  }
  _processHeartbeat(e, t) {
    this._itemOwners.get(e) !== t && (t === null ? this._releaseItem(e) : this._acquireItem(e, t));
  }
  _sendMessage(e) {
    const t = {
      type: "interactable-items",
      data: { items: e }
    };
    this._module.sendSystemMessage(t);
  }
  _sendCompetition(e, t) {
    this._module.sendCompetition("interaction", e, t);
  }
  _handleRequest(e) {
    this._pendingRequest = e, this._sendCompetition(this._interactionType, e);
  }
  _handleRelease(e) {
    const t = this._mySessionId;
    this._itemOwners.get(e) === t && (this._releaseItem(e), this._sendMessage([
      {
        itemName: e,
        ownerId: t,
        timestamp: Date.now(),
        action: "release",
        interactionType: this._interactionType
      }
    ]));
  }
  handleCompetition(e) {
    const { actionMsg: t, actionId: s, successor: i } = e;
    t === this._interactionType && this._hasNoOwner(s) && this._acquireItem(s, i);
  }
  handleMessageReceived(e) {
    const { interactionType: t, action: s, itemName: i, ownerId: r } = e;
    t === this._interactionType && (s === "release" ? this._releaseItem(i) : s === "heartbeat" && this._processHeartbeat(i, r));
  }
  cleanupStaleItems() {
    for (const [e, t] of this._itemOwners)
      t === null && this._itemOwners.delete(e);
  }
  gatherHeartbeatPayload() {
    const e = [];
    return this._itemOwners.forEach((t, s) => {
      e.push({
        itemName: s,
        ownerId: t,
        timestamp: Date.now(),
        action: "heartbeat",
        interactionType: this._interactionType
      });
    }), e;
  }
  retryPendingRequest() {
    this._pendingRequest && this._sendCompetition(this._interactionType, this._pendingRequest);
  }
  destroy() {
    this._itemOwners.clear(), this._playerItems.clear(), this._unbindEvents();
  }
}
class ae extends I {
  constructor(e, t) {
    super(e, t, "sit", {
      request: "interaction-network:request-seat",
      release: "interaction-network:leave-seat"
    });
  }
  _emitLocalAcquired(e) {
    this._system.viverseApp.emit("interaction-network:seat-acquired", {
      itemName: e,
      isLocal: !0
    });
  }
  _emitRemoteAcquired(e, t) {
    this._system.viverseApp.emit("interaction-network:seat-acquired", {
      itemName: e,
      isLocal: !1,
      ownerId: t
    });
  }
  _emitLocalReleased(e) {
    this._system.viverseApp.emit("interaction-network:seat-released", {
      itemName: e,
      isLocal: !0
    });
  }
  _emitRemoteReleased(e) {
    this._system.viverseApp.emit("interaction-network:seat-released", {
      itemName: e,
      isLocal: !1
    });
  }
}
class ne extends I {
  _avatarChangeListeners = /* @__PURE__ */ new Map();
  constructor(e, t) {
    super(e, t, "pick", {
      request: "interaction-network:request-pickable-item",
      release: "interaction-network:drop-pickable-item"
    });
  }
  _emitLocalAcquired(e) {
    this._system.viverseApp.emit("interaction-network:pickable-item-acquired", {
      itemName: e,
      isLocal: !0
    });
  }
  _emitRemoteAcquired(e, t) {
    const s = this._getGripBone(t);
    s && this._system.viverseApp.emit("interaction-network:pickable-item-acquired", {
      itemName: e,
      isLocal: !1,
      ownerId: t,
      gripBone: s
    });
  }
  _emitLocalReleased(e) {
    this._system.viverseApp.emit("interaction-network:pickable-item-released", {
      itemName: e,
      isLocal: !0
    });
  }
  _emitRemoteReleased(e, t) {
    const s = t ? this._module.getRemotePlayer(t) : null, { avatarContainerEntity: i, playerEntity: r } = s || {}, _ = i || r, n = this._system.pcApp.root;
    this._system.viverseApp.emit("interaction-network:pickable-item-released", {
      itemName: e,
      isLocal: !1,
      targetEntity: _ || n
    });
  }
  handleRemotePlayerAdded(e) {
    if (super.handleRemotePlayerAdded(e), e.useAvatarModule) {
      const t = () => {
        const s = this._playerItems.get(e.sessionId);
        s && this._emitRemoteAcquired(s, e.sessionId);
      };
      this._avatarChangeListeners.set(e.sessionId, t), e.on("remote-avatar:changed", t, this);
    } else {
      const t = this._playerItems.get(e.sessionId);
      t && this._emitRemoteAcquired(t, e.sessionId);
    }
  }
  handleRemotePlayerRemoved(e) {
    super.handleRemotePlayerRemoved(e);
    const t = this._avatarChangeListeners.get(e.sessionId);
    t && (e.off("remote-avatar:changed", t, this), this._avatarChangeListeners.delete(e.sessionId));
  }
  _getGripBone(e) {
    const t = this._module.getRemotePlayer(e);
    return t ? t.getGripBone() : null;
  }
}
class re {
  _system;
  _module;
  _syncInterval = 3e3;
  _lastSyncTime = 0;
  _cleanupInterval = 1e4;
  _lastCleanupTime = 0;
  _pendingRequestInterval = 5e3;
  _lastPendingRequestTime = 0;
  _sitNetworkHandler;
  _pickNetworkHandler;
  _handlers = /* @__PURE__ */ new Map();
  constructor(e, t) {
    this._system = e, this._module = t, this._sitNetworkHandler = new ae(e, t), this._pickNetworkHandler = new ne(e, t), this._handlers.set("sit", this._sitNetworkHandler), this._handlers.set("pick", this._pickNetworkHandler), this._bindEvents();
  }
  _bindEvents() {
    this._system.on("multiplayer:remote-player-added", this._onRemotePlayerAdded, this), this._system.on("multiplayer:before-remove-remote-player", this._onRemotePlayerRemoved, this);
  }
  _unbindEvents() {
    this._system.off("multiplayer:remote-player-added", this._onRemotePlayerAdded, this), this._system.off("multiplayer:before-remove-remote-player", this._onRemotePlayerRemoved, this);
  }
  _onRemotePlayerAdded(e) {
    this._handlers.forEach((t) => t.handleRemotePlayerAdded(e));
  }
  _onRemotePlayerRemoved(e) {
    this._handlers.forEach((t) => t.handleRemotePlayerRemoved(e));
  }
  handleMessageReceived(e) {
    const { items: t = [] } = e.payload.data;
    for (const s of t)
      this._handlers.get(s.interactionType)?.handleMessageReceived(s);
  }
  handleCompetitionReceived(e) {
    if (e.actionName !== "interaction") return;
    this._handlers.get(e.actionMsg)?.handleCompetition(e);
  }
  _gatherHeartbeatPayload() {
    return [...this._handlers.values()].flatMap((e) => e.gatherHeartbeatPayload());
  }
  _sendPeriodicPayload() {
    if (!this._module.checkIsMasterUser()) return;
    const t = this._gatherHeartbeatPayload();
    t.length !== 0 && this._sendSystemMessage({
      items: t
    });
  }
  _sendSystemMessage(e) {
    const t = {
      type: "interactable-items",
      data: e
    };
    this._module.sendSystemMessage(t);
  }
  _cleanupStaleItems() {
    this._handlers.forEach((e) => e.cleanupStaleItems());
  }
  _retryPendingRequests() {
    this._handlers.forEach((e) => e.retryPendingRequest());
  }
  update(e) {
    this._lastSyncTime += e * 1e3, this._lastSyncTime >= this._syncInterval && (this._lastSyncTime = 0, this._sendPeriodicPayload()), this._lastCleanupTime += e * 1e3, this._lastCleanupTime >= this._cleanupInterval && (this._lastCleanupTime = 0, this._cleanupStaleItems()), this._lastPendingRequestTime += e * 1e3, this._lastPendingRequestTime >= this._pendingRequestInterval && (this._lastPendingRequestTime = 0, this._retryPendingRequests());
  }
  destroy() {
    this._unbindEvents(), this._handlers.forEach((e) => e.destroy());
  }
}
class oe {
  system;
  constructor(e) {
    this.system = e;
  }
  handleMessageReceived(e) {
    const { payload: t, clientTime: s } = e, { data: i } = t;
    i.typing && this.system.emit("chat:typing", {
      ...i.typing,
      userSessionId: e.userSessionId
    }), i.message && this.system.emit("chat:message-received", {
      ...i.message,
      id: e.messageId,
      userSessionId: e.userSessionId,
      timestamp: i.message.timestamp || s
    });
  }
  destroy() {
  }
}
class le {
  _system;
  _adapter;
  _isEnabled = !1;
  _isMuted = !1;
  _inputDevices = [];
  _outputDevices = [];
  _localStream = null;
  _remoteStreams = /* @__PURE__ */ new Map();
  constructor(e, t) {
    this._system = e, this._adapter = t.adapter, this._bindEvents(), this.refreshDevices().catch(() => {
    });
  }
  get isEnabled() {
    return this._isEnabled;
  }
  get isMuted() {
    return this._isMuted;
  }
  get inputDevices() {
    return this._inputDevices;
  }
  get outputDevices() {
    return this._outputDevices;
  }
  getLocalStream() {
    return this._localStream;
  }
  getRemoteStream(e) {
    return this._remoteStreams.get(e) || null;
  }
  _bindEvents() {
    this._adapter.onLocalAudioStream && this._adapter.onLocalAudioStream(this._handleLocalStreamUpdated.bind(this)), this._adapter.onRemoteAudioStream && this._adapter.onRemoteAudioStream(this._handleRemoteStreamUpdated.bind(this));
  }
  _handleLocalStreamUpdated(e) {
    this._localStream = e, this._system.viverseApp.emit("multiplayer:local-stream-updated", e);
  }
  _handleRemoteStreamUpdated(e, t) {
    e ? this._remoteStreams.set(t, e) : this._remoteStreams.delete(t), this._system.viverseApp.emit("multiplayer:remote-stream-updated", t, e);
  }
  async enable(e) {
    if (!this._adapter.enableAudio) {
      y.warn("Adapter does not support audio");
      return;
    }
    try {
      await this._adapter.enableAudio({ deviceId: e }), this._isEnabled = !0, this._system.emit("multiplayer:audio-enabled"), await this.refreshDevices();
    } catch (t) {
      throw y.error("Failed to enable audio", t), t;
    }
  }
  async disable() {
    if (this._adapter.disableAudio)
      try {
        await this._adapter.disableAudio(), this._isEnabled = !1, this._localStream = null, this._remoteStreams.clear(), this._system.emit("multiplayer:audio-disabled");
      } catch (e) {
        throw y.error("Failed to disable audio", e), e;
      }
  }
  async mute() {
    if (this._adapter.muteAudio)
      try {
        await this._adapter.muteAudio(), this._isMuted = !0;
      } catch (e) {
        throw y.error("Failed to mute audio", e), e;
      }
  }
  async unmute() {
    if (this._adapter.unmuteAudio)
      try {
        await this._adapter.unmuteAudio(), this._isMuted = !1;
      } catch (e) {
        throw y.error("Failed to unmute audio", e), e;
      }
  }
  async refreshDevices() {
    this._adapter.listAudioInputDevices && (this._inputDevices = await this._adapter.listAudioInputDevices()), this._adapter.listAudioOutputDevices && (this._outputDevices = await this._adapter.listAudioOutputDevices());
  }
  async requestPermission() {
    try {
      (await navigator.mediaDevices.getUserMedia({ audio: !0 })).getTracks().forEach((t) => t.stop()), await this.refreshDevices();
    } catch (e) {
      throw y.error("Failed to get microphone permission", e), e;
    }
  }
  async setInputDevice(e) {
    if (this._adapter.setAudioInputDevice)
      try {
        await this._adapter.setAudioInputDevice(e), this._system.emit("multiplayer:audio-input-changed", e);
      } catch (t) {
        throw y.error("Failed to set audio input device", t), t;
      }
  }
  async setOutputDevice(e) {
    if (this._adapter.setAudioOutputDevice)
      try {
        await this._adapter.setAudioOutputDevice(e), this._system.emit("multiplayer:audio-output-changed", e);
      } catch (t) {
        throw y.error("Failed to set audio output device", t), t;
      }
  }
  destroy() {
    this.disable().catch(() => {
    }), this._localStream = null, this._remoteStreams.clear();
  }
}
class _e extends H {
  static moduleName = C.Multiplayer;
  sessionId = crypto.randomUUID();
  sessionIds = /* @__PURE__ */ new Set();
  defaultRoomId;
  _adapter;
  _isInitialized = !1;
  _autoJoinDefaultRoom = !0;
  _remotePlayers;
  _interactableItems;
  _chat;
  _audio;
  _currentRoomId = null;
  constructor(e, t) {
    super(e);
    const s = this.system.viverseApp.appId || "default";
    this.defaultRoomId = `room-${s}`;
    const {
      adapter: i,
      avatarClasses: r = [],
      avatarFadeOnOverlap: _ = !0,
      autoJoinDefaultRoom: n = !0
    } = t || {};
    this._autoJoinDefaultRoom = n, this._adapter = i || new $(), this._bindAdapterEvents(), this._remotePlayers = new ie(this.system, {
      avatarClasses: r,
      avatarFadeOnOverlap: _
    }), this._interactableItems = new re(this.system, this), this._chat = new oe(this.system), this._audio = new le(this.system, this), this._bindEvents();
  }
  get adapter() {
    return this._adapter;
  }
  get remotePlayers() {
    return this._remotePlayers;
  }
  get interactableItems() {
    return this._interactableItems;
  }
  get chat() {
    return this._chat;
  }
  get audio() {
    return this._audio;
  }
  get currentRoomId() {
    return this._currentRoomId;
  }
  get isInitialized() {
    return this._isInitialized;
  }
  _bindAdapterEvents() {
    this._adapter.onConnected?.(this._handleConnected.bind(this)), this._adapter.onClientConnected?.(this._handleClientConnected.bind(this)), this._adapter.onClientDisconnected?.(this._handleClientDisconnected.bind(this)), this._adapter.onMessageReceived?.(this._handleMessageReceived.bind(this)), this._adapter.onCompetitionReceived?.(this._handleCompetitionReceived.bind(this));
  }
  _bindEvents() {
    this.viverseApp.on("multiplayer:send-system-message", this._handleSendSystemMessage, this), this.viverseApp.on("multiplayer:send-competition", this._handleSendCompetition, this);
  }
  _unbindEvents() {
    this.viverseApp.off("multiplayer:send-system-message", this._handleSendSystemMessage, this), this.viverseApp.off("multiplayer:send-competition", this._handleSendCompetition, this);
  }
  _handleConnected() {
    this.system.emit("multiplayer:connected");
  }
  _handleClientConnected(e) {
    this.sessionIds.add(e), this.system.emit("multiplayer:client-connected", e);
  }
  _handleClientDisconnected(e) {
    this._remotePlayers.removePlayer(e), this.sessionIds.delete(e), this.system.emit("multiplayer:client-disconnected", e);
  }
  _parseMessage(e) {
    return JSON.parse(e);
  }
  _handleMessageReceived(e) {
    const t = this._parseMessage(e), { messageType: s } = t;
    s === R.System ? (this._handleReceivedSystemMessage(t), this.viverseApp.emit("multiplayer:system-message-received", t)) : s === R.Custom && this.viverseApp.emit("multiplayer:custom-message-received", t);
  }
  _handleSendSystemMessage(e) {
    this.sendSystemMessage(e);
  }
  _handleSendCompetition(e, t, s) {
    this.sendCompetition(e, t, s);
  }
  async _initializeAdapter() {
    await this._adapter.initialize(this.system.viverseApp), this._autoJoinDefaultRoom && await this.joinDefaultRoom();
  }
  async initialize() {
    if (!this._isInitialized)
      try {
        this._initializeAdapter().then(() => {
          this._isInitialized = !0;
        });
      } catch (e) {
        y.error("Failed to setup the Multiplayer module:", e);
      }
  }
  getRemotePlayer(e) {
    return this._remotePlayers.players.get(e) || null;
  }
  checkIsMasterUser() {
    return this._adapter.checkIsMasterUser?.() ?? !1;
  }
  _handleReceivedSystemMessage(e) {
    const { payload: t } = e;
    t.type === "player" ? this._remotePlayers.handleMessageReceived({ ...e, payload: t }) : t.type === "interactable-items" ? this._interactableItems.handleMessageReceived({ ...e, payload: t }) : t.type === "chat" && this._chat.handleMessageReceived({ ...e, payload: t });
  }
  _formatMessage(e, t) {
    const s = {
      messageType: t,
      messageId: crypto.randomUUID(),
      userSessionId: this.sessionId,
      clientTime: Date.now(),
      payload: e
    };
    return JSON.stringify(s);
  }
  _send(e) {
    this._adapter.connected && this._adapter.sendMessage(e);
  }
  _handleCompetitionReceived(e) {
    e.actionName === "interaction" && this._interactableItems.handleCompetitionReceived(e), this.viverseApp.emit("multiplayer:competition-received", e);
  }
  sendCompetition(e, t, s) {
    this._adapter.connected && this._adapter.sendCompetition?.(e, t, s);
  }
  sendSystemMessage(e) {
    const t = this._formatMessage(e, R.System);
    this._send(t);
  }
  sendMessage(e) {
    const t = this._formatMessage(e, R.Custom);
    this._send(t);
  }
  async joinDefaultRoom() {
    await this.switchRoom(this.defaultRoomId);
  }
  async joinRoom(e, t) {
    await this._adapter.joinRoom(e, this.sessionId, t), this._currentRoomId = e;
  }
  async leaveRoom(e) {
    await this._adapter.leaveRoom(e), this._currentRoomId = null;
  }
  async switchRoom(e, t) {
    await this._adapter.switchRoom(e, this.sessionId, t), this._currentRoomId = e;
  }
  update(e) {
    this._remotePlayers.update(e), this._interactableItems.update(e);
  }
  destroy() {
    this._isInitialized = !1, this._adapter.destroy?.(), this._unbindEvents(), this._chat.destroy(), this._audio.destroy(), this._remotePlayers.destroy();
  }
}
export {
  _e as MultiplayerModule,
  de as NetworkSystem
};
