Move and rename Air Source interface and backtank implementation, move static functions related to the backtank item.

This commit is contained in:
Lgmrszd 2023-07-10 21:51:47 +03:00
parent 68ba30e122
commit 826669eb71
No known key found for this signature in database
GPG key ID: D8E0CC2BFF5D4D9B
8 changed files with 207 additions and 160 deletions

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.equipment.armor.backtank_utils.BacktankAirSource;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.blockEntity.ComparatorUtil;
@ -80,7 +81,7 @@ public class BacktankBlockEntity extends KineticBlockEntity implements Nameable
return;
}
int max = BacktankUtil.maxAir(capacityEnchantLevel);
int max = BacktankAirSource.maxAir(capacityEnchantLevel);
if (level.isClientSide) {
Vec3 centerOf = VecHelper.getCenterOf(worldPosition);
Vec3 v = VecHelper.offsetRandomly(centerOf, level.random, .65f);
@ -105,7 +106,7 @@ public class BacktankBlockEntity extends KineticBlockEntity implements Nameable
}
public int getComparatorOutput() {
int max = BacktankUtil.maxAir(capacityEnchantLevel);
int max = BacktankAirSource.maxAir(capacityEnchantLevel);
return ComparatorUtil.fractionToRedstoneLevel(airLevel / (float) max);
}
@ -130,7 +131,7 @@ public class BacktankBlockEntity extends KineticBlockEntity implements Nameable
enchantmentTag = compound.getList("Enchantments", Tag.TAG_COMPOUND);
if (compound.contains("CustomName", 8))
this.customName = Component.Serializer.fromJson(compound.getString("CustomName"));
if (prev != 0 && prev != airLevel && airLevel == BacktankUtil.maxAir(capacityEnchantLevel) && clientPacket)
if (prev != 0 && prev != airLevel && airLevel == BacktankAirSource.maxAir(capacityEnchantLevel) && clientPacket)
playFilledEffect();
}

View file

@ -3,6 +3,8 @@ package com.simibubi.create.content.equipment.armor;
import java.util.Locale;
import java.util.function.Supplier;
import com.simibubi.create.content.equipment.armor.backtank_utils.BacktankAirSource;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.content.equipment.armor.CapacityEnchantment.ICapacityEnchantable;
@ -27,7 +29,7 @@ import net.minecraft.world.level.block.Block;
public class BacktankItem extends BaseArmorItem implements ICapacityEnchantable {
public static final EquipmentSlot SLOT = EquipmentSlot.CHEST;
public static final int BAR_COLOR = 0xEFEFEF;
private final Supplier<BacktankBlockItem> blockItem;
public BacktankItem(ArmorMaterial material, Properties properties, ResourceLocation textureLoc, Supplier<BacktankBlockItem> placeable) {
@ -69,7 +71,7 @@ public class BacktankItem extends BaseArmorItem implements ICapacityEnchantable
ItemStack stack = new ItemStack(this);
CompoundTag nbt = new CompoundTag();
nbt.putInt("Air", BacktankUtil.maxAirWithoutEnchants());
nbt.putInt("Air", BacktankAirSource.maxAirWithoutEnchants());
stack.setTag(nbt);
items.add(stack);
}
@ -81,7 +83,7 @@ public class BacktankItem extends BaseArmorItem implements ICapacityEnchantable
@Override
public int getBarWidth(ItemStack stack) {
return Math.round(13.0F * Mth.clamp(getRemainingAir(stack) / ((float) BacktankUtil.maxAir(stack)), 0, 1));
return Math.round(13.0F * Mth.clamp(getRemainingAir(stack) / ((float) BacktankAirSource.maxAir(stack)), 0, 1));
}
@Override

View file

@ -5,32 +5,21 @@ import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.simibubi.create.AllEnchantments;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.AllTags;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.infrastructure.config.AllConfigs;
import com.simibubi.create.content.equipment.armor.backtank_utils.BacktankAirSource;
import com.simibubi.create.content.equipment.armor.backtank_utils.IAirSource;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
public class BacktankUtil {
private static final List<Function<LivingEntity, List<BacktankWrapper>>> BACKTANK_SUPPLIERS = new ArrayList<>();
private static final List<Function<LivingEntity, List<IAirSource>>> BACKTANK_SUPPLIERS = new ArrayList<>();
static {
addBacktankSupplier(entity -> {
@ -43,13 +32,19 @@ public class BacktankUtil {
});
}
public static List<BacktankWrapper> getAllWithAir(LivingEntity entity) {
List<BacktankWrapper> all = new ArrayList<>();
/**
* Get all Air Sources from the entity that have some air.
* Will return empty list if all Air Sources (i.e. Backtanks) are empty.
* @param entity player or other entity to check
* @return list of Air Sources
*/
public static List<IAirSource> getAllWithAir(LivingEntity entity) {
List<IAirSource> all = new ArrayList<>();
for (Function<LivingEntity, List<BacktankWrapper>> supplier : BACKTANK_SUPPLIERS) {
List<BacktankWrapper> result = supplier.apply(entity);
for (Function<LivingEntity, List<IAirSource>> supplier : BACKTANK_SUPPLIERS) {
List<IAirSource> result = supplier.apply(entity);
for (BacktankWrapper stack : result)
for (IAirSource stack : result)
if (stack.hasAirRemaining())
all.add(stack);
}
@ -60,75 +55,22 @@ public class BacktankUtil {
return all;
}
// BackTank-specific functions - could be moved to DefaultBacktankWrapper
public static boolean hasAirRemaining(ItemStack backtank) {
return getAir(backtank) > 0;
}
public static float getAir(ItemStack backtank) {
CompoundTag tag = backtank.getOrCreateTag();
return Math.min(tag.getFloat("Air"), maxAir(backtank));
}
public static void consumeAir(LivingEntity entity, ItemStack backtank, float i) {
CompoundTag tag = backtank.getOrCreateTag();
int maxAir = maxAir(backtank);
float air = getAir(backtank);
float newAir = Math.max(air - i, 0);
tag.putFloat("Air", Math.min(newAir, maxAir));
backtank.setTag(tag);
if (!(entity instanceof ServerPlayer player))
return;
sendWarning(player, air, newAir, maxAir / 10f);
sendWarning(player, air, newAir, 1);
}
private static void sendWarning(ServerPlayer player, float air, float newAir, float threshold) {
if (newAir > threshold)
return;
if (air <= threshold)
return;
boolean depleted = threshold == 1;
MutableComponent component = Lang.translateDirect(depleted ? "backtank.depleted" : "backtank.low");
AllSoundEvents.DENY.play(player.level, null, player.blockPosition(), 1, 1.25f);
AllSoundEvents.STEAM.play(player.level, null, player.blockPosition(), .5f, .5f);
player.connection.send(new ClientboundSetTitlesAnimationPacket(10, 40, 10));
player.connection.send(new ClientboundSetSubtitleTextPacket(
Components.literal("\u26A0 ").withStyle(depleted ? ChatFormatting.RED : ChatFormatting.GOLD)
.append(component.withStyle(ChatFormatting.GRAY))));
player.connection.send(new ClientboundSetTitleTextPacket(Components.immutableEmpty()));
}
public static int maxAir(ItemStack backtank) {
return maxAir(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), backtank));
}
public static int maxAir(int enchantLevel) {
return AllConfigs.server().equipment.airInBacktank.get()
+ AllConfigs.server().equipment.enchantedBacktankCapacity.get() * enchantLevel;
}
public static int maxAirWithoutEnchants() {
return AllConfigs.server().equipment.airInBacktank.get();
}
// BackTank-agnostic functions
/**
* Try to use air from any Air Source available.
* @param entity player or other entity to check
* @param usesPerTank how many uses does the tool have per non-enchanted Copper Backtank (used to calculate cost)
* @return if air was consumed
*/
public static boolean canAbsorbDamage(LivingEntity entity, int usesPerTank) {
if (usesPerTank == 0)
return true;
if (entity instanceof Player && ((Player) entity).isCreative())
return true;
List<BacktankWrapper> backtanks = getAllWithAir(entity);
List<IAirSource> backtanks = getAllWithAir(entity);
if (backtanks.isEmpty())
return false;
float cost = ((float) maxAirWithoutEnchants()) / usesPerTank;
float cost = ((float) BacktankAirSource.maxAirWithoutEnchants()) / usesPerTank;
backtanks.get(0).consumeAir(entity, cost);
return true;
}
@ -141,7 +83,7 @@ public class BacktankUtil {
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
if (player == null)
return false;
List<BacktankWrapper> backtanks = getAllWithAir(player);
List<IAirSource> backtanks = getAllWithAir(player);
if (backtanks.isEmpty())
return stack.isDamaged();
return true;
@ -154,7 +96,7 @@ public class BacktankUtil {
if (player == null)
return 13;
List<BacktankWrapper> backtanks = getAllWithAir(player);
List<IAirSource> backtanks = getAllWithAir(player);
if (backtanks.isEmpty())
return Math.round(13.0F - (float) stack.getDamageValue() / stack.getMaxDamage() * 13.0F);
@ -164,7 +106,7 @@ public class BacktankUtil {
// If there is more than one backtank, average the bar widths.
int sumBarWidth = backtanks.stream()
.map(BacktankWrapper::getBarWidth)
.map(IAirSource::getBarWidth)
.reduce(0, Integer::sum);
return Math.round((float) sumBarWidth / backtanks.size());
@ -176,7 +118,7 @@ public class BacktankUtil {
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
if (player == null)
return 0;
List<BacktankWrapper> backtanks = getAllWithAir(player);
List<IAirSource> backtanks = getAllWithAir(player);
// Fallback colour
if (backtanks.isEmpty())
@ -193,73 +135,15 @@ public class BacktankUtil {
*/
public static void addBacktankSupplier(Function<LivingEntity, List<ItemStack>> supplier) {
BACKTANK_SUPPLIERS.add(entity ->
supplier.apply(entity).stream().map(DefaultBacktankWrapper::new).collect(Collectors.toList())
supplier.apply(entity).stream().map(BacktankAirSource::new).collect(Collectors.toList())
);
}
public static void addBacktankWrapperSupplier(Function<LivingEntity, List<BacktankWrapper>> supplier) {
/**
* Use this method to add entry points to custom, non-backtank air sources.
*/
public static void addBacktankWrapperSupplier(Function<LivingEntity, List<IAirSource>> supplier) {
BACKTANK_SUPPLIERS.add(supplier);
}
public interface BacktankWrapper {
float getAir();
int maxAir();
void consumeAir(LivingEntity entity, float i);
boolean hasAirRemaining();
int getBarWidth();
int getBarColor();
boolean isFireResistant();
ItemStack getDisplayedBacktank();
}
public static class DefaultBacktankWrapper implements BacktankWrapper {
private final ItemStack backtankStack;
public DefaultBacktankWrapper(ItemStack backtankStack) {
this.backtankStack = backtankStack;
}
@Override
public float getAir() {
return BacktankUtil.getAir(backtankStack);
}
public int maxAir() {
return BacktankUtil.maxAir(backtankStack);
}
@Override
public void consumeAir(LivingEntity entity, float i) {
BacktankUtil.consumeAir(entity, backtankStack, i);
}
@Override
public boolean hasAirRemaining() {
return BacktankUtil.hasAirRemaining(backtankStack);
}
@Override
public int getBarWidth() {
return backtankStack.getBarWidth();
}
@Override
public int getBarColor() {
return backtankStack.getBarColor();
}
@Override
public boolean isFireResistant() {
return backtankStack.getItem().isFireResistant();
}
@Override
public ItemStack getDisplayedBacktank() {
return backtankStack;
}
}
}

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.equipment.armor;
import com.simibubi.create.content.equipment.armor.backtank_utils.IAirSource;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import net.minecraft.resources.ResourceLocation;
@ -77,7 +78,7 @@ public class DivingHelmetItem extends BaseArmorItem {
if (entity instanceof Player && ((Player) entity).isCreative())
return;
List<BacktankUtil.BacktankWrapper> backtanks = BacktankUtil.getAllWithAir(entity);
List<IAirSource> backtanks = BacktankUtil.getAllWithAir(entity);
if (backtanks.isEmpty())
return;
@ -85,7 +86,7 @@ public class DivingHelmetItem extends BaseArmorItem {
if (entity instanceof ServerPlayer sp)
AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp);
if (backtanks.stream()
.noneMatch(backtank -> backtank.isFireResistant()))
.noneMatch(IAirSource::isFireResistant))
return;
}
@ -95,13 +96,12 @@ public class DivingHelmetItem extends BaseArmorItem {
if (world.isClientSide)
entity.getPersistentData()
.putInt("VisualBacktankAir", Math.round(backtanks.stream()
.map(BacktankUtil.BacktankWrapper::getAir)
.map(IAirSource::getAir)
.reduce(0f, Float::sum)));
if (!second)
return;
// BacktankUtil.consumeAir(entity, backtanks.get(0), 1);
backtanks.get(0).consumeAir(entity, 1);
if (lavaDiving)

View file

@ -2,6 +2,8 @@ package com.simibubi.create.content.equipment.armor;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.equipment.armor.backtank_utils.BacktankAirSource;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
@ -34,7 +36,7 @@ public final class NetheriteDivingHandler {
clearBit(entity, slot);
}
} else if (slot == EquipmentSlot.CHEST) {
if (AllItems.NETHERITE_BACKTANK.isIn(to) && BacktankUtil.hasAirRemaining(to)) {
if (AllItems.NETHERITE_BACKTANK.isIn(to) && BacktankAirSource.hasAirRemaining(to)) {
setBit(entity, slot);
} else {
clearBit(entity, slot);

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.equipment.armor;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.equipment.armor.backtank_utils.IAirSource;
import com.simibubi.create.foundation.gui.element.GuiGameElement;
import com.simibubi.create.foundation.utility.Color;
import com.simibubi.create.foundation.utility.Components;
@ -61,7 +62,7 @@ public class RemainingAirOverlay implements IIngameOverlay {
}
public static ItemStack getDisplayedBacktank(LocalPlayer player) {
List<BacktankUtil.BacktankWrapper> backtanks = BacktankUtil.getAllWithAir(player);
List<IAirSource> backtanks = BacktankUtil.getAllWithAir(player);
if (!backtanks.isEmpty()) {
return backtanks.get(0).getDisplayedBacktank();
}

View file

@ -0,0 +1,127 @@
package com.simibubi.create.content.equipment.armor.backtank_utils;
import com.simibubi.create.AllEnchantments;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
public class BacktankAirSource implements IAirSource {
private final ItemStack backtankStack;
public BacktankAirSource(ItemStack backtankStack) {
this.backtankStack = backtankStack;
}
@Override
public float getAir() {
return getAir(backtankStack);
}
// public int maxAir() {
// return maxAir(backtankStack);
// }
@Override
public void consumeAir(LivingEntity entity, float i) {
consumeAir(entity, backtankStack, i);
}
@Override
public boolean hasAirRemaining() {
return hasAirRemaining(backtankStack);
}
@Override
public int getBarWidth() {
return backtankStack.getBarWidth();
}
@Override
public int getBarColor() {
return backtankStack.getBarColor();
}
@Override
public boolean isFireResistant() {
return backtankStack.getItem().isFireResistant();
}
@Override
public ItemStack getDisplayedBacktank() {
return backtankStack;
}
// Static methods moved from BacktankUtil
public static boolean hasAirRemaining(ItemStack backtank) {
return getAir(backtank) > 0;
}
public static float getAir(ItemStack backtank) {
CompoundTag tag = backtank.getOrCreateTag();
return Math.min(tag.getFloat("Air"), maxAir(backtank));
}
public static void consumeAir(LivingEntity entity, ItemStack backtank, float i) {
CompoundTag tag = backtank.getOrCreateTag();
int maxAir = maxAir(backtank);
float air = getAir(backtank);
float newAir = Math.max(air - i, 0);
tag.putFloat("Air", Math.min(newAir, maxAir));
backtank.setTag(tag);
if (!(entity instanceof ServerPlayer player))
return;
sendWarning(player, air, newAir, maxAir / 10f);
sendWarning(player, air, newAir, 1);
}
private static void sendWarning(ServerPlayer player, float air, float newAir, float threshold) {
if (newAir > threshold)
return;
if (air <= threshold)
return;
boolean depleted = threshold == 1;
MutableComponent component = Lang.translateDirect(depleted ? "backtank.depleted" : "backtank.low");
AllSoundEvents.DENY.play(player.level, null, player.blockPosition(), 1, 1.25f);
AllSoundEvents.STEAM.play(player.level, null, player.blockPosition(), .5f, .5f);
player.connection.send(new ClientboundSetTitlesAnimationPacket(10, 40, 10));
player.connection.send(new ClientboundSetSubtitleTextPacket(
Components.literal("\u26A0 ").withStyle(depleted ? ChatFormatting.RED : ChatFormatting.GOLD)
.append(component.withStyle(ChatFormatting.GRAY))));
player.connection.send(new ClientboundSetTitleTextPacket(Components.immutableEmpty()));
}
public static int maxAir(ItemStack backtank) {
return maxAir(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), backtank));
}
public static int maxAir(int enchantLevel) {
return AllConfigs.server().equipment.airInBacktank.get()
+ AllConfigs.server().equipment.enchantedBacktankCapacity.get() * enchantLevel;
}
public static int maxAirWithoutEnchants() {
return AllConfigs.server().equipment.airInBacktank.get();
}
}

View file

@ -0,0 +1,30 @@
package com.simibubi.create.content.equipment.armor.backtank_utils;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
/**
* Base interface for the Air provider (such as Backtanks).
* <p>
* If you use Air Providers (such as implementing a tool),
* you should use {@link com.simibubi.create.content.equipment.armor.BacktankUtil}
* (For example, use {@link com.simibubi.create.content.equipment.armor.BacktankUtil#getAllWithAir(LivingEntity)}
* to get player Air Sources )
*/
public interface IAirSource {
float getAir();
// int maxAir();
void consumeAir(LivingEntity entity, float i);
boolean hasAirRemaining();
int getBarWidth();
int getBarColor();
boolean isFireResistant();
ItemStack getDisplayedBacktank();
}