roavatar-renderer 1.5.12 → 1.5.13

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.d.ts CHANGED
@@ -1440,12 +1440,16 @@ export declare const FLAGS: {
1440
1440
  AUTO_RESTORE_CONTEXT: boolean;
1441
1441
  /**RenderTarget textures are converted to CanvasTextures which can be exported */
1442
1442
  RENDERTARGET_TO_CANVASTEXTURE: boolean;
1443
- /**Amount of time thumbnail generator will wait after no assets are being loaded to resolve, should be a little time at least so particles can render */
1443
+ /**Amount of time thumbnail generator will wait after no assets are being loaded to resolve, should be a little time at least so particles can render OR just set PARTICLES_START_FULL = true */
1444
1444
  THUMBNAIL_TIMEOUT: number;
1445
1445
  /**Always render attachments even when theyre set to not be visible */
1446
1446
  ALWAYS_SHOW_ATTACHMENTS: boolean;
1447
1447
  /**Multiplier for delta time used by renderer things (does not affect datamodel side of things but particles and such instead) */
1448
1448
  RENDERER_DELTA_TIME_MULTIPLIER: number;
1449
+ /**How many seconds particles will presimulate (mainly so they arent incomplete in thumbnail generations) */
1450
+ PARTICLES_START_FULL: number;
1451
+ /**Framerate of presimulation particles */
1452
+ PARTICLES_START_FULL_FRAMERATE: number;
1449
1453
  /**shows ThreeJS SkeletonHelper */
1450
1454
  SHOW_SKELETON_HELPER: boolean;
1451
1455
  /**if set the skeleton helper will only show if the instance has the name */
@@ -1566,9 +1570,12 @@ export declare function generateModelThumbnail(auth: Authentication, renderScene
1566
1570
  * **Example on generating 1000x1000 webp thumbnail for blank outfit**
1567
1571
  * ```ts
1568
1572
  * const outfit = new Outfit()
1573
+ * FLAGS.THUMBNAIL_TIMEOUT = 1 //makes thumbnail generation faster
1574
+ * FLAGS.PARTICLES_START_FULL = 10 //makes emitters appear as if theyve been there for some time (10 seconds)
1569
1575
  * FLAGS.RENDERTARGET_TO_CANVASTEXTURE = true //required for gltf export
1570
1576
  * const result = await generateOutfitThumbnail(new Authentication(), outfit, [1000,1000], "webp", 0.99)
1571
1577
  * FLAGS.RENDERTARGET_TO_CANVASTEXTURE = false
1578
+ * FLAGS.PARTICLES_START_FULL = 0
1572
1579
  * console.log(result)
1573
1580
  * ```
1574
1581
  */
@@ -2719,6 +2726,7 @@ export declare class OutfitRenderer {
2719
2726
  currentRigType: AvatarType;
2720
2727
  doCameraUpdateOnLoad: boolean; /**Makes camera update when new avatar has loaded */
2721
2728
  doCameraUpdate: boolean; /**Does camera update every frame */
2729
+ doAddInstance: boolean; /**If outfitRenderer should call RBXRenderer.addInstance() */
2722
2730
  currentlyChangingRig: boolean;
2723
2731
  currentlyUpdating: boolean;
2724
2732
  hasNewUpdate: boolean;
@@ -2763,6 +2771,10 @@ export declare class OutfitRenderer {
2763
2771
  * Starts updating the animation of the outfit per frame
2764
2772
  */
2765
2773
  startAnimating(): void;
2774
+ /**
2775
+ * Updates the animation once
2776
+ */
2777
+ animateOnce(deltaTimeOverride?: number): void;
2766
2778
  /**
2767
2779
  * Stops updating the animation of the outfit per frame
2768
2780
  */
@@ -2770,8 +2782,9 @@ export declare class OutfitRenderer {
2770
2782
  /**
2771
2783
  * Sets the current animation being played
2772
2784
  * @param name The name of the animation, for example "idle", "run" or "emote.1234"
2785
+ * @returns If the animation started playing, it may start playing later if it has been queued despite returning false
2773
2786
  */
2774
- setMainAnimation(name: string): void;
2787
+ setMainAnimation(name: string): Promise<boolean>;
2775
2788
  /**Calls destroy on the rig and stops animating, the OutfitRenderer should not be interacted with after this */
2776
2789
  destroy(): void;
2777
2790
  }
package/dist/index.js CHANGED
@@ -29864,6 +29864,8 @@ const FLAGS = {
29864
29864
  THUMBNAIL_TIMEOUT: 500,
29865
29865
  ALWAYS_SHOW_ATTACHMENTS: false,
29866
29866
  RENDERER_DELTA_TIME_MULTIPLIER: 1,
29867
+ PARTICLES_START_FULL: 0,
29868
+ PARTICLES_START_FULL_FRAMERATE: 20,
29867
29869
  //skeleton
29868
29870
  SHOW_SKELETON_HELPER: false,
29869
29871
  SKELETON_HELPER_INSTANCE_NAME: void 0,
@@ -33776,7 +33778,11 @@ class Outfit {
33776
33778
  if (Number(assetTypeId) === assetTypeId) {
33777
33779
  this.addAsset(assetId, assetTypeId, `${AssetTypes[assetTypeId] || "Asset"} (${assetId})`);
33778
33780
  resolve(void 0);
33781
+ } else {
33782
+ resolve(void 0);
33779
33783
  }
33784
+ } else {
33785
+ resolve(void 0);
33780
33786
  }
33781
33787
  });
33782
33788
  }));
@@ -50303,6 +50309,14 @@ class EmitterGroupDesc extends RenderDesc {
50303
50309
  this.disposeMeshes(scene, originalResults);
50304
50310
  this.disposeRenderLists(renderer);
50305
50311
  }
50312
+ if (FLAGS.PARTICLES_START_FULL) {
50313
+ for (const emitterDesc of this.emitterDescs) {
50314
+ for (let i = 0; i < Math.min(emitterDesc.lifetime.Max * FLAGS.PARTICLES_START_FULL_FRAMERATE, FLAGS.PARTICLES_START_FULL * FLAGS.PARTICLES_START_FULL_FRAMERATE); i++) {
50315
+ emitterDesc.tick(1 / FLAGS.PARTICLES_START_FULL_FRAMERATE, this);
50316
+ emitterDesc.updateResult(this.renderScene);
50317
+ }
50318
+ }
50319
+ }
50306
50320
  return this.results;
50307
50321
  }
50308
50322
  updateResults() {
@@ -51509,6 +51523,8 @@ class OutfitRenderer {
51509
51523
  /**Makes camera update when new avatar has loaded */
51510
51524
  doCameraUpdate = false;
51511
51525
  /**Does camera update every frame */
51526
+ doAddInstance = true;
51527
+ /**If outfitRenderer should call RBXRenderer.addInstance() */
51512
51528
  currentlyChangingRig = false;
51513
51529
  currentlyUpdating = false;
51514
51530
  hasNewUpdate = false;
@@ -51559,7 +51575,7 @@ class OutfitRenderer {
51559
51575
  dataModel.Destroy();
51560
51576
  this.currentRig = newRig;
51561
51577
  this.currentlyChangingRig = false;
51562
- RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51578
+ if (this.doAddInstance) RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51563
51579
  resolve(newRig);
51564
51580
  } else {
51565
51581
  this.onError.Fire("rig");
@@ -51597,7 +51613,7 @@ class OutfitRenderer {
51597
51613
  }
51598
51614
  this.currentlyUpdating = false;
51599
51615
  if (this.currentRig) {
51600
- RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51616
+ if (this.doAddInstance) RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51601
51617
  if (this.doCameraUpdateOnLoad) {
51602
51618
  this.centerCamera();
51603
51619
  }
@@ -51615,9 +51631,11 @@ class OutfitRenderer {
51615
51631
  }
51616
51632
  });
51617
51633
  } else {
51634
+ this.onError.Fire("rig");
51618
51635
  this.currentlyUpdating = false;
51619
51636
  }
51620
51637
  } else {
51638
+ this.onError.Fire("rig");
51621
51639
  this.currentlyUpdating = false;
51622
51640
  }
51623
51641
  });
@@ -51658,21 +51676,27 @@ class OutfitRenderer {
51658
51676
  if (this.currentRig && this.doCameraUpdate) {
51659
51677
  this.centerCamera();
51660
51678
  }
51661
- if (this.currentRig && this.auth) {
51662
- const humanoid = this.currentRig.FindFirstChildOfClass("Humanoid");
51663
- if (humanoid) {
51664
- const animator = humanoid.FindFirstChildOfClass("Animator");
51665
- if (animator) {
51666
- const deltaTime = (Date.now() / 1e3 - this.lastFrameTime) * this.deltaTimeMultiplier;
51667
- this.lastFrameTime = Date.now() / 1e3;
51668
- const animatorW = new AnimatorWrapper(animator);
51669
- animatorW.renderAnimation(deltaTime);
51670
- this.currentRig.preRender();
51671
- RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51672
- }
51679
+ this.animateOnce();
51680
+ }, 1e3 / this.animationFPS);
51681
+ }
51682
+ /**
51683
+ * Updates the animation once
51684
+ */
51685
+ animateOnce(deltaTimeOverride) {
51686
+ if (this.currentRig && this.auth) {
51687
+ const humanoid = this.currentRig.FindFirstChildOfClass("Humanoid");
51688
+ if (humanoid) {
51689
+ const animator = humanoid.FindFirstChildOfClass("Animator");
51690
+ if (animator) {
51691
+ const deltaTime = deltaTimeOverride || (Date.now() / 1e3 - this.lastFrameTime) * this.deltaTimeMultiplier;
51692
+ this.lastFrameTime = Date.now() / 1e3;
51693
+ const animatorW = new AnimatorWrapper(animator);
51694
+ animatorW.renderAnimation(deltaTime);
51695
+ this.currentRig.preRender();
51696
+ if (this.doAddInstance) RBXRenderer.addInstance(this.currentRig, this.auth, this.renderScene);
51673
51697
  }
51674
51698
  }
51675
- }, 1e3 / this.animationFPS);
51699
+ }
51676
51700
  }
51677
51701
  /**
51678
51702
  * Stops updating the animation of the outfit per frame
@@ -51686,26 +51710,36 @@ class OutfitRenderer {
51686
51710
  /**
51687
51711
  * Sets the current animation being played
51688
51712
  * @param name The name of the animation, for example "idle", "run" or "emote.1234"
51713
+ * @returns If the animation started playing, it may start playing later if it has been queued despite returning false
51689
51714
  */
51690
51715
  setMainAnimation(name) {
51691
- if (this.currentRig) {
51692
- const humanoid = this.currentRig.FindFirstChildOfClass("Humanoid");
51693
- if (humanoid) {
51694
- const animator = humanoid.FindFirstChildOfClass("Animator");
51695
- if (animator) {
51696
- const animatorW = new AnimatorWrapper(animator);
51697
- const successfullyPlayed = animatorW.playAnimation(name);
51698
- if (!successfullyPlayed && name.startsWith("emote.") && name) {
51699
- const emoteId = BigInt(name.split(".")[1]);
51700
- animatorW.loadAvatarAnimation(emoteId, true, true).then(() => {
51701
- animatorW.playAnimation(name);
51702
- });
51716
+ return new Promise((resolve) => {
51717
+ if (this.currentRig) {
51718
+ const humanoid = this.currentRig.FindFirstChildOfClass("Humanoid");
51719
+ if (humanoid) {
51720
+ const animator = humanoid.FindFirstChildOfClass("Animator");
51721
+ if (animator) {
51722
+ const animatorW = new AnimatorWrapper(animator);
51723
+ const successfullyPlayed = animatorW.playAnimation(name);
51724
+ if (!successfullyPlayed && name.startsWith("emote.") && name) {
51725
+ const emoteId = BigInt(name.split(".")[1]);
51726
+ animatorW.loadAvatarAnimation(emoteId, true, true).then(() => {
51727
+ resolve(animatorW.playAnimation(name));
51728
+ });
51729
+ } else {
51730
+ resolve(false);
51731
+ }
51732
+ } else {
51733
+ resolve(false);
51703
51734
  }
51735
+ } else {
51736
+ resolve(false);
51704
51737
  }
51738
+ } else {
51739
+ this._queuedMainAnimation = name;
51740
+ resolve(false);
51705
51741
  }
51706
- } else {
51707
- this._queuedMainAnimation = name;
51708
- }
51742
+ });
51709
51743
  }
51710
51744
  /**Calls destroy on the rig and stops animating, the OutfitRenderer should not be interacted with after this */
51711
51745
  destroy() {
@@ -51780,15 +51814,26 @@ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "
51780
51814
  const renderScene = RBXRenderer.addScene();
51781
51815
  setupThumbnailScene(renderScene);
51782
51816
  const outfitRenderer = new OutfitRenderer(auth, outfit, renderScene);
51817
+ outfitRenderer.doAddInstance = false;
51783
51818
  if (outfit.playerAvatarType === AvatarType.R6) outfitRenderer.deltaTimeMultiplier = 0;
51784
- outfitRenderer.startAnimating();
51785
- if (!outfit.containsAssetType("Gear")) {
51786
- if (outfit.playerAvatarType === AvatarType.R15) {
51787
- outfitRenderer.setMainAnimation("pose");
51819
+ API.Misc.startCurrentlyLoadingAssets("thumbnail-animation");
51820
+ outfitRenderer.onSuccess.Connect(() => {
51821
+ if (!outfit.containsAssetType("Gear")) {
51822
+ if (outfit.playerAvatarType === AvatarType.R15) {
51823
+ outfitRenderer.setMainAnimation("pose").then(() => {
51824
+ API.Misc.stopCurrentlyLoadingAssets("thumbnail-animation");
51825
+ });
51826
+ } else {
51827
+ outfitRenderer.setMainAnimation("idle").then(() => {
51828
+ API.Misc.stopCurrentlyLoadingAssets("thumbnail-animation");
51829
+ });
51830
+ }
51831
+ } else {
51832
+ outfitRenderer.setMainAnimation("toolnone").then(() => {
51833
+ API.Misc.stopCurrentlyLoadingAssets("thumbnail-animation");
51834
+ });
51788
51835
  }
51789
- } else {
51790
- outfitRenderer.setMainAnimation("toolnone");
51791
- }
51836
+ });
51792
51837
  let exportTimeout = !API.Misc.getCurrentlyLoading() ? setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT) : void 0;
51793
51838
  const onLoadingConnection = API.Events.OnLoadingAssets.Connect((currentlyLoading) => {
51794
51839
  if (exportTimeout) {
@@ -51802,10 +51847,10 @@ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "
51802
51847
  async function doExport() {
51803
51848
  onLoadingConnection.Disconnect();
51804
51849
  if (outfitRenderer.currentRig) {
51850
+ outfitRenderer.animateOnce(!outfit.containsAssetType("Gear") && outfit.playerAvatarType === AvatarType.R6 ? 0 : 1);
51805
51851
  const thumbnailResult = await generateModelThumbnail(auth, renderScene, outfitRenderer.currentRig, size, type, quality, gltfAutoDownload);
51806
51852
  console.log("Generated outfit thumbnail after seconds:", (performance.now() - startTime) / 1e3);
51807
51853
  resolve(thumbnailResult);
51808
- outfitRenderer.stopAnimating();
51809
51854
  if (outfitRenderer.currentRig) outfitRenderer.currentRig.Destroy();
51810
51855
  } else {
51811
51856
  resolve(void 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.5.12",
3
+ "version": "1.5.13",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",