Initial Commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@Mod.EventBusSubscriber(modid = KnockedBack.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class Config
|
||||
{
|
||||
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
|
||||
private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
|
||||
.comment("Whether to log the dirt block on common setup")
|
||||
.define("logDirtBlock", true);
|
||||
|
||||
private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER
|
||||
.comment("A magic number")
|
||||
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
|
||||
|
||||
public static final ForgeConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
|
||||
.comment("What you want the introduction message to be for the magic number")
|
||||
.define("magicNumberIntroduction", "The magic number is... ");
|
||||
|
||||
// a list of strings that are treated as resource locations for items
|
||||
private static final ForgeConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
|
||||
.comment("A list of items to log on common setup.")
|
||||
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
|
||||
|
||||
static final ForgeConfigSpec SPEC = BUILDER.build();
|
||||
|
||||
public static boolean logDirtBlock;
|
||||
public static int magicNumber;
|
||||
public static String magicNumberIntroduction;
|
||||
public static Set<Item> items;
|
||||
|
||||
private static boolean validateItemName(final Object obj)
|
||||
{
|
||||
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
static void onLoad(final ModConfigEvent event)
|
||||
{
|
||||
logDirtBlock = LOG_DIRT_BLOCK.get();
|
||||
magicNumber = MAGIC_NUMBER.get();
|
||||
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
|
||||
|
||||
// convert the list of strings into a set of items
|
||||
items = ITEM_STRINGS.get().stream()
|
||||
.map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ExecuteKnockedPacket {
|
||||
public ExecuteKnockedPacket() { }
|
||||
public static void encode(ExecuteKnockedPacket msg, FriendlyByteBuf buf) {
|
||||
|
||||
}
|
||||
|
||||
public static ExecuteKnockedPacket decode(FriendlyByteBuf buf) {
|
||||
return new ExecuteKnockedPacket();
|
||||
}
|
||||
|
||||
public static void handle(ExecuteKnockedPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
ServerPlayer executor = ctx.get().getSender();
|
||||
if (executor == null) return;
|
||||
LivingEntity target = findNearestKnockedEntity(executor);
|
||||
if (target != null) {
|
||||
PlayerExecutionHandler.executeKnockedPlayer(executor, target);
|
||||
}
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static LivingEntity findNearestKnockedEntity(ServerPlayer executor) {
|
||||
return KnockedManager.getKnockedUuids().stream()
|
||||
.map(uuid -> NetworkHandlerHelper.getPlayerByUuid(executor.getServer(), uuid))
|
||||
.filter(player -> player != null && player.distanceTo(executor) <= (float) PlayerExecutionHandler.EXECUTION_RANGE)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.fretux.knockedback.effects.KnockedEffect;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDeathEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import org.slf4j.Logger;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
|
||||
@Mod(KnockedBack.MOD_ID)
|
||||
public class KnockedBack {
|
||||
public static final String MOD_ID = "knockedback";
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public KnockedBack() {
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
MinecraftForge.EVENT_BUS.register(new KnockedEffect());
|
||||
MinecraftForge.EVENT_BUS.register(new MobKillHandler());
|
||||
MinecraftForge.EVENT_BUS.register(new PlayerExecutionHandler());
|
||||
}
|
||||
|
||||
private void setup(final FMLCommonSetupEvent event) {
|
||||
NetworkHandler.register();
|
||||
PlayerExecutionHandler.register();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerStarting(ServerStartingEvent event) {
|
||||
LOGGER.info("KnockedBack mod server starting");
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onLivingHurt(LivingHurtEvent event) {
|
||||
DamageSource source = event.getSource();
|
||||
String damageType = source.getMsgId();
|
||||
if (event.getEntity() instanceof Player player && player.getHealth() - event.getAmount() <= 0) {
|
||||
if (!(damageType.equals("fall") || damageType.equals("explosion") || damageType.equals("explosion.player") ||
|
||||
damageType.equals("fire") || damageType.equals("lava") || damageType.equals("onFire") ||
|
||||
damageType.equals("fireball"))) {
|
||||
event.setCanceled(true);
|
||||
KnockedManager.applyKnockedState(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onLivingDeath(LivingDeathEvent event) {
|
||||
if (KnockedManager.isKnocked(event.getEntity())) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.END && event.side.isServer()) {
|
||||
KnockedManager.tickKnockedStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class KnockedManager {
|
||||
private static final Map<UUID, Integer> knockedEntities = new HashMap<>();
|
||||
private static final Set<UUID> grippedEntities = new HashSet<>();
|
||||
private static final int KNOCKED_DURATION = 400;
|
||||
|
||||
public static void applyKnockedState(LivingEntity entity) {
|
||||
if (!(entity instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
if (!isKnocked(entity)) {
|
||||
knockedEntities.put(entity.getUUID(), KNOCKED_DURATION);
|
||||
entity.setHealth(1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isKnocked(LivingEntity entity) {
|
||||
return knockedEntities.containsKey(entity.getUUID());
|
||||
}
|
||||
|
||||
public static void removeKnockedState(LivingEntity entity) {
|
||||
knockedEntities.remove(entity.getUUID());
|
||||
grippedEntities.remove(entity.getUUID());
|
||||
MobKillHandler.clearKillAttempt(entity.getUUID());
|
||||
}
|
||||
|
||||
public static void setGripped(LivingEntity entity, boolean isGripped) {
|
||||
if (isGripped) {
|
||||
grippedEntities.add(entity.getUUID());
|
||||
} else {
|
||||
grippedEntities.remove(entity.getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<UUID> getKnockedUuids() {
|
||||
return new HashSet<>(knockedEntities.keySet());
|
||||
}
|
||||
|
||||
public static void tickKnockedStates() {
|
||||
Iterator<Map.Entry<UUID, Integer>> it = knockedEntities.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<UUID, Integer> entry = it.next();
|
||||
UUID entityId = entry.getKey();
|
||||
int timeLeft = entry.getValue();
|
||||
if (grippedEntities.contains(entityId)) {
|
||||
continue;
|
||||
}
|
||||
int newTime = timeLeft - 1;
|
||||
if (newTime <= 0) {
|
||||
it.remove();
|
||||
} else {
|
||||
entry.setValue(newTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLivingHurt(LivingHurtEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
if (!isKnocked(entity)) return;
|
||||
|
||||
// Always reset the timer regardless of other conditions
|
||||
knockedEntities.put(entity.getUUID(), KNOCKED_DURATION);
|
||||
|
||||
DamageSource source = event.getSource();
|
||||
String damageType = source.getMsgId();
|
||||
|
||||
// Handle lethal damage cases (fire, explosions, etc.)
|
||||
if (damageType.equals("fire") || damageType.equals("lava") || damageType.equals("onFire") ||
|
||||
damageType.equals("explosion") || damageType.equals("explosion.player") || damageType.equals("fireball")) {
|
||||
entity.setHealth(0.0F);
|
||||
removeKnockedState(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle falling or lethal explosion
|
||||
if ((damageType.equals("fall") || damageType.equals("explosion") || damageType.equals("explosion.player")) &&
|
||||
event.getAmount() >= entity.getHealth()) {
|
||||
entity.setHealth(0.0F);
|
||||
removeKnockedState(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Still cancel damage for non-lethal hits, but **reset timer**
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.fretux.knockedback.KnockedManager.removeKnockedState;
|
||||
import static net.fretux.knockedback.KnockedManager.setGripped;
|
||||
|
||||
/**
|
||||
* Manages the logic for mobs killing knocked players after a 3-second delay,
|
||||
* which resets if the mob is hit during those 3 seconds.
|
||||
*/
|
||||
public class MobKillHandler {
|
||||
private static final int EXECUTION_DELAY_TICKS = 3 * 20;
|
||||
/**
|
||||
* A record of ongoing kill attempts.
|
||||
* Key = Knocked player's UUID
|
||||
* Value = An object tracking the mob's UUID & the countdown in ticks.
|
||||
*/
|
||||
private static final Map<UUID, KillAttempt> killAttempts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Data structure to hold which mob is trying to kill a knocked player,
|
||||
* along with how many ticks remain before execution.
|
||||
*/
|
||||
private static class KillAttempt {
|
||||
private final UUID mobUuid;
|
||||
private int timeLeft;
|
||||
|
||||
public KillAttempt(UUID mobUuid, int timeLeft) {
|
||||
this.mobUuid = mobUuid;
|
||||
this.timeLeft = timeLeft;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs once per server tick; we look for mobs near knocked players
|
||||
* and handle the execution countdown.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
// Only run logic at the END of each tick on the server
|
||||
if (event.phase == TickEvent.Phase.END && event.side.isServer()) {
|
||||
tickKillAttempts();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the kill timer if the mob about to perform the kill is attacked.
|
||||
* "If they're hit in those 3 seconds, the timer resets."
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public void onMobHurt(LivingHurtEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
if (!(entity instanceof Mob mob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID mobUuid = mob.getUUID();
|
||||
boolean mobWasReset = false;
|
||||
UUID playerToRelease = null;
|
||||
|
||||
for (Map.Entry<UUID, KillAttempt> entry : killAttempts.entrySet()) {
|
||||
KillAttempt attempt = entry.getValue();
|
||||
if (attempt.mobUuid.equals(mobUuid)) {
|
||||
playerToRelease = entry.getKey();
|
||||
mobWasReset = true;
|
||||
break; // Break early because we will remove later
|
||||
}
|
||||
}
|
||||
|
||||
if (playerToRelease != null) {
|
||||
killAttempts.remove(playerToRelease);
|
||||
Player player = getPlayerByUuid(playerToRelease);
|
||||
if (player != null) {
|
||||
KnockedManager.setGripped(player, false);
|
||||
mob.setTarget(null);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main logic to find mobs near knocked players and manage execution timers.
|
||||
*/
|
||||
private void tickKillAttempts() {
|
||||
Map<UUID, KillAttempt> updatedAttempts = new HashMap<>();
|
||||
|
||||
for (UUID knockedPlayerUuid : KnockedManager.getKnockedUuids()) {
|
||||
Player knockedPlayer = getPlayerByUuid(knockedPlayerUuid);
|
||||
if (knockedPlayer == null || !knockedPlayer.isAlive()) {
|
||||
continue;
|
||||
}
|
||||
Mob mobInRange = getMobInRange(knockedPlayer);
|
||||
if (mobInRange == null) {
|
||||
setGripped(knockedPlayer, false);
|
||||
continue;
|
||||
}
|
||||
setGripped(knockedPlayer, true);
|
||||
KillAttempt attempt = killAttempts.get(knockedPlayerUuid);
|
||||
if (attempt == null || !attempt.mobUuid.equals(mobInRange.getUUID())) {
|
||||
attempt = new KillAttempt(mobInRange.getUUID(), EXECUTION_DELAY_TICKS);
|
||||
} else {
|
||||
attempt.timeLeft--;
|
||||
gripPlayer(knockedPlayer, mobInRange);
|
||||
if (attempt.timeLeft <= 0) {
|
||||
executeKnockedPlayer(knockedPlayer, mobInRange);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
updatedAttempts.put(knockedPlayerUuid, attempt);
|
||||
}
|
||||
killAttempts.clear();
|
||||
killAttempts.putAll(updatedAttempts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles gripping behavior where the mob focuses on the knocked player.
|
||||
*/
|
||||
private void gripPlayer(Player knockedPlayer, Mob mob) {
|
||||
mob.setTarget(knockedPlayer);
|
||||
mob.getNavigation().stop();
|
||||
spawnExecutionParticles(knockedPlayer, mob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the knocked player when the countdown finishes.
|
||||
*/
|
||||
private void executeKnockedPlayer(Player knockedPlayer, Mob mob) {
|
||||
knockedPlayer.setHealth(0.0F);
|
||||
mob.getNavigation().stop();
|
||||
removeKnockedState(knockedPlayer);
|
||||
knockedPlayer.sendSystemMessage(Component.literal(
|
||||
"You were executed by " + mob.getName().getString() + "!"
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a mob that is within a certain range of the knocked player.
|
||||
* Only hostile mobs, aggressive neutral mobs, and players are considered.
|
||||
*/
|
||||
@Nullable
|
||||
private Mob getMobInRange(Player knockedPlayer) {
|
||||
if (knockedPlayer.level() instanceof ServerLevel serverLevel) {
|
||||
double range = 2.5;
|
||||
AABB aabb = new AABB(
|
||||
knockedPlayer.getX() - range, knockedPlayer.getY() - range, knockedPlayer.getZ() - range,
|
||||
knockedPlayer.getX() + range, knockedPlayer.getY() + range, knockedPlayer.getZ() + range
|
||||
);
|
||||
return serverLevel.getEntitiesOfClass(Mob.class, aabb).stream()
|
||||
.filter(mob -> isHostile(mob) || isAggressiveNeutral(mob))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a mob is hostile (e.g., zombies, skeletons).
|
||||
*/
|
||||
private boolean isHostile(Mob mob) {
|
||||
return mob instanceof net.minecraft.world.entity.monster.Monster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a neutral mob is aggressive (e.g., a wolf that has been attacked).
|
||||
*/
|
||||
private boolean isAggressiveNeutral(Mob mob) {
|
||||
if (mob instanceof net.minecraft.world.entity.animal.Wolf wolf) {
|
||||
return wolf.isAngry();
|
||||
}
|
||||
if (mob instanceof net.minecraft.world.entity.monster.EnderMan enderman) {
|
||||
return enderman.isCreepy();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to retrieve a Player by UUID from the server.
|
||||
*/
|
||||
@Nullable
|
||||
private Player getPlayerByUuid(UUID uuid) {
|
||||
var server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
|
||||
if (server != 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
|
||||
public class NetworkHandler {
|
||||
public static final String PROTOCOL_VERSION = "1";
|
||||
public static SimpleChannel CHANNEL;
|
||||
|
||||
public static void register() {
|
||||
CHANNEL = NetworkRegistry.newSimpleChannel(
|
||||
new ResourceLocation(KnockedBack.MOD_ID, "main"),
|
||||
() -> PROTOCOL_VERSION,
|
||||
PROTOCOL_VERSION::equals,
|
||||
PROTOCOL_VERSION::equals
|
||||
);
|
||||
|
||||
int id = 0;
|
||||
CHANNEL.registerMessage(id++,
|
||||
ExecuteKnockedPacket.class,
|
||||
ExecuteKnockedPacket::encode,
|
||||
ExecuteKnockedPacket::decode,
|
||||
ExecuteKnockedPacket::handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class NetworkHandlerHelper {
|
||||
public static ServerPlayer getPlayerByUuid(MinecraftServer server, UUID uuid) {
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
return server.getPlayerList().getPlayer(uuid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.fretux.knockedback;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "knockedback", bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class PlayerExecutionHandler {
|
||||
public static final double EXECUTION_RANGE = 2.0;
|
||||
|
||||
public static void register() {
|
||||
MinecraftForge.EVENT_BUS.register(new PlayerExecutionHandler());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCommonSetup(FMLCommonSetupEvent event) {
|
||||
register();
|
||||
}
|
||||
|
||||
public static void executeKnockedPlayer(ServerPlayer executor, LivingEntity knockedPlayer) {
|
||||
KnockedManager.removeKnockedState(knockedPlayer);
|
||||
knockedPlayer.setHealth(0.0F);
|
||||
executor.sendSystemMessage(Component.literal("You executed " + knockedPlayer.getName().getString() + "!"));
|
||||
if (knockedPlayer instanceof ServerPlayer serverPlayer) {
|
||||
serverPlayer.sendSystemMessage(Component.literal("You were executed by " + executor.getName().getString() + "!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.fretux.knockedback.client;
|
||||
|
||||
import net.fretux.knockedback.ExecuteKnockedPacket;
|
||||
import net.fretux.knockedback.NetworkHandler;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "knockedback", value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE)
|
||||
public class ClientKeyHandler {
|
||||
public static final KeyMapping EXECUTE_KEY = new KeyMapping(
|
||||
"key.knockedback.execute",
|
||||
GLFW.GLFW_KEY_B,
|
||||
"key.categories.knockedback"
|
||||
);
|
||||
|
||||
// This event still needs to be registered on the MOD bus for key mapping registration.
|
||||
@Mod.EventBusSubscriber(modid = "knockedback", value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public static class KeyMappingRegistration {
|
||||
@SubscribeEvent
|
||||
public static void registerKeyMappings(RegisterKeyMappingsEvent event) {
|
||||
event.register(EXECUTE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
||||
if (Minecraft.getInstance().screen != null) return;
|
||||
if (EXECUTE_KEY.consumeClick()) {
|
||||
if (Minecraft.getInstance().player != null) {
|
||||
Minecraft.getInstance().player.sendSystemMessage(
|
||||
Component.literal("Key B pressed! Sending execution request to server.")
|
||||
);
|
||||
// Send the packet to the server
|
||||
NetworkHandler.CHANNEL.sendToServer(new ExecuteKnockedPacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package net.fretux.knockedback.effects;
|
||||
|
||||
import net.fretux.knockedback.KnockedManager;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent;
|
||||
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "knockedback", bus = Mod.EventBusSubscriber.Bus.FORGE)
|
||||
public class KnockedEffect {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTick(LivingEvent.LivingTickEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) return;
|
||||
if (KnockedManager.isKnocked(player)) {
|
||||
player.setDeltaMovement(0, 0, 0);
|
||||
player.setSprinting(false);
|
||||
player.hurtMarked = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (KnockedManager.isKnocked(event.getEntity())) {
|
||||
if (event.isCancelable()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onBreakBlock(PlayerEvent.BreakSpeed event) {
|
||||
if (KnockedManager.isKnocked(event.getEntity())) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onAttack(AttackEntityEvent event) {
|
||||
Player player = event.getEntity();
|
||||
if (KnockedManager.isKnocked(player)) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLivingJump(LivingEvent.LivingJumpEvent event) {
|
||||
if (event.getEntity() instanceof Player player && KnockedManager.isKnocked(player)) {
|
||||
event.getEntity().setDeltaMovement(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user