From a1c37c5af6c856fec142081fda92f737d2422c09 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 12 Dec 2019 07:38:44 +0100 Subject: [PATCH] Fantastic - Encased fans are now directional and only emit air flows on one side - Reworked particles emitted by fans and in-world item processing - Air flows can now morph into different particle types along the way - Air flows are more precise about being blocked or not - Nerfed sand washing --- .../java/com/simibubi/create/AllBlocks.java | 4 +- .../com/simibubi/create/AllParticles.java | 2 + .../java/com/simibubi/create/AllRecipes.java | 2 +- .../com/simibubi/create/AllTileEntities.java | 4 +- .../com/simibubi/create/CreateClient.java | 3 - .../simibubi/create/CreateClientConfig.java | 18 +- .../com/simibubi/create/CreateConfig.java | 6 +- .../compat/jei/ProcessingViaFanCategory.java | 6 +- .../create/compat/jei/SplashingCategory.java | 2 +- .../create/foundation/utility/VecHelper.java | 5 + .../utility/recipe/RecipeConditions.java | 37 ++ .../utility/recipe/RecipeFinder.java | 96 ++++++ .../base/DirectionalKineticBlock.java | 29 +- .../particle/AirFlowParticle.java | 176 ++++++++++ .../particle/AirFlowParticleData.java | 64 ++++ .../receivers/EncasedFanBeltHandler.java | 71 ---- .../receivers/EncasedFanParticleHandler.java | 121 ------- .../receivers/EncasedFanTileEntity.java | 318 ------------------ .../EncasedFanTileEntityRenderer.java | 18 - .../contraptions/receivers/SawTileEntity.java | 22 +- .../receivers/fan/AirCurrent.java | 294 ++++++++++++++++ .../receivers/{ => fan}/EncasedFanBlock.java | 49 +-- .../receivers/fan/EncasedFanTileEntity.java | 196 +++++++++++ .../fan/EncasedFanTileEntityRenderer.java | 48 +++ .../receivers/{ => fan}/SplashingRecipe.java | 2 +- .../modules/logistics/InWorldProcessing.java | 50 ++- .../create/blockstates/encased_fan.json | 25 +- .../create/blockstates/encased_fan_inner.json | 25 +- .../resources/assets/create/lang/en_us.json | 8 +- .../models/block/encased_fan/casing.json | 78 +++++ .../create/models/block/encased_fan/item.json | 111 ++++++ .../models/block/encased_fan/propeller.json | 32 ++ .../create/models/item/encased_fan.json | 102 +----- .../assets/create/particles/air_flow.json | 12 + .../data/create/recipes/splashing/sand.json | 3 +- 35 files changed, 1322 insertions(+), 717 deletions(-) create mode 100644 src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeConditions.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeFinder.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticle.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java delete mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBeltHandler.java delete mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanParticleHandler.java delete mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java delete mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntityRenderer.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/AirCurrent.java rename src/main/java/com/simibubi/create/modules/contraptions/receivers/{ => fan}/EncasedFanBlock.java (53%) create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntity.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntityRenderer.java rename src/main/java/com/simibubi/create/modules/contraptions/receivers/{ => fan}/SplashingRecipe.java (93%) create mode 100644 src/main/resources/assets/create/models/block/encased_fan/casing.json create mode 100644 src/main/resources/assets/create/models/block/encased_fan/item.json create mode 100644 src/main/resources/assets/create/models/block/encased_fan/propeller.json create mode 100644 src/main/resources/assets/create/particles/air_flow.json diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index b23271ec1..2612f5f28 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -15,7 +15,6 @@ import com.simibubi.create.modules.contraptions.receivers.CrushingWheelBlock; import com.simibubi.create.modules.contraptions.receivers.CrushingWheelControllerBlock; import com.simibubi.create.modules.contraptions.receivers.DrillBlock; import com.simibubi.create.modules.contraptions.receivers.DrillBlock.DrillHeadBlock; -import com.simibubi.create.modules.contraptions.receivers.EncasedFanBlock; import com.simibubi.create.modules.contraptions.receivers.HarvesterBlock; import com.simibubi.create.modules.contraptions.receivers.HarvesterBlock.HarvesterBladeBlock; import com.simibubi.create.modules.contraptions.receivers.MechanicalMixerBlock; @@ -32,6 +31,7 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.piston.Mech import com.simibubi.create.modules.contraptions.receivers.constructs.piston.MechanicalPistonHeadBlock; import com.simibubi.create.modules.contraptions.receivers.constructs.piston.PistonPoleBlock; import com.simibubi.create.modules.contraptions.receivers.crafter.MechanicalCrafterBlock; +import com.simibubi.create.modules.contraptions.receivers.fan.EncasedFanBlock; import com.simibubi.create.modules.contraptions.redstone.ContactBlock; import com.simibubi.create.modules.contraptions.relays.ClutchBlock; import com.simibubi.create.modules.contraptions.relays.CogWheelBlock; @@ -116,7 +116,7 @@ public enum AllBlocks { MOTOR(new MotorBlock()), WATER_WHEEL(new WaterWheelBlock()), ENCASED_FAN(new EncasedFanBlock()), - ENCASED_FAN_INNER(new RenderUtilityAxisBlock()), + ENCASED_FAN_INNER(new RenderUtilityDirectionalBlock()), TURNTABLE(new TurntableBlock()), SHAFT_HALF(new ShaftHalfBlock()), diff --git a/src/main/java/com/simibubi/create/AllParticles.java b/src/main/java/com/simibubi/create/AllParticles.java index 37c95fbf2..6ef5147a5 100644 --- a/src/main/java/com/simibubi/create/AllParticles.java +++ b/src/main/java/com/simibubi/create/AllParticles.java @@ -3,6 +3,7 @@ package com.simibubi.create; import java.util.function.Supplier; import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.modules.contraptions.particle.AirFlowParticle; import com.simibubi.create.modules.contraptions.particle.RotationIndicatorParticle; import net.minecraft.client.Minecraft; @@ -18,6 +19,7 @@ import net.minecraftforge.registries.IForgeRegistry; public enum AllParticles { ROTATION_INDICATOR(RotationIndicatorParticle.Type::new, RotationIndicatorParticle.Factory::new), + AIR_FLOW(AirFlowParticle.Type::new, AirFlowParticle.Factory::new), ; diff --git a/src/main/java/com/simibubi/create/AllRecipes.java b/src/main/java/com/simibubi/create/AllRecipes.java index 64a33d3a1..1bd509a6d 100644 --- a/src/main/java/com/simibubi/create/AllRecipes.java +++ b/src/main/java/com/simibubi/create/AllRecipes.java @@ -8,7 +8,7 @@ import com.simibubi.create.modules.contraptions.receivers.CrushingRecipe; import com.simibubi.create.modules.contraptions.receivers.CuttingRecipe; import com.simibubi.create.modules.contraptions.receivers.MixingRecipe; import com.simibubi.create.modules.contraptions.receivers.PressingRecipe; -import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe; +import com.simibubi.create.modules.contraptions.receivers.fan.SplashingRecipe; import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunUpgradeRecipe; import net.minecraft.inventory.IInventory; diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 1bb970ba9..20659d167 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -13,8 +13,6 @@ import com.simibubi.create.modules.contraptions.receivers.CrushingWheelControlle import com.simibubi.create.modules.contraptions.receivers.CrushingWheelTileEntity; import com.simibubi.create.modules.contraptions.receivers.DrillTileEntity; import com.simibubi.create.modules.contraptions.receivers.DrillTileEntityRenderer; -import com.simibubi.create.modules.contraptions.receivers.EncasedFanTileEntity; -import com.simibubi.create.modules.contraptions.receivers.EncasedFanTileEntityRenderer; import com.simibubi.create.modules.contraptions.receivers.HarvesterTileEntity; import com.simibubi.create.modules.contraptions.receivers.HarvesterTileEntityRenderer; import com.simibubi.create.modules.contraptions.receivers.MechanicalMixerTileEntity; @@ -31,6 +29,8 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.piston.Mech import com.simibubi.create.modules.contraptions.receivers.constructs.piston.MechanicalPistonTileEntityRenderer; import com.simibubi.create.modules.contraptions.receivers.crafter.MechanicalCrafterTileEntity; import com.simibubi.create.modules.contraptions.receivers.crafter.MechanicalCrafterTileEntityRenderer; +import com.simibubi.create.modules.contraptions.receivers.fan.EncasedFanTileEntity; +import com.simibubi.create.modules.contraptions.receivers.fan.EncasedFanTileEntityRenderer; import com.simibubi.create.modules.contraptions.relays.ClutchTileEntity; import com.simibubi.create.modules.contraptions.relays.EncasedShaftTileEntity; import com.simibubi.create.modules.contraptions.relays.EncasedShaftTileEntityRenderer; diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 4ab00aca4..5b7c9545c 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -13,7 +13,6 @@ import com.simibubi.create.foundation.block.SpriteShifter.SpriteShiftEntry; import com.simibubi.create.foundation.utility.SuperByteBufferCache; import com.simibubi.create.modules.contraptions.WrenchModel; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.modules.contraptions.receivers.EncasedFanParticleHandler; import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionRenderer; import com.simibubi.create.modules.curiosities.deforester.DeforesterModel; import com.simibubi.create.modules.curiosities.partialWindows.WindowInABlockModel; @@ -50,7 +49,6 @@ public class CreateClient { public static SchematicHandler schematicHandler; public static SchematicHologram schematicHologram; public static SchematicAndQuillHandler schematicAndQuillHandler; - public static EncasedFanParticleHandler fanParticles; public static SuperByteBufferCache bufferCache; public static int renderTicks; @@ -72,7 +70,6 @@ public class CreateClient { schematicHandler = new SchematicHandler(); schematicHologram = new SchematicHologram(); schematicAndQuillHandler = new SchematicAndQuillHandler(); - fanParticles = new EncasedFanParticleHandler(); bufferCache = new SuperByteBufferCache(); bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); diff --git a/src/main/java/com/simibubi/create/CreateClientConfig.java b/src/main/java/com/simibubi/create/CreateClientConfig.java index e9dabe069..d8575d48f 100644 --- a/src/main/java/com/simibubi/create/CreateClientConfig.java +++ b/src/main/java/com/simibubi/create/CreateClientConfig.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.tuple.Pair; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; +import net.minecraftforge.common.ForgeConfigSpec.DoubleValue; public class CreateClientConfig { @@ -13,21 +14,28 @@ public class CreateClientConfig { static { final Pair specPair = new ForgeConfigSpec.Builder() .configure(CreateClientConfig::new); - + specification = specPair.getRight(); instance = specPair.getLeft(); } public BooleanValue enableTooltips; - + public DoubleValue fanParticleDensity; + CreateClientConfig(final ForgeConfigSpec.Builder builder) { - builder.comment("Client-only settings - If you're looking for server/common settings, look inside your worlds serverconfig folder!").push("client"); + builder.comment( + "Client-only settings - If you're looking for server/common settings, look inside your worlds serverconfig folder!") + .push("client"); String basePath = "create.config.client."; - + String name = "enableTooltips"; enableTooltips = builder.comment("", "Show item descriptions on Shift and controls on Ctrl.") .translation(basePath + name).define(name, true); - + + name = "fanParticleDensity"; + fanParticleDensity = builder.comment("", "Controls the average amount of fan particles spawned per tick.") + .translation(basePath + name).defineInRange(name, .5D, 0D, 1D); + builder.pop(); } diff --git a/src/main/java/com/simibubi/create/CreateConfig.java b/src/main/java/com/simibubi/create/CreateConfig.java index f6651d6dd..596bb11f0 100644 --- a/src/main/java/com/simibubi/create/CreateConfig.java +++ b/src/main/java/com/simibubi/create/CreateConfig.java @@ -200,7 +200,7 @@ public class CreateConfig { name = "fanBlockCheckRate"; fanBlockCheckRate = builder .comment("", "Game ticks between Fans checking for anything blocking their air flow.") - .translation(basePath + name).defineInRange(name, 100, 20, Integer.MAX_VALUE); + .translation(basePath + name).defineInRange(name, 30, 10, Integer.MAX_VALUE); name = "fanMaxPushDistance"; fanMaxPushDistance = builder.comment("", "Maximum distance in blocks Fans can push entities.") @@ -208,11 +208,11 @@ public class CreateConfig { name = "fanMaxPullDistance"; fanMaxPullDistance = builder.comment("", "Maximum distance in blocks from where Fans can pull entities.") - .translation(basePath + name).defineInRange(name, 5, 1, Integer.MAX_VALUE); + .translation(basePath + name).defineInRange(name, 10, 1, Integer.MAX_VALUE); name = "fanRotationArgmax"; fanRotationArgmax = builder.comment("", "Rotation speed at which the maximum stats of fans are reached.") - .translation(basePath + name).defineInRange(name, 8192, 64, Integer.MAX_VALUE); + .translation(basePath + name).defineInRange(name, 1024, 64, Integer.MAX_VALUE); name = "generatingFanSpeed"; generatingFanSpeed = builder.comment("", "Rotation speed generated by a vertical fan above fire.") diff --git a/src/main/java/com/simibubi/create/compat/jei/ProcessingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/ProcessingViaFanCategory.java index 8711e518c..428040eec 100644 --- a/src/main/java/com/simibubi/create/compat/jei/ProcessingViaFanCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/ProcessingViaFanCategory.java @@ -16,7 +16,7 @@ import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.block.BlockState; import net.minecraft.item.crafting.IRecipe; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Direction; public abstract class ProcessingViaFanCategory> implements IRecipeCategory { @@ -72,12 +72,12 @@ public abstract class ProcessingViaFanCategory> implements protected BlockState renderFanCasing() { - return AllBlocks.ENCASED_FAN.get().getDefaultState().with(BlockStateProperties.AXIS, Axis.X); + return AllBlocks.ENCASED_FAN.get().getDefaultState().with(BlockStateProperties.FACING, Direction.WEST); } protected BlockState renderFanInner() { - return AllBlocks.ENCASED_FAN_INNER.get().getDefaultState().with(BlockStateProperties.AXIS, Axis.X); + return AllBlocks.ENCASED_FAN_INNER.get().getDefaultState().with(BlockStateProperties.FACING, Direction.WEST); } public abstract void renderAttachedBlock(); diff --git a/src/main/java/com/simibubi/create/compat/jei/SplashingCategory.java b/src/main/java/com/simibubi/create/compat/jei/SplashingCategory.java index dacedafc9..87b93a918 100644 --- a/src/main/java/com/simibubi/create/compat/jei/SplashingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/SplashingCategory.java @@ -10,7 +10,7 @@ import com.simibubi.create.ScreenResources; import com.simibubi.create.foundation.gui.ScreenElementRenderer; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.base.StochasticOutput; -import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe; +import com.simibubi.create.modules.contraptions.receivers.fan.SplashingRecipe; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index cc22db867..104150150 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -38,6 +38,11 @@ public class VecHelper { vec.z + (r.nextFloat() - .5f) * 2 * radius); } + public static Vec3d planeByNormal(Vec3d vec) { + vec = vec.normalize(); + return new Vec3d(1, 1, 1).subtract(Math.abs(vec.x), Math.abs(vec.y), Math.abs(vec.z)); + } + public static ListNBT writeNBT(Vec3d vec) { ListNBT listnbt = new ListNBT(); listnbt.add(new DoubleNBT(vec.x)); diff --git a/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeConditions.java b/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeConditions.java new file mode 100644 index 000000000..0fafa6b6b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeConditions.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.utility.recipe; + +import java.util.function.Predicate; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeType; + +/** + * Commonly used Predicates for searching through recipe collections. + * + * @author simibubi + * + */ +public class RecipeConditions { + + public static Predicate> isOfType(IRecipeType type, IRecipeType... otherTypes) { + return recipe -> { + IRecipeType recipeType = recipe.getType(); + if (recipeType == type) + return true; + for (IRecipeType other : otherTypes) + if (recipeType == other) + return true; + return false; + }; + } + + public static Predicate> firstIngredientMatches(ItemStack stack) { + return r -> !r.getIngredients().isEmpty() && r.getIngredients().get(0).test(stack); + } + + public static Predicate> outputMatchesFilter(ItemStack filter) { + return r -> filter.isEmpty() || ItemStack.areItemsEqual(filter, r.getRecipeOutput()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeFinder.java b/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeFinder.java new file mode 100644 index 000000000..1c369d74d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/recipe/RecipeFinder.java @@ -0,0 +1,96 @@ +package com.simibubi.create.foundation.utility.recipe; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.annotation.Nullable; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.world.World; + +/** + * Utility for searching through a world's recipe collection. Non-dynamic + * conditions can be split off into an initial search for caching intermediate + * results. + * + * @author simibubi + * + */ +public class RecipeFinder { + + private static Cache cachedSearches = CacheBuilder.newBuilder().build(); + + public static class StartedSearch { + List> findings; + + public StartedSearch(List> findings) { + this.findings = findings; + } + + public RecipeStream> search() { + return new RecipeStream<>(findings.stream()); + } + + public static class RecipeStream> { + Stream stream; + + public RecipeStream(Stream stream) { + this.stream = stream; + } + + @SuppressWarnings("unchecked") + public > RecipeStream assumeType(IRecipeType type) { + return (RecipeStream) this; + } + + public RecipeStream filter(Predicate condition) { + stream.filter(condition); + return this; + } + + public List asList() { + return stream.collect(Collectors.toList()); + } + + } + + } + + /** + * Find all IRecipes matching the condition predicate. If this search is made + * more than once, using the same object instance as the cacheKey will retrieve + * the cached result from the first time. + * + * @param cacheKey (can be null to prevent the caching) + * @param world + * @param conditions + * @return A started search to continue with more specific conditions. + */ + public static StartedSearch get(@Nullable Object cacheKey, World world, Predicate> conditions) { + if (cacheKey == null) + return startSearch(world, conditions); + + try { + return cachedSearches.get(cacheKey, () -> startSearch(world, conditions)); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + return new StartedSearch(Collections.emptyList()); + } + + private static StartedSearch startSearch(World world, Predicate> conditions) { + List> list = world.getRecipeManager().getRecipes().stream().filter(conditions) + .collect(Collectors.toList()); + return new StartedSearch(list); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java index 998ca1ef9..5cc41fa23 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java @@ -6,28 +6,47 @@ import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; import net.minecraft.util.Mirror; import net.minecraft.util.Rotation; public abstract class DirectionalKineticBlock extends KineticBlock { public static final DirectionProperty FACING = BlockStateProperties.FACING; - + public DirectionalKineticBlock(Properties properties) { super(properties); } - + @Override protected void fillStateContainer(Builder builder) { builder.add(FACING); super.fillStateContainer(builder); } - + + public Direction getPreferredFacing(BlockItemUseContext context) { + Direction prefferedSide = null; + for (Direction side : Direction.values()) { + BlockState blockState = context.getWorld().getBlockState(context.getPos().offset(side)); + if (blockState.getBlock() instanceof IRotate) { + if (((IRotate) blockState.getBlock()).hasShaftTowards(context.getWorld(), context.getPos().offset(side), + blockState, side.getOpposite())) + if (prefferedSide != null && prefferedSide.getAxis() != side.getAxis()) { + prefferedSide = null; + break; + } else { + prefferedSide = side; + } + } + } + return prefferedSide; + } + @Override public BlockState getStateForPlacement(BlockItemUseContext context) { return getDefaultState().with(FACING, context.getFace()); } - + @Override public BlockState rotate(BlockState state, Rotation rot) { return state.with(FACING, rot.rotate(state.get(FACING))); @@ -37,5 +56,5 @@ public abstract class DirectionalKineticBlock extends KineticBlock { public BlockState mirror(BlockState state, Mirror mirrorIn) { return state.rotate(mirrorIn.toRotation(state.get(FACING))); } - + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticle.java b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticle.java new file mode 100644 index 000000000..d12fe1e9e --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticle.java @@ -0,0 +1,176 @@ +package com.simibubi.create.modules.contraptions.particle; + +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.contraptions.receivers.fan.EncasedFanTileEntity; +import com.simibubi.create.modules.logistics.InWorldProcessing; + +import net.minecraft.block.Blocks; +import net.minecraft.client.particle.IAnimatedSprite; +import net.minecraft.client.particle.IParticleFactory; +import net.minecraft.client.particle.IParticleRenderType; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.SimpleAnimatedParticle; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.ParticleType; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class AirFlowParticle extends SimpleAnimatedParticle { + + private EncasedFanTileEntity source; + + protected AirFlowParticle(World world, EncasedFanTileEntity source, double x, double y, double z, + IAnimatedSprite sprite) { + super(world, x, y, z, sprite, world.rand.nextFloat() * .5f); + this.source = source; + this.particleScale *= 0.75F; + this.maxAge = 40; + canCollide = false; + selectSprite(7); + Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .25f); + this.setPosition(posX + offset.x, posY + offset.y, posZ + offset.z); + this.prevPosX = posX; + this.prevPosY = posY; + this.prevPosZ = posZ; + setAlphaF(.25f); + } + + public IParticleRenderType getRenderType() { + return IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT; + } + + @Override + public void tick() { + if (source == null || source.isRemoved()) { + dissipate(); + return; + } + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + if (this.age++ >= this.maxAge) { + this.setExpired(); + } else { + if (source.airCurrent == null || !source.airCurrent.bounds.grow(.25f).contains(posX, posY, posZ)) { + dissipate(); + return; + } + + Vec3d directionVec = new Vec3d(source.airCurrent.direction.getDirectionVec()); + Vec3d motion = directionVec.scale(1 / 8f); + if (!source.airCurrent.pushing) + motion = motion.scale(-1); + + double distance = new Vec3d(posX, posY, posZ).subtract(VecHelper.getCenterOf(source.getPos())) + .mul(directionVec).length() - .5f; + if (distance > source.airCurrent.maxDistance + 1 || distance < -.25f) { + dissipate(); + return; + } + motion = motion.scale(source.airCurrent.maxDistance - (distance - 1f)).scale(.5f); + selectSprite((int) MathHelper.clamp((distance / source.airCurrent.maxDistance) * 8 + world.rand.nextInt(4), + 0, 7)); + + morphType(distance); + + motionX = motion.x; + motionY = motion.y; + motionZ = motion.z; + + if (this.onGround) { + this.motionX *= (double) 0.7F; + this.motionZ *= (double) 0.7F; + } + this.move(this.motionX, this.motionY, this.motionZ); + + } + + } + + public void morphType(double distance) { + InWorldProcessing.Type type = source.airCurrent.getSegmentAt((float) distance); + + if (type == InWorldProcessing.Type.SPLASHING) { + setColor(ColorHelper.mixColors(0x4499FF, 0x2277FF, world.rand.nextFloat())); + setAlphaF(1f); + selectSprite(world.rand.nextInt(3)); + if (world.rand.nextFloat() < 1 / 32f) + world.addParticle(ParticleTypes.BUBBLE, posX, posY, posZ, motionX * .125f, motionY * .125f, + motionZ * .125f); + if (world.rand.nextFloat() < 1 / 32f) + world.addParticle(ParticleTypes.BUBBLE_POP, posX, posY, posZ, motionX * .125f, motionY * .125f, + motionZ * .125f); + } + + if (type == InWorldProcessing.Type.SMOKING) { + setColor(ColorHelper.mixColors(0x0, 0x555555, world.rand.nextFloat())); + setAlphaF(1f); + selectSprite(world.rand.nextInt(3)); + if (world.rand.nextFloat() < 1 / 32f) + world.addParticle(ParticleTypes.SMOKE, posX, posY, posZ, motionX * .125f, motionY * .125f, + motionZ * .125f); + if (world.rand.nextFloat() < 1 / 32f) + world.addParticle(ParticleTypes.LARGE_SMOKE, posX, posY, posZ, motionX * .125f, motionY * .125f, + motionZ * .125f); + } + + if (type == InWorldProcessing.Type.BLASTING) { + setColor(ColorHelper.mixColors(0xFF4400, 0xFF8855, world.rand.nextFloat())); + setAlphaF(.5f); + selectSprite(world.rand.nextInt(3)); + if (world.rand.nextFloat() < 1 / 32f) + world.addParticle(ParticleTypes.FLAME, posX, posY, posZ, motionX * .25f, motionY * .25f, + motionZ * .25f); + if (world.rand.nextFloat() < 1 / 16f) + world.addParticle(new BlockParticleData(ParticleTypes.BLOCK, Blocks.LAVA.getDefaultState()), posX, posY, + posZ, motionX * .25f, motionY * .25f, motionZ * .25f); + } + + if (type == null) { + setColor(0xEEEEEE); + setAlphaF(.25f); + setSize(.2f, .2f); + } + } + + private void dissipate() { + setExpired(); + } + + public int getBrightnessForRender(float partialTick) { + BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ); + return this.world.isBlockPresent(blockpos) ? this.world.getCombinedLight(blockpos, 0) : 0; + } + + private void selectSprite(int index) { + setSprite(field_217584_C.get(index, 8)); + } + + public static class Type extends ParticleType { + public Type() { + super(false, AirFlowParticleData.DESERIALIZER); + } + } + + public static class Factory implements IParticleFactory { + private final IAnimatedSprite spriteSet; + + public Factory(IAnimatedSprite animatedSprite) { + this.spriteSet = animatedSprite; + } + + public Particle makeParticle(AirFlowParticleData data, World worldIn, double x, double y, double z, + double xSpeed, double ySpeed, double zSpeed) { + TileEntity te = worldIn.getTileEntity(new BlockPos(data.posX, data.posY, data.posZ)); + if (!(te instanceof EncasedFanTileEntity)) + te = null; + return new AirFlowParticle(worldIn, (EncasedFanTileEntity) te, x, y, z, this.spriteSet); + } + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java new file mode 100644 index 000000000..56ba97113 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java @@ -0,0 +1,64 @@ +package com.simibubi.create.modules.contraptions.particle; + +import java.util.Locale; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.simibubi.create.AllParticles; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.particles.IParticleData; +import net.minecraft.particles.ParticleType; +import net.minecraft.util.math.Vec3i; + +public class AirFlowParticleData implements IParticleData { + + public static final IParticleData.IDeserializer DESERIALIZER = new IParticleData.IDeserializer() { + public AirFlowParticleData deserialize(ParticleType particleTypeIn, StringReader reader) + throws CommandSyntaxException { + reader.expect(' '); + int x = reader.readInt(); + reader.expect(' '); + int y = reader.readInt(); + reader.expect(' '); + int z = reader.readInt(); + return new AirFlowParticleData(x, y, z); + } + + public AirFlowParticleData read(ParticleType particleTypeIn, PacketBuffer buffer) { + return new AirFlowParticleData(buffer.readInt(), buffer.readInt(), buffer.readInt()); + } + }; + + final int posX; + final int posY; + final int posZ; + + public AirFlowParticleData(Vec3i pos) { + this(pos.getX(), pos.getY(), pos.getZ()); + } + + public AirFlowParticleData(int posX, int posY, int posZ) { + this.posX = posX; + this.posY = posY; + this.posZ = posZ; + } + + @Override + public ParticleType getType() { + return AllParticles.AIR_FLOW.get(); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeInt(posX); + buffer.writeInt(posY); + buffer.writeInt(posZ); + } + + @Override + public String getParameters() { + return String.format(Locale.ROOT, "%s %d %d %d", AllParticles.ROTATION_INDICATOR.parameter(), posX, posY, posZ); + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBeltHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBeltHandler.java deleted file mode 100644 index ab4e01f04..000000000 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBeltHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.simibubi.create.modules.contraptions.receivers; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.modules.logistics.InWorldProcessing; -import com.simibubi.create.modules.logistics.InWorldProcessing.Type; - -import net.minecraft.particles.ParticleTypes; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -public class EncasedFanBeltHandler { - - // Fans need to be aware of belt TEs within their range - // all belts are handled equally - // requires ref to controller and index - - static List findBelts(EncasedFanTileEntity fan) { - if (fan.getSpeed() == 0) - return Collections.emptyList(); - List belts = new ArrayList<>(); - AxisAlignedBB searchBB = fan.frontBB.shrink(.25).contract(0, 0, 0).expand(0, -.25f, 0); - - BlockPos.getAllInBox((int) searchBB.minX, (int) searchBB.minY, (int) searchBB.minZ, (int) searchBB.maxX - 1, - (int) searchBB.maxY - 1, (int) searchBB.maxZ - 1) - .filter(p -> AllBlocks.BELT.typeOf(fan.getWorld().getBlockState(p))).forEach(p -> { - TileEntity te = fan.getWorld().getTileEntity(p); - if (te == null || !(te instanceof BeltTileEntity)) - return; - belts.add((BeltTileEntity) te); - }); - - return belts; - } - - static void tickBelts(EncasedFanTileEntity fan, List belts) { - Type processingType = fan.getProcessingType(); - if (processingType == null) - return; - for (BeltTileEntity belt : belts) { - BeltTileEntity controller = belt.getControllerTE(); - if (controller == null) - continue; - World world = belt.getWorld(); - - controller.getInventory().forEachWithin(belt.index + .5f, .5f, (transported) -> { - if (world.rand.nextInt(4) == 0 && world.isRemote) { - Vec3d vec = controller.getInventory().getVectorForOffset(transported.beltPosition); - if (processingType == Type.BLASTING) - world.addParticle(ParticleTypes.LARGE_SMOKE, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0); - if (processingType == Type.SMOKING) - world.addParticle(ParticleTypes.CLOUD, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0); - if (processingType == Type.SPLASHING) - world.addParticle(ParticleTypes.BUBBLE_POP, vec.x + (world.rand.nextFloat() - .5f) * .5f, - vec.y + .25f, vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 16f, 0); - } - if (world.isRemote) - return null; - return InWorldProcessing.applyProcessing(transported, belt, processingType); - }); - } - - } -} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanParticleHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanParticleHandler.java deleted file mode 100644 index f40e14b24..000000000 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanParticleHandler.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.simibubi.create.modules.contraptions.receivers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.particles.BlockParticleData; -import net.minecraft.particles.IParticleData; -import net.minecraft.particles.ParticleTypes; -import net.minecraft.particles.RedstoneParticleData; -import net.minecraft.util.Direction; -import net.minecraft.util.math.Vec3i; - -public class EncasedFanParticleHandler { - - public final Map> effects = new HashMap<>(); - - public EncasedFanParticleHandler() { - initEffects(); - } - - private void initEffects() { - List standardFX = new ArrayList<>(2); - standardFX.add(new FanEffect(ParticleTypes.BUBBLE_POP, 1 / 4f, 1 / 4f, 1 / 8f, 1)); - standardFX.add(new FanEffect(new RedstoneParticleData(1, 1, 1, 1), 1 / 2f, 1 / 32f, 1/16f, 512f)); - effects.put(Blocks.AIR, standardFX); - - List waterFX = new ArrayList<>(2); - waterFX.add(new FanEffect(new BlockParticleData(ParticleTypes.BLOCK, Blocks.WATER.getDefaultState()), 1 / 4f, - 1 / 2f, 1 / 4f, 1)); - waterFX.add(new FanEffect(ParticleTypes.SPLASH, 1 / 4f, 1 / 2f, 0.5f, 1)); - effects.put(Blocks.WATER, waterFX); - - List fireFX = new ArrayList<>(2); - fireFX.add(new FanEffect(ParticleTypes.LARGE_SMOKE, 1 / 4f, 1 / 8f, 0.125f, .5f)); - fireFX.add(new FanEffect(ParticleTypes.FLAME, 1 / 4f, 1 / 8f, 1 / 32f, 1 / 256f)); - effects.put(Blocks.FIRE, fireFX); - - List lavaFX = new ArrayList<>(3); - lavaFX.add(new FanEffect(new BlockParticleData(ParticleTypes.BLOCK, Blocks.LAVA.getDefaultState()), 1 / 4f, - 1 / 2f, 1 / 4f, 1)); - lavaFX.add(new FanEffect(ParticleTypes.LAVA, 1 / 2f, 1 / 32f, 0, .25f)); - lavaFX.add(new FanEffect(ParticleTypes.FLAME, 1 / 4f, 1 / 32f, 1 / 32f, 1 / 256f)); - effects.put(Blocks.LAVA, lavaFX); - } - - public void makeParticles(EncasedFanTileEntity te) { - Direction direction = te.getAirFlow(); - Vec3i directionVec = direction.getDirectionVec(); - - boolean hasFx = false; - BlockState frontBlock = te.frontBlock; - if (frontBlock != null) { - if (effects.containsKey(frontBlock.getBlock())) { - hasFx = true; - for (FanEffect fx : effects.get(frontBlock.getBlock())) - fx.render(directionVec, true, te); - } - } - - if (!hasFx) - for (FanEffect fx : effects.get(Blocks.AIR)) - fx.render(directionVec, true, te); - - for (FanEffect fx : effects.get(Blocks.AIR)) - fx.render(directionVec, false, te); - } - - protected static class FanEffect { - private IParticleData particle; - private float density; - private float chance; - private float spread; - private float speed; - private Random r; - - public FanEffect(IParticleData particle, float density, float chance, float spread, float speed) { - r = new Random(); - this.particle = particle; - this.density = density; - this.chance = chance; - this.spread = spread; - this.speed = speed; - } - - public void render(Vec3i directionVec, boolean front, EncasedFanTileEntity te) { - render(directionVec, front ? .5f : -te.pullDistance, front ? te.pushDistance : -.5f, te); - } - - private void render(Vec3i directionVec, float start, float end, EncasedFanTileEntity te) { - float x = directionVec.getX(); - float y = directionVec.getY(); - float z = directionVec.getZ(); - float speed = this.speed * Math.abs(te.getSpeed()) / 512f; - - for (float offset = start; offset < end; offset += density) { - if (r.nextFloat() > chance) - continue; - float xs = rollOffset() * spread; - float ys = rollOffset() * spread; - float zs = rollOffset() * spread; - float xs2 = rollOffset() * spread; - float ys2 = rollOffset() * spread; - float zs2 = rollOffset() * spread; - te.getWorld().addParticle(particle, te.getPos().getX() + .5f + x * offset + xs2, - te.getPos().getY() + .5f + y * offset + ys2, te.getPos().getZ() + .5f + z * offset + zs2, - x * speed + xs, y * speed + ys, z * speed + zs); - } - } - - private float rollOffset() { - return (r.nextFloat() - .5f) * 2; - } - } - -} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java deleted file mode 100644 index dd0fc8a2c..000000000 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java +++ /dev/null @@ -1,318 +0,0 @@ -package com.simibubi.create.modules.contraptions.receivers; - -import static com.simibubi.create.CreateConfig.parameters; -import static net.minecraft.state.properties.BlockStateProperties.AXIS; -import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; -import static net.minecraft.util.Direction.AxisDirection.POSITIVE; - -import java.util.Collections; -import java.util.List; - -import com.simibubi.create.AllBlockTags; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.CreateClient; -import com.simibubi.create.CreateConfig; -import com.simibubi.create.foundation.utility.VecHelper; -import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.modules.logistics.InWorldProcessing; -import com.simibubi.create.modules.logistics.InWorldProcessing.Type; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.ItemEntity; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.particles.ParticleTypes; -import net.minecraft.util.DamageSource; -import net.minecraft.util.Direction; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvents; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; - -public class EncasedFanTileEntity extends GeneratingKineticTileEntity { - - private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled() - .setFireDamage(); - private static DamageSource damageSourceLava = new DamageSource("create.fan_lava").setDifficultyScaled() - .setFireDamage(); - private static EncasedFanParticleHandler particleHandler; - - protected float pushDistance; - protected float pullDistance; - protected AxisAlignedBB frontBB; - protected AxisAlignedBB backBB; - - protected int blockCheckCooldown; - protected boolean findFrontBlock; - protected BlockState frontBlock; - protected boolean isGenerator; - protected List affectedBelts = Collections.emptyList(); - - public EncasedFanTileEntity() { - super(AllTileEntities.ENCASED_FAN.type); - blockCheckCooldown = -1; - findFrontBlock = true; - frontBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); - backBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); - particleHandler = CreateClient.fanParticles; - isGenerator = false; - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - super.readClientUpdate(tag); - updateFrontBlock(); - updateBBs(); - affectedBelts = EncasedFanBeltHandler.findBelts(this); - } - - @Override - public void read(CompoundNBT compound) { - super.read(compound); - isGenerator = compound.getBoolean("Generating"); - pushDistance = compound.getFloat("PushDistance"); - pullDistance = compound.getFloat("PullDistance"); - } - - @Override - public CompoundNBT write(CompoundNBT compound) { - compound.putBoolean("Generating", isGenerator); - compound.putFloat("PushDistance", pushDistance); - compound.putFloat("PullDistance", pullDistance); - return super.write(compound); - } - - @Override - public float getAddedStressCapacity() { - return isGenerator ? super.getAddedStressCapacity() : 0; - } - - @Override - public float getGeneratedSpeed() { - return isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0; - } - - public void updateGenerator() { - boolean shouldGenerate = world.isBlockPowered(pos) && world.isBlockPresent(pos.down()) && blockBelowIsHot(); - if (shouldGenerate == isGenerator) - return; - - isGenerator = shouldGenerate; - updateGeneratedRotation(); - } - - public boolean blockBelowIsHot() { - return world.getBlockState(pos.down()).getBlock().isIn(AllBlockTags.FAN_HEATERS.tag); - } - - protected void updateReachAndForce() { - if (getWorld() == null) - return; - if (world.isRemote) - return; - - float speed = Math.abs(this.getSpeed()); - float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1); - - pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get()); - pullDistance = MathHelper.lerp(distanceFactor, 1.5f, parameters.fanMaxPullDistance.get()); - - Direction direction = getAirFlow(); - if (speed != 0) { - for (int distance = 1; distance <= pushDistance; distance++) { - if (!EncasedFanBlock.canAirPassThrough(world, getPos().offset(direction, distance), direction)) { - pushDistance = distance - 1; - break; - } - } - for (int distance = 1; distance <= pullDistance; distance++) { - if (!EncasedFanBlock.canAirPassThrough(world, getPos().offset(direction, -distance), direction)) { - pullDistance = distance - 1; - break; - } - } - updateBBs(); - } else { - frontBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); - backBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); - } - - affectedBelts = EncasedFanBeltHandler.findBelts(this); - sendData(); - } - - protected void updateBBs() { - Direction flow = getAirFlow(); - if (flow == null) - return; - Vec3i flowVec = flow.getDirectionVec(); - float remainder = pushDistance - (int) pushDistance; - frontBB = new AxisAlignedBB(pos.offset(flow), pos.offset(flow, (int) pushDistance)) - .expand(flowVec.getX() * remainder + 1, flowVec.getY() * remainder + 1, flowVec.getZ() * remainder + 1) - .grow(.25f); - remainder = pullDistance - (int) pullDistance; - backBB = new AxisAlignedBB(pos.offset(flow, -(int) pullDistance), pos.offset(flow, -1)) - .expand(-flowVec.getX() * remainder + 1, -flowVec.getY() * remainder + 1, - -flowVec.getZ() * remainder + 1) - .grow(.25f); - } - - public void updateFrontBlock() { - Direction facing = getAirFlow(); - if (facing == null) { - frontBlock = Blocks.AIR.getDefaultState(); - return; - } - BlockPos front = pos.offset(facing); - if (world.isBlockPresent(front)) - frontBlock = world.getBlockState(front); - updateReachAndForce(); - } - - public Direction getAirFlow() { - if (getSpeed() == 0) - return null; - return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), getSpeed() > 0 ? POSITIVE : NEGATIVE); - } - - @Override - public void onSpeedChanged() { - updateReachAndForce(); - updateFrontBlock(); - } - - @Override - public void tick() { - super.tick(); - - if (getSpeed() == 0 || isGenerator) - return; - - EncasedFanBeltHandler.tickBelts(this, affectedBelts); - - List frontEntities = world.getEntitiesWithinAABBExcludingEntity(null, frontBB); - for (Entity entity : frontEntities) { - moveEntity(entity, true); - processEntity(entity); - } - - for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, backBB)) { - moveEntity(entity, false); - } - - if (findFrontBlock) { - findFrontBlock = false; - updateFrontBlock(); - } - - if (!world.isRemote && blockCheckCooldown-- <= 0) { - blockCheckCooldown = parameters.fanBlockCheckRate.get(); - updateReachAndForce(); - } - - if (world.isRemote) { - particleHandler.makeParticles(this); - return; - } - - } - - public void processEntity(Entity entity) { - if (InWorldProcessing.isFrozen()) - return; - - if (entity instanceof ItemEntity) { - if (world.rand.nextInt(4) == 0) { - Type processingType = getProcessingType(); - if (processingType == Type.BLASTING) - world.addParticle(ParticleTypes.LARGE_SMOKE, entity.posX, entity.posY + .25f, entity.posZ, 0, - 1 / 16f, 0); - if (processingType == Type.SMOKING) - world.addParticle(ParticleTypes.CLOUD, entity.posX, entity.posY + .25f, entity.posZ, 0, 1 / 16f, 0); - if (processingType == Type.SPLASHING) - world.addParticle(ParticleTypes.BUBBLE_POP, entity.posX + (world.rand.nextFloat() - .5f) * .5f, - entity.posY + .25f, entity.posZ + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 16f, 0); - } - - if (world.isRemote) - return; - - if (canProcess((ItemEntity) entity)) - InWorldProcessing.applyProcessing((ItemEntity) entity, getProcessingType()); - - } else { - if (getProcessingType() == Type.SMOKING) { - entity.setFire(2); - entity.attackEntityFrom(damageSourceFire, 4); - } - if (getProcessingType() == Type.BLASTING) { - entity.setFire(10); - entity.attackEntityFrom(damageSourceLava, 8); - } - if (getProcessingType() == Type.SPLASHING) { - if (entity.isBurning()) { - entity.extinguish(); - world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, - SoundCategory.NEUTRAL, 0.7F, - 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); - } - } - } - } - - protected boolean canProcess() { - return getProcessingType() != null; - } - - protected boolean canProcess(ItemEntity entity) { - return canProcess() && InWorldProcessing.canProcess(entity, getProcessingType()); - } - - protected InWorldProcessing.Type getProcessingType() { - if (frontBlock == null) - return null; - - Block block = frontBlock.getBlock(); - - if (block == Blocks.FIRE) - return Type.SMOKING; - if (block == Blocks.WATER) - return Type.SPLASHING; - if (block == Blocks.LAVA) - return Type.BLASTING; - - return null; - } - - protected void moveEntity(Entity entity, boolean push) { - if ((entity instanceof ItemEntity) && AllBlocks.BELT.typeOf(world.getBlockState(entity.getPosition())) - && getAirFlow() != Direction.UP) { - return; - } - - Vec3d center = VecHelper.getCenterOf(pos); - Vec3i flow = getAirFlow().getDirectionVec(); - - float sneakModifier = entity.isSneaking() ? 4096f : 512f; - float acceleration = (float) (getSpeed() * 1 / sneakModifier - / (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance))); - Vec3d previousMotion = entity.getMotion(); - float maxAcceleration = 5; - - double xIn = MathHelper.clamp(flow.getX() * acceleration - previousMotion.x, -maxAcceleration, maxAcceleration); - double yIn = MathHelper.clamp(flow.getY() * acceleration - previousMotion.y, -maxAcceleration, maxAcceleration); - double zIn = MathHelper.clamp(flow.getZ() * acceleration - previousMotion.z, -maxAcceleration, maxAcceleration); - - entity.setMotion( - previousMotion.add(new Vec3d(xIn, yIn, zIn).mul(flow.getX(), flow.getY(), flow.getZ()).scale(1 / 8f))); - entity.fallDistance = 0; - } - -} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntityRenderer.java deleted file mode 100644 index 069036195..000000000 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntityRenderer.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.simibubi.create.modules.contraptions.receivers; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; - -import net.minecraft.block.BlockState; -import net.minecraft.state.properties.BlockStateProperties; - -public class EncasedFanTileEntityRenderer extends KineticTileEntityRenderer { - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return AllBlocks.ENCASED_FAN_INNER.get().getDefaultState().with(BlockStateProperties.AXIS, - te.getBlockState().get(BlockStateProperties.AXIS)); - } - -} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/SawTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/SawTileEntity.java index 631c28311..b20757e8f 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/SawTileEntity.java @@ -5,12 +5,13 @@ import static com.simibubi.create.modules.contraptions.receivers.SawBlock.RUNNIN import java.util.LinkedList; import java.util.List; import java.util.Random; -import java.util.stream.Collectors; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.recipe.RecipeConditions; +import com.simibubi.create.foundation.utility.recipe.RecipeFinder; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.logistics.block.IHaveFilter; @@ -39,6 +40,7 @@ import net.minecraftforge.items.IItemHandler; public class SawTileEntity extends KineticTileEntity implements IHaveFilter { + private static final Object cuttingRecipesKey = new Object(); public ProcessingInventory inventory; private int recipeIndex; private ItemStack filter; @@ -235,7 +237,7 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter { } private void applyRecipe() { - List> recipes = getRecipes(); + List> recipes = getRecipes(); if (recipes.isEmpty()) return; if (recipeIndex >= recipes.size()) @@ -267,14 +269,12 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter { } - private List> getRecipes() { - List> recipes = world.getRecipeManager().getRecipes().parallelStream() - .filter(r -> r.getType() == IRecipeType.STONECUTTING || r.getType() == AllRecipes.Types.CUTTING) - .filter(r -> filter.isEmpty() || ItemStack.areItemsEqual(filter, r.getRecipeOutput())) - .filter(r -> !r.getIngredients().isEmpty() - && r.getIngredients().get(0).test(inventory.getStackInSlot(0))) - .collect(Collectors.toList()); - return recipes; + private List> getRecipes() { + return RecipeFinder + .get(cuttingRecipesKey, world, + RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipes.Types.CUTTING)) + .search().filter(RecipeConditions.outputMatchesFilter(filter)) + .filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))).asList(); } public void insertItem(ItemEntity entity) { @@ -299,7 +299,7 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter { if (world.isRemote) return; - List> recipes = getRecipes(); + List> recipes = getRecipes(); boolean valid = !recipes.isEmpty(); int time = 100; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/AirCurrent.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/AirCurrent.java new file mode 100644 index 000000000..fbcf818e8 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/AirCurrent.java @@ -0,0 +1,294 @@ +package com.simibubi.create.modules.contraptions.receivers.fan; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.CreateClientConfig; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.contraptions.particle.AirFlowParticleData; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.modules.logistics.InWorldProcessing; +import com.simibubi.create.modules.logistics.InWorldProcessing.Type; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.Direction; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.World; + +public class AirCurrent { + + private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled() + .setFireDamage(); + private static DamageSource damageSourceLava = new DamageSource("create.fan_lava").setDifficultyScaled() + .setFireDamage(); + + public final EncasedFanTileEntity source; + public AxisAlignedBB bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + public List segments = new ArrayList<>(); + public Direction direction; + public boolean pushing; + public float maxDistance; + + protected List> affectedBelts = new ArrayList<>(); + protected List caughtEntities = new ArrayList<>(); + + public AirCurrent(EncasedFanTileEntity source) { + this.source = source; + } + + public void tick() { + World world = source.getWorld(); + Direction facing = direction; + if (world.isRemote) { + float offset = pushing ? 0.5f : maxDistance + .5f; + Vec3d pos = VecHelper.getCenterOf(source.getPos()).add(new Vec3d(facing.getDirectionVec()).scale(offset)); + if (world.rand.nextFloat() < CreateClientConfig.instance.fanParticleDensity.get()) + world.addParticle(new AirFlowParticleData(source.getPos()), pos.x, pos.y, pos.z, 0, 0, 0); + } + + for (Iterator iterator = caughtEntities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + if (!entity.getBoundingBox().intersects(bounds)) { + iterator.remove(); + continue; + } + + Vec3d center = VecHelper.getCenterOf(source.getPos()); + Vec3i flow = (pushing ? facing : facing.getOpposite()).getDirectionVec(); + + float sneakModifier = entity.isSneaking() ? 4096f : 512f; + float speed = Math.abs(source.getSpeed()); + double entityDistance = entity.getPositionVec().distanceTo(center); + float acceleration = (float) (speed / sneakModifier / (entityDistance / maxDistance)); + Vec3d previousMotion = entity.getMotion(); + float maxAcceleration = 5; + + double xIn = MathHelper.clamp(flow.getX() * acceleration - previousMotion.x, -maxAcceleration, + maxAcceleration); + double yIn = MathHelper.clamp(flow.getY() * acceleration - previousMotion.y, -maxAcceleration, + maxAcceleration); + double zIn = MathHelper.clamp(flow.getZ() * acceleration - previousMotion.z, -maxAcceleration, + maxAcceleration); + + entity.setMotion(previousMotion.add(new Vec3d(xIn, yIn, zIn).scale(1 / 8f))); + entity.fallDistance = 0; + + if (InWorldProcessing.isFrozen()) + return; + + entityDistance -= .5f; + InWorldProcessing.Type processingType = getSegmentAt((float) entityDistance); + if (entity instanceof ItemEntity) { + InWorldProcessing.spawnParticlesForProcessing(world, entity.getPositionVec(), processingType); + if (InWorldProcessing.canProcess(((ItemEntity) entity), processingType)) + InWorldProcessing.applyProcessing((ItemEntity) entity, processingType); + + } else { + if (processingType == InWorldProcessing.Type.SMOKING) { + entity.setFire(2); + entity.attackEntityFrom(damageSourceFire, 2); + } + if (processingType == InWorldProcessing.Type.BLASTING) { + entity.setFire(10); + entity.attackEntityFrom(damageSourceLava, 4); + } + if (processingType == InWorldProcessing.Type.SPLASHING) { + if (entity.isBurning()) { + entity.extinguish(); + world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, + SoundCategory.NEUTRAL, 0.7F, + 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); + } + } + } + } + + tickBelts(); + } + + public void rebuild() { + if (source.getSpeed() == 0) { + maxDistance = 0; + segments.clear(); + bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + return; + } + + World world = source.getWorld(); + BlockPos start = source.getPos(); + direction = source.getBlockState().get(BlockStateProperties.FACING); + pushing = source.getAirFlowDirection() == direction; + Vec3d directionVec = new Vec3d(direction.getDirectionVec()); + Vec3d planeVec = VecHelper.planeByNormal(directionVec); + + // 4 Rays test for holes in the shapes blocking the flow + float offsetDistance = .25f; + Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance), + planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance), + planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance), + planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), }; + + maxDistance = source.getMaxDistance(); + float limitedDistance = 0; + + // Determine the distance of the air flow + Outer: for (int i = 1; i < maxDistance; i++) { + BlockPos currentPos = start.offset(direction, i); + if (!world.isBlockPresent(currentPos)) + break; + BlockState state = world.getBlockState(currentPos); + VoxelShape voxelshape = state.getCollisionShape(world, currentPos, ISelectionContext.dummy()); + + for (Vec3d offset : offsets) { + Vec3d rayStart = VecHelper.getCenterOf(currentPos).subtract(directionVec.scale(.5f + 1 / 32f)) + .add(offset); + Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f)); + BlockRayTraceResult blockraytraceresult = world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, + state); + if (blockraytraceresult == null) + continue Outer; + + double distance = i - 1 + blockraytraceresult.getHitVec().distanceTo(rayStart); + if (limitedDistance < distance) + limitedDistance = (float) distance; + } + + maxDistance = limitedDistance; + break; + } + + // Determine segments with transported fluids/gases + AirCurrentSegment currentSegment = new AirCurrentSegment(); + segments.clear(); + currentSegment.startOffset = 0; + InWorldProcessing.Type type = null; + + int limit = (int) (maxDistance + .5f); + int searchStart = pushing ? 0 : limit; + int searchEnd = pushing ? limit : 0; + int searchStep = pushing ? 1 : -1; + + for (int i = searchStart; i * searchStep <= searchEnd * searchStep; i += searchStep) { + BlockPos currentPos = start.offset(direction, i); + InWorldProcessing.Type newType = InWorldProcessing.Type.byBlock(world, currentPos); + if (newType != null) + type = newType; + if (currentSegment.type != type || currentSegment.startOffset == 0) { + currentSegment.endOffset = i; + if (currentSegment.startOffset != 0) + segments.add(currentSegment); + currentSegment = new AirCurrentSegment(); + currentSegment.startOffset = i; + currentSegment.type = type; + } + } + currentSegment.endOffset = searchEnd + searchStep; + segments.add(currentSegment); + + // Build Bounding Box + if (maxDistance < 0.25f) + bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + else { + float factor = maxDistance - 1; + Vec3d scale = directionVec.scale(factor); + if (factor > 0) + bounds = new AxisAlignedBB(start.offset(direction)).expand(scale); + else { + bounds = new AxisAlignedBB(start.offset(direction)).contract(scale.x, scale.y, scale.z).offset(scale); + } + } + findAffectedBelts(); + } + + public void findEntities() { + caughtEntities.clear(); + caughtEntities = source.getWorld().getEntitiesWithinAABBExcludingEntity(null, bounds); + } + + public void findAffectedBelts() { + World world = source.getWorld(); + BlockPos start = source.getPos(); + affectedBelts.clear(); + for (int i = 0; i < maxDistance + 1; i++) { + Type type = getSegmentAt(i); + if (type != null) { + BlockPos pos = start.offset(direction, i); + TileEntity te = world.getTileEntity(pos); + if (te != null && (te instanceof BeltTileEntity)) + affectedBelts.add(Pair.of((BeltTileEntity) te, type)); + if (direction.getAxis().isVertical()) + continue; + + pos = pos.down(); + te = world.getTileEntity(pos); + if (te == null || !(te instanceof BeltTileEntity)) + continue; + affectedBelts.add(Pair.of((BeltTileEntity) te, type)); + } + } + } + + public void tickBelts() { + for (Pair pair : affectedBelts) { + BeltTileEntity belt = pair.getKey(); + InWorldProcessing.Type processingType = pair.getRight(); + BeltTileEntity controller = belt.getControllerTE(); + if (controller == null) + continue; + World world = belt.getWorld(); + + controller.getInventory().forEachWithin(belt.index + .5f, .5f, (transported) -> { + InWorldProcessing.spawnParticlesForProcessing(world, + controller.getInventory().getVectorForOffset(transported.beltPosition), processingType); + if (world.isRemote) + return null; + return InWorldProcessing.applyProcessing(transported, belt, processingType); + }); + } + } + + public void writeToNBT(CompoundNBT nbt) { + + } + + public void readFromNBT(CompoundNBT nbt) { + + } + + public InWorldProcessing.Type getSegmentAt(float offset) { + for (AirCurrentSegment airCurrentSegment : segments) { + if (offset > airCurrentSegment.endOffset && pushing) + continue; + if (offset < airCurrentSegment.endOffset && !pushing) + continue; + return airCurrentSegment.type; + } + return null; + } + + public static class AirCurrentSegment { + InWorldProcessing.Type type; + int startOffset; + int endOffset; + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanBlock.java similarity index 53% rename from src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java rename to src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanBlock.java index 089a2cfae..5253d6315 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanBlock.java @@ -1,11 +1,11 @@ -package com.simibubi.create.modules.contraptions.receivers; +package com.simibubi.create.modules.contraptions.receivers.fan; -import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.block.IWithTileEntity; -import com.simibubi.create.modules.contraptions.relays.EncasedShaftBlock; +import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.item.BlockItemUseContext; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; @@ -16,7 +16,11 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.World; -public class EncasedFanBlock extends EncasedShaftBlock implements IWithTileEntity { +public class EncasedFanBlock extends DirectionalKineticBlock implements IWithTileEntity { + + public EncasedFanBlock() { + super(Properties.from(Blocks.ANDESITE)); + } @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { @@ -33,7 +37,7 @@ public class EncasedFanBlock extends EncasedShaftBlock implements IWithTileEntit boolean isMoving) { notifyFanTile(worldIn, pos); - if (worldIn.isRemote || state.get(AXIS).isHorizontal()) + if (worldIn.isRemote || getRotationAxis(state).isHorizontal()) return; withTileEntityDo(worldIn, pos, EncasedFanTileEntity::updateGenerator); @@ -41,20 +45,15 @@ public class EncasedFanBlock extends EncasedShaftBlock implements IWithTileEntit @Override public BlockState getStateForPlacement(BlockItemUseContext context) { - if (context.isPlacerSneaking()) - return super.getStateForPlacement(context); - BlockState blockState = context.getWorld() - .getBlockState(context.getPos().offset(context.getFace().getOpposite())); - if (AllBlocks.ENCASED_FAN.typeOf(blockState)) - return getDefaultState().with(AXIS, blockState.get(AXIS)); - Axis preferred = getPreferredAxis(context); - if (preferred != null) - return getDefaultState().with(AXIS, preferred); - return super.getStateForPlacement(context); + Direction preferredFacing = getPreferredFacing(context); + if (preferredFacing == null) + preferredFacing = context.getNearestLookingDirection(); + return getDefaultState().with(FACING, + context.isPlacerSneaking() ? preferredFacing : preferredFacing.getOpposite()); } protected void notifyFanTile(IWorld world, BlockPos pos) { - withTileEntityDo(world, pos, EncasedFanTileEntity::updateFrontBlock); + withTileEntityDo(world, pos, EncasedFanTileEntity::blockInFrontChanged); } @Override @@ -62,11 +61,19 @@ public class EncasedFanBlock extends EncasedShaftBlock implements IWithTileEntit return BlockRenderLayer.CUTOUT; } - public static boolean canAirPassThrough(World world, BlockPos pos, Direction direction) { - if (!world.isBlockPresent(pos)) - return true; - BlockState state = world.getBlockState(pos); - return !Block.hasSolidSide(state, world, pos, direction.getOpposite()); + @Override + public Axis getRotationAxis(BlockState state) { + return state.get(FACING).getAxis(); + } + + @Override + protected boolean hasStaticPart() { + return true; + } + + @Override + public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) { + return face == state.get(FACING).getOpposite(); } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntity.java new file mode 100644 index 000000000..d4f3a709f --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntity.java @@ -0,0 +1,196 @@ +package com.simibubi.create.modules.contraptions.receivers.fan; + +import static com.simibubi.create.CreateConfig.parameters; + +import com.simibubi.create.AllBlockTags; +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.CreateConfig; +import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.math.MathHelper; + +public class EncasedFanTileEntity extends GeneratingKineticTileEntity { + + public AirCurrent airCurrent; + protected int airCurrentUpdateCooldown; + protected int entitySearchCooldown; + protected boolean isGenerator; + protected boolean updateAirFlow; + + public EncasedFanTileEntity() { + super(AllTileEntities.ENCASED_FAN.type); + isGenerator = false; + airCurrent = new AirCurrent(this); + updateAirFlow = true; + } + + @Override + public void readClientUpdate(CompoundNBT tag) { + super.readClientUpdate(tag); + airCurrent.rebuild(); + } + + @Override + public void read(CompoundNBT compound) { + super.read(compound); + isGenerator = compound.getBoolean("Generating"); + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + compound.putBoolean("Generating", isGenerator); + return super.write(compound); + } + + @Override + public float getAddedStressCapacity() { + return isGenerator ? super.getAddedStressCapacity() : 0; + } + + @Override + public float getGeneratedSpeed() { + return isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0; + } + + public void updateGenerator() { + boolean shouldGenerate = world.isBlockPowered(pos) && world.isBlockPresent(pos.down()) && blockBelowIsHot(); + if (shouldGenerate == isGenerator) + return; + + isGenerator = shouldGenerate; + updateGeneratedRotation(); + } + + public boolean blockBelowIsHot() { + return world.getBlockState(pos.down()).getBlock().isIn(AllBlockTags.FAN_HEATERS.tag); + } + + public float getMaxDistance() { + float speed = Math.abs(this.getSpeed()); + float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1); + float pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get()); + float pullDistance = MathHelper.lerp(distanceFactor, 1.5f, parameters.fanMaxPullDistance.get()); + return this.getSpeed() > 0 ? pushDistance : pullDistance; + } + + public Direction getAirFlowDirection() { + if (getSpeed() == 0) + return null; + Direction facing = getBlockState().get(BlockStateProperties.FACING); + return getSpeed() > 0 ? facing : facing.getOpposite(); + } + + @Override + public void onSpeedChanged() { + updateAirFlow = true; + } + + public void blockInFrontChanged() { + updateAirFlow = true; + } + + @Override + public void tick() { + super.tick(); + + if (!world.isRemote && airCurrentUpdateCooldown-- <= 0) { + airCurrentUpdateCooldown = parameters.fanBlockCheckRate.get(); + updateAirFlow = true; + } + + if (updateAirFlow) { + updateAirFlow = false; + airCurrent.rebuild(); + sendData(); + } + + if (getSpeed() == 0 || isGenerator) + return; + + if (entitySearchCooldown-- <= 0) { + entitySearchCooldown = 5; + airCurrent.findEntities(); + } + + airCurrent.tick(); + } + +// public void processEntity(Entity entity) { +// if (InWorldProcessing.isFrozen()) +// return; +// +// if (entity instanceof ItemEntity) { +// if (world.rand.nextInt(4) == 0) { +// Type processingType = getProcessingType(); +// if (processingType == Type.BLASTING) +// world.addParticle(ParticleTypes.LARGE_SMOKE, entity.posX, entity.posY + .25f, entity.posZ, 0, +// 1 / 16f, 0); +// if (processingType == Type.SMOKING) +// world.addParticle(ParticleTypes.CLOUD, entity.posX, entity.posY + .25f, entity.posZ, 0, 1 / 16f, 0); +// if (processingType == Type.SPLASHING) +// world.addParticle(ParticleTypes.BUBBLE_POP, entity.posX + (world.rand.nextFloat() - .5f) * .5f, +// entity.posY + .25f, entity.posZ + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 16f, 0); +// } +// +// if (world.isRemote) +// return; +// +// if (canProcess((ItemEntity) entity)) +// InWorldProcessing.applyProcessing((ItemEntity) entity, getProcessingType()); +// +// } else { +// if (getProcessingType() == Type.SMOKING) { +// entity.setFire(2); +// entity.attackEntityFrom(damageSourceFire, 4); +// } +// if (getProcessingType() == Type.BLASTING) { +// entity.setFire(10); +// entity.attackEntityFrom(damageSourceLava, 8); +// } +// if (getProcessingType() == Type.SPLASHING) { +// if (entity.isBurning()) { +// entity.extinguish(); +// world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, +// SoundCategory.NEUTRAL, 0.7F, +// 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); +// } +// } +// } +// } +// +// protected boolean canProcess() { +// return getProcessingType() != null; +// } +// +// protected boolean canProcess(ItemEntity entity) { +// return canProcess() && InWorldProcessing.canProcess(entity, getProcessingType()); +// } +// +// protected void moveEntity(Entity entity, boolean push) { +// if ((entity instanceof ItemEntity) && AllBlocks.BELT.typeOf(world.getBlockState(entity.getPosition())) +// && getAirFlowDirection() != Direction.UP) { +// return; +// } +// +// Vec3d center = VecHelper.getCenterOf(pos); +// Vec3i flow = getAirFlowDirection().getDirectionVec(); +// +// float sneakModifier = entity.isSneaking() ? 4096f : 512f; +// float acceleration = (float) (getSpeed() * 1 / sneakModifier +// / (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance))); +// Vec3d previousMotion = entity.getMotion(); +// float maxAcceleration = 5; +// +// double xIn = MathHelper.clamp(flow.getX() * acceleration - previousMotion.x, -maxAcceleration, maxAcceleration); +// double yIn = MathHelper.clamp(flow.getY() * acceleration - previousMotion.y, -maxAcceleration, maxAcceleration); +// double zIn = MathHelper.clamp(flow.getZ() * acceleration - previousMotion.z, -maxAcceleration, maxAcceleration); +// +// entity.setMotion( +// previousMotion.add(new Vec3d(xIn, yIn, zIn).mul(flow.getX(), flow.getY(), flow.getZ()).scale(1 / 8f))); +// entity.fallDistance = 0; +// } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntityRenderer.java new file mode 100644 index 000000000..61f50778f --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/EncasedFanTileEntityRenderer.java @@ -0,0 +1,48 @@ +package com.simibubi.create.modules.contraptions.receivers.fan; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.modules.contraptions.base.KineticTileEntity; +import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; + +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.math.MathHelper; + +public class EncasedFanTileEntityRenderer extends KineticTileEntityRenderer { + + @Override + public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks, + int destroyStage, BufferBuilder buffer) { + super.renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, buffer); + + float time = AnimationTickHolder.getRenderTick(); + float speed = te.getSpeed() * 20; + if (speed > 0) + speed = MathHelper.clamp(speed, 80, 128 * 20); + if (speed < 0) + speed = MathHelper.clamp(speed, -128 * 20, -80); + float angle = (time * speed) % 360; + angle = angle / 180f * (float) Math.PI; + + SuperByteBuffer superByteBuffer = CreateClient.bufferCache.renderBlockState(KINETIC_TILE, + getRenderedPropellerState(te)); + kineticRotationTransform(superByteBuffer, te, te.getBlockState().get(FACING).getAxis(), angle, getWorld()); + superByteBuffer.translate(x, y, z).renderInto(buffer); + + } + + @Override + protected BlockState getRenderedBlockState(KineticTileEntity te) { + return AllBlocks.SHAFT_HALF.get().getDefaultState().with(FACING, te.getBlockState().get(FACING).getOpposite()); + } + + protected BlockState getRenderedPropellerState(KineticTileEntity te) { + return AllBlocks.ENCASED_FAN_INNER.get().getDefaultState().with(FACING, te.getBlockState().get(FACING)); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/SplashingRecipe.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/SplashingRecipe.java similarity index 93% rename from src/main/java/com/simibubi/create/modules/contraptions/receivers/SplashingRecipe.java rename to src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/SplashingRecipe.java index 5058f4de1..31b95b797 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/SplashingRecipe.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/fan/SplashingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.modules.contraptions.receivers; +package com.simibubi.create.modules.contraptions.receivers.fan; import java.util.List; diff --git a/src/main/java/com/simibubi/create/modules/logistics/InWorldProcessing.java b/src/main/java/com/simibubi/create/modules/logistics/InWorldProcessing.java index ca8475e82..98500f8a6 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/InWorldProcessing.java +++ b/src/main/java/com/simibubi/create/modules/logistics/InWorldProcessing.java @@ -8,12 +8,18 @@ import java.util.Optional; import com.simibubi.create.AllRecipes; import com.simibubi.create.CreateConfig; import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.modules.contraptions.base.ProcessingRecipe; -import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe; +import com.simibubi.create.modules.contraptions.receivers.fan.SplashingRecipe; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.contraptions.relays.belt.TransportedItemStack; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CampfireBlock; import net.minecraft.entity.item.ItemEntity; +import net.minecraft.fluid.Fluids; +import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.BlastingRecipe; import net.minecraft.item.crafting.FurnaceRecipe; @@ -21,9 +27,14 @@ import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeType; import net.minecraft.item.crafting.SmokingRecipe; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.particles.RedstoneParticleData; import net.minecraft.tileentity.BlastFurnaceTileEntity; import net.minecraft.tileentity.FurnaceTileEntity; import net.minecraft.tileentity.SmokerTileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; @@ -41,6 +52,21 @@ public class InWorldProcessing { public enum Type { SMOKING, BLASTING, SPLASHING + + ; + + public static Type byBlock(IBlockReader reader, BlockPos pos) { + BlockState blockState = reader.getBlockState(pos); + IFluidState fluidState = reader.getFluidState(pos); + if (fluidState.getFluid() == Fluids.WATER) + return Type.SPLASHING; + if (blockState.getBlock() == Blocks.FIRE + || (blockState.getBlock() == Blocks.CAMPFIRE && blockState.get(CampfireBlock.LIT))) + return Type.SMOKING; + if (blockState.getBlock() == Blocks.LAVA) + return Type.BLASTING; + return null; + } } public static boolean canProcess(ItemEntity entity, Type type) { @@ -105,7 +131,8 @@ public class InWorldProcessing { } } - public static List applyProcessing(TransportedItemStack transported, BeltTileEntity belt, Type type) { + public static List applyProcessing(TransportedItemStack transported, BeltTileEntity belt, + Type type) { if (transported.processedBy != type) { transported.processedBy = type; transported.processingTime = CreateConfig.parameters.inWorldProcessingTime.get() + 1; @@ -193,7 +220,7 @@ public class InWorldProcessing { processing.putInt("Time", value); return value; } - + public static void applyRecipeOn(ItemEntity entity, IRecipe recipe) { List stacks = applyRecipeOn(entity.getItem(), recipe); if (stacks == null) @@ -243,6 +270,23 @@ public class InWorldProcessing { return stacks; } + public static void spawnParticlesForProcessing(World world, Vec3d vec, Type type) { + if (world.rand.nextInt(4) == 0 && world.isRemote) { + if (type == Type.BLASTING) + world.addParticle(ParticleTypes.LARGE_SMOKE, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0); + if (type == Type.SMOKING) + world.addParticle(ParticleTypes.POOF, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0); + if (type == Type.SPLASHING) { + Vec3d color = ColorHelper.getRGB(0x0055FF); + world.addParticle(new RedstoneParticleData((float) color.x, (float) color.y, (float) color.z, 1), + vec.x + (world.rand.nextFloat() - .5f) * .5f, vec.y + .5f, + vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + world.addParticle(ParticleTypes.SPIT, vec.x + (world.rand.nextFloat() - .5f) * .5f, vec.y + .5f, + vec.z + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + } + } + } + public static boolean isFrozen() { return CreateConfig.parameters.freezeInWorldProcessing.get(); } diff --git a/src/main/resources/assets/create/blockstates/encased_fan.json b/src/main/resources/assets/create/blockstates/encased_fan.json index dacd65e90..988875525 100644 --- a/src/main/resources/assets/create/blockstates/encased_fan.json +++ b/src/main/resources/assets/create/blockstates/encased_fan.json @@ -1,13 +1,16 @@ { - "forge_marker": 1, - "defaults": { - "model": "create:block/encased_fan" - }, - "variants": { - "axis" : { - "x": { "y": 90 }, - "y": { "x": 90 }, - "z": { } - } - } + "forge_marker": 1, + "defaults": { + "model": "create:block/encased_fan/casing" + }, + "variants": { + "facing": { + "north": { "y": 0 }, + "south": { "y": 180 }, + "west": { "y": 270 }, + "up": { "x": 270 }, + "down": { "x": 90 }, + "east": { "y": 90 } + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/blockstates/encased_fan_inner.json b/src/main/resources/assets/create/blockstates/encased_fan_inner.json index da7f43ad8..03f39ab0d 100644 --- a/src/main/resources/assets/create/blockstates/encased_fan_inner.json +++ b/src/main/resources/assets/create/blockstates/encased_fan_inner.json @@ -1,13 +1,16 @@ { - "forge_marker": 1, - "defaults": { - "model": "create:block/encased_fan_inner" - }, - "variants": { - "axis" : { - "x": { "y": 90 }, - "y": { "x": 90 }, - "z": { } - } - } + "forge_marker": 1, + "defaults": { + "model": "create:block/encased_fan/propeller" + }, + "variants": { + "facing": { + "north": { "y": 0 }, + "south": { "y": 180 }, + "west": { "y": 270 }, + "up": { "x": 270 }, + "down": { "x": 90 }, + "east": { "y": 90 } + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index f2daf42af..a42157cd6 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -546,11 +546,11 @@ "block.create.encased_fan.tooltip": "ENCASED FAN", "block.create.encased_fan.tooltip.summary": "Converts _Rotational_ _Force_ to _Air_ _Currents_ and back. Has a variety of uses.", "block.create.encased_fan.tooltip.condition1": "When Powered by Redstone", - "block.create.encased_fan.tooltip.behaviour1": "Provides _Rotational_ _Force_ from any _heat_ _sources_ immediately below itself (fan has to be vertical)", + "block.create.encased_fan.tooltip.behaviour1": "Provides _rotational_ _force_ from any _heat_ _sources_ immediately below itself. The fan has to be facing down.", "block.create.encased_fan.tooltip.condition2": "When Rotated", - "block.create.encased_fan.tooltip.behaviour2": "_Pushes_ Entities on one side, _Pulls_ on the other. Force and Speed depend on incoming Rotations.", - "block.create.encased_fan.tooltip.condition3": "When air flows through special blocks", - "block.create.encased_fan.tooltip.behaviour3": "Processes items in front of the Block: _Water_ washes, _Fire_ smokes and _Lava_ smelts the ingredient.", + "block.create.encased_fan.tooltip.behaviour2": "_Pushes_ or _Pulls_ Entities, depending on the incoming Rotation speed.", + "block.create.encased_fan.tooltip.condition3": "When blowing through special blocks", + "block.create.encased_fan.tooltip.behaviour3": "_Liquids_ and _Fire_ emit particles into the air flow. This can be used to _process_ _items._", "block.create.turntable.tooltip": "TURNTABLE", "block.create.turntable.tooltip.summary": "Turns _Rotational_ _Force_ into refined Motion Sickness.", diff --git a/src/main/resources/assets/create/models/block/encased_fan/casing.json b/src/main/resources/assets/create/models/block/encased_fan/casing.json new file mode 100644 index 000000000..508bf2e24 --- /dev/null +++ b/src/main/resources/assets/create/models/block/encased_fan/casing.json @@ -0,0 +1,78 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "back": "create:block/gearbox", + "fan_casing": "create:block/fan_casing", + "fan_side": "create:block/fan_side", + "particle": "create:block/fan_side" + }, + "elements": [ + { + "name": "Bottom", + "from": [0, 0, 0], + "to": [16, 2, 16], + "faces": { + "north": {"uv": [0, 14, 16, 16], "texture": "#fan_casing"}, + "east": {"uv": [14, 0, 16, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 14, 16, 16], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 16, 16], "rotation": 90, "texture": "#fan_side"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#fan_side"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#fan_side"} + } + }, + { + "name": "Top", + "from": [0, 14, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 2], "texture": "#fan_casing"}, + "east": {"uv": [0, 0, 2, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 0, 16, 2], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 16, 16], "rotation": 270, "texture": "#fan_side"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#fan_side"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#fan_side"} + } + }, + { + "name": "Side", + "from": [0, 2, 0], + "to": [2, 14, 16], + "faces": { + "north": {"uv": [14, 2, 16, 14], "texture": "#fan_casing"}, + "east": {"uv": [2, 0, 14, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 2, 2, 14], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 2, 16], "rotation": 270, "texture": "#fan_side"} + } + }, + { + "name": "Side", + "from": [14, 2, 0], + "to": [16, 14, 16], + "faces": { + "north": {"uv": [0, 2, 2, 14], "texture": "#fan_casing"}, + "east": {"uv": [2, 0, 14, 16], "rotation": 270, "texture": "#fan_side"}, + "south": {"uv": [14, 2, 16, 14], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 2, 16], "rotation": 270, "texture": "#fan_side"} + } + }, + { + "name": "Lattice", + "from": [2, 2, 1], + "to": [14, 14, 1], + "faces": { + "north": {"uv": [2, 2, 14, 14], "texture": "#fan_casing"}, + "south": {"uv": [2, 2, 14, 14], "texture": "#fan_casing"} + } + }, + { + "name": "Back", + "from": [2, 2, 9], + "to": [14, 14, 15], + "faces": { + "north": {"uv": [2, 2, 14, 14], "texture": "#back"}, + "south": {"uv": [2, 2, 14, 14], "texture": "#back"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/encased_fan/item.json b/src/main/resources/assets/create/models/block/encased_fan/item.json new file mode 100644 index 000000000..00f5a814e --- /dev/null +++ b/src/main/resources/assets/create/models/block/encased_fan/item.json @@ -0,0 +1,111 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "2": "create:block/gearbox", + "fan_casing": "create:block/fan_casing", + "fan_side": "create:block/fan_side", + "particle": "create:block/fan_side", + "axis_top": "create:block/axis_top", + "fan_blades": "create:block/fan_blades", + "axis": "create:block/axis" + }, + "elements": [ + { + "name": "Bottom", + "from": [0, 0, 0], + "to": [16, 2, 16], + "faces": { + "north": {"uv": [0, 14, 16, 16], "texture": "#fan_casing"}, + "east": {"uv": [14, 0, 16, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 14, 16, 16], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 16, 16], "rotation": 90, "texture": "#fan_side"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#fan_side"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#fan_side"} + } + }, + { + "name": "Top", + "from": [0, 14, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 2], "texture": "#fan_casing"}, + "east": {"uv": [0, 0, 2, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 0, 16, 2], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 16, 16], "rotation": 270, "texture": "#fan_side"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#fan_side"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#fan_side"} + } + }, + { + "name": "Side", + "from": [0, 2, 0], + "to": [2, 14, 16], + "faces": { + "north": {"uv": [14, 2, 16, 14], "texture": "#fan_casing"}, + "east": {"uv": [2, 0, 14, 16], "rotation": 90, "texture": "#fan_side"}, + "south": {"uv": [0, 2, 2, 14], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 2, 16], "rotation": 270, "texture": "#fan_side"} + } + }, + { + "name": "Side", + "from": [14, 2, 0], + "to": [16, 14, 16], + "faces": { + "north": {"uv": [0, 2, 2, 14], "texture": "#fan_casing"}, + "east": {"uv": [2, 0, 14, 16], "rotation": 270, "texture": "#fan_side"}, + "south": {"uv": [14, 2, 16, 14], "texture": "#fan_casing"}, + "west": {"uv": [14, 0, 2, 16], "rotation": 270, "texture": "#fan_side"} + } + }, + { + "name": "Lattice", + "from": [2, 2, 1], + "to": [14, 14, 1], + "faces": { + "north": {"uv": [2, 2, 14, 14], "texture": "#fan_casing"}, + "south": {"uv": [2, 2, 14, 14], "texture": "#fan_casing"} + } + }, + { + "name": "Back", + "from": [2, 2, 9], + "to": [14, 14, 15], + "faces": { + "north": {"uv": [2, 2, 14, 14], "texture": "#2"}, + "south": {"uv": [2, 2, 14, 14], "texture": "#2"} + } + }, + { + "name": "Shaft", + "from": [6, 6, 1.2], + "to": [10, 10, 16], + "faces": { + "north": {"uv": [6, 6, 10, 10], "texture": "#axis_top"}, + "east": {"uv": [6, 0, 10, 16], "rotation": 90, "texture": "#axis"}, + "south": {"uv": [6, 6, 10, 10], "texture": "#axis_top"}, + "west": {"uv": [6, 0, 10, 16], "rotation": 270, "texture": "#axis"}, + "up": {"uv": [6, 0, 10, 16], "texture": "#axis"}, + "down": {"uv": [6, 0, 10, 16], "texture": "#axis"} + } + }, + { + "name": "Fan", + "from": [1, 1, 4], + "to": [15, 15, 12], + "rotation": {"angle": 22.5, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "texture": "#fan_blades"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#fan_blades"} + } + } + ], + "groups": [0, 1, 2, 3, 4, 5, + { + "name": "encased_fan_inner", + "origin": [8, 8, 8], + "children": [6, 7] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/encased_fan/propeller.json b/src/main/resources/assets/create/models/block/encased_fan/propeller.json new file mode 100644 index 000000000..9004fe89f --- /dev/null +++ b/src/main/resources/assets/create/models/block/encased_fan/propeller.json @@ -0,0 +1,32 @@ +{ + "textures": { + "axis_top": "create:block/axis_top", + "fan_blades": "create:block/fan_blades", + "axis": "create:block/axis" + }, + "elements": [ + { + "name": "Shaft", + "from": [6, 6, 1.2], + "to": [10, 10, 8], + "faces": { + "north": {"uv": [6, 6, 10, 10], "texture": "#axis_top"}, + "east": {"uv": [6, 0, 10, 6.8], "rotation": 90, "texture": "#axis"}, + "south": {"uv": [6, 6, 10, 10], "texture": "#axis_top"}, + "west": {"uv": [6, 0, 10, 6.8], "rotation": 90, "texture": "#axis"}, + "up": {"uv": [6, 0, 10, 6.8], "rotation": 90, "texture": "#axis"}, + "down": {"uv": [6, 0, 10, 6.8], "rotation": 90, "texture": "#axis"} + } + }, + { + "name": "Fan", + "from": [1, 1, 4], + "to": [15, 15, 12], + "rotation": {"angle": 22.5, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "texture": "#fan_blades"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#fan_blades"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/encased_fan.json b/src/main/resources/assets/create/models/item/encased_fan.json index 111afb408..d86445d68 100644 --- a/src/main/resources/assets/create/models/item/encased_fan.json +++ b/src/main/resources/assets/create/models/item/encased_fan.json @@ -1,103 +1,3 @@ { - "__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)", - "parent": "block/block", - "textures": { - "particle": "create:block/fan_side", - "fan_casing": "create:block/fan_casing", - "fan_side": "create:block/fan_side", - "axis_top": "create:block/axis_top", - "fan_blades": "create:block/fan_blades", - "axis": "create:block/axis" - }, - "elements": [ - { - "name": "Bottom", - "from": [ 0, 0, 0 ], - "to": [ 16, 2, 16 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 0, 14, 16, 16 ] }, - "east": { "texture": "#fan_side", "uv": [ 14, 0, 16, 16 ], "rotation": 90 }, - "south": { "texture": "#fan_casing", "uv": [ 0, 14, 16, 16 ] }, - "west": { "texture": "#fan_side", "uv": [ 14, 0, 16, 16 ], "rotation": 90 }, - "up": { "texture": "#fan_side", "uv": [ 0, 0, 16, 16 ] }, - "down": { "texture": "#fan_side", "uv": [ 0, 0, 16, 16 ] } - } - }, - { - "name": "Top", - "from": [ 0, 14, 0 ], - "to": [ 16, 16, 16 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 0, 0, 16, 2 ] }, - "east": { "texture": "#fan_side", "uv": [ 0, 0, 2, 16 ], "rotation": 90 }, - "south": { "texture": "#fan_casing", "uv": [ 0, 0, 16, 2 ] }, - "west": { "texture": "#fan_side", "uv": [ 14, 0, 16, 16 ], "rotation": 270 }, - "up": { "texture": "#fan_side", "uv": [ 0, 0, 16, 16 ] }, - "down": { "texture": "#fan_side", "uv": [ 0, 0, 16, 16 ] } - } - }, - { - "name": "Side", - "from": [ 0, 2, 0 ], - "to": [ 2, 14, 16 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 14, 2, 16, 14 ] }, - "east": { "texture": "#fan_side", "uv": [ 2, 0, 14, 16 ], "rotation": 90 }, - "south": { "texture": "#fan_casing", "uv": [ 0, 2, 2, 14 ] }, - "west": { "texture": "#fan_side", "uv": [ 14, 0, 2, 16 ], "rotation": 270 } - } - }, - { - "name": "Side", - "from": [ 14, 2, 0 ], - "to": [ 16, 14, 16 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 0, 2, 2, 14 ] }, - "east": { "texture": "#fan_side", "uv": [ 2, 0, 14, 16 ], "rotation": 270 }, - "south": { "texture": "#fan_casing", "uv": [ 14, 2, 16, 14 ] }, - "west": { "texture": "#fan_side", "uv": [ 14, 0, 2, 16 ], "rotation": 270 } - } - }, - { - "name": "Lattice", - "from": [ 2, 2, 1 ], - "to": [ 14, 14, 1 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 2, 2, 14, 14 ] }, - "south": { "texture": "#fan_casing", "uv": [ 2, 2, 14, 14 ] } - } - }, - { - "name": "Lattice", - "from": [ 2, 2, 15 ], - "to": [ 14, 14, 15 ], - "faces": { - "north": { "texture": "#fan_casing", "uv": [ 2, 2, 14, 14 ] }, - "south": { "texture": "#fan_casing", "uv": [ 2, 2, 14, 14 ] } - } - }, - { - "name": "Shaft", - "from": [ 6, 6, 0 ], - "to": [ 10, 10, 16 ], - "faces": { - "north": { "texture": "#axis_top", "uv": [ 6, 6, 10, 10 ] }, - "east": { "texture": "#axis", "uv": [ 6, 0, 10, 16 ], "rotation": 90 }, - "south": { "texture": "#axis_top", "uv": [ 6, 6, 10, 10 ] }, - "west": { "texture": "#axis", "uv": [ 6, 0, 10, 16 ], "rotation": 270 }, - "up": { "texture": "#axis", "uv": [ 6, 0, 10, 16 ] }, - "down": { "texture": "#axis", "uv": [ 6, 0, 10, 16 ] } - } - }, - { - "name": "Fan", - "from": [ 1, 1, 4 ], - "to": [ 15, 15, 12 ], - "rotation": { "origin": [ 8, 8, 8 ], "axis": "z", "angle": 22.5 }, - "faces": { - "north": { "texture": "#fan_blades", "uv": [ 1, 1, 15, 15 ] }, - "south": { "texture": "#fan_blades", "uv": [ 1, 1, 15, 15 ] } - } - } - ] + "parent": "create:block/encased_fan/item" } \ No newline at end of file diff --git a/src/main/resources/assets/create/particles/air_flow.json b/src/main/resources/assets/create/particles/air_flow.json new file mode 100644 index 000000000..271261099 --- /dev/null +++ b/src/main/resources/assets/create/particles/air_flow.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "minecraft:generic_7", + "minecraft:generic_6", + "minecraft:generic_5", + "minecraft:generic_4", + "minecraft:generic_3", + "minecraft:generic_2", + "minecraft:generic_1", + "minecraft:generic_0" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/splashing/sand.json b/src/main/resources/data/create/recipes/splashing/sand.json index 8502ab5f3..02d552ded 100644 --- a/src/main/resources/data/create/recipes/splashing/sand.json +++ b/src/main/resources/data/create/recipes/splashing/sand.json @@ -9,7 +9,8 @@ "results": [ { "item": "minecraft:clay_ball", - "count": 2 + "count": 1, + "chance": 0.25 } ], "processingTime": 100