Files
KnockedBack/src/main/java/net/fretux/knockedback/PlayerExecutionHandler.java
T

205 lines
8.8 KiB
Java

package net.fretux.knockedback;
import net.fretux.knockedback.config.Config;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.network.PacketDistributor;
import java.util.*;
@Mod.EventBusSubscriber(modid = "knockedback", bus = Mod.EventBusSubscriber.Bus.FORGE)
public class PlayerExecutionHandler {
public static final double EXECUTION_RANGE = 2.0;
private static final Set<UUID> killingNow = new HashSet<>();
public static int getExecutionTime() {
return Config.COMMON.executionTime.get();
}
public static boolean isBeingPlayerExecuted(UUID knockedId) {
return executionAttempts.containsKey(knockedId);
}
public static boolean isExecuting(UUID playerUuid) {
return executionAttempts.values().stream().anyMatch(attempt -> attempt.executorUuid.equals(playerUuid));
}
public static boolean isExecutingTarget(UUID executorId, UUID knockedId) {
PlayerExecutionAttempt attempt = executionAttempts.get(knockedId);
return attempt != null && attempt.executorUuid.equals(executorId);
}
@SubscribeEvent
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
if (event.side.isServer() && event.phase == TickEvent.Phase.END && event.player instanceof ServerPlayer sp && isExecuting(sp.getUUID())) {
sp.setDeltaMovement(0, 0, 0);
sp.setSprinting(false);
}
}
@SubscribeEvent
public static void onAttackEntity(AttackEntityEvent event) {
if (event.getEntity() instanceof ServerPlayer sp && isExecuting(sp.getUUID())) {
event.setCanceled(true);
}
}
private static final Map<UUID, PlayerExecutionAttempt> executionAttempts = new HashMap<>();
private static class PlayerExecutionAttempt {
private final UUID executorUuid;
private int timeLeft;
public PlayerExecutionAttempt(UUID executorUuid) {
this.executorUuid = executorUuid;
this.timeLeft = getExecutionTime();
}
}
public static void startExecution(ServerPlayer executor, Player target) {
if (KnockedManager.isKnocked(executor)) {
executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_while_knocked"));
return;
}
UUID knockedId = target.getUUID();
if (!KnockedManager.isKnocked(target)) return;
if (CarryManager.isBeingCarried(target.getUUID())) {
executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_carried_player"));
return;
}
if (HelpUpHandler.isBeingHelped(knockedId)) return;
if (executionAttempts.containsKey(knockedId)) return;
executionAttempts.put(knockedId, new PlayerExecutionAttempt(executor.getUUID()));
executor.sendSystemMessage(Component.translatable("message.knockedback.execution_started"));
target.sendSystemMessage(Component.translatable("message.knockedback.being_executed"));
}
public static void cancelExecution(UUID knockedId) {
PlayerExecutionAttempt attempt = executionAttempts.remove(knockedId);
if (attempt != null) {
ServerPlayer knocked = getPlayerByUuid(knockedId);
if (knocked != null) {
knocked.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted"));
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> knocked),
new ExecutionProgressPacket(0, null)
);
}
ServerPlayer executor = getPlayerByUuid(attempt.executorUuid);
if (executor != null) {
executor.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted_executor"));
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(0, null)
);
}
}
}
@SubscribeEvent
public static void onLivingHurt(LivingHurtEvent event) {
if (!(event.getEntity() instanceof ServerPlayer hurtPlayer)) return;
UUID hurtId = hurtPlayer.getUUID();
List<UUID> toCancel = executionAttempts.entrySet().stream()
.filter(entry -> entry.getValue().executorUuid.equals(hurtId))
.map(Map.Entry::getKey)
.toList();
for (UUID knockedId : toCancel) {
cancelExecution(knockedId);
}
}
private static ServerPlayer getPlayerByUuid(UUID uuid) {
MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
return server.getPlayerList().getPlayer(uuid);
}
public static void executeKnockedPlayer(ServerPlayer executor, LivingEntity knockedPlayer) {
UUID id = knockedPlayer.getUUID();
executionAttempts.remove(id);
KnockedManager.removeKnockedState(knockedPlayer);
KnockedManager.markKillInProgress(knockedPlayer);
knockedPlayer.kill();
KnockedManager.unmarkKillInProgress(knockedPlayer);
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(0, null)
);
if (knockedPlayer instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0, null)
);
}
KnockedbackAdvancements.recordExecution(executor);
executor.sendSystemMessage(Component.translatable("message.knockedback.you_executed", knockedPlayer.getDisplayName()));
if (knockedPlayer instanceof ServerPlayer serverPlayer) {
serverPlayer.sendSystemMessage(Component.translatable("message.knockedback.you_were_executed", executor.getDisplayName()));
}
}
@SubscribeEvent
public static void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase != TickEvent.Phase.END || !event.side.isServer()) return;
Map<UUID, PlayerExecutionAttempt> updated = new HashMap<>();
List<UUID> toCancel = new ArrayList<>();
List<UUID> toExecute = new ArrayList<>();
for (Map.Entry<UUID, PlayerExecutionAttempt> entry : executionAttempts.entrySet()) {
UUID knockedId = entry.getKey();
PlayerExecutionAttempt attempt = entry.getValue();
ServerPlayer knocked = getPlayerByUuid(knockedId);
ServerPlayer executor = getPlayerByUuid(attempt.executorUuid);
if (knocked == null || executor == null || !KnockedManager.isKnocked(knocked)) {
toCancel.add(knockedId);
continue;
}
if (executor.distanceTo(knocked) > EXECUTION_RANGE) {
toCancel.add(knockedId);
continue;
}
attempt.timeLeft--;
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(attempt.timeLeft, getExecutionTime(), ExecutionProgressPacket.Action.EXECUTION, knocked.getDisplayName().getString(), attempt.executorUuid)
);
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> knocked),
new ExecutionProgressPacket(attempt.timeLeft, getExecutionTime(), ExecutionProgressPacket.Action.EXECUTION, knocked.getDisplayName().getString(), attempt.executorUuid)
);
if (attempt.timeLeft <= 0) {
toExecute.add(knockedId);
} else {
updated.put(knockedId, attempt);
}
}
for (UUID knockedId : toCancel) {
cancelExecution(knockedId);
}
for (UUID knockedId : toExecute) {
PlayerExecutionAttempt attempt = executionAttempts.get(knockedId);
if (attempt == null) {
continue;
}
ServerPlayer knocked = getPlayerByUuid(knockedId);
ServerPlayer executor = getPlayerByUuid(attempt.executorUuid);
if (knocked == null || executor == null) {
cancelExecution(knockedId);
continue;
}
executeKnockedPlayer(executor, knocked);
}
executionAttempts.clear();
executionAttempts.putAll(updated);
}
}