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:
parent
785d77a59d
commit
fca3b74909
26 changed files with 358 additions and 205 deletions
|
@ -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")
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,5 +43,7 @@ public class Debug {
|
|||
}
|
||||
return text + TextFormatting.GRAY + " ...";
|
||||
}
|
||||
|
||||
public static void markTemporary() {};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -50,14 +50,9 @@ public class RecipeFinder {
|
|||
public <X extends IRecipe<?>> RecipeStream<X> assumeType(IRecipeType<X> type) {
|
||||
return (RecipeStream<X>) this;
|
||||
}
|
||||
|
||||
public RecipeStream<R> filter(Predicate<R> condition) {
|
||||
stream.filter(condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<R> asList() {
|
||||
return stream.collect(Collectors.toList());
|
||||
|
||||
public List<R> filter(Predicate<R> condition) {
|
||||
return stream.filter(condition).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,8 +96,12 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
|
|||
return true;
|
||||
}
|
||||
|
||||
public void onSpeedChanged() {
|
||||
speedChangeCounter += 5;
|
||||
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
|
||||
|
@ -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--;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getRenderBoundingBox() {
|
||||
return new AxisAlignedBB(pos).grow(1);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ public class SawBlock extends DirectionalAxisKineticBlock
|
|||
public float getFilterAngle(BlockState state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isFilterVisible(BlockState state) {
|
||||
return state.get(FACING) == Direction.UP;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -28,8 +28,17 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
|
|||
else
|
||||
color = 0xFF0000;
|
||||
}
|
||||
|
||||
|
||||
sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged(float prevSpeed) {
|
||||
super.onSpeedChanged(prevSpeed);
|
||||
if (getSpeed() == 0)
|
||||
dialTarget = 0;
|
||||
else
|
||||
sync(maxStress, currentStress);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
// 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;
|
||||
boolean dropBlock = !player.isCreative();
|
||||
World world = worldIn.getWorld();
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
if (state.isIn(BlockTags.LOGS) && !entityLiving.isSneaking()) {
|
||||
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();
|
||||
for (BlockPos log : tree.logs)
|
||||
worldIn.destroyBlock(log, dropBlock);
|
||||
for (BlockPos leaf : tree.leaves)
|
||||
worldIn.destroyBlock(leaf, dropBlock);
|
||||
}
|
||||
for (BlockPos log : tree.logs)
|
||||
BlockHelper.destroyBlock(world, log, 1 / 2f, item -> {
|
||||
if (dropBlock)
|
||||
Block.spawnAsEntity(world, log, item);
|
||||
});
|
||||
for (BlockPos leaf : tree.leaves)
|
||||
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 |
Loading…
Reference in a new issue