--- a/net/minecraft/world/damagesource/DamageSource.java
+++ b/net/minecraft/world/damagesource/DamageSource.java
@@ -20,6 +_,92 @@
     private final Entity directEntity;
     @Nullable
     private final Vec3 damageSourcePosition;
+    // CraftBukkit start
+    @Nullable
+    private org.bukkit.event.entity.EntityDamageEvent.DamageCause knownCause; // When the damage event cause is known by the context of the call rather than the damage source data
+    @Nullable
+    private Entity eventEntityDamager = null; // Relevant entity set when the game doesn't normally set a causingEntity/directEntity
+    @Nullable
+    private org.bukkit.block.Block eventBlockDamager; // Relevant block set. damageSourcePosition is only used for bad respawn point explosion or custom damage
+    @Nullable
+    private org.bukkit.block.BlockState fromBlockSnapshot; // Captured block snapshot when the eventBlockDamager is not relevant (e.g. for bad respawn point explosions the block is already removed)
+    private boolean critical; // Supports arrows and sweeping damage
+
+    public DamageSource knownCause(final org.bukkit.event.entity.EntityDamageEvent.DamageCause cause) {
+        final DamageSource damageSource = this.copy();
+        damageSource.knownCause = cause;
+        return damageSource;
+    }
+
+    @Nullable
+    public org.bukkit.event.entity.EntityDamageEvent.DamageCause knownCause() {
+        return this.knownCause;
+    }
+
+    @Nullable
+    public Entity eventEntityDamager() {
+        return this.eventEntityDamager;
+    }
+
+    public DamageSource eventEntityDamager(final Entity entity) {
+        if (this.directEntity != null) {
+            throw new IllegalStateException("Cannot set an event damager when a direct entity is already set (report a bug to Paper)");
+        }
+        final DamageSource damageSource = this.copy();
+        damageSource.eventEntityDamager = entity;
+        return damageSource;
+    }
+
+    @Nullable
+    public org.bukkit.block.Block eventBlockDamager() {
+        return this.eventBlockDamager;
+    }
+
+    public DamageSource eventBlockDamager(final @Nullable net.minecraft.world.level.LevelAccessor level, final @Nullable net.minecraft.core.BlockPos pos) {
+        if (pos == null) {
+            return this;
+        }
+
+        final DamageSource damageSource = this.copy();
+        damageSource.eventBlockDamager = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+        return damageSource;
+    }
+
+    @Nullable
+    public org.bukkit.block.BlockState causingBlockSnapshot() {
+        return this.fromBlockSnapshot;
+    }
+
+    public DamageSource causingBlockSnapshot(final @Nullable org.bukkit.block.BlockState blockState) {
+        if (this.eventBlockDamager != null) {
+            throw new IllegalStateException("Cannot set a block snapshot when an event block damager is already set (report a bug to Paper)");
+        }
+        final DamageSource damageSource = this.copy();
+        damageSource.fromBlockSnapshot = blockState;
+        return damageSource;
+    }
+
+    public boolean isCritical() {
+        return this.critical;
+    }
+
+    public DamageSource critical() {
+        final DamageSource damageSource = this.copy();
+        damageSource.critical = true;
+        return damageSource;
+    }
+
+    // Cloning the instance lets us return unique instances of DamageSource without affecting constants defined in DamageSources
+    private DamageSource copy() {
+        final DamageSource damageSource = new DamageSource(this.type, this.directEntity, this.causingEntity, this.damageSourcePosition);
+        damageSource.knownCause = this.knownCause;
+        damageSource.eventEntityDamager = this.eventEntityDamager;
+        damageSource.eventBlockDamager = this.eventBlockDamager;
+        damageSource.fromBlockSnapshot = this.fromBlockSnapshot;
+        damageSource.critical = this.critical;
+        return damageSource;
+    }
+    // CraftBukkit end
 
     @Override
     public String toString() {
