mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-26 12:57:58 +01:00
Upgrade BackTankUtil to handle multiple (backtank) air sources (#4777)
- Addons can now register backtank-esque air sources placed in curios slots - Diving helmets now support multiple (backtank) air sources
This commit is contained in:
parent
e42fba6341
commit
440d7e0e39
4 changed files with 119 additions and 44 deletions
|
@ -1,8 +1,12 @@
|
||||||
package com.simibubi.create.compat.curios;
|
package com.simibubi.create.compat.curios;
|
||||||
|
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
|
import com.simibubi.create.content.equipment.armor.BacktankUtil;
|
||||||
import com.simibubi.create.content.equipment.goggles.GogglesItem;
|
import com.simibubi.create.content.equipment.goggles.GogglesItem;
|
||||||
|
import com.simibubi.create.AllTags;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
@ -12,29 +16,61 @@ import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
|
||||||
import top.theillusivec4.curios.api.CuriosCapability;
|
import top.theillusivec4.curios.api.CuriosCapability;
|
||||||
import top.theillusivec4.curios.api.SlotTypeMessage;
|
import top.theillusivec4.curios.api.SlotTypeMessage;
|
||||||
import top.theillusivec4.curios.api.SlotTypePreset;
|
import top.theillusivec4.curios.api.SlotTypePreset;
|
||||||
|
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
|
||||||
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
|
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class Curios {
|
public class Curios {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the Stacks Handler Map given an Entity.
|
||||||
|
* It is recommended to then use a `.map(curiosMap -> curiosMap.get({key})`,
|
||||||
|
* which can be null and would therefore be caught by the Optional::map function.
|
||||||
|
*
|
||||||
|
* @param entity The entity which possibly has a Curio Inventory capability
|
||||||
|
* @return An optional of the Stacks Handler Map
|
||||||
|
*/
|
||||||
|
private static Optional<Map<String, ICurioStacksHandler>> resolveCuriosMap(LivingEntity entity) {
|
||||||
|
return entity.getCapability(CuriosCapability.INVENTORY).map(ICuriosItemHandler::getCurios);
|
||||||
|
}
|
||||||
|
|
||||||
public static void init(IEventBus modEventBus, IEventBus forgeEventBus) {
|
public static void init(IEventBus modEventBus, IEventBus forgeEventBus) {
|
||||||
modEventBus.addListener(Curios::onInterModEnqueue);
|
modEventBus.addListener(Curios::onInterModEnqueue);
|
||||||
modEventBus.addListener(Curios::onClientSetup);
|
modEventBus.addListener(Curios::onClientSetup);
|
||||||
|
|
||||||
GogglesItem.addIsWearingPredicate(player -> player.getCapability(CuriosCapability.INVENTORY)
|
GogglesItem.addIsWearingPredicate(player -> resolveCuriosMap(player)
|
||||||
.map(handler -> {
|
.map(curiosMap -> curiosMap.get("head"))
|
||||||
ICurioStacksHandler stacksHandler = handler.getCurios()
|
.map(stacksHandler -> {
|
||||||
.get("head");
|
// Check all the Head slots for Goggles existing
|
||||||
if (stacksHandler == null)
|
|
||||||
return false;
|
|
||||||
int slots = stacksHandler.getSlots();
|
int slots = stacksHandler.getSlots();
|
||||||
for (int slot = 0; slot < slots; slot++)
|
for (int slot = 0; slot < slots; slot++)
|
||||||
if (AllItems.GOGGLES.isIn(stacksHandler.getStacks()
|
if (AllItems.GOGGLES.isIn(stacksHandler.getStacks().getStackInSlot(slot)))
|
||||||
.getStackInSlot(slot)))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.orElse(false));
|
.orElse(false));
|
||||||
|
|
||||||
|
BacktankUtil.addBacktankSupplier(entity -> resolveCuriosMap(entity)
|
||||||
|
.map(curiosMap -> {
|
||||||
|
List<ItemStack> stacks = new ArrayList<>();
|
||||||
|
for (ICurioStacksHandler stacksHandler : curiosMap.values()) {
|
||||||
|
// Search all the curio slots for pressurized air sources, and add them to the list
|
||||||
|
int slots = stacksHandler.getSlots();
|
||||||
|
for (int slot = 0; slot < slots; slot++) {
|
||||||
|
final ItemStack itemStack = stacksHandler.getStacks().getStackInSlot(slot);
|
||||||
|
if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack))
|
||||||
|
stacks.add(itemStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stacks;
|
||||||
|
}).orElse(new ArrayList<>()));
|
||||||
|
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
|
||||||
() -> () -> modEventBus.addListener(CuriosRenderers::onLayerRegister));
|
() -> () -> modEventBus.addListener(CuriosRenderers::onLayerRegister));
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
|
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
|
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
@ -23,13 +22,39 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class BacktankUtil {
|
public class BacktankUtil {
|
||||||
|
|
||||||
public static ItemStack get(LivingEntity entity) {
|
private static final List<Function<LivingEntity, List<ItemStack>>> BACKTANK_SUPPLIERS = new ArrayList<>();
|
||||||
for (ItemStack itemStack : entity.getArmorSlots())
|
static {
|
||||||
if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack))
|
addBacktankSupplier(entity -> {
|
||||||
return itemStack;
|
List<ItemStack> stacks = new ArrayList<>();
|
||||||
return ItemStack.EMPTY;
|
for (ItemStack itemStack : entity.getArmorSlots())
|
||||||
|
if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack))
|
||||||
|
stacks.add(itemStack);
|
||||||
|
|
||||||
|
return stacks;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ItemStack> getAllWithAir(LivingEntity entity) {
|
||||||
|
List<ItemStack> all = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Function<LivingEntity, List<ItemStack>> supplier : BACKTANK_SUPPLIERS) {
|
||||||
|
List<ItemStack> result = supplier.apply(entity);
|
||||||
|
|
||||||
|
for (ItemStack stack : result)
|
||||||
|
if (hasAirRemaining(stack))
|
||||||
|
all.add(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort with ascending order (we want to prioritize the most empty so things actually run out)
|
||||||
|
all.sort((a, b) -> Float.compare(getAir(a), getAir(b)));
|
||||||
|
|
||||||
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasAirRemaining(ItemStack backtank) {
|
public static boolean hasAirRemaining(ItemStack backtank) {
|
||||||
|
@ -45,7 +70,7 @@ public class BacktankUtil {
|
||||||
CompoundTag tag = backtank.getOrCreateTag();
|
CompoundTag tag = backtank.getOrCreateTag();
|
||||||
int maxAir = maxAir(backtank);
|
int maxAir = maxAir(backtank);
|
||||||
float air = getAir(backtank);
|
float air = getAir(backtank);
|
||||||
float newAir = air - i;
|
float newAir = Math.max(air - i, 0);
|
||||||
tag.putFloat("Air", Math.min(newAir, maxAir));
|
tag.putFloat("Air", Math.min(newAir, maxAir));
|
||||||
backtank.setTag(tag);
|
backtank.setTag(tag);
|
||||||
|
|
||||||
|
@ -92,13 +117,11 @@ public class BacktankUtil {
|
||||||
return true;
|
return true;
|
||||||
if (entity instanceof Player && ((Player) entity).isCreative())
|
if (entity instanceof Player && ((Player) entity).isCreative())
|
||||||
return true;
|
return true;
|
||||||
ItemStack backtank = get(entity);
|
List<ItemStack> backtanks = getAllWithAir(entity);
|
||||||
if (backtank.isEmpty())
|
if (backtanks.isEmpty())
|
||||||
return false;
|
|
||||||
if (!hasAirRemaining(backtank))
|
|
||||||
return false;
|
return false;
|
||||||
float cost = ((float) maxAirWithoutEnchants()) / usesPerTank;
|
float cost = ((float) maxAirWithoutEnchants()) / usesPerTank;
|
||||||
consumeAir(entity, backtank, cost);
|
consumeAir(entity, backtanks.get(0), cost);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +133,8 @@ public class BacktankUtil {
|
||||||
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
||||||
if (player == null)
|
if (player == null)
|
||||||
return false;
|
return false;
|
||||||
ItemStack backtank = get(player);
|
List<ItemStack> backtanks = getAllWithAir(player);
|
||||||
if (backtank.isEmpty() || !hasAirRemaining(backtank))
|
if (backtanks.isEmpty())
|
||||||
return stack.isDamaged();
|
return stack.isDamaged();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -122,11 +145,21 @@ public class BacktankUtil {
|
||||||
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
||||||
if (player == null)
|
if (player == null)
|
||||||
return 13;
|
return 13;
|
||||||
ItemStack backtank = get(player);
|
|
||||||
if (backtank.isEmpty() || !hasAirRemaining(backtank))
|
List<ItemStack> backtanks = getAllWithAir(player);
|
||||||
|
|
||||||
|
if (backtanks.isEmpty())
|
||||||
return Math.round(13.0F - (float) stack.getDamageValue() / stack.getMaxDamage() * 13.0F);
|
return Math.round(13.0F - (float) stack.getDamageValue() / stack.getMaxDamage() * 13.0F);
|
||||||
return backtank.getItem()
|
|
||||||
.getBarWidth(backtank);
|
if (backtanks.size() == 1)
|
||||||
|
return backtanks.get(0).getItem().getBarWidth(backtanks.get(0));
|
||||||
|
|
||||||
|
// If there is more than one backtank, average the bar widths.
|
||||||
|
int sumBarWidth = backtanks.stream()
|
||||||
|
.map(backtank -> backtank.getItem().getBarWidth(backtank))
|
||||||
|
.reduce(0 , Integer::sum);
|
||||||
|
|
||||||
|
return Math.round((float) sumBarWidth / backtanks.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getBarColor(ItemStack stack, int usesPerTank) {
|
public static int getBarColor(ItemStack stack, int usesPerTank) {
|
||||||
|
@ -135,12 +168,17 @@ public class BacktankUtil {
|
||||||
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player);
|
||||||
if (player == null)
|
if (player == null)
|
||||||
return 0;
|
return 0;
|
||||||
ItemStack backtank = get(player);
|
List<ItemStack> backtanks = getAllWithAir(player);
|
||||||
if (backtank.isEmpty() || !hasAirRemaining(backtank))
|
|
||||||
return Mth.hsvToRgb(Math.max(0.0F, 1.0F - (float) stack.getDamageValue() / stack.getMaxDamage()) / 3.0F,
|
// Just return the "first" backtank for the bar color since that's the one we are consuming from
|
||||||
1.0F, 1.0F);
|
return backtanks.get(0).getItem().getBarColor(backtanks.get(0));
|
||||||
return backtank.getItem()
|
|
||||||
.getBarColor(backtank);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to add custom entry points to the backtank item stack supplier, e.g. getting them from custom
|
||||||
|
* slots or items.
|
||||||
|
*/
|
||||||
|
public static void addBacktankSupplier(Function<LivingEntity, List<ItemStack>> supplier) {
|
||||||
|
BACKTANK_SUPPLIERS.add(supplier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@EventBusSubscriber
|
@EventBusSubscriber
|
||||||
public class DivingHelmetItem extends BaseArmorItem {
|
public class DivingHelmetItem extends BaseArmorItem {
|
||||||
public static final EquipmentSlot SLOT = EquipmentSlot.HEAD;
|
public static final EquipmentSlot SLOT = EquipmentSlot.HEAD;
|
||||||
|
@ -75,17 +77,14 @@ public class DivingHelmetItem extends BaseArmorItem {
|
||||||
if (entity instanceof Player && ((Player) entity).isCreative())
|
if (entity instanceof Player && ((Player) entity).isCreative())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ItemStack backtank = BacktankUtil.get(entity);
|
List<ItemStack> backtanks = BacktankUtil.getAllWithAir(entity);
|
||||||
if (backtank.isEmpty())
|
if (backtanks.isEmpty())
|
||||||
return;
|
|
||||||
if (!BacktankUtil.hasAirRemaining(backtank))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (lavaDiving) {
|
if (lavaDiving) {
|
||||||
if (entity instanceof ServerPlayer sp)
|
if (entity instanceof ServerPlayer sp)
|
||||||
AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp);
|
AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp);
|
||||||
if (!backtank.getItem()
|
if (backtanks.stream().noneMatch(backtank -> backtank.getItem().isFireResistant()))
|
||||||
.isFireResistant())
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +93,12 @@ public class DivingHelmetItem extends BaseArmorItem {
|
||||||
|
|
||||||
if (world.isClientSide)
|
if (world.isClientSide)
|
||||||
entity.getPersistentData()
|
entity.getPersistentData()
|
||||||
.putInt("VisualBacktankAir", (int) BacktankUtil.getAir(backtank));
|
.putInt("VisualBacktankAir", Math.round(backtanks.stream().map(BacktankUtil::getAir).reduce(0f, Float::sum)));
|
||||||
|
|
||||||
if (!second)
|
if (!second)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BacktankUtil.consumeAir(entity, backtank, 1);
|
BacktankUtil.consumeAir(entity, backtanks.get(0), 1);
|
||||||
|
|
||||||
if (lavaDiving)
|
if (lavaDiving)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,6 +16,8 @@ import net.minecraft.world.level.GameType;
|
||||||
import net.minecraftforge.client.gui.ForgeIngameGui;
|
import net.minecraftforge.client.gui.ForgeIngameGui;
|
||||||
import net.minecraftforge.client.gui.IIngameOverlay;
|
import net.minecraftforge.client.gui.IIngameOverlay;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class RemainingAirOverlay implements IIngameOverlay {
|
public class RemainingAirOverlay implements IIngameOverlay {
|
||||||
public static final RemainingAirOverlay INSTANCE = new RemainingAirOverlay();
|
public static final RemainingAirOverlay INSTANCE = new RemainingAirOverlay();
|
||||||
|
|
||||||
|
@ -59,9 +61,9 @@ public class RemainingAirOverlay implements IIngameOverlay {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemStack getDisplayedBacktank(LocalPlayer player) {
|
public static ItemStack getDisplayedBacktank(LocalPlayer player) {
|
||||||
ItemStack backtank = BacktankUtil.get(player);
|
List<ItemStack> backtanks = BacktankUtil.getAllWithAir(player);
|
||||||
if (!backtank.isEmpty()) {
|
if (!backtanks.isEmpty()) {
|
||||||
return backtank;
|
return backtanks.get(0);
|
||||||
}
|
}
|
||||||
return AllItems.COPPER_BACKTANK.asStack();
|
return AllItems.COPPER_BACKTANK.asStack();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue