diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4466ae1851..fb77d098c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 
 ### Changed
+- Entity-entity pushback is no longer applied in forced movement states like rolling and leaping.
 
 ### Removed
 
diff --git a/assets/voxygen/i18n/en/_manifest.ron b/assets/voxygen/i18n/en/_manifest.ron
index 737713c4dc..2be067818b 100644
--- a/assets/voxygen/i18n/en/_manifest.ron
+++ b/assets/voxygen/i18n/en/_manifest.ron
@@ -58,6 +58,7 @@
             "You can toggle showing your amount of health on the healthbar in the settings.",            
             "Sit near a campfire (with the 'K' key) to slowly recover from your injuries.",
             "Need more bags or better armor to continue your journey? Press 'C' to open the crafting menu!",
+            "Try jumping when rolling through creatures.",
         ],
         "npc.speech.villager": [
             "Isn't it such a lovely day?",
diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs
index 4e40b2ac6c..b21d90008f 100644
--- a/common/src/comp/character_state.rs
+++ b/common/src/comp/character_state.rs
@@ -2,7 +2,7 @@ use crate::{
     combat::Attack,
     comp::{tool::ToolKind, Density, Energy, InputAttr, InputKind, Ori, Pos, Vel},
     event::{LocalEvent, ServerEvent},
-    states::{behavior::JoinData, *},
+    states::{behavior::JoinData, utils::StageSection, *},
 };
 use serde::{Deserialize, Serialize};
 use specs::{Component, DerefFlaggedStorage, VecStorage};
@@ -196,6 +196,15 @@ impl CharacterState {
 
     pub fn is_stunned(&self) -> bool { matches!(self, CharacterState::Stunned(_)) }
 
+    pub fn is_forced_movement(&self) -> bool {
+        matches!(self,
+            CharacterState::ComboMelee(s) if s.stage_section == StageSection::Swing)
+            || matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge)
+            || matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement)
+            || matches!(self, CharacterState::SpinMelee(s) if s.stage_section == StageSection::Swing)
+            || matches!(self, CharacterState::Roll(s) if s.stage_section == StageSection::Movement)
+    }
+
     /// Compares for shallow equality (does not check internal struct equality)
     pub fn same_variant(&self, other: &Self) -> bool {
         // Check if state is the same without looking at the inner data
diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs
index 48c36e506d..1f4521496c 100644
--- a/common/systems/src/phys.rs
+++ b/common/systems/src/phys.rs
@@ -333,6 +333,21 @@ impl<'a> PhysicsData<'a> {
                         };
                     }
 
+                    // Don't apply e2e pushback to entities that are in a forced movement state
+                    // (e.g. roll, leapmelee). This allows leaps to work properly (since you won't
+                    // get pushed away before delivering the hit), and allows rolling through an
+                    // enemy when trapped (e.g. with minotaur). This allows using e2e pushback to
+                    // gain speed by jumping out of a roll while in the middle of a collider, this
+                    // is an intentional combat mechanic.
+                    if let Some(cs) = char_state_maybe {
+                        if cs.is_forced_movement() {
+                            return PhysicsMetrics {
+                                entity_entity_collision_checks,
+                                entity_entity_collisions,
+                            };
+                        }
+                    }
+
                     let z_limits = calc_z_limit(char_state_maybe, collider);
 
                     // Resets touch_entities in physics