mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-14 20:33:43 +01:00
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
This commit is contained in:
parent
c56fd66012
commit
a1c37c5af6
35 changed files with 1322 additions and 717 deletions
|
@ -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()),
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
@ -19,15 +20,22 @@ public class CreateClientConfig {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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<T extends IRecipe<?>> implements IRecipeCategory<T> {
|
||||
|
||||
|
@ -72,12 +72,12 @@ public abstract class ProcessingViaFanCategory<T extends IRecipe<?>> 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<IRecipe<?>> 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<IRecipe<?>> firstIngredientMatches(ItemStack stack) {
|
||||
return r -> !r.getIngredients().isEmpty() && r.getIngredients().get(0).test(stack);
|
||||
}
|
||||
|
||||
public static Predicate<IRecipe<?>> outputMatchesFilter(ItemStack filter) {
|
||||
return r -> filter.isEmpty() || ItemStack.areItemsEqual(filter, r.getRecipeOutput());
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Object, StartedSearch> cachedSearches = CacheBuilder.newBuilder().build();
|
||||
|
||||
public static class StartedSearch {
|
||||
List<IRecipe<?>> findings;
|
||||
|
||||
public StartedSearch(List<IRecipe<?>> findings) {
|
||||
this.findings = findings;
|
||||
}
|
||||
|
||||
public RecipeStream<IRecipe<?>> search() {
|
||||
return new RecipeStream<>(findings.stream());
|
||||
}
|
||||
|
||||
public static class RecipeStream<R extends IRecipe<?>> {
|
||||
Stream<R> stream;
|
||||
|
||||
public RecipeStream(Stream<R> stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X extends IRecipe<?>> RecipeStream<X> assumeType(IRecipeType<X> type) {
|
||||
return (RecipeStream<X>) this;
|
||||
}
|
||||
|
||||
public RecipeStream<R> filter(Predicate<R> condition) {
|
||||
stream.filter(condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<R> 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<IRecipe<?>> 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<? super IRecipe<?>> conditions) {
|
||||
List<IRecipe<?>> list = world.getRecipeManager().getRecipes().stream().filter(conditions)
|
||||
.collect(Collectors.toList());
|
||||
return new StartedSearch(list);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ 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;
|
||||
|
||||
|
@ -23,6 +24,24 @@ public abstract class DirectionalKineticBlock extends KineticBlock {
|
|||
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());
|
||||
|
|
|
@ -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<AirFlowParticleData> {
|
||||
public Type() {
|
||||
super(false, AirFlowParticleData.DESERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements IParticleFactory<AirFlowParticleData> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<AirFlowParticleData> DESERIALIZER = new IParticleData.IDeserializer<AirFlowParticleData>() {
|
||||
public AirFlowParticleData deserialize(ParticleType<AirFlowParticleData> 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<AirFlowParticleData> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<BeltTileEntity> findBelts(EncasedFanTileEntity fan) {
|
||||
if (fan.getSpeed() == 0)
|
||||
return Collections.emptyList();
|
||||
List<BeltTileEntity> 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<BeltTileEntity> 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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<Block, List<FanEffect>> effects = new HashMap<>();
|
||||
|
||||
public EncasedFanParticleHandler() {
|
||||
initEffects();
|
||||
}
|
||||
|
||||
private void initEffects() {
|
||||
List<FanEffect> 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<FanEffect> 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<FanEffect> 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<FanEffect> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<BeltTileEntity> 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<Entity> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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<IRecipe<?>> recipes = getRecipes();
|
||||
List<? extends IRecipe<?>> recipes = getRecipes();
|
||||
if (recipes.isEmpty())
|
||||
return;
|
||||
if (recipeIndex >= recipes.size())
|
||||
|
@ -267,14 +269,12 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
|
||||
}
|
||||
|
||||
private List<IRecipe<?>> getRecipes() {
|
||||
List<IRecipe<?>> 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<? extends IRecipe<?>> 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<IRecipe<?>> recipes = getRecipes();
|
||||
List<? extends IRecipe<?>> recipes = getRecipes();
|
||||
boolean valid = !recipes.isEmpty();
|
||||
int time = 100;
|
||||
|
||||
|
|
|
@ -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<AirCurrentSegment> segments = new ArrayList<>();
|
||||
public Direction direction;
|
||||
public boolean pushing;
|
||||
public float maxDistance;
|
||||
|
||||
protected List<Pair<BeltTileEntity, InWorldProcessing.Type>> affectedBelts = new ArrayList<>();
|
||||
protected List<Entity> 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<Entity> 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<BeltTileEntity, Type> 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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<EncasedFanTileEntity> {
|
||||
public class EncasedFanBlock extends DirectionalKineticBlock implements IWithTileEntity<EncasedFanTileEntity> {
|
||||
|
||||
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))
|
||||
@Override
|
||||
public Axis getRotationAxis(BlockState state) {
|
||||
return state.get(FACING).getAxis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasStaticPart() {
|
||||
return true;
|
||||
BlockState state = world.getBlockState(pos);
|
||||
return !Block.hasSolidSide(state, world, pos, direction.getOpposite());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) {
|
||||
return face == state.get(FACING).getOpposite();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.simibubi.create.modules.contraptions.receivers;
|
||||
package com.simibubi.create.modules.contraptions.receivers.fan;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -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<TransportedItemStack> applyProcessing(TransportedItemStack transported, BeltTileEntity belt, Type type) {
|
||||
public static List<TransportedItemStack> applyProcessing(TransportedItemStack transported, BeltTileEntity belt,
|
||||
Type type) {
|
||||
if (transported.processedBy != type) {
|
||||
transported.processedBy = type;
|
||||
transported.processingTime = CreateConfig.parameters.inWorldProcessingTime.get() + 1;
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"defaults": {
|
||||
"model": "create:block/encased_fan"
|
||||
"model": "create:block/encased_fan/casing"
|
||||
},
|
||||
"variants": {
|
||||
"axis" : {
|
||||
"x": { "y": 90 },
|
||||
"y": { "x": 90 },
|
||||
"z": { }
|
||||
"facing": {
|
||||
"north": { "y": 0 },
|
||||
"south": { "y": 180 },
|
||||
"west": { "y": 270 },
|
||||
"up": { "x": 270 },
|
||||
"down": { "x": 90 },
|
||||
"east": { "y": 90 }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,16 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"defaults": {
|
||||
"model": "create:block/encased_fan_inner"
|
||||
"model": "create:block/encased_fan/propeller"
|
||||
},
|
||||
"variants": {
|
||||
"axis" : {
|
||||
"x": { "y": 90 },
|
||||
"y": { "x": 90 },
|
||||
"z": { }
|
||||
"facing": {
|
||||
"north": { "y": 0 },
|
||||
"south": { "y": 180 },
|
||||
"west": { "y": 270 },
|
||||
"up": { "x": 270 },
|
||||
"down": { "x": 90 },
|
||||
"east": { "y": 90 }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.",
|
||||
|
|
|
@ -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"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
12
src/main/resources/assets/create/particles/air_flow.json
Normal file
12
src/main/resources/assets/create/particles/air_flow.json
Normal file
|
@ -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"
|
||||
]
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
"results": [
|
||||
{
|
||||
"item": "minecraft:clay_ball",
|
||||
"count": 2
|
||||
"count": 1,
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"processingTime": 100
|
||||
|
|
Loading…
Reference in a new issue