add "Help Up" feature for knocked players, improve execution handling, and update mod version to 1.6.0

This commit is contained in:
2026-05-23 19:44:51 +02:00
parent 332b6552cf
commit dbb226bcde
6 changed files with 100 additions and 26 deletions
@@ -10,6 +10,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.event.entity.EntityMountEvent; import net.minecraftforge.event.entity.EntityMountEvent;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import net.minecraft.server.level.ServerLevel;
import java.util.*; import java.util.*;
@@ -26,11 +27,15 @@ public class CarryManager {
Optional<Player> existing = carrier.getPassengers().stream() Optional<Player> existing = carrier.getPassengers().stream()
.filter(p -> p instanceof Player) .filter(p -> p instanceof Player)
.map(p -> (Player) p) .map(p -> (Player) p)
.filter(p -> carrier.getUUID().equals(carrying.get(p.getUUID())))
.findFirst(); .findFirst();
if (existing.isPresent()) { if (existing.isPresent()) {
stopCarry(existing.get(), carrier); stopCarry(existing.get(), carrier);
return; return;
} }
if (stopCarrying(carrier.getUUID())) {
return;
}
Player near = findNearestKnocked(carrier); Player near = findNearestKnocked(carrier);
if (near != null) startCarry(carrier, near); if (near != null) startCarry(carrier, near);
} }
@@ -45,18 +50,19 @@ public class CarryManager {
&& !isBeingCarried(p.getUUID()) && !isBeingCarried(p.getUUID())
&& !PlayerExecutionHandler.isBeingPlayerExecuted(p.getUUID()) && !PlayerExecutionHandler.isBeingPlayerExecuted(p.getUUID())
&& !HelpUpHandler.isBeingHelped(p.getUUID())) && !HelpUpHandler.isBeingHelped(p.getUUID()))
.findFirst() .min(Comparator.comparingDouble(carrier::distanceToSqr))
.orElse(null); .orElse(null);
} }
private static void startCarry(ServerPlayer carrier, Player knocked) { private static void startCarry(ServerPlayer carrier, Player knocked) {
knocked.startRiding(carrier, true); if (knocked.level() != carrier.level()) {
carrying.put(knocked.getUUID(), carrier.getUUID()); return;
ClientboundSetPassengersPacket mountPacket = new ClientboundSetPassengersPacket(carrier);
carrier.connection.send(mountPacket);
if (knocked instanceof ServerPlayer spKnocked) {
spKnocked.connection.send(mountPacket);
} }
if (!knocked.startRiding(carrier, true)) {
return;
}
carrying.put(knocked.getUUID(), carrier.getUUID());
sendPassengerUpdate(carrier);
KnockedbackAdvancements.recordCarry(carrier); KnockedbackAdvancements.recordCarry(carrier);
carrier.sendSystemMessage(Component.translatable("message.knockedback.picked_up", knocked.getDisplayName())); carrier.sendSystemMessage(Component.translatable("message.knockedback.picked_up", knocked.getDisplayName()));
knocked.sendSystemMessage(Component.translatable("message.knockedback.being_carried", carrier.getDisplayName())); knocked.sendSystemMessage(Component.translatable("message.knockedback.being_carried", carrier.getDisplayName()));
@@ -66,15 +72,43 @@ public class CarryManager {
private static void stopCarry(Player knocked, ServerPlayer carrier) { private static void stopCarry(Player knocked, ServerPlayer carrier) {
carrying.remove(knocked.getUUID()); carrying.remove(knocked.getUUID());
knocked.stopRiding(); knocked.stopRiding();
ClientboundSetPassengersPacket dismountPacket = new ClientboundSetPassengersPacket(carrier); sendPassengerUpdate(carrier);
carrier.connection.send(dismountPacket);
if (knocked instanceof ServerPlayer spKnocked) {
spKnocked.connection.send(dismountPacket);
}
carrier.sendSystemMessage(Component.translatable("message.knockedback.dropped", knocked.getDisplayName())); carrier.sendSystemMessage(Component.translatable("message.knockedback.dropped", knocked.getDisplayName()));
knocked.sendSystemMessage(Component.translatable("message.knockedback.been_dropped", carrier.getDisplayName())); knocked.sendSystemMessage(Component.translatable("message.knockedback.been_dropped", carrier.getDisplayName()));
} }
public static void stopCarry(UUID knockedId) {
UUID carrierId = carrying.get(knockedId);
if (carrierId == null) return;
var server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
ServerPlayer carrier = NetworkHandlerHelper.getPlayerByUuid(server, carrierId);
ServerPlayer knocked = NetworkHandlerHelper.getPlayerByUuid(server, knockedId);
if (carrier != null && knocked != null) {
stopCarry(knocked, carrier);
} else {
carrying.remove(knockedId);
}
}
public static boolean stopCarrying(UUID carrierId) {
List<UUID> knockedIds = carrying.entrySet().stream()
.filter(entry -> entry.getValue().equals(carrierId))
.map(Map.Entry::getKey)
.toList();
for (UUID knockedId : knockedIds) {
stopCarry(knockedId);
}
return !knockedIds.isEmpty();
}
private static void sendPassengerUpdate(ServerPlayer carrier) {
if (carrier.level() instanceof ServerLevel level) {
level.getChunkSource().broadcastAndSend(carrier, new ClientboundSetPassengersPacket(carrier));
} else {
carrier.connection.send(new ClientboundSetPassengersPacket(carrier));
}
}
@SubscribeEvent @SubscribeEvent
public static void onServerTick(TickEvent.ServerTickEvent ev) { public static void onServerTick(TickEvent.ServerTickEvent ev) {
if (ev.phase != TickEvent.Phase.END || !ev.side.isServer()) return; if (ev.phase != TickEvent.Phase.END || !ev.side.isServer()) return;
@@ -87,7 +121,9 @@ public class CarryManager {
ServerPlayer knocked = NetworkHandlerHelper.getPlayerByUuid(server, knockedId); ServerPlayer knocked = NetworkHandlerHelper.getPlayerByUuid(server, knockedId);
if (carrier == null || knocked == null if (carrier == null || knocked == null
|| !KnockedManager.isKnocked(knocked) || !KnockedManager.isKnocked(knocked)
|| carrier.distanceTo(knocked) > CARRY_RANGE) { || carrier.level() != knocked.level()
|| knocked.getVehicle() != carrier
|| carrier.distanceToSqr(knocked) > CARRY_RANGE * CARRY_RANGE) {
toDrop.add(knockedId); toDrop.add(knockedId);
} }
} }
@@ -45,8 +45,9 @@ public class ExecuteKnockedPacket {
.map(uuid -> NetworkHandlerHelper.getPlayerByUuid(executor.getServer(), uuid)) .map(uuid -> NetworkHandlerHelper.getPlayerByUuid(executor.getServer(), uuid))
.filter(player -> player != null .filter(player -> player != null
&& !player.getUUID().equals(executor.getUUID()) && !player.getUUID().equals(executor.getUUID())
&& player.distanceTo(executor) <= (float) PlayerExecutionHandler.EXECUTION_RANGE) && player.level() == executor.level()
.findFirst() && player.distanceToSqr(executor) <= PlayerExecutionHandler.EXECUTION_RANGE * PlayerExecutionHandler.EXECUTION_RANGE)
.min(java.util.Comparator.comparingDouble(executor::distanceToSqr))
.orElse(null); .orElse(null);
} }
} }
@@ -115,14 +115,17 @@ public class HelpUpHandler {
HelpUpAttempt attempt = entry.getValue(); HelpUpAttempt attempt = entry.getValue();
ServerPlayer knocked = getPlayerByUuid(knockedId); ServerPlayer knocked = getPlayerByUuid(knockedId);
ServerPlayer helper = getPlayerByUuid(attempt.helperId); ServerPlayer helper = getPlayerByUuid(attempt.helperId);
if (knocked == null || helper == null || !KnockedManager.isKnocked(knocked)) { if (knocked == null || helper == null
|| !KnockedManager.isKnocked(knocked)
|| KnockedManager.isKnocked(helper)) {
toCancel.add(knockedId); toCancel.add(knockedId);
continue; continue;
} }
if (CarryManager.isBeingCarried(knockedId) if (CarryManager.isBeingCarried(knockedId)
|| PlayerExecutionHandler.isBeingPlayerExecuted(knockedId) || PlayerExecutionHandler.isBeingPlayerExecuted(knockedId)
|| MobKillHandler.isBeingMobExecuted(knockedId) || MobKillHandler.isBeingMobExecuted(knockedId)
|| helper.distanceTo(knocked) > HELP_UP_RANGE) { || helper.level() != knocked.level()
|| helper.distanceToSqr(knocked) > HELP_UP_RANGE * HELP_UP_RANGE) {
toCancel.add(knockedId); toCancel.add(knockedId);
continue; continue;
} }
@@ -143,7 +146,9 @@ public class HelpUpHandler {
if (attempt == null) continue; if (attempt == null) continue;
ServerPlayer knocked = getPlayerByUuid(knockedId); ServerPlayer knocked = getPlayerByUuid(knockedId);
ServerPlayer helper = getPlayerByUuid(attempt.helperId); ServerPlayer helper = getPlayerByUuid(attempt.helperId);
if (knocked == null || helper == null) { if (knocked == null || helper == null
|| helper.level() != knocked.level()
|| helper.distanceToSqr(knocked) > HELP_UP_RANGE * HELP_UP_RANGE) {
cancelHelpUp(knockedId); cancelHelpUp(knockedId);
continue; continue;
} }
@@ -190,7 +195,7 @@ public class HelpUpHandler {
&& !PlayerExecutionHandler.isBeingPlayerExecuted(player.getUUID()) && !PlayerExecutionHandler.isBeingPlayerExecuted(player.getUUID())
&& !MobKillHandler.isBeingMobExecuted(player.getUUID()) && !MobKillHandler.isBeingMobExecuted(player.getUUID())
&& !isBeingHelped(player.getUUID())) && !isBeingHelped(player.getUUID()))
.findFirst() .min(java.util.Comparator.comparingDouble(helper::distanceToSqr))
.orElse(null); .orElse(null);
} }
@@ -69,9 +69,11 @@ public class KnockedManager {
} }
public static void removeKnockedState(LivingEntity entity) { public static void removeKnockedState(LivingEntity entity) {
CarryManager.stopCarry(entity.getUUID());
knockedEntities.remove(entity.getUUID()); knockedEntities.remove(entity.getUUID());
setGripped(entity, false); setGripped(entity, false);
MobKillHandler.clearKillAttempt(entity.getUUID()); MobKillHandler.clearKillAttempt(entity.getUUID());
PlayerExecutionHandler.cancelExecution(entity.getUUID());
HelpUpHandler.cancelHelpUp(entity.getUUID()); HelpUpHandler.cancelHelpUp(entity.getUUID());
entity.setPose(Pose.STANDING); entity.setPose(Pose.STANDING);
if (entity instanceof ServerPlayer sp) { if (entity instanceof ServerPlayer sp) {
@@ -211,8 +213,12 @@ public class KnockedManager {
knockedEntities.remove(playerId); knockedEntities.remove(playerId);
grippedEntities.remove(playerId); grippedEntities.remove(playerId);
MobKillHandler.clearKillAttempt(playerId); MobKillHandler.clearKillAttempt(playerId);
PlayerExecutionHandler.cancelExecution(playerId);
PlayerExecutionHandler.cancelExecutionByExecutor(playerId);
HelpUpHandler.cancelHelpUp(playerId); HelpUpHandler.cancelHelpUp(playerId);
HelpUpHandler.cancelHelpUpByHelper(playerId); HelpUpHandler.cancelHelpUpByHelper(playerId);
CarryManager.stopCarry(playerId);
CarryManager.stopCarrying(playerId);
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new KnockedTimePacket(0) new KnockedTimePacket(0)
@@ -238,7 +244,10 @@ public class KnockedManager {
return; return;
} }
HelpUpHandler.cancelHelpUpByHelper(sp.getUUID()); HelpUpHandler.cancelHelpUpByHelper(sp.getUUID());
PlayerExecutionHandler.cancelExecutionByExecutor(sp.getUUID());
CarryManager.stopCarrying(sp.getUUID());
if (!isKnocked(sp)) { if (!isKnocked(sp)) {
CarryManager.stopCarry(sp.getUUID());
return; return;
} }
killAndRemove(sp); killAndRemove(sp);
@@ -109,6 +109,11 @@ public class MobKillHandler {
setGripped(knocked, false); setGripped(knocked, false);
continue; continue;
} }
if (PlayerExecutionHandler.isBeingPlayerExecuted(knockedId)
|| HelpUpHandler.isBeingHelped(knockedId)) {
setGripped(knocked, false);
continue;
}
KillAttempt attempt = killAttempts.get(knockedId); KillAttempt attempt = killAttempts.get(knockedId);
Mob mob = attempt != null ? getMobInRangeById(knocked, attempt.mobUuid) : null; Mob mob = attempt != null ? getMobInRangeById(knocked, attempt.mobUuid) : null;
if (mob == null) { if (mob == null) {
@@ -70,13 +70,17 @@ public class PlayerExecutionHandler {
executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_while_knocked")); executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_while_knocked"));
return; return;
} }
if (isExecuting(executor.getUUID())) return;
UUID knockedId = target.getUUID(); UUID knockedId = target.getUUID();
if (!KnockedManager.isKnocked(target)) return; if (!KnockedManager.isKnocked(target)) return;
if (executor.level() != target.level()
|| executor.distanceToSqr(target) > EXECUTION_RANGE * EXECUTION_RANGE) return;
if (CarryManager.isBeingCarried(target.getUUID())) { if (CarryManager.isBeingCarried(target.getUUID())) {
executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_carried_player")); executor.sendSystemMessage(Component.translatable("message.knockedback.cannot_execute_carried_player"));
return; return;
} }
if (HelpUpHandler.isBeingHelped(knockedId)) return; if (HelpUpHandler.isBeingHelped(knockedId)) return;
if (MobKillHandler.isBeingMobExecuted(knockedId)) return;
if (executionAttempts.containsKey(knockedId)) return; if (executionAttempts.containsKey(knockedId)) return;
executionAttempts.put(knockedId, new PlayerExecutionAttempt(executor.getUUID())); executionAttempts.put(knockedId, new PlayerExecutionAttempt(executor.getUUID()));
executor.sendSystemMessage(Component.translatable("message.knockedback.execution_started")); executor.sendSystemMessage(Component.translatable("message.knockedback.execution_started"));
@@ -105,12 +109,9 @@ public class PlayerExecutionHandler {
} }
} }
@SubscribeEvent public static void cancelExecutionByExecutor(UUID executorId) {
public static void onLivingHurt(LivingHurtEvent event) {
if (!(event.getEntity() instanceof ServerPlayer hurtPlayer)) return;
UUID hurtId = hurtPlayer.getUUID();
List<UUID> toCancel = executionAttempts.entrySet().stream() List<UUID> toCancel = executionAttempts.entrySet().stream()
.filter(entry -> entry.getValue().executorUuid.equals(hurtId)) .filter(entry -> entry.getValue().executorUuid.equals(executorId))
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.toList(); .toList();
for (UUID knockedId : toCancel) { for (UUID knockedId : toCancel) {
@@ -118,12 +119,24 @@ public class PlayerExecutionHandler {
} }
} }
@SubscribeEvent
public static void onLivingHurt(LivingHurtEvent event) {
if (!(event.getEntity() instanceof ServerPlayer hurtPlayer)) return;
cancelExecutionByExecutor(hurtPlayer.getUUID());
}
private static ServerPlayer getPlayerByUuid(UUID uuid) { private static ServerPlayer getPlayerByUuid(UUID uuid) {
MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
return server.getPlayerList().getPlayer(uuid); return server.getPlayerList().getPlayer(uuid);
} }
public static void executeKnockedPlayer(ServerPlayer executor, LivingEntity knockedPlayer) { public static void executeKnockedPlayer(ServerPlayer executor, LivingEntity knockedPlayer) {
if (!KnockedManager.isKnocked(knockedPlayer)
|| executor.level() != knockedPlayer.level()
|| executor.distanceToSqr(knockedPlayer) > EXECUTION_RANGE * EXECUTION_RANGE) {
cancelExecution(knockedPlayer.getUUID());
return;
}
UUID id = knockedPlayer.getUUID(); UUID id = knockedPlayer.getUUID();
executionAttempts.remove(id); executionAttempts.remove(id);
KnockedManager.removeKnockedState(knockedPlayer); KnockedManager.removeKnockedState(knockedPlayer);
@@ -159,11 +172,16 @@ public class PlayerExecutionHandler {
PlayerExecutionAttempt attempt = entry.getValue(); PlayerExecutionAttempt attempt = entry.getValue();
ServerPlayer knocked = getPlayerByUuid(knockedId); ServerPlayer knocked = getPlayerByUuid(knockedId);
ServerPlayer executor = getPlayerByUuid(attempt.executorUuid); ServerPlayer executor = getPlayerByUuid(attempt.executorUuid);
if (knocked == null || executor == null || !KnockedManager.isKnocked(knocked)) { if (knocked == null || executor == null
|| !KnockedManager.isKnocked(knocked)
|| KnockedManager.isKnocked(executor)) {
toCancel.add(knockedId); toCancel.add(knockedId);
continue; continue;
} }
if (executor.distanceTo(knocked) > EXECUTION_RANGE) { if (executor.level() != knocked.level()
|| executor.distanceToSqr(knocked) > EXECUTION_RANGE * EXECUTION_RANGE
|| CarryManager.isBeingCarried(knockedId)
|| HelpUpHandler.isBeingHelped(knockedId)) {
toCancel.add(knockedId); toCancel.add(knockedId);
continue; continue;
} }