start working on physics, all over the place right now

This commit is contained in:
Evert Prants 2023-06-19 23:41:20 +03:00
parent f1509a3a64
commit 9c980bc725
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
22 changed files with 663 additions and 15 deletions

View File

@ -29,6 +29,8 @@
"@freeblox/engine": "workspace:^",
"three": "^0.153.0",
"vite-plugin-dts": "^2.3.0",
"vite-plugin-top-level-await": "^1.3.1",
"vite-plugin-wasm": "^3.2.2",
"vue": "^3.2.47"
},
"devDependencies": {

View File

@ -6,6 +6,7 @@ import {
LevelComponent,
Engine,
assetManager,
PhysicsWorldComponent,
} from '@freeblox/engine';
import { GameEvents } from '../types/events';
import { GameplayComponent } from './gameplay';
@ -21,6 +22,7 @@ export class Game extends Engine {
this.use(LevelComponent);
this.use(GameplayComponent);
this.use(MouseComponent);
this.use(PhysicsWorldComponent);
this.getComponent(ViewportComponent).setSizeFromViewport();
this.start();

View File

@ -28,6 +28,7 @@ export class GameplayComponent extends EngineComponent {
left: 0,
right: 0,
};
public jump = false;
private move = new Vector3();
private look = new Vector3();
@ -60,6 +61,10 @@ export class GameplayComponent extends EngineComponent {
if (this.move.length()) {
this.character?.setLook(this.move.clone().normalize());
}
if (this.jump) {
this.jump = false;
this.character?.jump();
}
}
override dispose(): void {
@ -98,6 +103,9 @@ export class GameplayComponent extends EngineComponent {
case 'KeyD':
this.movement.right = this.movementSpeed;
break;
case 'Space':
this.jump = true;
break;
}
};
const keyUpEvent = (event: KeyboardEvent) => {

View File

@ -1,16 +1,18 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import dts from 'vite-plugin-dts'
import dts from 'vite-plugin-dts';
import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), dts()],
plugins: [vue(), dts(), wasm(), topLevelAwait()],
build: {
lib: {
entry: 'src/index.ts',
name: 'Client',
fileName: 'client',
formats: ['es', 'cjs', 'umd']
formats: ['es', 'cjs', 'umd'],
},
rollupOptions: {
external: ['vue'],
@ -20,5 +22,5 @@ export default defineConfig({
},
},
},
}
},
});

View File

@ -22,6 +22,7 @@
"typescript": "^5.0.4"
},
"dependencies": {
"@dimforge/rapier3d": "^0.11.2",
"reflect-metadata": "^0.1.13",
"three": "^0.153.0"
}

View File

@ -2,3 +2,4 @@ export * from './environment';
export * from './viewport';
export * from './mouse';
export * from './level';
export * from './physicsworld';

View File

@ -0,0 +1,154 @@
import { SkinnedMesh, Vector3 } from 'three';
import { EngineComponent } from '../types/engine-component';
import { World } from '../gameobjects/world.object';
import {
PhysicsObjectAssociation,
getRapier,
ColliderFactory,
HumanoidPhysicsProxy,
} from '../physics';
import { Brick } from '../gameobjects/brick.object';
import type Rapier from '@dimforge/rapier3d';
import { Humanoid } from '../gameobjects/humanoid.object';
export class PhysicsWorldComponent extends EngineComponent {
public name = PhysicsWorldComponent.name;
private world!: World;
private physicsWorld!: Rapier.World;
private physicsEngine!: typeof Rapier;
private characterPhysics!: Rapier.KinematicCharacterController;
private characterRay!: Rapier.Ray;
private initEventFiredBeforeEngineLoad = false;
private cleanUpEvents?: Function;
private sceneInitialized = false;
private trackedObjects: PhysicsObjectAssociation[] = [];
initialize(): void {
this.world = this.renderer.scene.getObjectByName('World') as World;
this.cleanUpEvents = this.bindEvents();
this.createRapier();
}
update(delta: number): void {
// FIXME: physics is tied to the FPS
this.physicsWorld?.step();
for (const object of this.trackedObjects) object.tick(delta);
}
dispose(): void {
this.cleanUpEvents?.call(this);
this.physicsWorld.removeCharacterController(this.characterPhysics);
}
private createRapier() {
getRapier().then((R) => {
const gravity = new Vector3(0, this.world.gravity, 0);
const world = new R.World(gravity);
this.physicsWorld = world;
this.physicsEngine = R;
if (this.initEventFiredBeforeEngineLoad) {
this.initEventFiredBeforeEngineLoad = false;
setTimeout(() => this.initializePhysicsScene(), 500); // FIXME
}
});
}
private bindEvents() {
const initializeEvent = () => {
if (!this.physicsWorld) {
this.initEventFiredBeforeEngineLoad = true;
return;
}
setTimeout(() => this.initializePhysicsScene(), 500); // FIXME
};
this.events.addListener('initialized', initializeEvent);
return () => {
this.events.removeEventListener('initialized', initializeEvent);
};
}
private applyPhysics(object: Brick) {
// This object has effecively no physics:
// doesn't move, doesn't collide
if (object.anchored && !object.canCollide) return;
let bodyDesc: Rapier.RigidBodyDesc;
if (object.anchored) bodyDesc = this.physicsEngine.RigidBodyDesc.fixed();
else bodyDesc = this.physicsEngine.RigidBodyDesc.dynamic();
bodyDesc
.setTranslation(...object.position.toArray())
.setRotation(object.quaternion);
const body = this.physicsWorld.createRigidBody(bodyDesc);
let collider: Rapier.Collider | undefined;
if (object.canCollide) {
collider = ColliderFactory.createCollider(
object,
this.physicsEngine,
this.physicsWorld,
body
);
}
const tracker = new PhysicsObjectAssociation(object, collider, body);
console.log(tracker);
this.trackedObjects.push(tracker);
return tracker;
}
private applyHumanoidPhysics(humanoid: Humanoid) {
const halfVec = new Vector3(0, humanoid.characterHalfHeight, 0);
const colliderDesc = this.physicsEngine.ColliderDesc.cuboid(
1,
humanoid.characterHalfHeight,
0.5
);
const rigidBodyDesc =
this.physicsEngine.RigidBodyDesc.kinematicPositionBased();
const rigidBody = this.physicsWorld.createRigidBody(rigidBodyDesc);
const collider = this.physicsWorld.createCollider(colliderDesc, rigidBody);
rigidBody.setTranslation(humanoid.parent!.position.clone(), true);
rigidBody.setRotation(humanoid.parent!.quaternion, true);
collider.setTranslationWrtParent(halfVec);
const proxy = new HumanoidPhysicsProxy(
humanoid,
this.characterPhysics,
this.characterRay,
this.physicsWorld,
collider,
rigidBody
);
this.trackedObjects.push(proxy);
humanoid.setPhysics(proxy);
console.log('set physics', proxy);
}
private async initializePhysicsScene() {
if (this.sceneInitialized) return;
console.log('init scene');
this.characterRay = new this.physicsEngine.Ray(
{ x: 0, y: 0, z: 0 },
{ x: 0, y: -0.5, z: 0 }
);
this.characterPhysics = this.physicsWorld.createCharacterController(0.01);
this.characterPhysics.setApplyImpulsesToDynamicBodies(true);
this.characterPhysics.setMaxSlopeClimbAngle((75 * Math.PI) / 180);
// Automatically slide down on slopes smaller than 30 degrees.
// this.characterPhysics.setMinSlopeSlideAngle((30 * Math.PI) / 180);
this.world.traverse((object) => {
if (object instanceof Humanoid) return this.applyHumanoidPhysics(object);
if (!(object instanceof Brick)) return;
// Do not apply physics to animated objects
if ((object.getMesh() as SkinnedMesh).skeleton) return;
this.applyPhysics(object);
});
this.sceneInitialized = true;
}
}

View File

@ -74,4 +74,12 @@ export class Brick extends GameObject3D {
this.name = this.objectType;
this.add(this.mesh);
}
getGeometry() {
return this.geometry;
}
getMesh() {
return this.mesh;
}
}

View File

@ -11,9 +11,11 @@ import { GameObject } from '../types/game-object';
import { Ticking } from '../types/ticking';
import { EditorProperty } from '../decorators/property';
import { MeshPart } from './mesh.object';
import { clamp } from 'three/src/math/MathUtils.js';
import { clamp, lerp } from 'three/src/math/MathUtils.js';
import { NameTag } from './nametag.object';
import { CanvasUtils } from '../canvas/utils';
import { Disposable } from '../types/disposable';
import { HumanoidPhysicsProxy } from '../physics';
export type HumanoidBodyPart =
| 'Head'
@ -23,7 +25,7 @@ export type HumanoidBodyPart =
| 'LegRight'
| 'LegLeft';
export class Humanoid extends GameObject implements Ticking {
export class Humanoid extends GameObject implements Ticking, Disposable {
public isTickingObject = true;
public objectType = 'Humanoid';
public name = 'Humanoid';
@ -32,9 +34,12 @@ export class Humanoid extends GameObject implements Ticking {
private _health = 100;
private _maxHealth = 100;
private _velocity = new Vector3(0, 0, 0);
private _appliedGravity = new Vector3(0, 0, 0);
private _grounded = true;
private _lookAt = new Vector3(0, 0, 1);
private _currentLookAt = new Vector3(0, 0, 1);
private _animState = 0;
private _jumpEnergy = 0;
public static bodyPartNames = [
'Head',
'Torso',
@ -63,11 +68,18 @@ export class Humanoid extends GameObject implements Ticking {
textBorderSize: 1,
});
public characterHeight = 5.5;
public characterHalfHeight = this.characterHeight / 2;
public jumpPower = 18;
private mixer!: AnimationMixer;
private idleAction!: AnimationAction;
private walkAction!: AnimationAction;
private jumpAction!: AnimationAction;
private nameTag?: NameTag;
private physics?: HumanoidPhysicsProxy;
@EditorProperty({ type: Number })
get health() {
@ -95,6 +107,16 @@ export class Humanoid extends GameObject implements Ticking {
return this.health > 0;
}
get grounded() {
return this._grounded;
}
set grounded(value: boolean) {
if (value && this._jumpEnergy < this.jumpPower / 2) {
this._jumpEnergy = 0;
}
this._grounded = value;
}
private get bodyParts() {
return Humanoid.bodyPartNames.map((key) => this.getBodyPartByName(key));
}
@ -123,8 +145,10 @@ export class Humanoid extends GameObject implements Ticking {
const idleClip = AnimationClip.findByName(this.parent.animations, 'Idle');
const walkClip = AnimationClip.findByName(this.parent.animations, 'Walk');
const jumpClip = AnimationClip.findByName(this.parent.animations, 'Jump');
this.idleAction = this.mixer.clipAction(idleClip);
this.walkAction = this.mixer.clipAction(walkClip);
this.jumpAction = this.mixer.clipAction(jumpClip);
this.idleAction.play();
this.createNameTag();
@ -140,14 +164,40 @@ export class Humanoid extends GameObject implements Ticking {
this._lookAt.lerp(vector, 0.15);
}
jump() {
if (!this.grounded) return;
this.grounded = false;
this._jumpEnergy = this.jumpPower;
}
tick(dt: number): void {
if (!this.ready) return;
this.mixer.update(dt);
this.parent?.position.add(this._velocity.clone().multiplyScalar(dt));
if (!this.grounded) {
this._appliedGravity.y = -9.81;
} else {
this._appliedGravity.y = 0;
}
if (this._jumpEnergy > 0) {
this._appliedGravity.y += this._jumpEnergy;
this._jumpEnergy -= 10 * dt;
}
if (this.physics)
this.physics.applyMovement(
this.parent!.position,
this._velocity.clone().add(this._appliedGravity).multiplyScalar(dt)
);
else this.parent?.position.add(this._velocity.clone().multiplyScalar(dt));
this._currentLookAt.copy(this.parent!.position);
this._currentLookAt.add(this._lookAt);
this.parent?.lookAt(this._currentLookAt);
if (this.physics) {
this.physics.applyRotation(this.parent!.quaternion);
}
}
setWalkAnimationState(index: number) {
@ -197,4 +247,12 @@ export class Humanoid extends GameObject implements Ticking {
this.nameTag.position.set(0, 1.5, 0);
this.add(this.nameTag);
}
setPhysics(physics?: HumanoidPhysicsProxy) {
this.physics = physics;
}
dispose(): void {
this.nameTag?.dispose();
}
}

View File

@ -18,10 +18,6 @@ export class MeshPart extends Brick {
super(geometry, material, mesh);
}
getMesh() {
return this.mesh;
}
/** Do some surgery to convert a loaded SkinnedMesh into a game object */
static fromLoaded(loaded: SkinnedMesh) {
const newObject = new MeshPart(loaded.geometry, undefined, loaded);

View File

@ -1,8 +1,9 @@
import { Sprite, CanvasTexture, SpriteMaterial } from 'three';
import { CanvasUtils } from '../canvas';
import { GameObject } from '..';
import { Disposable } from '../types/disposable';
import { GameObject } from '../types/game-object';
export class NameTag extends GameObject {
export class NameTag extends GameObject implements Disposable {
public objectType = NameTag.name;
public virtual = true;
public archivable = false;

View File

@ -1,3 +1,4 @@
import { EditorProperty } from '..';
import { GameObject } from '../types/game-object';
export class World extends GameObject {
@ -5,8 +6,12 @@ export class World extends GameObject {
public name = 'World';
public virtual = true;
@EditorProperty({ type: Number })
public gravity = -9.81;
override get properties() {
return [];
const properties = super.properties;
return properties.filter((prop) => ['gravity'].includes(prop.name));
}
constructor() {

View File

@ -0,0 +1,160 @@
import {
Brick,
Cylinder,
Sphere,
Torus,
Capsule,
Wedge,
WedgeCorner,
WedgeInnerCorner,
} from '../gameobjects';
import type RAPIER from '@dimforge/rapier3d';
import { Instancable } from '../types/instancable';
import { Matrix4 } from 'three';
export class ColliderFactory {
static gameObjectColliders = [
{
instance: Cylinder,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const height = obj.scale.y / 2;
const radius = (obj.scale.x / 2 + obj.scale.z / 2) / 2;
const collider = factory.ColliderDesc.cylinder(height, radius);
return world.createCollider(collider, body);
},
},
{
instance: Sphere,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const radius = Math.max(obj.scale.x, obj.scale.y, obj.scale.z) / 2;
const collider = factory.ColliderDesc.ball(radius);
return world.createCollider(collider, body);
},
},
{
instance: Torus,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const height = obj.scale.y / 2;
const radius = (obj.scale.x / 2 + obj.scale.z / 2) / 2;
const collider = factory.ColliderDesc.roundCylinder(
height,
radius,
height
);
return world.createCollider(collider, body);
},
},
{
instance: Capsule,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const height = obj.scale.y / 2;
const radius = (obj.scale.x / 2 + obj.scale.z / 2) / 2;
const collider = factory.ColliderDesc.capsule(height, radius);
return world.createCollider(collider, body);
},
},
{
instance: Wedge,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const mat = new Matrix4();
mat.makeScale(...obj.scale.toArray());
const points = obj
.getGeometry()
.getAttribute('position')
.clone()
.applyMatrix4(mat)?.array as Float32Array;
const collider = factory.ColliderDesc.convexMesh(points)!;
return world.createCollider(collider, body);
},
},
{
instance: WedgeCorner,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const mat = new Matrix4();
mat.makeScale(...obj.scale.toArray());
const points = obj
.getGeometry()
.getAttribute('position')
.clone()
.applyMatrix4(mat)?.array as Float32Array;
const collider = factory.ColliderDesc.convexMesh(points)!;
return world.createCollider(collider, body);
},
},
{
instance: WedgeInnerCorner,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const mat = new Matrix4();
mat.makeScale(...obj.scale.toArray());
const points = obj
.getGeometry()
.getAttribute('position')
.clone()
.applyMatrix4(mat)?.array as Float32Array;
const collider = factory.ColliderDesc.convexMesh(points)!;
return world.createCollider(collider, body);
},
},
{
instance: Brick,
createCollisionShape: (
obj: Brick,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) => {
const scale = obj.scale.clone().divideScalar(2);
const collider = factory.ColliderDesc.cuboid(scale.x, scale.y, scale.z);
return world.createCollider(collider, body);
},
},
];
static createCollider<T extends Brick>(
obj: T,
factory: typeof RAPIER,
world: RAPIER.World,
body?: RAPIER.RigidBody
) {
const collider = ColliderFactory.gameObjectColliders.find(
(entry) => obj instanceof entry.instance
);
if (!collider) return undefined;
return collider.createCollisionShape(obj, factory, world, body);
}
}

View File

@ -0,0 +1,3 @@
export * from './rapier';
export * from './physics-object';
export * from './colliders';

View File

@ -0,0 +1,73 @@
import { Quaternion, Vector3 } from 'three';
import { GameObject3D } from '../types/game-object';
import { Ticking } from '../types/ticking';
import type { Humanoid } from '../gameobjects/humanoid.object';
import type Rapier from '@dimforge/rapier3d';
export class PhysicsObjectAssociation implements Ticking {
uuid: string;
isTickingObject = true;
constructor(
public object: GameObject3D,
public collider?: Rapier.Collider,
public body?: Rapier.RigidBody
) {
this.uuid = object.uuid;
}
initialize(): void {}
tick(dt: number): void {
if (!this.body) return;
this.object.position.copy(this.body.translation() as any);
this.object.quaternion.copy(this.body.rotation() as any);
}
}
export class HumanoidPhysicsProxy extends PhysicsObjectAssociation {
constructor(
private humanoid: Humanoid,
private controller: Rapier.KinematicCharacterController,
private ray: Rapier.Ray,
private world: Rapier.World,
collider: Rapier.Collider,
body: Rapier.RigidBody
) {
super(humanoid.parent! as GameObject3D, collider, body);
}
applyMovement(position: Vector3, velocity: Vector3) {
const vec3 = position.clone();
this.controller.computeColliderMovement(this.collider!, velocity);
const computed = this.controller.computedMovement();
vec3.copy(computed as Vector3);
// console.log(computed, position);
this.body?.setNextKinematicTranslation(vec3.add(position));
// After the collider movement calculation is done, we can read the
// collision events.
// for (let i = 0; i < this.controller.numComputedCollisions(); i++) {
// let collision = this.controller.computedCollision(i);
// // Do something with that collision information.
// console.log(collision);
// }
// this.collider?.setTranslation(colliderHalf);
// this.humanoid.parent!.position.copy(computed as Vector3).sub(halfVec);
vec3.copy(this.humanoid.parent!.position);
this.ray.origin = vec3;
this.ray.origin.y -= 0.01;
const hit = this.world.castRay(this.ray, 0.5, false);
this.humanoid.grounded = false;
if (hit) {
const point = this.ray.pointAt(hit.toi);
const diff = vec3.y - (point.y + 0.15);
if (diff < 0) {
this.humanoid.grounded = true;
}
}
}
applyRotation(quat: Quaternion) {
this.body?.setNextKinematicRotation(quat);
}
}

View File

@ -0,0 +1,5 @@
export type Rapier = typeof import('@dimforge/rapier3d');
export function getRapier() {
return import('@dimforge/rapier3d');
}

View File

@ -0,0 +1,3 @@
export interface Disposable {
dispose(): void;
}

View File

@ -1,8 +1,9 @@
import { Disposable } from './disposable';
import { Renderer } from '../core/renderer';
import { EventEmitter } from '../utils/events';
import { EngineEvents } from './events';
export abstract class EngineComponent {
export abstract class EngineComponent implements Disposable {
public abstract name: string;
constructor(

View File

@ -80,6 +80,7 @@ export type EngineEvents = {
instance: (event: InstanceEvent) => void;
sceneJoin: (event: Object3D) => void;
sceneLeave: (event: Object3D) => void;
queueFree: (event: Object3D) => void;
loadComplete: () => void;
initialized: () => void;
reset: () => void;

View File

@ -5,3 +5,4 @@ export * from './game-object';
export * from './instancable';
export * from './world-file';
export * from './asset';
export * from './disposable';

View File

@ -80,6 +80,7 @@ export const instanceCharacterObject = async (name: string) => {
controller.position.set(0, 4.75, 0);
controller.archivable = false;
baseObject.add(controller);
baseObject.position.set(0, 0.1, 0);
return baseObject;
};

View File

@ -98,6 +98,12 @@ importers:
vite-plugin-dts:
specifier: ^2.3.0
version: 2.3.0(vite@4.3.9)
vite-plugin-top-level-await:
specifier: ^1.3.1
version: 1.3.1(vite@4.3.9)
vite-plugin-wasm:
specifier: ^3.2.2
version: 3.2.2(vite@4.3.9)
vue:
specifier: ^3.2.47
version: 3.2.47
@ -160,6 +166,9 @@ importers:
packages/engine:
dependencies:
'@dimforge/rapier3d':
specifier: ^0.11.2
version: 0.11.2
reflect-metadata:
specifier: ^0.1.13
version: 0.1.13
@ -529,6 +538,10 @@ packages:
mime: 3.0.0
dev: true
/@dimforge/rapier3d@0.11.2:
resolution: {integrity: sha512-B+AKkPmtJxED3goMTGU8v0ju8hUAUQGLgghzCos4G4OeN9X+mJ5lfN2xtNA0n8tJRJk2YfsMk9BOj/6AN89Acg==}
dev: false
/@esbuild-kit/cjs-loader@2.4.2:
resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
dependencies:
@ -1322,6 +1335,16 @@ packages:
terser: 5.18.1
dev: true
/@rollup/plugin-virtual@3.0.1:
resolution: {integrity: sha512-fK8O0IL5+q+GrsMLuACVNk2x21g3yaw+sG2qn16SnUd3IlBsQyvWxLMGHmCmXRMecPjGRSZ/1LmZB4rjQm68og==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0
peerDependenciesMeta:
rollup:
optional: true
dev: false
/@rollup/plugin-wasm@6.1.3(rollup@3.23.0):
resolution: {integrity: sha512-7ItTTeyauE6lwdDtQWceEHZ9+txbi4RRy0mYPFn9BW7rD7YdgBDu7HTHsLtHrRzJc313RM/1m6GKgV3np/aEaw==}
engines: {node: '>=14.0.0'}
@ -1419,6 +1442,118 @@ packages:
- supports-color
dev: true
/@swc/core-darwin-arm64@1.3.65:
resolution: {integrity: sha512-fQIXZgr7CD/+1ADqrVbz/gHvSoIMmggHvPzguQjV8FggBuS9Efm1D1ZrdUSqptggKvuLLHMZf+49tENq8NWWcg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@swc/core-darwin-x64@1.3.65:
resolution: {integrity: sha512-kGuWP7OP9mwOiIcJpEVa+ydC3Wxf0fPQ1MK0hUIPFcR6tAUEdOvdAuCzP6U20RX/JbbgwfI/Qq6ugT7VL6omgg==}
engines: {node: '>=10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@swc/core-linux-arm-gnueabihf@1.3.65:
resolution: {integrity: sha512-Bjbzldp8n4mWSdAvBt4VuLiHlfFM5pyftjJvJnmSY4H1IzbxkByyT60OHOedcIPRiZveD8NJzUJqutqrgTmtLg==}
engines: {node: '>=10'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@swc/core-linux-arm64-gnu@1.3.65:
resolution: {integrity: sha512-GmxtcCymeQqEqT9n5mo857koRsUbEwmuijrBA4OeD5KOPW9gqAmUxr+ZgwgYHwyJ3CiN+UbK8uEqPsL6UVQmLg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@swc/core-linux-arm64-musl@1.3.65:
resolution: {integrity: sha512-yv9jP3gbfMsYrqswT2MwK5Q1+avSwRXAKo+LYUknTeoLQNNlukDfqSLHajNq23XrVDRP4B3Pjn7kaqjxRcihbg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@swc/core-linux-x64-gnu@1.3.65:
resolution: {integrity: sha512-GQkwysEPTlAOQ3jiTiedObzh6pBaf9RLaQqpGdCp+iKze9+BR+STBP0IIKhZDMPG/nWWNhrYFD/VMQxRoYPjfw==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@swc/core-linux-x64-musl@1.3.65:
resolution: {integrity: sha512-ETzhOhtDluYFK4x73OTM9gVTMyzGd2WeWGlCu3WoT1EPPUwCqQpcAqI3TfEcP1ljFDG0pPkpYzVpwNf8yjQElg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@swc/core-win32-arm64-msvc@1.3.65:
resolution: {integrity: sha512-3weD0I6F8bggN0KOnbZkvYC1PBrT5wrvohpvtgijRsODxjoWwztozjawJxF3rqgVqlSI/+nA+JkrN48e2cxJjQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@swc/core-win32-ia32-msvc@1.3.65:
resolution: {integrity: sha512-i6c3D7E9Ca41HteW3+hn1OKQfjIabc2P0p1mJRXBkn+igwb+Ba6gXJc7NqhrlF8uZsDhhcGZTsAqBBtfcfTuHQ==}
engines: {node: '>=10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@swc/core-win32-x64-msvc@1.3.65:
resolution: {integrity: sha512-tQ9hEDtwPZxQ2sYb2n8ypfmdMjobKAf6VSnChteLMktofU7o562op5pLS6D6QCP2AtL3lcwe1piTCgIhk4vmjA==}
engines: {node: '>=10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@swc/core@1.3.65:
resolution: {integrity: sha512-d5iDiKWf12FBo6h9Fro2pcnLK6HSPbyZ7A1U5iFNpRRx8XEd4uGdKtf5NoXJ3GDLQDLXnNSLA82Cl6SfrJ1lyw==}
engines: {node: '>=10'}
requiresBuild: true
peerDependencies:
'@swc/helpers': ^0.5.0
peerDependenciesMeta:
'@swc/helpers':
optional: true
optionalDependencies:
'@swc/core-darwin-arm64': 1.3.65
'@swc/core-darwin-x64': 1.3.65
'@swc/core-linux-arm-gnueabihf': 1.3.65
'@swc/core-linux-arm64-gnu': 1.3.65
'@swc/core-linux-arm64-musl': 1.3.65
'@swc/core-linux-x64-gnu': 1.3.65
'@swc/core-linux-x64-musl': 1.3.65
'@swc/core-win32-arm64-msvc': 1.3.65
'@swc/core-win32-ia32-msvc': 1.3.65
'@swc/core-win32-x64-msvc': 1.3.65
dev: false
/@tootallnate/once@2.0.0:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
@ -6655,6 +6790,11 @@ packages:
which-typed-array: 1.1.9
dev: true
/uuid@9.0.0:
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
hasBin: true
dev: false
/validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
dependencies:
@ -6790,6 +6930,20 @@ packages:
- supports-color
dev: true
/vite-plugin-top-level-await@1.3.1(vite@4.3.9):
resolution: {integrity: sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==}
peerDependencies:
vite: '>=2.8'
dependencies:
'@rollup/plugin-virtual': 3.0.1
'@swc/core': 1.3.65
uuid: 9.0.0
vite: 4.3.9(@types/node@18.0.0)(sass@1.62.1)
transitivePeerDependencies:
- '@swc/helpers'
- rollup
dev: false
/vite-plugin-vue-inspector@3.4.2(vite@4.3.9):
resolution: {integrity: sha512-q5OTkcZJqL78bwGJl1Zk8CNqtxZ9wP2udJYqyFIZzL1lTax0/oq7DhNkLrnPTxkJuf0QPZKdunb1vDyCByn4dQ==}
peerDependencies:
@ -6809,6 +6963,14 @@ packages:
- supports-color
dev: true
/vite-plugin-wasm@3.2.2(vite@4.3.9):
resolution: {integrity: sha512-cdbBUNR850AEoMd5nvLmnyeq63CSfoP1ctD/L2vLk/5+wsgAPlAVAzUK5nGKWO/jtehNlrSSHLteN+gFQw7VOA==}
peerDependencies:
vite: ^2 || ^3 || ^4
dependencies:
vite: 4.3.9(@types/node@18.0.0)(sass@1.62.1)
dev: false
/vite@4.3.9(@types/node@18.0.0)(sass@1.62.1):
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
engines: {node: ^14.18.0 || >=16.0.0}