From 336a8a23374b957272b8d18a76fecb1e2034e6ae Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Wed, 29 May 2024 21:22:33 +0300 Subject: [PATCH] hazards part 2 (#1341) * fix component item eating happening twice * make antidotes take off % of hazard time instead of a flat amount of it * clean up how hazard effects are tracked and saved * make paracetamol fully an LV recipe * make formaldehyde an inhalation poison * make it possible to add new hazard types (for custom lang keys etc.) * spotless, datagen --- .../resources/assets/gtceu/lang/en_ud.json | 7 +- .../resources/assets/gtceu/lang/en_us.json | 7 +- .../api/capability/IHazardEffectTracker.java | 18 +- .../gtceu/api/item/ComponentItem.java | 2 +- .../material/properties/HazardProperty.java | 146 +++++++------- .../capability/HazardEffectTracker.java | 182 ++++++------------ .../gtceu/common/commands/ServerCommands.java | 13 +- .../gtceu/common/item/AntidoteBehavior.java | 80 +++++--- .../gtceu/core/mixins/InventoryMixin.java | 93 +-------- .../gregtechceu/gtceu/data/item/GTItems.java | 7 +- .../gtceu/data/lang/LangHandler.java | 6 +- .../data/material/FirstDegreeMaterials.java | 1 + .../serialized/chemistry/AntidoteRecipes.java | 4 +- .../gtceu/forge/ForgeCommonEventListener.java | 29 +++ 14 files changed, 251 insertions(+), 344 deletions(-) diff --git a/src/generated/resources/assets/gtceu/lang/en_ud.json b/src/generated/resources/assets/gtceu/lang/en_ud.json index 5031cd53a1..6b7bf00abd 100644 --- a/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -2516,14 +2516,15 @@ "gtceu.gui.toggle_view.disabled": ")spınןℲ( ʍǝıΛ ǝןbbo⟘", "gtceu.gui.toggle_view.enabled": ")sɯǝʇI( ʍǝıΛ ǝןbbo⟘", "gtceu.hazard.antidote.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ ǝʇopıʇuⱯɐ§", - "gtceu.hazard.antidote.description.time_removed": "ǝɯıʇ ,sʇuǝɯןıɐ ʇuǝɹɹnɔ ɟo %ss sǝʌoɯǝᴚ", - "gtceu.hazard.antidote.description.time_removed.all": "ןןɐ", + "gtceu.hazard.antidote.description.effect_removed": "sʇɔǝɟɟǝ ,sʇuǝɯןıɐ ʇuǝɹɹnɔ ɟo %s%% sǝʌoɯǝᴚ", + "gtceu.hazard.antidote.description.effect_removed.all": "sʇɔǝɟɟǝ ,sʇuǝɯןıɐ ʇuǝɹɹnɔ ɟo ןןɐ sǝʌoɯǝᴚ", "gtceu.hazard.antidote.description_shift": ":sǝdʎʇ sǝɹnƆɐ§", "gtceu.hazard.contact_poison": "uosıoԀ ʇɔɐʇuoƆϛ§", "gtceu.hazard.corrosive": "ǝʌısoɹɹoƆ9§", "gtceu.hazard.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ S∩OᗡᴚⱯZⱯHɔ§ן§", "gtceu.hazard.description_shift": ":S∩OᗡᴚⱯZⱯHɔ§ן§", "gtceu.hazard.inhalation_poison": "pǝןɐɥuı uǝɥʍ snouosıoԀᄅ§", + "gtceu.hazard.none": "snoɹǝbuɐᗡ ʇoNᄅ§", "gtceu.hazard.radioactive": "ǝʌıʇɔɐoıpɐᴚǝ§", "gtceu.io.both": "ɥʇoᗺ", "gtceu.io.export": "ʇɹodxƎ", @@ -5549,4 +5550,4 @@ "tile.gtceu.reinforced_foam.name": "ɯɐoℲ pǝɔɹoɟuıǝᴚ", "tile.gtceu.reinforced_stone.name": "ǝuoʇS pǝɔɹoɟuıǝᴚ", "tile.gtceu.seal.name": "ʞɔoןᗺ pǝןɐǝS" -} +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/lang/en_us.json b/src/generated/resources/assets/gtceu/lang/en_us.json index 04ff6bbc02..3be48efe2d 100644 --- a/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/src/generated/resources/assets/gtceu/lang/en_us.json @@ -2547,14 +2547,15 @@ "gtceu.gui.toggle_view.disabled": "Toggle View (Fluids)", "gtceu.gui.toggle_view.enabled": "Toggle View (Items)", "gtceu.hazard.antidote.description": "§aAntidote §7Hold Shift to show details", - "gtceu.hazard.antidote.description.time_removed": "Removes %ss of current ailments' time", - "gtceu.hazard.antidote.description.time_removed.all": "all", + "gtceu.hazard.antidote.description.effect_removed": "Removes %s%% of current ailments' effects", + "gtceu.hazard.antidote.description.effect_removed.all": "Removes all of current ailments' effects", "gtceu.hazard.antidote.description_shift": "§aCures types:", "gtceu.hazard.contact_poison": "§5Contact Poison", "gtceu.hazard.corrosive": "§6Corrosive", "gtceu.hazard.description": "§l§cHAZARDOUS §7Hold Shift to show details", "gtceu.hazard.description_shift": "§l§cHAZARDOUS:", "gtceu.hazard.inhalation_poison": "§2Poisonous when inhaled", + "gtceu.hazard.none": "§2Not Dangerous", "gtceu.hazard.radioactive": "§eRadioactive", "gtceu.implosion_compressor": "Implosion Compressor", "gtceu.io.both": "Both", @@ -5546,4 +5547,4 @@ "tile.gtceu.reinforced_foam.name": "Reinforced Foam", "tile.gtceu.reinforced_stone.name": "Reinforced Stone", "tile.gtceu.seal.name": "Sealed Block" -} +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java b/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java index db79e6ddce..2b3d89776d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java @@ -1,24 +1,22 @@ package com.gregtechceu.gtceu.api.capability; +import com.gregtechceu.gtceu.api.material.material.Material; -import com.gregtechceu.gtceu.api.material.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.material.material.stack.UnificationEntry; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import java.util.Map; import java.util.Set; public interface IHazardEffectTracker { /** - * @return a map of the hazard types to their effects. + * @return a set of hazard effect to how long it's been applied for. */ - Map> getTypesToEffects(); + Set getExtraHazards(); /** - * @return a map of hazard effect to how long it's been applied for. + * @return a map of material to how long its effects been applied for. */ - Object2IntMap getCurrentHazardEffects(); + Object2IntMap getCurrentHazards(); /** * @return the maximum air supply for the entity this is attached to. -1 for default (300). @@ -26,9 +24,9 @@ public interface IHazardEffectTracker { // default maxAirSupply for players is 300. int getMaxAirSupply(); - void removeHazardItem(UnificationEntry entry); + void startTick(); - void addHazardItem(UnificationEntry entry); + void tick(Material material); - void tick(); + void endTick(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/item/ComponentItem.java b/src/main/java/com/gregtechceu/gtceu/api/item/ComponentItem.java index f065b9e14f..148f82a09b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/item/ComponentItem.java +++ b/src/main/java/com/gregtechceu/gtceu/api/item/ComponentItem.java @@ -156,7 +156,7 @@ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livi stack = interactionItem.finishUsingItem(stack, level, livingEntity); } } - return super.finishUsingItem(stack, level, livingEntity); + return stack; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/material/material/properties/HazardProperty.java b/src/main/java/com/gregtechceu/gtceu/api/material/material/properties/HazardProperty.java index a4134e9138..a907d37089 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/material/material/properties/HazardProperty.java +++ b/src/main/java/com/gregtechceu/gtceu/api/material/material/properties/HazardProperty.java @@ -1,15 +1,18 @@ package com.gregtechceu.gtceu.api.material.material.properties; +import com.gregtechceu.gtceu.api.item.TagPrefixItem; import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; +import com.gregtechceu.gtceu.api.material.ChemicalHelper; +import com.gregtechceu.gtceu.api.material.material.Material; +import com.gregtechceu.gtceu.api.material.material.stack.UnificationEntry; import com.gregtechceu.gtceu.api.tag.TagPrefix; +import com.gregtechceu.gtceu.api.item.forge.GTBucketItem; import com.gregtechceu.gtceu.common.data.GTMobEffects; +import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.CustomTags; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.Holder; +import net.minecraft.util.StringRepresentable; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.LivingEntity; @@ -17,6 +20,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; @@ -65,40 +69,45 @@ public HazardProperty(HazardType hazardType, List e @Override public void verifyProperty(MaterialProperties properties) {} - public enum HazardType { + public record HazardType(String name, ProtectionType protectionType, Set affectedTagPrefixes) + implements StringRepresentable { - INHALATION_POISON(ProtectionType.MASK, TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny, - TagPrefix.dustPure, TagPrefix.dustImpure), - CONTACT_POISON(ProtectionType.FULL), - RADIOACTIVE(ProtectionType.FULL), - CORROSIVE(ProtectionType.HANDS, TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny), - NONE(ProtectionType.FULL); + public static final Map ALL_HAZARDS = new HashMap<>(); - public static final HazardType[] ALL = { INHALATION_POISON, CONTACT_POISON, RADIOACTIVE, CORROSIVE }; + public static final HazardType INHALATION_POISON = new HazardType("inhalation_poison", ProtectionType.MASK, + TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny, TagPrefix.dustPure, TagPrefix.dustImpure); + public static final HazardType CONTACT_POISON = new HazardType("contacy_poison", ProtectionType.FULL); + public static final HazardType RADIOACTIVE = new HazardType("radioactive", ProtectionType.FULL); + public static final HazardType CORROSIVE = new HazardType("corrosive", ProtectionType.HANDS, + TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny); + public static final HazardType NONE = new HazardType("none", ProtectionType.NONE); - private final Set affectedTagPrefixes = new HashSet<>(); - @Getter - private final ProtectionType protectionType; + public HazardType { + ALL_HAZARDS.put(name, this); + } - HazardType(ProtectionType protectionType, TagPrefix... tagPrefixes) { - this.protectionType = protectionType; + public HazardType(String name, ProtectionType protectionType, TagPrefix... tagPrefixes) { + this(name, protectionType, new HashSet<>()); affectedTagPrefixes.addAll(Arrays.asList(tagPrefixes)); - if (tagPrefixes.length > 0) - affectedTagPrefixes.add(null); // add a null for fluid, because they don't have a prefix but still need - // to always be harmful. } public boolean isAffected(TagPrefix prefix) { if (affectedTagPrefixes.isEmpty()) return true; // empty list means all prefixes are affected return affectedTagPrefixes.contains(prefix); } + + @Override + public String getSerializedName() { + return this.name; + } } public enum ProtectionType { MASK(ArmorItem.Type.HELMET), HANDS(ArmorItem.Type.CHESTPLATE), - FULL(ArmorItem.Type.BOOTS, ArmorItem.Type.HELMET, ArmorItem.Type.CHESTPLATE, ArmorItem.Type.LEGGINGS); + FULL(ArmorItem.Type.BOOTS, ArmorItem.Type.HELMET, ArmorItem.Type.CHESTPLATE, ArmorItem.Type.LEGGINGS), + NONE(); @Getter private final Set equipmentTypes; @@ -108,6 +117,9 @@ public enum ProtectionType { } public boolean isProtected(LivingEntity livingEntity) { + if (this == NONE) { + return true; + } Set correctArmorItems = new HashSet<>(); for (ArmorItem.Type equipmentType : equipmentTypes) { ItemStack armor = livingEntity.getItemBySlot(equipmentType.getSlot()); @@ -149,7 +161,7 @@ public static HazardProperty.HazardEffect miningFautigueEffect(int duration, int public static HazardProperty.HazardEffect poisonEffect(int duration, int startTime, int amplifier) { return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(GTMobEffects.WEAK_POISON.get(), 1, amplifier)); + () -> new MobEffectInstance(GTMobEffects.WEAK_POISON.getDelegate(), 1, amplifier)); } public static HazardProperty.HazardEffect weaknessEffect(int duration, int startTime, int amplifier) { @@ -162,6 +174,39 @@ public static HazardProperty.HazardEffect blindnessEffect(int duration, int star () -> new MobEffectInstance(MobEffects.BLINDNESS, 1, amplifier)); } + @Nullable + public static Material getValidHazardMaterial(ItemStack item) { + Material material = null; + TagPrefix prefix = null; + boolean isFluid = false; + if (item.getItem() instanceof TagPrefixItem prefixItem) { + material = prefixItem.material; + prefix = prefixItem.tagPrefix; + } else if (item.getItem() instanceof BucketItem bucket) { + if (ConfigHolder.INSTANCE.gameplay.universalHazards || bucket instanceof GTBucketItem) { + material = ChemicalHelper.getMaterial(bucket.content); + isFluid = true; + } + } else if (ConfigHolder.INSTANCE.gameplay.universalHazards) { + UnificationEntry entry = ChemicalHelper.getUnificationEntry(item.getItem()); + if (entry != null && entry.material != null) { + material = entry.material; + prefix = entry.tagPrefix; + } + } + if (material == null) { + return null; + } + HazardProperty property = material.getProperty(PropertyKey.HAZARD); + if (property == null) { + return null; + } + if (!isFluid && !property.getHazardType().isAffected(prefix)) { + return null; + } + return material; + } + /** * @param damage amount of damage applied every {@code delay} seconds. * @param delay damage is applied every {@code delay} seconds @@ -178,7 +223,7 @@ public record HazardDamage(int damage, int delay) {} * @param modifiers the attribute modifiers, if any. */ public record HazardEffect(int duration, int modifierStartTime, List> effects, - Map modifiers, int newMaxAirSupply) { + Map, AttributeModifier> modifiers, int newMaxAirSupply) { @SafeVarargs public HazardEffect(int duration, Supplier... effects) { @@ -190,15 +235,15 @@ public HazardEffect(int duration, int modifierStartTime, Supplier modifiers) { + public HazardEffect(int secondsToMax, Map, AttributeModifier> modifiers) { this(secondsToMax, 0, List.of(), modifiers, -1); } - public HazardEffect(int secondsToMax, int modifierStartTime, Map modifiers) { + public HazardEffect(int secondsToMax, int modifierStartTime, Map, AttributeModifier> modifiers) { this(secondsToMax, modifierStartTime, List.of(), modifiers, -1); } - public HazardEffect(int secondsToMax, Map modifiers, int maxAirModifier) { + public HazardEffect(int secondsToMax, Map, AttributeModifier> modifiers, int maxAirModifier) { this(secondsToMax, 0, List.of(), modifiers, maxAirModifier); } @@ -225,11 +270,11 @@ public List getEffectInstancesAtTime(int timeFromStart) { return effectInstances; } - public Map getModifiersAtTime(int timeFromStart) { + public Map, AttributeModifier> getModifiersAtTime(int timeFromStart) { if (this.modifiers.isEmpty()) { return Object2ObjectMaps.emptyMap(); } - Map modifierMap = new HashMap<>(); + Map, AttributeModifier> modifierMap = new HashMap<>(); for (var entry : this.modifiers.entrySet()) { AttributeModifier modifier = entry.getValue(); double amount = modifier.amount() * (double) timeFromStart / Math.max(duration, 1); @@ -245,48 +290,5 @@ public int getNewMaxAirSupplyAtTime(int timeFromStart) { } return newMaxAirSupply / Math.max(Math.round((float) timeFromStart / Math.max(duration, 1)), 1); } - - public CompoundTag serializeNBT() { - CompoundTag tag = new CompoundTag(); - tag.putInt("duration", duration); - tag.putInt("modifier_start_time", modifierStartTime); - - ListTag effectsTag = new ListTag(); - for (Supplier effect : effects) { - effectsTag.add(effect.get().save()); - } - tag.put("effects", effectsTag); - CompoundTag attributesTag = new CompoundTag(); - for (Map.Entry modifier : modifiers.entrySet()) { - attributesTag.put(BuiltInRegistries.ATTRIBUTE.getKey(modifier.getKey()).toString(), - modifier.getValue().save()); - } - tag.put("modifiers", attributesTag); - tag.putInt("max_air_supply", newMaxAirSupply); - - return tag; - } - - public static HazardEffect deserializeNBT(CompoundTag tag) { - int duration = tag.getInt("duration"); - int modifierStartTime = tag.getInt("modifier_start_time"); - - List> effects = new ArrayList<>(); - for (Tag effect : tag.getList("effects", Tag.TAG_COMPOUND)) { - if (!(effect instanceof CompoundTag compoundTag)) { - continue; - } - effects.add(() -> MobEffectInstance.load(compoundTag)); - } - Map modifiers = new HashMap<>(); - CompoundTag attributesTag = tag.getCompound("modifiers"); - for (String key : attributesTag.getAllKeys()) { - modifiers.put(BuiltInRegistries.ATTRIBUTE.get(new ResourceLocation(key)), - AttributeModifier.load(attributesTag.getCompound(key))); - } - int maxAirModifier = tag.getInt("max_air_supply"); - - return new HazardEffect(duration, modifierStartTime, effects, modifiers, maxAirModifier); - } } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java b/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java index 508cdbcd49..5b54f8cff6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java @@ -2,18 +2,15 @@ import com.gregtechceu.gtceu.api.GTCEuAPI; import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; - import com.gregtechceu.gtceu.api.material.material.Material; import com.gregtechceu.gtceu.api.material.material.properties.HazardProperty; import com.gregtechceu.gtceu.api.material.material.properties.PropertyKey; -import com.gregtechceu.gtceu.api.material.material.stack.UnificationEntry; -import com.gregtechceu.gtceu.api.tag.TagPrefix; -import it.unimi.dsi.fastutil.objects.Object2BooleanMap; + import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.core.HolderLookup; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.ai.attributes.AttributeInstance; @@ -21,17 +18,14 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ArmorItem; -import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.Getter; import lombok.Setter; import net.neoforged.neoforge.common.util.INBTSerializable; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import java.util.EnumMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; public class HazardEffectTracker implements IHazardEffectTracker, INBTSerializable { @@ -39,58 +33,52 @@ public class HazardEffectTracker implements IHazardEffectTracker, INBTSerializab @Getter @Setter private int maxAirSupply = -1; - - @Getter - private final Object2IntMap entryToAmount = new Object2IntOpenHashMap<>(); @Getter - private final Map> typesToEffects = new EnumMap<>( - HazardProperty.HazardType.class); + private final Set extraHazards = new HashSet<>(); @Getter - private final Object2IntMap currentHazardEffects = new Object2IntOpenHashMap<>(); + private final Object2IntMap currentHazards = new Object2IntOpenHashMap<>(); private final Player player; + private int totalMaxAirSupply, maxAirSupplySetterAmount; + public HazardEffectTracker(Player player) { this.player = player; } @Override - public void tick() { - Set protectedFrom = new HashSet<>(); - Object2BooleanMap isAffected = new Object2BooleanOpenHashMap<>(); - for (UnificationEntry entry : entryToAmount.keySet()) { - HazardProperty property = entry.material.getProperty(PropertyKey.HAZARD); - if (property.getHazardType().getProtectionType().isProtected(player)) { - // entity has proper safety equipment, so damage it per material every 5 seconds. - if (player.level().getGameTime() % 100 == 0) { - for (ArmorItem.Type type : property.getHazardType().getProtectionType().getEquipmentTypes()) { - player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, type.getSlot()); - } - } - protectedFrom.addAll(property.getEffects()); - } - for (var effect : property.getEffects()) { - isAffected.put(effect, property.getHazardType().isAffected(entry.tagPrefix)); - } + public void startTick() { + for (Material material : this.getExtraHazards()) { + tick(material); } - if (protectedFrom.containsAll(currentHazardEffects.keySet())) { + } + + @Override + public void tick(@NotNull Material material) { + HazardProperty property = material.getProperty(PropertyKey.HAZARD); + if (property == null) { return; } + int time = currentHazards.getOrDefault(material, 0); - int totalMaxAirSupply = 0; - int maxAirSupplySetterAmount = 0; - - for (var entry : currentHazardEffects.object2IntEntrySet()) { - HazardProperty.HazardEffect effect = entry.getKey(); - int time = entry.getIntValue(); - - if (protectedFrom.contains(effect) || !isAffected.getBoolean(effect)) { - continue; + if (property.getHazardType().protectionType().isProtected(player)) { + // entity has proper safety equipment, so damage it per material every 5 seconds. + if (player.level().getGameTime() % 100 == 0) { + for (ArmorItem.Type type : property.getHazardType().protectionType().getEquipmentTypes()) { + player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, type.getSlot()); + } } + // exit the hazard applying after. + return; + } + int totalTime = 0; + int effectsCount = 0; + for (HazardProperty.HazardEffect effect : property.getEffects()) { + totalTime += effect.duration() + effect.modifierStartTime(); + effectsCount++; if (time < effect.modifierStartTime()) { // if the current applied time is less than the minimum for effects to be applied, return early. - entry.setValue(time + 1); continue; } @@ -100,7 +88,7 @@ public void tick() { var attributeModifiers = effect.getModifiersAtTime(time); for (var modifierEntry : attributeModifiers.entrySet()) { AttributeModifier modifier = modifierEntry.getValue(); - AttributeInstance attributeInstance = player.getAttribute(BuiltInRegistries.ATTRIBUTE.wrapAsHolder(modifierEntry.getKey())); + AttributeInstance attributeInstance = player.getAttribute(modifierEntry.getKey()); if (attributeInstance == null) { continue; } @@ -115,113 +103,67 @@ public void tick() { totalMaxAirSupply += maxAirSupply; maxAirSupplySetterAmount++; } + } - entry.setValue(time + 1); + currentHazards.put(material, time += 1); + // if the hazardous material has been held for 5x the average of the effects' start times, make it permanent. + // this also makes it tick 1 more time per tick, thus speeding up the effects. + if (time >= 5 * (totalTime / effectsCount)) { + extraHazards.add(material); } + } + @Override + public void endTick() { if (maxAirSupplySetterAmount > 0) { this.setMaxAirSupply(totalMaxAirSupply / maxAirSupplySetterAmount); } + totalMaxAirSupply = 0; + maxAirSupplySetterAmount = 0; } @Override public @UnknownNullability CompoundTag serializeNBT(HolderLookup.Provider provider) { CompoundTag tag = new CompoundTag(); - ListTag amountsTag = new ListTag(); - for (var amount : entryToAmount.object2IntEntrySet()) { - CompoundTag amountTag = new CompoundTag(); - if (amount.getKey().tagPrefix != null) { - amountTag.putString("prefix", amount.getKey().tagPrefix.name); - } - amountTag.putString("material", amount.getKey().material.toString()); - amountTag.putInt("amount", amount.getIntValue()); - amountsTag.add(amountTag); - } - tag.put("amounts", amountsTag); ListTag effectsTag = new ListTag(); - for (var effect : currentHazardEffects.object2IntEntrySet()) { - CompoundTag effectTag = new CompoundTag(); - effectTag.put("effect", effect.getKey().serializeNBT()); - HazardProperty.HazardType type = getType(effect.getKey()); - if (type != null) { - effectTag.putByte("type", (byte) type.ordinal()); + for (var effect : currentHazards.object2IntEntrySet()) { + if (effect.getKey() == null) { + continue; } + CompoundTag effectTag = new CompoundTag(); + effectTag.putString("material", effect.getKey().getResourceLocation().toString()); effectTag.putInt("time", effect.getIntValue()); effectsTag.add(effectTag); } tag.put("effects", effectsTag); + + ListTag extrasTag = new ListTag(); + for (Material material : extraHazards) { + extrasTag.add(StringTag.valueOf(material.getResourceLocation().toString())); + } + tag.put("extras", extrasTag); + return tag; } @Override public void deserializeNBT(HolderLookup.Provider provider, CompoundTag arg) { - ListTag amounts = arg.getList("amounts", Tag.TAG_COMPOUND); - for (Tag tag : amounts) { - if (!(tag instanceof CompoundTag compoundTag)) { - continue; - } - TagPrefix prefix = null; - if (compoundTag.contains("prefix", Tag.TAG_STRING)) { - prefix = TagPrefix.get(compoundTag.getString("prefix")); - } - Material material = GTCEuAPI.materialManager.getMaterial(compoundTag.getString("material")); - int amount = compoundTag.getInt("amount"); - entryToAmount.put(new UnificationEntry(prefix, material), amount); - } - ListTag effects = arg.getList("effects", Tag.TAG_COMPOUND); for (Tag tag : effects) { if (!(tag instanceof CompoundTag compoundTag)) { continue; } - HazardProperty.HazardEffect effect = HazardProperty.HazardEffect - .deserializeNBT(compoundTag.getCompound("effect")); + Material material = GTCEuAPI.materialManager.getMaterial(compoundTag.getString("material")); int time = compoundTag.getInt("time"); - currentHazardEffects.put(effect, time); - if (compoundTag.contains("type", Tag.TAG_BYTE)) { - HazardProperty.HazardType type = HazardProperty.HazardType.values()[compoundTag.getByte("type")]; - if (!typesToEffects.containsKey(type)) { - typesToEffects.put(type, new HashSet<>()); - } - typesToEffects.get(type).add(effect); - } + currentHazards.put(material, time); } - } - - @Override - public void removeHazardItem(UnificationEntry entry) { - if (!entryToAmount.containsKey(entry)) { - return; - } - entryToAmount.put(entry, entryToAmount.getOrDefault(entry, 0) - 1); - if (entryToAmount.getInt(entry) <= 0) { - entryToAmount.removeInt(entry); - } - } - - @Override - public void addHazardItem(UnificationEntry entry) { - if (player.isCreative()) { - return; - } - entryToAmount.put(entry, entryToAmount.getOrDefault(entry, 0) + 1); - // noinspection DataFlowIssue property existence is checked before this method is called. - for (HazardProperty.HazardEffect effect : entry.material.getProperty(PropertyKey.HAZARD).getEffects()) { - if (!this.currentHazardEffects.containsKey(effect)) { - this.currentHazardEffects.put(effect, 0); - } - } - } - - @Nullable - public HazardProperty.HazardType getType(HazardProperty.HazardEffect value) { - for (var entry : typesToEffects.entrySet()) { - if (entry.getValue().contains(value)) { - return entry.getKey(); + ListTag extras = arg.getList("extras", Tag.TAG_STRING); + for (Tag tag : extras) { + if (!(tag instanceof StringTag stringTag)) { + continue; } + extraHazards.add(GTCEuAPI.materialManager.getMaterial(stringTag.getAsString())); } - return null; } - } diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java index 41d1668efb..2c4aaa17bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java @@ -5,8 +5,6 @@ import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; -import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; -import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.gui.factory.GTUIEditorFactory; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.common.commands.arguments.MaterialArgument; @@ -71,8 +69,8 @@ public static List> createServerComma if (tracker == null) { throw EntityArgument.NO_PLAYERS_FOUND.create(); } - int count = tracker.getCurrentHazardEffects().keySet().size(); - tracker.getCurrentHazardEffects().clear(); + int count = tracker.getCurrentHazards().keySet().size(); + tracker.getCurrentHazards().clear(); return count; }) .then(Commands.argument("targets", EntityArgument.players()) @@ -86,8 +84,8 @@ public static List> createServerComma if (tracker == null) { continue; } - count += tracker.getCurrentHazardEffects().keySet().size(); - tracker.getCurrentHazardEffects().clear(); + count += tracker.getCurrentHazards().keySet().size(); + tracker.getCurrentHazards().clear(); } if (count == 0) { throw ERROR_CLEAR_EVERYTHING_FAILED.create(); @@ -114,8 +112,7 @@ public static List> createServerComma if (tracker == null) { continue; } - tracker.addHazardItem( - new UnificationEntry(TagPrefix.dust, material)); + tracker.getExtraHazards().add(material); success++; } if (success == 0) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java index 58fe464f43..04990eb0dd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java @@ -2,9 +2,11 @@ import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; +import com.gregtechceu.gtceu.api.material.material.Material; +import com.gregtechceu.gtceu.api.material.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.material.material.properties.PropertyKey; import com.gregtechceu.gtceu.api.item.component.IAddInformation; import com.gregtechceu.gtceu.api.item.component.IInteractionItem; -import com.gregtechceu.gtceu.api.material.material.properties.HazardProperty; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.GTUtil; @@ -15,54 +17,70 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; /** * Defines an antidote for a hazard (e.g. poisoning) - * - * @param types the type of the hazard to remove - * @param timeToRemove the time to remove from the chosen hazard. -1 for all. + * + * @param types the type of the hazard to remove + * @param removePercent the time to remove from the chosen hazard, as a percentage of the current time [0, 100]. + * -1 for all. */ -public record AntidoteBehavior(Set types, int timeToRemove) +public record AntidoteBehavior(Set types, int removePercent) implements IInteractionItem, IAddInformation { public AntidoteBehavior(int timeToRemove, HazardProperty.HazardType... types) { - this(Arrays.stream(types).collect(Collectors.toSet()), timeToRemove); + this(new HashSet<>(), timeToRemove); + this.types.addAll(Arrays.asList(types)); } @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) { ItemStack itemstack = IInteractionItem.super.finishUsingItem(stack, level, livingEntity); IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(livingEntity); - if (tracker != null) { - var effectTimes = tracker.getCurrentHazardEffects(); - var typesToEffects = tracker.getTypesToEffects(); - for (var type : this.types) { - var effects = typesToEffects.getOrDefault(type, Set.of()); - for (HazardProperty.HazardEffect effect : effects) { - if (!effectTimes.containsKey(effect)) { - continue; - } - if (timeToRemove == -1) { - effectTimes.removeInt(effect); - } else { - int effectTime = effectTimes.getInt(effect); - effectTimes.put(effect, Math.max(0, effectTime - this.timeToRemove)); - if (effectTimes.getInt(effect) == 0) { - effectTimes.removeInt(effect); - } - } + if (tracker == null) { + return itemstack; + } + var iterator = tracker.getCurrentHazards().object2IntEntrySet().iterator(); + while (iterator.hasNext()) { + var entry = iterator.next(); + if (entry.getKey() == null) { + continue; + } + HazardProperty.HazardType type = getHazardTypeFromMaterial(entry.getKey()); + if (type == null || !this.types.contains(type)) { + continue; + } + if (removePercent == -1) { + iterator.remove(); + } else { + int time = entry.getIntValue(); + float timeToRemove = time * (removePercent / 100.0f); + if (timeToRemove > 0.05f * time) { + iterator.remove(); + continue; } + entry.setValue((int) (time - timeToRemove)); } } return itemstack; } + @Nullable + public static HazardProperty.HazardType getHazardTypeFromMaterial(@NotNull Material material) { + HazardProperty property = material.getProperty(PropertyKey.HAZARD); + if (property == null) { + return null; + } + return property.getHazardType(); + } + @Override public void appendHoverText(ItemStack stack, @Nullable Item.TooltipContext context, List tooltipComponents, TooltipFlag isAdvanced) { @@ -72,12 +90,14 @@ public void appendHoverText(ItemStack stack, @Nullable Item.TooltipContext conte tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description_shift")); for (var type : types) { tooltipComponents.add(Component - .translatable("gtceu.hazard." + type.name().toLowerCase())); + .translatable("gtceu.hazard." + type.getSerializedName())); + } + if (removePercent == -1) { + tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description.effect_removed.all")); + } else { + tooltipComponents + .add(Component.translatable("gtceu.hazard.antidote.description.effect_removed", removePercent)); } - Component time = this.timeToRemove == -1 ? - Component.translatable("gtceu.hazard.antidote.description.time_removed.all") : - Component.literal(Integer.toString(this.timeToRemove / 20)); - tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description.time_removed", time)); return; } tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description")); diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java index 239f23f040..581bffe6d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java @@ -1,18 +1,9 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; -import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; -import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; import com.gregtechceu.gtceu.api.item.IGTTool; -import com.gregtechceu.gtceu.api.item.TagPrefixItem; -import com.gregtechceu.gtceu.api.item.forge.GTBucketItem; -import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; @@ -21,9 +12,6 @@ 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.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Inventory.class) public abstract class InventoryMixin { @@ -47,8 +35,7 @@ public abstract class InventoryMixin { @WrapOperation(method = "findSlotMatchingUnusedItem", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/item/ItemStack;isDamaged()Z", - remap = true)) + target = "Lnet/minecraft/world/item/ItemStack;isDamaged()Z")) private boolean gtceu$damagedToolBypass(ItemStack instance, Operation original) { if (instance.getItem() instanceof IGTTool) { return false; @@ -58,87 +45,11 @@ public abstract class InventoryMixin { @WrapOperation(method = "findSlotMatchingUnusedItem", at = @At(value = "INVOKE", - target = "Lnet/minecraft/world/item/ItemStack;isEnchanted()Z", - remap = true)) + target = "Lnet/minecraft/world/item/ItemStack;isEnchanted()Z")) private boolean gtceu$enchantedToolBypass(ItemStack instance, Operation original) { if (instance.getItem() instanceof IGTTool) { return false; } return original.call(instance); } - - // Capture any and all player inventory changes. why doesn't forge have an event for this??? - @Inject(method = "setItem", at = @At("HEAD")) - private void gtceu$setItemInSlot(int slot, ItemStack stack, CallbackInfo ci) { - if (this.player.level().isClientSide) { - return; - } - ItemStack current = !stack.isEmpty() ? stack : this.getItem(slot); - // force the stack to have a count of 1 in case it's empty. - if (current != ItemStack.EMPTY) { - ItemStack old = current; - int oldCount = old.getCount(); - current.setCount(1); - current = current.copy(); - old.setCount(oldCount); - } - - UnificationEntry entry = null; - if (current.getItem() instanceof BucketItem bucket) { - if (ConfigHolder.INSTANCE.gameplay.universalHazards || bucket instanceof GTBucketItem) { - // fake the entry being a prefix at all. - entry = new UnificationEntry(null, ChemicalHelper.getMaterial(bucket.getFluid())); - } - } else if (current.getItem() instanceof TagPrefixItem prefixItem) { - entry = new UnificationEntry(prefixItem.tagPrefix, prefixItem.material); - } else if (ConfigHolder.INSTANCE.gameplay.universalHazards) { - entry = ChemicalHelper.getUnificationEntry(current.getItem()); - } - if (entry == null || entry.material == null) { - return; - } - if (!entry.material.hasProperty(PropertyKey.HAZARD)) { - return; - } - IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(player); - if (tracker == null) { - return; - } - if (current.isEmpty()) { - tracker.removeHazardItem(entry); - } else { - tracker.addHazardItem(entry); - } - } - - @Inject(method = "removeItem(II)Lnet/minecraft/world/item/ItemStack;", at = @At("HEAD")) - private void gtceu$dropitem(int slot, int amount, CallbackInfoReturnable cir) { - if (this.player.level().isClientSide) { - return; - } - ItemStack current = this.getItem(slot); - - UnificationEntry entry = null; - if (current.getItem() instanceof BucketItem bucket) { - if (ConfigHolder.INSTANCE.gameplay.universalHazards || bucket instanceof GTBucketItem) { - // fake the fluid being an UnificationEntry at all. - entry = new UnificationEntry(null, ChemicalHelper.getMaterial(bucket.getFluid())); - } - } else if (current.getItem() instanceof TagPrefixItem prefixItem) { - entry = new UnificationEntry(prefixItem.tagPrefix, prefixItem.material); - } else if (ConfigHolder.INSTANCE.gameplay.universalHazards) { - entry = ChemicalHelper.getUnificationEntry(current.getItem()); - } - if (entry == null || entry.material == null) { - return; - } - if (!entry.material.hasProperty(PropertyKey.HAZARD)) { - return; - } - IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(player); - if (tracker == null) { - return; - } - tracker.removeHazardItem(entry); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/data/item/GTItems.java b/src/main/java/com/gregtechceu/gtceu/data/item/GTItems.java index 426d49d83b..0e79e182a5 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/item/GTItems.java +++ b/src/main/java/com/gregtechceu/gtceu/data/item/GTItems.java @@ -2249,12 +2249,15 @@ public Component getItemName(ItemStack stack) { public static ItemEntry PARACETAMOL_PILL = REGISTRATE.item("paracetamol_pill", ComponentItem::create) .lang("Paracetamol Pill") .properties(p -> p.food(GTFoods.ANTIDOTE)) - .onRegister(attach(new AntidoteBehavior(100, HazardProperty.HazardType.ALL))) + .onRegister(attach(new AntidoteBehavior(15, + HazardProperty.HazardType.CONTACT_POISON, + HazardProperty.HazardType.INHALATION_POISON, + HazardProperty.HazardType.CORROSIVE))) .register(); public static ItemEntry RAD_AWAY_PILL = REGISTRATE.item("rad_away_pill", ComponentItem::create) .lang("RadAway™ Pill") .properties(p -> p.food(GTFoods.ANTIDOTE)) - .onRegister(attach(new AntidoteBehavior(-1, HazardProperty.HazardType.RADIOACTIVE))) + .onRegister(attach(new AntidoteBehavior(75, HazardProperty.HazardType.RADIOACTIVE))) .register(); public static ItemEntry NANO_SABER; diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java index e59f8d94eb..02f7c14158 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java @@ -123,10 +123,12 @@ public static void init(RegistrateLangProvider provider) { provider.add("gtceu.hazard.inhalation_poison", "§2Poisonous when inhaled"); provider.add("gtceu.hazard.corrosive", "§6Corrosive"); provider.add("gtceu.hazard.radioactive", "§eRadioactive"); + provider.add("gtceu.hazard.none", "§2Not Dangerous"); provider.add("gtceu.hazard.antidote.description", "§aAntidote §7Hold Shift to show details"); provider.add("gtceu.hazard.antidote.description_shift", "§aCures types:"); - provider.add("gtceu.hazard.antidote.description.time_removed", "Removes %ss of current ailments' time"); - provider.add("gtceu.hazard.antidote.description.time_removed.all", "all"); + provider.add("gtceu.hazard.antidote.description.effect_removed", "Removes %s%% of current ailments' effects"); + provider.add("gtceu.hazard.antidote.description.effect_removed.all", + "Removes all of current ailments' effects"); provider.add("item.gtceu.tool.replace_tool_head", "Craft with a new Tool Head to replace it"); diff --git a/src/main/java/com/gregtechceu/gtceu/data/material/FirstDegreeMaterials.java b/src/main/java/com/gregtechceu/gtceu/data/material/FirstDegreeMaterials.java index 985acc25ba..beaf38f894 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/material/FirstDegreeMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/data/material/FirstDegreeMaterials.java @@ -1592,6 +1592,7 @@ public static void register() { .color(0xddeced) .flags(DECOMPOSITION_BY_ELECTROLYZING) .components(Carbon, 1, Hydrogen, 2, Oxygen, 1) + .hazard(HazardProperty.HazardType.INHALATION_POISON) .buildAndRegister(); Glycolonitrile = new Material.Builder(GTCEu.id("glycolonitrile")) diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AntidoteRecipes.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AntidoteRecipes.java index 6ace866b71..7ab4ae3c93 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AntidoteRecipes.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AntidoteRecipes.java @@ -33,14 +33,14 @@ private static void paracetamolProcess(Consumer provider) { .notConsumable(dust, Iron) .outputFluids(AminoPhenol.getFluid(1000)) .outputFluids(DilutedSulfuricAcid.getFluid(1000)) - .duration(300).EUt(VA[MV]).save(provider); + .duration(300).EUt(VA[LV]).save(provider); CHEMICAL_RECIPES.recipeBuilder("paracetamol") .inputFluids(AceticAnhydride.getFluid(1000)) .inputFluids(AminoPhenol.getFluid(1000)) .outputItems(dust, Paracetamol, 1) .outputFluids(AceticAcid.getFluid(1000)) - .duration(100).EUt(VA[MV]).save(provider); + .duration(100).EUt(VA[LV]).save(provider); } private static void potassiumHydroxideProcess(Consumer provider) { diff --git a/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java b/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java index 7b5dfa8a1f..fb8fbde40c 100644 --- a/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java @@ -2,7 +2,11 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.block.MetaMachineBlock; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; import com.gregtechceu.gtceu.api.capability.forge.GTCapability; +import com.gregtechceu.gtceu.api.material.material.Material; +import com.gregtechceu.gtceu.api.material.material.properties.HazardProperty; import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; import com.gregtechceu.gtceu.api.machine.feature.IInteractedMachine; import com.gregtechceu.gtceu.common.capability.HazardEffectTracker; @@ -24,12 +28,15 @@ import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.event.AddReloadListenerEvent; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.entity.living.LivingFallEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.neoforged.neoforge.event.level.LevelEvent; import net.neoforged.neoforge.event.tick.LevelTickEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; +import net.neoforged.neoforge.items.IItemHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -67,6 +74,28 @@ public void deserializeNBT(CompoundTag arg) { } } + @SubscribeEvent + public static void tickPlayerInventoryHazards(PlayerTickEvent.Post event) { + if (event.getEntity().level().isClientSide) { + return; + } + Player player = event.getEntity(); + IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(player); + IItemHandler inventory = player.getCapability(Capabilities.ItemHandler.ENTITY); + if (tracker != null && inventory != null) { + tracker.startTick(); + for (int i = 0; i < inventory.getSlots(); ++i) { + ItemStack stack = inventory.getStackInSlot(i); + Material material = HazardProperty.getValidHazardMaterial(stack); + if (material == null) { + continue; + } + tracker.tick(material); + } + tracker.endTick(); + } + } + @SubscribeEvent public static void onLeftClickBlock(PlayerInteractEvent.LeftClickBlock event) { var blockState = event.getLevel().getBlockState(event.getPos());