@adatechnology/game-weapons-three 0.6.2 → 0.7.1

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.
package/dist/index.js CHANGED
@@ -5127,83 +5127,35 @@ function buildRound(kit, dims, shape) {
5127
5127
  return { group, radius: dims.caseDiameter / 2e3 };
5128
5128
  }
5129
5129
 
5130
+ // src/fx/viewmodel.ts
5131
+ import { createVfxRenderer } from "@adatechnology/game-vfx-three";
5132
+
5130
5133
  // src/fx/effects.ts
5131
- var PI12 = Math.PI;
5132
5134
  var FLASH_BY_CASE = { shell: 1.6, big: 2.6, tiny: 0.5, pistol: 0.8, rifle: 1.2 };
5133
- var FLASH_SECONDS = 0.055;
5134
- function createEffects(kit, scene, particles, random) {
5135
- const { THREE, M } = kit;
5136
- const light = new THREE.PointLight(16756832, 0, 3, 2);
5137
- scene.add(light);
5138
- let flash = null;
5139
- const buildFlash = (size) => {
5140
- const group = new THREE.Group();
5141
- const cone = new THREE.Mesh(new THREE.ConeGeometry(0.013 * size, 0.085 * size, 10, 1, true), M.flashA);
5142
- cone.rotation.z = -PI12 / 2;
5143
- cone.position.x = 0.042 * size;
5144
- group.add(cone);
5145
- for (let i = 0; i < 4; i++) {
5146
- const angle = i * PI12 / 2 + random() * 0.6;
5147
- const spike = new THREE.Mesh(new THREE.ConeGeometry(5e-3 * size, 0.04 * size, 6), M.flashA);
5148
- spike.position.set(0.012 * size, Math.cos(angle) * 0.016 * size, Math.sin(angle) * 0.016 * size);
5149
- spike.rotation.set(angle, 0, 0);
5150
- spike.rotateZ(-PI12 / 2);
5151
- group.add(spike);
5152
- }
5153
- const core = new THREE.Mesh(new THREE.SphereGeometry(0.016 * size, 12, 8), M.flashB);
5154
- core.position.x = 8e-3 * size;
5155
- group.add(core);
5156
- return group;
5157
- };
5158
- const endFlash = () => {
5159
- if (!flash) return;
5160
- flash.group.removeFromParent();
5161
- flash.group.traverse((child) => {
5162
- const mesh = child;
5163
- if (mesh.isMesh) mesh.geometry.dispose();
5164
- });
5165
- flash = null;
5166
- light.intensity = 0;
5167
- };
5168
- const effects = {
5135
+ var VIEWMODEL_EFFECT_IDS = { flash: "viewmodel_muzzle_flash", smoke: "weapon_smoke_puff", backblast: "launcher_backblast", flameJet: "flame_jet" };
5136
+ var vec = (vector) => [vector.x, vector.y, vector.z];
5137
+ var quaternion = (q) => [q.x, q.y, q.z, q.w];
5138
+ function createEffects(THREE, sink, random) {
5139
+ const seed = () => 1 + Math.floor(random() * 2147483646);
5140
+ const barrel = (orientation) => vec(new THREE.Vector3(1, 0, 0).applyQuaternion(orientation));
5141
+ return {
5169
5142
  muzzleFlash(position, orientation, size) {
5170
- endFlash();
5171
- const group = buildFlash(size);
5172
- group.position.copy(position);
5173
- group.quaternion.copy(orientation);
5174
- group.rotateX(random() * PI12);
5175
- scene.add(group);
5176
- flash = { group, age: 0 };
5177
- light.position.copy(position);
5178
- light.intensity = 4 * size;
5179
- light.distance = 2 * size;
5180
- for (let i = 0; i < 6; i++) {
5181
- const velocity = new THREE.Vector3(0.15 + random() * 0.35, 0.03 + random() * 0.12, (random() - 0.5) * 0.14).applyQuaternion(orientation);
5182
- effects.smoke(position, velocity, 0.013 * size, 1.3 + random() * 0.6, 0.45);
5183
- }
5143
+ sink?.play({ effect: VIEWMODEL_EFFECT_IDS.flash, point: vec(position), direction: barrel(orientation), orientation: quaternion(orientation), seed: seed(), values: { size } });
5184
5144
  },
5185
5145
  smoke(position, velocity, size, life, opacity) {
5186
- const puff = new THREE.Mesh(new THREE.SphereGeometry(size, 10, 8), M.smokeP.clone());
5187
- puff.position.copy(position);
5188
- particles.spawn(puff, velocity, { gravity: -0.08, life, fadeFrom: opacity, grow: 2.1, drag: 2.2, radius: -1, ownsGeometry: true });
5146
+ sink?.play({ effect: VIEWMODEL_EFFECT_IDS.smoke, point: vec(position), seed: seed(), values: { vx: velocity.x, vy: velocity.y, vz: velocity.z, radius: size, life, opacity } });
5189
5147
  },
5190
- update(dt) {
5191
- if (!flash) return;
5192
- flash.age += dt;
5193
- flash.group.scale.setScalar(0.6 + Math.min(1, flash.age / FLASH_SECONDS) * 0.9);
5194
- if (flash.age >= FLASH_SECONDS) endFlash();
5148
+ backblast(rear, orientation) {
5149
+ sink?.play({ effect: VIEWMODEL_EFFECT_IDS.backblast, point: vec(rear), direction: barrel(orientation), orientation: quaternion(orientation), seed: seed() });
5195
5150
  },
5196
- dispose() {
5197
- endFlash();
5198
- light.removeFromParent();
5199
- light.dispose();
5151
+ flameJet(muzzle, orientation, dt, scale) {
5152
+ sink?.play({ effect: VIEWMODEL_EFFECT_IDS.flameJet, point: vec(muzzle), direction: barrel(orientation), orientation: quaternion(orientation), seed: seed(), values: { dt, scale } });
5200
5153
  }
5201
5154
  };
5202
- return effects;
5203
5155
  }
5204
5156
 
5205
5157
  // src/fx/heavy.ts
5206
- var PI13 = Math.PI;
5158
+ var PI12 = Math.PI;
5207
5159
  var flameMaterials = (kit) => {
5208
5160
  const { THREE } = kit;
5209
5161
  return [
@@ -5213,40 +5165,20 @@ var flameMaterials = (kit) => {
5213
5165
  new THREE.MeshBasicMaterial({ color: 16773296, transparent: true, opacity: 0.9, blending: THREE.AdditiveBlending, depthWrite: false })
5214
5166
  ];
5215
5167
  };
5216
- var spread = (context, x, y, z) => new context.kit.THREE.Vector3((context.random() - 0.5) * x, (context.random() - 0.5) * y, (context.random() - 0.5) * z);
5217
- function createBits(context) {
5218
- const { kit, particles, random } = context;
5219
- const { THREE } = kit;
5220
- const palette = flameMaterials(kit);
5221
- return {
5222
- flame(position, velocity, size, life) {
5223
- const bit = new THREE.Mesh(new THREE.IcosahedronGeometry(size, 1), palette[Math.floor(random() * 4)].clone());
5224
- bit.position.copy(position);
5225
- bit.rotation.set(random() * 3, random() * 3, 0);
5226
- particles.spawn(bit, velocity, { gravity: -1.4, life, fadeFrom: 0.9, grow: 2.2, drag: 1.4, radius: -1, spin: new THREE.Vector3(3, 4, 2), ownsGeometry: true });
5227
- },
5228
- smoke(position, velocity, size, life, opacity) {
5229
- context.effects.smoke(position, velocity, size, life, opacity);
5230
- },
5231
- dispose: () => palette.forEach((material) => material.dispose())
5232
- };
5233
- }
5234
5168
  function launchRocket(context) {
5235
5169
  const { kit, scene, parts, random } = context;
5236
5170
  const { THREE } = kit;
5237
- const bits = createBits(context);
5238
5171
  const forward = context.forward();
5239
5172
  const muzzle = context.positionOf(parts.muzzle);
5240
5173
  const rear = context.positionOf(parts.rear);
5241
- for (let i = 0; i < 26; i++) bits.smoke(rear.clone(), forward.clone().multiplyScalar(-(1.5 + random() * 3)).add(spread(context, 1.4, 0.8, 1.4)), 0.03 + random() * 0.03, 1.8 + random() * 1.4, 0.5);
5242
- for (let i = 0; i < 14; i++) bits.flame(rear.clone(), forward.clone().multiplyScalar(-(2 + random() * 2)).add(spread(context, 1, 0.6, 1)), 0.02, 0.25);
5174
+ context.effects.backblast(rear, context.orientation());
5243
5175
  const rocket = parts.makeRound ? parts.makeRound() : buildFlyingRocket(kit, parts.launcherType);
5244
5176
  if (parts.round) parts.round.visible = false;
5245
5177
  rocket.quaternion.copy(context.orientation());
5246
5178
  rocket.position.copy(muzzle);
5247
5179
  scene.add(rocket);
5248
5180
  const exhaust = new THREE.Mesh(new THREE.ConeGeometry(0.018, 0.12, 8, 1, true), new THREE.MeshBasicMaterial({ color: 16760896, transparent: true, opacity: 0.9, depthWrite: false }));
5249
- exhaust.rotation.z = PI13 / 2;
5181
+ exhaust.rotation.z = PI12 / 2;
5250
5182
  exhaust.position.x = -0.08;
5251
5183
  rocket.add(exhaust);
5252
5184
  const light = new THREE.PointLight(16751168, 3, 2.5);
@@ -5259,37 +5191,29 @@ function launchRocket(context) {
5259
5191
  rocket.position.copy(muzzle).addScaledVector(forward, distance);
5260
5192
  rocket.rotation.x += 0.25 * dt * 60;
5261
5193
  exhaust.scale.set(1, 0.6 + random() * 0.8, 1);
5262
- if (random() < 0.9) bits.smoke(rocket.position.clone().addScaledVector(forward, -0.12), spread(context, 0.1, 0, 0.1).setY(0.05), 0.02 + random() * 0.015, 2.2, 0.5);
5194
+ if (random() < 0.9) context.effects.smoke(rocket.position.clone().addScaledVector(forward, -0.12), new THREE.Vector3((random() - 0.5) * 0.1, 0.05, (random() - 0.5) * 0.1), 0.02 + random() * 0.015, 2.2, 0.5);
5263
5195
  },
5264
5196
  () => {
5265
5197
  rocket.removeFromParent();
5266
5198
  exhaust.geometry.dispose();
5267
5199
  exhaust.material.dispose();
5268
5200
  light.dispose();
5269
- bits.dispose();
5270
5201
  }
5271
5202
  );
5272
5203
  }
5273
5204
  function flameJet(context, dt, scale) {
5274
5205
  const { kit, particles, random, parts } = context;
5275
5206
  const { THREE } = kit;
5276
- const bits = createBits(context);
5277
5207
  const forward = context.forward();
5278
5208
  const muzzle = context.positionOf(parts.muzzle);
5279
- const count = Math.floor(dt * 420 * scale);
5280
- for (let i = 0; i < count; i++) {
5281
- const speed = (2.2 + random() * 1.1) * scale;
5282
- bits.flame(muzzle.clone().addScaledVector(forward, random() * speed * Math.min(dt, 0.3)), forward.clone().multiplyScalar(speed).add(new THREE.Vector3((random() - 0.5) * 0.35, (random() - 0.3) * 0.3, (random() - 0.5) * 0.35)), 0.02 + random() * 0.022, 0.4 + random() * 0.35);
5283
- }
5284
- if (random() < 0.5) bits.smoke(muzzle.clone().addScaledVector(forward, 1.1 * scale + random() * 0.4), new THREE.Vector3(forward.x * 0.6, 0.35, forward.z * 0.6), 0.03, 1.6, 0.4);
5209
+ context.effects.flameJet(muzzle, context.orientation(), dt, scale);
5285
5210
  if (random() < 0.18) {
5286
5211
  const droplet = new THREE.Mesh(new THREE.SphereGeometry(6e-3, 6, 4), new THREE.MeshBasicMaterial({ color: 16742946 }));
5287
5212
  droplet.position.copy(muzzle).addScaledVector(forward, 0.3 + random() * 0.5);
5288
- particles.spawn(droplet, forward.clone().multiplyScalar(1.2 * scale).add(new THREE.Vector3(0, 0.2, 0)), { life: 3, radius: 3e-3, ownsGeometry: true, onGround: (position) => groundFire(context, bits, position) });
5213
+ particles.spawn(droplet, forward.clone().multiplyScalar(1.2 * scale).add(new THREE.Vector3(0, 0.2, 0)), { life: 3, radius: 3e-3, ownsGeometry: true, onGround: (position) => groundFire(context, position) });
5289
5214
  }
5290
- bits.dispose();
5291
5215
  }
5292
- function groundFire(context, bits, position) {
5216
+ function groundFire(context, position) {
5293
5217
  const { kit, scene, random } = context;
5294
5218
  const { THREE } = kit;
5295
5219
  const fire = new THREE.Group();
@@ -5308,7 +5232,7 @@ function groundFire(context, bits, position) {
5308
5232
  (progress, dt) => {
5309
5233
  clock += dt;
5310
5234
  flames.forEach((flame, index) => flame.scale.set(1 - progress * 0.7, (0.6 + Math.sin(clock * 20 + index * 2) * 0.35) * (1 - progress), 1 - progress * 0.7));
5311
- if (random() < 0.08) bits.smoke(fire.position.clone().add(new THREE.Vector3(0, 0.08, 0)), new THREE.Vector3(0, 0.15, 0), 0.015, 1.2, 0.25);
5235
+ if (random() < 0.08) context.effects.smoke(fire.position.clone().add(new THREE.Vector3(0, 0.08, 0)), new THREE.Vector3(0, 0.15, 0), 0.015, 1.2, 0.25);
5312
5236
  },
5313
5237
  () => {
5314
5238
  fire.removeFromParent();
@@ -5436,13 +5360,13 @@ var worldPositionOf = (session, part, out) => {
5436
5360
  return part.getWorldPosition(out);
5437
5361
  };
5438
5362
  var toWorld = (session, vector, scaled = false) => {
5439
- const quaternion = session.model.root.getWorldQuaternion(new session.kit.THREE.Quaternion());
5440
- const world = vector.clone().applyQuaternion(quaternion);
5363
+ const quaternion2 = session.model.root.getWorldQuaternion(new session.kit.THREE.Quaternion());
5364
+ const world = vector.clone().applyQuaternion(quaternion2);
5441
5365
  return scaled ? world.multiplyScalar(session.holderScale) : world;
5442
5366
  };
5443
5367
 
5444
5368
  // src/fx/viewmodel-events.ts
5445
- var PI14 = Math.PI;
5369
+ var PI13 = Math.PI;
5446
5370
  var UGL_FLASH = 1.6;
5447
5371
  var restFlat = (object) => {
5448
5372
  object.rotation.x = 0;
@@ -5516,14 +5440,14 @@ function createClipEventHandler(world, session) {
5516
5440
  root.updateWorldMatrix(true, true);
5517
5441
  const copy = parts.mag.clone(true);
5518
5442
  parts.mag.matrixWorld.decompose(copy.position, copy.quaternion, copy.scale);
5519
- particles.spawn(copy, toWorld(session, vector(up ? -0.25 : 0.05, up ? 0.9 : -0.3, 0.18)), { kind: "magazine", life: 25, radius: 0.014, bounce: 0.15, spin: vector(1.5, 0.5, 2.5), onRest: (object) => object.rotation.set(0, object.rotation.y, PI14 / 2) });
5443
+ particles.spawn(copy, toWorld(session, vector(up ? -0.25 : 0.05, up ? 0.9 : -0.3, 0.18)), { kind: "magazine", life: 25, radius: 0.014, bounce: 0.15, spin: vector(1.5, 0.5, 2.5), onRest: (object) => object.rotation.set(0, object.rotation.y, PI13 / 2) });
5520
5444
  };
5521
5445
  const stuckCase = () => {
5522
5446
  if (!session.cartridge || !parts.eject) return;
5523
5447
  const casing = buildCasing(kit, session.cartridge.dims, session.cartridge.shape);
5524
5448
  const at = root.worldToLocal(offsetFrom(positionOf(parts.eject), 0, casing.length * 0.35, 0));
5525
5449
  casing.group.position.copy(at);
5526
- casing.group.rotation.set(0, 0, PI14 / 2 - 0.25);
5450
+ casing.group.rotation.set(0, 0, PI13 / 2 - 0.25);
5527
5451
  root.add(casing.group);
5528
5452
  session.stuckCase = casing.group;
5529
5453
  };
@@ -5602,14 +5526,14 @@ function createClipEventHandler(world, session) {
5602
5526
  }
5603
5527
 
5604
5528
  // src/fx/viewmodel.ts
5605
- var PI15 = Math.PI;
5529
+ var PI14 = Math.PI;
5606
5530
  var HAND_OFFSET2 = [0.2, -0.2, -0.42];
5607
5531
  var HEAT_DISPLAY_MAX_FALLBACK = 120;
5608
5532
  var LAUNCH_VOLUME = 0.6;
5609
5533
  var fittedOf2 = (parts) => parts.map((part) => ({ id: part.id, mount: part.mount, ...part.integral ? { integral: true } : {}, ...part.on === void 0 ? {} : { on: part.on } }));
5610
5534
  var collapsedStockPose = (move2) => {
5611
5535
  if (move2.kind === "retract") return { position: [move2.travel, 0, 0] };
5612
- return { rotation: [move2.axis === "x" ? PI15 : 0, move2.axis === "y" ? PI15 : 0, move2.axis === "z" ? PI15 : 0] };
5536
+ return { rotation: [move2.axis === "x" ? PI14 : 0, move2.axis === "y" ? PI14 : 0, move2.axis === "z" ? PI14 : 0] };
5613
5537
  };
5614
5538
  var underbarrelStep = (step, tool) => tool.underbarrelActive && step.type === "play" && (step.clip === "shot" || step.clip === "reload") ? { ...step, variant: "ugl" } : step;
5615
5539
  var caliberOf = (arsenal, def) => def.action.kind === "firearm" ? arsenal.calibers.get(def.action.caliber) : void 0;
@@ -5621,12 +5545,13 @@ function createViewmodel(options) {
5621
5545
  const distance = () => options.soundDistance?.() ?? 0;
5622
5546
  const particles = createParticles(THREE, scene, groundAt);
5623
5547
  particles.onBounce = (kind) => kind === "casing" ? audio?.clink() : kind === "magazine" ? audio?.thud() : void 0;
5624
- const effects = createEffects(kit, scene, particles, random);
5548
+ const ownVfx = options.effects ? void 0 : createVfxRenderer(THREE, { scene, camera, vfx: { profile: "medium" } });
5549
+ const effects = createEffects(THREE, options.effects ?? ownVfx, random);
5625
5550
  const hand = new THREE.Group();
5626
5551
  hand.name = VIEWMODEL_NODE_NAME;
5627
5552
  scene.add(hand);
5628
5553
  const holder = new THREE.Group();
5629
- holder.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), PI15 / 2);
5554
+ holder.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), PI14 / 2);
5630
5555
  hand.add(holder);
5631
5556
  let tasks = [];
5632
5557
  let session = null;
@@ -5802,8 +5727,8 @@ function createViewmodel(options) {
5802
5727
  tasks = tasks.filter((other) => other !== task);
5803
5728
  }
5804
5729
  }
5805
- effects.update(dt);
5806
5730
  particles.update(dt);
5731
+ ownVfx?.update(dt);
5807
5732
  },
5808
5733
  setCondition(next) {
5809
5734
  condition = next;
@@ -5821,7 +5746,7 @@ function createViewmodel(options) {
5821
5746
  dispose() {
5822
5747
  release();
5823
5748
  particles.dispose();
5824
- effects.dispose();
5749
+ ownVfx?.dispose();
5825
5750
  hand.removeFromParent();
5826
5751
  }
5827
5752
  };
@@ -5844,7 +5769,8 @@ function createWeaponFx(options) {
5844
5769
  ...options.tool ? { tool: options.tool } : {},
5845
5770
  ...options.condition ? { condition: options.condition } : {},
5846
5771
  ...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
5847
- ...options.raycast ? { raycast: options.raycast } : {}
5772
+ ...options.raycast ? { raycast: options.raycast } : {},
5773
+ ...options.effects ? { effects: options.effects } : {}
5848
5774
  });
5849
5775
  return {
5850
5776
  handle(event, tool) {
@@ -6958,6 +6884,7 @@ function createWeaponsTestModule(options = {}) {
6958
6884
  tool: lent.tool,
6959
6885
  soundDistance: () => soundDistance,
6960
6886
  raycast: createLaserRaycast(lent.THREE, lent.scene, lent.camera),
6887
+ ...lent.effects ? { effects: lent.effects } : {},
6961
6888
  ...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
6962
6889
  ...options.condition ? { condition: options.condition } : {},
6963
6890
  ...options.seed === void 0 ? {} : { seed: options.seed }