mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-14 06:24:29 +01:00
Allow registration of custom fan processing types
- Fix crash on startup
This commit is contained in:
parent
8f5031c330
commit
2a1c6e6916
@ -14,8 +14,8 @@ import com.simibubi.create.content.kinetics.crafter.MechanicalCraftingRecipe;
|
||||
import com.simibubi.create.content.kinetics.crusher.CrushingRecipe;
|
||||
import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe;
|
||||
import com.simibubi.create.content.kinetics.deployer.ManualApplicationRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.HauntingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.SplashingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.HauntingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.SplashingRecipe;
|
||||
import com.simibubi.create.content.kinetics.millstone.MillingRecipe;
|
||||
import com.simibubi.create.content.kinetics.mixer.CompactingRecipe;
|
||||
import com.simibubi.create.content.kinetics.mixer.MixingRecipe;
|
||||
|
@ -17,6 +17,7 @@ import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.BuiltinPotatoProjectileTypes;
|
||||
import com.simibubi.create.content.fluids.tank.BoilerHeaters;
|
||||
import com.simibubi.create.content.kinetics.TorquePropagator;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
|
||||
import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes;
|
||||
import com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours;
|
||||
import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler;
|
||||
@ -138,9 +139,8 @@ public class Create {
|
||||
AllDisplayBehaviours.registerDefaults();
|
||||
ContraptionMovementSetting.registerDefaults();
|
||||
AllArmInteractionPointTypes.register();
|
||||
AllFanProcessingTypes.register();
|
||||
BlockSpoutingBehaviour.registerDefaults();
|
||||
BoilerHeaters.registerDefaults();
|
||||
BuiltinPotatoProjectileTypes.register();
|
||||
BogeySizes.init();
|
||||
AllBogeyStyles.register();
|
||||
// ----
|
||||
@ -164,6 +164,13 @@ public class Create {
|
||||
|
||||
public static void init(final FMLCommonSetupEvent event) {
|
||||
event.enqueueWork(() -> {
|
||||
// TODO: custom registration should all happen in one place
|
||||
// Most registration happens in the constructor.
|
||||
// These registrations use Create's registered objects directly so they must run after registration has finished.
|
||||
BuiltinPotatoProjectileTypes.register();
|
||||
BoilerHeaters.registerDefaults();
|
||||
// --
|
||||
|
||||
AttachedRegistry.unwrapAll();
|
||||
AllAdvancements.register();
|
||||
AllTriggers.register();
|
||||
|
@ -51,8 +51,8 @@ import com.simibubi.create.content.kinetics.crusher.AbstractCrushingRecipe;
|
||||
import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe;
|
||||
import com.simibubi.create.content.kinetics.deployer.ItemApplicationRecipe;
|
||||
import com.simibubi.create.content.kinetics.deployer.ManualApplicationRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.HauntingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.SplashingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.HauntingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.SplashingRecipe;
|
||||
import com.simibubi.create.content.kinetics.press.MechanicalPressBlockEntity;
|
||||
import com.simibubi.create.content.kinetics.press.PressingRecipe;
|
||||
import com.simibubi.create.content.kinetics.saw.CuttingRecipe;
|
||||
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics;
|
||||
import com.simibubi.create.content.kinetics.fan.HauntingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.HauntingRecipe;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
import com.simibubi.create.foundation.gui.element.GuiGameElement;
|
||||
|
||||
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics;
|
||||
import com.simibubi.create.content.kinetics.fan.SplashingRecipe;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.SplashingRecipe;
|
||||
import com.simibubi.create.foundation.gui.element.GuiGameElement;
|
||||
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
@ -337,7 +337,7 @@ public class BlockMovementChecks {
|
||||
return direction == state.getValue(StickerBlock.FACING)
|
||||
&& !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite());
|
||||
}
|
||||
if (block instanceof AbstractBogeyBlock bogey)
|
||||
if (block instanceof AbstractBogeyBlock<?> bogey)
|
||||
return bogey.getStickySurfaces(world, pos, state)
|
||||
.contains(direction);
|
||||
if (block instanceof WhistleBlock)
|
||||
|
@ -3,7 +3,7 @@ package com.simibubi.create.content.kinetics.belt.transport;
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.content.kinetics.belt.BeltHelper;
|
||||
import com.simibubi.create.content.kinetics.fan.FanProcessing;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@ -25,7 +25,7 @@ public class TransportedItemStack implements Comparable<TransportedItemStack> {
|
||||
public float prevBeltPosition;
|
||||
public float prevSideOffset;
|
||||
|
||||
public FanProcessing.Type processedBy;
|
||||
public FanProcessingType processedBy;
|
||||
public int processingTime;
|
||||
|
||||
public TransportedItemStack(ItemStack stack) {
|
||||
|
@ -10,7 +10,9 @@ import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.decoration.copycat.CopycatBlock;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult;
|
||||
import com.simibubi.create.content.kinetics.fan.FanProcessing.Type;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.FanProcessing;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
@ -29,7 +31,6 @@ import net.minecraft.world.entity.item.ItemEntity;
|
||||
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.material.Fluids;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@ -49,7 +50,7 @@ public class AirCurrent {
|
||||
public boolean pushing;
|
||||
public float maxDistance;
|
||||
|
||||
protected List<Pair<TransportedItemStackHandlerBehaviour, FanProcessing.Type>> affectedItemHandlers =
|
||||
protected List<Pair<TransportedItemStackHandlerBehaviour, FanProcessingType>> affectedItemHandlers =
|
||||
new ArrayList<>();
|
||||
protected List<Entity> caughtEntities = new ArrayList<>();
|
||||
|
||||
@ -110,14 +111,14 @@ public class AirCurrent {
|
||||
((ServerPlayer) entity).connection.aboveGroundTickCount = 0;
|
||||
|
||||
entityDistance -= .5f;
|
||||
FanProcessing.Type processingType = getSegmentAt((float) entityDistance);
|
||||
FanProcessingType processingType = getSegmentAt((float) entityDistance);
|
||||
|
||||
if (processingType == null || processingType == Type.NONE)
|
||||
if (processingType == AllFanProcessingTypes.NONE)
|
||||
continue;
|
||||
|
||||
if (entity instanceof ItemEntity itemEntity) {
|
||||
if (world.isClientSide) {
|
||||
processingType.spawnParticlesForProcessing(world, entity.position());
|
||||
if (world != null && world.isClientSide) {
|
||||
processingType.spawnProcessingParticles(world, entity.position());
|
||||
continue;
|
||||
}
|
||||
if (FanProcessing.canProcess(itemEntity, processingType))
|
||||
@ -127,7 +128,8 @@ public class AirCurrent {
|
||||
continue;
|
||||
}
|
||||
|
||||
processingType.affectEntity(entity, world);
|
||||
if (world != null)
|
||||
processingType.affectEntity(entity, world);
|
||||
}
|
||||
|
||||
}
|
||||
@ -155,7 +157,7 @@ public class AirCurrent {
|
||||
AirCurrentSegment currentSegment = new AirCurrentSegment();
|
||||
segments.clear();
|
||||
currentSegment.startOffset = 0;
|
||||
FanProcessing.Type type = Type.NONE;
|
||||
FanProcessingType type = AllFanProcessingTypes.NONE;
|
||||
|
||||
int limit = (int) (maxDistance + .5f);
|
||||
int searchStart = pushing ? 0 : limit;
|
||||
@ -164,8 +166,8 @@ public class AirCurrent {
|
||||
|
||||
for (int i = searchStart; i * searchStep <= searchEnd * searchStep; i += searchStep) {
|
||||
BlockPos currentPos = start.relative(direction, i);
|
||||
FanProcessing.Type newType = FanProcessing.Type.byBlock(world, currentPos);
|
||||
if (newType != Type.NONE)
|
||||
FanProcessingType newType = FanProcessingType.getAt(world, currentPos);
|
||||
if (newType != AllFanProcessingTypes.NONE)
|
||||
type = newType;
|
||||
if (currentSegment.type != type || currentSegment.startOffset == 0) {
|
||||
currentSegment.endOffset = i;
|
||||
@ -258,21 +260,18 @@ public class AirCurrent {
|
||||
BlockPos start = source.getAirCurrentPos();
|
||||
affectedItemHandlers.clear();
|
||||
for (int i = 0; i < maxDistance + 1; i++) {
|
||||
Type type = getSegmentAt(i);
|
||||
if (type == null)
|
||||
continue;
|
||||
|
||||
FanProcessingType segmentType = getSegmentAt(i);
|
||||
for (int offset : Iterate.zeroAndOne) {
|
||||
BlockPos pos = start.relative(direction, i)
|
||||
.below(offset);
|
||||
TransportedItemStackHandlerBehaviour behaviour =
|
||||
BlockEntityBehaviour.get(world, pos, TransportedItemStackHandlerBehaviour.TYPE);
|
||||
FanProcessing.Type typeAtHandler = type;
|
||||
if (world.getFluidState(pos)
|
||||
.is(Fluids.WATER))
|
||||
typeAtHandler = Type.SPLASHING;
|
||||
if (behaviour != null)
|
||||
affectedItemHandlers.add(Pair.of(behaviour, typeAtHandler));
|
||||
if (behaviour == null)
|
||||
continue;
|
||||
FanProcessingType type = FanProcessingType.getAt(world, pos);
|
||||
if (type == AllFanProcessingTypes.NONE)
|
||||
type = segmentType;
|
||||
affectedItemHandlers.add(Pair.of(behaviour, type));
|
||||
if (direction.getAxis()
|
||||
.isVertical())
|
||||
break;
|
||||
@ -281,15 +280,14 @@ public class AirCurrent {
|
||||
}
|
||||
|
||||
public void tickAffectedHandlers() {
|
||||
for (Pair<TransportedItemStackHandlerBehaviour, Type> pair : affectedItemHandlers) {
|
||||
for (Pair<TransportedItemStackHandlerBehaviour, FanProcessingType> pair : affectedItemHandlers) {
|
||||
TransportedItemStackHandlerBehaviour handler = pair.getKey();
|
||||
Level world = handler.getWorld();
|
||||
FanProcessing.Type processingType = pair.getRight();
|
||||
FanProcessingType processingType = pair.getRight();
|
||||
|
||||
handler.handleProcessingOnAllItems((transported) -> {
|
||||
handler.handleProcessingOnAllItems(transported -> {
|
||||
if (world.isClientSide) {
|
||||
if (world != null)
|
||||
processingType.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported));
|
||||
processingType.spawnProcessingParticles(world, handler.getWorldPositionOf(transported));
|
||||
return TransportedResult.doNothing();
|
||||
}
|
||||
TransportedResult applyProcessing = FanProcessing.applyProcessing(transported, world, processingType);
|
||||
@ -304,7 +302,7 @@ public class AirCurrent {
|
||||
return AllTags.AllBlockTags.FAN_TRANSPARENT.matches(state);
|
||||
}
|
||||
|
||||
public FanProcessing.Type getSegmentAt(float offset) {
|
||||
public FanProcessingType getSegmentAt(float offset) {
|
||||
for (AirCurrentSegment airCurrentSegment : segments) {
|
||||
if (offset > airCurrentSegment.endOffset && pushing)
|
||||
continue;
|
||||
@ -312,11 +310,11 @@ public class AirCurrent {
|
||||
continue;
|
||||
return airCurrentSegment.type;
|
||||
}
|
||||
return FanProcessing.Type.NONE;
|
||||
return AllFanProcessingTypes.NONE;
|
||||
}
|
||||
|
||||
public static class AirCurrentSegment {
|
||||
FanProcessing.Type type;
|
||||
FanProcessingType type;
|
||||
int startOffset;
|
||||
int endOffset;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package com.simibubi.create.content.kinetics.fan;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
@ -14,16 +14,15 @@ import net.minecraft.client.particle.SimpleAnimatedParticle;
|
||||
import net.minecraft.client.particle.SpriteSet;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class AirFlowParticle extends SimpleAnimatedParticle {
|
||||
|
||||
private final IAirCurrentSource source;
|
||||
private final Access access = new Access();
|
||||
|
||||
protected AirFlowParticle(ClientLevel world, IAirCurrentSource source, double x, double y, double z,
|
||||
SpriteSet sprite) {
|
||||
@ -33,11 +32,12 @@ public class AirFlowParticle extends SimpleAnimatedParticle {
|
||||
this.lifetime = 40;
|
||||
hasPhysics = false;
|
||||
selectSprite(7);
|
||||
Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, .25f);
|
||||
Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, random, .25f);
|
||||
this.setPos(x + offset.x, y + offset.y, z + offset.z);
|
||||
this.xo = x;
|
||||
this.yo = y;
|
||||
this.zo = z;
|
||||
setColor(0xEEEEEE);
|
||||
setAlpha(.25f);
|
||||
}
|
||||
|
||||
@ -49,36 +49,44 @@ public class AirFlowParticle extends SimpleAnimatedParticle {
|
||||
@Override
|
||||
public void tick() {
|
||||
if (source == null || source.isSourceRemoved()) {
|
||||
dissipate();
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
this.xo = this.x;
|
||||
this.yo = this.y;
|
||||
this.zo = this.z;
|
||||
if (this.age++ >= this.lifetime) {
|
||||
this.remove();
|
||||
remove();
|
||||
} else {
|
||||
if (source.getAirCurrent() == null || !source.getAirCurrent().bounds.inflate(.25f).contains(x, y, z)) {
|
||||
dissipate();
|
||||
AirCurrent airCurrent = source.getAirCurrent();
|
||||
if (airCurrent == null || !airCurrent.bounds.inflate(.25f).contains(x, y, z)) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 directionVec = Vec3.atLowerCornerOf(source.getAirCurrent().direction.getNormal());
|
||||
Vec3 directionVec = Vec3.atLowerCornerOf(airCurrent.direction.getNormal());
|
||||
Vec3 motion = directionVec.scale(1 / 8f);
|
||||
if (!source.getAirCurrent().pushing)
|
||||
motion = motion.scale(-1);
|
||||
|
||||
double distance = new Vec3(x, y, z).subtract(VecHelper.getCenterOf(source.getAirCurrentPos()))
|
||||
.multiply(directionVec).length() - .5f;
|
||||
if (distance > source.getAirCurrent().maxDistance + 1 || distance < -.25f) {
|
||||
dissipate();
|
||||
if (distance > airCurrent.maxDistance + 1 || distance < -.25f) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
motion = motion.scale(source.getAirCurrent().maxDistance - (distance - 1f)).scale(.5f);
|
||||
selectSprite((int) Mth.clamp((distance / source.getAirCurrent().maxDistance) * 8 + level.random.nextInt(4),
|
||||
0, 7));
|
||||
motion = motion.scale(airCurrent.maxDistance - (distance - 1f)).scale(.5f);
|
||||
|
||||
morphType(distance);
|
||||
FanProcessingType type = getType(distance);
|
||||
if (type == AllFanProcessingTypes.NONE) {
|
||||
setColor(0xEEEEEE);
|
||||
setAlpha(.25f);
|
||||
selectSprite((int) Mth.clamp((distance / airCurrent.maxDistance) * 8 + random.nextInt(4),
|
||||
0, 7));
|
||||
} else {
|
||||
type.morphAirFlow(access, random);
|
||||
selectSprite(random.nextInt(3));
|
||||
}
|
||||
|
||||
xd = motion.x;
|
||||
yd = motion.y;
|
||||
@ -94,68 +102,10 @@ public class AirFlowParticle extends SimpleAnimatedParticle {
|
||||
|
||||
}
|
||||
|
||||
public void morphType(double distance) {
|
||||
private FanProcessingType getType(double distance) {
|
||||
if (source.getAirCurrent() == null)
|
||||
return;
|
||||
FanProcessing.Type type = source.getAirCurrent().getSegmentAt((float) distance);
|
||||
|
||||
if (type == FanProcessing.Type.SPLASHING) {
|
||||
setColor(Color.mixColors(0x4499FF, 0x2277FF, level.random.nextFloat()));
|
||||
setAlpha(1f);
|
||||
selectSprite(level.random.nextInt(3));
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.BUBBLE, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.BUBBLE_POP, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
}
|
||||
|
||||
if (type == FanProcessing.Type.SMOKING) {
|
||||
setColor(Color.mixColors(0x0, 0x555555, level.random.nextFloat()));
|
||||
setAlpha(1f);
|
||||
selectSprite(level.random.nextInt(3));
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.SMOKE, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.LARGE_SMOKE, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
}
|
||||
|
||||
if (type == FanProcessing.Type.HAUNTING) {
|
||||
setColor(Color.mixColors(0x0, 0x126568, level.random.nextFloat()));
|
||||
setAlpha(1f);
|
||||
selectSprite(level.random.nextInt(3));
|
||||
if (level.random.nextFloat() < 1 / 128f)
|
||||
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.SMOKE, x, y, z, xd * .125f, yd * .125f,
|
||||
zd * .125f);
|
||||
}
|
||||
|
||||
if (type == FanProcessing.Type.BLASTING) {
|
||||
setColor(Color.mixColors(0xFF4400, 0xFF8855, level.random.nextFloat()));
|
||||
setAlpha(.5f);
|
||||
selectSprite(level.random.nextInt(3));
|
||||
if (level.random.nextFloat() < 1 / 32f)
|
||||
level.addParticle(ParticleTypes.FLAME, x, y, z, xd * .25f, yd * .25f,
|
||||
zd * .25f);
|
||||
if (level.random.nextFloat() < 1 / 16f)
|
||||
level.addParticle(new BlockParticleOption(ParticleTypes.BLOCK, Blocks.LAVA.defaultBlockState()), x, y,
|
||||
z, xd * .25f, yd * .25f, zd * .25f);
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
setColor(0xEEEEEE);
|
||||
setAlpha(.25f);
|
||||
setSize(.2f, .2f);
|
||||
}
|
||||
}
|
||||
|
||||
private void dissipate() {
|
||||
remove();
|
||||
return AllFanProcessingTypes.NONE;
|
||||
return source.getAirCurrent().getSegmentAt((float) distance);
|
||||
}
|
||||
|
||||
public int getLightColor(float partialTick) {
|
||||
@ -183,4 +133,21 @@ public class AirFlowParticle extends SimpleAnimatedParticle {
|
||||
}
|
||||
}
|
||||
|
||||
private class Access implements FanProcessingType.AirFlowParticleAccess {
|
||||
@Override
|
||||
public void setColor(int color) {
|
||||
AirFlowParticle.this.setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float alpha) {
|
||||
AirFlowParticle.this.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnExtraParticle(ParticleOptions options, float speedMultiplier) {
|
||||
level.addParticle(options, x, y, z, xd * speedMultiplier, yd * speedMultiplier, zd * speedMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,452 +0,0 @@
|
||||
package com.simibubi.create.content.kinetics.fan;
|
||||
|
||||
import static com.simibubi.create.content.processing.burner.BlazeBurnerBlock.getHeatLevelOf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult;
|
||||
import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock;
|
||||
import com.simibubi.create.foundation.recipe.RecipeApplier;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.animal.horse.Horse;
|
||||
import net.minecraft.world.entity.animal.horse.SkeletonHorse;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.AbstractCookingRecipe;
|
||||
import net.minecraft.world.item.crafting.BlastingRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.world.item.crafting.SmeltingRecipe;
|
||||
import net.minecraft.world.item.crafting.SmokingRecipe;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.CampfireBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class FanProcessing {
|
||||
|
||||
private static final DamageSource FIRE_DAMAGE_SOURCE = new DamageSource("create.fan_fire").setScalesWithDifficulty()
|
||||
.setIsFire();
|
||||
private static final DamageSource LAVA_DAMAGE_SOURCE = new DamageSource("create.fan_lava").setScalesWithDifficulty()
|
||||
.setIsFire();
|
||||
|
||||
private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1));
|
||||
private static final SplashingWrapper SPLASHING_WRAPPER = new SplashingWrapper();
|
||||
private static final HauntingWrapper HAUNTING_WRAPPER = new HauntingWrapper();
|
||||
|
||||
public static boolean canProcess(ItemEntity entity, Type type) {
|
||||
if (entity.getPersistentData()
|
||||
.contains("CreateData")) {
|
||||
CompoundTag compound = entity.getPersistentData()
|
||||
.getCompound("CreateData");
|
||||
if (compound.contains("Processing")) {
|
||||
CompoundTag processing = compound.getCompound("Processing");
|
||||
|
||||
if (Type.valueOf(processing.getString("Type")) != type)
|
||||
return type.canProcess(entity.getItem(), entity.level);
|
||||
else if (processing.getInt("Time") >= 0)
|
||||
return true;
|
||||
else if (processing.getInt("Time") == -1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return type.canProcess(entity.getItem(), entity.level);
|
||||
}
|
||||
|
||||
public static boolean isWashable(ItemStack stack, Level world) {
|
||||
SPLASHING_WRAPPER.setItem(0, stack);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
public static boolean isHauntable(ItemStack stack, Level world) {
|
||||
HAUNTING_WRAPPER.setItem(0, stack);
|
||||
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
public static boolean applyProcessing(ItemEntity entity, Type type) {
|
||||
if (decrementProcessingTime(entity, type) != 0)
|
||||
return false;
|
||||
List<ItemStack> stacks = process(entity.getItem(), type, entity.level);
|
||||
if (stacks == null)
|
||||
return false;
|
||||
if (stacks.isEmpty()) {
|
||||
entity.discard();
|
||||
return false;
|
||||
}
|
||||
entity.setItem(stacks.remove(0));
|
||||
for (ItemStack additional : stacks) {
|
||||
ItemEntity entityIn = new ItemEntity(entity.level, entity.getX(), entity.getY(), entity.getZ(), additional);
|
||||
entityIn.setDeltaMovement(entity.getDeltaMovement());
|
||||
entity.level.addFreshEntity(entityIn);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static TransportedResult applyProcessing(TransportedItemStack transported, Level world, Type type) {
|
||||
TransportedResult ignore = TransportedResult.doNothing();
|
||||
if (transported.processedBy != type) {
|
||||
transported.processedBy = type;
|
||||
int timeModifierForStackSize = ((transported.stack.getCount() - 1) / 16) + 1;
|
||||
int processingTime =
|
||||
(int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1;
|
||||
transported.processingTime = processingTime;
|
||||
if (!type.canProcess(transported.stack, world))
|
||||
transported.processingTime = -1;
|
||||
return ignore;
|
||||
}
|
||||
if (transported.processingTime == -1)
|
||||
return ignore;
|
||||
if (transported.processingTime-- > 0)
|
||||
return ignore;
|
||||
|
||||
List<ItemStack> stacks = process(transported.stack, type, world);
|
||||
if (stacks == null)
|
||||
return ignore;
|
||||
|
||||
List<TransportedItemStack> transportedStacks = new ArrayList<>();
|
||||
for (ItemStack additional : stacks) {
|
||||
TransportedItemStack newTransported = transported.getSimilar();
|
||||
newTransported.stack = additional.copy();
|
||||
transportedStacks.add(newTransported);
|
||||
}
|
||||
return TransportedResult.convertTo(transportedStacks);
|
||||
}
|
||||
|
||||
private static List<ItemStack> process(ItemStack stack, Type type, Level world) {
|
||||
if (type == Type.SPLASHING) {
|
||||
SPLASHING_WRAPPER.setItem(0, stack);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world);
|
||||
if (recipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, recipe.get());
|
||||
return null;
|
||||
}
|
||||
if (type == Type.HAUNTING) {
|
||||
HAUNTING_WRAPPER.setItem(0, stack);
|
||||
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world);
|
||||
if (recipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, recipe.get());
|
||||
return null;
|
||||
}
|
||||
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmokingRecipe> smokingRecipe = world.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, world);
|
||||
|
||||
if (type == Type.BLASTING) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<? extends AbstractCookingRecipe> smeltingRecipe = world.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, world);
|
||||
if (!smeltingRecipe.isPresent()) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
smeltingRecipe = world.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, world);
|
||||
}
|
||||
|
||||
if (smeltingRecipe.isPresent()) {
|
||||
if (!smokingRecipe.isPresent() || !ItemStack.isSame(smokingRecipe.get()
|
||||
.getResultItem(),
|
||||
smeltingRecipe.get()
|
||||
.getResultItem())) {
|
||||
return RecipeApplier.applyRecipeOn(stack, smeltingRecipe.get());
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (type == Type.SMOKING && smokingRecipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, smokingRecipe.get());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int decrementProcessingTime(ItemEntity entity, Type type) {
|
||||
CompoundTag nbt = entity.getPersistentData();
|
||||
|
||||
if (!nbt.contains("CreateData"))
|
||||
nbt.put("CreateData", new CompoundTag());
|
||||
CompoundTag createData = nbt.getCompound("CreateData");
|
||||
|
||||
if (!createData.contains("Processing"))
|
||||
createData.put("Processing", new CompoundTag());
|
||||
CompoundTag processing = createData.getCompound("Processing");
|
||||
|
||||
if (!processing.contains("Type") || Type.valueOf(processing.getString("Type")) != type) {
|
||||
processing.putString("Type", type.name());
|
||||
int timeModifierForStackSize = ((entity.getItem()
|
||||
.getCount() - 1) / 16) + 1;
|
||||
int processingTime =
|
||||
(int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1;
|
||||
processing.putInt("Time", processingTime);
|
||||
}
|
||||
|
||||
int value = processing.getInt("Time") - 1;
|
||||
processing.putInt("Time", value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
SPLASHING {
|
||||
@Override
|
||||
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
Vector3f color = new Color(0x0055FF).asVectorF();
|
||||
level.addParticle(new DustParticleOptions(color, 1), pos.x + (level.random.nextFloat() - .5f) * .5f,
|
||||
pos.y + .5f, pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
|
||||
level.addParticle(ParticleTypes.SPIT, pos.x + (level.random.nextFloat() - .5f) * .5f, pos.y + .5f,
|
||||
pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM
|
||||
|| entity.getType() == EntityType.BLAZE) {
|
||||
entity.hurt(DamageSource.DROWN, 2);
|
||||
}
|
||||
if (entity.isOnFire()) {
|
||||
entity.clearFire();
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
|
||||
SoundSource.NEUTRAL, 0.7F, 1.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
return isWashable(stack, level);
|
||||
}
|
||||
},
|
||||
SMOKING {
|
||||
@Override
|
||||
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
level.addParticle(ParticleTypes.POOF, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (!entity.fireImmune()) {
|
||||
entity.setSecondsOnFire(2);
|
||||
entity.hurt(FIRE_DAMAGE_SOURCE, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmokingRecipe> recipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
},
|
||||
HAUNTING {
|
||||
@Override
|
||||
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
pos = pos.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
|
||||
.multiply(1, 0.05f, 1)
|
||||
.normalize()
|
||||
.scale(0.15f));
|
||||
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, pos.x, pos.y + .45f, pos.z, 0, 0, 0);
|
||||
if (level.random.nextInt(2) == 0)
|
||||
level.addParticle(ParticleTypes.SMOKE, pos.x, pos.y + .25f, pos.z, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide) {
|
||||
if (entity instanceof Horse) {
|
||||
Vec3 p = entity.getPosition(0);
|
||||
Vec3 v = p.add(0, 0.5f, 0)
|
||||
.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
|
||||
.multiply(1, 0.2f, 1)
|
||||
.normalize()
|
||||
.scale(1f));
|
||||
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0);
|
||||
if (level.random.nextInt(3) == 0)
|
||||
level.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z,
|
||||
(level.random.nextFloat() - .5f) * .5f, 0.1f, (level.random.nextFloat() - .5f) * .5f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false));
|
||||
livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false));
|
||||
}
|
||||
if (entity instanceof Horse horse) {
|
||||
int progress = horse.getPersistentData()
|
||||
.getInt("CreateHaunting");
|
||||
if (progress < 100) {
|
||||
if (progress % 10 == 0) {
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL,
|
||||
1f, 1.5f * progress / 100f);
|
||||
}
|
||||
horse.getPersistentData()
|
||||
.putInt("CreateHaunting", progress + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
|
||||
SoundSource.NEUTRAL, 1.25f, 0.65f);
|
||||
|
||||
SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(level);
|
||||
CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag());
|
||||
serializeNBT.remove("UUID");
|
||||
if (!horse.getArmor()
|
||||
.isEmpty())
|
||||
horse.spawnAtLocation(horse.getArmor());
|
||||
|
||||
skeletonHorse.deserializeNBT(serializeNBT);
|
||||
skeletonHorse.setPos(horse.getPosition(0));
|
||||
level.addFreshEntity(skeletonHorse);
|
||||
horse.discard();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
return isHauntable(stack, level);
|
||||
}
|
||||
},
|
||||
BLASTING {
|
||||
@Override
|
||||
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (!entity.fireImmune()) {
|
||||
entity.setSecondsOnFire(10);
|
||||
entity.hurt(LAVA_DAMAGE_SOURCE, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmeltingRecipe> smeltingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level);
|
||||
|
||||
if (smeltingRecipe.isPresent())
|
||||
return true;
|
||||
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<BlastingRecipe> blastingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level);
|
||||
|
||||
if (blastingRecipe.isPresent())
|
||||
return true;
|
||||
|
||||
return !stack.getItem()
|
||||
.isFireResistant();
|
||||
}
|
||||
},
|
||||
NONE {
|
||||
@Override
|
||||
public void spawnParticlesForProcessing(Level level, Vec3 pos) {}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public abstract boolean canProcess(ItemStack stack, Level level);
|
||||
|
||||
public abstract void spawnParticlesForProcessing(Level level, Vec3 pos);
|
||||
|
||||
public abstract void affectEntity(Entity entity, Level level);
|
||||
|
||||
public static Type byBlock(BlockGetter reader, BlockPos pos) {
|
||||
FluidState fluidState = reader.getFluidState(pos);
|
||||
if (fluidState.getType() == Fluids.WATER || fluidState.getType() == Fluids.FLOWING_WATER)
|
||||
return Type.SPLASHING;
|
||||
BlockState blockState = reader.getBlockState(pos);
|
||||
Block block = blockState.getBlock();
|
||||
if (block == Blocks.SOUL_FIRE
|
||||
|| block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT)
|
||||
.orElse(false)
|
||||
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
|
||||
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.SOUL)
|
||||
.orElse(false))
|
||||
return Type.HAUNTING;
|
||||
if (block == Blocks.FIRE
|
||||
|| blockState.is(BlockTags.CAMPFIRES) && blockState.getOptionalValue(CampfireBlock.LIT)
|
||||
.orElse(false)
|
||||
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
|
||||
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.REGULAR)
|
||||
.orElse(false)
|
||||
|| getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING)
|
||||
return Type.SMOKING;
|
||||
if (block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
|
||||
return Type.BLASTING;
|
||||
return Type.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SplashingWrapper extends RecipeWrapper {
|
||||
public SplashingWrapper() {
|
||||
super(new ItemStackHandler(1));
|
||||
}
|
||||
}
|
||||
|
||||
public static class HauntingWrapper extends RecipeWrapper {
|
||||
public HauntingWrapper() {
|
||||
super(new ItemStackHandler(1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,488 @@
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import static com.simibubi.create.content.processing.burner.BlazeBurnerBlock.getHeatLevelOf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.HauntingRecipe.HauntingWrapper;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.SplashingRecipe.SplashingWrapper;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock;
|
||||
import com.simibubi.create.foundation.recipe.RecipeApplier;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.animal.horse.Horse;
|
||||
import net.minecraft.world.entity.animal.horse.SkeletonHorse;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.AbstractCookingRecipe;
|
||||
import net.minecraft.world.item.crafting.BlastingRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.world.item.crafting.SmeltingRecipe;
|
||||
import net.minecraft.world.item.crafting.SmokingRecipe;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.CampfireBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class AllFanProcessingTypes {
|
||||
public static final NoneType NONE = register("none", new NoneType());
|
||||
public static final BlastingType BLASTING = register("blasting", new BlastingType());
|
||||
public static final HauntingType HAUNTING = register("haunting", new HauntingType());
|
||||
public static final SmokingType SMOKING = register("smoking", new SmokingType());
|
||||
public static final SplashingType SPLASHING = register("splashing", new SplashingType());
|
||||
|
||||
private static final Map<String, FanProcessingType> LEGACY_NAME_MAP;
|
||||
|
||||
static {
|
||||
Object2ReferenceOpenHashMap<String, FanProcessingType> map = new Object2ReferenceOpenHashMap<>();
|
||||
map.put("NONE", NONE);
|
||||
map.put("BLASTING", BLASTING);
|
||||
map.put("HAUNTING", HAUNTING);
|
||||
map.put("SMOKING", SMOKING);
|
||||
map.put("SPLASHING", SPLASHING);
|
||||
map.trim();
|
||||
LEGACY_NAME_MAP = map;
|
||||
}
|
||||
|
||||
private static <T extends FanProcessingType> T register(String id, T type) {
|
||||
FanProcessingTypeRegistry.register(Create.asResource(id), type);
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FanProcessingType ofLegacyName(String name) {
|
||||
return LEGACY_NAME_MAP.get(name);
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
}
|
||||
|
||||
public static FanProcessingType parseLegacy(String str) {
|
||||
FanProcessingType type = ofLegacyName(str);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
return FanProcessingType.parse(str);
|
||||
}
|
||||
|
||||
public static class NoneType implements FanProcessingType {
|
||||
@Override
|
||||
public boolean isValidAt(Level level, BlockPos pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return -1000000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ItemStack> process(ItemStack stack, Level level) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnProcessingParticles(Level level, Vec3 pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void morphAirFlow(AirFlowParticleAccess particleAccess, Random random) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlastingType implements FanProcessingType {
|
||||
private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1));
|
||||
private static final DamageSource LAVA_DAMAGE_SOURCE = new DamageSource("create.fan_lava").setScalesWithDifficulty()
|
||||
.setIsFire();
|
||||
|
||||
@Override
|
||||
public boolean isValidAt(Level level, BlockPos pos) {
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
Block block = blockState.getBlock();
|
||||
return block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmeltingRecipe> smeltingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level);
|
||||
|
||||
if (smeltingRecipe.isPresent())
|
||||
return true;
|
||||
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<BlastingRecipe> blastingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level);
|
||||
|
||||
if (blastingRecipe.isPresent())
|
||||
return true;
|
||||
|
||||
return !stack.getItem()
|
||||
.isFireResistant();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ItemStack> process(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmokingRecipe> smokingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level);
|
||||
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<? extends AbstractCookingRecipe> smeltingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level);
|
||||
if (!smeltingRecipe.isPresent()) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
smeltingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level);
|
||||
}
|
||||
|
||||
if (smeltingRecipe.isPresent()) {
|
||||
if (!smokingRecipe.isPresent() || !ItemStack.isSame(smokingRecipe.get()
|
||||
.getResultItem(),
|
||||
smeltingRecipe.get()
|
||||
.getResultItem())) {
|
||||
return RecipeApplier.applyRecipeOn(stack, smeltingRecipe.get());
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnProcessingParticles(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void morphAirFlow(AirFlowParticleAccess particleAccess, Random random) {
|
||||
particleAccess.setColor(Color.mixColors(0xFF4400, 0xFF8855, random.nextFloat()));
|
||||
particleAccess.setAlpha(.5f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.FLAME, .25f);
|
||||
if (random.nextFloat() < 1 / 16f)
|
||||
particleAccess.spawnExtraParticle(new BlockParticleOption(ParticleTypes.BLOCK, Blocks.LAVA.defaultBlockState()), .25f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (!entity.fireImmune()) {
|
||||
entity.setSecondsOnFire(10);
|
||||
entity.hurt(LAVA_DAMAGE_SOURCE, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class HauntingType implements FanProcessingType {
|
||||
private static final HauntingWrapper HAUNTING_WRAPPER = new HauntingWrapper();
|
||||
|
||||
@Override
|
||||
public boolean isValidAt(Level level, BlockPos pos) {
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
Block block = blockState.getBlock();
|
||||
return block == Blocks.SOUL_FIRE
|
||||
|| block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT)
|
||||
.orElse(false)
|
||||
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
|
||||
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.SOUL)
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
HAUNTING_WRAPPER.setItem(0, stack);
|
||||
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, level);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ItemStack> process(ItemStack stack, Level level) {
|
||||
HAUNTING_WRAPPER.setItem(0, stack);
|
||||
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, level);
|
||||
if (recipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, recipe.get());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnProcessingParticles(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
pos = pos.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
|
||||
.multiply(1, 0.05f, 1)
|
||||
.normalize()
|
||||
.scale(0.15f));
|
||||
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, pos.x, pos.y + .45f, pos.z, 0, 0, 0);
|
||||
if (level.random.nextInt(2) == 0)
|
||||
level.addParticle(ParticleTypes.SMOKE, pos.x, pos.y + .25f, pos.z, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void morphAirFlow(AirFlowParticleAccess particleAccess, Random random) {
|
||||
particleAccess.setColor(Color.mixColors(0x0, 0x126568, random.nextFloat()));
|
||||
particleAccess.setAlpha(1f);
|
||||
if (random.nextFloat() < 1 / 128f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.SOUL_FIRE_FLAME, .125f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.SMOKE, .125f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide) {
|
||||
if (entity instanceof Horse) {
|
||||
Vec3 p = entity.getPosition(0);
|
||||
Vec3 v = p.add(0, 0.5f, 0)
|
||||
.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
|
||||
.multiply(1, 0.2f, 1)
|
||||
.normalize()
|
||||
.scale(1f));
|
||||
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0);
|
||||
if (level.random.nextInt(3) == 0)
|
||||
level.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z,
|
||||
(level.random.nextFloat() - .5f) * .5f, 0.1f, (level.random.nextFloat() - .5f) * .5f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false));
|
||||
livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false));
|
||||
}
|
||||
if (entity instanceof Horse horse) {
|
||||
int progress = horse.getPersistentData()
|
||||
.getInt("CreateHaunting");
|
||||
if (progress < 100) {
|
||||
if (progress % 10 == 0) {
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL,
|
||||
1f, 1.5f * progress / 100f);
|
||||
}
|
||||
horse.getPersistentData()
|
||||
.putInt("CreateHaunting", progress + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
|
||||
SoundSource.NEUTRAL, 1.25f, 0.65f);
|
||||
|
||||
SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(level);
|
||||
CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag());
|
||||
serializeNBT.remove("UUID");
|
||||
if (!horse.getArmor()
|
||||
.isEmpty())
|
||||
horse.spawnAtLocation(horse.getArmor());
|
||||
|
||||
skeletonHorse.deserializeNBT(serializeNBT);
|
||||
skeletonHorse.setPos(horse.getPosition(0));
|
||||
level.addFreshEntity(skeletonHorse);
|
||||
horse.discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SmokingType implements FanProcessingType {
|
||||
private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1));
|
||||
private static final DamageSource FIRE_DAMAGE_SOURCE = new DamageSource("create.fan_fire").setScalesWithDifficulty()
|
||||
.setIsFire();
|
||||
|
||||
@Override
|
||||
public boolean isValidAt(Level level, BlockPos pos) {
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
Block block = blockState.getBlock();
|
||||
return block == Blocks.FIRE
|
||||
|| blockState.is(BlockTags.CAMPFIRES) && blockState.getOptionalValue(CampfireBlock.LIT)
|
||||
.orElse(false)
|
||||
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
|
||||
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.REGULAR)
|
||||
.orElse(false)
|
||||
|| getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmokingRecipe> recipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ItemStack> process(ItemStack stack, Level level) {
|
||||
RECIPE_WRAPPER.setItem(0, stack);
|
||||
Optional<SmokingRecipe> smokingRecipe = level.getRecipeManager()
|
||||
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level);
|
||||
|
||||
if (smokingRecipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, smokingRecipe.get());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnProcessingParticles(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
level.addParticle(ParticleTypes.POOF, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void morphAirFlow(AirFlowParticleAccess particleAccess, Random random) {
|
||||
particleAccess.setColor(Color.mixColors(0x0, 0x555555, random.nextFloat()));
|
||||
particleAccess.setAlpha(1f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.SMOKE, .125f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.LARGE_SMOKE, .125f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (!entity.fireImmune()) {
|
||||
entity.setSecondsOnFire(2);
|
||||
entity.hurt(FIRE_DAMAGE_SOURCE, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SplashingType implements FanProcessingType {
|
||||
private static final SplashingWrapper SPLASHING_WRAPPER = new SplashingWrapper();
|
||||
|
||||
@Override
|
||||
public boolean isValidAt(Level level, BlockPos pos) {
|
||||
FluidState fluidState = level.getFluidState(pos);
|
||||
Fluid fluid = fluidState.getType();
|
||||
return fluid == Fluids.WATER || fluid == Fluids.FLOWING_WATER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 400;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(ItemStack stack, Level level) {
|
||||
SPLASHING_WRAPPER.setItem(0, stack);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, level);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ItemStack> process(ItemStack stack, Level level) {
|
||||
SPLASHING_WRAPPER.setItem(0, stack);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, level);
|
||||
if (recipe.isPresent())
|
||||
return RecipeApplier.applyRecipeOn(stack, recipe.get());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnProcessingParticles(Level level, Vec3 pos) {
|
||||
if (level.random.nextInt(8) != 0)
|
||||
return;
|
||||
Vector3f color = new Color(0x0055FF).asVectorF();
|
||||
level.addParticle(new DustParticleOptions(color, 1), pos.x + (level.random.nextFloat() - .5f) * .5f,
|
||||
pos.y + .5f, pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
|
||||
level.addParticle(ParticleTypes.SPIT, pos.x + (level.random.nextFloat() - .5f) * .5f, pos.y + .5f,
|
||||
pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void morphAirFlow(AirFlowParticleAccess particleAccess, Random random) {
|
||||
particleAccess.setColor(Color.mixColors(0x4499FF, 0x2277FF, random.nextFloat()));
|
||||
particleAccess.setAlpha(1f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.BUBBLE, .125f);
|
||||
if (random.nextFloat() < 1 / 32f)
|
||||
particleAccess.spawnExtraParticle(ParticleTypes.BUBBLE_POP, .125f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectEntity(Entity entity, Level level) {
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM
|
||||
|| entity.getType() == EntityType.BLAZE) {
|
||||
entity.hurt(DamageSource.DROWN, 2);
|
||||
}
|
||||
if (entity.isOnFire()) {
|
||||
entity.clearFire();
|
||||
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
|
||||
SoundSource.NEUTRAL, 0.7F, 1.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult;
|
||||
import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class FanProcessing {
|
||||
public static boolean canProcess(ItemEntity entity, FanProcessingType type) {
|
||||
if (entity.getPersistentData()
|
||||
.contains("CreateData")) {
|
||||
CompoundTag compound = entity.getPersistentData()
|
||||
.getCompound("CreateData");
|
||||
if (compound.contains("Processing")) {
|
||||
CompoundTag processing = compound.getCompound("Processing");
|
||||
|
||||
if (AllFanProcessingTypes.parseLegacy(processing.getString("Type")) != type)
|
||||
return type.canProcess(entity.getItem(), entity.level);
|
||||
else if (processing.getInt("Time") >= 0)
|
||||
return true;
|
||||
else if (processing.getInt("Time") == -1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return type.canProcess(entity.getItem(), entity.level);
|
||||
}
|
||||
|
||||
public static boolean applyProcessing(ItemEntity entity, FanProcessingType type) {
|
||||
if (decrementProcessingTime(entity, type) != 0)
|
||||
return false;
|
||||
List<ItemStack> stacks = type.process(entity.getItem(), entity.level);
|
||||
if (stacks == null)
|
||||
return false;
|
||||
if (stacks.isEmpty()) {
|
||||
entity.discard();
|
||||
return false;
|
||||
}
|
||||
entity.setItem(stacks.remove(0));
|
||||
for (ItemStack additional : stacks) {
|
||||
ItemEntity entityIn = new ItemEntity(entity.level, entity.getX(), entity.getY(), entity.getZ(), additional);
|
||||
entityIn.setDeltaMovement(entity.getDeltaMovement());
|
||||
entity.level.addFreshEntity(entityIn);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static TransportedResult applyProcessing(TransportedItemStack transported, Level world, FanProcessingType type) {
|
||||
TransportedResult ignore = TransportedResult.doNothing();
|
||||
if (transported.processedBy != type) {
|
||||
transported.processedBy = type;
|
||||
int timeModifierForStackSize = ((transported.stack.getCount() - 1) / 16) + 1;
|
||||
int processingTime =
|
||||
(int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1;
|
||||
transported.processingTime = processingTime;
|
||||
if (!type.canProcess(transported.stack, world))
|
||||
transported.processingTime = -1;
|
||||
return ignore;
|
||||
}
|
||||
if (transported.processingTime == -1)
|
||||
return ignore;
|
||||
if (transported.processingTime-- > 0)
|
||||
return ignore;
|
||||
|
||||
List<ItemStack> stacks = type.process(transported.stack, world);
|
||||
if (stacks == null)
|
||||
return ignore;
|
||||
|
||||
List<TransportedItemStack> transportedStacks = new ArrayList<>();
|
||||
for (ItemStack additional : stacks) {
|
||||
TransportedItemStack newTransported = transported.getSimilar();
|
||||
newTransported.stack = additional.copy();
|
||||
transportedStacks.add(newTransported);
|
||||
}
|
||||
return TransportedResult.convertTo(transportedStacks);
|
||||
}
|
||||
|
||||
private static int decrementProcessingTime(ItemEntity entity, FanProcessingType type) {
|
||||
CompoundTag nbt = entity.getPersistentData();
|
||||
|
||||
if (!nbt.contains("CreateData"))
|
||||
nbt.put("CreateData", new CompoundTag());
|
||||
CompoundTag createData = nbt.getCompound("CreateData");
|
||||
|
||||
if (!createData.contains("Processing"))
|
||||
createData.put("Processing", new CompoundTag());
|
||||
CompoundTag processing = createData.getCompound("Processing");
|
||||
|
||||
if (!processing.contains("Type") || AllFanProcessingTypes.parseLegacy(processing.getString("Type")) != type) {
|
||||
processing.putString("Type", FanProcessingTypeRegistry.getIdOrThrow(type).toString());
|
||||
int timeModifierForStackSize = ((entity.getItem()
|
||||
.getCount() - 1) / 16) + 1;
|
||||
int processingTime =
|
||||
(int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1;
|
||||
processing.putInt("Time", processingTime);
|
||||
}
|
||||
|
||||
int value = processing.getInt("Time") - 1;
|
||||
processing.putInt("Time", value);
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface FanProcessingType {
|
||||
boolean isValidAt(Level level, BlockPos pos);
|
||||
|
||||
int getPriority();
|
||||
|
||||
boolean canProcess(ItemStack stack, Level level);
|
||||
|
||||
@Nullable
|
||||
List<ItemStack> process(ItemStack stack, Level level);
|
||||
|
||||
void spawnProcessingParticles(Level level, Vec3 pos);
|
||||
|
||||
void morphAirFlow(AirFlowParticleAccess particleAccess, Random random);
|
||||
|
||||
void affectEntity(Entity entity, Level level);
|
||||
|
||||
static FanProcessingType parse(String str) {
|
||||
ResourceLocation id = ResourceLocation.tryParse(str);
|
||||
if (id == null) {
|
||||
return AllFanProcessingTypes.NONE;
|
||||
}
|
||||
FanProcessingType type = FanProcessingTypeRegistry.getType(id);
|
||||
if (type == null) {
|
||||
return AllFanProcessingTypes.NONE;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static FanProcessingType getAt(Level level, BlockPos pos) {
|
||||
for (FanProcessingType type : FanProcessingTypeRegistry.getSortedTypesView()) {
|
||||
if (type.isValidAt(level, pos)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return AllFanProcessingTypes.NONE;
|
||||
}
|
||||
|
||||
interface AirFlowParticleAccess {
|
||||
void setColor(int color);
|
||||
|
||||
void setAlpha(float alpha);
|
||||
|
||||
void spawnExtraParticle(ParticleOptions options, float speedMultiplier);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FanProcessingTypeRegistry {
|
||||
private static final Map<ResourceLocation, FanProcessingType> TYPES = new Object2ReferenceOpenHashMap<>();
|
||||
private static final Map<FanProcessingType, ResourceLocation> IDS = new Reference2ObjectOpenHashMap<>();
|
||||
private static final List<FanProcessingType> SORTED_TYPES = new ReferenceArrayList<>();
|
||||
private static final List<FanProcessingType> SORTED_TYPES_VIEW = Collections.unmodifiableList(SORTED_TYPES);
|
||||
|
||||
public static void register(ResourceLocation id, FanProcessingType type) {
|
||||
if (TYPES.put(id, type) != null) {
|
||||
throw new IllegalArgumentException("Tried to override FanProcessingType registration for id '" + id + "'. This is not supported!");
|
||||
}
|
||||
ResourceLocation prevId = IDS.put(type, id);
|
||||
if (prevId != null) {
|
||||
throw new IllegalArgumentException("Tried to register same FanProcessingType instance for multiple ids '" + prevId + "' and '" + id + "'. This is not supported!");
|
||||
}
|
||||
insertSortedType(type, id);
|
||||
}
|
||||
|
||||
private static void insertSortedType(FanProcessingType type, ResourceLocation id) {
|
||||
int index = Collections.binarySearch(SORTED_TYPES, type, (type1, type2) -> type2.getPriority() - type1.getPriority());
|
||||
if (index >= 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
SORTED_TYPES.add(-index - 1, type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FanProcessingType getType(ResourceLocation id) {
|
||||
return TYPES.get(id);
|
||||
}
|
||||
|
||||
public static FanProcessingType getTypeOrThrow(ResourceLocation id) {
|
||||
FanProcessingType type = getType(id);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Could not get FanProcessingType for id '" + id + "'!");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ResourceLocation getId(FanProcessingType type) {
|
||||
return IDS.get(type);
|
||||
}
|
||||
|
||||
public static ResourceLocation getIdOrThrow(FanProcessingType type) {
|
||||
ResourceLocation id = getId(type);
|
||||
if (id == null) {
|
||||
throw new IllegalArgumentException("Could not get id for FanProcessingType " + type + "!");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static List<FanProcessingType> getSortedTypesView() {
|
||||
return SORTED_TYPES_VIEW;
|
||||
}
|
||||
}
|
@ -1,22 +1,25 @@
|
||||
package com.simibubi.create.content.kinetics.fan;
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.HauntingRecipe.HauntingWrapper;
|
||||
import com.simibubi.create.content.processing.recipe.ProcessingRecipe;
|
||||
import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public class HauntingRecipe extends ProcessingRecipe<FanProcessing.HauntingWrapper> {
|
||||
public class HauntingRecipe extends ProcessingRecipe<HauntingWrapper> {
|
||||
|
||||
public HauntingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.HAUNTING, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(FanProcessing.HauntingWrapper inv, Level worldIn) {
|
||||
public boolean matches(HauntingWrapper inv, Level worldIn) {
|
||||
if (inv.isEmpty())
|
||||
return false;
|
||||
return ingredients.get(0)
|
||||
@ -33,4 +36,10 @@ public class HauntingRecipe extends ProcessingRecipe<FanProcessing.HauntingWrapp
|
||||
return 12;
|
||||
}
|
||||
|
||||
public static class HauntingWrapper extends RecipeWrapper {
|
||||
public HauntingWrapper() {
|
||||
super(new ItemStackHandler(1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
package com.simibubi.create.content.kinetics.fan;
|
||||
package com.simibubi.create.content.kinetics.fan.processing;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.kinetics.fan.FanProcessing.SplashingWrapper;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.SplashingRecipe.SplashingWrapper;
|
||||
import com.simibubi.create.content.processing.recipe.ProcessingRecipe;
|
||||
import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public class SplashingRecipe extends ProcessingRecipe<FanProcessing.SplashingWrapper> {
|
||||
public class SplashingRecipe extends ProcessingRecipe<SplashingWrapper> {
|
||||
|
||||
public SplashingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.SPLASHING, params);
|
||||
@ -34,4 +36,10 @@ public class SplashingRecipe extends ProcessingRecipe<FanProcessing.SplashingWra
|
||||
return 12;
|
||||
}
|
||||
|
||||
public static class SplashingWrapper extends RecipeWrapper {
|
||||
public SplashingWrapper() {
|
||||
super(new ItemStackHandler(1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.kinetics.fan.FanProcessing;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
|
||||
import com.simibubi.create.content.logistics.filter.attribute.BookAuthorAttribute;
|
||||
import com.simibubi.create.content.logistics.filter.attribute.BookCopyAttribute;
|
||||
import com.simibubi.create.content.logistics.filter.attribute.ColorAttribute;
|
||||
@ -145,8 +145,8 @@ public interface ItemAttribute {
|
||||
EQUIPABLE(s -> LivingEntity.getEquipmentSlotForItem(s)
|
||||
.getType() != EquipmentSlot.Type.HAND),
|
||||
FURNACE_FUEL(AbstractFurnaceBlockEntity::isFuel),
|
||||
WASHABLE(FanProcessing::isWashable),
|
||||
HAUNTABLE(FanProcessing::isHauntable),
|
||||
WASHABLE(AllFanProcessingTypes.SPLASHING::canProcess),
|
||||
HAUNTABLE(AllFanProcessingTypes.HAUNTING::canProcess),
|
||||
CRUSHABLE((s, w) -> testRecipe(s, w, AllRecipeTypes.CRUSHING.getType())
|
||||
|| testRecipe(s, w, AllRecipeTypes.MILLING.getType())),
|
||||
SMELTABLE((s, w) -> testRecipe(s, w, RecipeType.SMELTING)),
|
||||
|
@ -13,6 +13,7 @@ import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.equipment.blueprint.BlueprintOverlayRenderer;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
@ -44,7 +45,6 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.HitResult.Type;
|
||||
@ -478,18 +478,6 @@ public class TrackPlacement {
|
||||
info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited);
|
||||
}
|
||||
|
||||
private static BlockState copyProperties(BlockState from, BlockState onto) {
|
||||
for (Property property : onto.getProperties()) {
|
||||
if (from.hasProperty(property))
|
||||
onto = onto.setValue(property, from.getValue(property));
|
||||
}
|
||||
return onto;
|
||||
}
|
||||
|
||||
private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) {
|
||||
return keepFrom ? from : copyProperties(from, onto);
|
||||
}
|
||||
|
||||
private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2,
|
||||
BlockPos targetPos1, BlockPos targetPos2, boolean simulate) {
|
||||
info.requiredTracks = 0;
|
||||
@ -518,7 +506,7 @@ public class TrackPlacement {
|
||||
BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z);
|
||||
BlockState stateAtPos = level.getBlockState(offsetPos);
|
||||
// copy over all shared properties from the shaped state to the correct track material block
|
||||
BlockState toPlace = copyProperties(state, info.trackMaterial.getBlock().defaultBlockState());
|
||||
BlockState toPlace = BlockHelper.copyProperties(state, info.trackMaterial.getBlock().defaultBlockState());
|
||||
|
||||
boolean canPlace = stateAtPos.getMaterial()
|
||||
.isReplaceable();
|
||||
@ -544,12 +532,12 @@ public class TrackPlacement {
|
||||
BlockState onto = info.trackMaterial.getBlock().defaultBlockState();
|
||||
BlockState stateAtPos = level.getBlockState(targetPos1);
|
||||
level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level,
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto))
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : BlockHelper.copyProperties(state1, onto))
|
||||
.setValue(TrackBlock.HAS_BE, true), targetPos1), 3);
|
||||
|
||||
stateAtPos = level.getBlockState(targetPos2);
|
||||
level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level,
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto))
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : BlockHelper.copyProperties(state2, onto))
|
||||
.setValue(TrackBlock.HAS_BE, true), targetPos2), 3);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user