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()