more changes to heater and particles

-heater now uses a enum for the blaze state
-added new particles for the heater
-changed heaters voxel shape
This commit is contained in:
Zelophed 2020-07-18 20:07:22 +02:00
parent e7a851c8c0
commit b2a5a4822a
13 changed files with 510 additions and 110 deletions

View File

@ -69,6 +69,10 @@ minecraft {
}
}
compileJava {
options.compilerArgs = ["-Xdiags:verbose"]
}
sourceSets.main.resources {
srcDir 'src/generated/resources'
}

View File

@ -2,13 +2,11 @@ package com.simibubi.create;
import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.particle.AirFlowParticleData;
import com.simibubi.create.content.contraptions.particle.HeaterParticleData;
import com.simibubi.create.content.contraptions.particle.ICustomParticle;
import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData;
import com.simibubi.create.content.contraptions.particle.*;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleType;
@ -23,15 +21,21 @@ public enum AllParticleTypes {
ROTATION_INDICATOR(RotationIndicatorParticleData::new),
AIR_FLOW(AirFlowParticleData::new),
HEATER_PARTICLE(HeaterParticleData::new)
HEATER_PARTICLE(HeaterParticleData::new),
CUBE(CubeParticleData::dummy, CubeParticle.Factory::new)
;
private ParticleEntry<?> entry;
private <D extends IParticleData> AllParticleTypes(Supplier<? extends ICustomParticle<D>> typeFactory) {
<D extends IParticleData> AllParticleTypes(Supplier<? extends ICustomParticle<D>> typeFactory) {
String asId = Lang.asId(this.name());
entry = new ParticleEntry<D>(new ResourceLocation(Create.ID, asId), typeFactory);
entry = new ParticleEntry<>(new ResourceLocation(Create.ID, asId), typeFactory);
}
<D extends IParticleData> AllParticleTypes(Supplier<? extends ICustomParticle<D>> typeFactory, Supplier<IParticleFactory<D>> particleMetaFactory) {
String asId = Lang.asId(this.name());
entry = new ParticleEntry<>(new ResourceLocation(Create.ID, asId), typeFactory, particleMetaFactory);
}
public static void register(RegistryEvent.Register<ParticleType<?>> event) {
@ -56,12 +60,18 @@ public enum AllParticleTypes {
private class ParticleEntry<D extends IParticleData> {
Supplier<? extends ICustomParticle<D>> typeFactory;
Supplier<IParticleFactory<D>> particleMetaFactory;
ParticleType<D> type;
ResourceLocation id;
public ParticleEntry(ResourceLocation id, Supplier<? extends ICustomParticle<D>> typeFactory) {
public ParticleEntry(ResourceLocation id, Supplier<? extends ICustomParticle<D>> typeFactory, Supplier<IParticleFactory<D>> particleMetaFactory) {
this.id = id;
this.typeFactory = typeFactory;
this.particleMetaFactory = particleMetaFactory;
}
public ParticleEntry(ResourceLocation id, Supplier<? extends ICustomParticle<D>> typeFactory) {
this(id, typeFactory, null);
}
ParticleType<?> getType() {
@ -85,8 +95,10 @@ public enum AllParticleTypes {
@OnlyIn(Dist.CLIENT)
void registerFactory(ParticleManager particles) {
makeType();
particles.registerFactory(type, typeFactory.get()
.getFactory());
if (particleMetaFactory == null)
particles.registerFactory(type, typeFactory.get().getFactory());
else
particles.registerFactory(type, particleMetaFactory.get());
}
}

View File

@ -113,11 +113,11 @@ public class AllShapes {
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 13, 16).erase(2, 5, 2, 14, 14, 14)
.add(2, 0, 2, 14, 2, 14)
.build(),
.build(),
HEATER_BLOCK_SHAPE =
shape(2, 0, 2, 14, 16, 14).add(0, 0, 0, 16, 2, 16)
.erase(3, 5, 3, 13, 16, 13)
.build(),
shape(2, 0, 2, 14, 14, 14).add(0, 0, 0, 16, 4, 16).build(),
HEATER_BLOCK_SPECIAL_COLLISION_SHAPE =
shape(0, 0, 0, 16, 4, 16).build(),
CRUSHING_WHEEL_COLLISION_SHAPE = cuboid(0, 0, 0, 16, 22, 16),
MECHANICAL_PROCESSOR_SHAPE = shape(VoxelShapes.fullCube()).erase(4, 0, 4, 12, 16, 12)
.build(),

View File

@ -162,6 +162,7 @@ public class CreateJEI implements IModPlugin {
registration.addRecipeCatalyst(new ItemStack(AllItems.BLOCKZAPPER.get()), blockzapperCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_MIXER.get()), mixingCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(AllBlocks.BASIN.get()), mixingCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(AllBlocks.HEATER.get()), mixingCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_SAW.get()), sawingCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_SAW.get()), blockCuttingCategory.getUid());
registration.addRecipeCatalyst(new ItemStack(Blocks.STONECUTTER), blockCuttingCategory.getUid());

View File

@ -6,9 +6,7 @@ import com.simibubi.create.content.contraptions.processing.HeaterBlock;
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.CKinetics;
import net.minecraft.block.BlockState;
import net.minecraft.block.CampfireBlock;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
@ -78,9 +76,17 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
if (world == null)
return false;
BlockState checkState = world.getBlockState(pos.down());
return checkState.getBlock().isIn(AllBlockTags.FAN_HEATERS.tag)
&& ((!checkState.has(HeaterBlock.BLAZE_LEVEL)) || checkState.get(HeaterBlock.BLAZE_LEVEL) >= 1)
&& (!checkState.has(BlockStateProperties.LIT) || checkState.get(BlockStateProperties.LIT));
if (!checkState.getBlock().isIn(AllBlockTags.FAN_HEATERS.tag))
return false;
if (checkState.has(HeaterBlock.BLAZE_LEVEL) && !checkState.get(HeaterBlock.BLAZE_LEVEL).min(HeaterBlock.HeatLevel.FADING))
return false;
if (checkState.has(BlockStateProperties.LIT) && !checkState.get(BlockStateProperties.LIT))
return false;
return true;
}
public float getMaxDistance() {

View File

@ -232,7 +232,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
if (!(recipe instanceof MixingRecipe))
return true;
return ((MixingRecipe) recipe).getHeatLevelRequired() <= getHeatLevelApplied();
return ((MixingRecipe) recipe).getHeatLevelRequired() <= getHeatLevelApplied().ordinal();
}
@Override
@ -269,12 +269,12 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
return running;
}
private int getHeatLevelApplied() {
private HeaterBlock.HeatLevel getHeatLevelApplied() {
if (world == null)
return 0;
return HeaterBlock.HeatLevel.NONE;
BlockState state = world.getBlockState(pos.down(3));
if (state.has(HeaterBlock.BLAZE_LEVEL))
return state.get(HeaterBlock.BLAZE_LEVEL);
return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? 1 : 0;
return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeaterBlock.HeatLevel.SMOULDERING : HeaterBlock.HeatLevel.NONE;
}
}

View File

@ -0,0 +1,147 @@
package com.simibubi.create.content.contraptions.particle;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.particle.IParticleRenderType;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
public class CubeParticle extends Particle {
public static final Vec3d[] CUBE = {
// TOP
new Vec3d(1, 1, -1), new Vec3d(1, 1, 1), new Vec3d(-1, 1, 1), new Vec3d(-1, 1, -1),
// BOTTOM
new Vec3d(-1, -1, -1), new Vec3d(-1, -1, 1), new Vec3d(1, -1, 1), new Vec3d(1, -1, -1),
// FRONT
new Vec3d(-1, -1, 1), new Vec3d(-1, 1, 1), new Vec3d(1, 1, 1), new Vec3d(1, -1, 1),
// BACK
new Vec3d(1, -1, -1), new Vec3d(1, 1, -1), new Vec3d(-1, 1, -1), new Vec3d(-1, -1, -1),
// LEFT
new Vec3d(-1, -1, -1), new Vec3d(-1, 1, -1), new Vec3d(-1, 1, 1), new Vec3d(-1, -1, 1),
// RIGHT
new Vec3d(1, -1, 1), new Vec3d(1, 1, 1), new Vec3d(1, 1, -1), new Vec3d(1, -1, -1) };
public static final Vec3d[] CUBE_NORMALS = {
//modified normals for the sides
new Vec3d(0, 1, 0),
new Vec3d(0, -1, 0),
new Vec3d(0, 0, 1),
new Vec3d(0, 0, 1),
new Vec3d(0, 0, 1),
new Vec3d(0, 0, 1),
/*new Vec3d(0, 1, 0),
new Vec3d(0, -1, 0),
new Vec3d(0, 0, 1),
new Vec3d(0, 0, -1),
new Vec3d(-1, 0, 0),
new Vec3d(1, 0, 0)*/
};
private static final IParticleRenderType renderType = new IParticleRenderType() {
@Override
public void beginRender(BufferBuilder builder, TextureManager textureManager) {
RenderSystem.disableTexture();
//transparent, additive blending
//RenderSystem.depthMask(false);
//RenderSystem.enableBlend();
//RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE);
//RenderSystem.enableLighting();
//opaque
RenderSystem.depthMask(true);
RenderSystem.disableBlend();
RenderSystem.enableLighting();
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
}
@Override
public void finishRender(Tessellator tessellator) {
tessellator.draw();
RenderSystem.enableTexture();
}
};
protected float scale;
public CubeParticle(World world, double x, double y, double z, double motionX, double motionY, double motionZ) {
super(world, x, y, z);
this.motionX = motionX;
this.motionY = motionY;
this.motionZ = motionZ;
setScale(0.2F);
}
public void setScale(float scale) {
this.scale = scale;
this.setSize(scale, scale);
}
public void averageAge(int age) {
this.maxAge = (int) (age + (rand.nextDouble() * 2D - 1D) * 8);
}
@Override
public void buildGeometry(IVertexBuilder builder, ActiveRenderInfo renderInfo, float p_225606_3_) {
Vec3d projectedView = renderInfo.getProjectedView();
float lerpedX = (float)(MathHelper.lerp(p_225606_3_, this.prevPosX, this.posX) - projectedView.getX());
float lerpedY = (float)(MathHelper.lerp(p_225606_3_, this.prevPosY, this.posY) - projectedView.getY());
float lerpedZ = (float)(MathHelper.lerp(p_225606_3_, this.prevPosZ, this.posZ) - projectedView.getZ());
//int light = getBrightnessForRender(p_225606_3_);
int light = 15728880;//15<<20 && 15<<4
double ageMultiplier = 1 - Math.pow(age, 3) / Math.pow(maxAge, 3);
for (int i = 0; i < 6; i++) {
//6 faces to a cube
for (int j = 0; j < 4; j++) {
Vec3d vec = CUBE[i * 4 + j];
vec = vec
/*.rotate(?)*/
.scale(scale * ageMultiplier)
.add(lerpedX, lerpedY, lerpedZ);
Vec3d normal = CUBE_NORMALS[i];
builder.vertex(vec.x, vec.y, vec.z).color(particleRed, particleGreen, particleBlue, particleAlpha).texture(0,0).light(light).normal((float)normal.x,(float) normal.y,(float) normal.z).endVertex();
}
}
}
@Override
public IParticleRenderType getRenderType() {
return renderType;
}
public static class Factory implements IParticleFactory<CubeParticleData> {
public Factory() {}
@Override
public Particle makeParticle(CubeParticleData data, World world, double x, double y, double z, double motionX, double motionY, double motionZ) {
CubeParticle particle = new CubeParticle(world, x, y, z, motionX, motionY, motionZ);
particle.setColor(data.r, data.g, data.b);
particle.setScale(data.scale);
particle.averageAge(data.avgAge);
return particle;
}
}
}

View File

@ -0,0 +1,83 @@
package com.simibubi.create.content.contraptions.particle;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.simibubi.create.AllParticleTypes;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.network.PacketBuffer;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleType;
import java.util.Locale;
public class CubeParticleData implements IParticleData, ICustomParticle<CubeParticleData> {
public static final IParticleData.IDeserializer<CubeParticleData> DESERIALIZER = new IParticleData.IDeserializer<CubeParticleData>() {
@Override
public CubeParticleData deserialize(ParticleType<CubeParticleData> type, StringReader reader) throws CommandSyntaxException {
reader.expect(' ');
float r = reader.readFloat();
reader.expect(' ');
float g = reader.readFloat();
reader.expect(' ');
float b = reader.readFloat();
reader.expect(' ');
float scale = reader.readFloat();
reader.expect(' ');
int avgAge = reader.readInt();
return new CubeParticleData(r, g, b, scale, avgAge);
}
@Override
public CubeParticleData read(ParticleType<CubeParticleData> type, PacketBuffer buffer) {
return new CubeParticleData(buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readInt());
}
};
final float r;
final float g;
final float b;
final float scale;
final int avgAge;
public CubeParticleData(float r, float g, float b, float scale, int avgAge) {
this.r = r;
this.g = g;
this.b = b;
this.scale = scale;
this.avgAge = avgAge;
}
public static CubeParticleData dummy() {
return new CubeParticleData(0, 0, 0, 0, 0);
}
@Override
public IDeserializer<CubeParticleData> getDeserializer() {
return DESERIALIZER;
}
@Override
public ParticleManager.IParticleMetaFactory<CubeParticleData> getFactory() {
return null;
}
@Override
public ParticleType<?> getType() {
return AllParticleTypes.CUBE.get();
}
@Override
public void write(PacketBuffer buffer) {
buffer.writeFloat(r);
buffer.writeFloat(g);
buffer.writeFloat(b);
buffer.writeFloat(scale);
buffer.writeInt(avgAge);
}
@Override
public String getParameters() {
return String.format(Locale.ROOT, "%s %f %f %f %f %d", AllParticleTypes.CUBE.parameter(), r, g, b, scale, avgAge);
}
}

View File

@ -7,18 +7,20 @@ import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.utility.Lang;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.IProperty;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.MathHelper;
@ -31,11 +33,12 @@ import net.minecraft.world.World;
@ParametersAreNonnullByDefault
public class HeaterBlock extends Block implements ITE<HeaterTileEntity> {
public static IProperty<Integer> BLAZE_LEVEL = IntegerProperty.create("blaze_level", 0, 4);
//public static IProperty<Integer> BLAZE_LEVEL = IntegerProperty.create("blaze_level", 0, 4);
public static IProperty<HeatLevel> BLAZE_LEVEL = EnumProperty.create("blaze", HeatLevel.class);
public HeaterBlock(Properties properties) {
super(properties);
setDefaultState(super.getDefaultState().with(BLAZE_LEVEL, 0));
setDefaultState(super.getDefaultState().with(BLAZE_LEVEL, HeatLevel.NONE));
}
@Override
@ -46,7 +49,7 @@ public class HeaterBlock extends Block implements ITE<HeaterTileEntity> {
@Override
public boolean hasTileEntity(BlockState state) {
return state.get(BLAZE_LEVEL) >= 1;
return state.get(BLAZE_LEVEL).min(HeatLevel.SMOULDERING);
}
@Nullable
@ -61,28 +64,36 @@ public class HeaterBlock extends Block implements ITE<HeaterTileEntity> {
}
@Override
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
BlockRayTraceResult blockRayTraceResult) {
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult blockRayTraceResult) {
if (!hasTileEntity(state))
return ActionResultType.PASS;
TileEntity te = world.getTileEntity(pos);
if (te instanceof HeaterTileEntity && ((HeaterTileEntity) te).tryUpdateFuel(player.getHeldItem(hand), player)) {
if (!player.isCreative())
player.getHeldItem(hand)
.shrink(1);
return ActionResultType.SUCCESS;
}
return ActionResultType.PASS;
if (!(te instanceof HeaterTileEntity))
return ActionResultType.PASS;
if (!((HeaterTileEntity) te).tryUpdateFuel(player.getHeldItem(hand), player))
return ActionResultType.PASS;
if (!player.isCreative())
player.getHeldItem(hand).shrink(1);
return ActionResultType.SUCCESS;
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
ItemStack item = context.getItem();
BlockState state = super.getStateForPlacement(context);
return (state != null ? state : getDefaultState()).with(BLAZE_LEVEL,
(item.hasTag() && item.getTag() != null && item.getTag()
.contains("has_blaze") && item.getTag()
.getBoolean("has_blaze")) ? 1 : 0);
if (!context.getItem().hasTag())
return getDefaultState();
CompoundNBT tag = context.getItem().getTag();
if (!tag.contains("has_blaze"))
return getDefaultState();
if (tag.getBoolean("has_blaze"))
return getDefaultState().with(BLAZE_LEVEL, HeatLevel.SMOULDERING);
return getDefaultState();
}
@Override
@ -91,16 +102,43 @@ public class HeaterBlock extends Block implements ITE<HeaterTileEntity> {
}
@Override
public int getLightValue(BlockState state, IBlockReader world, BlockPos pos) {
return MathHelper.clamp(state.get(BLAZE_LEVEL) * 4 - 1, 0, 15);
public VoxelShape getCollisionShape(BlockState p_220071_1_, IBlockReader p_220071_2_, BlockPos p_220071_3_, ISelectionContext p_220071_4_) {
if (p_220071_4_ == ISelectionContext.dummy())
return AllShapes.HEATER_BLOCK_SPECIAL_COLLISION_SHAPE;
return super.getShape(p_220071_1_, p_220071_2_, p_220071_3_, p_220071_4_);
}
static void setBlazeLevel(@Nullable World world, BlockPos pos, int blazeLevel) {
@Override
public int getLightValue(BlockState state, IBlockReader world, BlockPos pos) {
return MathHelper.clamp(state.get(BLAZE_LEVEL).ordinal() * 4 - 1, 0, 15);
}
static void setBlazeLevel(@Nullable World world, BlockPos pos, HeatLevel blazeLevel) {
if (world != null)
world.setBlockState(pos, world.getBlockState(pos).with(BLAZE_LEVEL, blazeLevel));
}
public static int getHeaterLevel(BlockState blockState) {
return blockState.has(HeaterBlock.BLAZE_LEVEL) ? blockState.get(HeaterBlock.BLAZE_LEVEL) : 0;
public static HeatLevel getHeaterLevel(BlockState blockState) {
return blockState.has(HeaterBlock.BLAZE_LEVEL) ? blockState.get(HeaterBlock.BLAZE_LEVEL) : HeatLevel.NONE;
}
public enum HeatLevel implements IStringSerializable {
NONE,
SMOULDERING,
FADING,
KINDLED,
SEETHING,
//if you think you have better names let me know :)
;
@Override
public String getName() {
return Lang.asId(name());
}
public boolean min(HeatLevel heatLevel) {
return this.ordinal() >= heatLevel.ordinal();
}
}
}

View File

@ -16,13 +16,13 @@ import java.util.HashMap;
public class HeaterRenderer extends SafeTileEntityRenderer<HeaterTileEntity> {
private static final Minecraft INSTANCE = Minecraft.getInstance();
private static final HashMap<Integer, AllBlockPartials> blazeModelMap = new HashMap<>();
private static final HashMap<HeaterBlock.HeatLevel, AllBlockPartials> blazeModelMap = new HashMap<>();
public HeaterRenderer(TileEntityRendererDispatcher dispatcher) {
super(dispatcher);
blazeModelMap.put(2, AllBlockPartials.BLAZE_HEATER_BLAZE_TWO);
blazeModelMap.put(3, AllBlockPartials.BLAZE_HEATER_BLAZE_THREE);
blazeModelMap.put(4, AllBlockPartials.BLAZE_HEATER_BLAZE_FOUR);
blazeModelMap.put(HeaterBlock.HeatLevel.FADING, AllBlockPartials.BLAZE_HEATER_BLAZE_TWO);
blazeModelMap.put(HeaterBlock.HeatLevel.KINDLED, AllBlockPartials.BLAZE_HEATER_BLAZE_THREE);
blazeModelMap.put(HeaterBlock.HeatLevel.SEETHING, AllBlockPartials.BLAZE_HEATER_BLAZE_FOUR);
}
@Override

View File

@ -5,56 +5,75 @@ import java.util.Random;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.components.deployer.DeployerFakePlayer;
import com.simibubi.create.content.contraptions.particle.HeaterParticleData;
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.ColorHelper;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.EggEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class HeaterTileEntity extends SmartTileEntity {
private int fuelLevel;
private int burnTimeRemaining;
private final static int[][] heatParticleColors = {
{0x3B141A, 0x47141A, 0x7A3B24, 0x854D26},
{0x2A0103, 0x741B0A, 0xC38246, 0xCCBD78},
{0x630B03, 0x8B3503, 0xBC8200, 0xCCC849},
{0x1C6378, 0x4798B5, 0x4DA6C0, 0xBAC8CE}
};
private static final int maxHeatCapacity = 10000;
private int remainingBurnTime;
private FuelType activeFuel;
public HeaterTileEntity(TileEntityType<? extends HeaterTileEntity> tileEntityTypeIn) {
super(tileEntityTypeIn);
fuelLevel = 0;
burnTimeRemaining = 0;
setLazyTickRate(20);
activeFuel = FuelType.NONE;
remainingBurnTime = 0;
setLazyTickRate(40);
}
@Override
public void tick() {
super.tick();
if (burnTimeRemaining > 0) {
burnTimeRemaining--;
if (burnTimeRemaining <= 0 && fuelLevel > 1) {
fuelLevel--;
burnTimeRemaining = maxHeatCapacity / 2;
}
updateHeatLevel();
markDirty();
spawnParticles(getHeatLevel());
if (remainingBurnTime <= 0) {
return;
}
remainingBurnTime--;
if (remainingBurnTime == 0)
if (activeFuel == FuelType.SPECIAL) {
activeFuel = FuelType.NORMAL;
remainingBurnTime = maxHeatCapacity / 2;
updateHeatLevel();
} else {
activeFuel = FuelType.NONE;
updateHeatLevel();
}
markDirty();
}
@Override
public void lazyTick() {
super.lazyTick();
spawnParticles(ParticleTypes.SMOKE);
int heatLevel = getHeatLevel();
if (heatLevel >= 2)
spawnParticles(ParticleTypes.FLAME);
if (heatLevel > 3) {
spawnParticles(new HeaterParticleData(0.3f, 0.3f, 1f));
}
//using lazy ticks to transition between kindled and fading, this doesn't need to happen instantly at the threshold
updateHeatLevel();
}
@Override
@ -62,62 +81,148 @@ public class HeaterTileEntity extends SmartTileEntity {
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.putInt("fuelLevel", fuelLevel);
compound.putInt("burnTimeRemaining", burnTimeRemaining);
compound.putInt("fuelLevel", activeFuel.ordinal());
compound.putInt("burnTimeRemaining", remainingBurnTime);
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
fuelLevel = compound.getInt("fuelLevel");
burnTimeRemaining = compound.getInt("burnTimeRemaining");
activeFuel = FuelType.values()[compound.getInt("fuelLevel")];
remainingBurnTime = compound.getInt("burnTimeRemaining");
super.read(compound);
if (fuelLevel == 0)
burnTimeRemaining = 0;
updateHeatLevel();
}
/**
* @return true if the heater updated its burn time and a item should be consumed
*/
boolean tryUpdateFuel(ItemStack itemStack, PlayerEntity player) {
boolean specialFuelUsed = itemStack.getItem() == AllItems.FUEL_PELLET.get();
int burnTime =
itemStack.getItem() == Items.EGG ? 150 : (specialFuelUsed ? 1000 : ForgeHooks.getBurnTime(itemStack));
int newFuelLevel = (specialFuelUsed ? 2 : 1);
if (burnTime <= 0 || newFuelLevel < fuelLevel)
return false;
if (newFuelLevel > this.fuelLevel) {
fuelLevel = newFuelLevel;
burnTimeRemaining = burnTime;
} else {
if (burnTimeRemaining + burnTime > maxHeatCapacity && player instanceof DeployerFakePlayer)
return false;
burnTimeRemaining = MathHelper.clamp(burnTimeRemaining + burnTime, 0, maxHeatCapacity);
FuelType newFuel = FuelType.NONE;
int burnTick = ForgeHooks.getBurnTime(itemStack);
if (burnTick > 0)
newFuel = FuelType.NORMAL;
if (itemStack.getItem() == AllItems.FUEL_PELLET.get()) {
burnTick = 1000;
newFuel = FuelType.SPECIAL;
}
if (newFuel == FuelType.NONE || newFuel.ordinal() < activeFuel.ordinal())
return false;
if (newFuel == activeFuel) {
if (remainingBurnTime + burnTick > maxHeatCapacity && player instanceof DeployerFakePlayer)
return false;
remainingBurnTime = MathHelper.clamp(remainingBurnTime + burnTick, 0, maxHeatCapacity);
} else {
activeFuel = newFuel;
remainingBurnTime = burnTick;
}
updateHeatLevel();
return true;
}
public int getHeatLevel() {
public HeaterBlock.HeatLevel getHeatLevel() {
return HeaterBlock.getHeaterLevel(getBlockState());
}
private void updateHeatLevel() {
if (fuelLevel == 2)
HeaterBlock.setBlazeLevel(world, pos, 4);
else if (fuelLevel == 0 || burnTimeRemaining <= 0)
HeaterBlock.setBlazeLevel(world, pos, 1);
else {
HeaterBlock.setBlazeLevel(world, pos, (double) burnTimeRemaining / maxHeatCapacity > 0.1 ? 3 : 2);
switch (activeFuel) {
case SPECIAL:
HeaterBlock.setBlazeLevel(world, pos, HeaterBlock.HeatLevel.SEETHING);
break;
case NORMAL:
boolean lowPercent = (double) remainingBurnTime / maxHeatCapacity < 0.1;
HeaterBlock.setBlazeLevel(world, pos, lowPercent ? HeaterBlock.HeatLevel.FADING : HeaterBlock.HeatLevel.KINDLED);
break;
case NONE:
HeaterBlock.setBlazeLevel(world, pos, HeaterBlock.HeatLevel.SMOULDERING);
}
}
private void spawnParticles(IParticleData basicparticletype) {
private void spawnParticles(HeaterBlock.HeatLevel heatLevel) {
if (world == null)
return;
if (heatLevel == HeaterBlock.HeatLevel.NONE)
return;
Random r = world.getRandom();
if (heatLevel == HeaterBlock.HeatLevel.SMOULDERING) {
if (r.nextDouble() > 0.25)
return;
Vec3d color = randomColor(heatLevel);
spawnParticle(new CubeParticleData((float) color.x,(float) color.y,(float) color.z, 0.03F, 15), 0.015, 0.1);
} else if (heatLevel == HeaterBlock.HeatLevel.FADING) {
if (r.nextDouble() > 0.5)
return;
Vec3d color = randomColor(heatLevel);
spawnParticle(new CubeParticleData((float) color.x,(float) color.y,(float) color.z, 0.035F, 18), 0.03, 0.15);
} else if (heatLevel == HeaterBlock.HeatLevel.KINDLED) {
Vec3d color = randomColor(heatLevel);
spawnParticle(new CubeParticleData((float) color.x,(float) color.y,(float) color.z, 0.04F, 21), 0.05, 0.2);
}else if (heatLevel == HeaterBlock.HeatLevel.SEETHING) {
for (int i = 0; i < 2; i++) {
if (r.nextDouble() > 0.6)
return;
Vec3d color = randomColor(heatLevel);
spawnParticle(new CubeParticleData((float) color.x,(float) color.y,(float) color.z, 0.045F, 24), 0.06, 0.22);
}
}
}
private void spawnParticle(IParticleData particleData, double speed, double spread) {
Random random = world.getRandom();
world.addOptionalParticle(basicparticletype, true,
(double) pos.getX() + 0.5D + random.nextDouble() / 3.0D * (double) (random.nextBoolean() ? 1 : -1),
(double) pos.getY() + random.nextDouble() + random.nextDouble(),
(double) pos.getZ() + 0.5D + random.nextDouble() / 3.0D * (double) (random.nextBoolean() ? 1 : -1), 0.0D,
0.07D, 0.0D);
world.addOptionalParticle(
particleData,
(double) pos.getX() + 0.5D + (random.nextDouble() * 2.0 - 1D) * spread,
(double) pos.getY() + 0.6D + random.nextDouble() / 10.0,
(double) pos.getZ() + 0.5D + (random.nextDouble() * 2.0 - 1D) * spread,
0.0D,
speed,
0.0D);
}
private static Vec3d randomColor(HeaterBlock.HeatLevel heatLevel) {
if (heatLevel == HeaterBlock.HeatLevel.NONE)
return new Vec3d(0,0,0);
return ColorHelper.getRGB(heatParticleColors[heatLevel.ordinal()-1][(int) (Math.random()*4)]);
}
@SubscribeEvent
public static void eggsGetEaten(ProjectileImpactEvent.Throwable event) {
if (!(event.getThrowable() instanceof EggEntity))
return;
if (event.getRayTraceResult().getType() != RayTraceResult.Type.BLOCK)
return;
TileEntity tile = event.getThrowable().world.getTileEntity(new BlockPos(event.getRayTraceResult().getHitVec()));
if (!(tile instanceof HeaterTileEntity)) {
return;
}
event.setCanceled(true);
event.getThrowable().setMotion(Vec3d.ZERO);
event.getThrowable().remove();
HeaterTileEntity heater = (HeaterTileEntity) tile;
if (heater.activeFuel != FuelType.SPECIAL)
heater.activeFuel = FuelType.NORMAL;
heater.remainingBurnTime = MathHelper.clamp(heater.remainingBurnTime + 80, 0, maxHeatCapacity);
heater.markDirty();
}
private enum FuelType {
NONE,
NORMAL,
SPECIAL
}
}

View File

@ -7,6 +7,7 @@ import java.util.Optional;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe;
import com.simibubi.create.content.contraptions.processing.HeaterBlock;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.config.AllConfigs;
@ -62,9 +63,9 @@ public class InWorldProcessing {
if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER)
return Type.SPLASHING;
if (blockState.getBlock() == Blocks.FIRE
|| (blockState.getBlock() == Blocks.CAMPFIRE && blockState.get(CampfireBlock.LIT)) || getHeaterLevel(blockState) == 1)
|| (blockState.getBlock() == Blocks.CAMPFIRE && blockState.get(CampfireBlock.LIT)) || getHeaterLevel(blockState) == HeaterBlock.HeatLevel.SMOULDERING)
return Type.SMOKING;
if (blockState.getBlock() == Blocks.LAVA || getHeaterLevel(blockState) >= 2)
if (blockState.getBlock() == Blocks.LAVA || getHeaterLevel(blockState).min(HeaterBlock.HeatLevel.FADING))
return Type.BLASTING;
return null;
}

View File

@ -0,0 +1,3 @@
{
}