Merge remote-tracking branch 'origin/mc1.14-v0.2.1' into mc1.15-v0.2.1

Conflicts:
	build.gradle
This commit is contained in:
tterrag 2020-03-22 14:27:03 -04:00
commit 96106f2a9e
38 changed files with 420 additions and 238 deletions

View file

@ -13,7 +13,7 @@ apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse' apply plugin: 'eclipse'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
version = 'mc1.15.2_v0.2' version = 'mc1.15.2_v0.2.1'
group = 'com.simibubi.create' group = 'com.simibubi.create'
archivesBaseName = 'create' archivesBaseName = 'create'

View file

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

View file

@ -8,6 +8,7 @@ import org.apache.logging.log4j.Logger;
import com.simibubi.create.config.AllConfigs; import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.command.CreateCommand; import com.simibubi.create.foundation.command.CreateCommand;
import com.simibubi.create.foundation.command.ServerLagger; import com.simibubi.create.foundation.command.ServerLagger;
import com.simibubi.create.foundation.world.AllWorldFeatures;
import com.simibubi.create.modules.ModuleLoadedCondition; import com.simibubi.create.modules.ModuleLoadedCondition;
import com.simibubi.create.modules.contraptions.TorquePropagator; import com.simibubi.create.modules.contraptions.TorquePropagator;
import com.simibubi.create.modules.logistics.RedstoneLinkNetworkHandler; import com.simibubi.create.modules.logistics.RedstoneLinkNetworkHandler;
@ -62,6 +63,7 @@ public class Create {
modEventBus.addListener(AllConfigs::onLoad); modEventBus.addListener(AllConfigs::onLoad);
modEventBus.addListener(AllConfigs::onReload); modEventBus.addListener(AllConfigs::onReload);
CreateClient.addListeners(modEventBus); CreateClient.addListeners(modEventBus);
AllWorldFeatures.reload();
} }
public static void init(final FMLCommonSetupEvent event) { public static void init(final FMLCommonSetupEvent event) {

View file

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

View file

@ -7,6 +7,7 @@ public class CKinetics extends ConfigBase {
public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage); public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed); public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed);
public ConfigInt waterWheelSpeed = i(5, 1, "waterWheelSpeed", Comments.rpm, Comments.waterWheelSpeed); public ConfigInt waterWheelSpeed = i(5, 1, "waterWheelSpeed", Comments.rpm, Comments.waterWheelSpeed);
public ConfigInt furnaceEngineSpeed = i(16, 1, "furnaceEngineSpeed", Comments.rpm, Comments.furnaceEngineSpeed);
public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed); public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed);
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks = public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks); e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
@ -69,6 +70,7 @@ public class CKinetics extends ConfigBase {
static String stress = "Fine tune the kinetic stats of individual components"; static String stress = "Fine tune the kinetic stats of individual components";
static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them."; static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them.";
static String waterWheelSpeed = "Rotation speed gained by a water wheel for each side with running water. (halved if not against blades)"; static String waterWheelSpeed = "Rotation speed gained by a water wheel for each side with running water. (halved if not against blades)";
static String furnaceEngineSpeed = "Base rotation speed for the furnace engine generator";
static String disableStress = "Disable the Stress mechanic altogether."; static String disableStress = "Disable the Stress mechanic altogether.";
static String kineticValidationFrequency = "Game ticks between Kinetic Blocks checking whether their source is still valid."; static String kineticValidationFrequency = "Game ticks between Kinetic Blocks checking whether their source is still valid.";
} }

View file

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

View file

@ -20,6 +20,12 @@ public class CWorldGen extends ConfigBase {
super.onReload(); super.onReload();
} }
@Override
public void onLoad() {
AllWorldFeatures.reload();
super.onLoad();
}
@Override @Override
public String getName() { public String getName() {
return "world"; return "world";

View file

@ -3,21 +3,27 @@ package com.simibubi.create.config;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
public class StressConfigDefaults { 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) { public static double getDefaultStressCapacity(AllBlocks block) {
switch (block) { switch (block) {
case CREATIVE_MOTOR: case CREATIVE_MOTOR:
return 1024; return 2048;
case FURNACE_ENGINE: case FURNACE_ENGINE:
return 512; return 1024;
case MECHANICAL_BEARING: case MECHANICAL_BEARING:
return 256; return 512;
case ENCASED_FAN: case ENCASED_FAN:
case HAND_CRANK: case HAND_CRANK:
return 16; return 32;
case WATER_WHEEL: case WATER_WHEEL:
return 4; return 8;
default: default:
return -1; 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,26 +1,5 @@
package com.simibubi.create.foundation.item; package com.simibubi.create.foundation.item;
import static com.simibubi.create.foundation.item.TooltipHelper.cutString;
import static net.minecraft.util.text.TextFormatting.AQUA;
import static net.minecraft.util.text.TextFormatting.BLUE;
import static net.minecraft.util.text.TextFormatting.DARK_GRAY;
import static net.minecraft.util.text.TextFormatting.DARK_GREEN;
import static net.minecraft.util.text.TextFormatting.DARK_PURPLE;
import static net.minecraft.util.text.TextFormatting.DARK_RED;
import static net.minecraft.util.text.TextFormatting.GOLD;
import static net.minecraft.util.text.TextFormatting.GRAY;
import static net.minecraft.util.text.TextFormatting.GREEN;
import static net.minecraft.util.text.TextFormatting.LIGHT_PURPLE;
import static net.minecraft.util.text.TextFormatting.RED;
import static net.minecraft.util.text.TextFormatting.STRIKETHROUGH;
import static net.minecraft.util.text.TextFormatting.WHITE;
import static net.minecraft.util.text.TextFormatting.YELLOW;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.config.AllConfigs; import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.config.CKinetics; import com.simibubi.create.config.CKinetics;
@ -28,8 +7,10 @@ import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.IRotate; import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact; import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact;
import com.simibubi.create.modules.contraptions.components.fan.EncasedFanBlock;
import com.simibubi.create.modules.contraptions.components.flywheel.engine.EngineBlock; import com.simibubi.create.modules.contraptions.components.flywheel.engine.EngineBlock;
import com.simibubi.create.modules.contraptions.components.flywheel.engine.FurnaceEngineBlock;
import com.simibubi.create.modules.contraptions.components.waterwheel.WaterWheelBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
@ -40,6 +21,14 @@ import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static com.simibubi.create.foundation.item.TooltipHelper.cutString;
import static net.minecraft.util.text.TextFormatting.*;
public class ItemDescription { public class ItemDescription {
public static final ItemDescription MISSING = new ItemDescription(null); public static final ItemDescription MISSING = new ItemDescription(null);
@ -144,6 +133,11 @@ public class ItemDescription {
add(linesOnShift, GRAY + Lang.translate("tooltip.capacityProvided")); add(linesOnShift, GRAY + Lang.translate("tooltip.capacityProvided"));
add(linesOnShift, level); add(linesOnShift, level);
String genSpeed = generatorSpeed(block, rpmUnit);
if (!genSpeed.equals("")) {
add(linesOnShift, GREEN + " " + genSpeed);
}
} }
if (hasSpeedRequirement || hasStressImpact || hasStressCapacity) if (hasSpeedRequirement || hasStressImpact || hasStressCapacity)
@ -269,4 +263,23 @@ public class ItemDescription {
return linesOnShift; return linesOnShift;
} }
private String generatorSpeed(Block block, String unitRPM) {
String value = "";
if (block instanceof WaterWheelBlock) {
int baseSpeed = AllConfigs.SERVER.kinetics.waterWheelSpeed.get();
value = baseSpeed + "-" + (baseSpeed * 3);
}
else if (block instanceof EncasedFanBlock)
value = AllConfigs.SERVER.kinetics.generatingFanSpeed.get().toString();
else if (block instanceof FurnaceEngineBlock) {
int baseSpeed = AllConfigs.SERVER.kinetics.furnaceEngineSpeed.get();
value = baseSpeed + "-" + (baseSpeed * 2);
}
return !value.equals("") ? Lang.translate("tooltip.generationSpeed", value, unitRPM) : "";
}
} }

View file

@ -44,13 +44,13 @@ public enum AllWorldFeatures {
for (AllWorldFeatures entry : AllWorldFeatures.values()) { for (AllWorldFeatures entry : AllWorldFeatures.values()) {
for (Biome biome : ForgeRegistries.BIOMES) { for (Biome biome : ForgeRegistries.BIOMES) {
if (entry.featureInstances.containsKey(biome)) if (entry.featureInstances.containsKey(biome))
biome.getFeatures(entry.feature.getGenerationStage()).remove(entry.featureInstances.remove(biome)); biome.getFeatures(entry.feature.getGenerationStage()).remove(entry.featureInstances.remove(biome));
Optional<ConfiguredFeature<?>> createFeature = entry.feature.createFeature(biome); Optional<ConfiguredFeature<?>> createFeature = entry.feature.createFeature(biome);
if (!createFeature.isPresent()) if (!createFeature.isPresent())
continue; continue;
entry.featureInstances.put(biome, createFeature.get()); entry.featureInstances.put(biome, createFeature.get());
biome.addFeature(entry.feature.getGenerationStage(), createFeature.get()); biome.addFeature(entry.feature.getGenerationStage(), createFeature.get());
} }

View file

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

View file

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

View file

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

View file

@ -31,7 +31,8 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override @Override
public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { public boolean canBreak(World world, BlockPos breakingPos, BlockState state) {
return super.canBreak(world, breakingPos, state) && state.isIn(BlockTags.LOGS); return super.canBreak(world, breakingPos, state)
&& (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES));
} }
@Override @Override

View file

@ -1,58 +1,52 @@
package com.simibubi.create.modules.contraptions.components.contraptions; package com.simibubi.create.modules.contraptions.components.contraptions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
import com.simibubi.create.foundation.utility.TessellatorHelper; 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.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.Minecraft;
import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult; 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; import net.minecraft.world.World;
public class ChassisRangeDisplay { 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 final int DISPLAY_TIME = 200;
private static GroupEntry lastHoveredGroup = null; private static GroupEntry lastHoveredGroup = null;
private static class Entry { private static class Entry {
VoxelShape shape; Set<BlockPos> includedPositions;
ChassisTileEntity te; ChassisTileEntity te;
int timer; int timer;
public Entry(ChassisTileEntity te) { public Entry(ChassisTileEntity te) {
this.te = te; this.te = te;
this.shape = createSelection(te); includedPositions = createSelection(te);
timer = DISPLAY_TIME; timer = DISPLAY_TIME;
} }
protected VoxelShape createSelection(ChassisTileEntity chassis) { protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
List<BlockPos> positions = chassis.getIncludedBlockPositions(null, true); Set<BlockPos> positions = new HashSet<>();
VoxelShape shape = VoxelShapes.empty(); List<BlockPos> includedBlockPositions = chassis.getIncludedBlockPositions(null, true);
if (positions == null) if (includedBlockPositions == null)
return shape; return Collections.emptySet();
for (BlockPos blockPos : positions) positions.addAll(includedBlockPositions);
shape = return positions;
VoxelShapes.or(shape, BLOCK_OUTLINE.withOffset(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
return shape;
} }
} }
@ -66,21 +60,14 @@ public class ChassisRangeDisplay {
} }
@Override @Override
protected VoxelShape createSelection(ChassisTileEntity chassis) { protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
VoxelShape shape = VoxelShapes.empty(); Set<BlockPos> list = new HashSet<>();
includedTEs = te.collectChassisGroup(); includedTEs = te.collectChassisGroup();
if (includedTEs == null) if (includedTEs == null)
return shape; return list;
// 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);
for (ChassisTileEntity chassisTileEntity : includedTEs) for (ChassisTileEntity chassisTileEntity : includedTEs)
shape = VoxelShapes.or(shape, super.createSelection(chassisTileEntity)); list.addAll(super.createSelection(chassisTileEntity));
return shape; return list;
} }
} }
@ -106,35 +93,40 @@ public class ChassisRangeDisplay {
} }
} }
if (hasWrench) { if (!hasWrench)
RayTraceResult over = Minecraft.getInstance().objectMouseOver; return;
if (!(over instanceof BlockRayTraceResult))
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; 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() { private static void deselect() {
@ -184,23 +176,31 @@ public class ChassisRangeDisplay {
GlStateManager.lineWidth(2); GlStateManager.lineWidth(2);
TessellatorHelper.prepareForDrawing(); TessellatorHelper.prepareForDrawing();
GlStateManager.disableTexture(); GlStateManager.disableTexture();
GlStateManager.enableAlphaTest();
for (Entry entry : entries.values()) { for (Entry entry : entries.values())
float timer = entry.timer - partialTicks; renderPositions(entry, partialTicks);
float alpha = timer > 20 ? 1 : timer / 20f; for (Entry groupEntry : groupEntries)
WorldRenderer.drawShape(entry.shape, 0, 0, 0, 1, .7f, 0, alpha); renderPositions(groupEntry, partialTicks);
}
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);
}
GlStateManager.enableTexture(); GlStateManager.enableTexture();
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
TessellatorHelper.cleanUpAfterDrawing(); TessellatorHelper.cleanUpAfterDrawing();
GlStateManager.lineWidth(1); 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) { private static GroupEntry getExistingGroupForPos(BlockPos pos) {
for (GroupEntry groupEntry : groupEntries) for (GroupEntry groupEntry : groupEntries)
for (ChassisTileEntity chassis : groupEntry.includedTEs) for (ChassisTileEntity chassis : groupEntry.includedTEs)

View file

@ -77,7 +77,8 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock {
controllerShouldExist = true; controllerShouldExist = true;
KineticTileEntity te = (KineticTileEntity) world.getTileEntity(pos); KineticTileEntity te = (KineticTileEntity) world.getTileEntity(pos);
KineticTileEntity otherTe = (KineticTileEntity) world.getTileEntity(otherWheelPos); 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); float signum = Math.signum(te.getSpeed()) * (state.get(AXIS) == Axis.X ? -1 : 1);
controllerShouldBeValid = facing.getAxisDirection().getOffset() != signum; 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.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.Difficulty;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -88,7 +89,10 @@ public class CrushingWheelControllerBlock extends Block implements IHaveNoBlockI
((ItemEntity) entityIn).setPickupDelay(10); ((ItemEntity) entityIn).setPickupDelay(10);
if (te.isOccupied()) if (te.isOccupied())
return; 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; return;
te.startCrushing(entityIn); 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 = new ScrollValueBehaviour(Lang.translate("mechanical_mixer.min_ingredients"), this, slot);
minIngredients.between(1, 9); minIngredients.between(1, 9);
minIngredients.withCallback(i -> checkBasin = true); minIngredients.withCallback(i -> basinChecker.scheduleUpdate());
minIngredients.requiresWrench(); minIngredients.requiresWrench();
behaviours.add(minIngredients); behaviours.add(minIngredients);
} }
@ -217,7 +217,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
@Override @Override
public void startProcessingBasin() { public void startProcessingBasin() {
if (running) if (running && runningTicks <= 20)
return; return;
super.startProcessingBasin(); super.startProcessingBasin();
running = true; running = true;
@ -244,4 +244,9 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
return shapelessOrMixingRecipesKey; return shapelessOrMixingRecipesKey;
} }
@Override
protected boolean isRunning() {
return running;
}
} }

View file

@ -32,6 +32,7 @@ public class MotorTileEntity extends GeneratingKineticTileEntity {
generatedSpeed = new ScrollValueBehaviour(Lang.translate("generic.speed"), this, slot); generatedSpeed = new ScrollValueBehaviour(Lang.translate("generic.speed"), this, slot);
generatedSpeed.between(-max, max); generatedSpeed.between(-max, max);
generatedSpeed.value = DEFAULT_SPEED; generatedSpeed.value = DEFAULT_SPEED;
generatedSpeed.scrollableValue = DEFAULT_SPEED;
generatedSpeed.withUnit(i -> Lang.translate("generic.unit.rpm")); generatedSpeed.withUnit(i -> Lang.translate("generic.unit.rpm"));
generatedSpeed.withCallback(i -> this.updateGeneratedRotation()); generatedSpeed.withCallback(i -> this.updateGeneratedRotation());
generatedSpeed.withStepFunction(MotorTileEntity::step); generatedSpeed.withStepFunction(MotorTileEntity::step);

View file

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

View file

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

View file

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

View file

@ -69,4 +69,7 @@ public class AnalogLeverTileEntity extends SmartTileEntity {
sendData(); sendData();
} }
public int getState() {
return state;
}
} }

View file

@ -20,6 +20,7 @@ import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact; import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.redstone.AnalogLeverTileEntity;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
@ -42,6 +43,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
public class GaugeInformationRenderer { public class GaugeInformationRenderer {
private static DecimalFormat decimalFormat = new DecimalFormat("#.##"); private static DecimalFormat decimalFormat = new DecimalFormat("#.##");
private static String spacing = " ";
@SubscribeEvent @SubscribeEvent
public static void lookingAtBlocksThroughGogglesShowsTooltip(RenderGameOverlayEvent.Post event) { public static void lookingAtBlocksThroughGogglesShowsTooltip(RenderGameOverlayEvent.Post event) {
@ -64,7 +66,7 @@ public class GaugeInformationRenderer {
if (!AllItems.GOGGLES.typeOf(goggles) && !notFastEnough) if (!AllItems.GOGGLES.typeOf(goggles) && !notFastEnough)
return; return;
if (mc.player.isSneaking()) if (mc.player.isSneaking() && !(te instanceof AnalogLeverTileEntity))
return; return;
List<String> tooltip = new ArrayList<>(); List<String> tooltip = new ArrayList<>();
@ -79,6 +81,8 @@ public class GaugeInformationRenderer {
addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te); addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te);
if (te instanceof KineticTileEntity) if (te instanceof KineticTileEntity)
addStressTooltip(state, tooltip, (KineticTileEntity) te); addStressTooltip(state, tooltip, (KineticTileEntity) te);
if (te instanceof AnalogLeverTileEntity)
addLeverTooltip(state, tooltip, (AnalogLeverTileEntity) te);
} }
if (tooltip.isEmpty()) if (tooltip.isEmpty())
@ -117,7 +121,6 @@ public class GaugeInformationRenderer {
} }
private static void addStressTooltip(BlockState state, List<String> tooltip, KineticTileEntity te) { private static void addStressTooltip(BlockState state, List<String> tooltip, KineticTileEntity te) {
String spacing = " ";
float stressApplied = te.getStressApplied(); float stressApplied = te.getStressApplied();
if (stressApplied == 0 || !StressImpact.isEnabled()) if (stressApplied == 0 || !StressImpact.isEnabled())
return; return;
@ -139,7 +142,6 @@ public class GaugeInformationRenderer {
} }
private static void addGeneratorTooltip(BlockState state, List<String> tooltip, GeneratingKineticTileEntity te) { private static void addGeneratorTooltip(BlockState state, List<String> tooltip, GeneratingKineticTileEntity te) {
String spacing = " ";
float addedStressCapacity = te.getAddedStressCapacity(); float addedStressCapacity = te.getAddedStressCapacity();
if (addedStressCapacity == 0 || !StressImpact.isEnabled()) if (addedStressCapacity == 0 || !StressImpact.isEnabled())
return; return;
@ -182,7 +184,6 @@ public class GaugeInformationRenderer {
String _atCurrentSpeed = Lang.translate("gui.goggles.at_current_speed"); String _atCurrentSpeed = Lang.translate("gui.goggles.at_current_speed");
String _baseValue = Lang.translate("gui.goggles.base_value"); String _baseValue = Lang.translate("gui.goggles.base_value");
String spacing = " ";
tooltip.add(spacing + _infoHeader); tooltip.add(spacing + _infoHeader);
if (AllBlocks.STRESS_GAUGE.typeOf(state)) { if (AllBlocks.STRESS_GAUGE.typeOf(state)) {
@ -261,6 +262,11 @@ public class GaugeInformationRenderer {
} }
} }
private static void addLeverTooltip(BlockState state, List<String> tooltip, AnalogLeverTileEntity te) {
int leverState = te.getState();
tooltip.add(spacing + Lang.translate("tooltip.analogStrength", leverState));
}
private static String format(double d) { private static String format(double d) {
return decimalFormat.format(d); return decimalFormat.format(d);
} }

View file

@ -30,7 +30,11 @@ public class LatchBlock extends ToggleLatchBlock {
boolean back = state.get(POWERED); boolean back = state.get(POWERED);
boolean shouldBack = this.shouldBePowered(worldIn, pos, state); boolean shouldBack = this.shouldBePowered(worldIn, pos, state);
boolean side = state.get(POWERED_SIDE); 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; TickPriority tickpriority = TickPriority.HIGH;
if (this.isFacingTowardsRepeater(worldIn, pos, state)) if (this.isFacingTowardsRepeater(worldIn, pos, state))
@ -49,7 +53,11 @@ public class LatchBlock extends ToggleLatchBlock {
boolean back = state.get(POWERED); boolean back = state.get(POWERED);
boolean shouldBack = this.shouldBePowered(worldIn, pos, state); boolean shouldBack = this.shouldBePowered(worldIn, pos, state);
boolean side = state.get(POWERED_SIDE); 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; BlockState stateIn = state;
if (back != shouldBack) { if (back != shouldBack) {

View file

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

View file

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

View file

@ -310,7 +310,7 @@
"create.generic.unit.ticks": "Ticks", "create.generic.unit.ticks": "Ticks",
"create.generic.unit.seconds": "Seconds", "create.generic.unit.seconds": "Seconds",
"create.generic.unit.minutes": "Minutes", "create.generic.unit.minutes": "Minutes",
"create.generic.unit.rpm": "rpm", "create.generic.unit.rpm": "RPM",
"create.generic.unit.stress": "su", "create.generic.unit.stress": "su",
"create.generic.unit.degrees": "°", "create.generic.unit.degrees": "°",
@ -607,6 +607,9 @@
"create.tooltip.capacityProvided.medium": "Medium", "create.tooltip.capacityProvided.medium": "Medium",
"create.tooltip.capacityProvided.high": "Large", "create.tooltip.capacityProvided.high": "Large",
"create.tooltip.capacityProvided.asGenerator": "(As Generator)", "create.tooltip.capacityProvided.asGenerator": "(As Generator)",
"create.tooltip.generationSpeed" : "Generates at %1$s %2$s",
"create.tooltip.analogStrength": "Analog Strength: %1$s/15",
"create.tooltip.wip": "WIP", "create.tooltip.wip": "WIP",
"create.tooltip.workInProgress": "Work in progress!", "create.tooltip.workInProgress": "Work in progress!",

View file

@ -0,0 +1,16 @@
{
"replace": false,
"values": [
"create:limestone",
"create:polished_limestone",
"create:weathered_limestone",
"create:polished_weathered_limestone",
"create:gabbro",
"create:polished_gabbro",
"create:dolomite",
"create:polished_dolomite",
"create:scoria",
"create:polished_scoria"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"#forge:storage_blocks/copper"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"create:copper_block"
]
}

View file

@ -0,0 +1,16 @@
{
"replace": false,
"values": [
"create:limestone",
"create:polished_limestone",
"create:weathered_limestone",
"create:polished_weathered_limestone",
"create:gabbro",
"create:polished_gabbro",
"create:dolomite",
"create:polished_dolomite",
"create:scoria",
"create:polished_scoria"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"#forge:storage_blocks/copper"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"create:copper_block"
]
}

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.