Flicker awareness & Tree cutting

- Kinetic blocks break when their speed updates to frequently
- Fixed Stress gauge not resetting when source was removed
- Fixed Kinetic networks doubling their stress when saving and loading the world
- Fixed Generators not updating network stress when their speed changed
- Fixed Processing saw crashing when used
- Fixed tree cutting algorithm looping indefinitely
- Fixed sourceless kinetic blocks in rainbow debug
- Horizontal saws cut trees in front of them
- Deforester now works in creative mode
This commit is contained in:
simibubi 2019-12-13 18:15:11 +01:00
parent 785d77a59d
commit fca3b74909
26 changed files with 358 additions and 205 deletions

View file

@ -20,7 +20,7 @@ archivesBaseName = 'create'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
minecraft {
mappings channel: 'snapshot', version: '20191107-1.14.3'
mappings channel: 'snapshot', version: '20191130-1.14.3'
runs {
client {
@ -71,7 +71,7 @@ repositories {
}
dependencies {
minecraft 'net.minecraftforge:forge:1.14.4-28.1.85'
minecraft 'net.minecraftforge:forge:1.14.4-28.1.106'
// compile against the JEI API but do not include it at runtime
compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.10:api")

View file

@ -1,11 +1,20 @@
package com.simibubi.create.foundation.utility;
import java.util.function.Consumer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.SlabType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public class BlockHelper {
@ -61,4 +70,25 @@ public class BlockHelper {
return itemStack;
}
public static void destroyBlock(World world, BlockPos pos, float effectChance) {
destroyBlock(world, pos, effectChance, stack -> Block.spawnAsEntity(world, pos, stack));
}
public static void destroyBlock(World world, BlockPos pos, float effectChance,
Consumer<ItemStack> droppedItemCallback) {
IFluidState ifluidstate = world.getFluidState(pos);
BlockState state = world.getBlockState(pos);
if (world.rand.nextFloat() < effectChance)
world.playEvent(2001, pos, Block.getStateId(state));
TileEntity tileentity = state.hasTileEntity() ? world.getTileEntity(pos) : null;
if (world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS) && !world.restoringBlockSnapshots) {
for (ItemStack itemStack : Block.getDrops(state, (ServerWorld) world, pos, tileentity))
droppedItemCallback.accept(itemStack);
state.spawnAdditionalDrops(world, pos, ItemStack.EMPTY);
}
world.setBlockState(pos, ifluidstate.getBlockState());
}
}

View file

@ -44,4 +44,6 @@ public class Debug {
return text + TextFormatting.GRAY + " ...";
}
public static void markTemporary() {};
}

View file

@ -49,6 +49,8 @@ public class TreeCutter {
// Find all logs
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
if (visited.contains(currentPos))
continue;
visited.add(currentPos);
if (!isLog(reader.getBlockState(currentPos)))
@ -63,6 +65,9 @@ public class TreeCutter {
frontier.addAll(logs);
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
if (!logs.contains(currentPos))
if (visited.contains(currentPos))
continue;
visited.add(currentPos);
BlockState blockState = reader.getBlockState(currentPos);

View file

@ -1,6 +1,6 @@
package com.simibubi.create.foundation.utility.recipe;
import java.util.function.Predicate;
import com.google.common.base.Predicate;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;

View file

@ -51,13 +51,8 @@ public class RecipeFinder {
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());
public List<R> filter(Predicate<R> condition) {
return stream.filter(condition).collect(Collectors.toList());
}
}

View file

@ -38,11 +38,11 @@ public class KineticNetwork {
return;
if (te.isSource()) {
float capacity = te.getAddedStressCapacity();
unloadedStressCapacity -= capacity;
unloadedStressCapacity -= capacity * getStressMultiplierForSpeed(te.getGeneratedSpeed());
sources.put(te, capacity);
}
float stressApplied = te.getStressApplied();
unloadedStress -= stressApplied;
unloadedStress -= stressApplied * getStressMultiplierForSpeed(te.speed);
members.put(te, stressApplied);
}

View file

@ -176,14 +176,14 @@ public class RotationPropagator {
continue;
if (neighbourTE.hasSource() && neighbourTE.getSource().equals(addedTE.getPos())) {
addedTE.setSpeed(neighbourTE.speed * speedModifier);
addedTE.onSpeedChanged();
addedTE.onSpeedChanged(0);
addedTE.sendData();
continue;
}
addedTE.setSpeed(neighbourTE.speed * speedModifier);
addedTE.setSource(neighbourTE.getPos());
addedTE.onSpeedChanged();
addedTE.onSpeedChanged(0);
addedTE.sendData();
propagateNewSource(addedTE);
return;
@ -209,7 +209,8 @@ public class RotationPropagator {
&& (newSpeed != 0 && neighbourTE.speed != 0);
boolean tooFast = Math.abs(newSpeed) > parameters.maxRotationSpeed.get();
if (tooFast) {
boolean speedChangedTooOften = updateTE.speedChangeCounter > 25;
if (tooFast || speedChangedTooOften) {
world.destroyBlock(pos, true);
return;
}
@ -224,8 +225,9 @@ public class RotationPropagator {
if (Math.abs(oppositeSpeed) > Math.abs(updateTE.speed)) {
// Neighbour faster, overpower the incoming tree
updateTE.setSource(neighbourTE.getPos());
float prevSpeed = updateTE.getSpeed();
updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE));
updateTE.onSpeedChanged();
updateTE.onSpeedChanged(prevSpeed);
updateTE.sendData();
propagateNewSource(updateTE);
@ -241,8 +243,9 @@ public class RotationPropagator {
}
neighbourTE.setSource(updateTE.getPos());
float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(updateTE.speed * getRotationSpeedModifier(updateTE, neighbourTE));
neighbourTE.onSpeedChanged();
neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData();
propagateNewSource(neighbourTE);
}
@ -253,9 +256,10 @@ public class RotationPropagator {
if (neighbourTE.speed == newSpeed)
continue;
float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(newSpeed);
neighbourTE.setSource(updateTE.getPos());
neighbourTE.onSpeedChanged();
neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData();
propagateNewSource(neighbourTE);

View file

@ -24,6 +24,7 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
public void updateGeneratedRotation() {
float speed = getGeneratedSpeed();
float prevSpeed = this.speed;
if (this.speed != speed) {
@ -71,10 +72,13 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
}
}
if (hasNetwork() && speed != 0)
if (hasNetwork() && speed != 0) {
getNetwork().updateCapacityFor(this, getAddedStressCapacity());
getNetwork().updateStressCapacity();
getNetwork().updateStress();
}
onSpeedChanged();
onSpeedChanged(prevSpeed);
sendData();
}

View file

@ -64,8 +64,9 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
this.currentStress = currentStress;
boolean overStressed = maxStress < currentStress;
if (overStressed != this.overStressed) {
float prevSpeed = getSpeed();
this.overStressed = overStressed;
onSpeedChanged();
onSpeedChanged(prevSpeed);
sendData();
}
}
@ -95,9 +96,13 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
return true;
}
public void onSpeedChanged() {
public void onSpeedChanged(float previousSpeed) {
boolean fromOrToZero = (previousSpeed == 0) != (getSpeed() == 0);
boolean directionSwap = !fromOrToZero && Math.signum(previousSpeed) != Math.signum(getSpeed());
if (fromOrToZero || directionSwap) {
speedChangeCounter += 5;
}
}
@Override
public void remove() {
@ -217,8 +222,9 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
this.source = Optional.empty();
newNetworkID = null;
updateNetwork = true;
float prevSpeed = getSpeed();
setSpeed(0);
onSpeedChanged();
onSpeedChanged(prevSpeed);
}
public KineticNetwork getNetwork() {
@ -263,9 +269,6 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
public void tick() {
if (world.isRemote)
return;
if (speedChangeCounter > 25)
world.destroyBlock(pos, true);
if (speedChangeCounter > 0)
speedChangeCounter--;

View file

@ -59,6 +59,8 @@ public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTil
rainbowMode = true;
if (te.hasNetwork())
buffer.color(LogisticalActorTileEntity.colorFromUUID(te.getNetworkID()));
else
buffer.color(0xFFFFFF);
}
return buffer;

View file

@ -0,0 +1,150 @@
package com.simibubi.create.modules.contraptions.components.actors;
import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.block.AirBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
import net.minecraft.world.server.ServerWorld;
public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
private static final AtomicInteger NEXT_BREAKER_ID = new AtomicInteger();
protected int ticksUntilNextProgress;
protected int destroyProgress;
protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet();
protected BlockPos breakingPos;
public BlockBreakingKineticTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
}
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
if (destroyProgress == -1)
destroyNextTick();
}
public void destroyNextTick() {
ticksUntilNextProgress = 1;
}
protected abstract BlockPos getBreakingPos();
protected boolean shouldRun() {
return true;
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.putInt("Progress", destroyProgress);
compound.putInt("NextTick", ticksUntilNextProgress);
if (breakingPos != null)
compound.put("Breaking", NBTUtil.writeBlockPos(breakingPos));
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
destroyProgress = compound.getInt("Progress");
ticksUntilNextProgress = compound.getInt("NextTick");
if (compound.contains("Breaking"))
breakingPos = NBTUtil.readBlockPos(compound.getCompound("Breaking"));
super.read(compound);
}
@Override
public void remove() {
if (!world.isRemote && destroyProgress != 0)
world.sendBlockBreakProgress(breakerId, breakingPos, -1);
super.remove();
}
@Override
public void tick() {
super.tick();
if (world.isRemote)
return;
if (!shouldRun())
return;
if (getSpeed() == 0)
return;
if (breakingPos == null)
breakingPos = getBreakingPos();
if (ticksUntilNextProgress < 0)
return;
if (ticksUntilNextProgress-- > 0)
return;
BlockState stateToBreak = world.getBlockState(breakingPos);
float blockHardness = stateToBreak.getBlockHardness(world, breakingPos);
if (!canBreak(stateToBreak, blockHardness)) {
if (destroyProgress != 0) {
destroyProgress = 0;
world.sendBlockBreakProgress(breakerId, breakingPos, -1);
}
return;
}
float breakSpeed = getBreakSpeed();
destroyProgress += MathHelper.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress);
if (destroyProgress >= 10) {
onBlockBroken(stateToBreak);
destroyProgress = 0;
ticksUntilNextProgress = -1;
world.sendBlockBreakProgress(breakerId, breakingPos, -1);
return;
}
ticksUntilNextProgress = (int) (blockHardness / breakSpeed);
world.sendBlockBreakProgress(breakerId, breakingPos, (int) destroyProgress);
}
public boolean canBreak(BlockState stateToBreak, float blockHardness) {
return !(stateToBreak.getMaterial().isLiquid() || stateToBreak.getBlock() instanceof AirBlock
|| blockHardness == -1);
}
public void onBlockBroken(BlockState stateToBreak) {
IFluidState ifluidstate = world.getFluidState(breakingPos);
world.playEvent(2001, breakingPos, Block.getStateId(stateToBreak));
TileEntity tileentity = stateToBreak.hasTileEntity() ? world.getTileEntity(breakingPos) : null;
Vec3d vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(breakingPos), world.rand, .125f);
Block.getDrops(stateToBreak, (ServerWorld) world, breakingPos, tileentity).forEach((stack) -> {
if (!stack.isEmpty() && world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
&& !world.restoringBlockSnapshots) {
ItemEntity itementity = new ItemEntity(world, vec.x, vec.y, vec.z, stack);
itementity.setDefaultPickupDelay();
itementity.setMotion(Vec3d.ZERO);
world.addEntity(itementity);
}
});
stateToBreak.spawnAdditionalDrops(world, breakingPos, ItemStack.EMPTY);
world.setBlockState(breakingPos, ifluidstate.getBlockState(), 3);
}
protected float getBreakSpeed() {
return Math.abs(speed / 100f);
}
}

View file

@ -1,139 +1,21 @@
package com.simibubi.create.modules.contraptions.components.actors;
import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.block.AirBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.ItemStack;
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.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
import net.minecraft.world.server.ServerWorld;
public class DrillTileEntity extends KineticTileEntity {
private static final AtomicInteger NEXT_DRILL_ID = new AtomicInteger();
public class DrillTileEntity extends BlockBreakingKineticTileEntity {
public static DamageSource damageSourceDrill = new DamageSource("create.drill").setDamageBypassesArmor();
private int ticksUntilNextProgress;
private int destroyProgress;
private int drillId = -NEXT_DRILL_ID.incrementAndGet();
public DrillTileEntity() {
super(AllTileEntities.DRILL.type);
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
if (destroyProgress == -1)
destroyNextTick();
}
public void destroyNextTick() {
ticksUntilNextProgress = 1;
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.putInt("Progress", destroyProgress);
compound.putInt("NextTick", ticksUntilNextProgress);
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
destroyProgress = compound.getInt("Progress");
ticksUntilNextProgress = compound.getInt("NextTick");
super.read(compound);
}
@Override
public void remove() {
if (!world.isRemote && destroyProgress != 0) {
BlockPos posToBreak = pos.offset(getBlockState().get(BlockStateProperties.FACING));
world.sendBlockBreakProgress(drillId, posToBreak, -1);
}
super.remove();
}
@Override
public void tick() {
super.tick();
if (world.isRemote)
return;
if (getSpeed() == 0)
return;
BlockPos posToBreak = pos.offset(getBlockState().get(BlockStateProperties.FACING));
if (ticksUntilNextProgress < 0) {
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, new AxisAlignedBB(posToBreak)))
if (!(entity instanceof ItemEntity))
entity.attackEntityFrom(damageSourceDrill, MathHelper.clamp(Math.abs(speed / 512f) + 1, 0, 20));
return;
}
if (ticksUntilNextProgress-- > 0)
return;
BlockState stateToBreak = world.getBlockState(posToBreak);
float blockHardness = stateToBreak.getBlockHardness(world, posToBreak);
if (stateToBreak.getMaterial().isLiquid() || stateToBreak.getBlock() instanceof AirBlock
|| blockHardness == -1) {
if (destroyProgress != 0) {
destroyProgress = 0;
world.sendBlockBreakProgress(drillId, posToBreak, -1);
}
return;
}
float breakSpeed = Math.abs(speed / 100f);
destroyProgress += MathHelper.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress);
if (destroyProgress >= 10) {
IFluidState ifluidstate = world.getFluidState(pos);
world.playEvent(2001, posToBreak, Block.getStateId(stateToBreak));
TileEntity tileentity = stateToBreak.hasTileEntity() ? world.getTileEntity(posToBreak) : null;
Vec3d vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(posToBreak), world.rand, .125f);
Block.getDrops(stateToBreak, (ServerWorld) world, posToBreak, tileentity).forEach((stack) -> {
if (!stack.isEmpty() && world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
&& !world.restoringBlockSnapshots) {
ItemEntity itementity = new ItemEntity(world, vec.x, vec.y, vec.z, stack);
itementity.setDefaultPickupDelay();
itementity.setMotion(Vec3d.ZERO);
world.addEntity(itementity);
}
});
stateToBreak.spawnAdditionalDrops(world, posToBreak, ItemStack.EMPTY);
world.setBlockState(posToBreak, ifluidstate.getBlockState(), 3);
destroyProgress = 0;
ticksUntilNextProgress = -1;
world.sendBlockBreakProgress(drillId, posToBreak, -1);
return;
}
ticksUntilNextProgress = (int) (blockHardness / breakSpeed);
world.sendBlockBreakProgress(drillId, posToBreak, (int) destroyProgress);
protected BlockPos getBreakingPos() {
return getPos().offset(getBlockState().get(DrillBlock.FACING));
}
}

View file

@ -45,7 +45,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (!isWindmill && running) {
updateGeneratedRotation();
if (getSpeed() == 0)
disassembleConstruct();
assembleNextTick = true;
}
sendData();
@ -89,8 +89,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
assembleNextTick = true;
}

View file

@ -30,8 +30,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
assembleNextTick = true;
}

View file

@ -13,8 +13,8 @@ public class CrushingWheelTileEntity extends KineticTileEntity {
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
for (Direction d : Direction.values())
((CrushingWheelBlock) getBlockState().getBlock()).updateControllers(getBlockState(), getWorld(), getPos(),
d);

View file

@ -29,18 +29,13 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements IWithTil
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
notifyFanTile(worldIn, pos);
blockUpdate(state, worldIn, pos);
}
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
notifyFanTile(worldIn, pos);
if (worldIn.isRemote || getRotationAxis(state).isHorizontal())
return;
withTileEntityDo(worldIn, pos, EncasedFanTileEntity::updateGenerator);
blockUpdate(state, worldIn, pos);
}
@Override
@ -52,6 +47,13 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements IWithTil
context.isPlacerSneaking() ? preferredFacing : preferredFacing.getOpposite());
}
protected void blockUpdate(BlockState state, World worldIn, BlockPos pos) {
notifyFanTile(worldIn, pos);
if (worldIn.isRemote || state.get(FACING) != Direction.DOWN)
return;
withTileEntityDo(worldIn, pos, EncasedFanTileEntity::updateGenerator);
}
protected void notifyFanTile(IWorld world, BlockPos pos) {
withTileEntityDo(world, pos, EncasedFanTileEntity::blockInFrontChanged);
}

View file

@ -84,8 +84,8 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
updateAirFlow = true;
}

View file

@ -60,8 +60,8 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
checkBasin = true;
}

View file

@ -148,8 +148,8 @@ public class SawBlock extends DirectionalAxisKineticBlock
@Override
public Vec3d getFilterPosition(BlockState state) {
Vec3d x = new Vec3d(8f / 16f, 12.5f / 16f + 1f/256f, 12.25f / 16f);
Vec3d z = new Vec3d(12.25f / 16f, 12.5f / 16f + 1f/256f, 8f / 16f);
Vec3d x = new Vec3d(8f / 16f, 12.5f / 16f + 1f / 256f, 12.25f / 16f);
Vec3d z = new Vec3d(12.25f / 16f, 12.5f / 16f + 1f / 256f, 8f / 16f);
return state.get(AXIS_ALONG_FIRST_COORDINATE) ? z : x;
}

View file

@ -6,17 +6,24 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import com.google.common.base.Predicates;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllRecipes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
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.foundation.utility.recipe.RecipeFinder.StartedSearch;
import com.simibubi.create.foundation.utility.recipe.RecipeFinder.StartedSearch.RecipeStream;
import com.simibubi.create.modules.contraptions.components.actors.BlockBreakingKineticTileEntity;
import com.simibubi.create.modules.contraptions.processing.ProcessingInventory;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.IHaveFilter;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
@ -28,6 +35,7 @@ import net.minecraft.particles.BlockParticleData;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tags.BlockTags;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
@ -39,7 +47,7 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
public class SawTileEntity extends BlockBreakingKineticTileEntity implements IHaveFilter {
private static final Object cuttingRecipesKey = new Object();
public ProcessingInventory inventory;
@ -62,8 +70,8 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
boolean shouldRun = Math.abs(getSpeed()) > 1 / 64f;
boolean running = getBlockState().get(RUNNING);
if (shouldRun != running)
@ -88,7 +96,10 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
@Override
public void tick() {
if (shouldRun() && ticksUntilNextProgress < 0)
destroyNextTick();
super.tick();
if (!canProcess())
return;
if (getSpeed() == 0)
@ -229,7 +240,7 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
float offset = inventory.recipeDuration != 0 ? (float) (inventory.remainingTime) / inventory.recipeDuration : 0;
offset -= .5f;
world.addParticle(particleData, pos.getX() + -vec.x * offset, pos.getY() + .45f, pos.getZ() + -vec.z * offset,
vec.x * speed, r.nextFloat() * speed, vec.z * speed);
-vec.x * speed, r.nextFloat() * speed, -vec.z * speed);
}
public Vec3d getItemMovementVec() {
@ -272,11 +283,11 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
}
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();
StartedSearch startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipes.Types.CUTTING));
RecipeStream<IRecipe<?>> search = startedSearch.search();
return search.filter(Predicates.and(RecipeConditions.outputMatchesFilter(filter),
RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))));
}
public void insertItem(ItemEntity entity) {
@ -345,4 +356,41 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
return filter;
}
// Block Breaker
@Override
protected boolean shouldRun() {
return getBlockState().get(SawBlock.FACING).getAxis().isHorizontal();
}
@Override
protected BlockPos getBreakingPos() {
return getPos().offset(getBlockState().get(SawBlock.FACING));
}
@Override
public void onBlockBroken(BlockState stateToBreak) {
super.onBlockBroken(stateToBreak);
Tree tree = TreeCutter.cutTree(world, breakingPos);
if (tree != null) {
for (BlockPos log : tree.logs)
BlockHelper.destroyBlock(world, log, 1 / 2f, stack -> dropItemFromCutTree(log, stack));
for (BlockPos leaf : tree.leaves)
BlockHelper.destroyBlock(world, leaf, 1 / 8f, stack -> dropItemFromCutTree(leaf, stack));
}
}
public void dropItemFromCutTree(BlockPos pos, ItemStack stack) {
float distance = (float) Math.sqrt(pos.distanceSq(breakingPos));
Vec3d dropPos = VecHelper.getCenterOf(pos);
ItemEntity entity = new ItemEntity(world, dropPos.x, dropPos.y, dropPos.z, stack);
entity.setMotion(new Vec3d(breakingPos.subtract(this.pos)).scale(distance / 20f));
world.addEntity(entity);
}
@Override
public boolean canBreak(BlockState stateToBreak, float blockHardness) {
return super.canBreak(stateToBreak, blockHardness) && stateToBreak.isIn(BlockTags.LOGS);
}
}

View file

@ -30,12 +30,6 @@ public class GaugeTileEntity extends KineticTileEntity {
super.read(compound);
}
@Override
public void removeSource() {
super.removeSource();
dialTarget = 0;
}
@Override
public void tick() {
super.tick();

View file

@ -14,8 +14,8 @@ public class SpeedGaugeTileEntity extends GaugeTileEntity {
}
@Override
public void onSpeedChanged() {
super.onSpeedChanged();
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
float speed = Math.abs(getSpeed());
float medium = CreateConfig.parameters.mediumSpeed.get().floatValue();
float fast = CreateConfig.parameters.fastSpeed.get().floatValue();

View file

@ -32,4 +32,13 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
sendData();
}
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
if (getSpeed() == 0)
dialTarget = 0;
else
sync(maxStress, currentStress);
}
}

View file

@ -1,40 +1,63 @@
package com.simibubi.create.modules.curiosities.deforester;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.modules.curiosities.tools.AllToolTiers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AxeItem;
import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
@EventBusSubscriber(bus = Bus.FORGE)
public class DeforesterItem extends AxeItem {
public DeforesterItem(Properties builder) {
super(AllToolTiers.RADIANT, 10.0F, -3.1F, builder);
}
@Override
public boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos,
LivingEntity entityLiving) {
if (state.isIn(BlockTags.LOGS) && !entityLiving.isSneaking()) {
// Moved away from Item#onBlockDestroyed as it does not get called in Creative
public static void destroyTree(ItemStack stack, IWorld worldIn, BlockState state, BlockPos pos,
PlayerEntity player) {
if (!state.isIn(BlockTags.LOGS) || player.isSneaking())
return;
Tree tree = TreeCutter.cutTree(worldIn, pos);
if (tree == null)
return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving);
boolean dropBlock = !(entityLiving instanceof PlayerEntity) || !((PlayerEntity) entityLiving).isCreative();
return;
boolean dropBlock = !player.isCreative();
World world = worldIn.getWorld();
if (world == null)
return;
for (BlockPos log : tree.logs)
worldIn.destroyBlock(log, dropBlock);
BlockHelper.destroyBlock(world, log, 1 / 2f, item -> {
if (dropBlock)
Block.spawnAsEntity(world, log, item);
});
for (BlockPos leaf : tree.leaves)
worldIn.destroyBlock(leaf, dropBlock);
BlockHelper.destroyBlock(world, leaf, 1 / 8f, item -> {
if (dropBlock)
Block.spawnAsEntity(world, leaf, item);
});
}
return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving);
@SubscribeEvent
public static void onBlockDestroyed(BlockEvent.BreakEvent event) {
ItemStack heldItemMainhand = event.getPlayer().getHeldItemMainhand();
if (!AllItems.DEFORESTER.typeOf(heldItemMainhand))
return;
destroyTree(heldItemMainhand, event.getWorld(), event.getState(), event.getPos(), event.getPlayer());
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 558 B