From a452e2f6b05c6c6c36734130247d9c7d5ef07f2e Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:17:41 +0100 Subject: [PATCH 01/10] Expose GetBoneVelocity (The math is all good!) --- engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs b/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs index f832e64a6..483d38179 100644 --- a/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs +++ b/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs @@ -25,9 +25,8 @@ internal bool HasBoneOverrides() /// /// Calculate velocity from previous and current bone transform - /// (I want to expose this public but want to make sure the math is correct first) /// - internal void GetBoneVelocity( int boneIndex, out Vector3 linear, out Vector3 angular ) + public void GetBoneVelocity( int boneIndex, out Vector3 linear, out Vector3 angular ) { linear = default; angular = default; From ad6422063a0d0bae6a759537f13bafaf88141ade Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:28:58 +0100 Subject: [PATCH 02/10] Document SceneModel.Bones, expose HasBoneOverrides --- .../Systems/SceneSystem/SceneModel.Bones.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs b/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs index 483d38179..94fb1eee8 100644 --- a/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs +++ b/engine/Sandbox.Engine/Systems/SceneSystem/SceneModel.Bones.cs @@ -6,6 +6,11 @@ namespace Sandbox; /// public sealed partial class SceneModel : SceneObject { + /// + /// Manually override the final bone transform. + /// + /// + /// Local coordinates based on the SceneModel's transform public void SetBoneOverride( int boneIndex, in Transform transform ) { if ( boneIndex < 0 ) return; @@ -13,18 +18,24 @@ public void SetBoneOverride( int boneIndex, in Transform transform ) animNative.SetPhysicsBone( (ushort)boneIndex, transform ); } + /// + /// Clears all bone transform overrides. + /// public void ClearBoneOverrides() { animNative.ClearPhysicsBones(); } - internal bool HasBoneOverrides() + /// + /// Whether any bone transforms have been overridden. + /// + public bool HasBoneOverrides() { return animNative.HasPhysicsBones(); } /// - /// Calculate velocity from previous and current bone transform + /// Calculates the velocity from the previous and current bone transforms. /// public void GetBoneVelocity( int boneIndex, out Vector3 linear, out Vector3 angular ) { From e6325b54fae133b5b090239d8426a5e4e611e401 Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:30:38 +0100 Subject: [PATCH 03/10] Make ModelChanged public and add summary --- .../Sandbox.Engine/Scene/Components/Render/ModelRenderer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Render/ModelRenderer.cs b/engine/Sandbox.Engine/Scene/Components/Render/ModelRenderer.cs index d4bb0b7df..6f851fddb 100644 --- a/engine/Sandbox.Engine/Scene/Components/Render/ModelRenderer.cs +++ b/engine/Sandbox.Engine/Scene/Components/Render/ModelRenderer.cs @@ -196,7 +196,10 @@ internal void OnModelReloaded() OnModelChanged(); } - internal Action ModelChanged; + /// + /// Invoked when has been changed. + /// + public Action ModelChanged; internal void OnModelChanged() { From 1ecc1e142a99a80d841ee3101cfa43bdbce563c6 Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:34:05 +0100 Subject: [PATCH 04/10] Fix spelling --- .../Scene/Components/Render/SkinnedModelRenderer.Bones.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs b/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs index a6322c588..f1356058c 100644 --- a/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs +++ b/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs @@ -196,7 +196,7 @@ public Transform[] GetBoneTransforms( bool world ) public record struct BoneVelocity( Vector3 Linear, Vector3 Angular ); /// - /// Allocate an array of bone veloicities in world space + /// Allocate an array of bone velocities in world space /// public BoneVelocity[] GetBoneVelocities() { From 161fdfa91b33aa5026ece070040b7f465a0e067e Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:40:09 +0100 Subject: [PATCH 05/10] GetBoneVelocity( int ), fix GetBoneVelocities assert --- .../Render/SkinnedModelRenderer.Bones.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs b/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs index f1356058c..82ae9ca55 100644 --- a/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs +++ b/engine/Sandbox.Engine/Scene/Components/Render/SkinnedModelRenderer.Bones.cs @@ -200,7 +200,7 @@ public record struct BoneVelocity( Vector3 Linear, Vector3 Angular ); /// public BoneVelocity[] GetBoneVelocities() { - Assert.NotNull( Model, "Model should not be null when calling GetBoneTransforms" ); + Assert.NotNull( Model, "Model should not be null when calling GetBoneVelocities" ); BoneVelocity[] transforms = new BoneVelocity[Model.BoneCount]; @@ -215,4 +215,18 @@ public BoneVelocity[] GetBoneVelocities() return transforms; } + + /// + /// Retrieve the bone's velocities based on previous and current position + /// + public BoneVelocity GetBoneVelocity( int boneIndex ) + { + Assert.NotNull( Model, "Model should not be null when calling GetBoneVelocity" ); + + if ( !SceneModel.IsValid() || boneIndex < 0 || boneIndex >= Model.BoneCount ) + return default; + + SceneModel.GetBoneVelocity( boneIndex, out var linear, out var angular ); + return new BoneVelocity( linear, angular ); + } } From 40590c16df966302f21374a799c7f3f3702650ae Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:05:44 +0100 Subject: [PATCH 06/10] Implement #7718 Expose ModelHitboxes component's Hitboxes list Expose Hitbox's bounds --- engine/Sandbox.Engine/Scene/Components/Game/Hitbox.cs | 2 +- engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Game/Hitbox.cs b/engine/Sandbox.Engine/Scene/Components/Game/Hitbox.cs index 9fdf95b76..b7facdf52 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/Hitbox.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/Hitbox.cs @@ -23,7 +23,7 @@ internal Hitbox( GameObject gameObject, BoneCollection.Bone bone, ITagSet tagSet public BoneCollection.Bone Bone { get; private set; } public ITagSet Tags { get; private set; } public PhysicsBody Body { get; set; } - internal BBox Bounds { get; set; } + public BBox Bounds { get; set; } public void Dispose() { diff --git a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs index f0abeae32..00fc37eab 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs @@ -53,6 +53,8 @@ public GameObject Target } } + public readonly List Hitboxes = new(); + protected override void OnAwake() { Scene.GetSystem( out system ); @@ -163,8 +165,6 @@ public void UpdatePositions() } } - internal readonly List Hitboxes = new(); - public void AddHitbox( Hitbox hitbox ) { Hitboxes.Add( hitbox ); From 86736d0fe47c8e8da13b9a2ae1c65caa5edc1d72 Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:22:17 +0100 Subject: [PATCH 07/10] Make Hitboxes internal again, add GetHitboxes() and RemoveHitbox --- .../Scene/Components/Game/ModelHitboxes.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs index 00fc37eab..500e16d7c 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs @@ -53,8 +53,6 @@ public GameObject Target } } - public readonly List Hitboxes = new(); - protected override void OnAwake() { Scene.GetSystem( out system ); @@ -165,11 +163,20 @@ public void UpdatePositions() } } + internal readonly List Hitboxes = new(); + public void AddHitbox( Hitbox hitbox ) { Hitboxes.Add( hitbox ); } + public void RemoveHitbox( Hitbox hitbox ) + { + Hitboxes.Remove( hitbox ); + } + + public IReadOnlyList GetHitboxes() => Hitboxes; + /// /// The gameobject tags have changed, update collision tags on the target objects /// From ff94f1dfc4d87cfa1ed78f949eae074e207d1fb6 Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:58:25 +0100 Subject: [PATCH 08/10] Use new field --- .../Scene/Components/Game/ModelHitboxes.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs index 500e16d7c..1fcab5ae2 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs @@ -12,8 +12,6 @@ public sealed class ModelHitboxes : Component, Component.ExecuteInEditor { HitboxSystem system; - SkinnedModelRenderer _renderer; - /// /// The target SkinnedModelRenderer that holds the model/skeleton you want to /// take the hitboxes from. @@ -21,33 +19,31 @@ public sealed class ModelHitboxes : Component, Component.ExecuteInEditor [Property] public SkinnedModelRenderer Renderer { - get => _renderer; + get; set { - if ( _renderer == value ) return; + if ( field == value ) return; Clear(); - _renderer = value; + field = value; AddFrom( Renderer ); } } - GameObject _target; - /// /// The target GameObject to report in trace hits. If this is unset we'll defaault to the gameobject on which this component is. /// [Property] public GameObject Target { - get => _target; + get; set { - if ( _target == value ) return; + if ( field == value ) return; - _target = value; + field = value; Rebuild(); } @@ -173,7 +169,7 @@ public void AddHitbox( Hitbox hitbox ) public void RemoveHitbox( Hitbox hitbox ) { Hitboxes.Remove( hitbox ); - } + } public IReadOnlyList GetHitboxes() => Hitboxes; From c260655b27d00a6416070c1ca1a8c09522703338 Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:25:35 +0100 Subject: [PATCH 09/10] Add GetHitbox with many overloads and summaries --- .../Scene/Components/Game/ModelHitboxes.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs index 1fcab5ae2..878d8fb28 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs @@ -161,18 +161,58 @@ public void UpdatePositions() internal readonly List Hitboxes = new(); + /// + /// Adds a hitbox to the models hitbox list + /// + /// public void AddHitbox( Hitbox hitbox ) { Hitboxes.Add( hitbox ); } + /// + /// Removes a hitbox from the models hitbox list. + /// + /// public void RemoveHitbox( Hitbox hitbox ) { Hitboxes.Remove( hitbox ); } + /// + /// Returns every hitbox on this model. + /// + /// public IReadOnlyList GetHitboxes() => Hitboxes; + /// + /// Retrieves the hitbox associated with the bone index. + /// + /// The bone index to retrieve. + /// null if no matching hitbox is found. + public Hitbox GetHitbox( int boneIndex ) => Hitboxes.FirstOrDefault( x => x.Bone.Index == boneIndex ); + + /// + /// Retrieves the hitbox associated with the specified bone. + /// + /// The bone for which to find the corresponding hitbox. + /// null if no matching hitbox is found. + public Hitbox GetHitbox( BoneCollection.Bone bone ) => Hitboxes.FirstOrDefault( x => x.Bone == bone ); + + /// + /// Retrieves the hitbox associated with the specified bone name. + /// + /// The name of the bone for which to retrieve the hitbox. + /// null if no matching hitbox is found. + public Hitbox GetHitbox( string boneName ) => Hitboxes.FirstOrDefault( x => x.Bone.Name == boneName ); + + /// + /// Retrieves the hitbox associated with the specified physics body. + /// + /// The physics body for which to find the corresponding hitbox. + /// null if no matching hitbox is found. + public Hitbox GetHitbox( PhysicsBody physicsBody ) => Hitboxes.FirstOrDefault( x => x.Body == physicsBody ); + /// /// The gameobject tags have changed, update collision tags on the target objects /// From b015a2b4bd35bafdf9e9bd15e837d34f60760ebf Mon Sep 17 00:00:00 2001 From: yuberee <59583743+yuberee@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:31:58 +0100 Subject: [PATCH 10/10] Add HitboxesRebuilt to subscribe to --- .../Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs index 878d8fb28..6845a317a 100644 --- a/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs +++ b/engine/Sandbox.Engine/Scene/Components/Game/ModelHitboxes.cs @@ -69,10 +69,16 @@ protected override void OnDestroy() Clear(); } + /// + /// Invoked when the hitboxes have been rebuilt. + /// + public Action HitboxesRebuilt; + public void Rebuild() { Clear(); AddFrom( Renderer ); + HitboxesRebuilt?.Invoke(); } void Clear()