A patch of peppers

- Netherite diving boots now improve movement abilities in lava
- Lava diving now consumes air from the netherite backtank
- Fixed netherite backtank armor not showing in first person view
This commit is contained in:
simibubi 2023-04-23 00:33:09 +02:00
parent a673734c71
commit 8de06ce5c5
11 changed files with 216 additions and 45 deletions

View file

@ -248,30 +248,50 @@ public class AllItems {
public static final ItemEntry<? extends BacktankItem>
COPPER_BACKTANK = REGISTRATE.item("copper_backtank", p -> new BacktankItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving"), COPPER_BACKTANK_PLACEABLE))
COPPER_BACKTANK =
REGISTRATE
.item("copper_backtank",
p -> new BacktankItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving"),
COPPER_BACKTANK_PLACEABLE))
.model(AssetLookup.customGenericItemModel("_", "item"))
.tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag)
.register(),
NETHERITE_BACKTANK = REGISTRATE.item("netherite_backtank", p -> new BacktankItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"), NETHERITE_BACKTANK_PLACEABLE))
NETHERITE_BACKTANK = REGISTRATE
.item("netherite_backtank",
p -> new BacktankItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"),
NETHERITE_BACKTANK_PLACEABLE))
.model(AssetLookup.customGenericItemModel("_", "item"))
.properties(p -> p.fireResistant())
.tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag)
.register();
public static final ItemEntry<? extends DivingHelmetItem>
COPPER_DIVING_HELMET = REGISTRATE.item("copper_diving_helmet", p -> new DivingHelmetItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
COPPER_DIVING_HELMET =
REGISTRATE
.item("copper_diving_helmet",
p -> new DivingHelmetItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
.register(),
NETHERITE_DIVING_HELMET = REGISTRATE.item("netherite_diving_helmet", p -> new DivingHelmetItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
NETHERITE_DIVING_HELMET = REGISTRATE
.item("netherite_diving_helmet",
p -> new DivingHelmetItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
.properties(p -> p.fireResistant())
.register();
public static final ItemEntry<? extends DivingBootsItem>
COPPER_DIVING_BOOTS = REGISTRATE.item("copper_diving_boots", p -> new DivingBootsItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
COPPER_DIVING_BOOTS =
REGISTRATE
.item("copper_diving_boots",
p -> new DivingBootsItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
.register(),
NETHERITE_DIVING_BOOTS = REGISTRATE.item("netherite_diving_boots", p -> new DivingBootsItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
NETHERITE_DIVING_BOOTS = REGISTRATE
.item("netherite_diving_boots",
p -> new DivingBootsItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
.properties(p -> p.fireResistant())
.register();
public static final ItemEntry<SandPaperItem> SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new)

View file

@ -1,5 +1,7 @@
package com.simibubi.create.content.curiosities.armor;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.resources.ResourceLocation;
@ -9,6 +11,7 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -23,10 +26,19 @@ public class DivingBootsItem extends BaseArmorItem {
}
public static boolean isWornBy(Entity entity) {
if (!(entity instanceof LivingEntity livingEntity)) {
ItemStack stack = getWornItem(entity);
if (stack == null) {
return false;
}
return livingEntity.getItemBySlot(SLOT).getItem() instanceof DivingBootsItem;
return stack.getItem() instanceof DivingBootsItem;
}
@Nullable
public static ItemStack getWornItem(Entity entity) {
if (!(entity instanceof LivingEntity livingEntity)) {
return null;
}
return livingEntity.getItemBySlot(SLOT);
}
@SubscribeEvent
@ -72,4 +84,28 @@ public class DivingBootsItem extends BaseArmorItem {
}
return true;
}
public static Vec3 getMovementMultiplier(Entity entity) {
double yMotion = entity.getDeltaMovement().y;
double vMultiplier = yMotion < 0 ? Math.max(0, 2.5 - Math.abs(yMotion) * 2) : 1;
if (!entity.isOnGround()) {
if (entity instanceof LivingEntity le && le.jumping && entity.getPersistentData()
.contains("LavaGrounded")) {
vMultiplier = yMotion == 0 ? 0 : 1 / yMotion;
} else if (yMotion > 0)
vMultiplier = 1.3;
entity.getPersistentData()
.remove("LavaGrounded");
return new Vec3(1.75, vMultiplier, 1.75);
}
if (entity instanceof LivingEntity)
entity.getPersistentData()
.putBoolean("LavaGrounded", true);
double hMultiplier = entity.isSprinting() ? 1.85 : 1.75;
return new Vec3(hMultiplier, vMultiplier, hMultiplier);
}
}

View file

@ -28,11 +28,13 @@ public class DivingHelmetItem extends BaseArmorItem {
super(material, SLOT, properties, textureLoc);
}
public static boolean isWornBy(Entity entity) {
public static boolean isWornBy(Entity entity, boolean fireproof) {
ItemStack stack = getWornItem(entity);
if (stack == null) {
if (stack == null)
return false;
if (!stack.getItem()
.isFireResistant() && fireproof)
return false;
}
return stack.getItem() instanceof DivingHelmetItem;
}
@ -55,10 +57,9 @@ public class DivingHelmetItem extends BaseArmorItem {
entity.getPersistentData()
.remove("VisualBacktankAir");
if (!isWornBy(entity))
return;
boolean lavaDiving = entity.isEyeInFluid(FluidTags.LAVA);
if (!isWornBy(entity, lavaDiving))
return;
if (!entity.isEyeInFluid(FluidTags.WATER) && !lavaDiving)
return;
if (entity instanceof Player && ((Player) entity).isCreative())
@ -73,7 +74,9 @@ public class DivingHelmetItem extends BaseArmorItem {
if (lavaDiving) {
if (entity instanceof ServerPlayer sp)
AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp);
return;
if (!backtank.getItem()
.isFireResistant())
return;
}
if (drowning)
@ -85,12 +88,16 @@ public class DivingHelmetItem extends BaseArmorItem {
if (!second)
return;
BacktankUtil.consumeAir(entity, backtank, 1);
if (lavaDiving)
return;
if (entity instanceof ServerPlayer sp)
AllAdvancements.DIVING_SUIT.awardTo(sp);
entity.setAirSupply(Math.min(entity.getMaxAirSupply(), entity.getAirSupply() + 10));
entity.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 30, 0, true, false, true));
BacktankUtil.consumeAir(entity, backtank, 1);
}
}

View file

@ -0,0 +1,63 @@
package com.simibubi.create.content.curiosities.armor;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderArmEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber(value = Dist.CLIENT)
public class NetheriteBacktankFirstPersonRenderer {
private static final ResourceLocation BACKTANK_ARMOR_LOCATION =
Create.asResource("textures/models/armor/netherite_diving_arm.png");
private static boolean rendererActive = false;
public static void clientTick() {
Minecraft mc = Minecraft.getInstance();
rendererActive =
mc.player != null && AllItems.NETHERITE_BACKTANK.isIn(mc.player.getItemBySlot(EquipmentSlot.CHEST));
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public static void onRenderPlayerHand(RenderArmEvent event) {
if (!rendererActive)
return;
Minecraft mc = Minecraft.getInstance();
LocalPlayer player = mc.player;
MultiBufferSource buffer = event.getMultiBufferSource();
if (!(mc.getEntityRenderDispatcher()
.getRenderer(player) instanceof PlayerRenderer pr))
return;
PlayerModel<AbstractClientPlayer> model = pr.getModel();
model.attackTime = 0.0F;
model.crouching = false;
model.swimAmount = 0.0F;
model.setupAnim(player, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F);
ModelPart armPart = event.getArm() == HumanoidArm.LEFT ? model.leftSleeve : model.rightSleeve;
armPart.xRot = 0.0F;
armPart.render(event.getPoseStack(), buffer.getBuffer(RenderType.entitySolid(BACKTANK_ARMOR_LOCATION)),
LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY);
event.setCanceled(true);
}
}

View file

@ -38,35 +38,33 @@ public final class NetheriteDivingHandler {
if (slot == EquipmentSlot.HEAD) {
if (AllItems.NETHERITE_DIVING_HELMET.isIn(to)) {
setBit(entity, 0);
setBit(entity, slot);
} else {
clearBit(entity, 0);
clearBit(entity, slot);
}
} else if (slot == EquipmentSlot.CHEST) {
if (AllItems.NETHERITE_BACKTANK.isIn(to)) {
setBit(entity, 1);
if (AllItems.NETHERITE_BACKTANK.isIn(to) && BacktankUtil.hasAirRemaining(to)) {
setBit(entity, slot);
} else {
clearBit(entity, 1);
clearBit(entity, slot);
}
} else if (slot == EquipmentSlot.LEGS) {
if (to.getItem() instanceof ArmorItem armorItem && armorItem.getMaterial() == ArmorMaterials.NETHERITE) {
setBit(entity, 2);
} else if (slot == EquipmentSlot.LEGS || slot == EquipmentSlot.FEET) {
if (isNetheriteArmor(to)) {
setBit(entity, slot);
} else {
clearBit(entity, 2);
}
} else if (slot == EquipmentSlot.FEET) {
if (to.getItem() instanceof ArmorItem armorItem && armorItem.getMaterial() == ArmorMaterials.NETHERITE) {
setBit(entity, 3);
} else {
clearBit(entity, 3);
clearBit(entity, slot);
}
}
}
public static void setBit(LivingEntity entity, int i) {
public static boolean isNetheriteArmor(ItemStack stack) {
return stack.getItem() instanceof ArmorItem armorItem && armorItem.getMaterial() == ArmorMaterials.NETHERITE;
}
public static void setBit(LivingEntity entity, EquipmentSlot slot) {
CompoundTag nbt = entity.getPersistentData();
byte bits = nbt.getByte(NETHERITE_DIVING_BITS_KEY);
bits |= 1 << i;
bits |= 1 << slot.getIndex();
nbt.putByte(NETHERITE_DIVING_BITS_KEY, bits);
if ((bits & 0xF) == 0xF) {
@ -74,7 +72,7 @@ public final class NetheriteDivingHandler {
}
}
public static void clearBit(LivingEntity entity, int i) {
public static void clearBit(LivingEntity entity, EquipmentSlot slot) {
CompoundTag nbt = entity.getPersistentData();
if (!nbt.contains(NETHERITE_DIVING_BITS_KEY)) {
return;
@ -82,7 +80,7 @@ public final class NetheriteDivingHandler {
byte bits = nbt.getByte(NETHERITE_DIVING_BITS_KEY);
boolean prevFullSet = (bits & 0xF) == 0xF;
bits &= ~(1 << i);
bits &= ~(1 << slot.getIndex());
nbt.putByte(NETHERITE_DIVING_BITS_KEY, bits);
if (prevFullSet) {

View file

@ -33,7 +33,7 @@ public class RemainingAirOverlay implements IIngameOverlay {
if (!player.getPersistentData()
.contains("VisualBacktankAir"))
return;
if (!player.isEyeInFluid(FluidTags.WATER))
if (!player.isEyeInFluid(FluidTags.WATER) && !player.isEyeInFluid(FluidTags.LAVA))
return;
int timeLeft = player.getPersistentData()
@ -41,10 +41,12 @@ public class RemainingAirOverlay implements IIngameOverlay {
poseStack.pushPose();
poseStack.translate(width / 2 + 90, height - 53, 0);
ItemStack backtank = getDisplayedBacktank(player);
poseStack.translate(width / 2 + 90, height - 53 + (backtank.getItem()
.isFireResistant() ? 9 : 0), 0);
Component text = Components.literal(StringUtil.formatTickDuration(timeLeft * 20));
GuiGameElement.of(getDisplayedBacktank(player))
Component text = Components.literal(StringUtil.formatTickDuration(Math.max(0, timeLeft - 1) * 20));
GuiGameElement.of(backtank)
.at(0, 0)
.render(poseStack);
int color = 0xFF_FFFFFF;

View file

@ -22,6 +22,7 @@ import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRe
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
import com.simibubi.create.content.curiosities.armor.BacktankArmorLayer;
import com.simibubi.create.content.curiosities.armor.DivingHelmetItem;
import com.simibubi.create.content.curiosities.armor.NetheriteBacktankFirstPersonRenderer;
import com.simibubi.create.content.curiosities.clipboard.ClipboardValueSettingsHandler;
import com.simibubi.create.content.curiosities.girder.GirderWrenchBehavior;
import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient;
@ -67,6 +68,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@ -163,6 +165,7 @@ public class ClientEvents {
ClipboardValueSettingsHandler.clientTick();
CreateClient.VALUE_SETTINGS_HANDLER.tick();
ScrollValueHandler.tick();
NetheriteBacktankFirstPersonRenderer.clientTick();
}
@SubscribeEvent
@ -283,14 +286,15 @@ public class ClientEvents {
@SubscribeEvent
public static void getFogDensity(EntityViewRenderEvent.RenderFogEvent event) {
Camera info = event.getCamera();
Camera camera = event.getCamera();
Level level = Minecraft.getInstance().level;
BlockPos blockPos = info.getBlockPosition();
BlockPos blockPos = camera.getBlockPosition();
FluidState fluidState = level.getFluidState(blockPos);
if (info.getPosition().y > blockPos.getY() + fluidState.getHeight(level, blockPos))
if (camera.getPosition().y >= blockPos.getY() + fluidState.getHeight(level, blockPos))
return;
Fluid fluid = fluidState.getType();
Entity entity = camera.getEntity();
if (AllFluids.CHOCOLATE.get()
.isSame(fluid)) {
@ -306,12 +310,20 @@ public class ClientEvents {
return;
}
ItemStack divingHelmet = DivingHelmetItem.getWornItem(Minecraft.getInstance().cameraEntity);
if (entity.isSpectator())
return;
ItemStack divingHelmet = DivingHelmetItem.getWornItem(entity);
if (divingHelmet != null) {
if (FluidHelper.isWater(fluid) || FluidHelper.isLava(fluid) && AllItems.NETHERITE_DIVING_HELMET.isIn(divingHelmet)) {
if (FluidHelper.isWater(fluid)) {
event.scaleFarPlaneDistance(6.25f);
event.setCanceled(true);
return;
} else if (FluidHelper.isLava(fluid) && AllItems.NETHERITE_DIVING_HELMET.isIn(divingHelmet)) {
event.setNearPlaneDistance(-4.0f);
event.setFarPlaneDistance(20.0f);
event.setCanceled(true);
return;
}
}
}

View file

@ -22,7 +22,7 @@ public abstract class HeavyBootsOnPlayerMixin extends AbstractClientPlayer {
super(level, profile);
}
@Inject(at = @At("HEAD"), method = "isUnderWater", cancellable = true)
@Inject(method = "isUnderWater()Z", at = @At("HEAD"), cancellable = true)
public void noSwimmingWithHeavyBootsOn(CallbackInfoReturnable<Boolean> cir) {
CompoundTag persistentData = getPersistentData();
if (persistentData.contains("HeavyBoots"))

View file

@ -0,0 +1,32 @@
package com.simibubi.create.foundation.mixin;
import org.spongepowered.asm.mixin.Mixin;
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.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.curiosities.armor.DivingBootsItem;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
@Mixin(LivingEntity.class)
public abstract class LavaSwimmingMixin extends Entity {
public LavaSwimmingMixin(EntityType<?> type, Level level) {
super(type, level);
}
@Inject(method = "travel(Lnet/minecraft/world/phys/Vec3;)V", slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isInLava()Z")), at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;move(Lnet/minecraft/world/entity/MoverType;Lnet/minecraft/world/phys/Vec3;)V", shift = Shift.AFTER, ordinal = 0))
private void onLavaTravel(Vec3 travelVector, CallbackInfo ci) {
ItemStack bootsStack = DivingBootsItem.getWornItem(this);
if (bootsStack != null && AllItems.NETHERITE_DIVING_BOOTS.isIn(bootsStack))
setDeltaMovement(getDeltaMovement().multiply(DivingBootsItem.getMovementMultiplier(this)));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

View file

@ -12,6 +12,7 @@
"EnchantmentHelperMixin",
"EnchantmentMixin",
"EntityMixin",
"LavaSwimmingMixin",
"MapItemSavedDataMixin",
"accessor.AbstractProjectileDispenseBehaviorAccessor",
"accessor.DispenserBlockAccessor",