This commit is contained in:
Octol1ttle 2024-07-15 11:22:53 +05:00
parent a91692ded7
commit f1c52e4371
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
38 changed files with 1854 additions and 35 deletions

View file

@ -16,16 +16,16 @@ show_testing_output = false
# Mod Information # Mod Information
# HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/ # HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/
mod_version = 1.0.0 mod_version = 1.0.0
root_package = com.example root_package = ru.octol1ttle
mod_id = modid mod_id = knockdowns
mod_name = Mod Name mod_name = Knockdowns (Legacy)
# Mod Metadata (Optional) # Mod Metadata (Optional)
mod_description = mod_description =
mod_url = mod_url =
mod_update_json = mod_update_json =
# Delimit authors with commas # Delimit authors with commas
mod_authors = mod_authors = Octol1ttle
mod_credits = mod_credits =
mod_logo_path = mod_logo_path =
@ -97,7 +97,7 @@ access_transformer_locations = ${mod_id}_at.cfg
# Powerful tool to do runtime description changes of classes # Powerful tool to do runtime description changes of classes
# Wiki: https://github.com/SpongePowered/Mixin/wiki + https://github.com/CleanroomMC/MixinBooter/ + https://cleanroommc.com/wiki/forge-mod-development/mixin/preface # Wiki: https://github.com/SpongePowered/Mixin/wiki + https://github.com/CleanroomMC/MixinBooter/ + https://cleanroommc.com/wiki/forge-mod-development/mixin/preface
# Only use mixins once you understand the underlying structure # Only use mixins once you understand the underlying structure
use_mixins = false use_mixins = true
mixin_booter_version = 9.1 mixin_booter_version = 9.1
# A configuration defines a mixin set, and you may have as many mixin sets as you require for your application. # A configuration defines a mixin set, and you may have as many mixin sets as you require for your application.
# Each config can only have one and only one package root. # Each config can only have one and only one package root.
@ -115,12 +115,12 @@ mixin_refmap = mixins.${mod_id}.refmap.json
# Only make a coremod if you are absolutely sure of what you are doing # Only make a coremod if you are absolutely sure of what you are doing
# Change the property `coremod_includes_mod` to false if your coremod doesn't have a @Mod annotation # Change the property `coremod_includes_mod` to false if your coremod doesn't have a @Mod annotation
# You MUST state a class name for `coremod_plugin_class_name` if you are making a coremod, the class should implement `IFMLLoadingPlugin` # You MUST state a class name for `coremod_plugin_class_name` if you are making a coremod, the class should implement `IFMLLoadingPlugin`
is_coremod = false is_coremod = true
coremod_includes_mod = true coremod_includes_mod = true
coremod_plugin_class_name = coremod_plugin_class_name = ru.octol1ttle.knockdowns.common.KnockdownsFMLLoadingPlugin
# AssetMover # AssetMover
# Convenient way to allow downloading of assets from official vanilla Minecraft servers, CurseForge, or any direct links # Convenient way to allow downloading of assets from official vanilla Minecraft servers, CurseForge, or any direct links
# Documentation: https://github.com/CleanroomMC/AssetMover # Documentation: https://github.com/CleanroomMC/AssetMover
use_asset_mover = false use_asset_mover = false
asset_mover_version = 2.5 asset_mover_version = 2.5

View file

@ -1,24 +0,0 @@
package com.example.modid;
import com.example.modid.Tags;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Mod(modid = Tags.MOD_ID, name = Tags.MOD_NAME, version = Tags.VERSION)
public class ExampleMod {
public static final Logger LOGGER = LogManager.getLogger(Tags.MOD_NAME);
/**
* <a href="https://cleanroommc.com/wiki/forge-mod-development/event#overview">
* Take a look at how many FMLStateEvents you can listen to via the @Mod.EventHandler annotation here
* </a>
*/
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER.info("Hello From {}!", Tags.MOD_NAME);
}
}

View file

@ -0,0 +1,15 @@
package ru.octol1ttle.knockdowns.client;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.client.event.KnockdownsKeyListener;
import ru.octol1ttle.knockdowns.common.IClientProxy;
@SideOnly(Side.CLIENT)
public class ClientProxy implements IClientProxy {
@Override
public void onFMLInit(FMLInitializationEvent event) {
KnockdownsKeyListener.registerKeyBindings();
}
}

View file

@ -0,0 +1,34 @@
package ru.octol1ttle.knockdowns.client.communication;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.client.util.Callout;
import ru.octol1ttle.knockdowns.client.util.DirectionalCallSound;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
@SideOnly(Side.CLIENT)
public class CalloutManager {
private static final Minecraft client = Minecraft.getMinecraft();
private static final Map<Integer, Callout> callouts = new HashMap<>();
public static Set<Map.Entry<Integer, Callout>> getCallouts() {
return callouts.entrySet();
}
public static boolean addOrUpdateCallout(PlayerCalloutS2CPacket message) {
return callouts.put(message.playerId, new Callout(message.position, message.type, client.world.getTotalWorldTime())) == null;
}
public static void playCalloutSound(PlayerCalloutS2CPacket message) {
client.getSoundHandler().playSound(new DirectionalCallSound(KnockdownsSoundEvents.CALLOUT, client.world.getEntityByID(message.playerId), message.position));
}
public static void clearCallouts() {
callouts.clear();
}
}

View file

@ -0,0 +1,28 @@
package ru.octol1ttle.knockdowns.client.communication;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.client.util.KnockedPlayerData;
@SideOnly(Side.CLIENT)
public class KnockedNotificationManager {
private static final Minecraft client = Minecraft.getMinecraft();
private static final List<KnockedPlayerData> knockedDatas = new ArrayList<>();
public static void addKnockedNotification(int playerId, Vec3d position) {
knockedDatas.add(new KnockedPlayerData(playerId, position, client.world.getTotalWorldTime()));
}
public static Collection<KnockedPlayerData> getKnockedPlayerDatas() {
return knockedDatas;
}
public static void clearDatas() {
knockedDatas.clear();
}
}

View file

@ -0,0 +1,71 @@
package ru.octol1ttle.knockdowns.client.event;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
import ru.octol1ttle.knockdowns.client.gui.CommunicationGui;
import ru.octol1ttle.knockdowns.client.gui.KnockedNotificationGui;
import ru.octol1ttle.knockdowns.client.gui.ReviveGui;
import ru.octol1ttle.knockdowns.common.ReviverTracker;
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(value = Side.CLIENT, modid = Tags.MOD_ID)
public class KnockdownsClientEventListener {
private static final Minecraft client = Minecraft.getMinecraft();
private static final CommunicationGui communicationGui = new CommunicationGui();
private static final KnockedNotificationGui notificationGui = new KnockedNotificationGui();
private static final ReviveGui reviveGui = new ReviveGui();
@SubscribeEvent
public static void onTick(TickEvent.ClientTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
return;
}
if (client.world == null) {
CalloutManager.clearCallouts();
KnockedNotificationManager.clearDatas();
return;
}
CalloutManager.getCallouts().removeIf(callout -> client.world.getTotalWorldTime() - callout.getValue().getReceiveTime() > 60);
KnockedNotificationManager.getKnockedPlayerDatas().removeIf(notification -> client.world.getTotalWorldTime() - notification.getReceiveTime() > 100);
}
@SubscribeEvent
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
List<EntityPlayer> revivers = ReviverTracker.getRevivers(event.player);
if (revivers.contains(client.player) && !event.player.equals(client.pointedEntity)) {
KnockdownsNetwork.sendToServer(new CancelReviveC2SPacket());
revivers.remove(client.player);
}
}
@SubscribeEvent
public static void onRenderWorldLast(RenderWorldLastEvent event) {
communicationGui.renderCallouts(event.getPartialTicks());
notificationGui.renderNotifications(event.getPartialTicks());
}
@SubscribeEvent
public static void onRenderGameOverlay(RenderGameOverlayEvent.Chat event) {
communicationGui.render(event.getPartialTicks(), event.getResolution());
reviveGui.render(event.getPartialTicks(), event.getResolution());
}
@SubscribeEvent
public static void onKeyInput(InputEvent.KeyInputEvent event) {
KnockdownsKeyListener.tickKeys();
}
}

View file

@ -0,0 +1,56 @@
package ru.octol1ttle.knockdowns.client.event;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.input.Keyboard;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(value = Side.CLIENT, modid = Tags.MOD_ID)
public class KnockdownsKeyListener {
private static final Minecraft client = Minecraft.getMinecraft();
public static final Map<KeyBinding, Supplier<CalloutType>> calloutBindings = new HashMap<>();
public static void registerKeyBindings() {
calloutBindings.put(
new KeyBinding("knockdowns.key.callout.danger", Keyboard.KEY_LEFT, "knockdowns.key.category"),
() -> CalloutType.DANGER
);
calloutBindings.put(
new KeyBinding("knockdowns.key.callout.booyah", Keyboard.KEY_DOWN, "knockdowns.key.category"),
() -> CalloutType.BOOYAH
);
calloutBindings.put(
new KeyBinding("knockdowns.key.callout.this_way_help", Keyboard.KEY_UP, "knockdowns.key.category"),
() -> IKnockdownsPlayerData.get(client.player).isKnockedDown() ? CalloutType.HELP : CalloutType.THIS_WAY
);
calloutBindings.put(
new KeyBinding("knockdowns.key.callout.ouch", Keyboard.KEY_RIGHT, "knockdowns.key.category"),
() -> CalloutType.OUCH
);
for (KeyBinding binding : calloutBindings.keySet()) {
ClientRegistry.registerKeyBinding(binding);
}
}
public static void tickKeys() {
for (KeyBinding binding : calloutBindings.keySet()) {
if (binding.isPressed()) {
KnockdownsNetwork.sendToServer(new PlayerCalloutC2SPacket(calloutBindings.get(binding).get()));
break;
}
}
}
}

View file

@ -0,0 +1,175 @@
package ru.octol1ttle.knockdowns.client.gui;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
import ru.octol1ttle.knockdowns.client.event.KnockdownsKeyListener;
import ru.octol1ttle.knockdowns.client.util.Callout;
@SideOnly(Side.CLIENT)
public class CommunicationGui extends KnockdownsBaseGui {
private static final Minecraft client = Minecraft.getMinecraft();
private static final ResourceLocation LEFT_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/left_arrow.png");
private static final ResourceLocation DOWN_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/down_arrow.png");
private static final ResourceLocation UP_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/up_arrow.png");
private static final ResourceLocation RIGHT_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/right_arrow.png");
private static final int SCREEN_EDGE_MARGIN = 5;
private static final int SEPARATOR_MARGIN = 2;
private static final int KEY_SIZE = 17;
private float totalPartialTicks;
@Override
public void render(float partialTicks, ScaledResolution resolution) {
FontRenderer font = client.fontRenderer;
int x = SCREEN_EDGE_MARGIN;
int y = resolution.getScaledHeight() - SCREEN_EDGE_MARGIN - font.FONT_HEIGHT;
KeyBinding[] sortedBindings = new KeyBinding[4];
for (KeyBinding binding : KnockdownsKeyListener.calloutBindings.keySet())
{
switch (binding.getKeyCode()) {
case Keyboard.KEY_LEFT:
sortedBindings[0] = binding;
break;
case Keyboard.KEY_DOWN:
sortedBindings[1] = binding;
break;
case Keyboard.KEY_UP:
sortedBindings[2] = binding;
break;
case Keyboard.KEY_RIGHT:
sortedBindings[3] = binding;
break;
}
}
KeyBinding leftCallout = sortedBindings[0];
if (leftCallout != null) {
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(leftCallout).get().getTextKey());
font.drawStringWithShadow(
text,
x,
y - 12,
0xFFFFFF
);
x += font.getStringWidth(text) + SEPARATOR_MARGIN;
client.getTextureManager().bindTexture(LEFT_ARROW);
this.drawTexture(
x,
y - KEY_SIZE,
KEY_SIZE,
KEY_SIZE
);
x += KEY_SIZE + SEPARATOR_MARGIN;
}
KeyBinding downCallout = sortedBindings[1];
if (downCallout != null) {
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(downCallout).get().getTextKey());
font.drawStringWithShadow(
text,
x + KEY_SIZE * 0.5f - font.getStringWidth(text) * 0.5f,
y + SEPARATOR_MARGIN,
0xFFFFFF
);
client.getTextureManager().bindTexture(DOWN_ARROW);
this.drawTexture(
x,
y - KEY_SIZE,
KEY_SIZE,
KEY_SIZE
);
}
KeyBinding upCallout = sortedBindings[2];
if (upCallout != null) {
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(upCallout).get().getTextKey());
font.drawStringWithShadow(
text,
x + KEY_SIZE * 0.5f - font.getStringWidth(text) * 0.5f,
y - KEY_SIZE * 2 - 12,
0xFFFFFF
);
client.getTextureManager().bindTexture(UP_ARROW);
this.drawTexture(
x,
y - KEY_SIZE * 2 - 2,
KEY_SIZE,
KEY_SIZE
);
}
KeyBinding rightCallout = sortedBindings[3];
if (rightCallout != null) {
x += KEY_SIZE + SEPARATOR_MARGIN;
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(rightCallout).get().getTextKey());
font.drawStringWithShadow(
text,
x + KEY_SIZE + SEPARATOR_MARGIN,
y - 12,
0xFFFFFF
);
client.getTextureManager().bindTexture(RIGHT_ARROW);
this.drawTexture(
x,
y - KEY_SIZE,
KEY_SIZE,
KEY_SIZE
);
}
}
public void renderCallouts(float partialTicks) {
totalPartialTicks += partialTicks;
for (Map.Entry<Integer, Callout> calloutEntry : CalloutManager.getCallouts()) {
Entity entity = client.world.getEntityByID(calloutEntry.getKey());
renderCallout(
I18n.format(calloutEntry.getValue().getType().getTextKey()),
entity != null ? entity.getPositionEyes(partialTicks).add(0, 1, 0) : calloutEntry.getValue().getPosition(),
client.getRenderManager().playerViewX,
client.getRenderManager().playerViewY,
client.getRenderManager().options.thirdPersonView == 2
);
}
}
private void renderCallout(String text, Vec3d position, float pitch, float yaw, boolean isThirdPersonFrontal) {
FontRenderer font = client.fontRenderer;
Vec3d deltaPos = position.subtract(client.getRenderManager().viewerPosX, client.getRenderManager().viewerPosY, client.getRenderManager().viewerPosZ);
GlStateManager.pushMatrix();
GlStateManager.translate(deltaPos.x, deltaPos.y, deltaPos.z);
GlStateManager.rotate(-yaw, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate((float)(isThirdPersonFrontal ? -1 : 1) * pitch, 1.0F, 0.0F, 0.0F);
float scale = (float) Math.max(deltaPos.length() / 8.0f, 1.0f) * (0.75f + MathHelper.abs((float) (MathHelper.sin(totalPartialTicks / 10F) / Math.PI)));
GlStateManager.scale(-0.025F * scale, -0.025F * scale, 0.025F * scale);
GlStateManager.color(1f, 1f, 1f, 1f);
GlStateManager.disableCull();
GlStateManager.depthFunc(GL11.GL_ALWAYS);
font.drawStringWithShadow(text, -font.getStringWidth(text) * 0.5f, -font.FONT_HEIGHT * 0.5f, 0xFFFFFF);
GlStateManager.depthFunc(GL11.GL_LEQUAL);
GlStateManager.enableCull();
GlStateManager.popMatrix();
}
}

View file

@ -0,0 +1,25 @@
package ru.octol1ttle.knockdowns.client.gui;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public abstract class KnockdownsBaseGui extends Gui {
public abstract void render(float partialTicks, ScaledResolution resolution);
protected void drawTexture(int x, int y, int width, int height) {
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuffer();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX);
bufferbuilder.pos(x, y, this.zLevel).tex(0, 0).endVertex();
bufferbuilder.pos(x, y + height, this.zLevel).tex(0, 1).endVertex();
bufferbuilder.pos(x + width, y + height, this.zLevel).tex(1, 1).endVertex();
bufferbuilder.pos(x + width, y, this.zLevel).tex(1, 0).endVertex();
tessellator.draw();
}
}

View file

@ -0,0 +1,64 @@
package ru.octol1ttle.knockdowns.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import org.lwjgl.opengl.GL11;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
import ru.octol1ttle.knockdowns.client.util.KnockedPlayerData;
public class KnockedNotificationGui extends KnockdownsBaseGui {
private static final Minecraft client = Minecraft.getMinecraft();
private static final int KNOCKED_ICON_SIZE = 18;
private static final ResourceLocation KNOCKED_ICON = new ResourceLocation(Tags.MOD_ID, "textures/gui/knocked_icon.png");
private float totalPartialTicks;
@Deprecated
@Override
public void render(float partialTicks, ScaledResolution resolution) {
}
public void renderNotifications(float partialTicks) {
totalPartialTicks += partialTicks;
for (KnockedPlayerData data : KnockedNotificationManager.getKnockedPlayerDatas()) {
Entity entity = client.world.getEntityByID(data.getPlayerId());
renderKnockedNotification(
entity != null ? entity.getPositionEyes(partialTicks).add(0, 1, 0) : data.getPosition(),
client.getRenderManager().playerViewX,
client.getRenderManager().playerViewY,
client.getRenderManager().options.thirdPersonView == 2
);
}
}
private void renderKnockedNotification(Vec3d position, float pitch, float yaw, boolean isThirdPersonFrontal) {
Vec3d deltaPos = position.subtract(client.getRenderManager().viewerPosX, client.getRenderManager().viewerPosY, client.getRenderManager().viewerPosZ);
GlStateManager.pushMatrix();
GlStateManager.translate(deltaPos.x, deltaPos.y, deltaPos.z);
GlStateManager.rotate(-yaw, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate((float)(isThirdPersonFrontal ? -1 : 1) * pitch, 1.0F, 0.0F, 0.0F);
float scale = (float) Math.max(deltaPos.length() / 8.0f, 1.0f) * (0.75f + MathHelper.abs((float) (MathHelper.sin(totalPartialTicks / 10F) / Math.PI)));
GlStateManager.scale(0.05F * scale, 0.05F * scale, 0.05F * scale);
GlStateManager.color(1f, 1f, 1f, 1f);
GlStateManager.disableCull();
GlStateManager.depthFunc(GL11.GL_ALWAYS);
client.getTextureManager().bindTexture(KNOCKED_ICON);
this.drawTexture(
-KNOCKED_ICON_SIZE / 2,
-KNOCKED_ICON_SIZE / 2,
KNOCKED_ICON_SIZE,
KNOCKED_ICON_SIZE
);
GlStateManager.depthFunc(GL11.GL_LEQUAL);
GlStateManager.enableCull();
GlStateManager.popMatrix();
}
}

View file

@ -0,0 +1,47 @@
package ru.octol1ttle.knockdowns.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.text.TextFormatting;
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
import ru.octol1ttle.knockdowns.common.ReviverTracker;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
public class ReviveGui extends KnockdownsBaseGui {
private static final Minecraft client = Minecraft.getMinecraft();
@Override
public void render(float partialTicks, ScaledResolution resolution) {
EntityPlayer reviving =
client.pointedEntity instanceof EntityPlayer && ReviverTracker.getRevivers((EntityPlayer) client.pointedEntity).contains(client.player)
? (EntityPlayer) client.pointedEntity
: client.player;
if (IKnockdownsPlayerData.get(reviving).getReviveTimeLeft() == KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT) {
return;
}
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(reviving);
FontRenderer font = client.fontRenderer;
String timerText = String.format("%.1f", data.getReviveTimeLeft() / 20.0f);
float timerX = (resolution.getScaledWidth() - font.getStringWidth(timerText)) * 0.5f;
int reviverCount = ReviverTracker.getRevivers(reviving).size();
TextFormatting color;
if (reviverCount == 0) {
color = TextFormatting.RED;
} else if (reviverCount == 1) {
color = TextFormatting.WHITE;
} else {
color = TextFormatting.GREEN;
}
String reviverCountText = "x" + reviverCount;
float reviveCountX = (resolution.getScaledWidth() - font.getStringWidth(reviverCountText)) * 0.5f;
font.drawStringWithShadow(color + timerText, timerX, resolution.getScaledHeight() * 0.5f + 5, 553648127);
font.drawStringWithShadow(color + reviverCountText, reviveCountX, resolution.getScaledHeight() * 0.5f + 14, 553648127);
}
}

View file

@ -0,0 +1,145 @@
package ru.octol1ttle.knockdowns.client.network;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
import ru.octol1ttle.knockdowns.client.util.DirectionalCallSound;
import ru.octol1ttle.knockdowns.common.ReviverTracker;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
public class KnockdownsClientPacketHandler {
public static class Callout implements IMessageHandler<PlayerCalloutS2CPacket, IMessage> {
private static final Minecraft client = Minecraft.getMinecraft();
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(PlayerCalloutS2CPacket message, MessageContext ctx) {
client.addScheduledTask(() -> {
if (CalloutManager.addOrUpdateCallout(message)) {
CalloutManager.playCalloutSound(message);
}
});
return null;
}
}
public static class PlayerKnockedDown implements IMessageHandler<PlayerKnockedDownS2CPacket, IMessage> {
private static final Minecraft client = Minecraft.getMinecraft();
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(PlayerKnockedDownS2CPacket message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(message.playerId);
if (entity != null) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
data.setKnockedDown(true);
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
}
if (client.player.dimension == message.dimensionId) {
client.getSoundHandler().playSound(new DirectionalCallSound(KnockdownsSoundEvents.KNOCKED_DOWN, entity, message.position));
KnockedNotificationManager.addKnockedNotification(message.playerId, message.position);
}
});
return null;
}
}
public static class SynchronizePlayerData {
private static final Minecraft client = Minecraft.getMinecraft();
public static class KnockedDown implements IMessageHandler<SynchronizePlayerDataS2CPacket.KnockedDown, IMessage> {
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(SynchronizePlayerDataS2CPacket.KnockedDown message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(message.playerId);
if (entity != null) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
data.setKnockedDown(message.knockedDown);
}
});
return null;
}
}
public static class ReviveTimeLeft implements IMessageHandler<SynchronizePlayerDataS2CPacket.ReviveTimeLeft, IMessage> {
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(SynchronizePlayerDataS2CPacket.ReviveTimeLeft message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(message.playerId);
if (entity != null) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
data.setReviveTimeLeft(message.reviveTimeLeft);
}
});
return null;
}
}
public static class Full implements IMessageHandler<SynchronizePlayerDataS2CPacket.Full, IMessage> {
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(SynchronizePlayerDataS2CPacket.Full message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(message.playerId);
if (entity != null) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
data.setKnockedDown(message.knockedDown);
data.setReviveTimeLeft(message.reviveTimeLeft);
}
});
return null;
}
}
}
public static class SynchronizeRevivers {
private static final Minecraft client = Minecraft.getMinecraft();
public static class Add implements IMessageHandler<SynchronizeReviversS2CPacket.Add, IMessage> {
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(SynchronizeReviversS2CPacket.Add message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer knocked = (EntityPlayer) client.world.getEntityByID(message.knockedId);
EntityPlayer reviver = (EntityPlayer) client.world.getEntityByID(message.reviverId);
if (knocked != null && reviver != null) {
ReviverTracker.startReviving(knocked, reviver);
}
});
return null;
}
}
public static class Remove implements IMessageHandler<SynchronizeReviversS2CPacket.Remove, IMessage> {
@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(SynchronizeReviversS2CPacket.Remove message, MessageContext ctx) {
client.addScheduledTask(() -> {
EntityPlayer knocked = (EntityPlayer) client.world.getEntityByID(message.knockedId);
EntityPlayer reviver = (EntityPlayer) client.world.getEntityByID(message.reviverId);
if (knocked != null && reviver != null) {
ReviverTracker.stopReviving(knocked, reviver);
}
});
return null;
}
}
}
}

View file

@ -0,0 +1,31 @@
package ru.octol1ttle.knockdowns.client.util;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
@SideOnly(Side.CLIENT)
public class Callout {
private final Vec3d position;
private final CalloutType type;
private final long receiveTime;
public Callout(Vec3d position, CalloutType type, long receiveTime) {
this.position = position;
this.type = type;
this.receiveTime = receiveTime;
}
public Vec3d getPosition() {
return position;
}
public CalloutType getType() {
return type;
}
public long getReceiveTime() {
return receiveTime;
}
}

View file

@ -0,0 +1,42 @@
package ru.octol1ttle.knockdowns.client.util;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.Entity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class DirectionalCallSound extends MovingSound {
private final @Nullable Entity entity;
private final Vec3d position;
private int time;
public DirectionalCallSound(SoundEvent event, @Nullable Entity entity, Vec3d position) {
super(event, SoundCategory.PLAYERS);
this.entity = entity;
this.position = position;
}
@Override
public void update() {
this.time++;
if (this.time > 40 || this.entity != null && this.entity.isDead) {
this.donePlaying = true;
return;
}
Minecraft client = Minecraft.getMinecraft();
Vec3d calloutPos = this.entity != null ? this.entity.getPositionVector() : this.position;
Vec3d directionVec = calloutPos.subtract(client.player.getPositionVector()).normalize();
Vec3d finalPos = client.player.getPositionVector().add(directionVec);
this.xPosF = (float) finalPos.x;
this.yPosF = (float) finalPos.y;
this.zPosF = (float) finalPos.z;
}
}

View file

@ -0,0 +1,27 @@
package ru.octol1ttle.knockdowns.client.util;
import net.minecraft.util.math.Vec3d;
public class KnockedPlayerData {
private final int playerId;
private final Vec3d position;
private final long receiveTime;
public KnockedPlayerData(int playerId, Vec3d position, long receiveTime) {
this.playerId = playerId;
this.position = position;
this.receiveTime = receiveTime;
}
public int getPlayerId() {
return playerId;
}
public Vec3d getPosition() {
return position;
}
public long getReceiveTime() {
return receiveTime;
}
}

View file

@ -0,0 +1,13 @@
package ru.octol1ttle.knockdowns.common;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
public interface IClientProxy {
void onFMLInit(FMLInitializationEvent event);
class Dummy implements IClientProxy {
@Override
public void onFMLInit(FMLInitializationEvent event) {
}
}
}

View file

@ -0,0 +1,239 @@
package ru.octol1ttle.knockdowns.common;
import java.util.List;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
import ru.octol1ttle.knockdowns.common.data.KnockdownsCapability;
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_HURT_PERIOD;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_INVULNERABILITY_TICKS;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_TENACITY;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.allPlayersKnocked;
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.resetKnockedState;
@Mod.EventBusSubscriber(modid = Tags.MOD_ID)
public class KnockdownsCommonEventListener {
public static void onFMLInit(FMLInitializationEvent event) {
KnockdownsNetwork.registerPackets();
KnockdownsCapability.register();
}
@SubscribeEvent
public static void onSoundsRegister(RegistryEvent.Register<SoundEvent> event) {
event.getRegistry().register(KnockdownsSoundEvents.CALLOUT);
}
@SubscribeEvent
public static void onCapabilitiesAttach(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof EntityPlayer) {
event.addCapability(KnockdownsCapability.ID, new KnockdownsCapability());
}
}
@SubscribeEvent
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
MinecraftServer server = event.player.getServer();
if (event.phase == TickEvent.Phase.START || server == null) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) event.player;
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(player);
if (!data.isKnockedDown()) {
return;
}
if (allPlayersKnocked(server, player)) {
player.attackEntityFrom(DamageSource.GENERIC, player.getMaxHealth());
return;
}
List<EntityPlayer> revivers = ReviverTracker.getRevivers(player);
if (!revivers.isEmpty()) {
data.setReviveTimeLeft(data.getReviveTimeLeft() - revivers.size());
KnockdownsNetwork.sendToMultiple(
new SynchronizePlayerDataS2CPacket.ReviveTimeLeft(player.getEntityId(), data.getReviveTimeLeft()),
revivers,
player
);
if (data.getReviveTimeLeft() <= 0) {
resetKnockedState(player, data);
player.setEntityInvulnerable(false);
player.setHealth(player.getMaxHealth() * 0.3f);
player.setAbsorptionAmount(0.0f);
}
return;
}
int oldReviveTimeLeft = data.getReviveTimeLeft();
data.setReviveTimeLeft(Math.min(INITIAL_REVIVE_TIME_LEFT, oldReviveTimeLeft + 1));
if (data.getReviveTimeLeft() != oldReviveTimeLeft) {
KnockdownsNetwork.sendToPlayer(
new SynchronizePlayerDataS2CPacket.ReviveTimeLeft(player.getEntityId(), data.getReviveTimeLeft()),
player
);
}
data.setTicksKnocked(data.getTicksKnocked() + 1);
int period = MathHelper.floor(KNOCKED_HURT_PERIOD * 20);
if (data.getTicksKnocked() >= KNOCKED_INVULNERABILITY_TICKS && data.getTicksKnocked() % period == 0) {
player.setEntityInvulnerable(false);
player.attackEntityFrom(DamageSource.GENERIC, player.getMaxHealth() / (KNOCKED_TENACITY / KNOCKED_HURT_PERIOD));
}
}
@SubscribeEvent
public static void onPlayerDeath(LivingDeathEvent event) {
if (!(event.getEntityLiving() instanceof EntityPlayerMP)) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) event.getEntityLiving();
IKnockdownsPlayerData data = player.getCapability(KnockdownsCapability.CAPABILITY, null);
if (data == null) {
return;
}
if (data.isKnockedDown() || allPlayersKnocked(player.getServer(), player)) {
ReviverTracker.clearRevivers(player);
return;
}
player.clearActivePotions();
player.setEntityInvulnerable(true);
player.setHealth(1.0f);
player.setAbsorptionAmount(player.getMaxHealth() - 1.0f);
player.extinguish();
player.setAir(300);
player.clearElytraFlying();
player.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 6000, 3));
Entity trueSource = event.getSource().getTrueSource();
if (trueSource instanceof EntityLiving) {
((EntityLiving) trueSource).setAttackTarget(null);
}
data.setKnockedDown(true);
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
data.setTicksKnocked(0);
KnockdownsNetwork.sendToAll(new PlayerKnockedDownS2CPacket(player.getEntityId(), player.dimension, player.getPositionEyes(1).add(0, 1, 0)));
TextComponentTranslation deathMessage = (TextComponentTranslation) player.getCombatTracker().getDeathMessage();
String knockdownKey = deathMessage.getKey().replace("death.", "knockdown.");
player.getServer().getPlayerList().sendMessage(
I18n.hasKey(knockdownKey)
? new TextComponentTranslation(knockdownKey, deathMessage.getFormatArgs())
: deathMessage,
true
);
event.setCanceled(true);
}
@SubscribeEvent
public static void onMobTarget(LivingSetAttackTargetEvent event) {
if (event.getTarget() instanceof EntityPlayer && IKnockdownsPlayerData.get((EntityPlayer) event.getTarget()).isKnockedDown()) {
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
}
@SubscribeEvent
public static void onPlayerStartTracking(PlayerEvent.StartTracking event) {
if (event.getTarget() instanceof EntityPlayerMP) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get((EntityPlayer) event.getTarget());
if (data.isKnockedDown()) {
KnockdownsNetwork.sendToPlayer(
new SynchronizePlayerDataS2CPacket.KnockedDown(
event.getTarget().getEntityId(),
data.isKnockedDown()
),
(EntityPlayerMP) event.getEntityPlayer()
);
}
}
}
@SubscribeEvent
public static void onKnockedAttack(AttackEntityEvent event) {
if (IKnockdownsPlayerData.get(event.getEntityPlayer()).isKnockedDown()) {
event.setCanceled(true);
}
}
@SubscribeEvent
public static void onKnockedInteraction(PlayerInteractEvent event) {
if (IKnockdownsPlayerData.get(event.getEntityPlayer()).isKnockedDown()) {
if (!(event instanceof PlayerInteractEvent.RightClickBlock) && event.isCancelable()) {
event.setCanceled(true);
event.setCancellationResult(EnumActionResult.FAIL);
}
} else if (event instanceof PlayerInteractEvent.EntityInteract) {
onPlayerInteraction((PlayerInteractEvent.EntityInteract) event);
}
}
public static void onPlayerInteraction(PlayerInteractEvent.EntityInteract event) {
if (event.getEntityLiving() instanceof EntityPlayerMP) {
EntityPlayerMP knocked = (EntityPlayerMP) event.getEntityLiving();
if (IKnockdownsPlayerData.get(knocked).isKnockedDown()) {
KnockdownsNetwork.sendToMultiple(
new SynchronizeReviversS2CPacket.Add(event.getEntityLiving().getEntityId(), event.getEntityPlayer().getEntityId()),
ReviverTracker.getRevivers(knocked),
knocked
);
ReviverTracker.startReviving(knocked, event.getEntityPlayer());
}
}
}
@SubscribeEvent
public static void onPlayerJoin(PlayerLoggedInEvent event) {
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(event.player);
KnockdownsNetwork.sendToPlayer(
new SynchronizePlayerDataS2CPacket.Full(event.player.getEntityId(), data.isKnockedDown(), data.getReviveTimeLeft()),
(EntityPlayerMP) event.player
);
}
@SubscribeEvent
public static void onPlayerLeave(PlayerLoggedOutEvent event) {
ReviverTracker.clearRevivers(event.player);
}
}

View file

@ -0,0 +1,43 @@
package ru.octol1ttle.knockdowns.common;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import zone.rong.mixinbooter.IEarlyMixinLoader;
@IFMLLoadingPlugin.MCVersion("1.12.2")
public class KnockdownsFMLLoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader {
@Override
public String[] getASMTransformerClass() {
return null;
}
@Override
public String getModContainerClass() {
return null;
}
@Nullable
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {
}
@Override
public String getAccessTransformerClass() {
return null;
}
@Override
public List<String> getMixinConfigs() {
ArrayList<String> list = new ArrayList<>();
list.add("mixins.knockdowns.json");
return list;
}
}

View file

@ -0,0 +1,21 @@
package ru.octol1ttle.knockdowns.common;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ru.octol1ttle.knockdowns.Tags;
@Mod(modid = Tags.MOD_ID, name = Tags.MOD_NAME, version = Tags.VERSION)
public class KnockdownsMod {
public static final Logger LOGGER = LogManager.getLogger(Tags.MOD_NAME);
@SidedProxy(clientSide = "ru.octol1ttle.knockdowns.client.ClientProxy", serverSide = "ru.octol1ttle.knockdowns.common.IClientProxy$Dummy")
public static IClientProxy clientProxy;
@Mod.EventHandler
public void onFMLInit(FMLInitializationEvent event) {
clientProxy.onFMLInit(event);
KnockdownsCommonEventListener.onFMLInit(event);
}
}

View file

@ -0,0 +1,43 @@
package ru.octol1ttle.knockdowns.common;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.server.MinecraftServer;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
public class KnockdownsUtils {
public static final int INITIAL_REVIVE_TIME_LEFT = 200;
public static final float KNOCKED_INVULNERABILITY_TICKS = 3.0f * 20.0f;
public static final float KNOCKED_HURT_PERIOD = 1.2f;
public static final float KNOCKED_TENACITY = 60.0f;
public static boolean allPlayersKnocked(MinecraftServer server, EntityPlayer except) {
for (EntityPlayer player : server.getPlayerList().getPlayers()) {
if (player.equals(except)) {
continue;
}
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(player);
if (player.isEntityAlive() && !data.isKnockedDown()) {
return false;
}
}
return false;
}
public static void resetKnockedState(EntityPlayerMP player, IKnockdownsPlayerData data) {
player.removePotionEffect(MobEffects.SLOWNESS);
data.setKnockedDown(false);
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
data.setTicksKnocked(0);
KnockdownsNetwork.sendToTrackingAndSelf(
new SynchronizePlayerDataS2CPacket.KnockedDown(player.getEntityId(), data.isKnockedDown()),
player
);
ReviverTracker.clearRevivers(player);
}
}

View file

@ -0,0 +1,32 @@
package ru.octol1ttle.knockdowns.common;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.entity.player.EntityPlayer;
public class ReviverTracker {
private static final Map<EntityPlayer, List<EntityPlayer>> knockedToReviversMap = new HashMap<>();
public static void startReviving(EntityPlayer knocked, EntityPlayer reviver) {
getRevivers(knocked).add(reviver);
}
public static void stopReviving(EntityPlayer knocked, EntityPlayer reviver) {
getRevivers(knocked).remove(reviver);
}
public static void clearRevivers(EntityPlayer knocked) {
getRevivers(knocked).clear();
}
public static List<EntityPlayer> getRevivers(EntityPlayer knocked) {
return knockedToReviversMap.computeIfAbsent(knocked, player -> new ArrayList<>());
}
public static Set<Map.Entry<EntityPlayer, List<EntityPlayer>>> getAllRevivers() {
return knockedToReviversMap.entrySet();
}
}

View file

@ -0,0 +1,35 @@
package ru.octol1ttle.knockdowns.common.communication;
public enum CalloutType {
DANGER((byte) 0, "knockdowns.callout.danger"),
BOOYAH((byte) 1, "knockdowns.callout.booyah"),
THIS_WAY((byte) 2, "knockdowns.callout.this_way"),
OUCH((byte) 3, "knockdowns.callout.ouch"),
HELP((byte) 4, "knockdowns.callout.help");
private final byte id;
private final String textKey;
CalloutType(byte id, String textKey) {
this.id = id;
this.textKey = textKey;
}
public byte getId() {
return id;
}
public String getTextKey() {
return textKey;
}
public static CalloutType byId(byte id) {
for (CalloutType type : CalloutType.values()) {
if (id == type.getId()) {
return type;
}
}
throw new IllegalArgumentException();
}
}

View file

@ -0,0 +1,21 @@
package ru.octol1ttle.knockdowns.common.data;
import java.util.Objects;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.INBTSerializable;
public interface IKnockdownsPlayerData extends INBTSerializable<NBTTagCompound> {
boolean isKnockedDown();
void setKnockedDown(boolean knockedDown);
int getReviveTimeLeft();
void setReviveTimeLeft(int reviveTimeLeft);
int getTicksKnocked();
void setTicksKnocked(int ticksKnocked);
static IKnockdownsPlayerData get(EntityPlayer player) {
return Objects.requireNonNull(player.getCapability(KnockdownsCapability.CAPABILITY, null));
}
}

View file

@ -0,0 +1,65 @@
package ru.octol1ttle.knockdowns.common.data;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.LazyLoadBase;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import ru.octol1ttle.knockdowns.Tags;
public class KnockdownsCapability implements ICapabilitySerializable<NBTTagCompound> {
@CapabilityInject(IKnockdownsPlayerData.class)
public static Capability<IKnockdownsPlayerData> CAPABILITY;
public static final ResourceLocation ID = new ResourceLocation(Tags.MOD_ID, "data");
private KnockdownsPlayerData playerData = null;
private final LazyLoadBase<KnockdownsPlayerData> lazy = new LazyLoadBase<KnockdownsPlayerData>() {
@Override
protected KnockdownsPlayerData load() {
return playerData == null ? (playerData = new KnockdownsPlayerData()) : playerData;
}
};
public static void register() {
CapabilityManager.INSTANCE.register(IKnockdownsPlayerData.class, new Capability.IStorage<IKnockdownsPlayerData>() {
@Nullable
@Override
public NBTBase writeNBT(Capability<IKnockdownsPlayerData> capability, IKnockdownsPlayerData instance, EnumFacing side) {
return instance.serializeNBT();
}
@Override
public void readNBT(Capability<IKnockdownsPlayerData> capability, IKnockdownsPlayerData instance, EnumFacing side, NBTBase nbt) {
instance.deserializeNBT((NBTTagCompound) nbt);
}
}, KnockdownsPlayerData::new);
}
@Override
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
return capability == CAPABILITY;
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
return capability == CAPABILITY ? (T) lazy.getValue() : null;
}
@Override
public NBTTagCompound serializeNBT() {
return lazy.getValue().serializeNBT();
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
lazy.getValue().deserializeNBT(nbt);
}
}

View file

@ -0,0 +1,59 @@
package ru.octol1ttle.knockdowns.common.data;
import net.minecraft.nbt.NBTTagCompound;
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
public class KnockdownsPlayerData implements IKnockdownsPlayerData {
private static final String KEY_KNOCKED_DOWN = "KnockedDown";
private static final String KEY_REVIVE_TIME_LEFT = "ReviveTimeLeft";
private static final String KEY_TICKS_KNOCKED = "TicksKnocked";
private boolean knockedDown = false;
private int reviveTimeLeft = KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
private int ticksKnocked = 0;
@Override
public boolean isKnockedDown() {
return this.knockedDown;
}
@Override
public void setKnockedDown(boolean knockedDown) {
this.knockedDown = knockedDown;
}
@Override
public int getReviveTimeLeft() {
return this.reviveTimeLeft;
}
@Override
public void setReviveTimeLeft(int reviveTimeLeft) {
this.reviveTimeLeft = reviveTimeLeft;
}
@Override
public int getTicksKnocked() {
return this.ticksKnocked;
}
@Override
public void setTicksKnocked(int ticksKnocked) {
this.ticksKnocked = ticksKnocked;
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setBoolean(KEY_KNOCKED_DOWN, this.knockedDown);
nbt.setInteger(KEY_REVIVE_TIME_LEFT, this.reviveTimeLeft);
nbt.setInteger(KEY_TICKS_KNOCKED, this.ticksKnocked);
return nbt;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
this.knockedDown = nbt.getBoolean(KEY_KNOCKED_DOWN);
this.reviveTimeLeft = nbt.getInteger(KEY_REVIVE_TIME_LEFT);
this.ticksKnocked = nbt.getInteger(KEY_TICKS_KNOCKED);
}
}

View file

@ -0,0 +1,31 @@
package ru.octol1ttle.knockdowns.common.mixins;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
@SuppressWarnings("ConstantValue")
@Mixin(EntityLivingBase.class)
public abstract class EntityLivingBaseMixin extends Entity {
public EntityLivingBaseMixin(World worldIn) {
super(worldIn);
}
@Inject(method = "checkTotemDeathProtection", at = @At("RETURN"))
public void onTotemActivation(CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValue() && ((Object) this) instanceof EntityPlayerMP) {
EntityPlayerMP player = (EntityPlayerMP) (Object) this;
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(player);
if (data.isKnockedDown()) {
KnockdownsUtils.resetKnockedState(player, data);
}
}
}
}

View file

@ -0,0 +1,22 @@
package ru.octol1ttle.knockdowns.common.mixins;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.entity.player.EntityPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
@SuppressWarnings("ConstantValue")
@Mixin(EntityPlayer.class)
public class EntityPlayerMixin {
@ModifyReturnValue(method = "shouldHeal", at = @At("RETURN"))
private boolean dontHealIfKnockedDown(boolean original) {
if (((Object) this) instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) (Object) this;
if (IKnockdownsPlayerData.get(player).isKnockedDown()) {
return false;
}
}
return original;
}
}

View file

@ -0,0 +1,71 @@
package ru.octol1ttle.knockdowns.common.network;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import ru.octol1ttle.knockdowns.Tags;
import ru.octol1ttle.knockdowns.client.network.KnockdownsClientPacketHandler;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
public class KnockdownsNetwork {
private static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(Tags.MOD_ID);
private static int packetId = 0;
public static void registerPackets() {
INSTANCE.registerMessage(KnockdownsServerPacketHandler.Callout.class, PlayerCalloutC2SPacket.class, packetId++, Side.SERVER);
INSTANCE.registerMessage(KnockdownsServerPacketHandler.CancelRevive.class, CancelReviveC2SPacket.class, packetId++, Side.SERVER);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.Callout.class, PlayerCalloutS2CPacket.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.PlayerKnockedDown.class, PlayerKnockedDownS2CPacket.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.SynchronizePlayerData.KnockedDown.class, SynchronizePlayerDataS2CPacket.KnockedDown.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.SynchronizePlayerData.ReviveTimeLeft.class, SynchronizePlayerDataS2CPacket.ReviveTimeLeft.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.SynchronizePlayerData.Full.class, SynchronizePlayerDataS2CPacket.Full.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.SynchronizeRevivers.Add.class, SynchronizeReviversS2CPacket.Add.class, packetId++, Side.CLIENT);
INSTANCE.registerMessage(KnockdownsClientPacketHandler.SynchronizeRevivers.Remove.class, SynchronizeReviversS2CPacket.Remove.class, packetId++, Side.CLIENT);
}
@SideOnly(Side.CLIENT)
public static void sendToServer(IMessage message) {
INSTANCE.sendToServer(message);
}
public static void sendToAll(IMessage message) {
INSTANCE.sendToAll(message);
}
public static void sendToDimension(IMessage message, MessageContext context) {
INSTANCE.sendToDimension(message, context.getServerHandler().player.dimension);
}
public static void sendToTrackingAndSelf(IMessage message, EntityPlayerMP player) {
sendToPlayer(message, player);
sendToTracking(message, player);
}
public static void sendToMultiple(IMessage message, List<EntityPlayer> players, EntityPlayerMP player) {
sendToPlayer(message, player);
for (EntityPlayer listed : players) {
sendToPlayer(message, (EntityPlayerMP) listed);
}
}
public static void sendToTracking(IMessage message, Entity entity) {
INSTANCE.sendToAllTracking(message, entity);
}
public static void sendToPlayer(IMessage message, EntityPlayerMP player) {
INSTANCE.sendTo(message, player);
}
}

View file

@ -0,0 +1,51 @@
package ru.octol1ttle.knockdowns.common.network;
import java.util.List;
import java.util.Map;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import ru.octol1ttle.knockdowns.common.ReviverTracker;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
public class KnockdownsServerPacketHandler {
public static class Callout implements IMessageHandler<PlayerCalloutC2SPacket, IMessage> {
@Override
public IMessage onMessage(PlayerCalloutC2SPacket message, MessageContext ctx) {
KnockdownsNetwork.sendToDimension(
new PlayerCalloutS2CPacket(
ctx.getServerHandler().player.getEntityId(),
ctx.getServerHandler().player.getPositionEyes(1).add(0, 1, 0),
message.type
),
ctx
);
return null;
}
}
public static class CancelRevive implements IMessageHandler<CancelReviveC2SPacket, IMessage> {
@Override
public IMessage onMessage(CancelReviveC2SPacket message, MessageContext ctx) {
EntityPlayerMP player = ctx.getServerHandler().player;
for (Map.Entry<EntityPlayer, List<EntityPlayer>> revivers : ReviverTracker.getAllRevivers()) {
if (revivers.getValue().contains(player)) {
revivers.getValue().remove(player);
KnockdownsNetwork.sendToMultiple(
new SynchronizeReviversS2CPacket.Remove(revivers.getKey().getEntityId(), player.getEntityId()),
revivers.getValue(),
(EntityPlayerMP) revivers.getKey()
);
break;
}
}
return null;
}
}
}

View file

@ -0,0 +1,17 @@
package ru.octol1ttle.knockdowns.common.network.packets.c2s;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class CancelReviveC2SPacket implements IMessage {
public CancelReviveC2SPacket() {
}
@Override
public void toBytes(ByteBuf buf) {
}
@Override
public void fromBytes(ByteBuf buf) {
}
}

View file

@ -0,0 +1,25 @@
package ru.octol1ttle.knockdowns.common.network.packets.c2s;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
public class PlayerCalloutC2SPacket implements IMessage {
public PlayerCalloutC2SPacket() {
}
public CalloutType type;
public PlayerCalloutC2SPacket(CalloutType type) {
this.type = type;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeByte(this.type.getId());
}
@Override
public void fromBytes(ByteBuf buf) {
this.type = CalloutType.byId(buf.readByte());
}
}

View file

@ -0,0 +1,37 @@
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
import io.netty.buffer.ByteBuf;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
public class PlayerCalloutS2CPacket implements IMessage {
public PlayerCalloutS2CPacket() {
}
public int playerId;
public Vec3d position;
public CalloutType type;
public PlayerCalloutS2CPacket(int playerId, Vec3d position, CalloutType type) {
this.playerId = playerId;
this.position = position;
this.type = type;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.playerId);
buf.writeDouble(this.position.x);
buf.writeDouble(this.position.y);
buf.writeDouble(this.position.z);
buf.writeByte(this.type.getId());
}
@Override
public void fromBytes(ByteBuf buf) {
this.playerId = buf.readInt();
this.position = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
this.type = CalloutType.byId(buf.readByte());
}
}

View file

@ -0,0 +1,36 @@
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
import io.netty.buffer.ByteBuf;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class PlayerKnockedDownS2CPacket implements IMessage {
public PlayerKnockedDownS2CPacket() {
}
public int playerId;
public int dimensionId;
public Vec3d position;
public PlayerKnockedDownS2CPacket(int playerId, int dimensionId, Vec3d position) {
this.playerId = playerId;
this.dimensionId = dimensionId;
this.position = position;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.playerId);
buf.writeInt(this.dimensionId);
buf.writeDouble(this.position.x);
buf.writeDouble(this.position.y);
buf.writeDouble(this.position.z);
}
@Override
public void fromBytes(ByteBuf buf) {
this.playerId = buf.readInt();
this.dimensionId = buf.readInt();
this.position = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
}
}

View file

@ -0,0 +1,85 @@
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class SynchronizePlayerDataS2CPacket {
public static class KnockedDown implements IMessage {
public KnockedDown() {
}
public int playerId;
public boolean knockedDown;
public KnockedDown(int playerId, boolean knockedDown) {
this.playerId = playerId;
this.knockedDown = knockedDown;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.playerId);
buf.writeBoolean(this.knockedDown);
}
@Override
public void fromBytes(ByteBuf buf) {
this.playerId = buf.readInt();
this.knockedDown = buf.readBoolean();
}
}
public static class ReviveTimeLeft implements IMessage {
public ReviveTimeLeft() {
}
public int playerId;
public int reviveTimeLeft;
public ReviveTimeLeft(int playerId, int reviveTimeLeft) {
this.playerId = playerId;
this.reviveTimeLeft = reviveTimeLeft;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.playerId);
buf.writeInt(this.reviveTimeLeft);
}
@Override
public void fromBytes(ByteBuf buf) {
this.playerId = buf.readInt();
this.reviveTimeLeft = buf.readInt();
}
}
public static class Full implements IMessage {
public Full() {
}
public int playerId;
public boolean knockedDown;
public int reviveTimeLeft;
public Full(int playerId, boolean knockedDown, int reviveTimeLeft) {
this.playerId = playerId;
this.knockedDown = knockedDown;
this.reviveTimeLeft = reviveTimeLeft;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.playerId);
buf.writeBoolean(this.knockedDown);
buf.writeInt(this.reviveTimeLeft);
}
@Override
public void fromBytes(ByteBuf buf) {
this.playerId = buf.readInt();
this.knockedDown = buf.readBoolean();
this.reviveTimeLeft = buf.readInt();
}
}
}

View file

@ -0,0 +1,56 @@
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class SynchronizeReviversS2CPacket {
public static class Add implements IMessage {
public Add() {
}
public int knockedId;
public int reviverId;
public Add(int knockedId, int reviverId) {
this.knockedId = knockedId;
this.reviverId = reviverId;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.knockedId);
buf.writeInt(this.reviverId);
}
@Override
public void fromBytes(ByteBuf buf) {
this.knockedId = buf.readInt();
this.reviverId = buf.readInt();
}
}
public static class Remove implements IMessage {
public Remove() {
}
public int knockedId;
public int reviverId;
public Remove(int knockedId, int reviverId) {
this.knockedId = knockedId;
this.reviverId = reviverId;
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(this.knockedId);
buf.writeInt(this.reviverId);
}
@Override
public void fromBytes(ByteBuf buf) {
this.knockedId = buf.readInt();
this.reviverId = buf.readInt();
}
}
}

View file

@ -0,0 +1,17 @@
package ru.octol1ttle.knockdowns.common.registry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import ru.octol1ttle.knockdowns.Tags;
public class KnockdownsSoundEvents {
public static final SoundEvent CALLOUT;
public static final SoundEvent KNOCKED_DOWN;
static {
ResourceLocation callout = new ResourceLocation(Tags.MOD_ID, "callout");
CALLOUT = new SoundEvent(callout).setRegistryName(callout);
ResourceLocation knockedDown = new ResourceLocation(Tags.MOD_ID, "knocked_down");
KNOCKED_DOWN = new SoundEvent(knockedDown).setRegistryName(knockedDown);
}
}

View file

@ -0,0 +1,64 @@
knockdowns.key.category=Knockdowns
knockdowns.key.callout.danger="Опасность!"
knockdowns.key.callout.booyah="Йо-хо!"
knockdowns.key.callout.this_way_help="Сюда!" ("SOS!" когда тяжело ранен)
knockdowns.key.callout.ouch="Непруха!"
knockdowns.callout.danger=Опасность!
knockdowns.callout.booyah=Йо-хо!
knockdowns.callout.this_way=Сюда!
knockdowns.callout.ouch=Непруха!
knockdowns.callout.help=SOS!
knockdowns.subtitles.callout=Игрок зовёт союзников
knockdowns.subtitles.knocked_down=Игрок тяжело ранен
knockdown.attack.anvil=%1$s тяжело ранен упавшей наковальней
knockdown.attack.arrow=%1$s тяжело ранен стрелой %2$s
knockdown.attack.arrow.item=%1$s тяжело ранен стрелой %2$s с помощью %3$s
knockdown.attack.cactus=%1$s исколот до тяжелого ранения
knockdown.attack.cactus.player=%1$s тяжело ранен кактусом, спасаясь от %2$s
knockdown.attack.cramming=%1$s расплющен до тяжелого ранения
knockdown.attack.dragonBreath=%1$s тяжело ранен в драконьем дыхании
knockdown.attack.drown=%1$s тяжело ранен от нехватки воздуха
knockdown.attack.drown.player=%1$s тяжело ранен от нехватки воздуха, спасаясь от %2$s
knockdown.attack.explosion=%1$s тяжело ранен взрывом
knockdown.attack.explosion.player=%1$s был тяжело ранен взрывом %2$s
knockdown.attack.fall=%1$s разбился до тяжелого ранения
knockdown.attack.fallingBlock=%1$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.flyIntoWall=%1$s преобразовал кинетическую энергию в тяжелое ранение
knockdown.attack.generic=%1$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.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.magic=%1$s был тяжело ранен магией
knockdown.attack.mob=%1$s был тяжело ранен %2$s
knockdown.attack.onFire=%1$s сгорел до тяжелого ранения
knockdown.attack.onFire.player=%1$s был сожжён до тяжелого ранения, пока боролся с %2$s
knockdown.attack.outOfWorld=%1$s тяжело ранен отсутствием земли под собой
knockdown.attack.player=%1$s был тяжело ранен %2$s
knockdown.attack.player.item=%1$s был тяжело ранен %2$s с помощью %3$s
knockdown.attack.starve=%1$s тяжело ранен от голода
knockdown.attack.thorns=%1$s был тяжело ранен, пытаясь навредить %2$s
knockdown.attack.thrown=%1$s был избит до тяжелого ранения %2$s
knockdown.attack.thrown.item=%1$s был избит до тяжелого ранения %2$s с помощью %3$s
knockdown.attack.wither=%1$s тяжело ранен иссушением
knockdown.fell.accident.generic=%1$s разбился до тяжелого ранения
knockdown.fell.accident.ladder=%1$s свалился с лестницы и был тяжело ранен
knockdown.fell.accident.vines=%1$s сорвался с лианы и был тяжело ранен
knockdown.fell.accident.water=%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 был обречён на тяжелое ранение

View file

@ -1,11 +1,11 @@
{ {
"package": "", "package": "ru.octol1ttle.knockdowns.common.mixins",
"required": true, "required": true,
"refmap": "${mixin_refmap}", "refmap": "${mixin_refmap}",
"target": "@env(DEFAULT)", "target": "@env(DEFAULT)",
"minVersion": "0.8.5", "minVersion": "0.8.5",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"mixins": [], "mixins": [ "EntityLivingBaseMixin", "EntityPlayerMixin" ],
"server": [], "server": [],
"client": [] "client": []
} }