diff --git a/build.gradle b/build.gradle index d5234af..b4c6a6d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.3-SNAPSHOT" apply false + id "dev.architectury.loom" version "1.4-SNAPSHOT" apply false } architectury { diff --git a/common/build.gradle b/common/build.gradle index fe38fa0..a545d0d 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -12,6 +12,8 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" // Remove the next line if you don't want to depend on the API modApi "dev.architectury:architectury:${rootProject.architectury_version}" + + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.3.3")) } publishing { diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsCommon.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsCommon.java index f41886f..d7fea13 100644 --- a/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsCommon.java +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsCommon.java @@ -1,7 +1,16 @@ package ru.octol1ttle.knockdowns.common; +import ru.octol1ttle.knockdowns.common.events.KnockdownsClientEvents; +import ru.octol1ttle.knockdowns.common.events.KnockdownsEvents; +import ru.octol1ttle.knockdowns.common.registries.KnockdownsSoundEvents; + public class KnockdownsCommon { public static final String MOD_ID = "knockdowns"; + public static void init() { + KnockdownsSoundEvents.register(); + KnockdownsNetwork.registerPackets(); + KnockdownsClientEvents.registerCallbacks(); + KnockdownsEvents.registerCallbacks(); } } diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsNetwork.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsNetwork.java new file mode 100644 index 0000000..3e552bc --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/KnockdownsNetwork.java @@ -0,0 +1,90 @@ +package ru.octol1ttle.knockdowns.common; + +import dev.architectury.networking.NetworkChannel; +import dev.architectury.networking.NetworkManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.Packet; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.EntityTrackingListener; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.server.world.ThreadedAnvilChunkStorage; +import net.minecraft.util.Identifier; +import ru.octol1ttle.knockdowns.common.packets.KnockedDownStatusPacket; +import ru.octol1ttle.knockdowns.common.packets.PlayKnockedDownSoundS2CPacket; +import ru.octol1ttle.knockdowns.common.packets.ReviveStatusPacket; + +public class KnockdownsNetwork { + private static final NetworkChannel CHANNEL = NetworkChannel.create(new Identifier(KnockdownsCommon.MOD_ID, "main")); + public static void registerPackets() { + CHANNEL.register(KnockedDownStatusPacket.SendS2C.class, KnockedDownStatusPacket.SendS2C::encode, KnockedDownStatusPacket.SendS2C::new, KnockedDownStatusPacket.SendS2C::apply); + CHANNEL.register(KnockedDownStatusPacket.RequestC2S.class, KnockedDownStatusPacket.RequestC2S::encode, KnockedDownStatusPacket.RequestC2S::new, KnockedDownStatusPacket.RequestC2S::apply); + + CHANNEL.register(PlayKnockedDownSoundS2CPacket.class, PlayKnockedDownSoundS2CPacket::encode, PlayKnockedDownSoundS2CPacket::new, PlayKnockedDownSoundS2CPacket::apply); + + CHANNEL.register(ReviveStatusPacket.SendS2C.class, ReviveStatusPacket.SendS2C::encode, ReviveStatusPacket.SendS2C::new, ReviveStatusPacket.SendS2C::apply); + CHANNEL.register(ReviveStatusPacket.SendC2S.class, ReviveStatusPacket.SendC2S::encode, ReviveStatusPacket.SendC2S::new, ReviveStatusPacket.SendC2S::apply); + CHANNEL.register(ReviveStatusPacket.RequestC2S.class, ReviveStatusPacket.RequestC2S::encode, ReviveStatusPacket.RequestC2S::new, ReviveStatusPacket.RequestC2S::apply); + CHANNEL.register(ReviveStatusPacket.RevivedC2S.class, ReviveStatusPacket.RevivedC2S::encode, ReviveStatusPacket.RevivedC2S::new, ReviveStatusPacket.RevivedC2S::apply); + } + + public static void sendToServer(T message) { + if (CHANNEL.canServerReceive(message.getClass())) { + CHANNEL.sendToServer(message); + } + } + + public static void sendToPlayer(PlayerEntity player, T message) { + Packet packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message); + Class messageClass = message.getClass(); + + sendToPlayer(player, packet, messageClass); + } + + public static void sendToPlayer(PlayerEntity player, Packet packet, Class messageClass) { + if (!(player instanceof ServerPlayerEntity serverPlayer)) { + throw new IllegalArgumentException("Cannot send to client players"); + } + if (CHANNEL.canPlayerReceive(serverPlayer, messageClass)) { + serverPlayer.networkHandler.sendPacket(packet); + } + } + + // TODO: PR to Architectury API + public static void sendToListeners(Entity entity, T message) { + Packet packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message); + Class messageClass = message.getClass(); + + sendToListeners(entity, packet, messageClass); + } + + private static void sendToListeners(Entity entity, Packet packet, Class messageClass) { + ServerChunkManager chunkManager = (ServerChunkManager) entity.getWorld().getChunkManager(); + ThreadedAnvilChunkStorage.EntityTracker entityTracker = chunkManager.threadedAnvilChunkStorage.entityTrackers.get(entity.getId()); + + for (EntityTrackingListener listener : entityTracker.listeners) { + sendToPlayer(listener.getPlayer(), packet, messageClass); + } + } + + public static void sendToListenersAndSelf(PlayerEntity player, T message) { + Packet packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message); + Class messageClass = message.getClass(); + sendToPlayer(player, packet, messageClass); + sendToListeners(player, packet, messageClass); + } + + public static void sendToWorld(ServerWorld world, T message) { + Packet packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message); + Class messageClass = message.getClass(); + + sendToWorld(world, packet, messageClass); + } + + private static void sendToWorld(ServerWorld world, Packet packet, Class messageClass) { + for (ServerPlayerEntity player : world.getPlayers()) { + sendToPlayer(player, packet, messageClass); + } + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/api/IKnockableDown.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/api/IKnockableDown.java new file mode 100644 index 0000000..03f010f --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/api/IKnockableDown.java @@ -0,0 +1,15 @@ +package ru.octol1ttle.knockdowns.common.api; + +import java.util.UUID; + +public interface IKnockableDown { + boolean knockdowns$isKnockedDown(); + + void knockdowns$setKnockedDown(boolean knockedDown); + + boolean knockdowns$isBeingRevived(); + + void knockdowns$setBeingRevived(boolean beingRevived); + + UUID knockdowns$getUuid(); +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsClientEvents.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsClientEvents.java new file mode 100644 index 0000000..459d763 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsClientEvents.java @@ -0,0 +1,105 @@ +package ru.octol1ttle.knockdowns.common.events; + +import dev.architectury.event.EventResult; +import dev.architectury.event.events.client.ClientGuiEvent; +import dev.architectury.event.events.client.ClientPlayerEvent; +import dev.architectury.event.events.client.ClientTickEvent; +import dev.architectury.event.events.common.InteractionEvent; +import java.util.UUID; +import net.minecraft.SharedConstants; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import ru.octol1ttle.knockdowns.common.KnockdownsNetwork; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; +import ru.octol1ttle.knockdowns.common.packets.KnockedDownStatusPacket; +import ru.octol1ttle.knockdowns.common.packets.ReviveStatusPacket; + +public class KnockdownsClientEvents { + private static final int REVIVAL_WAIT_TIME = 10 * SharedConstants.TICKS_PER_SECOND; + private static IKnockableDown reviving = null; + private static int revivalTimer = -1; + + public static void registerCallbacks() { + registerOnEntityLoad(); + registerOnEntityUse(); + registerOnWorldTick(); + registerOnHudRender(); + } + + private static void registerOnEntityLoad() { + ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(player -> { + UUID playerUuid = player.getUuid(); + KnockdownsNetwork.sendToServer(new KnockedDownStatusPacket.RequestC2S(playerUuid)); + KnockdownsNetwork.sendToServer(new ReviveStatusPacket.RequestC2S(playerUuid)); + }); + } + + private static void registerOnEntityUse() { + InteractionEvent.INTERACT_ENTITY.register((player, entity, hand) -> { + if (!(entity instanceof IKnockableDown knockableEntity) || !knockableEntity.knockdowns$isKnockedDown() + || knockableEntity.knockdowns$isBeingRevived()) { + return EventResult.pass(); + } + + IKnockableDown self = (IKnockableDown) player; + if (self.knockdowns$isKnockedDown()) { + return EventResult.interruptFalse(); + } + + knockableEntity.knockdowns$setBeingRevived(true); + KnockdownsNetwork.sendToServer(new ReviveStatusPacket.SendC2S(entity.getUuid(), true)); + + reviving = knockableEntity; + revivalTimer = REVIVAL_WAIT_TIME; + + return EventResult.interruptTrue(); + }); + } + + private static void registerOnWorldTick() { + ClientTickEvent.ClientLevel.CLIENT_LEVEL_POST.register(world -> { + boolean revived = false; + revivalTimer--; + if (revivalTimer <= 0) { + revivalTimer = -1; + revived = true; + } + + if (reviving == null) { + return; + } + + HitResult crosshairTarget = MinecraftClient.getInstance().crosshairTarget; + if (revived || crosshairTarget == null || crosshairTarget.getType() != HitResult.Type.ENTITY + || !((EntityHitResult) crosshairTarget).getEntity().getUuid().equals(reviving.knockdowns$getUuid())) { + reviving.knockdowns$setBeingRevived(false); + + KnockdownsNetwork.sendToServer(new ReviveStatusPacket.SendC2S(reviving.knockdowns$getUuid(), false)); + if (revived) { + reviving.knockdowns$setKnockedDown(false); + + KnockdownsNetwork.sendToServer(new ReviveStatusPacket.RevivedC2S(reviving.knockdowns$getUuid())); + } + + reviving = null; + revivalTimer = -1; + } + }); + } + + private static void registerOnHudRender() { + ClientGuiEvent.RENDER_HUD.register((drawContext, tickDelta) -> { + if (revivalTimer == -1) { + return; + } + + TextRenderer renderer = MinecraftClient.getInstance().textRenderer; + String text = String.format("%.1f", revivalTimer / (float) SharedConstants.TICKS_PER_SECOND); + int x = (drawContext.getScaledWindowWidth() - renderer.getWidth(text)) / 2; + + drawContext.drawTextWithShadow(renderer, text, x, drawContext.getScaledWindowHeight() / 2 + 15, 0xFFFFFF); + }); + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsEvents.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsEvents.java new file mode 100644 index 0000000..a812469 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/events/KnockdownsEvents.java @@ -0,0 +1,87 @@ +package ru.octol1ttle.knockdowns.common.events; + +import dev.architectury.event.CompoundEventResult; +import dev.architectury.event.EventResult; +import dev.architectury.event.events.common.EntityEvent; +import dev.architectury.event.events.common.InteractionEvent; +import dev.architectury.event.events.common.PlayerEvent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableTextContent; +import net.minecraft.util.Hand; +import net.minecraft.world.GameRules; +import ru.octol1ttle.knockdowns.common.KnockdownsNetwork; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; +import ru.octol1ttle.knockdowns.common.packets.KnockedDownStatusPacket; +import ru.octol1ttle.knockdowns.common.packets.PlayKnockedDownSoundS2CPacket; + +public class KnockdownsEvents { + public static void registerCallbacks() { + registerOnLivingDeath(); + registerOnPlayerInteractions(); + } + + private static void registerOnLivingDeath() { + EntityEvent.LIVING_DEATH.register((entity, source) -> { + if (!(entity instanceof IKnockableDown knockableDown) || knockableDown.knockdowns$isKnockedDown()) { + return EventResult.pass(); + } + + ServerPlayerEntity serverPlayer = (ServerPlayerEntity) entity; + // TODO: timer + if (!serverPlayer.getWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) { + serverPlayer.getInventory().dropAll(); + } + entity.setHealth(1.0f); + entity.setInvulnerable(true); + entity.setGlowing(true); + entity.setAir(entity.getMaxAir()); + entity.extinguish(); + entity.setFrozenTicks(0); + entity.setOnFire(false); + entity.clearStatusEffects(); + + knockableDown.knockdowns$setKnockedDown(true); + + KnockdownsNetwork.sendToListenersAndSelf(serverPlayer, new KnockedDownStatusPacket.SendS2C(serverPlayer.getUuid(), true)); + KnockdownsNetwork.sendToWorld(serverPlayer.getServerWorld(), new PlayKnockedDownSoundS2CPacket(serverPlayer.getX(), serverPlayer.getY(), serverPlayer.getZ())); + + TranslatableTextContent content = (TranslatableTextContent) entity.getDamageTracker().getDeathMessage().getContent(); + Text replaced = Text.translatableWithFallback(content.getKey().replace("death.", "knockdown."), content.getKey(), content.getArgs()); + MinecraftServer server = serverPlayer.getServer(); + if (server != null) { + server.getPlayerManager().broadcast(replaced, false); + } + + return EventResult.interruptFalse(); + }); + } + + private static void registerOnPlayerInteractions() { + InteractionEvent.LEFT_CLICK_BLOCK.register((player, hand, pos, direction) -> { + if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) { + return EventResult.interruptFalse(); + } + return EventResult.pass(); + }); + PlayerEvent.ATTACK_ENTITY.register((player, world, hand, entity, hitResult) -> { + if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) { + return EventResult.interruptFalse(); + } + return EventResult.pass(); + }); + InteractionEvent.RIGHT_CLICK_ITEM.register((player, hand) -> { + if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) { + return CompoundEventResult.interruptFalse(hand == Hand.MAIN_HAND ? player.getMainHandStack() : player.getOffHandStack()); + } + return CompoundEventResult.pass(); + }); + InteractionEvent.RIGHT_CLICK_BLOCK.register((player, hand, pos, direction) -> { + if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) { + return EventResult.interruptFalse(); + } + return EventResult.pass(); + }); + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/PlayerEntityMixin.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/PlayerEntityMixin.java new file mode 100644 index 0000000..15ebee3 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/PlayerEntityMixin.java @@ -0,0 +1,71 @@ +package ru.octol1ttle.knockdowns.common.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import java.util.UUID; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.NbtCompound; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; + +@Mixin(PlayerEntity.class) +public abstract class PlayerEntityMixin implements IKnockableDown { + @Unique + private boolean knockedDown; + @Unique + private boolean beingRevived; + + @ModifyExpressionValue(method = "updatePose", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;isSwimming()Z")) + private boolean enterSwimmingIfKnockedDown(boolean original) { + PlayerEntity player = (PlayerEntity)(Object)this; + if (!(player instanceof IKnockableDown knockableDown)) { + throw new IllegalStateException(); + } + + return original || knockableDown.knockdowns$isKnockedDown(); + } + + @ModifyReturnValue(method = "canFoodHeal", at = @At("RETURN")) + private boolean dontHealIfKnockedDown(boolean original) { + return original && !this.knockdowns$isKnockedDown(); + } + + @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) + public void readKnockedDownFromNbt(NbtCompound nbt, CallbackInfo ci) { + this.knockedDown = nbt.getBoolean("KnockedDown"); + } + + @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) + public void writeKnockedDownToNbt(NbtCompound nbt, CallbackInfo ci) { + nbt.putBoolean("KnockedDown", this.knockedDown); + } + + @Override + public boolean knockdowns$isKnockedDown() { + return knockedDown; + } + + @Override + public void knockdowns$setKnockedDown(boolean knockedDown) { + this.knockedDown = knockedDown; + } + + @Override + public boolean knockdowns$isBeingRevived() { + return beingRevived; + } + + @Override + public void knockdowns$setBeingRevived(boolean beingRevived) { + this.beingRevived = beingRevived; + } + + @Override + public UUID knockdowns$getUuid() { + return ((PlayerEntity)(Object)this).getUuid(); + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/client/ClientPlayerEntityMixin.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/client/ClientPlayerEntityMixin.java new file mode 100644 index 0000000..5756cdf --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/mixin/client/ClientPlayerEntityMixin.java @@ -0,0 +1,16 @@ +package ru.octol1ttle.knockdowns.common.mixin.client; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import net.minecraft.client.network.ClientPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; + +@Mixin(ClientPlayerEntity.class) +public abstract class ClientPlayerEntityMixin { + @ModifyReturnValue(method = "shouldSlowDown", at = @At("RETURN")) + private boolean shouldSlowDown(boolean original) { + IKnockableDown self = (IKnockableDown) this; + return original || self.knockdowns$isKnockedDown(); + } +} \ No newline at end of file diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockdownsPacket.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockdownsPacket.java new file mode 100644 index 0000000..0267f16 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockdownsPacket.java @@ -0,0 +1,19 @@ +package ru.octol1ttle.knockdowns.common.packets; + +import dev.architectury.networking.NetworkManager; +import java.util.function.Supplier; +import net.minecraft.network.PacketByteBuf; + +public abstract class KnockdownsPacket { + public KnockdownsPacket(PacketByteBuf buf) { + // Decode data into a message + } + + public KnockdownsPacket(/* args here */) { + // Message creation + } + + public abstract void encode(PacketByteBuf buf); + + public abstract void apply(Supplier contextSupplier); +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockedDownStatusPacket.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockedDownStatusPacket.java new file mode 100644 index 0000000..fa0fc82 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/KnockedDownStatusPacket.java @@ -0,0 +1,69 @@ +package ru.octol1ttle.knockdowns.common.packets; + +import dev.architectury.networking.NetworkManager; +import java.util.UUID; +import java.util.function.Supplier; +import net.minecraft.network.PacketByteBuf; +import ru.octol1ttle.knockdowns.common.KnockdownsNetwork; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; + +public class KnockedDownStatusPacket { + public static class SendS2C extends KnockdownsPacket { + private final UUID playerUuid; + private final boolean knockedDown; + + public SendS2C(PacketByteBuf buf) { + this(buf.readUuid(), buf.readBoolean()); + } + + public SendS2C(UUID playerUuid, boolean knockedDown) { + this.playerUuid = playerUuid; + this.knockedDown = knockedDown; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + buf.writeBoolean(this.knockedDown); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + IKnockableDown knockableDown = (IKnockableDown) context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + if (knockableDown != null) { + knockableDown.knockdowns$setKnockedDown(this.knockedDown); + } + }); + } + } + + public static class RequestC2S extends KnockdownsPacket { + private final UUID playerUuid; + + public RequestC2S(PacketByteBuf buf) { + this(buf.readUuid()); + } + + public RequestC2S(UUID playerUuid) { + this.playerUuid = playerUuid; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + IKnockableDown knockableDown = (IKnockableDown) context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + if (knockableDown != null) { + KnockdownsNetwork.sendToPlayer(context.getPlayer(), new SendS2C(this.playerUuid, knockableDown.knockdowns$isKnockedDown())); + } + }); + } + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/PlayKnockedDownSoundS2CPacket.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/PlayKnockedDownSoundS2CPacket.java new file mode 100644 index 0000000..041d112 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/PlayKnockedDownSoundS2CPacket.java @@ -0,0 +1,40 @@ +package ru.octol1ttle.knockdowns.common.packets; + +import dev.architectury.networking.NetworkManager; +import java.util.function.Supplier; +import net.minecraft.client.MinecraftClient; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.math.Vec3d; +import ru.octol1ttle.knockdowns.common.registries.KnockdownsSoundEvents; +import ru.octol1ttle.knockdowns.common.registries.KnockedDownSoundInstance; + +public class PlayKnockedDownSoundS2CPacket extends KnockdownsPacket { + private final double x; + private final double y; + private final double z; + + public PlayKnockedDownSoundS2CPacket(PacketByteBuf buf) { + this(buf.readDouble(), buf.readDouble(), buf.readDouble()); + } + + public PlayKnockedDownSoundS2CPacket(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeDouble(this.x); + buf.writeDouble(this.y); + buf.writeDouble(this.z); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> MinecraftClient.getInstance().getSoundManager().play( + new KnockedDownSoundInstance(KnockdownsSoundEvents.KNOCKED_DOWN.get(), new Vec3d(this.x, this.y, this.z)) + )); + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/ReviveStatusPacket.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/ReviveStatusPacket.java new file mode 100644 index 0000000..e84b7da --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/packets/ReviveStatusPacket.java @@ -0,0 +1,138 @@ +package ru.octol1ttle.knockdowns.common.packets; + +import dev.architectury.networking.NetworkManager; +import java.util.UUID; +import java.util.function.Supplier; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import ru.octol1ttle.knockdowns.common.KnockdownsNetwork; +import ru.octol1ttle.knockdowns.common.api.IKnockableDown; + +public class ReviveStatusPacket { + public static class SendS2C extends KnockdownsPacket { + private final UUID playerUuid; + private final boolean beingRevived; + + public SendS2C(PacketByteBuf buf) { + this(buf.readUuid(), buf.readBoolean()); + } + + public SendS2C(UUID playerUuid, boolean beingRevived) { + this.playerUuid = playerUuid; + this.beingRevived = beingRevived; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + buf.writeBoolean(this.beingRevived); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + IKnockableDown knockableDown = (IKnockableDown) context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + if (knockableDown != null) { + knockableDown.knockdowns$setBeingRevived(this.beingRevived); + } + }); + } + } + + public static class SendC2S extends KnockdownsPacket { + private final UUID playerUuid; + private final boolean beingRevived; + + public SendC2S(PacketByteBuf buf) { + this(buf.readUuid(), buf.readBoolean()); + } + + public SendC2S(UUID playerUuid, boolean beingRevived) { + this.playerUuid = playerUuid; + this.beingRevived = beingRevived; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + buf.writeBoolean(this.beingRevived); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + IKnockableDown knockableDown = (IKnockableDown) context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + if (knockableDown != null) { + knockableDown.knockdowns$setBeingRevived(this.beingRevived); + KnockdownsNetwork.sendToListenersAndSelf(context.getPlayer(), new ReviveStatusPacket.SendS2C(this.playerUuid, this.beingRevived)); + } + }); + } + } + + public static class RequestC2S extends KnockdownsPacket { + private final UUID playerUuid; + + public RequestC2S(PacketByteBuf buf) { + this(buf.readUuid()); + } + + public RequestC2S(UUID playerUuid) { + this.playerUuid = playerUuid; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + IKnockableDown knockableDown = (IKnockableDown) context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + if (knockableDown != null) { + KnockdownsNetwork.sendToPlayer(context.getPlayer(), new ReviveStatusPacket.SendS2C(this.playerUuid, knockableDown.knockdowns$isBeingRevived())); + } + }); + } + } + + public static class RevivedC2S extends KnockdownsPacket { + private final UUID playerUuid; + + public RevivedC2S(PacketByteBuf buf) { + this(buf.readUuid()); + } + + public RevivedC2S(UUID playerUuid) { + this.playerUuid = playerUuid; + } + + @Override + public void encode(PacketByteBuf buf) { + buf.writeUuid(this.playerUuid); + } + + @Override + public void apply(Supplier contextSupplier) { + NetworkManager.PacketContext context = contextSupplier.get(); + context.queue(() -> { + PlayerEntity reviving = context.getPlayer().getWorld().getPlayerByUuid(this.playerUuid); + IKnockableDown knockableDown = (IKnockableDown) reviving; + if (knockableDown == null || !knockableDown.knockdowns$isKnockedDown()) { + return; + } + + reviving.setInvulnerable(false); + reviving.setGlowing(false); + reviving.setHealth(6.0f); + + knockableDown.knockdowns$setKnockedDown(false); + KnockdownsNetwork.sendToListenersAndSelf(reviving, new KnockedDownStatusPacket.SendS2C(reviving.getUuid(), false)); + }); + } + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockdownsSoundEvents.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockdownsSoundEvents.java new file mode 100644 index 0000000..a207925 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockdownsSoundEvents.java @@ -0,0 +1,18 @@ +package ru.octol1ttle.knockdowns.common.registries; + +import dev.architectury.registry.registries.DeferredRegister; +import dev.architectury.registry.registries.RegistrySupplier; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; +import ru.octol1ttle.knockdowns.common.KnockdownsCommon; + +public class KnockdownsSoundEvents { + private static final DeferredRegister SOUND_EVENTS = DeferredRegister.create(KnockdownsCommon.MOD_ID, RegistryKeys.SOUND_EVENT); + public static final RegistrySupplier KNOCKED_DOWN = SOUND_EVENTS.register(KnockdownsCommon.MOD_ID, + () -> SoundEvent.of(new Identifier(KnockdownsCommon.MOD_ID, "knocked_down"))); + + public static void register() { + SOUND_EVENTS.register(); + } +} diff --git a/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockedDownSoundInstance.java b/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockedDownSoundInstance.java new file mode 100644 index 0000000..7781165 --- /dev/null +++ b/common/src/main/java/ru/octol1ttle/knockdowns/common/registries/KnockedDownSoundInstance.java @@ -0,0 +1,31 @@ +package ru.octol1ttle.knockdowns.common.registries; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.sound.MovingSoundInstance; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; + +public class KnockedDownSoundInstance extends MovingSoundInstance { + private final Vec3d pos; + + public KnockedDownSoundInstance(SoundEvent sound, Vec3d pos) { + super(sound, SoundCategory.MASTER, Random.create(0L)); + this.pos = pos; + this.relative = true; + } + + @Override + public void tick() { + ClientPlayerEntity player = MinecraftClient.getInstance().player; + if (player == null) { + throw new IllegalStateException(); + } + Vec3d vec = pos.subtract(player.getPos()).normalize(); + this.x = vec.x; + this.y = vec.y; + this.z = vec.z; + } +} diff --git a/common/src/main/resources/assets/knockdowns/lang/en_us.json b/common/src/main/resources/assets/knockdowns/lang/en_us.json index 2805821..256bd9b 100644 --- a/common/src/main/resources/assets/knockdowns/lang/en_us.json +++ b/common/src/main/resources/assets/knockdowns/lang/en_us.json @@ -1,3 +1,102 @@ { - "item.knockdowns.example_item": "Example Item" + "knockdown.attack.anvil": "%1$s was knocked down by a falling anvil", + "knockdown.attack.anvil.player": "%1$s was knocked down by a falling anvil while fighting %2$s", + "knockdown.attack.arrow": "%1$s was knocked down due to an arrow fired by %2$s", + "knockdown.attack.arrow.item": "%1$s was knocked down due to an arrow fired by %2$s using %3$s", + "knockdown.attack.badRespawnPoint.link": "Intentional Game Design", + "knockdown.attack.badRespawnPoint.message": "%1$s was knocked down by %2$s", + "knockdown.attack.cactus": "%1$s was knocked down by a cactus", + "knockdown.attack.cactus.player": "%1$s was knocked down into a cactus while trying to escape %2$s", + "knockdown.attack.cramming": "%1$s was knocked down by squishing", + "knockdown.attack.cramming.player": "%1$s was knocked down due to being squashed by %2$s", + "knockdown.attack.dragonBreath": "%1$s was knocked down by dragon's breath", + "knockdown.attack.dragonBreath.player": "%1$s was knocked down by dragon's breath by %2$s", + "knockdown.attack.drown": "%1$s was knocked down by drowning", + "knockdown.attack.drown.player": "%1$s was knocked down by drowning while trying to escape %2$s", + "knockdown.attack.dryout": "%1$s was knocked down by dehydration", + "knockdown.attack.dryout.player": "%1$s was knocked down by dehydration while trying to escape %2$s", + "knockdown.attack.even_more_magic": "%1$s was knocked down by even more magic", + "knockdown.attack.explosion": "%1$s was knocked down due to an explosion", + "knockdown.attack.explosion.player": "%1$s was knocked down due to an explosion caused by %2$s", + "knockdown.attack.explosion.player.item": "%1$s was knocked down due to an explosion caused by %2$s using %3$s", + "knockdown.attack.fall": "%1$s was knocked down by a fall", + "knockdown.attack.fall.player": "%1$s was knocked down by a fall while trying to escape %2$s", + "knockdown.attack.fallingBlock": "%1$s was knocked down by a falling block", + "knockdown.attack.fallingBlock.player": "%1$s was knocked down by a falling block while fighting %2$s", + "knockdown.attack.fallingStalactite": "%1$s was knocked down by a falling stalactite", + "knockdown.attack.fallingStalactite.player": "%1$s was knocked down by a falling stalactite while fighting %2$s", + "knockdown.attack.fireball": "%1$s was knocked down due to a fireball fired by %2$s", + "knockdown.attack.fireball.item": "%1$s was knocked down due to a fireball fired by %2$s using %3$s", + "knockdown.attack.fireworks": "%1$s was knocked down with a bang", + "knockdown.attack.fireworks.item": "%1$s was knocked down with a bang due to a firework fired from %3$s by %2$s", + "knockdown.attack.fireworks.player": "%1$s was knocked down with a bang while fighting %2$s", + "knockdown.attack.flyIntoWall": "%1$s was knocked down by kinetic energy", + "knockdown.attack.flyIntoWall.player": "%1$s was knocked down by kinetic energy while trying to escape %2$s", + "knockdown.attack.freeze": "%1$s was knocked down by freezing", + "knockdown.attack.freeze.player": "%1$s was knocked down by freezing by %2$s", + "knockdown.attack.generic": "%1$s was knocked down", + "knockdown.attack.generic.player": "%1$s was knocked down because of %2$s", + "knockdown.attack.genericKill": "%1$s was knocked down", + "knockdown.attack.genericKill.player": "%1$s was knocked down while fighting %2$s", + "knockdown.attack.hotFloor": "%1$s was knocked down by the lava floor", + "knockdown.attack.hotFloor.player": "%1$s was knocked down by the lava floor due to %2$s", + "knockdown.attack.indirectMagic": "%1$s was knocked down by %2$s using magic", + "knockdown.attack.indirectMagic.item": "%1$s was knocked down by %2$s using %3$s", + "knockdown.attack.inFire": "%1$s was knocked down by fire", + "knockdown.attack.inFire.player": "%1$s was knocked down by fire while fighting %2$s", + "knockdown.attack.inWall": "%1$s was knocked down by suffocation", + "knockdown.attack.inWall.player": "%1$s was knocked down by suffocation while fighting %2$s", + "knockdown.attack.lava": "%1$s was knocked down by lava", + "knockdown.attack.lava.player": "%1$s was knocked down by lava while trying to escape %2$s", + "knockdown.attack.lightningBolt": "%1$s was knocked down by lightning", + "knockdown.attack.lightningBolt.player": "%1$s was knocked down by lightning while fighting %2$s", + "knockdown.attack.magic": "%1$s was knocked down by magic", + "knockdown.attack.magic.player": "%1$s was knocked down by magic while trying to escape %2$s", + "knockdown.attack.message_too_long": "Actually, the message was too long to deliver fully. Sorry! Here's a stripped version: %s", + "knockdown.attack.mob": "%1$s was knocked down by %2$s", + "knockdown.attack.mob.item": "%1$s was knocked down by %2$s using %3$s", + "knockdown.attack.onFire": "%1$s was knocked down by fire", + "knockdown.attack.onFire.item": "%1$s was knocked down by fire while fighting %2$s wielding %3$s", + "knockdown.attack.onFire.player": "%1$s was knocked down by fire while fighting %2$s", + "knockdown.attack.outOfWorld": "%1$s was knocked down by the void", + "knockdown.attack.outOfWorld.player": "%1$s was knocked down by the void while fighting %2$s", + "knockdown.attack.outsideBorder": "%1$s was knocked down by the world border", + "knockdown.attack.outsideBorder.player": "%1$s was knocked down by the world border while fighting %2$s", + "knockdown.attack.player": "%1$s was knocked down by %2$s", + "knockdown.attack.player.item": "%1$s was knocked down by %2$s using %3$s", + "knockdown.attack.sonic_boom": "%1$s was knocked down by a sonically-charged shriek", + "knockdown.attack.sonic_boom.item": "%1$s was knocked down by a sonically-charged shriek while trying to escape %2$s wielding %3$s", + "knockdown.attack.sonic_boom.player": "%1$s was knocked down by a sonically-charged shriek while trying to escape %2$s", + "knockdown.attack.stalagmite": "%1$s was knocked down by a stalagmite", + "knockdown.attack.stalagmite.player": "%1$s was knocked down by a stalagmite while fighting %2$s", + "knockdown.attack.starve": "%1$s was knocked down by starving", + "knockdown.attack.starve.player": "%1$s was knocked down by starving while fighting %2$s", + "knockdown.attack.sting": "%1$s was knocked down by stings", + "knockdown.attack.sting.item": "%1$s was knocked down by stings by %2$s using %3$s", + "knockdown.attack.sting.player": "%1$s was knocked down by stings by %2$s", + "knockdown.attack.sweetBerryBush": "%1$s was knocked down by a sweet berry bush", + "knockdown.attack.sweetBerryBush.player": "%1$s was knocked down by a sweet berry bush while trying to escape %2$s", + "knockdown.attack.thorns": "%1$s was knocked down while trying to hurt %2$s", + "knockdown.attack.thorns.item": "%1$s was knocked down by %3$s while trying to hurt %2$s", + "knockdown.attack.thrown": "%1$s was knocked down due to being thrown by %2$s", + "knockdown.attack.thrown.item": "%1$s was knocked down due to being thrown by %2$s using %3$s", + "knockdown.attack.trident": "%1$s was knocked down due to being impaled by %2$s", + "knockdown.attack.trident.item": "%1$s was knocked down due to being impaled by %2$s with %3$s", + "knockdown.attack.wither": "%1$s was knocked down by withering", + "knockdown.attack.wither.player": "%1$s was knocked down by withering while fighting %2$s", + "knockdown.attack.witherSkull": "%1$s was knocked down by a skull from %2$s", + "knockdown.attack.witherSkull.item": "%1$s was knocked down by a skull from %2$s using %3$s", + "knockdown.fell.accident.generic": "%1$s was knocked down by a fall", + "knockdown.fell.accident.ladder": "%1$s was knocked down by a fall off a ladder", + "knockdown.fell.accident.other_climbable": "%1$s was knocked down by a fall while climbing", + "knockdown.fell.accident.scaffolding": "%1$s was knocked down by a fall off scaffolding", + "knockdown.fell.accident.twisting_vines": "%1$s was knocked down by a fall off some twisting vines", + "knockdown.fell.accident.vines": "%1$s was knocked down by a fall off some vines", + "knockdown.fell.accident.weeping_vines": "%1$s was knocked down by a fall off some weeping vines", + "knockdown.fell.assist": "%1$s was doomed to get knocked down by %2$s", + "knockdown.fell.assist.item": "%1$s was doomed to get knocked down by %2$s using %3$s", + "knockdown.fell.finish": "%1$s fell too far and was knocked down by %2$s", + "knockdown.fell.finish.item": "%1$s fell too far and was knocked down by %2$s using %3$s", + "knockdown.fell.killer": "%1$s was doomed to get knocked down by a fall", + "subtitles.knockdowns.knocked_down": "Player knocked down" } \ No newline at end of file diff --git a/common/src/main/resources/assets/knockdowns/lang/ru_ru.json b/common/src/main/resources/assets/knockdowns/lang/ru_ru.json new file mode 100644 index 0000000..5cdd965 --- /dev/null +++ b/common/src/main/resources/assets/knockdowns/lang/ru_ru.json @@ -0,0 +1,102 @@ +{ + "knockdown.attack.anvil": "%1$s был тяжело ранен упавшей наковальней", + "knockdown.attack.anvil.player": "%1$s был тяжело ранен упавшей наковальней, пока сражался с %2$s", + "knockdown.attack.arrow": "%1$s тяжело ранен стрелой %2$s", + "knockdown.attack.arrow.item": "%1$s тяжело ранен стрелой %2$s из %3$s", + "knockdown.attack.badRespawnPoint.link": "жестокими правилами игры", + "knockdown.attack.badRespawnPoint.message": "%1$s был тяжело ранен %2$s", + "knockdown.attack.cactus": "%1$s был тяжело ранен кактусом", + "knockdown.attack.cactus.player": "%1$s был тяжело ранен кактусом, спасаясь от %2$s", + "knockdown.attack.cramming": "%1$s был тяжело ранен расплющиванием", + "knockdown.attack.cramming.player": "%1$s был тяжело ранен расплющиванием %2$s", + "knockdown.attack.dragonBreath": "%1$s был тяжело ранен в драконьем дыхании", + "knockdown.attack.dragonBreath.player": "%1$s был тяжело ранен в драконьем дыхании из-за %2$s", + "knockdown.attack.drown": "%1$s был тяжело ранен утоплением", + "knockdown.attack.drown.player": "%1$s был тяжело ранен утоплением, спасаясь от %2$s", + "knockdown.attack.dryout": "%1$s был тяжело ранен обезвоживанием", + "knockdown.attack.dryout.player": "%1$s был тяжело ранен обезвоживанием, спасаясь от %2$s", + "knockdown.attack.even_more_magic": "%1$s был тяжело ранен неизведанной магией", + "knockdown.attack.explosion": "%1$s был тяжело ранен взрывом", + "knockdown.attack.explosion.player": "%1$s был тяжело ранен взрывом %2$s", + "knockdown.attack.explosion.player.item": "%1$s был тяжело ранен взрывом %2$s с помощью %3$s", + "knockdown.attack.fall": "%1$s был тяжело ранен падением", + "knockdown.attack.fall.player": "%1$s был тяжело ранен падением, спасаясь от %2$s", + "knockdown.attack.fallingBlock": "%1$s был тяжело ранен упавшим блоком", + "knockdown.attack.fallingBlock.player": "%1$s был тяжело ранен упавшим блоком, пока боролся с %2$s", + "knockdown.attack.fallingStalactite": "%1$s был тяжело ранен обрушившимся сталактитом", + "knockdown.attack.fallingStalactite.player": "%1$s был тяжело ранен обрушившимся сталактитом, пока боролся с %2$s", + "knockdown.attack.fireball": "%1$s был тяжело ранен файерболом %2$s", + "knockdown.attack.fireball.item": "%1$s был тяжело ранен файерболом %2$s с помощью %3$s", + "knockdown.attack.fireworks": "%1$s был тяжело ранен взрывом фейерверка", + "knockdown.attack.fireworks.item": "%1$s был тяжело ранен взрывом фейерверка %2$s, выпущенного из %3$s", + "knockdown.attack.fireworks.player": "%1$s был тяжело ранен взрывом фейерверка, пока боролся с %2$s", + "knockdown.attack.flyIntoWall": "%1$s был тяжело ранен кинетической энергией", + "knockdown.attack.flyIntoWall.player": "%1$s был тяжело ранен кинетической энергией, спасаясь от %2$s", + "knockdown.attack.freeze": "%1$s был тяжело ранен замерзанием", + "knockdown.attack.freeze.player": "%1$s был тяжело ранен замерзанием благодаря %2$s", + "knockdown.attack.generic": "%1$s тяжело ранен", + "knockdown.attack.generic.player": "%1$s тяжело ранен из-за %2$s", + "knockdown.attack.genericKill": "%1$s тяжело ранен", + "knockdown.attack.genericKill.player": "%1$s был тяжело ранен, пока боролся с %2$s", + "knockdown.attack.hotFloor": "%1$s был тяжело ранен, обнаружив, что пол — это лава", + "knockdown.attack.hotFloor.player": "%1$s был тяжело ранен, так как зашёл в опасную зону из-за %2$s", + "knockdown.attack.inFire": "%1$s был тяжело ранен в огне", + "knockdown.attack.inFire.player": "%1$s был тяжело ранен в огне, пока боролся с %2$s", + "knockdown.attack.inWall": "%1$s был тяжело ранен погребением заживо", + "knockdown.attack.inWall.player": "%1$s был тяжело ранен погребением заживо, пока боролся с %2$s", + "knockdown.attack.indirectMagic": "%1$s был тяжело ранен %2$s с помощью магии", + "knockdown.attack.indirectMagic.item": "%1$s был тяжело ранен %2$s с помощью %3$s", + "knockdown.attack.lava": "%1$s был тяжело ранен лавой", + "knockdown.attack.lava.player": "%1$s был тяжело ранен лавой, убегая от %2$s", + "knockdown.attack.lightningBolt": "%1$s был тяжело ранен молнией", + "knockdown.attack.lightningBolt.player": "%1$s был тяжело ранен молнией, пока сражался с %2$s", + "knockdown.attack.magic": "%1$s был тяжело ранен магией", + "knockdown.attack.magic.player": "%1$s был тяжело ранен магией, убегая от %2$s", + "knockdown.attack.message_too_long": "Сообщение слишком длинное для доставки. Извините! Вот сокращённая версия: %s", + "knockdown.attack.mob": "%1$s был тяжело ранен %2$s", + "knockdown.attack.mob.item": "%1$s был тяжело ранен %2$s с помощью %3$s", + "knockdown.attack.onFire": "%1$s был тяжело ранен огнём", + "knockdown.attack.onFire.item": "%1$s был тяжело ранен огнём, пока боролся с %2$s, с помощью %3$s", + "knockdown.attack.onFire.player": "%1$s был тяжело ранен огнём, пока боролся с %2$s", + "knockdown.attack.outOfWorld": "%1$s был тяжело ранен пустотой", + "knockdown.attack.outOfWorld.player": "%1$s был тяжело ранен пустотой, благодаря %2$s", + "knockdown.attack.outsideBorder": "%1$s был тяжело ранен пределами этого мира", + "knockdown.attack.outsideBorder.player": "%1$s был тяжело ранен пределами этого мира, пока боролся с %2$s", + "knockdown.attack.player": "%1$s был тяжело ранен %2$s", + "knockdown.attack.player.item": "%1$s был тяжело ранен %2$s с помощью %3$s", + "knockdown.attack.sonic_boom": "%1$s был тяжело ранен звуковым зарядом", + "knockdown.attack.sonic_boom.item": "%1$s был тяжело ранен звуковым ударом, спасаясь от %2$s c %3$s", + "knockdown.attack.sonic_boom.player": "%1$s был тяжело ранен звуковым ударом, спасаясь от %2$s", + "knockdown.attack.stalagmite": "%1$s был тяжело ранен сталагмитом", + "knockdown.attack.stalagmite.player": "%1$s был тяжело ранен сталагмитом, пока боролся с %2$s", + "knockdown.attack.starve": "%1$s был тяжело ранен голодом", + "knockdown.attack.starve.player": "%1$s был тяжело ранен голодом, пока боролся с %2$s", + "knockdown.attack.sting": "%1$s был тяжело ранен изжалением", + "knockdown.attack.sting.item": "%1$s был тяжело ранен изжалением %2$s с помощью %3$s", + "knockdown.attack.sting.player": "%1$s был тяжело ранен изжалением %2$s", + "knockdown.attack.sweetBerryBush": "%1$s был тяжело ранен исколением в кустах сладких ягод", + "knockdown.attack.sweetBerryBush.player": "%1$s был тяжело ранен исколением в кустах сладких ягод, спасаясь от %2$s", + "knockdown.attack.thorns": "%1$s был тяжело ранен, пытаясь навредить %2$s", + "knockdown.attack.thorns.item": "%1$s был тяжело ранен %3$s, пытаясь навредить %2$s", + "knockdown.attack.thrown": "%1$s был тяжело ранен %2$s", + "knockdown.attack.thrown.item": "%1$s был тяжело ранен %2$s с помощью %3$s", + "knockdown.attack.trident": "%1$s был тяжело ранен пронзанием %2$s", + "knockdown.attack.trident.item": "%1$s был тяжело ранен пронзанием %2$s с помощью %3$s", + "knockdown.attack.wither": "%1$s был тяжело ранен иссушением", + "knockdown.attack.wither.player": "%1$s был тяжело ранен иссушением, пока боролся с %2$s", + "knockdown.attack.witherSkull": "%1$s был тяжело ранен поражением черепом из %2$s", + "knockdown.attack.witherSkull.item": "%1$s был тяжело ранен поражением черепом из %2$s с помощью %3$s", + "knockdown.fell.accident.generic": "%1$s был тяжело ранен падением", + "knockdown.fell.accident.ladder": "%1$s был тяжело ранен падением с лестницы", + "knockdown.fell.accident.other_climbable": "%1$s был тяжело ранен падением", + "knockdown.fell.accident.scaffolding": "%1$s был тяжело ранен падением с подмосток", + "knockdown.fell.accident.twisting_vines": "%1$s был тяжело ранен падением с вьющейся лозы", + "knockdown.fell.accident.vines": "%1$s был тяжело ранен падением с лианы", + "knockdown.fell.accident.weeping_vines": "%1$s был тяжело ранен падением с плакучей лозы", + "knockdown.fell.assist": "%1$s был тяжело ранен падением благодаря %2$s", + "knockdown.fell.assist.item": "%1$s был тяжело ранен падением благодаря %2$s с помощью %3$s", + "knockdown.fell.finish": "%1$s упал с высоты и был тяжело ранен %2$s", + "knockdown.fell.finish.item": "%1$s упал с высоты и был тяжело ранен %2$s с помощью %3$s", + "knockdown.fell.killer": "%1$s был тяжело ранен падением", + "subtitles.knockdowns.knocked_down": "Игрок тяжело ранен" +} \ No newline at end of file diff --git a/common/src/main/resources/assets/knockdowns/sounds.json b/common/src/main/resources/assets/knockdowns/sounds.json new file mode 100644 index 0000000..52d77b8 --- /dev/null +++ b/common/src/main/resources/assets/knockdowns/sounds.json @@ -0,0 +1,10 @@ +{ + "knocked_down": { + "subtitle": "subtitles.knockdowns.knocked_down", + "sounds": [ + { + "name": "knockdowns:knocked_down" + } + ] + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/knockdowns/sounds/knocked_down.ogg b/common/src/main/resources/assets/knockdowns/sounds/knocked_down.ogg new file mode 100644 index 0000000..ccb17cc Binary files /dev/null and b/common/src/main/resources/assets/knockdowns/sounds/knocked_down.ogg differ diff --git a/common/src/main/resources/knockdowns-common.mixins.json b/common/src/main/resources/knockdowns-common.mixins.json index fd7619d..8eef057 100644 --- a/common/src/main/resources/knockdowns-common.mixins.json +++ b/common/src/main/resources/knockdowns-common.mixins.json @@ -1,12 +1,13 @@ { "required": true, - "package": "net.knockdowns.mixin", + "package": "ru.octol1ttle.knockdowns.common.mixin", "compatibilityLevel": "JAVA_17", "minVersion": "0.8", "client": [ - "ru.octol1ttle.knockdowns.mixin.MixinTitleScreen" + "client.ClientPlayerEntityMixin" ], "mixins": [ + "PlayerEntityMixin" ], "injectors": { "defaultRequire": 1 diff --git a/common/src/main/resources/knockdowns.accesswidener b/common/src/main/resources/knockdowns.accesswidener index 13268c3..4dddd12 100644 --- a/common/src/main/resources/knockdowns.accesswidener +++ b/common/src/main/resources/knockdowns.accesswidener @@ -1 +1,4 @@ -accessWidener v2 named \ No newline at end of file +accessWidener v2 named + +accessible field net/minecraft/server/world/ThreadedAnvilChunkStorage entityTrackers Lit/unimi/dsi/fastutil/ints/Int2ObjectMap; +accessible field net/minecraft/server/world/ThreadedAnvilChunkStorage$EntityTracker listeners Ljava/util/Set; \ No newline at end of file diff --git a/fabric/src/main/resources/knockdowns.mixins.json b/fabric/src/main/resources/knockdowns.mixins.json index c33ed01..76a92ed 100644 --- a/fabric/src/main/resources/knockdowns.mixins.json +++ b/fabric/src/main/resources/knockdowns.mixins.json @@ -1,6 +1,6 @@ { "required": true, - "package": "net.knockdowns.mixin.fabric", + "package": "ru.octol1ttle.knockdowns.fabric.mixin", "compatibilityLevel": "JAVA_17", "minVersion": "0.8", "client": [ diff --git a/forge/build.gradle b/forge/build.gradle index 8f7a732..490b2f1 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -34,6 +34,8 @@ dependencies { common(project(path: ":common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false } + + implementation(include("io.github.llamalad7:mixinextras-forge:0.3.3")) } processResources { diff --git a/forge/src/main/java/ru/octol1ttle/knockdowns/forge/KnockdownsForge.java b/forge/src/main/java/ru/octol1ttle/knockdowns/forge/KnockdownsForge.java index a8e8643..e71aa25 100644 --- a/forge/src/main/java/ru/octol1ttle/knockdowns/forge/KnockdownsForge.java +++ b/forge/src/main/java/ru/octol1ttle/knockdowns/forge/KnockdownsForge.java @@ -1,9 +1,9 @@ package ru.octol1ttle.knockdowns.forge; import dev.architectury.platform.forge.EventBuses; -import ru.octol1ttle.knockdowns.common.KnockdownsCommon; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import ru.octol1ttle.knockdowns.common.KnockdownsCommon; @Mod(KnockdownsCommon.MOD_ID) public class KnockdownsForge { diff --git a/forge/src/main/resources/knockdowns.mixins.json b/forge/src/main/resources/knockdowns.mixins.json index 66779c8..bc08964 100644 --- a/forge/src/main/resources/knockdowns.mixins.json +++ b/forge/src/main/resources/knockdowns.mixins.json @@ -1,6 +1,6 @@ { "required": true, - "package": "net.knockdowns.mixin.forge", + "package": "ru.octol1ttle.knockdowns.forge.mixin", "compatibilityLevel": "JAVA_17", "minVersion": "0.8", "client": [ diff --git a/gradle.properties b/gradle.properties index a7ea28d..c3bc8bf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ maven_group=ru.octol1ttle.knockdowns architectury_version=9.1.12 fabric_api_version=0.90.4+1.20.1 -fabric_loader_version=0.15.4 +fabric_loader_version=0.15.5 forge_version=1.20.1-47.2.0