Armored Elytra

This commit is contained in:
Aleksey 2021-04-29 18:11:42 +03:00
parent d5a93cb730
commit bbf7169ccc
18 changed files with 472 additions and 39 deletions

View file

@ -0,0 +1,52 @@
package ru.betterend.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.ElytraLayer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.PlayerModelPart;
import net.minecraft.world.item.ItemStack;
import ru.betterend.BetterEnd;
import ru.betterend.item.ArmoredElytra;
import ru.betterend.item.model.ArmoredElytraModel;
import ru.betterend.registry.EndItems;
public class ArmoredElytraLayer<T extends LivingEntity, M extends EntityModel<T>> extends ElytraLayer<T, M> {
private final ArmoredElytraModel<T> elytraModel = new ArmoredElytraModel<>();
public ArmoredElytraLayer(RenderLayerParent<T, M> renderLayerParent) {
super(renderLayerParent);
}
public void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T livingEntity, float f, float g, float h, float j, float k, float l) {
ItemStack itemStack = livingEntity.getItemBySlot(EquipmentSlot.CHEST);
if (itemStack.getItem() instanceof ArmoredElytra) {
ResourceLocation wingsTexture = ((ArmoredElytra) itemStack.getItem()).getWingTexture();
if (livingEntity instanceof AbstractClientPlayer) {
AbstractClientPlayer abstractClientPlayer = (AbstractClientPlayer) livingEntity;
if (abstractClientPlayer.isElytraLoaded() && abstractClientPlayer.getElytraTextureLocation() != null) {
wingsTexture = abstractClientPlayer.getElytraTextureLocation();
} else if (abstractClientPlayer.isCapeLoaded() && abstractClientPlayer.getCloakTextureLocation() != null && abstractClientPlayer.isModelPartShown(PlayerModelPart.CAPE)) {
wingsTexture = abstractClientPlayer.getCloakTextureLocation();
}
}
poseStack.pushPose();
poseStack.translate(0.0D, 0.0D, 0.125D);
getParentModel().copyPropertiesTo(elytraModel);
elytraModel.setupAnim(livingEntity, f, g, j, k, l);
VertexConsumer vertexConsumer = ItemRenderer.getArmorFoilBuffer(multiBufferSource, RenderType.armorCutoutNoCull(wingsTexture), false, itemStack.hasFoil());
elytraModel.renderToBuffer(poseStack, vertexConsumer, i, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
poseStack.popPose();
}
}
}

View file

@ -0,0 +1,5 @@
package ru.betterend.interfaces;
public interface BreakableItem {
void registerBrokenItem();
}

View file

@ -0,0 +1,57 @@
package ru.betterend.item;
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.renderer.item.ItemPropertyFunction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.*;
import ru.betterend.BetterEnd;
import ru.betterend.interfaces.BreakableItem;
import ru.betterend.patterns.Patterned;
import ru.betterend.patterns.Patterns;
import ru.betterend.registry.EndItems;
public class ArmoredElytra extends ElytraItem implements EquipmentSlotProvider, BreakableItem, Patterned {
private final ResourceLocation wingTexture;
private final Item repairItem;
private final double movementFactor;
public ArmoredElytra(String name, Item repairItem, int durability, double movementFactor, boolean fireproof) {
super(fireproof ? EndItems.makeItemSettings().durability(durability).rarity(Rarity.RARE).fireResistant() :
EndItems.makeItemSettings().durability(durability).rarity(Rarity.RARE));
this.wingTexture = BetterEnd.makeID("textures/entity/" + name + ".png");
this.repairItem = repairItem;
this.movementFactor = movementFactor;
}
public double getMovementFactor() {
return movementFactor;
}
public ResourceLocation getWingTexture() {
return wingTexture;
}
@Override
public boolean isValidRepairItem(ItemStack itemStack, ItemStack itemStack2) {
return itemStack2.getItem() == repairItem;
}
@Override
public void registerBrokenItem() {
FabricModelPredicateProviderRegistry.register(this, new ResourceLocation("broken"),
(itemStack, clientLevel, livingEntity) -> ElytraItem.isFlyEnabled(itemStack) ? 0.0F : 1.0F);
}
@Override
public String getModelPattern(String name) {
return Patterns.createItemGenerated(name);
}
@Override
public EquipmentSlot getPreferredEquipmentSlot(ItemStack stack) {
return EquipmentSlot.CHEST;
}
}

View file

@ -11,6 +11,6 @@ public class PatternedItem extends Item implements Patterned {
@Override @Override
public String getModelPattern(String name) { public String getModelPattern(String name) {
return Patterns.createJson(Patterns.ITEM_GENERATED, name); return Patterns.createItemGenerated(name);
} }
} }

View file

@ -0,0 +1,73 @@
package ru.betterend.item.model;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.model.AgeableListModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.Vec3;
public class ArmoredElytraModel<T extends LivingEntity> extends AgeableListModel<T> {
private final ModelPart rightWing;
private final ModelPart leftWing;
public ArmoredElytraModel() {
this.leftWing = new ModelPart(this, 22, 0);
this.leftWing.addBox(-10.0F, 0.0F, 0.0F, 10.0F, 20.0F, 2.0F, 1.0F);
this.rightWing = new ModelPart(this, 22, 0);
this.rightWing.mirror = true;
this.rightWing.addBox(0.0F, 0.0F, 0.0F, 10.0F, 20.0F, 2.0F, 1.0F);
}
protected Iterable<ModelPart> headParts() {
return ImmutableList.of();
}
protected Iterable<ModelPart> bodyParts() {
return ImmutableList.of(leftWing, rightWing);
}
public void setupAnim(T livingEntity, float f, float g, float h, float i, float j) {
float rotX = 0.2617994F;
float rotZ = -0.2617994F;
float rotY = 0.0F;
float wingY = 0.0F;
if (livingEntity.isFallFlying()) {
float coef = 1.0F;
Vec3 vec3 = livingEntity.getDeltaMovement();
if (vec3.y < 0.0D) {
Vec3 normalized = vec3.normalize();
coef = 1.0F - (float) Math.pow(-normalized.y, 2.5D);
}
rotX = coef * 0.34906584F + (1.0F - coef) * rotX;
rotZ = coef * -1.5707964F + (1.0F - coef) * rotZ;
} else if (livingEntity.isCrouching()) {
rotX = 0.6981317F;
rotZ = -0.7853982F;
rotY = 0.08726646F;
wingY = 3.0F;
}
leftWing.x = 5.0F;
leftWing.y = wingY;
if (livingEntity instanceof AbstractClientPlayer) {
AbstractClientPlayer abstractClientPlayer = (AbstractClientPlayer) livingEntity;
abstractClientPlayer.elytraRotX = (float) ((double) abstractClientPlayer.elytraRotX + (double) (rotX - abstractClientPlayer.elytraRotX) * 0.1D);
abstractClientPlayer.elytraRotY = (float) ((double) abstractClientPlayer.elytraRotY + (double) (rotY - abstractClientPlayer.elytraRotY) * 0.1D);
abstractClientPlayer.elytraRotZ = (float) ((double) abstractClientPlayer.elytraRotZ + (double) (rotZ - abstractClientPlayer.elytraRotZ) * 0.1D);
leftWing.xRot = abstractClientPlayer.elytraRotX;
leftWing.yRot = abstractClientPlayer.elytraRotY;
leftWing.zRot = abstractClientPlayer.elytraRotZ;
} else {
leftWing.xRot = rotX;
leftWing.zRot = rotZ;
leftWing.yRot = rotY;
}
rightWing.x = -leftWing.x;
rightWing.yRot = -leftWing.yRot;
rightWing.y = leftWing.y;
rightWing.xRot = leftWing.xRot;
rightWing.zRot = -leftWing.zRot;
}
}

View file

@ -0,0 +1,25 @@
package ru.betterend.mixin.client;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.layers.CapeLayer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
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.CallbackInfo;
import ru.betterend.item.ArmoredElytra;
@Mixin(CapeLayer.class)
public class CapeLayerMixin {
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
public void be_checkCustomElytra(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, AbstractClientPlayer abstractClientPlayer, float f, float g, float h, float j, float k, float l, CallbackInfo info) {
ItemStack itemStack = abstractClientPlayer.getItemBySlot(EquipmentSlot.CHEST);
if (itemStack.getItem() instanceof ArmoredElytra) {
info.cancel();
}
}
}

View file

@ -0,0 +1,45 @@
package ru.betterend.mixin.client;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.Input;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ElytraItem;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.betterend.item.ArmoredElytra;
import ru.betterend.registry.EndItems;
import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin extends AbstractClientPlayer {
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
super(clientLevel, gameProfile);
}
@Final
@Shadow
public ClientPacketListener connection;
@Inject(method = "aiStep", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;",
shift = Shift.AFTER))
public void be_aiStep(CallbackInfo info) {
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
if (itemStack.getItem() instanceof ArmoredElytra && ElytraItem.isFlyEnabled(itemStack) && tryToStartFallFlying()) {
connection.send(new ServerboundPlayerCommandPacket(LocalPlayer.class.cast(this), ServerboundPlayerCommandPacket.Action.START_FALL_FLYING));
}
}
}

View file

@ -0,0 +1,25 @@
package ru.betterend.mixin.client;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
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.CallbackInfo;
import ru.betterend.client.render.ArmoredElytraLayer;
@Mixin(PlayerRenderer.class)
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
public PlayerRendererMixin(EntityRenderDispatcher entityRenderDispatcher, PlayerModel<AbstractClientPlayer> entityModel, float f) {
super(entityRenderDispatcher, entityModel, f);
}
@Inject(method = "<init>(Lnet/minecraft/client/renderer/entity/EntityRenderDispatcher;Z)V", at = @At("TAIL"))
public void be_addCustomLayer(EntityRenderDispatcher entityRenderDispatcher, boolean bl, CallbackInfo info) {
addLayer(new ArmoredElytraLayer<>(PlayerRenderer.class.cast(this)));
}
}

View file

@ -2,24 +2,59 @@ package ru.betterend.mixin.common;
import java.util.Collection; import java.util.Collection;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.animal.FlyingAnimal;
import net.minecraft.world.item.ElytraItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import ru.betterend.item.ArmoredElytra;
import ru.betterend.registry.EndItems;
@Mixin(LivingEntity.class) @Mixin(LivingEntity.class)
public abstract class LivingEntityMixin { public abstract class LivingEntityMixin extends Entity {
public LivingEntityMixin(EntityType<?> entityType, Level level) {
super(entityType, level);
}
@Shadow
protected int fallFlyTicks;
@Shadow
public abstract boolean hasEffect(MobEffect mobEffect);
@Shadow
public abstract ItemStack getItemBySlot(EquipmentSlot equipmentSlot);
@Shadow
public abstract void calculateEntityAnimation(LivingEntity livingEntity, boolean b);
@Shadow
protected abstract SoundEvent getFallDamageSound(int i);
@Shadow
public abstract boolean isFallFlying();
private Entity lastAttacker; private Entity lastAttacker;
@Inject(method = "hurt", at = @At("HEAD")) @Inject(method = "hurt", at = @At("HEAD"))
public void be_hurt(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) { public void be_hurt(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) {
this.lastAttacker = source.getEntity(); this.lastAttacker = source.getEntity();
@ -33,7 +68,90 @@ public abstract class LivingEntityMixin {
} }
return value; return value;
} }
@Inject(method = "updateFallFlying", at = @At("HEAD"), cancellable = true)
private void be_updateFallFlying(CallbackInfo info) {
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
if (!level.isClientSide && itemStack.getItem() instanceof ArmoredElytra) {
boolean isFlying = getSharedFlag(7);
if (isFlying && !onGround && !isPassenger() && !hasEffect(MobEffects.LEVITATION)) {
if (ElytraItem.isFlyEnabled(itemStack)) {
if ((fallFlyTicks + 1) % 20 == 0) {
itemStack.hurtAndBreak(1, LivingEntity.class.cast(this), (livingEntity) -> {
livingEntity.broadcastBreakEvent(EquipmentSlot.CHEST);
});
}
isFlying = true;
} else {
isFlying = false;
}
} else {
isFlying = false;
}
setSharedFlag(7, isFlying);
info.cancel();
}
}
@Inject(method = "travel", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/entity/LivingEntity;isFallFlying()Z",
shift = Shift.AFTER), cancellable = true)
public void be_travel(Vec3 vec3, CallbackInfo info) {
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
if (isFallFlying() && itemStack.getItem() instanceof ArmoredElytra) {
Vec3 moveDelta = getDeltaMovement();
if (moveDelta.y > -0.5D) {
fallDistance = 1.0F;
}
Vec3 lookAngle = getLookAngle();
double d = 0.08D;
float rotX = xRot * 0.017453292F;
double k = Math.sqrt(lookAngle.x * lookAngle.x + lookAngle.z * lookAngle.z);
double l = Math.sqrt(getHorizontalDistanceSqr(moveDelta));
double lookLen = lookAngle.length();
float n = Mth.cos(rotX);
n = (float) (n * n * Math.min(1.0D, lookLen / 0.4D));
moveDelta = getDeltaMovement().add(0.0D, d * (-1.0D + (double) n * 0.75D), 0.0D);
double coef;
if (moveDelta.y < 0.0D && k > 0.0D) {
coef = moveDelta.y * -0.1D * (double) n;
moveDelta = moveDelta.add(lookAngle.x * coef / k, coef, lookAngle.z * coef / k);
}
if (rotX < 0.0F && k > 0.0D) {
coef = l * (double) (-Mth.sin(rotX)) * 0.04D;
moveDelta = moveDelta.add(-lookAngle.x * coef / k, coef * 3.2D, -lookAngle.z * coef / k);
}
if (k > 0.0D) {
moveDelta = moveDelta.add((lookAngle.x / k * l - moveDelta.x) * 0.1D, 0.0D, (lookAngle.z / k * l - moveDelta.z) * 0.1D);
}
moveDelta = moveDelta.multiply(0.9900000095367432D, 0.9800000190734863D, 0.9900000095367432D);
double movementFactor = ((ArmoredElytra) itemStack.getItem()).getMovementFactor();
moveDelta = moveDelta.multiply(movementFactor, 1.0D, movementFactor);
setDeltaMovement(moveDelta);
move(MoverType.SELF, moveDelta);
if (!level.isClientSide) {
if (horizontalCollision) {
coef = Math.sqrt(getHorizontalDistanceSqr(moveDelta));
double r = l - coef;
float dmg = (float) (r * 10.0D - 3.0D);
if (dmg > 0.0F) {
playSound(getFallDamageSound((int) dmg), 1.0F, 1.0F);
hurt(DamageSource.FLY_INTO_WALL, dmg);
}
}
if (onGround) {
setSharedFlag(7, false);
}
}
calculateEntityAnimation(LivingEntity.class.cast(this), this instanceof FlyingAnimal);
info.cancel();
}
}
private double be_getKnockback(Item tool) { private double be_getKnockback(Item tool) {
if (tool == null) return 0.0D; if (tool == null) return 0.0D;
Collection<AttributeModifier> modifiers = tool.getDefaultAttributeModifiers(EquipmentSlot.MAINHAND).get(Attributes.ATTACK_KNOCKBACK); Collection<AttributeModifier> modifiers = tool.getDefaultAttributeModifiers(EquipmentSlot.MAINHAND).get(Attributes.ATTACK_KNOCKBACK);

View file

@ -2,7 +2,18 @@ package ru.betterend.mixin.common;
import java.util.Optional; import java.util.Optional;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ElytraItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -15,14 +26,21 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import ru.betterend.blocks.BlockProperties; import ru.betterend.blocks.BlockProperties;
import ru.betterend.blocks.BlockProperties.TripleShape; import ru.betterend.blocks.BlockProperties.TripleShape;
import ru.betterend.item.ArmoredElytra;
import ru.betterend.registry.EndBlocks; import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndItems;
import ru.betterend.util.BlocksHelper; import ru.betterend.util.BlocksHelper;
import ru.betterend.util.MHelper; import ru.betterend.util.MHelper;
@Mixin(Player.class) @Mixin(Player.class)
public abstract class PlayerMixin { public abstract class PlayerMixin extends LivingEntity {
protected PlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
}
private static Direction[] horizontal; private static Direction[] horizontal;
@Inject(method = "findRespawnPositionAndUseSpawnBlock", at = @At(value = "HEAD"), cancellable = true) @Inject(method = "findRespawnPositionAndUseSpawnBlock", at = @At(value = "HEAD"), cancellable = true)
private static void be_findRespawnPositionAndUseSpawnBlock(ServerLevel world, BlockPos pos, float f, boolean bl, boolean bl2, CallbackInfoReturnable<Optional<Vec3>> info) { private static void be_findRespawnPositionAndUseSpawnBlock(ServerLevel world, BlockPos pos, float f, boolean bl, boolean bl2, CallbackInfoReturnable<Optional<Vec3>> info) {
BlockState blockState = world.getBlockState(pos); BlockState blockState = world.getBlockState(pos);
@ -32,6 +50,17 @@ public abstract class PlayerMixin {
} }
} }
@Inject(method = "tryToStartFallFlying", at = @At("HEAD"), cancellable = true)
public void be_tryToStartFlying(CallbackInfoReturnable<Boolean> info) {
if (!onGround && !isFallFlying() && !isInWater() && !hasEffect(MobEffects.LEVITATION)) {
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
if (itemStack.getItem() instanceof ArmoredElytra && ElytraItem.isFlyEnabled(itemStack)) {
setSharedFlag(7, true);
info.setReturnValue(true);
}
}
}
private static Optional<Vec3> be_obeliskRespawnPosition(ServerLevel world, BlockPos pos, BlockState state) { private static Optional<Vec3> be_obeliskRespawnPosition(ServerLevel world, BlockPos pos, BlockState state) {
if (state.getValue(BlockProperties.TRIPLE_SHAPE) == TripleShape.TOP) { if (state.getValue(BlockProperties.TRIPLE_SHAPE) == TripleShape.TOP) {
pos = pos.below(2); pos = pos.below(2);

View file

@ -116,6 +116,10 @@ public class Patterns {
public final static ResourceLocation ITEM_GENERATED = BetterEnd.makeID("patterns/item/pattern_item_generated.json"); public final static ResourceLocation ITEM_GENERATED = BetterEnd.makeID("patterns/item/pattern_item_generated.json");
public final static ResourceLocation ITEM_HANDHELD = BetterEnd.makeID("patterns/item/pattern_item_handheld.json"); public final static ResourceLocation ITEM_HANDHELD = BetterEnd.makeID("patterns/item/pattern_item_handheld.json");
public final static ResourceLocation ITEM_SPAWN_EGG = BetterEnd.makeID("patterns/item/pattern_item_spawn_egg.json"); public final static ResourceLocation ITEM_SPAWN_EGG = BetterEnd.makeID("patterns/item/pattern_item_spawn_egg.json");
public static String createItemGenerated(String name) {
return createJson(ITEM_GENERATED, name);
}
public static String createJson(Reader data, String parent, String block) { public static String createJson(Reader data, String parent, String block) {
try (BufferedReader buffer = new BufferedReader(data)) { try (BufferedReader buffer = new BufferedReader(data)) {

View file

@ -73,15 +73,20 @@ public class SmithingRecipes {
.build(); .build();
SmithingTableRecipe.create("thallasium_anvil_updrade") SmithingTableRecipe.create("thallasium_anvil_updrade")
.setResult(EndBlocks.TERMINITE.anvil) .setResult(EndBlocks.TERMINITE.anvil)
.setBase(EndBlocks.THALLASIUM.anvil) .setBase(EndBlocks.THALLASIUM.anvil)
.setAddition(EndBlocks.TERMINITE.block) .setAddition(EndBlocks.TERMINITE.block)
.build(); .build();
SmithingTableRecipe.create("terminite_anvil_updrade") SmithingTableRecipe.create("terminite_anvil_updrade")
.setResult(EndBlocks.AETERNIUM_ANVIL) .setResult(EndBlocks.AETERNIUM_ANVIL)
.setBase(EndBlocks.TERMINITE.anvil) .setBase(EndBlocks.TERMINITE.anvil)
.setAddition(EndBlocks.AETERNIUM_BLOCK) .setAddition(EndBlocks.AETERNIUM_BLOCK)
.build(); .build();
SmithingTableRecipe.create("armored_elytra")
.setResult(EndItems.ARMORED_ELYTRA)
.setBase(Items.ELYTRA)
.setAddition(EndItems.AETERNIUM_INGOT)
.build();
} }
} }

View file

@ -4,6 +4,7 @@ import java.util.List;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.core.BlockSource; import net.minecraft.core.BlockSource;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -19,28 +20,13 @@ import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.food.FoodProperties; import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.food.Foods; import net.minecraft.world.food.Foods;
import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.*;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Item.Properties; import net.minecraft.world.item.Item.Properties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.ShovelItem;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.TieredItem;
import net.minecraft.world.item.Tiers;
import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.block.DispenserBlock;
import ru.betterend.BetterEnd; import ru.betterend.BetterEnd;
import ru.betterend.config.Configs; import ru.betterend.config.Configs;
import ru.betterend.item.DrinkItem; import ru.betterend.interfaces.BreakableItem;
import ru.betterend.item.EnchantedPetalItem; import ru.betterend.item.*;
import ru.betterend.item.EndArmorItem;
import ru.betterend.item.EndBucketItem;
import ru.betterend.item.EndSpawnEggItem;
import ru.betterend.item.EternalCrystalItem;
import ru.betterend.item.PatternedDiscItem;
import ru.betterend.item.PatternedItem;
import ru.betterend.item.material.EndArmorMaterial; import ru.betterend.item.material.EndArmorMaterial;
import ru.betterend.item.material.EndToolMaterial; import ru.betterend.item.material.EndToolMaterial;
import ru.betterend.item.tool.EndAxeItem; import ru.betterend.item.tool.EndAxeItem;
@ -89,7 +75,8 @@ public class EndItems {
public static final Item CRYSTALITE_CHESTPLATE = registerItem("crystalite_chestplate", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.CHEST, makeItemSettings().rarity(Rarity.UNCOMMON))); public static final Item CRYSTALITE_CHESTPLATE = registerItem("crystalite_chestplate", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.CHEST, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item CRYSTALITE_LEGGINGS = registerItem("crystalite_leggings", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.LEGS, makeItemSettings().rarity(Rarity.UNCOMMON))); public static final Item CRYSTALITE_LEGGINGS = registerItem("crystalite_leggings", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.LEGS, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item CRYSTALITE_BOOTS = registerItem("crystalite_boots", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.FEET, makeItemSettings().rarity(Rarity.UNCOMMON))); public static final Item CRYSTALITE_BOOTS = registerItem("crystalite_boots", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.FEET, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item ARMORED_ELYTRA = registerItem("elytra_armored", new ArmoredElytra("elytra_armored", AETERNIUM_INGOT, 700, 0.96D, true));
// Tools // // Tools //
public static final TieredItem AETERNIUM_SHOVEL = registerTool("aeternium_shovel", new EndShovelItem(EndToolMaterial.AETERNIUM, 1.5F, -3.0F, makeItemSettings().fireResistant())); public static final TieredItem AETERNIUM_SHOVEL = registerTool("aeternium_shovel", new EndShovelItem(EndToolMaterial.AETERNIUM, 1.5F, -3.0F, makeItemSettings().fireResistant()));
public static final TieredItem AETERNIUM_SWORD = registerTool("aeternium_sword", new EndSwordItem(EndToolMaterial.AETERNIUM, 3, -2.4F, makeItemSettings().fireResistant())); public static final TieredItem AETERNIUM_SWORD = registerTool("aeternium_sword", new EndSwordItem(EndToolMaterial.AETERNIUM, 3, -2.4F, makeItemSettings().fireResistant()));
@ -152,6 +139,9 @@ public class EndItems {
return item; return item;
} }
registerItem(id, item, MOD_ITEMS); registerItem(id, item, MOD_ITEMS);
if (item instanceof BreakableItem) {
((BreakableItem) item).registerBrokenItem();
}
return item; return item;
} }
@ -193,7 +183,7 @@ public class EndItems {
} else if (item instanceof EndHoeItem) { } else if (item instanceof EndHoeItem) {
TagHelper.addTag((Tag.Named<Item>) FabricToolTags.HOES, item); TagHelper.addTag((Tag.Named<Item>) FabricToolTags.HOES, item);
} else if (item instanceof EndHammerItem) { } else if (item instanceof EndHammerItem) {
TagHelper.addTag((Tag.Named<Item>) EndTags.HAMMERS, item); TagHelper.addTag(EndTags.HAMMERS, item);
} }
return item; return item;

View file

@ -75,6 +75,7 @@
"item.betterend.aeternium_sword_handle": "Aeternium Sword Handle", "item.betterend.aeternium_sword_handle": "Aeternium Sword Handle",
"item.betterend.leather_stripe": "Leather Stripe", "item.betterend.leather_stripe": "Leather Stripe",
"item.betterend.leather_wrapped_stick": "Leather Wrapped Stick", "item.betterend.leather_wrapped_stick": "Leather Wrapped Stick",
"item.betterend.elytra_armored": "Armored Elytra",
"effect.betterend.end_veil": "End Veil", "effect.betterend.end_veil": "End Veil",
"enchantment.betterend.end_veil": "End Veil", "enchantment.betterend.end_veil": "End Veil",

View file

@ -75,6 +75,7 @@
"item.betterend.aeternium_sword_handle": "Рукоятка этериевого меча", "item.betterend.aeternium_sword_handle": "Рукоятка этериевого меча",
"item.betterend.leather_stripe": "Полоска кожи", "item.betterend.leather_stripe": "Полоска кожи",
"item.betterend.leather_wrapped_stick": "Обернутая кожей палка", "item.betterend.leather_wrapped_stick": "Обернутая кожей палка",
"item.betterend.elytra_armored": "Армированная Элитра",
"effect.betterend.end_veil": "Вуаль Края", "effect.betterend.end_veil": "Вуаль Края",
"enchantment.betterend.end_veil": "Вуаль Края", "enchantment.betterend.end_veil": "Вуаль Края",

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

View file

@ -13,11 +13,14 @@
"ModelVariantMapMixin", "ModelVariantMapMixin",
"MinecraftClientMixin", "MinecraftClientMixin",
"ContextGsonAccessor", "ContextGsonAccessor",
"PlayerRendererMixin",
"WorldRendererMixin", "WorldRendererMixin",
"MusicTrackerMixin", "MusicTrackerMixin",
"AnvilScreenMixin", "AnvilScreenMixin",
"BiomeColorsMixin", "BiomeColorsMixin",
"ModelLoaderMixin" "ModelLoaderMixin",
"LocalPlayerMixin",
"CapeLayerMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1