Refactor MobKillHandler logic and increase execution delay.

This commit is contained in:
IM23a-spirgif
2025-04-28 09:20:01 +02:00
parent b46161f060
commit 1308cd6225
2 changed files with 81 additions and 107 deletions
@@ -1,179 +1,153 @@
package net.fretux.knockedback; package net.fretux.knockedback;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import org.jetbrains.annotations.Nullable; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.network.PacketDistributor;
import java.util.HashMap; import javax.annotation.Nullable;
import java.util.Map; import java.util.*;
import java.util.UUID;
import static net.fretux.knockedback.KnockedManager.removeKnockedState; import static net.fretux.knockedback.KnockedManager.removeKnockedState;
import static net.fretux.knockedback.KnockedManager.setGripped; import static net.fretux.knockedback.KnockedManager.setGripped;
@Mod.EventBusSubscriber(modid = KnockedBack.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class MobKillHandler { public class MobKillHandler {
private static final int EXECUTION_DELAY_TICKS = 3 * 20; private static final int EXECUTION_DELAY_TICKS = 3 * 20;
public static boolean isBeingMobExecuted(UUID knockedId) {
return killAttempts.containsKey(knockedId);
}
private static final Map<UUID, KillAttempt> killAttempts = new HashMap<>(); private static final Map<UUID, KillAttempt> killAttempts = new HashMap<>();
private static class KillAttempt { private static class KillAttempt {
private final UUID mobUuid; private final UUID mobUuid;
private int timeLeft; private int timeLeft;
public KillAttempt(UUID mobUuid, int timeLeft) { public KillAttempt(UUID mobUuid, int timeLeft) {
this.mobUuid = mobUuid; this.mobUuid = mobUuid;
this.timeLeft = timeLeft; this.timeLeft = timeLeft;
} }
} }
public static boolean isBeingMobExecuted(UUID knockedId) {
return killAttempts.containsKey(knockedId);
}
@SubscribeEvent @SubscribeEvent
public void onServerTick(TickEvent.ServerTickEvent event) { public void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.END && event.side.isServer()) { if (event.phase != TickEvent.Phase.END || !event.side.isServer()) return;
tickKillAttempts(); tickKillAttempts();
}
} }
@SubscribeEvent @SubscribeEvent
public void onMobHurt(LivingHurtEvent event) { public void onMobHurt(LivingHurtEvent event) {
LivingEntity entity = event.getEntity(); LivingEntity entity = event.getEntity();
if (!(entity instanceof Mob mob)) { if (!(entity instanceof Mob mob)) return;
return;
}
UUID mobUuid = mob.getUUID();
boolean mobWasReset = false;
UUID playerToRelease = null;
for (Map.Entry<UUID, KillAttempt> entry : killAttempts.entrySet()) { UUID mobUuid = mob.getUUID();
KillAttempt attempt = entry.getValue(); UUID toRelease = null;
if (attempt.mobUuid.equals(mobUuid)) { for (var e : killAttempts.entrySet()) {
playerToRelease = entry.getKey(); if (e.getValue().mobUuid.equals(mobUuid)) {
mobWasReset = true; toRelease = e.getKey();
break; break;
} }
} }
if (toRelease != null) {
if (playerToRelease != null) { killAttempts.remove(toRelease);
killAttempts.remove(playerToRelease); Player p = getPlayerByUuid(toRelease);
Player player = getPlayerByUuid(playerToRelease); if (p != null) {
if (player != null) { setGripped(p, false);
KnockedManager.setGripped(player, false);
mob.setTarget(null); mob.setTarget(null);
mob.getNavigation().stop(); mob.getNavigation().stop();
} }
} }
if (mobWasReset) {
System.out.println("Mob hit: Canceling execution attempt and releasing gripped player.");
}
}
public static void clearKillAttempt(UUID playerUuid) {
killAttempts.remove(playerUuid);
} }
private void tickKillAttempts() { private void tickKillAttempts() {
Map<UUID, KillAttempt> updatedAttempts = new HashMap<>(); var server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
Map<UUID, KillAttempt> updated = new HashMap<>();
for (UUID knockedPlayerUuid : KnockedManager.getKnockedUuids()) { for (UUID knockedId : KnockedManager.getKnockedUuids()) {
Player knockedPlayer = getPlayerByUuid(knockedPlayerUuid); Player knocked = getPlayerByUuid(knockedId);
if (knockedPlayer == null || !knockedPlayer.isAlive()) { if (knocked == null || !knocked.isAlive()) continue;
if (CarryManager.isBeingCarried(knockedId)) {
setGripped(knocked, false);
continue; continue;
} }
Mob mobInRange = getMobInRange(knockedPlayer); Mob mob = getMobInRange(knocked);
if (mobInRange == null) { if (mob == null) {
setGripped(knockedPlayer, false); setGripped(knocked, false);
continue; continue;
} }
setGripped(knockedPlayer, true); setGripped(knocked, true);
KillAttempt attempt = killAttempts.get(knockedPlayerUuid); KillAttempt attempt = killAttempts.get(knockedId);
if (attempt == null || !attempt.mobUuid.equals(mobInRange.getUUID())) { if (attempt == null || !attempt.mobUuid.equals(mob.getUUID())) {
attempt = new KillAttempt(mobInRange.getUUID(), EXECUTION_DELAY_TICKS); attempt = new KillAttempt(mob.getUUID(), EXECUTION_DELAY_TICKS);
} else { } else {
attempt.timeLeft--; attempt.timeLeft--;
gripPlayer(knockedPlayer, mobInRange); if (knocked instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(attempt.timeLeft)
);
}
if (attempt.timeLeft <= 0) { if (attempt.timeLeft <= 0) {
executeKnockedPlayer(knockedPlayer, mobInRange); executeKnockedPlayer(knocked, mob);
continue; continue;
} }
} }
updatedAttempts.put(knockedPlayerUuid, attempt); updated.put(knockedId, attempt);
} }
// 5) Replace the map
killAttempts.clear(); killAttempts.clear();
killAttempts.putAll(updatedAttempts); killAttempts.putAll(updated);
} }
private void gripPlayer(Player knockedPlayer, Mob mob) { private void executeKnockedPlayer(Player knocked, Mob mob) {
mob.setTarget(knockedPlayer); removeKnockedState(knocked);
knocked.setHealth(0.0F);
mob.getNavigation().stop(); mob.getNavigation().stop();
spawnExecutionParticles(knockedPlayer, mob); if (knocked instanceof ServerPlayer sp) {
} NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp),
private void executeKnockedPlayer(Player knockedPlayer, Mob mob) { new ExecutionProgressPacket(0)
knockedPlayer.setHealth(0.0F); );
mob.getNavigation().stop(); }
removeKnockedState(knockedPlayer); knocked.sendSystemMessage(Component.literal(
knockedPlayer.sendSystemMessage(Component.literal(
"You were executed by " + mob.getName().getString() + "!" "You were executed by " + mob.getName().getString() + "!"
)); ));
} }
@Nullable @Nullable
private Mob getMobInRange(Player knockedPlayer) { private Mob getMobInRange(Player p) {
if (knockedPlayer.level() instanceof ServerLevel serverLevel) { if (!(p.level() instanceof ServerLevel world)) return null;
double range = 2.5; double r = 2.5;
AABB aabb = new AABB( AABB box = new AABB(
knockedPlayer.getX() - range, knockedPlayer.getY() - range, knockedPlayer.getZ() - range, p.getX()-r, p.getY()-r, p.getZ()-r,
knockedPlayer.getX() + range, knockedPlayer.getY() + range, knockedPlayer.getZ() + range p.getX()+r, p.getY()+r, p.getZ()+r
); );
return serverLevel.getEntitiesOfClass(Mob.class, aabb).stream() return world.getEntitiesOfClass(Mob.class, box).stream()
.filter(mob -> isHostile(mob) || isAggressiveNeutral(mob)) .filter(m -> isHostile(m) || isAggressiveNeutral(m))
.findAny() .findAny().orElse(null);
.orElse(null);
}
return null;
} }
private boolean isHostile(Mob mob) { private boolean isHostile(Mob m) {
return mob instanceof net.minecraft.world.entity.monster.Monster; return m instanceof net.minecraft.world.entity.monster.Monster;
} }
private boolean isAggressiveNeutral(Mob m) {
private boolean isAggressiveNeutral(Mob mob) { if (m instanceof net.minecraft.world.entity.animal.Wolf w) return w.isAngry();
if (mob instanceof net.minecraft.world.entity.animal.Wolf wolf) { if (m instanceof net.minecraft.world.entity.monster.EnderMan e) return e.isCreepy();
return wolf.isAngry();
}
if (mob instanceof net.minecraft.world.entity.monster.EnderMan enderman) {
return enderman.isCreepy();
}
return false; return false;
} }
@Nullable @Nullable
private Player getPlayerByUuid(UUID uuid) { private Player getPlayerByUuid(UUID id) {
var server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); var srv = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
if (server != null) { return srv != null ? srv.getPlayerList().getPlayer(id) : null;
return server.getPlayerList().getPlayer(uuid);
}
return null;
}
private void spawnExecutionParticles(Player knockedPlayer, Mob mobInRange) {
if (knockedPlayer.level() instanceof ServerLevel serverLevel) {
serverLevel.sendParticles(
net.minecraft.core.particles.ParticleTypes.ANGRY_VILLAGER,
mobInRange.getX(),
mobInRange.getY() + mobInRange.getBbHeight() / 2,
mobInRange.getZ(),
1, 0.1, 0.2, 0.1, 0.005
);
}
} }
} }
@@ -20,7 +20,7 @@ import java.util.UUID;
@Mod.EventBusSubscriber(modid = "knockedback", bus = Mod.EventBusSubscriber.Bus.FORGE) @Mod.EventBusSubscriber(modid = "knockedback", bus = Mod.EventBusSubscriber.Bus.FORGE)
public class PlayerExecutionHandler { public class PlayerExecutionHandler {
public static final double EXECUTION_RANGE = 2.0; public static final double EXECUTION_RANGE = 2.0;
public static final int EXECUTION_DELAY_TICKS = 60; public static final int EXECUTION_DELAY_TICKS = 100;
public static boolean isBeingPlayerExecuted(UUID knockedId) { public static boolean isBeingPlayerExecuted(UUID knockedId) {
return executionAttempts.containsKey(knockedId); return executionAttempts.containsKey(knockedId);