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' sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
minecraft { minecraft {
mappings channel: 'snapshot', version: '20191107-1.14.3' mappings channel: 'snapshot', version: '20191130-1.14.3'
runs { runs {
client { client {
@ -71,7 +71,7 @@ repositories {
} }
dependencies { 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 // 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") 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; package com.simibubi.create.foundation.utility;
import java.util.function.Consumer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.SlabType; 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 { public class BlockHelper {
@ -61,4 +70,25 @@ public class BlockHelper {
return itemStack; 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 + " ..."; return text + TextFormatting.GRAY + " ...";
} }
public static void markTemporary() {};
} }

View file

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

View file

@ -1,6 +1,6 @@
package com.simibubi.create.foundation.utility.recipe; 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.ItemStack;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;

View file

@ -51,13 +51,8 @@ public class RecipeFinder {
return (RecipeStream<X>) this; return (RecipeStream<X>) this;
} }
public RecipeStream<R> filter(Predicate<R> condition) { public List<R> filter(Predicate<R> condition) {
stream.filter(condition); return stream.filter(condition).collect(Collectors.toList());
return this;
}
public List<R> asList() {
return stream.collect(Collectors.toList());
} }
} }

View file

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

View file

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

View file

@ -24,6 +24,7 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
public void updateGeneratedRotation() { public void updateGeneratedRotation() {
float speed = getGeneratedSpeed(); float speed = getGeneratedSpeed();
float prevSpeed = this.speed;
if (this.speed != 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().updateStressCapacity();
getNetwork().updateStress();
}
onSpeedChanged(); onSpeedChanged(prevSpeed);
sendData(); sendData();
} }

View file

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

View file

@ -59,6 +59,8 @@ public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTil
rainbowMode = true; rainbowMode = true;
if (te.hasNetwork()) if (te.hasNetwork())
buffer.color(LogisticalActorTileEntity.colorFromUUID(te.getNetworkID())); buffer.color(LogisticalActorTileEntity.colorFromUUID(te.getNetworkID()));
else
buffer.color(0xFFFFFF);
} }
return buffer; 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; package com.simibubi.create.modules.contraptions.components.actors;
import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.AllTileEntities; 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.DamageSource;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; 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 { public class DrillTileEntity extends BlockBreakingKineticTileEntity {
private static final AtomicInteger NEXT_DRILL_ID = new AtomicInteger();
public static DamageSource damageSourceDrill = new DamageSource("create.drill").setDamageBypassesArmor(); public static DamageSource damageSourceDrill = new DamageSource("create.drill").setDamageBypassesArmor();
private int ticksUntilNextProgress;
private int destroyProgress;
private int drillId = -NEXT_DRILL_ID.incrementAndGet();
public DrillTileEntity() { public DrillTileEntity() {
super(AllTileEntities.DRILL.type); super(AllTileEntities.DRILL.type);
} }
@Override @Override
public void onSpeedChanged() { protected BlockPos getBreakingPos() {
super.onSpeedChanged(); return getPos().offset(getBlockState().get(DrillBlock.FACING));
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);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,17 +6,24 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import com.google.common.base.Predicates;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllRecipes; import com.simibubi.create.AllRecipes;
import com.simibubi.create.AllTileEntities; 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.VecHelper;
import com.simibubi.create.foundation.utility.recipe.RecipeConditions; import com.simibubi.create.foundation.utility.recipe.RecipeConditions;
import com.simibubi.create.foundation.utility.recipe.RecipeFinder; 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.processing.ProcessingInventory;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.IHaveFilter; import com.simibubi.create.modules.logistics.block.IHaveFilter;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -28,6 +35,7 @@ import net.minecraft.particles.BlockParticleData;
import net.minecraft.particles.IParticleData; import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes; import net.minecraft.particles.ParticleTypes;
import net.minecraft.tags.BlockTags;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; 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.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; 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(); private static final Object cuttingRecipesKey = new Object();
public ProcessingInventory inventory; public ProcessingInventory inventory;
@ -62,8 +70,8 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
} }
@Override @Override
public void onSpeedChanged() { public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(); super.onSpeedChanged(prevSpeed);
boolean shouldRun = Math.abs(getSpeed()) > 1 / 64f; boolean shouldRun = Math.abs(getSpeed()) > 1 / 64f;
boolean running = getBlockState().get(RUNNING); boolean running = getBlockState().get(RUNNING);
if (shouldRun != running) if (shouldRun != running)
@ -88,7 +96,10 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
@Override @Override
public void tick() { public void tick() {
if (shouldRun() && ticksUntilNextProgress < 0)
destroyNextTick();
super.tick(); super.tick();
if (!canProcess()) if (!canProcess())
return; return;
if (getSpeed() == 0) 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; float offset = inventory.recipeDuration != 0 ? (float) (inventory.remainingTime) / inventory.recipeDuration : 0;
offset -= .5f; offset -= .5f;
world.addParticle(particleData, pos.getX() + -vec.x * offset, pos.getY() + .45f, pos.getZ() + -vec.z * offset, 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() { public Vec3d getItemMovementVec() {
@ -272,11 +283,11 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
} }
private List<? extends IRecipe<?>> getRecipes() { private List<? extends IRecipe<?>> getRecipes() {
return RecipeFinder StartedSearch startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
.get(cuttingRecipesKey, world, RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipes.Types.CUTTING));
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipes.Types.CUTTING)) RecipeStream<IRecipe<?>> search = startedSearch.search();
.search().filter(RecipeConditions.outputMatchesFilter(filter)) return search.filter(Predicates.and(RecipeConditions.outputMatchesFilter(filter),
.filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))).asList(); RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))));
} }
public void insertItem(ItemEntity entity) { public void insertItem(ItemEntity entity) {
@ -345,4 +356,41 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
return filter; 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); super.read(compound);
} }
@Override
public void removeSource() {
super.removeSource();
dialTarget = 0;
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();

View file

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

View file

@ -32,4 +32,13 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
sendData(); 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; 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;
import com.simibubi.create.foundation.utility.TreeCutter.Tree; import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.modules.curiosities.tools.AllToolTiers; import com.simibubi.create.modules.curiosities.tools.AllToolTiers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AxeItem; import net.minecraft.item.AxeItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World; 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 class DeforesterItem extends AxeItem {
public DeforesterItem(Properties builder) { public DeforesterItem(Properties builder) {
super(AllToolTiers.RADIANT, 10.0F, -3.1F, builder); super(AllToolTiers.RADIANT, 10.0F, -3.1F, builder);
} }
@Override // Moved away from Item#onBlockDestroyed as it does not get called in Creative
public boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos, public static void destroyTree(ItemStack stack, IWorld worldIn, BlockState state, BlockPos pos,
LivingEntity entityLiving) { PlayerEntity player) {
if (!state.isIn(BlockTags.LOGS) || player.isSneaking())
if (state.isIn(BlockTags.LOGS) && !entityLiving.isSneaking()) { return;
Tree tree = TreeCutter.cutTree(worldIn, pos); Tree tree = TreeCutter.cutTree(worldIn, pos);
if (tree == null) if (tree == null)
return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving); return;
boolean dropBlock = !(entityLiving instanceof PlayerEntity) || !((PlayerEntity) entityLiving).isCreative(); boolean dropBlock = !player.isCreative();
World world = worldIn.getWorld();
if (world == null)
return;
for (BlockPos log : tree.logs) 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) 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