Bug Fixes

- Fixed compat crash when tooltips are loaded early
- Buffed all sources
- Render buffers are now cleared when loading a world. Might help with shader issues
- Fixed eager loading of biomes in ore features
- Kinetic blocks now always clear their source when placed (needs testing)
- Kinetic blocks now remember their applied stress to a network before a config change
- Chassis range is now displayed with an overlay instead of outlines
- Crushing wheels are now more lenient about having different speeds
- Crushing wheels no longer pull players in peaceful mode
- Mixers no longer ignore items inserted during processing
- Powered Latch now reacts to weak power on the sides
- Fixed flexcrates not updating their inventory properly when extended
This commit is contained in:
simibubi 2020-03-21 18:32:53 +01:00
parent a12aed71d2
commit b4cdcb9729
23 changed files with 291 additions and 200 deletions

View file

@ -13,7 +13,7 @@ apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = 'mc1.14.4_v0.2'
version = 'mc1.14.4_v0.2.1'
group = 'com.simibubi.create'
archivesBaseName = 'create'
@ -71,7 +71,7 @@ repositories {
}
dependencies {
minecraft 'net.minecraftforge:forge:1.14.4-28.2.0'
minecraft 'net.minecraftforge:forge:1.14.4-28.2.3'
// compile against the JEI API but do not include it at runtime
compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.26:api")

View file

@ -127,6 +127,8 @@ public class ClientEvents {
public static void addToItemTooltip(ItemTooltipEvent event) {
if (!AllConfigs.CLIENT.tooltips.get())
return;
if (Minecraft.getInstance().player == null)
return;
ItemStack stack = event.getItemStack();
String translationKey = stack.getItem().getTranslationKey(stack);

View file

@ -15,6 +15,7 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.Tags;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.event.TickEvent.ServerTickEvent;
@ -22,6 +23,7 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBloc
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
@ -46,7 +48,8 @@ public class Events {
IWorld world = event.getWorld();
Create.redstoneLinkNetworkHandler.onLoadWorld(world);
Create.torquePropagator.onLoadWorld(world);
// Create.logisticalNetworkHandler.onLoadWorld(world);
if (event.getWorld().isRemote())
DistExecutor.runWhenOn(Dist.CLIENT, () -> CreateClient.bufferCache::invalidate);
}
@SubscribeEvent
@ -54,7 +57,6 @@ public class Events {
IWorld world = event.getWorld();
Create.redstoneLinkNetworkHandler.onUnloadWorld(world);
Create.torquePropagator.onUnloadWorld(world);
// Create.logisticalNetworkHandler.onUnloadWorld(world);
}
@SubscribeEvent

View file

@ -49,7 +49,7 @@ public class CStress extends ConfigBase {
@Override
public String getName() {
return "stressValues";
return "stressValues.v" + StressConfigDefaults.forcedUpdateVersion;
}
private static class Comments {

View file

@ -3,21 +3,27 @@ package com.simibubi.create.config;
import com.simibubi.create.AllBlocks;
public class StressConfigDefaults {
/**
* Increment this number if all stress entries should be updated in this update.
* Worlds from the previous version will overwrite potentially changed values with the new defaults.
*/
public static final int forcedUpdateVersion = 1;
public static double getDefaultStressCapacity(AllBlocks block) {
switch (block) {
case CREATIVE_MOTOR:
return 1024;
return 2048;
case FURNACE_ENGINE:
return 512;
return 1024;
case MECHANICAL_BEARING:
return 256;
return 512;
case ENCASED_FAN:
case HAND_CRANK:
return 16;
return 32;
case WATER_WHEEL:
return 4;
return 8;
default:
return -1;
}

View file

@ -0,0 +1,52 @@
package com.simibubi.create.foundation.behaviour.simple;
import java.util.function.Supplier;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import net.minecraft.nbt.CompoundNBT;
public class DeferralBehaviour extends TileEntityBehaviour {
public static IBehaviourType<DeferralBehaviour> TYPE = new IBehaviourType<DeferralBehaviour>() {
};
private boolean needsUpdate;
private Supplier<Boolean> callback;
public DeferralBehaviour(SmartTileEntity te, Supplier<Boolean> callback) {
super(te);
this.callback = callback;
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.putBoolean("NeedsUpdate", needsUpdate);
super.writeNBT(nbt);
}
@Override
public void readNBT(CompoundNBT nbt) {
needsUpdate = nbt.getBoolean("NeedsUpdate");
super.readNBT(nbt);
}
@Override
public void tick() {
super.tick();
if (needsUpdate && callback.get())
needsUpdate = false;
}
public void scheduleUpdate() {
needsUpdate = true;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -1,8 +1,5 @@
package com.simibubi.create.foundation.world;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.tuple.Pair;
@ -20,7 +17,6 @@ import net.minecraft.world.gen.feature.OreFeatureConfig;
import net.minecraft.world.gen.placement.IPlacementConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraftforge.common.ForgeConfigSpec.Builder;
import net.minecraftforge.registries.ForgeRegistries;
public abstract class OreFeature<T extends IPlacementConfig> extends ConfigBase implements IFeature {
@ -32,7 +28,7 @@ public abstract class OreFeature<T extends IPlacementConfig> extends ConfigBase
protected ConfigInt maxHeight;
private Block block;
private List<Biome> biomeWhitelist;
private Biome.Category biomeWhitelist;
public OreFeature(Block block, int clusterSize) {
this.block = block;
@ -50,16 +46,8 @@ public abstract class OreFeature<T extends IPlacementConfig> extends ConfigBase
return this;
}
public OreFeature<T> inBiomes(Biome... biomes) {
biomeWhitelist = Arrays.asList(biomes);
return this;
}
public OreFeature<T> inBiomes(Biome.Category category) {
biomeWhitelist = new LinkedList<>();
for (Biome biome : ForgeRegistries.BIOMES)
if (biome.getCategory() == category)
biomeWhitelist.add(biome);
biomeWhitelist = category;
return this;
}
@ -70,9 +58,9 @@ public abstract class OreFeature<T extends IPlacementConfig> extends ConfigBase
@Override
public Optional<ConfiguredFeature<?>> createFeature(Biome biome) {
if (biomeWhitelist != null && !biomeWhitelist.contains(biome))
if (biomeWhitelist != null && biome.getCategory() == biomeWhitelist)
return Optional.empty();
if (!canGenerate())
if (!canGenerate())
return Optional.empty();
Pair<Placement<T>, T> placement = getPlacement();

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.contraptions;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
@ -16,31 +17,42 @@ public class KineticNetwork {
private float currentStress;
private float unloadedCapacity;
private float unloadedStress;
private int unloadedMembers;
public KineticNetwork() {
sources = new HashMap<>();
members = new HashMap<>();
}
public void initFromTE(float maxStress, float currentStress) {
public void initFromTE(float maxStress, float currentStress, int members) {
unloadedCapacity = maxStress;
unloadedStress = currentStress;
unloadedMembers = members;
initialized = true;
updateStress();
updateCapacity();
}
public void addSilently(KineticTileEntity te) {
public void addSilently(KineticTileEntity te, float lastCapacity, float lastStress) {
if (members.containsKey(te))
return;
if (te.isSource()) {
float capacity = te.getAddedStressCapacity();
unloadedCapacity -= capacity * getStressMultiplierForSpeed(te.getGeneratedSpeed());
if (unloadedCapacity < 0)
unloadedCapacity = 0;
sources.put(te, capacity);
}
float stressApplied = te.getStressApplied();
unloadedStress -= stressApplied * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
if (unloadedStress < 0)
unloadedStress = 0;
members.put(te, stressApplied);
unloadedMembers--;
if (unloadedMembers < 0)
unloadedMembers = 0;
}
public void add(KineticTileEntity te) {
@ -112,22 +124,46 @@ public class KineticNetwork {
public float calculateCapacity() {
float presentCapacity = 0;
for (KineticTileEntity te : sources.keySet())
presentCapacity += sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
for (Iterator<KineticTileEntity> iterator = sources.keySet().iterator(); iterator.hasNext();) {
KineticTileEntity te = iterator.next();
if (te.getWorld().getTileEntity(te.getPos()) != te) {
iterator.remove();
continue;
}
presentCapacity += getActualCapacityOf(te);
}
float newMaxStress = presentCapacity + unloadedCapacity;
return newMaxStress;
}
public float calculateStress() {
float presentStress = 0;
for (KineticTileEntity te : members.keySet())
presentStress += members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
for (Iterator<KineticTileEntity> iterator = members.keySet().iterator(); iterator.hasNext();) {
KineticTileEntity te = iterator.next();
if (te.getWorld().getTileEntity(te.getPos()) != te) {
iterator.remove();
continue;
}
presentStress += getActualStressOf(te);
}
float newStress = presentStress + unloadedStress;
return newStress;
}
private float getStressMultiplierForSpeed(float speed) {
public float getActualCapacityOf(KineticTileEntity te) {
return sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
}
public float getActualStressOf(KineticTileEntity te) {
return members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
}
private static float getStressMultiplierForSpeed(float speed) {
return Math.abs(speed);
}
public int getSize() {
return unloadedMembers + members.size();
}
}

View file

@ -22,7 +22,7 @@ public class TorquePropagator {
Create.logger.debug("Removed Kinetic Network Space for " + world.getDimension().getType().getRegistryName());
}
public KineticNetwork getNetworkFor(KineticTileEntity te) {
public KineticNetwork getOrCreateNetworkFor(KineticTileEntity te) {
Long id = te.network;
KineticNetwork network;
Map<Long, KineticNetwork> map = networks.get(te.getWorld());

View file

@ -102,6 +102,7 @@ public abstract class KineticBlock extends Block implements IRotate {
return;
if (worldIn.isRemote())
return;
tileEntity.removeSource();
RotationPropagator.handleAdded(worldIn.getWorld(), pos, tileEntity);
}

View file

@ -39,7 +39,10 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
protected boolean overStressed;
private int flickerTally;
private int networkSize;
private int validationCountdown;
private float lastStressApplied;
private float lastCapacityProvided;
public KineticTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
@ -48,14 +51,15 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
@Override
public void initialize() {
super.initialize();
if (!hasNetwork())
return;
KineticNetwork network = getOrCreateNetwork();
if (!network.initialized)
network.initFromTE(capacity, stress);
network.addSilently(this);
network.initFromTE(capacity, stress, networkSize);
network.addSilently(this, lastCapacityProvided, lastStressApplied);
super.initialize();
}
@Override
@ -166,9 +170,18 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
if (hasNetwork()) {
CompoundNBT networkTag = new CompoundNBT();
networkTag.putLong("Id", network);
networkTag.putLong("Id", this.network);
networkTag.putFloat("Stress", stress);
networkTag.putFloat("Capacity", capacity);
networkTag.putInt("Size", getOrCreateNetwork().getSize());
float stressApplied = getStressApplied();
float addedStressCapacity = getAddedStressCapacity();
if (stressApplied != 0)
networkTag.putFloat("AddedStress", stressApplied);
if (addedStressCapacity != 0)
networkTag.putFloat("AddedCapacity", addedStressCapacity);
compound.put("Network", networkTag);
}
@ -184,6 +197,8 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
overStressed = false;
stress = 0;
capacity = 0;
lastStressApplied = 0;
lastCapacityProvided = 0;
if (compound.contains("Source"))
source = NBTUtil.readBlockPos(compound.getCompound("Source"));
@ -193,6 +208,9 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
network = networkTag.getLong("Id");
stress = networkTag.getFloat("Stress");
capacity = networkTag.getFloat("Capacity");
networkSize = networkTag.getInt("Size");
lastStressApplied = networkTag.getFloat("AddedStress");
lastCapacityProvided = networkTag.getFloat("AddedCapacity");
overStressed = capacity < stress && StressImpact.isEnabled();
}
@ -275,7 +293,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
}
public KineticNetwork getOrCreateNetwork() {
return Create.torquePropagator.getNetworkFor(this);
return Create.torquePropagator.getOrCreateNetworkFor(this);
}
public boolean hasNetwork() {

View file

@ -1,58 +1,52 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.LinearChassisBlock;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.World;
public class ChassisRangeDisplay {
private static final VoxelShape BLOCK_OUTLINE = Block.makeCuboidShape(-.5f, -.5f, -.5f, 16.5f, 16.5f, 16.5f);
private static final int DISPLAY_TIME = 200;
private static GroupEntry lastHoveredGroup = null;
private static class Entry {
VoxelShape shape;
Set<BlockPos> includedPositions;
ChassisTileEntity te;
int timer;
public Entry(ChassisTileEntity te) {
this.te = te;
this.shape = createSelection(te);
includedPositions = createSelection(te);
timer = DISPLAY_TIME;
}
protected VoxelShape createSelection(ChassisTileEntity chassis) {
List<BlockPos> positions = chassis.getIncludedBlockPositions(null, true);
VoxelShape shape = VoxelShapes.empty();
if (positions == null)
return shape;
for (BlockPos blockPos : positions)
shape =
VoxelShapes.or(shape, BLOCK_OUTLINE.withOffset(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
return shape;
protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
Set<BlockPos> positions = new HashSet<>();
List<BlockPos> includedBlockPositions = chassis.getIncludedBlockPositions(null, true);
if (includedBlockPositions == null)
return Collections.emptySet();
positions.addAll(includedBlockPositions);
return positions;
}
}
@ -66,21 +60,14 @@ public class ChassisRangeDisplay {
}
@Override
protected VoxelShape createSelection(ChassisTileEntity chassis) {
VoxelShape shape = VoxelShapes.empty();
protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
Set<BlockPos> list = new HashSet<>();
includedTEs = te.collectChassisGroup();
if (includedTEs == null)
return shape;
// outlining algo is not very scalable -> display only single chassis if group gets too large
if (LinearChassisBlock.isChassis(chassis.getBlockState()) && includedTEs.size() > 32)
includedTEs = Arrays.asList(chassis);
if (AllBlocks.ROTATION_CHASSIS.typeOf(chassis.getBlockState()) && includedTEs.size() > 8)
includedTEs = Arrays.asList(chassis);
return list;
for (ChassisTileEntity chassisTileEntity : includedTEs)
shape = VoxelShapes.or(shape, super.createSelection(chassisTileEntity));
return shape;
list.addAll(super.createSelection(chassisTileEntity));
return list;
}
}
@ -106,35 +93,40 @@ public class ChassisRangeDisplay {
}
}
if (hasWrench) {
RayTraceResult over = Minecraft.getInstance().objectMouseOver;
if (!(over instanceof BlockRayTraceResult))
if (!hasWrench)
return;
RayTraceResult over = Minecraft.getInstance().objectMouseOver;
if (!(over instanceof BlockRayTraceResult))
return;
BlockRayTraceResult ray = (BlockRayTraceResult) over;
BlockPos pos = ray.getPos();
TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity == null || tileEntity.isRemoved())
return;
if (!(tileEntity instanceof ChassisTileEntity))
return;
boolean ctrl = AllKeys.ctrlDown();
ChassisTileEntity chassisTileEntity = (ChassisTileEntity) tileEntity;
if (ctrl) {
GroupEntry existingGroupForPos = getExistingGroupForPos(pos);
if (existingGroupForPos != null) {
for (ChassisTileEntity included : existingGroupForPos.includedTEs)
entries.remove(included.getPos());
existingGroupForPos.timer = DISPLAY_TIME;
return;
BlockRayTraceResult ray = (BlockRayTraceResult) over;
BlockPos pos = ray.getPos();
TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity == null || tileEntity.isRemoved())
return;
if (tileEntity instanceof ChassisTileEntity) {
ChassisTileEntity chassisTileEntity = (ChassisTileEntity) tileEntity;
if (AllKeys.ctrlDown()) {
GroupEntry existingGroupForPos = getExistingGroupForPos(pos);
if (existingGroupForPos != null) {
for (ChassisTileEntity included : existingGroupForPos.includedTEs)
entries.remove(included.getPos());
existingGroupForPos.timer = DISPLAY_TIME;
return;
}
}
if (!entries.containsKey(pos) || AllKeys.ctrlDown())
display(chassisTileEntity);
else {
deselect();
if (!AllKeys.ctrlDown())
entries.get(pos).timer = DISPLAY_TIME;
}
}
}
if (!entries.containsKey(pos) || ctrl)
display(chassisTileEntity);
else {
deselect();
if (!ctrl)
entries.get(pos).timer = DISPLAY_TIME;
}
}
private static void deselect() {
@ -184,23 +176,31 @@ public class ChassisRangeDisplay {
GlStateManager.lineWidth(2);
TessellatorHelper.prepareForDrawing();
GlStateManager.disableTexture();
GlStateManager.enableAlphaTest();
for (Entry entry : entries.values()) {
float timer = entry.timer - partialTicks;
float alpha = timer > 20 ? 1 : timer / 20f;
WorldRenderer.drawShape(entry.shape, 0, 0, 0, 1, .7f, 0, alpha);
}
for (Entry entry : groupEntries) {
float timer = entry.timer - partialTicks;
float alpha = timer > 20 ? 1 : timer / 20f;
WorldRenderer.drawShape(entry.shape, 0, 0, 0, 1, .7f, 0, alpha);
}
for (Entry entry : entries.values())
renderPositions(entry, partialTicks);
for (Entry groupEntry : groupEntries)
renderPositions(groupEntry, partialTicks);
GlStateManager.enableTexture();
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
TessellatorHelper.cleanUpAfterDrawing();
GlStateManager.lineWidth(1);
}
public static void renderPositions(Entry entry, float partialTicks) {
TessellatorHelper.begin();
BlockPos size = new BlockPos(1, 1, 1);
float timer = entry.timer - partialTicks;
float alpha = timer > 20 ? .5f : timer / 40f;
GlStateManager.color4f(1, .7f, 0, alpha);
Set<BlockPos> includedPositions = entry.includedPositions;
for (BlockPos pos : includedPositions)
TessellatorHelper.cube(Tessellator.getInstance().getBuffer(), pos, size, 1 / 1024f, true, false);
TessellatorHelper.draw();
}
private static GroupEntry getExistingGroupForPos(BlockPos pos) {
for (GroupEntry groupEntry : groupEntries)
for (ChassisTileEntity chassis : groupEntry.includedTEs)

View file

@ -77,7 +77,8 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock {
controllerShouldExist = true;
KineticTileEntity te = (KineticTileEntity) world.getTileEntity(pos);
KineticTileEntity otherTe = (KineticTileEntity) world.getTileEntity(otherWheelPos);
if (te != null && otherTe != null && -te.getSpeed() == otherTe.getSpeed() && te.getSpeed() != 0) {
if (te != null && otherTe != null && (te.getSpeed() > 0) != (otherTe.getSpeed() > 0)
&& te.getSpeed() != 0) {
float signum = Math.signum(te.getSpeed()) * (state.get(AXIS) == Axis.X ? -1 : 1);
controllerShouldBeValid = facing.getAxisDirection().getOffset() != signum;
}

View file

@ -28,6 +28,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.Difficulty;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
@ -88,7 +89,10 @@ public class CrushingWheelControllerBlock extends Block implements IHaveNoBlockI
((ItemEntity) entityIn).setPickupDelay(10);
if (te.isOccupied())
return;
if ((entityIn instanceof PlayerEntity) && ((PlayerEntity) entityIn).isCreative())
boolean isPlayer = entityIn instanceof PlayerEntity;
if (isPlayer && ((PlayerEntity) entityIn).isCreative())
return;
if (isPlayer && entityIn.world.getDifficulty() == Difficulty.PEACEFUL)
return;
te.startCrushing(entityIn);

View file

@ -58,7 +58,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
};
minIngredients = new ScrollValueBehaviour(Lang.translate("mechanical_mixer.min_ingredients"), this, slot);
minIngredients.between(1, 9);
minIngredients.withCallback(i -> checkBasin = true);
minIngredients.withCallback(i -> basinChecker.scheduleUpdate());
minIngredients.requiresWrench();
behaviours.add(minIngredients);
}
@ -217,7 +217,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
@Override
public void startProcessingBasin() {
if (running)
if (running && runningTicks <= 20)
return;
super.startProcessingBasin();
running = true;
@ -244,4 +244,9 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
return shapelessOrMixingRecipesKey;
}
@Override
protected boolean isRunning() {
return running;
}
}

View file

@ -190,8 +190,10 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
}
if (!world.isRemote) {
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ITEM_BREAK.get(), SoundCategory.BLOCKS, .5f, 1f);
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ACTIVATION.get(), SoundCategory.BLOCKS, .125f, 1f);
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ITEM_BREAK.get(), SoundCategory.BLOCKS,
.5f, 1f);
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ACTIVATION.get(), SoundCategory.BLOCKS,
.125f, 1f);
}
}
@ -257,8 +259,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
public Optional<PressingRecipe> getRecipe(ItemStack item) {
pressingInv.setInventorySlotContents(0, item);
Optional<PressingRecipe> recipe = world.getRecipeManager().getRecipe(AllRecipes.PRESSING.getType(), pressingInv,
world);
Optional<PressingRecipe> recipe =
world.getRecipeManager().getRecipe(AllRecipes.PRESSING.getType(), pressingInv, world);
return recipe;
}
@ -305,7 +307,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
@Override
public void startProcessingBasin() {
if (running)
if (running && runningTicks <= 30)
return;
super.startProcessingBasin();
start(Mode.BASIN);
@ -320,4 +322,9 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
sendData();
}
@Override
protected boolean isRunning() {
return running;
}
}

View file

@ -39,7 +39,6 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
@Override
public CompoundNBT write(CompoundNBT compound) {
CompoundNBT flows = new CompoundNBT();
for (Direction d : Direction.values())
flows.putFloat(d.getName(), this.flows.get(d));

View file

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.simple.DeferralBehaviour;
import com.simibubi.create.foundation.utility.recipe.RecipeFinder;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.processing.BasinTileEntity.BasinInventory;
@ -16,6 +18,7 @@ import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.NonNullList;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
@ -24,7 +27,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
public abstract class BasinOperatingTileEntity extends KineticTileEntity {
public boolean checkBasin;
public DeferralBehaviour basinChecker;
public boolean basinRemoved;
protected IRecipe<?> lastRecipe;
protected LazyOptional<IItemHandler> basinInv = LazyOptional.empty();
@ -32,7 +35,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
public BasinOperatingTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
checkBasin = true;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
basinChecker = new DeferralBehaviour(this, this::updateBasin);
behaviours.add(basinChecker);
}
@Override
@ -40,7 +49,7 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
super.onSpeedChanged(prevSpeed);
if (getSpeed() == 0)
basinRemoved = true;
checkBasin = true;
basinChecker.scheduleUpdate();
}
public void gatherInputs() {
@ -57,8 +66,6 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
@Override
public void tick() {
super.tick();
if (basinRemoved) {
basinRemoved = false;
basinRemoved();
@ -66,40 +73,41 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
return;
}
super.tick();
}
protected boolean updateBasin() {
if (!isSpeedRequirementFulfilled())
return;
return true;
if (getSpeed() == 0)
return;
if (!isCheckingBasin())
return;
if (!checkBasin)
return;
checkBasin = false;
return true;
if (isRunning())
return false;
TileEntity basinTE = world.getTileEntity(pos.down(2));
if (basinTE == null || !(basinTE instanceof BasinTileEntity))
return;
return true;
if (!basinInv.isPresent())
basinInv = basinTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
if (!basinInv.isPresent())
return;
return true;
if (world.isRemote)
return;
return true;
gatherInputs();
List<IRecipe<?>> recipes = getMatchingRecipes();
if (recipes.isEmpty())
return;
return true;
lastRecipe = recipes.get(0);
startProcessingBasin();
sendData();
}
protected boolean isCheckingBasin() {
return true;
}
protected abstract boolean isRunning();
public void startProcessingBasin() {
}
@ -122,7 +130,9 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
List<ItemStack> catalysts = new ArrayList<>();
int buckets = 0;
Ingredients: for (Ingredient ingredient : lastRecipe.getIngredients()) {
NonNullList<Ingredient> ingredients = lastRecipe.getIngredients();
Ingredients: for (int i = 0; i < ingredients.size(); i++) {
Ingredient ingredient = ingredients.get(i);
for (int slot = 0; slot < inputs.getSlots(); slot++) {
if (!ingredient.test(inputs.extractItem(slot, 1, true)))
continue;
@ -131,8 +141,7 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
buckets++;
if ((lastRecipe instanceof ProcessingRecipe)) {
ProcessingRecipe<?> pr = (ProcessingRecipe<?>) lastRecipe;
if (pr.getRollableIngredients().get(slot).remains())
if (((ProcessingRecipe<?>) lastRecipe).getRollableIngredients().get(i).remains())
catalysts.add(extracted.copy());
}
continue Ingredients;
@ -152,6 +161,10 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
continueWithPreviousRecipe();
sendData();
}
TileEntity basinTE = world.getTileEntity(pos.down(2));
if (basinTE instanceof BasinTileEntity)
((BasinTileEntity) basinTE).contentsChanged = false;
}
protected List<IRecipe<?>> getMatchingRecipes() {

View file

@ -19,7 +19,7 @@ import net.minecraftforge.items.wrapper.RecipeWrapper;
public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEntity {
protected boolean updateProcessing;
public boolean contentsChanged;
protected ItemStackHandler outputInventory = new ItemStackHandler(9) {
protected void onContentsChanged(int slot) {
@ -36,7 +36,7 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
protected ItemStackHandler inputInventory = new ItemStackHandler(9) {
protected void onContentsChanged(int slot) {
updateProcessing = true;
contentsChanged = true;
sendData();
markDirty();
};
@ -91,7 +91,7 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
public BasinTileEntity() {
super(AllTileEntities.BASIN.type);
updateProcessing = true;
contentsChanged = true;
recipeInventory = new BasinInputInventory();
}
@ -134,15 +134,15 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
@Override
public void tick() {
if (!updateProcessing)
if (!contentsChanged)
return;
updateProcessing = false;
contentsChanged = false;
TileEntity te = world.getTileEntity(pos.up(2));
if (te == null)
return;
if (te instanceof BasinOperatingTileEntity)
((BasinOperatingTileEntity) te).checkBasin = true;
((BasinOperatingTileEntity) te).basinChecker.scheduleUpdate();
}

View file

@ -30,7 +30,11 @@ public class LatchBlock extends ToggleLatchBlock {
boolean back = state.get(POWERED);
boolean shouldBack = this.shouldBePowered(worldIn, pos, state);
boolean side = state.get(POWERED_SIDE);
boolean shouldSide = getPowerOnSides(worldIn, pos, state) > 0;
Direction direction = state.get(HORIZONTAL_FACING);
Direction left = direction.rotateY();
Direction right = direction.rotateYCCW();
boolean shouldSide = worldIn.isBlockPowered(pos.offset(left)) || worldIn.isBlockPowered(pos.offset(right));
TickPriority tickpriority = TickPriority.HIGH;
if (this.isFacingTowardsRepeater(worldIn, pos, state))
@ -49,7 +53,11 @@ public class LatchBlock extends ToggleLatchBlock {
boolean back = state.get(POWERED);
boolean shouldBack = this.shouldBePowered(worldIn, pos, state);
boolean side = state.get(POWERED_SIDE);
boolean shouldSide = getPowerOnSides(worldIn, pos, state) > 0;
Direction direction = state.get(HORIZONTAL_FACING);
Direction left = direction.rotateY();
Direction right = direction.rotateYCCW();
boolean shouldSide = worldIn.isBlockPowered(pos.offset(left)) || worldIn.isBlockPowered(pos.offset(right));
BlockState stateIn = state;
if (back != shouldBack) {

View file

@ -84,6 +84,7 @@ public class FlexcrateBlock extends ProperDirectionalBlock {
other.inventory.setStackInSlot(slot, ItemStack.EMPTY);
}
te.allowedAmount = other.allowedAmount;
other.invHandler.invalidate();
}
}

View file

@ -4,7 +4,7 @@ loaderVersion="[28,)"
[[mods]]
modId="create"
version="0.2"
version="mc1.14-0.2.1"
displayName="Create"
#updateJSONURL=""
authors="simibubi"
@ -14,7 +14,7 @@ Technology that empowers the player.'''
[[dependencies.create]]
modId="forge"
mandatory=true
versionRange="[28.1.0,)"
versionRange="[28.1.20,)"
ordering="NONE"
side="BOTH"

View file

@ -1,52 +0,0 @@
Some of the most prominent machines and components require **Rotational Force** to operate. Sometimes the provided rotation speed and direction reflects their behaviour, and some components may have a more significant _cost_ than others.
1. Generate & Convey
2. Changing Gear
3. Stress & Capacity
## Generate & Convey
Using appropiate generators(link), you can start setting things in motion. These kinetic components will apply the speed they generate at to attached shafts, cogs, etc. Any component can be connected to any other, so long as their integrated shafts/cogs are linked together.
(waterwheel powering something) (mechanical crafters powering each other)
**Multiple generators** can be connected together in order achieve a greater Capacity score for the attached kinetic network. When attaching new generators to running components, it is important that the added generator rotates in the **same direction** as the component it is attached to. When connecting two kinetic blocks with **incompatible direction** of rotation, you'll notice that the blocks just break. However, trouble-shooting this will be quite straight-forward - all you need to do is to include a means of reversing the rotation between the generator and the rest:
Relaying rotational power between two components is one of the most important tasks when creating with Create. There are a variety of options and multiple possible solutions for each situation. These are the components that allow you to move, spread and modify rotational behaviour most effectively:
(mesh of these components showing off their behaviour)
- **Shafts**, cheapest option for relaying in a straight line.
- **Cogwheels**, move sideways while keeping the same rotation axis; reverse the direction
- **Belts**, move sideways while while keeping the same rotation axis; cannot be vertical; do not reverse direction
- **Gearboxes**, relay between two different rotation axes in a compact fashion; reverse connections on the same axis
- **Encased Belts**, relay sideways and between different rotation axes; do not reverse direction
Best is play around with each component and familiarizing yourself with its abilities. It is important to know the options when having to deal with complex connection tasks in a potentially less forgiving environment.
## Changing Gear
Some kinetic blocks have the ability to **speed up** or **slow down** connected components. Attach a large to a regular cogwheel diagonally: powering one of them at their shaft will result in the other rotating twice or half the speed respectively.
With this and other more compact blocks, you will have full control over the speed provided to your contraptions. This is especially important for machines that require a **minimum level of speed** to operate (e.g. the Mechanical Mixer).
Connecting faster components to other slower components **directly** will cause the faster network to overpower the rest, alinging the speed of everything that is now part of it. (That is, if the direction lines up)
(image of something ridiculous)
With this mechanic you can take things to the extreme and either rotate machines at the configurated maximum speed (256rpm by default) or slow them down to a fraction. But you may notice that speeding up brings a cost with it...
## Stress & Capacity
_In Create 0.2+, a bit of balance had been brought to rotational power: something to resemble torque in a highly simplified fashion._
Rotational generators have limited capacity for what they power. "Stress Impact" and "Stress Capacity" are the two opposing values in a kinetic network: **generators add capacity, machines and components add impact**. If the capacity is exhausted, all connected parts will simply stop moving, until capacity is increased or stress is relieved again.
**Stress Impact is tied to rotation speed**. Increasing the speed increases a components stress impact or capacity proportionally.
(image of fans and water wheel)
Consider the following example:
Assume one Water Wheel can provide just enough power in order to power four fans at the same speed.
* Doubling the speed of the fans using cogwheels will make the fans blow stronger, but the network will cease to function until the count of fans is halved, or the count of water wheels is doubled.
* Similarly, you would be able to power eight fans running at half the speed of the water wheel.
By default, components used **only for relaying** rotational power, such as shafts and cogwheels, have **no stress impact** at all. This makes predicting the amount of generators required for your contraptions much simpler and prevents punishment for aesthetic detours between machines and generators.
Optimizing stress impact and comparing net capacity of sources at base speed can become quite scientific. For those who are interested in seeing some actual numbers and more exhaustive information, it is recommended to look into crafting a pair of Goggles and a Stress Gauge.