diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleGeneratorMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleGeneratorMachine.java index 1e23a3f118b..9dd612e5360 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleGeneratorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleGeneratorMachine.java @@ -4,8 +4,8 @@ import com.gregtechceu.gtceu.api.blockentity.BlockEntityCreationInfo; import com.gregtechceu.gtceu.api.capability.recipe.*; import com.gregtechceu.gtceu.api.gui.editor.EditableMachineUI; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; import com.gregtechceu.gtceu.api.machine.feature.IFancyUIMachine; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardEmitterTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; @@ -13,6 +13,7 @@ import com.gregtechceu.gtceu.api.recipe.modifier.ParallelLogic; import com.gregtechceu.gtceu.api.recipe.modifier.RecipeModifier; import com.gregtechceu.gtceu.api.recipe.ui.GTRecipeTypeUI; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.utils.Position; @@ -33,17 +34,18 @@ import java.util.function.BiFunction; public class SimpleGeneratorMachine extends WorkableTieredMachine - implements IFancyUIMachine, IEnvironmentalHazardEmitter { + implements IFancyUIMachine { @Getter - private final float hazardStrengthPerOperation; + private final EnvironmentalHazardEmitterTrait hazardEmitter; public SimpleGeneratorMachine(BlockEntityCreationInfo info, int tier, float hazardStrengthPerOperation, Int2IntFunction tankScalingFunction) { super(info, tier, tankScalingFunction); energyContainer.setSideOutputCondition(side -> !hasFrontFacing() || side == getFrontFacing()); - this.hazardStrengthPerOperation = hazardStrengthPerOperation; + this.hazardEmitter = new EnvironmentalHazardEmitterTrait(this, GTMedicalConditions.CARBON_MONOXIDE_POISONING, + hazardStrengthPerOperation); } public SimpleGeneratorMachine(BlockEntityCreationInfo info, int tier, Int2IntFunction tankScalingFunction) { @@ -112,7 +114,7 @@ public boolean canVoidRecipeOutputs(RecipeCapability capability) { @Override public void afterWorking() { super.afterWorking(); - spreadEnvironmentalHazard(); + hazardEmitter.emitHazard(); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardCleaner.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardCleaner.java deleted file mode 100644 index cdb7b0e7709..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardCleaner.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.feature; - -import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; - -public interface IEnvironmentalHazardCleaner extends IMachineFeature { - - float getRemovedLastSecond(); - - void cleanHazard(MedicalCondition condition, float amount); -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java deleted file mode 100644 index 4d4edb0c46e..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.feature; - -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; -import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; -import com.gregtechceu.gtceu.common.data.GTMedicalConditions; -import com.gregtechceu.gtceu.config.ConfigHolder; - -import net.minecraft.server.level.ServerLevel; - -/** - * common interface for environmental hazard (e.g. pollution) emitters like mufflers. - */ -public interface IEnvironmentalHazardEmitter extends IMachineFeature { - - /** - * @return the medical condition this hazard emitter creates. - */ - default MedicalCondition getConditionToEmit() { - return GTMedicalConditions.CARBON_MONOXIDE_POISONING; - } - - /** - * @return the starting strength of the hazard zone. - */ - float getHazardStrengthPerOperation(); - - default void spreadEnvironmentalHazard() { - if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { - return; - } - - if (self().getLevel() instanceof ServerLevel serverLevel) { - IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, - self().getBlockPos().relative(self().getFrontFacing()), self().getFrontFacing().getOpposite()); - if (container != null && - container.getHazardCanBeInserted(getConditionToEmit()) > getHazardStrengthPerOperation()) { - container.addHazard(getConditionToEmit(), getHazardStrengthPerOperation()); - return; - } - - var savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); - savedData.addZone(self().getBlockPos(), getHazardStrengthPerOperation(), true, - HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IExhaustVentMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IExhaustVentMachine.java deleted file mode 100644 index 7c62d616ba2..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IExhaustVentMachine.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.feature; - -import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; -import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; -import com.gregtechceu.gtceu.common.data.GTDamageTypes; -import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.utils.GTUtil; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.Shapes; - -import org.jetbrains.annotations.NotNull; - -/** - * Interface defining the functionality of a machine which vents exhaust from a side. - * - * @implNote {@link com.gregtechceu.gtceu.api.machine.steam.SimpleSteamMachine} - */ -public interface IExhaustVentMachine extends IMachineFeature { - - EnumProperty VENT_DIRECTION_PROPERTY = GTMachineModelProperties.VENT_DIRECTION; - - /** - * @return the direction the vent faces - */ - @NotNull - Direction getVentingDirection(); - - /** - * @return if venting is needed - */ - boolean isNeedsVenting(); - - void setNeedsVenting(boolean needsVenting); - - /** - * Mark the machine as no longer needing venting - */ - void markVentingComplete(); - - /** - * @return the damage to deal to entities in the vent area - */ - float getVentingDamage(); - - /** - * Checks the venting state. Performs venting only if required. - * - * @return if the machine does not need venting - */ - default boolean checkVenting() { - if (isNeedsVenting()) { - tryDoVenting(self().getLevel(), self().getBlockPos()); - } - return !isNeedsVenting(); - } - - /** - * @return if venting is being blocked by something - */ - default boolean isVentingBlocked() { - Level level = self().getLevel(); - Direction ventingSide = getVentingDirection(); - BlockPos ventingBlockPos = self().getBlockPos().relative(ventingSide); - BlockState state = level.getBlockState(ventingBlockPos); - - return state.canOcclude() || Shapes.blockOccudes(state.getCollisionShape(level, ventingBlockPos), - Shapes.block(), ventingSide.getOpposite()); - } - - /** - * Attempts to vent, if needed - * - * @param level the level containing the machine venting - * @param pos the position of the machine - */ - default void tryDoVenting(@NotNull Level level, @NotNull BlockPos pos) { - if (!isNeedsVenting()) return; - - if (!isVentingBlocked()) { - performVenting(level, pos); - return; - } - - BlockPos ventingPos = pos.relative(getVentingDirection()); - if (GTUtil.tryBreakSnow(level, ventingPos, level.getBlockState(ventingPos), false)) { - performVenting(level, pos); - } - } - - private void performVenting(@NotNull Level level, @NotNull BlockPos pos) { - doVentingDamage(level, pos); - - Direction ventingDirection = getVentingDirection(); - double posX = pos.getX() + 0.5 + ventingDirection.getStepX() * 0.6; - double posY = pos.getY() + 0.5 + ventingDirection.getStepY() * 0.6; - double posZ = pos.getZ() + 0.5 + ventingDirection.getStepZ() * 0.6; - createVentingParticles(level, posX, posY, posZ); - - if (ConfigHolder.INSTANCE.machines.machineSounds) { - playVentingSound(level, posX, posY, posZ); - } - - markVentingComplete(); - } - - /** - * Damages entities upon venting - * - * @param level the level containing the machine and entities - * @param pos the position of the machine venting - */ - default void doVentingDamage(@NotNull Level level, @NotNull BlockPos pos) { - for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, - new AABB(pos.relative(getVentingDirection())), - entity -> !(entity instanceof Player player) || !player.isSpectator() && !player.isCreative())) { - entity.hurt(GTDamageTypes.HEAT.source(level), getVentingDamage()); - // TODO ADVANCEMENT - // if (entity instanceof ServerPlayer) { - // AdvancementTriggers.STEAM_VENT_DEATH.trigger((ServerPlayer) entity); - // } - } - } - - /** - * Create the particles for venting - * - * @param level the level containing the machine - * @param posX the x position to send particles to - * @param posY the y position to send particles to - * @param posZ the z position to send particles to - */ - default void createVentingParticles(@NotNull Level level, double posX, double posY, double posZ) { - Direction ventingDirection = getVentingDirection(); - var count = 7 + level.random.nextInt(3); - if (level instanceof ServerLevel serverLevel) { - serverLevel.sendParticles(ParticleTypes.CLOUD, posX, posY, posZ, - count, - ventingDirection.getStepX() / 2.0, - ventingDirection.getStepY() / 2.0, - ventingDirection.getStepZ() / 2.0, 0.1); - } else { - for (int i = 0; i < count; ++i) { - double d1 = level.random.nextGaussian() * (double) ventingDirection.getStepX() / 2.0; - double d3 = level.random.nextGaussian() * (double) ventingDirection.getStepY() / 2.0; - double d5 = level.random.nextGaussian() * (double) ventingDirection.getStepZ() / 2.0; - double d6 = level.random.nextGaussian() * 0.1; - double d7 = level.random.nextGaussian() * 0.1; - double d8 = level.random.nextGaussian() * 0.1; - try { - level.addParticle(ParticleTypes.CLOUD, posX + d1, posY + d3, posZ + d5, d6, d7, d8); - continue; - } catch (Throwable throwable) { - GTCEu.LOGGER.warn("Could not spawn particle effect {}", ParticleTypes.CLOUD); - return; - } - } - } - } - - /** - * Play the venting sound - * - * @param level the level to play the sound in - * @param posX the x position to play the sound at - * @param posY the y position to play the sound at - * @param posZ the z position to play the sound at - */ - default void playVentingSound(@NotNull Level level, double posX, double posY, double posZ) { - level.playSound(null, posX, posY, posZ, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 1F, 1F); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java deleted file mode 100644 index f13c10b0af1..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.feature; - -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; -import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; -import com.gregtechceu.gtceu.common.data.GTMedicalConditions; -import com.gregtechceu.gtceu.config.ConfigHolder; - -import net.minecraft.server.level.ServerLevel; - -/** - * common interface for localized hazard (e.g. radiation) emitters like nuclear reactors. - */ -public interface ILocalizedHazardEmitter extends IMachineFeature { - - /** - * @return the medical condition this hazard emitter creates. - */ - default MedicalCondition getConditionToEmit() { - return GTMedicalConditions.CARCINOGEN; - } - - /** - * @return the starting strength of the hazard zone. recommended values are in the range [1,5) - */ - int getHazardSizePerOperation(); - - default void spreadLocalizedHazard() { - if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { - return; - } - - if (self().getLevel() instanceof ServerLevel serverLevel) { - IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, - self().getBlockPos().relative(self().getFrontFacing()), self().getFrontFacing().getOpposite()); - if (container != null && - container.getHazardCanBeInserted(getConditionToEmit()) > getHazardSizePerOperation()) { - container.addHazard(getConditionToEmit(), getHazardSizePerOperation()); - return; - } - - var savedData = LocalizedHazardSavedData.getOrCreate(serverLevel); - savedData.addSphericalZone(self().getBlockPos(), getHazardSizePerOperation(), false, - HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java deleted file mode 100644 index db1ea9e0ea4..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.gregtechceu.gtceu.api.machine.feature.multiblock; - -import com.gregtechceu.gtceu.api.GTValues; -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; -import com.gregtechceu.gtceu.api.gui.GuiTextures; -import com.gregtechceu.gtceu.api.gui.fancy.IFancyTooltip; -import com.gregtechceu.gtceu.api.gui.fancy.TooltipsPanel; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; -import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; -import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredPartMachine; -import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.common.data.GTParticleTypes; - -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; -import net.minecraft.world.item.ItemStack; - -import java.util.List; - -public interface IMufflerMachine extends IMultiPart, IEnvironmentalHazardEmitter { - - void recoverItemsTable(ItemStack... recoveryItems); - - /** - * @return true if front face is free and contains only air blocks in 1x1 area OR has a duct block on it. - */ - default boolean isFrontFaceFree() { - var frontPos = self().getBlockPos().relative(self().getFrontFacing()); - return self().getLevel().getBlockState(frontPos).isAir() || - GTCapabilityHelper.getHazardContainer(self().getLevel(), - frontPos, self().getFrontFacing().getOpposite()) != null; - } - - default void emitPollutionParticles() { - var pos = self().getBlockPos(); - var facing = self().getFrontFacing(); - - IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(self().getLevel(), - pos.relative(facing), facing.getOpposite()); - if (container != null) { - // do not emit particles if front face has a duct on it. - return; - } - - var center = pos.getCenter(); - var offset = .75f; - var xPos = (float) (center.x + facing.getStepX() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); - var yPos = (float) (center.y + facing.getStepY() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); - var zPos = (float) (center.z + facing.getStepZ() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); - - var ySpd = facing.getStepY() + (GTValues.RNG.nextFloat() - .15f) * .5f; - var xSpd = facing.getStepX() + (GTValues.RNG.nextFloat() - .5f) * .5f; - var zSpd = facing.getStepZ() + (GTValues.RNG.nextFloat() - .5f) * .5f; - - self().getLevel().addParticle(GTParticleTypes.MUFFLER_PARTICLE.get(), - xPos, yPos, zPos, xSpd, ySpd, zSpd); - } - - @Override - default GTRecipe modifyRecipe(GTRecipe recipe) { - if (!isFrontFaceFree()) { - return null; - } - return IMultiPart.super.modifyRecipe(recipe); - } - - @Override - default float getHazardStrengthPerOperation() { - float outputAmount = 2.5f; - return this instanceof TieredPartMachine tiered ? outputAmount / Math.max(tiered.getTier(), 1) : outputAmount; - } - - @Override - default boolean afterWorking(IWorkableMultiController controller) { - spreadEnvironmentalHazard(); - var supplier = controller.self().getDefinition().getRecoveryItems(); - if (supplier != null) { - recoverItemsTable(supplier.get()); - } - return IMultiPart.super.afterWorking(controller); - } - - ////////////////////////////////////// - // ******* FANCY GUI ********// - ////////////////////////////////////// - - @Override - default void attachFancyTooltipsToController(MultiblockControllerMachine controller, TooltipsPanel tooltipsPanel) { - attachTooltips(tooltipsPanel); - } - - @Override - default void attachTooltips(TooltipsPanel tooltipsPanel) { - tooltipsPanel.attachTooltips(new IFancyTooltip.Basic( - () -> GuiTextures.INDICATOR_NO_STEAM.get(false), - () -> List.of(Component.translatable("gtceu.multiblock.universal.muffler_obstructed") - .setStyle(Style.EMPTY.withColor(ChatFormatting.RED))), - () -> !isFrontFaceFree(), - () -> null)); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SimpleSteamMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SimpleSteamMachine.java index 42a5a224244..507e08d9807 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SimpleSteamMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SimpleSteamMachine.java @@ -9,9 +9,9 @@ import com.gregtechceu.gtceu.api.gui.UITemplate; import com.gregtechceu.gtceu.api.gui.widget.PredicatedImageWidget; import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.feature.IExhaustVentMachine; import com.gregtechceu.gtceu.api.machine.feature.IUIMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; +import com.gregtechceu.gtceu.api.machine.trait.ExhaustVentMachineTrait; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList; import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; @@ -34,7 +34,6 @@ import com.google.common.collect.Tables; import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -43,22 +42,23 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class SimpleSteamMachine extends SteamWorkableMachine implements IExhaustVentMachine, IUIMachine { +public class SimpleSteamMachine extends SteamWorkableMachine implements IUIMachine { @SaveField public final NotifiableItemStackHandler importItems; @SaveField public final NotifiableItemStackHandler exportItems; + @Getter - @Setter - @SaveField - private boolean needsVenting; + private final ExhaustVentMachineTrait exhaustVentTrait; public SimpleSteamMachine(BlockEntityCreationInfo info, boolean isHighPressure) { super(info, isHighPressure); this.importItems = createImportItemHandler(); this.exportItems = createExportItemHandler(); + this.exhaustVentTrait = new ExhaustVentMachineTrait(this); + exhaustVentTrait.setVentingDamageAmount(isHighPressure() ? 12F : 6F); MachineRenderState renderState = getRenderState(); if (renderState.hasProperty(GTMachineModelProperties.VENT_DIRECTION)) { // outputFacing will always be opposite the front facing on init @@ -81,6 +81,7 @@ protected NotifiableItemStackHandler createExportItemHandler() { @Override public void onLoad() { super.onLoad(); + exhaustVentTrait.setVentingDirection(Objects.requireNonNull(getOutputFacing())); // Simulate an EU machine via a SteamEnergyHandler this.addHandlerList(RecipeHandlerList.of(IO.IN, new SteamEnergyRecipeHandler(steamTank, getConversionRate()))); } @@ -96,17 +97,6 @@ public void onMachineDestroyed() { // ****** Venting Logic ******// ////////////////////////////////////// - @Override - public float getVentingDamage() { - return isHighPressure() ? 12F : 6F; - } - - @SuppressWarnings("DataFlowIssue") - @Override - public @NotNull Direction getVentingDirection() { - return getOutputFacing(); - } - public void updateModelVentDirection() { MachineRenderState renderState = getRenderState(); if (renderState.hasProperty(GTMachineModelProperties.VENT_DIRECTION)) { @@ -115,7 +105,8 @@ public void updateModelVentDirection() { if (getFrontFacing() == Direction.UP && !allowExtendedFacing()) { upwardsDir = upwardsDir.getOpposite(); } - var relative = RelativeDirection.findRelativeOf(getFrontFacing(), getVentingDirection(), upwardsDir); + var relative = RelativeDirection.findRelativeOf(getFrontFacing(), exhaustVentTrait.getVentingDirection(), + upwardsDir); setRenderState(renderState.setValue(GTMachineModelProperties.VENT_DIRECTION, relative)); } } @@ -126,6 +117,7 @@ public void setOutputFacing(@NotNull Direction outputFacing) { super.setOutputFacing(outputFacing); if (getOutputFacing() != oldFacing) { updateModelVentDirection(); + exhaustVentTrait.setVentingDirection(outputFacing); } } @@ -147,11 +139,6 @@ public void setUpwardsFacing(@NotNull Direction upwardsFacing) { } } - @Override - public void markVentingComplete() { - this.needsVenting = false; - } - public double getConversionRate() { return isHighPressure() ? 2.0 : 1.0; } @@ -175,7 +162,7 @@ public static ModifierFunction recipeModifier(@NotNull MetaMachine machine, @Not if (!(machine instanceof SimpleSteamMachine steamMachine)) { return RecipeModifier.nullWrongType(SimpleSteamMachine.class, machine); } - if (RecipeHelper.getRecipeEUtTier(recipe) > GTValues.LV || !steamMachine.checkVenting()) { + if (RecipeHelper.getRecipeEUtTier(recipe) > GTValues.LV || !steamMachine.exhaustVentTrait.checkVenting()) { return ModifierFunction.NULL; } @@ -187,8 +174,8 @@ public static ModifierFunction recipeModifier(@NotNull MetaMachine machine, @Not @Override public void afterWorking() { super.afterWorking(); - needsVenting = true; - checkVenting(); + exhaustVentTrait.setNeedsVenting(true); + exhaustVentTrait.checkVenting(); } ////////////////////////////////////// diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/ExhaustVentMachineTrait.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/ExhaustVentMachineTrait.java new file mode 100644 index 00000000000..a8862e5a58e --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/ExhaustVentMachineTrait.java @@ -0,0 +1,136 @@ +package com.gregtechceu.gtceu.api.machine.trait; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; +import com.gregtechceu.gtceu.common.data.GTDamageTypes; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.Shapes; + +import lombok.Getter; +import lombok.Setter; + +public class ExhaustVentMachineTrait extends MachineTrait { + + public static final MachineTraitType TYPE = new MachineTraitType<>( + ExhaustVentMachineTrait.class, false); + + @Getter + @Setter + private Direction ventingDirection; + @Getter + @Setter + @SaveField + private boolean needsVenting; + @Getter + @Setter + private float ventingDamageAmount; + + public ExhaustVentMachineTrait(MetaMachine machine) { + super(machine); + + this.ventingDirection = machine.getFrontFacing().getOpposite(); + this.needsVenting = false; + this.ventingDamageAmount = 0; + } + + @Override + public MachineTraitType getTraitType() { + return TYPE; + } + + public boolean isVentingBlocked() { + BlockPos ventingBlockPos = getBlockPos().relative(getVentingDirection()); + BlockState state = getLevel().getBlockState(ventingBlockPos); + + return state.canOcclude() || Shapes.blockOccudes(state.getCollisionShape(getLevel(), ventingBlockPos), + Shapes.block(), getVentingDirection().getOpposite()); + } + + public boolean checkVenting() { + if (!needsVenting) return true; + + if (!isVentingBlocked()) { + performVenting(); + return true; + } + + BlockPos ventingPos = getBlockPos().relative(getVentingDirection()); + if (GTUtil.tryBreakSnow(getLevel(), ventingPos, getLevel().getBlockState(ventingPos), false)) { + performVenting(); + return true; + } + return false; + } + + private void performVenting() { + doVentingDamage(); + createVentingParticles(); + if (ConfigHolder.INSTANCE.machines.machineSounds) { + playVentingSound(); + } + needsVenting = false; + } + + private void doVentingDamage() { + for (LivingEntity entity : getLevel().getEntitiesOfClass(LivingEntity.class, + new AABB(getBlockPos().relative(getVentingDirection())), + entity -> !(entity instanceof Player player) || !player.isSpectator() && !player.isCreative())) { + entity.hurt(GTDamageTypes.HEAT.source(getLevel()), ventingDamageAmount); + } + } + + private void createVentingParticles() { + var level = getLevel(); + var pos = getBlockPos(); + Direction ventingDirection = getVentingDirection(); + double posX = pos.getX() + 0.5 + ventingDirection.getStepX() * 0.6; + double posY = pos.getY() + 0.5 + ventingDirection.getStepY() * 0.6; + double posZ = pos.getZ() + 0.5 + ventingDirection.getStepZ() * 0.6; + var count = 7 + level.random.nextInt(3); + if (level instanceof ServerLevel serverLevel) { + serverLevel.sendParticles(ParticleTypes.CLOUD, posX, posY, posZ, + count, + ventingDirection.getStepX() / 2.0, + ventingDirection.getStepY() / 2.0, + ventingDirection.getStepZ() / 2.0, 0.1); + } else { + for (int i = 0; i < count; ++i) { + double d1 = level.random.nextGaussian() * (double) ventingDirection.getStepX() / 2.0; + double d3 = level.random.nextGaussian() * (double) ventingDirection.getStepY() / 2.0; + double d5 = level.random.nextGaussian() * (double) ventingDirection.getStepZ() / 2.0; + double d6 = level.random.nextGaussian() * 0.1; + double d7 = level.random.nextGaussian() * 0.1; + double d8 = level.random.nextGaussian() * 0.1; + try { + level.addParticle(ParticleTypes.CLOUD, posX + d1, posY + d3, posZ + d5, d6, d7, d8); + continue; + } catch (Throwable throwable) { + GTCEu.LOGGER.warn("Could not spawn particle effect {}", ParticleTypes.CLOUD); + return; + } + } + } + } + + private void playVentingSound() { + var pos = getBlockPos(); + var level = getLevel(); + double posX = pos.getX() + 0.5 + ventingDirection.getStepX() * 0.6; + double posY = pos.getY() + 0.5 + ventingDirection.getStepY() * 0.6; + double posZ = pos.getZ() + 0.5 + ventingDirection.getStepZ() * 0.6; + level.playSound(null, posX, posY, posZ, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 1F, 1F); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardCleanerTrait.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardCleanerTrait.java new file mode 100644 index 00000000000..73afc1c5c11 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardCleanerTrait.java @@ -0,0 +1,130 @@ +package com.gregtechceu.gtceu.api.machine.trait.hazard; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; +import com.gregtechceu.gtceu.api.machine.trait.MachineTraitType; +import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.network.GTNetwork; +import com.gregtechceu.gtceu.common.network.packets.hazard.SPacketRemoveHazardZone; +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunk; + +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiPredicate; + +public class EnvironmentalHazardCleanerTrait extends MachineTrait { + + public static final MachineTraitType TYPE = new MachineTraitType<>( + EnvironmentalHazardCleanerTrait.class); + + @Getter + protected float removedLastSecond; + + @Getter + protected float amountPerOperation; + @Getter + protected MedicalCondition conditionToRemove; + @Getter + protected int cleaningRadius; + @Getter + private boolean cleaningOperationInProgress; + + private final @Nullable BiPredicate cleaningHandler; + + public EnvironmentalHazardCleanerTrait(MetaMachine machine, int cleaningRadius, + @Nullable BiPredicate validateCleaningOperation) { + super(machine); + this.cleaningRadius = cleaningRadius; + this.cleaningHandler = validateCleaningOperation; + } + + @Override + public MachineTraitType getTraitType() { + return TYPE; + } + + public boolean cleanHazard(MedicalCondition condition, float totalAmountToRemove) { + if (cleaningHandler == null) return beginCleaningOperation(condition, totalAmountToRemove); + return cleaningHandler.test(condition, totalAmountToRemove); + } + + public boolean beginCleaningOperation(MedicalCondition condition, float amountPerOperation) { + if (cleaningOperationInProgress) return false; + + this.conditionToRemove = condition; + this.amountPerOperation = amountPerOperation; + this.cleaningOperationInProgress = true; + return true; + } + + public void endCleaningOperation() { + this.cleaningOperationInProgress = false; + } + + public void cleanHazard() { + if (!cleaningOperationInProgress) return; + if (machine.getOffsetTimer() % 20 == 0) { + removedLastSecond = 0; + + for (Direction dir : GTUtil.DIRECTIONS) { + BlockPos offset = getBlockPos().relative(dir); + if (GTCapabilityHelper.getHazardContainer(getLevel(), offset, dir.getOpposite()) != null) { + if (getLevel().getBlockEntity(offset) instanceof DuctPipeBlockEntity duct && + !duct.isConnected(dir.getOpposite())) { + continue; + } + return; + } + } + + final ServerLevel serverLevel = (ServerLevel) getLevel(); + EnvironmentalHazardSavedData savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + + final ChunkPos pos = new ChunkPos(getBlockPos()); + Object2FloatMap relativePositions = new Object2FloatOpenHashMap<>(); + if (cleaningRadius <= 0) { + // LV scrubber can only process the chunk it's in + relativePositions.put(pos, 1); + } else { + for (int x = -cleaningRadius; x <= cleaningRadius; ++x) { + for (int z = -cleaningRadius; z <= cleaningRadius; ++z) { + relativePositions.put(new ChunkPos(pos.x + x, pos.z + z), Mth.sqrt(Mth.abs(x * z)) + 1); + } + } + } + for (ChunkPos rel : relativePositions.keySet()) { + final float distance = relativePositions.getFloat(rel); + savedData.getHazardZones().compute(rel, (chunkPos, zone) -> { + if (zone == null || zone.strength() <= 0) { + return null; + } + + float toClean = amountPerOperation / distance; + removedLastSecond += toClean; + zone.removeStrength(toClean); + if (zone.strength() <= 0) { + if (serverLevel.hasChunk(chunkPos.x, chunkPos.z)) { + LevelChunk chunk = serverLevel.getChunk(chunkPos.x, chunkPos.z); + GTNetwork.sendToAllPlayersTrackingChunk(chunk, new SPacketRemoveHazardZone(chunkPos)); + } + return null; + } else return zone; + }); + } + } + return; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardEmitterTrait.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardEmitterTrait.java new file mode 100644 index 00000000000..f3dce5ffe4a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/EnvironmentalHazardEmitterTrait.java @@ -0,0 +1,64 @@ +package com.gregtechceu.gtceu.api.machine.trait.hazard; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; +import com.gregtechceu.gtceu.api.machine.trait.MachineTraitType; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.config.ConfigHolder; + +import net.minecraft.server.level.ServerLevel; + +import lombok.Getter; +import lombok.Setter; + +/** + * trait for environmental hazard (e.g. pollution) emitters like mufflers. + */ +public class EnvironmentalHazardEmitterTrait extends MachineTrait { + + public static final MachineTraitType TYPE = new MachineTraitType<>( + EnvironmentalHazardEmitterTrait.class); + + @Getter + @Setter + protected float emissionStrength; + @Getter + @Setter + protected MedicalCondition conditionToEmit; + + public EnvironmentalHazardEmitterTrait(MetaMachine machine, MedicalCondition conditionToEmit, + float emissionStrength) { + super(machine); + this.conditionToEmit = conditionToEmit; + this.emissionStrength = emissionStrength; + } + + @Override + public MachineTraitType getTraitType() { + return TYPE; + } + + public void emitHazard() { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { + return; + } + + if (getLevel() instanceof ServerLevel serverLevel) { + IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, + getBlockPos().relative(machine.getFrontFacing()), machine.getFrontFacing().getOpposite()); + if (container != null && + container.getHazardCanBeInserted(getConditionToEmit()) > getEmissionStrength()) { + container.addHazard(getConditionToEmit(), getEmissionStrength()); + return; + } + + var savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + savedData.addZone(getBlockPos(), getEmissionStrength(), true, + HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/LocalizedHazardEmitterTrait.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/LocalizedHazardEmitterTrait.java new file mode 100644 index 00000000000..8192765380b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/LocalizedHazardEmitterTrait.java @@ -0,0 +1,64 @@ +package com.gregtechceu.gtceu.api.machine.trait.hazard; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.MachineTrait; +import com.gregtechceu.gtceu.api.machine.trait.MachineTraitType; +import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; +import com.gregtechceu.gtceu.config.ConfigHolder; + +import net.minecraft.server.level.ServerLevel; + +import lombok.Getter; +import lombok.Setter; + +/** + * trait for localized hazard (e.g. radiation) emitters like nuclear reactors. + */ +public class LocalizedHazardEmitterTrait extends MachineTrait { + + public static final MachineTraitType TYPE = new MachineTraitType<>( + LocalizedHazardEmitterTrait.class); + + @Getter + @Setter + private MedicalCondition conditionToEmit; + @Getter + @Setter + private int conditionStrength; + + public LocalizedHazardEmitterTrait(MetaMachine machine, MedicalCondition conditionToEmit, + int defaultConditionStrength) { + super(machine); + this.conditionToEmit = conditionToEmit; + this.conditionStrength = defaultConditionStrength; + } + + @Override + public MachineTraitType getTraitType() { + return TYPE; + } + + public void spreadHazard() { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { + return; + } + + if (getLevel() instanceof ServerLevel serverLevel) { + IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, + getBlockPos().relative(machine.getFrontFacing()), machine.getFrontFacing().getOpposite()); + if (container != null && + container.getHazardCanBeInserted(getConditionToEmit()) > getConditionStrength()) { + container.addHazard(getConditionToEmit(), getConditionStrength()); + return; + } + + var savedData = LocalizedHazardSavedData.getOrCreate(serverLevel); + savedData.addSphericalZone(getBlockPos(), getConditionStrength(), false, + HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/package-info.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/package-info.java new file mode 100644 index 00000000000..a4d86990353 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/hazard/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.api.machine.trait.hazard; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java index 95cffc6ee83..548e1c613a5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java +++ b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java @@ -5,8 +5,8 @@ import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity; import com.gregtechceu.gtceu.api.capability.forge.GTCapability; import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardCleanerTrait; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardEmitterTrait; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider; import com.gregtechceu.gtceu.client.model.pipe.PipeModel; @@ -88,8 +88,10 @@ public boolean canPipeConnectToBlock(IPipeNode @Nullable BlockEntity tile) { return tile != null && (tile.getCapability(GTCapability.CAPABILITY_HAZARD_CONTAINER, side.getOpposite()).isPresent() || - tile instanceof MetaMachine metaMachine && (tile instanceof IEnvironmentalHazardCleaner || - tile instanceof IEnvironmentalHazardEmitter)); + tile instanceof MetaMachine metaMachine && + (metaMachine.getTraitHolder().getTrait(EnvironmentalHazardCleanerTrait.TYPE) != null || + metaMachine.getTraitHolder().getTrait(EnvironmentalHazardEmitterTrait.TYPE) != + null)); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java index 6a4a060339f..8c4b4c34667 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java @@ -5,8 +5,9 @@ import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; import com.gregtechceu.gtceu.api.capability.forge.GTCapability; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardCleanerTrait; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardEmitterTrait; import com.gregtechceu.gtceu.common.pipelike.duct.*; import com.gregtechceu.gtceu.utils.GTUtil; @@ -110,10 +111,11 @@ public boolean canAttachTo(Direction side) { return false; } BlockPos relative = getBlockPos().relative(side); - return GTCapabilityHelper.getHazardContainer(level, relative, side.getOpposite()) != - null || - (level.getBlockEntity(relative) instanceof IEnvironmentalHazardCleaner || - level.getBlockEntity(relative) instanceof IEnvironmentalHazardEmitter); + MetaMachine adjacent = MetaMachine.getMachine(level, relative); + return GTCapabilityHelper.getHazardContainer(level, relative, side.getOpposite()) != null || + (adjacent != null && + (adjacent.getTraitHolder().getTrait(EnvironmentalHazardEmitterTrait.TYPE) != null || + adjacent.getTraitHolder().getTrait(EnvironmentalHazardCleanerTrait.TYPE) != null)); } return false; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java index 2b4458f88e3..ecdbbc256b5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java @@ -1,48 +1,36 @@ package com.gregtechceu.gtceu.common.machine.electric; import com.gregtechceu.gtceu.api.blockentity.BlockEntityCreationInfo; -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.machine.SimpleTieredMachine; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardCleanerTrait; import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; -import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; import com.gregtechceu.gtceu.common.data.GTRecipeTypes; import com.gregtechceu.gtceu.common.data.machines.GTMachineUtils; -import com.gregtechceu.gtceu.common.network.GTNetwork; -import com.gregtechceu.gtceu.common.network.packets.hazard.SPacketRemoveHazardZone; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; -import com.gregtechceu.gtceu.utils.GTUtil; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.LevelChunk; - -import it.unimi.dsi.fastutil.objects.Object2FloatMap; -import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; import lombok.Getter; import org.jetbrains.annotations.Nullable; import static com.gregtechceu.gtceu.api.GTValues.LV; import static com.gregtechceu.gtceu.api.GTValues.VHA; -public class AirScrubberMachine extends SimpleTieredMachine implements IEnvironmentalHazardCleaner { +public class AirScrubberMachine extends SimpleTieredMachine { public static final float MIN_CLEANING_PER_OPERATION = 10; - private float cleaningPerOperation; + private MedicalCondition currentRecipeMedicalCondition; @Getter private float removedLastSecond; + @Getter + private final EnvironmentalHazardCleanerTrait cleanerTrait; + public AirScrubberMachine(BlockEntityCreationInfo info, int tier) { super(info, tier, GTMachineUtils.largeTankSizeFunction); - this.cleaningPerOperation = MIN_CLEANING_PER_OPERATION; + this.cleanerTrait = new EnvironmentalHazardCleanerTrait(this, tier / 2, this::validateCleaningOperation); } @Override @@ -50,16 +38,17 @@ public boolean regressWhenWaiting() { return false; } - @Override - public void cleanHazard(MedicalCondition condition, float amount) { + public boolean validateCleaningOperation(MedicalCondition condition, float amount) { if (this.recipeLogic.isActive()) { - return; + return false; } + currentRecipeMedicalCondition = condition; + GTRecipeBuilder builder = GTRecipeTypes.AIR_SCRUBBER_RECIPES.recipeBuilder(condition.name + "_autogen") .duration(200).EUt(VHA[LV]); condition.recipeModifier.accept(builder); - this.recipeLogic.checkMatchedRecipeAvailable(builder.buildRawRecipe()); + return this.recipeLogic.checkMatchedRecipeAvailable(builder.buildRawRecipe()); } @Override @@ -72,8 +61,8 @@ public boolean isRecipeLogicAvailable() { public boolean beforeWorking(@Nullable GTRecipe recipe) { if (super.beforeWorking(recipe) && recipe != null) { // Sets the amount of hazard to clean based on the recipe tier, not the machine tier - this.cleaningPerOperation = MIN_CLEANING_PER_OPERATION * (recipe.ocLevel + 1); - return true; + return cleanerTrait.beginCleaningOperation(currentRecipeMedicalCondition, + MIN_CLEANING_PER_OPERATION * (recipe.ocLevel + 1)); } return false; } @@ -83,57 +72,12 @@ public boolean onWorking() { if (!super.onWorking() || !ConfigHolder.INSTANCE.gameplay.environmentalHazards) { return false; } - - if (getOffsetTimer() % 20 == 0) { - removedLastSecond = 0; - - for (Direction dir : GTUtil.DIRECTIONS) { - BlockPos offset = getBlockPos().relative(dir); - if (GTCapabilityHelper.getHazardContainer(getLevel(), offset, dir.getOpposite()) != null) { - if (getLevel().getBlockEntity(offset) instanceof DuctPipeBlockEntity duct && - !duct.isConnected(dir.getOpposite())) { - continue; - } - return true; - } - } - - final ServerLevel serverLevel = (ServerLevel) getLevel(); - EnvironmentalHazardSavedData savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); - - final ChunkPos pos = new ChunkPos(getBlockPos()); - Object2FloatMap relativePositions = new Object2FloatOpenHashMap<>(); - int radius = tier / 2; - if (radius <= 0) { - // LV scrubber can only process the chunk it's in - relativePositions.put(pos, 1); - } else { - for (int x = -radius; x <= radius; ++x) { - for (int z = -radius; z <= radius; ++z) { - relativePositions.put(new ChunkPos(pos.x + x, pos.z + z), Mth.sqrt(Mth.abs(x * z)) + 1); - } - } - } - for (ChunkPos rel : relativePositions.keySet()) { - final float distance = relativePositions.getFloat(rel); - savedData.getHazardZones().compute(rel, (chunkPos, zone) -> { - if (zone == null || zone.strength() <= 0) { - return null; - } - - float toClean = cleaningPerOperation / distance; - removedLastSecond += toClean; - zone.removeStrength(toClean); - if (zone.strength() <= 0) { - if (serverLevel.hasChunk(chunkPos.x, chunkPos.z)) { - LevelChunk chunk = serverLevel.getChunk(chunkPos.x, chunkPos.z); - GTNetwork.sendToAllPlayersTrackingChunk(chunk, new SPacketRemoveHazardZone(chunkPos)); - } - return null; - } else return zone; - }); - } - } + cleanerTrait.cleanHazard(); return true; } + + @Override + public void afterWorking() { + cleanerTrait.endCleaningOperation(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 46006d60b70..1a15abaee0b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -11,7 +11,6 @@ import com.gregtechceu.gtceu.api.machine.feature.IDataInfoProvider; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IDisplayUIMachine; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMaintenanceMachine; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMufflerMachine; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart; import com.gregtechceu.gtceu.api.machine.multiblock.CleanroomType; import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; @@ -31,6 +30,7 @@ import com.gregtechceu.gtceu.common.machine.multiblock.generator.LargeCombustionEngineMachine; import com.gregtechceu.gtceu.common.machine.multiblock.generator.LargeTurbineMachine; import com.gregtechceu.gtceu.common.machine.multiblock.part.DiodePartMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.part.MufflerPartMachine; import com.gregtechceu.gtceu.common.machine.multiblock.primitive.CokeOvenMachine; import com.gregtechceu.gtceu.common.machine.multiblock.primitive.PrimitiveBlastFurnaceMachine; import com.gregtechceu.gtceu.common.machine.multiblock.primitive.PrimitivePumpMachine; @@ -441,7 +441,7 @@ public boolean addCache() { protected boolean isMachineBanned(MetaMachine machine) { // blacklisted machines: mufflers and all generators, miners/drills, primitives if (machine.getTraitHolder().getTrait(CleanroomProviderTrait.TYPE) != null) return true; - if (machine instanceof IMufflerMachine) return true; + if (machine instanceof MufflerPartMachine) return true; if (machine instanceof SimpleGeneratorMachine) return true; if (machine instanceof LargeCombustionEngineMachine) return true; if (machine instanceof LargeTurbineMachine) return true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MufflerPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MufflerPartMachine.java index f0b24e28460..9287241ef37 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MufflerPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MufflerPartMachine.java @@ -2,17 +2,23 @@ import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.blockentity.BlockEntityCreationInfo; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.UITemplate; import com.gregtechceu.gtceu.api.gui.widget.SlotWidget; import com.gregtechceu.gtceu.api.machine.TickableSubscription; import com.gregtechceu.gtceu.api.machine.feature.IRecipeLogicMachine; import com.gregtechceu.gtceu.api.machine.feature.IUIMachine; -import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMufflerMachine; +import com.gregtechceu.gtceu.api.machine.feature.multiblock.IWorkableMultiController; import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredPartMachine; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardEmitterTrait; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; +import com.gregtechceu.gtceu.common.data.GTParticleTypes; import com.gregtechceu.gtceu.utils.GTUtil; import com.lowdragmc.lowdraglib.gui.modular.ModularUI; @@ -28,6 +34,7 @@ import lombok.Getter; import org.jetbrains.annotations.MustBeInvokedByOverriders; +import org.jetbrains.annotations.Nullable; import java.util.stream.IntStream; @@ -35,7 +42,7 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class MufflerPartMachine extends TieredPartMachine implements IMufflerMachine, IUIMachine { +public class MufflerPartMachine extends TieredPartMachine implements IUIMachine { @Getter private final int recoveryChance; @@ -44,18 +51,21 @@ public class MufflerPartMachine extends TieredPartMachine implements IMufflerMac private final CustomItemStackHandler inventory; private TickableSubscription snowSubscription; + @Getter + private final EnvironmentalHazardEmitterTrait hazardEmitter; public MufflerPartMachine(BlockEntityCreationInfo info, int tier) { super(info, tier); this.recoveryChance = Math.max(1, tier * 10); this.inventory = new CustomItemStackHandler((int) Math.pow(tier + 1, 2)); + this.hazardEmitter = new EnvironmentalHazardEmitterTrait(this, GTMedicalConditions.CARBON_MONOXIDE_POISONING, + 2.5f / Math.max(tier, 1)); } ////////////////////////////////////// // ******** Muffler *********// ////////////////////////////////////// - @Override public void recoverItemsTable(ItemStack... recoveryItems) { int numRolls = Math.min(recoveryItems.length, inventory.getSlots()); IntStream.range(0, numRolls).forEach(slot -> { @@ -82,6 +92,21 @@ public void clientTick() { } } + @Override + public @Nullable GTRecipe modifyRecipe(GTRecipe recipe) { + return isFrontFaceFree() ? recipe : super.modifyRecipe(recipe); + } + + @Override + public boolean afterWorking(IWorkableMultiController controller) { + hazardEmitter.emitHazard(); + var supplier = controller.self().getDefinition().getRecoveryItems(); + if (supplier != null) { + recoverItemsTable(supplier.get()); + } + return super.afterWorking(controller); + } + @Override public void addedToController(MultiblockControllerMachine controller) { super.addedToController(controller); @@ -112,6 +137,38 @@ private void tryBreakSnow() { } } + public boolean isFrontFaceFree() { + var frontPos = self().getBlockPos().relative(self().getFrontFacing()); + return self().getLevel().getBlockState(frontPos).isAir() || + GTCapabilityHelper.getHazardContainer(self().getLevel(), + frontPos, self().getFrontFacing().getOpposite()) != null; + } + + public void emitPollutionParticles() { + var pos = self().getBlockPos(); + var facing = self().getFrontFacing(); + + IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(self().getLevel(), + pos.relative(facing), facing.getOpposite()); + if (container != null) { + // do not emit particles if front face has a duct on it. + return; + } + + var center = pos.getCenter(); + var offset = .75f; + var xPos = (float) (center.x + facing.getStepX() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); + var yPos = (float) (center.y + facing.getStepY() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); + var zPos = (float) (center.z + facing.getStepZ() * offset + (GTValues.RNG.nextFloat() - .5f) * .35f); + + var ySpd = facing.getStepY() + (GTValues.RNG.nextFloat() - .15f) * .5f; + var xSpd = facing.getStepX() + (GTValues.RNG.nextFloat() - .5f) * .5f; + var zSpd = facing.getStepZ() + (GTValues.RNG.nextFloat() - .5f) * .5f; + + self().getLevel().addParticle(GTParticleTypes.MUFFLER_PARTICLE.get(), + xPos, yPos, zPos, xSpd, ySpd, zSpd); + } + ////////////////////////////////////// // ********** GUI ***********// ////////////////////////////////////// diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java index 69e17bf6007..0c525dd8c36 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java @@ -4,21 +4,23 @@ import com.gregtechceu.gtceu.api.capability.recipe.FluidRecipeCapability; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.capability.recipe.ItemRecipeCapability; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableMultiblockMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardEmitterTrait; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraftforge.fluids.FluidType; +import lombok.Getter; + import javax.annotation.ParametersAreNonnullByDefault; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class PrimitiveWorkableMachine extends WorkableMultiblockMachine - implements IEnvironmentalHazardEmitter { +public class PrimitiveWorkableMachine extends WorkableMultiblockMachine { @SaveField public final NotifiableItemStackHandler importItems; @@ -29,12 +31,17 @@ public class PrimitiveWorkableMachine extends WorkableMultiblockMachine @SaveField public final NotifiableFluidTank exportFluids; + @Getter + private final EnvironmentalHazardEmitterTrait hazardEmitter; + public PrimitiveWorkableMachine(BlockEntityCreationInfo info) { super(info); this.importItems = createImportItemHandler(); this.exportItems = createExportItemHandler(); this.importFluids = createImportFluidHandler(); this.exportFluids = createExportFluidHandler(); + this.hazardEmitter = new EnvironmentalHazardEmitterTrait(this, GTMedicalConditions.CARBON_MONOXIDE_POISONING, + 0.1f); } ////////////////////////////////////// @@ -66,14 +73,9 @@ public void onMachineDestroyed() { exportItems.dropInventoryInWorld(); } - @Override - public float getHazardStrengthPerOperation() { - return 0.1f; - } - @Override public void afterWorking() { super.afterWorking(); - spreadEnvironmentalHazard(); + hazardEmitter.emitHazard(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamMinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamMinerMachine.java index 664a0cb5a73..9af41453752 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamMinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamMinerMachine.java @@ -11,9 +11,9 @@ import com.gregtechceu.gtceu.api.machine.TickableSubscription; import com.gregtechceu.gtceu.api.machine.feature.*; import com.gregtechceu.gtceu.api.machine.steam.SteamWorkableMachine; +import com.gregtechceu.gtceu.api.machine.trait.ExhaustVentMachineTrait; import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; -import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient; import com.gregtechceu.gtceu.common.item.PortableScannerBehavior; import com.gregtechceu.gtceu.common.machine.trait.miner.SteamMinerLogic; import com.gregtechceu.gtceu.utils.GTTransferUtils; @@ -47,13 +47,9 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class SteamMinerMachine extends SteamWorkableMachine implements IControllable, IExhaustVentMachine, +public class SteamMinerMachine extends SteamWorkableMachine implements IControllable, IUIMachine, IDataInfoProvider, IMiner { - @Getter - @SaveField - @SyncToClient - private boolean needsVenting; @SaveField public final NotifiableItemStackHandler importItems; @SaveField @@ -65,6 +61,9 @@ public class SteamMinerMachine extends SteamWorkableMachine implements IControll @Nullable protected ISubscription exportItemSubs; + @Getter + private final ExhaustVentMachineTrait exhaustVentTrait; + public SteamMinerMachine(BlockEntityCreationInfo info, boolean isHighPressure, int speed, int maximumRadius, int fortune, int energyPerTick) { super(info, isHighPressure, (m) -> new SteamMinerLogic(m, fortune, speed, maximumRadius)); @@ -73,6 +72,9 @@ public SteamMinerMachine(BlockEntityCreationInfo info, boolean isHighPressure, i this.energyPerTick = energyPerTick; this.importItems = createImportItemHandler(); this.exportItems = createExportItemHandler(); + this.exhaustVentTrait = new ExhaustVentMachineTrait(this); + exhaustVentTrait.setVentingDirection(Direction.UP); + exhaustVentTrait.setVentingDamageAmount(isHighPressure() ? 12F : 6F); } @Override @@ -143,11 +145,6 @@ protected void autoOutput() { updateAutoOutputSubscription(); } - public void setNeedsVenting(boolean venting) { - this.needsVenting = venting; - syncDataHolder.markClientSyncFieldDirty("needsVenting"); - } - ////////////////////////////////////// // *********** GUI ***********// ////////////////////////////////////// @@ -198,7 +195,7 @@ else if (!this.isWorkingEnabled()) if (getRecipeLogic().isInventoryFull()) textList.add(Component.translatable("gtceu.multiblock.large_miner.invfull") .withStyle(ChatFormatting.RED)); - if (isVentingBlocked()) + if (exhaustVentTrait.isVentingBlocked()) textList.add(Component.translatable("gtceu.multiblock.large_miner.vent") .withStyle(ChatFormatting.RED)); else if (!drainInput(true)) @@ -215,7 +212,7 @@ void addDisplayText2(List textList) { @Override public boolean drainInput(boolean simulate) { long resultSteam = steamTank.getFluidInTank(0).getAmount() - energyPerTick; - if (!this.isVentingBlocked() && resultSteam >= 0L && resultSteam <= steamTank.getTankCapacity(0)) { + if (!exhaustVentTrait.isVentingBlocked() && resultSteam >= 0L && resultSteam <= steamTank.getTankCapacity(0)) { if (!simulate) steamTank.drainInternal(energyPerTick, IFluidHandler.FluidAction.EXECUTE); return true; @@ -223,21 +220,6 @@ public boolean drainInput(boolean simulate) { return false; } - @Override - public @NotNull Direction getVentingDirection() { - return Direction.UP; - } - - @Override - public void markVentingComplete() { - this.needsVenting = false; - } - - @Override - public float getVentingDamage() { - return isHighPressure() ? 12F : 6F; - } - @NotNull @Override public List getDataInfo(PortableScannerBehavior.DisplayMode mode) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/SteamMinerLogic.java b/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/SteamMinerLogic.java index 5e5753a1e5d..3435e999ebf 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/SteamMinerLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/SteamMinerLogic.java @@ -1,10 +1,12 @@ package com.gregtechceu.gtceu.common.machine.trait.miner; -import com.gregtechceu.gtceu.api.machine.feature.IExhaustVentMachine; import com.gregtechceu.gtceu.api.machine.feature.IRecipeLogicMachine; +import com.gregtechceu.gtceu.common.machine.steam.SteamMinerMachine; public class SteamMinerLogic extends MinerLogic { + private final SteamMinerMachine steamMiner; + /** * Creates the logic for steam miners * @@ -15,17 +17,17 @@ public class SteamMinerLogic extends MinerLogic { */ public SteamMinerLogic(IRecipeLogicMachine metaTileEntity, int fortune, int speed, int maximumRadius) { super(metaTileEntity, fortune, speed, maximumRadius); + steamMiner = (SteamMinerMachine) metaTileEntity; } @Override protected boolean checkCanMine() { - IExhaustVentMachine machine = (IExhaustVentMachine) this.machine; - return super.checkCanMine() && machine.checkVenting(); + return super.checkCanMine() && steamMiner.getExhaustVentTrait().checkVenting(); } @Override protected void onMineOperation() { super.onMineOperation(); - ((IExhaustVentMachine) machine).setNeedsVenting(true); + steamMiner.getExhaustVentTrait().setNeedsVenting(true); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java index 913860aab60..754537f5165 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java @@ -4,7 +4,8 @@ import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner; +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardCleanerTrait; import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; @@ -65,9 +66,12 @@ public float changeHazard(MedicalCondition condition, float differenceAmount) { IHazardParticleContainer handler = path.getHandler(net.getLevel()); if (handler == null && path.getTargetPipe().isConnected(path.getTargetFacing())) { if (net.getLevel().getBlockEntity(path.getTargetPipePos() - .relative(path.getTargetFacing())) instanceof IEnvironmentalHazardCleaner cleaner) { - cleaner.cleanHazard(condition, differenceAmount); - break; + .relative(path.getTargetFacing())) instanceof MetaMachine machine) { + var cleanerTrait = machine.getTraitHolder().getTrait(EnvironmentalHazardCleanerTrait.TYPE); + if (cleanerTrait != null) { + cleanerTrait.cleanHazard(condition, differenceAmount); + break; + } } var savedData = EnvironmentalHazardSavedData.getOrCreate(net.getLevel()); diff --git a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/VentCondition.java b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/VentCondition.java index b0b1aed1b27..29c155831e6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/VentCondition.java +++ b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/VentCondition.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.common.recipe.condition; -import com.gregtechceu.gtceu.api.machine.feature.IExhaustVentMachine; +import com.gregtechceu.gtceu.api.machine.trait.ExhaustVentMachineTrait; import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.RecipeCondition; @@ -35,8 +35,9 @@ public Component getTooltips() { @Override public boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) { - if (recipeLogic.getProgress() % 10 == 0 && recipeLogic.machine instanceof IExhaustVentMachine ventMachine) { - return !(ventMachine.isNeedsVenting() && ventMachine.isVentingBlocked()); + var ventTrait = recipeLogic.machine.self().getTraitHolder().getTrait(ExhaustVentMachineTrait.TYPE); + if (recipeLogic.getProgress() % 10 == 0 && ventTrait != null) { + return !(ventTrait.isNeedsVenting() && ventTrait.isVentingBlocked()); } return true; } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ExhaustVentBlockProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ExhaustVentBlockProvider.java index 6c9004ece1d..27742384dc9 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ExhaustVentBlockProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ExhaustVentBlockProvider.java @@ -1,50 +1,31 @@ package com.gregtechceu.gtceu.integration.jade.provider; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.machine.MetaMachine; -import com.gregtechceu.gtceu.api.machine.feature.IExhaustVentMachine; +import com.gregtechceu.gtceu.api.machine.trait.ExhaustVentMachineTrait; import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; import snownee.jade.api.BlockAccessor; import snownee.jade.api.ITooltip; import snownee.jade.api.config.IPluginConfig; -public class ExhaustVentBlockProvider extends BlockInfoProvider { +public class ExhaustVentBlockProvider extends MachineTraitProvider { public ExhaustVentBlockProvider() { - super(GTCEu.id("exhaust_vent_info")); + super(GTCEu.id("exhaust_vent_info"), ExhaustVentMachineTrait.TYPE); } - @Nullable @Override - protected IExhaustVentMachine getCapability(Level level, BlockPos blockPos) { - if (MetaMachine.getMachine(level, blockPos) instanceof IExhaustVentMachine exhaustVentMachine) { - return exhaustVentMachine; - } - return null; - } - - @Override - protected boolean allowDisplaying(IExhaustVentMachine capability) { - return super.allowDisplaying(capability); - } - - @Override - protected void write(CompoundTag compoundTag, IExhaustVentMachine iExhaustVentMachine, - BlockAccessor blockAccessor) { - var direction = iExhaustVentMachine.getVentingDirection(); + protected void write(CompoundTag compoundTag, BlockAccessor blockAccessor, ExhaustVentMachineTrait trait) { + var direction = trait.getVentingDirection(); compoundTag.putString("ventDirection", direction.getName()); var level = blockAccessor.getLevel(); var pos = blockAccessor.getPosition().relative(direction); @@ -52,8 +33,8 @@ protected void write(CompoundTag compoundTag, IExhaustVentMachine iExhaustVentMa var key = BuiltInRegistries.BLOCK.getKey(level.getBlockState(pos).getBlock()); compoundTag.putString("ventBlock", key.toString()); } - compoundTag.putBoolean("ventBlocked", iExhaustVentMachine.isVentingBlocked()); - compoundTag.putBoolean("needsVenting", iExhaustVentMachine.isNeedsVenting()); + compoundTag.putBoolean("ventBlocked", trait.isVentingBlocked()); + compoundTag.putBoolean("needsVenting", trait.isNeedsVenting()); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/HazardCleanerBlockProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/HazardCleanerBlockProvider.java index d0d02160ae4..769f2d95c0b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/HazardCleanerBlockProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/HazardCleanerBlockProvider.java @@ -1,34 +1,25 @@ package com.gregtechceu.gtceu.integration.jade.provider; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner; +import com.gregtechceu.gtceu.api.machine.trait.hazard.EnvironmentalHazardCleanerTrait; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import org.jetbrains.annotations.Nullable; import snownee.jade.api.BlockAccessor; import snownee.jade.api.ITooltip; import snownee.jade.api.config.IPluginConfig; -public class HazardCleanerBlockProvider extends CapabilityBlockProvider { +public class HazardCleanerBlockProvider extends MachineTraitProvider { public HazardCleanerBlockProvider() { - super(GTCEu.id("hazard_cleaner_provider")); + super(GTCEu.id("hazard_cleaner_provider"), EnvironmentalHazardCleanerTrait.TYPE); } @Override - protected @Nullable IEnvironmentalHazardCleaner getCapability(Level level, BlockPos pos, @Nullable Direction side) { - return level.getBlockEntity(pos) instanceof IEnvironmentalHazardCleaner cleaner ? cleaner : null; - } - - @Override - protected void write(CompoundTag data, IEnvironmentalHazardCleaner capability) { + protected void write(CompoundTag data, BlockAccessor block, EnvironmentalHazardCleanerTrait capability) { data.putFloat("Cleaned", capability.getRemovedLastSecond()); }