@mml-io/3d-web-client-core 0.0.0-experimental-928ce80-20250424 → 0.0.0-experimental-c7dfa04-20250515

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,6 +59,7 @@ export declare class CameraManager {
59
59
  private easeOutExpo;
60
60
  updateAspect(aspect: number): void;
61
61
  recomputeFoV(immediately?: boolean): void;
62
+ isFlyCameraOn(): boolean;
62
63
  toggleFlyCamera(): void;
63
64
  get activeCamera(): PerspectiveCamera;
64
65
  update(): void;
@@ -12,6 +12,38 @@ import { CharacterModelLoader } from "./CharacterModelLoader";
12
12
  import { CharacterState } from "./CharacterState";
13
13
  import { LocalController } from "./LocalController";
14
14
  import { RemoteController } from "./RemoteController";
15
+ type SpawnPosition = {
16
+ x: number;
17
+ y: number;
18
+ z: number;
19
+ };
20
+ type SpawnPositionVariance = {
21
+ x: number;
22
+ y: number;
23
+ z: number;
24
+ };
25
+ type RespawnTrigger = {
26
+ minX: number;
27
+ maxX: number;
28
+ minY: number;
29
+ maxY: number;
30
+ minZ: number;
31
+ maxZ: number;
32
+ };
33
+ export type SpawnConfiguration = {
34
+ spawnPosition?: Partial<SpawnPosition>;
35
+ spawnPositionVariance?: Partial<SpawnPositionVariance>;
36
+ spawnYRotation?: number;
37
+ respawnTrigger?: Partial<RespawnTrigger>;
38
+ enableRespawnButton?: boolean;
39
+ };
40
+ export type SpawnConfigurationState = {
41
+ spawnPosition: SpawnPosition;
42
+ spawnPositionVariance: SpawnPositionVariance;
43
+ spawnYRotation: number;
44
+ respawnTrigger: RespawnTrigger;
45
+ enableRespawnButton: boolean;
46
+ };
15
47
  export type CharacterManagerConfig = {
16
48
  composer: Composer;
17
49
  characterModelLoader: CharacterModelLoader;
@@ -23,6 +55,7 @@ export type CharacterManagerConfig = {
23
55
  remoteUserStates: Map<number, CharacterState>;
24
56
  sendUpdate: (update: CharacterState) => void;
25
57
  animationConfig: AnimationConfig;
58
+ spawnConfiguration: SpawnConfigurationState;
26
59
  characterResolve: (clientId: number) => {
27
60
  username: string;
28
61
  characterDescription: CharacterDescription;
@@ -43,6 +76,7 @@ export declare class CharacterManager {
43
76
  private lastUpdateSentTime;
44
77
  constructor(config: CharacterManagerConfig);
45
78
  spawnLocalCharacter(id: number, username: string, characterDescription: CharacterDescription, spawnPosition?: Vector3, spawnRotation?: Euler): void;
79
+ createRespawnButton(): HTMLDivElement;
46
80
  setupTweakPane(tweakPane: TweakPane): void;
47
81
  spawnRemoteCharacter(id: number, username: string, characterDescription: CharacterDescription, spawnPosition?: Vector3, spawnRotation?: Euler): void;
48
82
  getLocalCharacterPositionAndRotation(): PositionAndRotation;
@@ -53,3 +87,4 @@ export declare class CharacterManager {
53
87
  respawnIfPresent(id: number): void;
54
88
  update(): void;
55
89
  }
90
+ export {};
@@ -5,6 +5,7 @@ import { KeyInputManager } from "../input/KeyInputManager";
5
5
  import { VirtualJoystick } from "../input/VirtualJoystick";
6
6
  import { TimeManager } from "../time/TimeManager";
7
7
  import { Character } from "./Character";
8
+ import { SpawnConfigurationState } from "./CharacterManager";
8
9
  import { CharacterState } from "./CharacterState";
9
10
  export type LocalControllerConfig = {
10
11
  id: number;
@@ -14,6 +15,7 @@ export type LocalControllerConfig = {
14
15
  virtualJoystick?: VirtualJoystick;
15
16
  cameraManager: CameraManager;
16
17
  timeManager: TimeManager;
18
+ spawnConfiguration: SpawnConfigurationState;
17
19
  };
18
20
  export declare class LocalController {
19
21
  private config;
@@ -70,7 +72,14 @@ export declare class LocalController {
70
72
  jumpReleased: boolean;
71
73
  networkState: CharacterState;
72
74
  private controlState;
75
+ private minimumX;
76
+ private maximumX;
77
+ private minimumY;
78
+ private maximumY;
79
+ private minimumZ;
80
+ private maximumZ;
73
81
  constructor(config: LocalControllerConfig);
82
+ updateSpawnConfig(spawnConfig: SpawnConfigurationState): void;
74
83
  update(): void;
75
84
  private getTargetAnimation;
76
85
  private updateRotationOffset;
@@ -85,5 +94,5 @@ export declare class LocalController {
85
94
  position: Vector3;
86
95
  } | null;
87
96
  private updateNetworkState;
88
- private resetPosition;
97
+ resetPosition(): void;
89
98
  }
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { CameraManager } from "./camera/CameraManager";
2
2
  export { CharacterDescription, AnimationConfig } from "./character/Character";
3
- export { CharacterManager } from "./character/CharacterManager";
3
+ export { CharacterManager, SpawnConfiguration, SpawnConfigurationState, } from "./character/CharacterManager";
4
4
  export * from "./character/url-position";
5
5
  export * from "./helpers/math-helpers";
6
6
  export { CharacterModelLoader } from "./character/CharacterModelLoader";
package/build/index.js CHANGED
@@ -431,6 +431,9 @@ var CameraManager = class {
431
431
  this.fov = this.targetFOV;
432
432
  }
433
433
  }
434
+ isFlyCameraOn() {
435
+ return this.isMainCameraActive === false && this.orbitControls.enabled === true;
436
+ }
434
437
  toggleFlyCamera() {
435
438
  this.isMainCameraActive = !this.isMainCameraActive;
436
439
  this.orbitControls.enabled = !this.isMainCameraActive;
@@ -1778,6 +1781,45 @@ var LocalController = class {
1778
1781
  rotation: { quaternionY: 0, quaternionW: 1 },
1779
1782
  state: 0 /* idle */
1780
1783
  };
1784
+ this.minimumX = this.config.spawnConfiguration.respawnTrigger.minX;
1785
+ this.maximumX = this.config.spawnConfiguration.respawnTrigger.maxX;
1786
+ this.minimumY = this.config.spawnConfiguration.respawnTrigger.minY;
1787
+ this.maximumY = this.config.spawnConfiguration.respawnTrigger.maxY;
1788
+ this.minimumZ = this.config.spawnConfiguration.respawnTrigger.minZ;
1789
+ this.maximumZ = this.config.spawnConfiguration.respawnTrigger.maxZ;
1790
+ const maxAbsSpawnX = Math.abs(this.config.spawnConfiguration.spawnPosition.x) + Math.abs(this.config.spawnConfiguration.spawnPositionVariance.x);
1791
+ const maxAbsSpawnY = Math.abs(this.config.spawnConfiguration.spawnPosition.y) + Math.abs(this.config.spawnConfiguration.spawnPositionVariance.y);
1792
+ const maxAbsSpawnZ = Math.abs(this.config.spawnConfiguration.spawnPosition.z) + Math.abs(this.config.spawnConfiguration.spawnPositionVariance.z);
1793
+ if (Math.abs(this.minimumX) < maxAbsSpawnX || Math.abs(this.maximumX) < maxAbsSpawnX) {
1794
+ this.minimumX = -maxAbsSpawnX - 1;
1795
+ this.maximumX = maxAbsSpawnX + 1;
1796
+ console.warn(
1797
+ "The respawnTrigger X values are out of the bounds of the spawnPosition + spawnPositionVariance. Please check your respawnTrigger config."
1798
+ );
1799
+ }
1800
+ if (Math.abs(this.minimumY) < maxAbsSpawnY || Math.abs(this.maximumY) < maxAbsSpawnY) {
1801
+ this.minimumY = -maxAbsSpawnY - 1;
1802
+ this.maximumY = maxAbsSpawnY + 1;
1803
+ console.warn(
1804
+ "The respawnTrigger Y values are out of the bounds of the spawnPosition + spawnPositionVariance. Please check your respawnTrigger config."
1805
+ );
1806
+ }
1807
+ if (Math.abs(this.minimumZ) < maxAbsSpawnZ) {
1808
+ this.minimumZ = -maxAbsSpawnZ - 1;
1809
+ this.maximumZ = maxAbsSpawnZ + 1;
1810
+ console.warn(
1811
+ "The respawnTrigger Z values are out of the bounds of the spawnPosition + spawnPositionVariance. Please check your respawnTrigger config."
1812
+ );
1813
+ }
1814
+ }
1815
+ updateSpawnConfig(spawnConfig) {
1816
+ this.config.spawnConfiguration = spawnConfig;
1817
+ this.minimumX = spawnConfig.respawnTrigger.minX;
1818
+ this.maximumX = spawnConfig.respawnTrigger.maxX;
1819
+ this.minimumY = spawnConfig.respawnTrigger.minY;
1820
+ this.maximumY = spawnConfig.respawnTrigger.maxY;
1821
+ this.minimumZ = spawnConfig.respawnTrigger.minZ;
1822
+ this.maximumZ = spawnConfig.respawnTrigger.maxZ;
1781
1823
  }
1782
1824
  update() {
1783
1825
  var _a, _b;
@@ -1804,7 +1846,13 @@ var LocalController = class {
1804
1846
  i
1805
1847
  );
1806
1848
  }
1807
- if (this.config.character.position.y < -100) {
1849
+ const outOfBounds = this.config.character.position.x < this.minimumX || // left
1850
+ this.config.character.position.x > this.maximumX || // right
1851
+ this.config.character.position.z < this.minimumZ || // back
1852
+ this.config.character.position.z > this.maximumZ || // front
1853
+ this.config.character.position.y < this.minimumY || // down
1854
+ this.config.character.position.y > this.maximumY;
1855
+ if (outOfBounds) {
1808
1856
  this.resetPosition();
1809
1857
  }
1810
1858
  this.updateNetworkState();
@@ -2063,8 +2111,34 @@ var LocalController = class {
2063
2111
  };
2064
2112
  }
2065
2113
  resetPosition() {
2114
+ const randomWithVariance = (value, variance) => {
2115
+ const min = value - variance;
2116
+ const max = value + variance;
2117
+ return Math.random() * (max - min) + min;
2118
+ };
2119
+ this.characterVelocity.x = 0;
2066
2120
  this.characterVelocity.y = 0;
2067
- this.config.character.position.y = 3;
2121
+ this.characterVelocity.z = 0;
2122
+ this.config.character.position.set(
2123
+ randomWithVariance(
2124
+ this.config.spawnConfiguration.spawnPosition.x,
2125
+ this.config.spawnConfiguration.spawnPositionVariance.x
2126
+ ),
2127
+ randomWithVariance(
2128
+ this.config.spawnConfiguration.spawnPosition.y,
2129
+ this.config.spawnConfiguration.spawnPositionVariance.y
2130
+ ),
2131
+ randomWithVariance(
2132
+ this.config.spawnConfiguration.spawnPosition.z,
2133
+ this.config.spawnConfiguration.spawnPositionVariance.z
2134
+ )
2135
+ );
2136
+ const respawnRotation = new Euler(
2137
+ 0,
2138
+ -this.config.spawnConfiguration.spawnYRotation * (Math.PI / 180),
2139
+ 0
2140
+ );
2141
+ this.config.character.rotation.set(respawnRotation.x, respawnRotation.y, respawnRotation.z);
2068
2142
  this.characterOnGround = false;
2069
2143
  this.doubleJumpUsed = false;
2070
2144
  this.jumpReleased = true;
@@ -2102,8 +2176,13 @@ var RemoteController = class {
2102
2176
  }
2103
2177
  updateFromNetwork(clientUpdate) {
2104
2178
  const { position, rotation, state } = clientUpdate;
2105
- this.config.character.position.lerp(new Vector37(position.x, position.y, position.z), 0.15);
2106
- const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
2179
+ const distanceSquared = this.config.character.position.distanceToSquared(position);
2180
+ if (distanceSquared > 5 * 5) {
2181
+ this.config.character.position.copy(position);
2182
+ } else {
2183
+ this.config.character.position.lerp(new Vector37(position.x, position.y, position.z), 0.15);
2184
+ }
2185
+ const rotationQuaternion = tempQuaternion.set(0, rotation.quaternionY, 0, rotation.quaternionW);
2107
2186
  this.config.character.quaternion.slerp(rotationQuaternion, 0.6);
2108
2187
  if (state !== this.currentAnimation) {
2109
2188
  this.currentAnimation = state;
@@ -2183,13 +2262,40 @@ var CharacterManager = class {
2183
2262
  keyInputManager: this.config.keyInputManager,
2184
2263
  virtualJoystick: this.config.virtualJoystick,
2185
2264
  cameraManager: this.config.cameraManager,
2186
- timeManager: this.config.timeManager
2265
+ timeManager: this.config.timeManager,
2266
+ spawnConfiguration: this.config.spawnConfiguration
2187
2267
  });
2188
2268
  this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
2189
2269
  this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
2190
2270
  this.group.add(character);
2191
2271
  this.localCharacterSpawned = true;
2192
2272
  }
2273
+ createRespawnButton() {
2274
+ const respawnButton = document.createElement("div");
2275
+ respawnButton.className = "respawn-button";
2276
+ respawnButton.textContent = "RESPAWN";
2277
+ respawnButton.addEventListener("click", () => {
2278
+ this.localController.resetPosition();
2279
+ });
2280
+ respawnButton.style.position = "absolute";
2281
+ respawnButton.style.top = "14px";
2282
+ respawnButton.style.left = "8px";
2283
+ respawnButton.style.zIndex = "102";
2284
+ respawnButton.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
2285
+ respawnButton.style.color = "#ffffff";
2286
+ respawnButton.style.borderRadius = "8px";
2287
+ respawnButton.style.border = "1px solid rgba(255, 255, 255, 0.21)";
2288
+ respawnButton.style.height = "22px";
2289
+ respawnButton.style.padding = "8px";
2290
+ respawnButton.style.cursor = "pointer";
2291
+ respawnButton.style.fontSize = "12px";
2292
+ respawnButton.style.fontFamily = "Helvetica, sans-serif";
2293
+ respawnButton.style.userSelect = "none";
2294
+ respawnButton.style.display = "flex";
2295
+ respawnButton.style.alignItems = "center";
2296
+ respawnButton.style.justifyContent = "center";
2297
+ return respawnButton;
2298
+ }
2193
2299
  setupTweakPane(tweakPane) {
2194
2300
  tweakPane.setupCharacterController(this.localController);
2195
2301
  }
@@ -2453,8 +2559,17 @@ var KeyInputManager = class {
2453
2559
  return this.keys.get(key) || false;
2454
2560
  }
2455
2561
  createKeyBinding(key, callback) {
2562
+ if (this.bindings.has(key)) {
2563
+ return;
2564
+ }
2456
2565
  this.bindings.set(key, callback);
2457
2566
  }
2567
+ removeKeyBinding(key) {
2568
+ if (!this.bindings.has(key)) {
2569
+ return;
2570
+ }
2571
+ this.bindings.delete(key);
2572
+ }
2458
2573
  isMovementKeyPressed() {
2459
2574
  return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
2460
2575
  }