--- a/net/minecraft/world/entity/raid/Raid.java
+++ b/net/minecraft/world/entity/raid/Raid.java
@@ -176,6 +176,12 @@
         return this.status == Raid.Status.LOSS;
     }
 
+    // CraftBukkit start
+    public boolean isInProgress() {
+        return this.status == Status.ONGOING;
+    }
+    // CraftBukkit end
+
     public float getTotalHealth() {
         return this.totalHealth;
     }
@@ -272,6 +278,7 @@
 
                 this.active = this.level.hasChunkAt(this.center);
                 if (this.level.getDifficulty() == EnumDifficulty.PEACEFUL) {
+                    org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.PEACE); // CraftBukkit
                     this.stop();
                     return;
                 }
@@ -291,13 +298,16 @@
                 if (!this.level.isVillage(this.center)) {
                     if (this.groupsSpawned > 0) {
                         this.status = Raid.Status.LOSS;
+                        org.bukkit.craftbukkit.event.CraftEventFactory.callRaidFinishEvent(this, new java.util.ArrayList<>()); // CraftBukkit
                     } else {
+                        org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.NOT_IN_VILLAGE); // CraftBukkit
                         this.stop();
                     }
                 }
 
                 ++this.ticksActive;
                 if (this.ticksActive >= 48000L) {
+                    org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.TIMEOUT); // CraftBukkit
                     this.stop();
                     return;
                 }
@@ -371,6 +381,7 @@
                     }
 
                     if (j > 3) {
+                        org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE);  // CraftBukkit
                         this.stop();
                         break;
                     }
@@ -383,6 +394,7 @@
                         this.status = Raid.Status.VICTORY;
                         Iterator iterator = this.heroesOfTheVillage.iterator();
 
+                        List<org.bukkit.entity.Player> winners = new java.util.ArrayList<>(); // CraftBukkit
                         while (iterator.hasNext()) {
                             UUID uuid = (UUID) iterator.next();
                             Entity entity = this.level.getEntity(uuid);
@@ -397,10 +409,12 @@
 
                                         entityplayer.awardStat(StatisticList.RAID_WIN);
                                         CriterionTriggers.RAID_WIN.trigger(entityplayer);
+                                        winners.add(entityplayer.getBukkitEntity()); // CraftBukkit
                                     }
                                 }
                             }
                         }
+                        org.bukkit.craftbukkit.event.CraftEventFactory.callRaidFinishEvent(this, winners); // CraftBukkit
                     }
                 }
 
@@ -408,6 +422,7 @@
             } else if (this.isOver()) {
                 ++this.celebrationTicks;
                 if (this.celebrationTicks >= 600) {
+                    org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.FINISHED); // CraftBukkit
                     this.stop();
                     return;
                 }
@@ -544,6 +559,10 @@
         int j = araid_wave.length;
         int k = 0;
 
+        // CraftBukkit start
+        EntityRaider leader = null;
+        List<EntityRaider> raiders = new java.util.ArrayList<>();
+        // CraftBukkit end
         while (k < j) {
             Raid.Wave raid_wave = araid_wave[k];
             int l = this.getDefaultNumSpawns(raid_wave, i, flag1) + this.getPotentialBonusSpawns(raid_wave, this.random, i, difficultydamagescaler, flag1);
@@ -559,9 +578,11 @@
                             entityraider.setPatrolLeader(true);
                             this.setLeader(i, entityraider);
                             flag = true;
+                            leader = entityraider; // CraftBukkit
                         }
 
                         this.joinRaid(i, entityraider, blockposition, false);
+                        raiders.add(entityraider); // CraftBukkit
                         if (raid_wave.entityType == EntityTypes.RAVAGER) {
                             EntityRaider entityraider1 = null;
 
@@ -580,6 +601,7 @@
                                 this.joinRaid(i, entityraider1, blockposition, false);
                                 entityraider1.moveTo(blockposition, 0.0F, 0.0F);
                                 entityraider1.startRiding(entityraider);
+                                raiders.add(entityraider); // CraftBukkit
                             }
                         }
 
@@ -597,6 +619,7 @@
         ++this.groupsSpawned;
         this.updateBossbar();
         this.setDirty();
+        org.bukkit.craftbukkit.event.CraftEventFactory.callRaidSpawnWaveEvent(this, leader, raiders); // CraftBukkit
     }
 
     public void joinRaid(int i, EntityRaider entityraider, @Nullable BlockPosition blockposition, boolean flag) {
@@ -612,7 +635,7 @@
                 entityraider.finalizeSpawn(this.level, this.level.getCurrentDifficultyAt(blockposition), EnumMobSpawn.EVENT, (GroupDataEntity) null, (NBTTagCompound) null);
                 entityraider.applyRaidBuffs(i, false);
                 entityraider.setOnGround(true);
-                this.level.addFreshEntityWithPassengers(entityraider);
+                this.level.addFreshEntityWithPassengers(entityraider, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.RAID); // CraftBukkit
             }
         }
 
@@ -862,6 +885,12 @@
         this.heroesOfTheVillage.add(entity.getUUID());
     }
 
+    // CraftBukkit start - a method to get all raiders
+    public java.util.Collection<EntityRaider> getRaiders() {
+        return this.groupRaiderMap.values().stream().flatMap(Set::stream).collect(java.util.stream.Collectors.toSet());
+    }
+    // CraftBukkit end
+
     private static enum Status {
 
         ONGOING, VICTORY, LOSS, STOPPED;
