Finite Energy

- Added a torque system with stress vs capacity scores for networks.
- Added config values for stress and capacity
- Added rainbow debug (tm)
- Added infinite new bugs
This commit is contained in:
simibubi 2019-11-07 11:30:29 +01:00
parent 5655fa0609
commit 6f185d4540
39 changed files with 1016 additions and 393 deletions

View file

@ -5,6 +5,8 @@ import java.util.function.Supplier;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipeSerializer;
import com.simibubi.create.modules.contraptions.receivers.CrushingRecipe;
import com.simibubi.create.modules.contraptions.receivers.CuttingRecipe;
import com.simibubi.create.modules.contraptions.receivers.MixingRecipe;
import com.simibubi.create.modules.contraptions.receivers.PressingRecipe;
import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe;
import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunUpgradeRecipe;
@ -23,6 +25,8 @@ public enum AllRecipes {
CRUSHING(() -> new ProcessingRecipeSerializer<>(CrushingRecipe::new), Types.CRUSHING),
SPLASHING(() -> new ProcessingRecipeSerializer<>(SplashingRecipe::new), Types.SPLASHING),
PRESSING(() -> new ProcessingRecipeSerializer<>(PressingRecipe::new), Types.PRESSING),
CUTTING(() -> new ProcessingRecipeSerializer<>(CuttingRecipe::new), Types.CUTTING),
MIXING(() -> new ProcessingRecipeSerializer<>(MixingRecipe::new), Types.MIXING),
;
@ -30,6 +34,8 @@ public enum AllRecipes {
public static IRecipeType<CrushingRecipe> CRUSHING = register("crushing");
public static IRecipeType<SplashingRecipe> SPLASHING = register("splashing");
public static IRecipeType<PressingRecipe> PRESSING = register("pressing");
public static IRecipeType<CuttingRecipe> CUTTING = register("cutting");
public static IRecipeType<MixingRecipe> MIXING = register("mixing");
static <T extends IRecipe<?>> IRecipeType<T> register(final String key) {
return Registry.register(Registry.RECIPE_TYPE, new ResourceLocation(key), new IRecipeType<T>() {

View file

@ -7,6 +7,8 @@ import com.simibubi.create.foundation.block.IBlockWithScrollableValue;
import com.simibubi.create.foundation.gui.ScreenOpener;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.TooltipHelper;
import com.simibubi.create.modules.contraptions.KineticDebugger;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.receivers.TurntableHandler;
import com.simibubi.create.modules.contraptions.relays.belt.BeltItemHandler;
@ -43,6 +45,11 @@ public class ClientEvents {
if (!isGameActive())
return;
if (!KineticDebugger.isActive() && KineticTileEntityRenderer.rainbowMode) {
KineticTileEntityRenderer.rainbowMode = false;
KineticTileEntityRenderer.invalidateCache();
}
ScreenOpener.tick();
onGameTick();
}
@ -57,6 +64,7 @@ public class ClientEvents {
CreateClient.schematicHandler.render();
CreateClient.schematicAndQuillHandler.render();
CreateClient.schematicHologram.render();
KineticDebugger.renderSourceOutline();
}
@SubscribeEvent
@ -69,6 +77,7 @@ public class ClientEvents {
public static void onRenderHotbar() {
CreateClient.schematicHandler.renderOverlay();
KineticDebugger.renderOverlayText();
}
@SubscribeEvent

View file

@ -112,9 +112,7 @@ public class Create {
@SubscribeEvent
public static void createConfigs(ModConfig.ModConfigEvent event) {
if (event.getConfig().getSpec() == CreateClientConfig.specification)
return;
if (event.getConfig().getSpec() == CreateConfig.specification)
config = event.getConfig();
}

View file

@ -2,9 +2,13 @@ package com.simibubi.create;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.modules.contraptions.base.KineticBlock;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.Builder;
@ -56,6 +60,12 @@ public class CreateConfig {
inWorldProcessingTime;
public IntValue maxChassisForTranslation, maxChassisForRotation, maxChassisRange, maxPistonPoles;
public DoubleValue waterWheelCapacity;
public DoubleValue generatingFanCapacity;
public DoubleValue mechanicalBearingCapacity;
public DoubleValue motorCapacity;
public Map<String, DoubleValue> stressEntries = new HashMap<>();
// Logistics
public IntValue extractorDelay, extractorAmount, linkRange;
@ -136,7 +146,7 @@ public class CreateConfig {
name = "cocoaLogGrowthSpeed";
cocoaLogGrowthSpeed = builder.comment("", "% of random Ticks causing a Cocoa log to grow.")
.translation(basePath + name).defineInRange(name, 0D, 20D, 100D);
.translation(basePath + name).defineInRange(name, 20D, 0D, 100D);
builder.pop();
}
@ -231,6 +241,8 @@ public class CreateConfig {
maxPistonPoles = builder.comment("", "Maximum amount of extension poles behind a Mechanical Piston.")
.translation(basePath + name).defineInRange(name, 64, 1, Integer.MAX_VALUE);
initStress(builder);
builder.pop();
}
@ -256,7 +268,8 @@ public class CreateConfig {
.translation(basePath + name).defineInRange(name, 50, 10, Integer.MAX_VALUE);
name = "allowGlassPanesInPartialBlocks";
allowGlassPanesInPartialBlocks = builder.comment("", "Allow Glass Panes to be put inside Blocks like Stairs, Slabs, Fences etc.")
allowGlassPanesInPartialBlocks = builder
.comment("", "Allow Glass Panes to be put inside Blocks like Stairs, Slabs, Fences etc.")
.translation(basePath + name).define(name, true);
builder.pop();
@ -318,6 +331,83 @@ public class CreateConfig {
builder.pop();
}
private void initStress(final ForgeConfigSpec.Builder builder) {
builder.comment(
"Configure the individual stress impact of mechanical blocks. Note that this cost is doubled for every speed increase it receives.")
.push("stress");
for (AllBlocks block : AllBlocks.values()) {
if (block.get() instanceof KineticBlock)
initStressEntry(block, builder);
}
builder.pop();
builder.comment("Configure how much stress a source can accommodate.").push("capacity");
String basePath = "create.config.capacity.";
String name = "";
name = "waterWheelCapacity";
waterWheelCapacity = builder.comment("").translation(basePath + name).defineInRange(name, 32D, 0D, 4096D);
name = "generatingFanCapacity";
generatingFanCapacity = builder.comment("").translation(basePath + name).defineInRange(name, 64D, 0D, 4096D);
name = "mechanicalBearingCapacity";
mechanicalBearingCapacity = builder.comment("").translation(basePath + name).defineInRange(name, 256D, 0D,
4096D);
name = "motorCapacity";
motorCapacity = builder.comment("").translation(basePath + name).defineInRange(name, 1024D, 0D, 4096D);
builder.pop();
}
private void initStressEntry(AllBlocks block, final ForgeConfigSpec.Builder builder) {
String basePath = "create.config.stress.";
String name = block.name();
stressEntries.put(block.get().getRegistryName().getPath(), builder.comment("").translation(basePath + name)
.defineInRange(name, getDefaultStressImpact(block), 0, 2048));
}
public static double getDefaultStressImpact(AllBlocks block) {
switch (block) {
case CRUSHING_WHEEL:
case MECHANICAL_PRESS:
case MOTOR:
return 32;
case DRILL:
case SAW:
case MECHANICAL_PISTON:
case STICKY_MECHANICAL_PISTON:
return 16;
case ENCASED_FAN:
case MECHANICAL_MIXER:
case MECHANICAL_BEARING:
return 8;
case WATER_WHEEL:
case TURNTABLE:
case GEARBOX:
case GEARSHIFT:
case LARGE_COGWHEEL:
return 4;
case CLUTCH:
return 2;
case BELT:
case COGWHEEL:
case ENCASED_BELT:
case ENCASED_SHAFT:
case SHAFT:
default:
return 1;
}
}
private boolean isValidPath(Object path) {
if (!(path instanceof String))
return false;

View file

@ -122,4 +122,24 @@ public abstract class BufferManipulator {
return buffer;
}
public static ByteBuffer recolorBuffer(ByteBuffer buffer, int color) {
buffer.rewind();
boolean defaultColor = color == -1;
int b = defaultColor ? 128 : color & 0xFF;
int g = defaultColor ? 128 : (color >> 8) & 0xFF;
int r = defaultColor ? 128 : (color >> 16) & 0xFF;
for (int vertex = 0; vertex < vertexCount(buffer); vertex++) {
float lum = 1;
int r2 = (int) (r * lum);
int g2 = (int) (g * lum);
int b2 = (int) (b * lum);
putColor(buffer, vertex, (byte) r2, (byte) g2, (byte) b2, (byte) 255);
}
return buffer;
}
}

View file

@ -0,0 +1,47 @@
package com.simibubi.create.foundation.utility;
import net.minecraft.client.Minecraft;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.common.thread.EffectiveSide;
/** Deprecated so simi doensn't forget to remove debug calls **/
@OnlyIn(value = Dist.CLIENT)
@Deprecated
public class Debug {
public static void debugChat(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), false);
}
public static void debugChatAndShowStack(String message, int depth) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player
.sendStatusMessage(new StringTextComponent(message + " @" + debugStack(depth)), false);
}
public static void debugMessage(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), true);
}
public static String getLogicalSide() {
return EffectiveSide.get().isClient() ? "CL" : "SV";
}
public static String debugStack(int depth) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
String text = "[" + TextFormatting.GOLD + getLogicalSide() + TextFormatting.WHITE + "] ";
for (int i = 1; i < depth + 2 && i < stackTraceElements.length; i++) {
StackTraceElement e = stackTraceElements[i];
if (e.getClassName().equals(Debug.class.getName()))
continue;
text = text + TextFormatting.YELLOW + e.getMethodName() + TextFormatting.WHITE + ", ";
}
return text + TextFormatting.GRAY + " ...";
}
}

View file

@ -6,12 +6,8 @@ import java.util.Locale;
import com.simibubi.create.Create;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class Lang {
@ -27,21 +23,6 @@ public class Lang {
player.sendStatusMessage(getTranslationComponent(key, args), true);
}
// Deprecated so simi doensn't forget to remove debug calls
@OnlyIn(value = Dist.CLIENT)
@Deprecated
public static void debugChat(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), false);
}
@OnlyIn(value = Dist.CLIENT)
@Deprecated
public static void debugMessage(String message) {
if (Minecraft.getInstance().player != null)
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), true);
}
public static List<String> translatedOptions(String prefix, String... keys) {
List<String> result = new ArrayList<>(keys.length);
for (String key : keys) {

View file

@ -0,0 +1,141 @@
package com.simibubi.create.foundation.utility;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.google.common.base.Predicates;
import net.minecraft.block.BlockState;
import net.minecraft.block.LeavesBlock;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
public class TreeCutter {
public static class Tree {
public List<BlockPos> logs;
public List<BlockPos> leaves;
public Tree(List<BlockPos> logs, List<BlockPos> leaves) {
this.logs = logs;
this.leaves = leaves;
}
}
/**
* Finds a tree at the given pos. Block at the position should be air
*
* @param reader
* @param pos
* @return null if not found or not fully cut
*/
public static Tree cutTree(IBlockReader reader, BlockPos pos) {
List<BlockPos> logs = new ArrayList<>();
List<BlockPos> leaves = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
List<BlockPos> frontier = new LinkedList<>();
if (!validateCut(reader, pos))
return null;
visited.add(pos);
addNeighbours(pos, frontier, visited);
// Find all logs
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
visited.add(currentPos);
if (!isLog(reader.getBlockState(currentPos)))
continue;
logs.add(currentPos);
addNeighbours(currentPos, frontier, visited);
}
// Find all leaves
visited.clear();
visited.addAll(logs);
frontier.addAll(logs);
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
visited.add(currentPos);
BlockState blockState = reader.getBlockState(currentPos);
boolean isLog = !isLog(blockState);
boolean isLeaf = !isLeaf(blockState);
if (!isLog && !isLeaf)
continue;
if (isLeaf)
leaves.add(currentPos);
int distance = isLog ? 0 : blockState.get(LeavesBlock.DISTANCE);
for (Direction direction : Direction.values()) {
BlockPos offset = currentPos.offset(direction);
if (visited.contains(offset))
continue;
BlockState state = reader.getBlockState(offset);
if (isLeaf(state) && state.get(LeavesBlock.DISTANCE) > distance)
frontier.add(offset);
}
}
return new Tree(logs, leaves);
}
/**
* Checks whether a tree was fully cut by seeing whether the layer above the cut
* is not supported by any more logs.
*
* @param reader
* @param pos
* @return
*/
private static boolean validateCut(IBlockReader reader, BlockPos pos) {
Set<BlockPos> visited = new HashSet<>();
List<BlockPos> frontier = new LinkedList<>();
frontier.add(pos.up());
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
visited.add(currentPos);
if (!isLog(reader.getBlockState(currentPos)))
continue;
if (isLog(reader.getBlockState(currentPos.down())))
return false;
for (Direction direction : Direction.values()) {
if (direction.getAxis().isVertical())
continue;
BlockPos offset = currentPos.offset(direction);
if (visited.contains(offset))
continue;
frontier.add(offset);
}
}
return true;
}
private static void addNeighbours(BlockPos pos, List<BlockPos> frontier, Set<BlockPos> visited) {
BlockPos.getAllInBox(pos.add(-1, -1, -1), pos.add(1, 1, 1)).filter(Predicates.not(visited::contains))
.forEach(frontier::add);
}
private static boolean isLog(BlockState state) {
return state.isIn(BlockTags.LOGS);
}
private static boolean isLeaf(BlockState state) {
return state.has(LeavesBlock.DISTANCE);
}
}

View file

@ -0,0 +1,85 @@
package com.simibubi.create.modules.contraptions;
import java.util.ArrayList;
import java.util.List;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.world.ClientWorld;
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.world.World;
public class KineticDebugger {
public static void renderSourceOutline() {
if (!isActive())
return;
KineticTileEntity te = getSelectedTE();
if (te == null)
return;
World world = Minecraft.getInstance().world;
BlockPos toOutline = te.hasSource() ? te.getSource() : te.getPos();
VoxelShape shape = world.getBlockState(toOutline).getShape(world, toOutline);
TessellatorHelper.prepareForDrawing();
GlStateManager.disableTexture();
GlStateManager.lineWidth(2);
WorldRenderer.drawShape(shape, toOutline.getX(), toOutline.getY(), toOutline.getZ(), te.hasSource() ? .5f : 1,
.75f, .75f, 1);
GlStateManager.lineWidth(1);
GlStateManager.enableTexture();
TessellatorHelper.cleanUpAfterDrawing();
}
public static void renderOverlayText() {
if (!isActive())
return;
KineticTileEntity te = getSelectedTE();
if (te == null)
return;
List<String> info = new ArrayList<>();
te.addDebugInformation(info);
Minecraft mc = Minecraft.getInstance();
int x = mc.mainWindow.getScaledWidth() / 2 - 25;
int y = mc.mainWindow.getScaledHeight() / 2 + 25;
for (String text : info) {
mc.fontRenderer.drawStringWithShadow(text, x, y, 0xFFFFFF);
y += 10;
}
}
public static boolean isActive() {
return Minecraft.getInstance().gameSettings.showDebugInfo;
}
public static KineticTileEntity getSelectedTE() {
RayTraceResult obj = Minecraft.getInstance().objectMouseOver;
ClientWorld world = Minecraft.getInstance().world;
if (obj == null)
return null;
if (world == null)
return null;
if (!(obj instanceof BlockRayTraceResult))
return null;
BlockRayTraceResult ray = (BlockRayTraceResult) obj;
TileEntity te = world.getTileEntity(ray.getPos());
if (te == null || !(te instanceof KineticTileEntity))
return null;
return (KineticTileEntity) te;
}
}

View file

@ -1,118 +1,127 @@
package com.simibubi.create.modules.contraptions;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
public class KineticNetwork {
public UUID id;
private float stressCapacityPool;
private float maxStress;
private float currentStress;
public boolean initialized;
private float maxStress;
private float currentStress;
private float unloadedStressCapacity;
private float unloadedStress;
public Map<KineticTileEntity, Float> sources;
public Set<KineticTileEntity> members;
public Map<KineticTileEntity, Float> members;
public KineticNetwork() {
id = UUID.randomUUID();
maxStress = stressCapacityPool = 0;
setCurrentStress(0);
sources = new HashMap<>();
members = new HashSet<>();
members = new HashMap<>();
}
public void initFromTE(KineticTileEntity te) {
maxStress = stressCapacityPool = te.maxStress;
currentStress = te.currentStress;
unloadedStressCapacity = te.maxStress;
unloadedStress = te.currentStress;
initialized = true;
addSilently(te);
updateStress();
updateStressCapacity();
}
public void addSilently(KineticTileEntity te) {
if (members.contains(te))
if (members.containsKey(te))
return;
if (te.isSource()) {
float capacity = te.getAddedStressCapacity();
stressCapacityPool -= capacity;
unloadedStressCapacity -= capacity;
sources.put(te, capacity);
}
members.add(te);
float stressApplied = te.getStressApplied();
unloadedStress -= stressApplied;
members.put(te, stressApplied);
}
public void add(KineticTileEntity te) {
if (members.contains(te))
if (members.containsKey(te))
return;
Lang.debugChat(te.getType().getRegistryName().getPath() + " added to Network");
te.setNetworkID(this.id);
// Debug.debugChatAndShowStack(te.getType().getRegistryName().getPath() + " added to Network", 5);
if (te.isSource()) {
float capacity = te.getAddedStressCapacity();
sources.put(te, capacity);
updateMaxStress();
sources.put(te, te.getAddedStressCapacity());
updateStressCapacity();
}
members.add(te);
setCurrentStress(getCurrentStress() + te.getStressApplied());
members.put(te, te.getStressApplied());
updateStress();
sync();
}
public void updateCapacityFor(KineticTileEntity te, float capacity) {
sources.put(te, capacity);
updateMaxStress();
updateStressCapacity();
}
public void updateStressFor(KineticTileEntity te, float stress) {
members.put(te, stress);
updateStress();
}
public void remove(KineticTileEntity te) {
if (!members.contains(te))
if (!members.containsKey(te))
return;
Lang.debugChat(te.getType().getRegistryName().getPath() + " removed from Network");
// Debug.debugChat(te.getType().getRegistryName().getPath() + " removed from Network");
if (te.isSource()) {
sources.remove(te);
updateMaxStress();
updateStressCapacity();
}
members.remove(te);
setCurrentStress(getCurrentStress() - te.getStressApplied());
updateStress();
sync();
}
public void sync() {
for (KineticTileEntity te : members) {
te.sync(id, getMaxStress(), getCurrentStress());
for (KineticTileEntity te : members.keySet()) {
te.sync(maxStress, currentStress);
}
}
public float getMaxStress() {
return maxStress;
}
private void updateMaxStress() {
public void updateStressCapacity() {
float presentCapacity = 0;
for (Float cap : sources.values())
presentCapacity += cap;
float newMaxStress = presentCapacity + stressCapacityPool;
for (KineticTileEntity te : sources.keySet())
presentCapacity += sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
float newMaxStress = presentCapacity + unloadedStressCapacity;
if (maxStress != newMaxStress) {
maxStress = newMaxStress;
sync();
}
Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress);
}
public float getCurrentStress() {
return currentStress;
}
public void setCurrentStress(float currentStress) {
this.currentStress = currentStress;
Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress);
// Debug.debugChatAndShowStack("Current Stress level: " + currentStress + "/" + maxStress, 5);
}
}
public void updateStress() {
float presentStress = 0;
for (KineticTileEntity te : members.keySet())
presentStress += members.get(te) * getStressMultiplierForSpeed(te.speed);
float newStress = presentStress + unloadedStress;
if (currentStress != newStress) {
currentStress = newStress;
sync();
// Debug.debugChatAndShowStack("Current Stress level: " + currentStress + "/" + maxStress, 5);
}
}
private float getStressMultiplierForSpeed(float speed) {
return Math.abs(speed);
}
}

View file

@ -223,13 +223,6 @@ public class RotationPropagator {
return;
}
boolean isSource = neighbourTE.isSource();
boolean hasSource = neighbourTE.hasSource();
boolean poweredBySomethingElse = isSource
|| hasSource && !neighbourTE.getSource().equals(updateTE.getPos());
if (poweredBySomethingElse) {
if (neighbourTE.speed != newSpeed) {
if (incompatible) {
// Opposite directions
world.destroyBlock(pos, true);
@ -243,10 +236,13 @@ public class RotationPropagator {
updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE));
updateTE.onSpeedChanged();
updateTE.sendData();
propagateNewSource(updateTE);
return;
}
if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed)) {
if (Math.abs(newSpeed) >= Math.abs(neighbourTE.speed)) {
if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed) || updateTE.newNetworkID != null
&& !updateTE.newNetworkID.equals(neighbourTE.newNetworkID)) {
// Current faster, overpower the neighbours' tree
if (updateTE.hasSource() && updateTE.getSource().equals(neighbourTE.getPos())) {
@ -258,12 +254,10 @@ public class RotationPropagator {
neighbourTE.onSpeedChanged();
neighbourTE.sendData();
propagateNewSource(neighbourTE);
continue;
}
}
}
continue;
}
}
if (neighbourTE.speed == newSpeed)
continue;

View file

@ -7,8 +7,6 @@ import java.util.UUID;
import com.simibubi.create.Create;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.IWorld;
public class TorquePropagator {
@ -32,9 +30,10 @@ public class TorquePropagator {
if (id == null) {
network = new KineticNetwork();
//TODO
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(te.getType().getRegistryName().getPath() + " created new Network"), false);
// Debug.debugChatAndShowStack(te.getType().getRegistryName().getPath() + " created new Network", 5);
te.newNetworkID = network.id;
te.updateNetwork = true;
map.put(id, network);
} else {
if (!map.containsKey(id)) {

View file

@ -0,0 +1,71 @@
package com.simibubi.create.modules.contraptions.base;
import java.util.Optional;
import java.util.UUID;
import net.minecraft.tileentity.TileEntityType;
public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
public GeneratingKineticTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
}
protected void notifyStressCapacityChange(float capacity) {
getNetwork().updateCapacityFor(this, capacity);
}
@Override
public void reActivateSource() {
updateGeneratedRotation();
}
public void updateGeneratedRotation() {
float speed = getGeneratedSpeed();
if (this.speed != speed) {
if (speed == 0) {
if (hasSource())
notifyStressCapacityChange(0);
else {
detachKinetics();
setSpeed(speed);
newNetworkID = null;
updateNetwork = true;
}
} else if (this.speed == 0) {
setSpeed(speed);
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
} else {
if (hasSource()) {
if (Math.abs(this.speed) >= Math.abs(speed)) {
if (Math.signum(this.speed) == Math.signum(speed))
notifyStressCapacityChange(getAddedStressCapacity());
else
world.destroyBlock(pos, true);
} else {
detachKinetics();
setSpeed(speed);
source = Optional.empty();
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
}
} else {
detachKinetics();
setSpeed(speed);
attachKinetics();
}
}
}
if (hasNetwork() && speed != 0)
getNetwork().updateStressCapacity();
onSpeedChanged();
sendData();
}
}

View file

@ -62,6 +62,8 @@ public abstract class KineticBlock extends Block implements IRotate {
KineticTileEntity tileEntity = (KineticTileEntity) worldIn.getTileEntity(pos);
if (tileEntity == null)
return;
if (worldIn.isRemote())
return;
RotationPropagator.handleAdded(worldIn.getWorld(), pos, tileEntity);
}

View file

@ -1,12 +1,17 @@
package com.simibubi.create.modules.contraptions.base;
import static net.minecraft.util.text.TextFormatting.GREEN;
import static net.minecraft.util.text.TextFormatting.WHITE;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import com.simibubi.create.Create;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.foundation.block.SyncedTileEntity;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.KineticNetwork;
import com.simibubi.create.modules.contraptions.RotationPropagator;
@ -17,17 +22,23 @@ import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.ForgeConfigSpec.DoubleValue;
public abstract class KineticTileEntity extends SyncedTileEntity implements ITickableTileEntity {
// Speed related
public float speed;
protected Optional<BlockPos> source;
public boolean reActivateSource;
// Torque related
public float maxStress;
public float currentStress;
public UUID networkID;
protected boolean overStressed;
public UUID networkID;
public UUID newNetworkID;
public boolean updateNetwork;
protected boolean initNetwork;
public KineticTileEntity(TileEntityType<?> typeIn) {
@ -36,16 +47,13 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
source = Optional.empty();
}
public void sync(UUID networkID, float maxStress, float currentStress) {
this.setNetworkID(networkID);
public void sync(float maxStress, float currentStress) {
this.maxStress = maxStress;
this.currentStress = currentStress;
boolean overStressed = maxStress < currentStress;
if (overStressed != this.overStressed) {
Lang.debugChat(getType().getRegistryName().getPath() + " jammed (" + currentStress + "/" + maxStress + ")");
this.overStressed = overStressed;
onSpeedChanged();
sendData();
}
}
@ -55,17 +63,15 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
}
public float getStressApplied() {
return isSource() ? 0 : 1;
Map<String, DoubleValue> stressEntries = CreateConfig.parameters.stressEntries;
String path = getBlockState().getBlock().getRegistryName().getPath();
if (!stressEntries.containsKey(path))
return 1;
return stressEntries.get(path).get().floatValue();
}
protected void notifyStressChange(float diff) {
KineticNetwork network = getNetwork();
network.setCurrentStress(network.getCurrentStress() + diff);
network.sync();
}
protected void notifyStressCapacityChange(float capacity) {
getNetwork().updateCapacityFor(this, capacity);
protected void notifyStressChange(float stress) {
getNetwork().updateStressFor(this, stress);
}
@Override
@ -74,10 +80,6 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
}
public void onSpeedChanged() {
// if (isSource() && !world.isRemote) {
// if (networkID == null)
// getNetwork().add(this);
// }
}
@Override
@ -122,14 +124,18 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
currentStress = compound.getFloat("Stress");
overStressed = maxStress < currentStress;
setNetworkID(NBTUtil.readUniqueId(compound.getCompound("Id")));
newNetworkID = networkID;
initNetwork = true;
} else {
networkID = newNetworkID = null;
overStressed = false;
}
super.read(compound);
}
public boolean isSource() {
return false;
return getGeneratedSpeed() != 0;
}
public float getSpeed() {
@ -138,6 +144,10 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
return speed;
}
public float getGeneratedSpeed() {
return 0;
}
public void setSpeed(float speed) {
this.speed = speed;
if (hasWorld() && speed != 0 && world.isRemote) {
@ -169,16 +179,18 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
if (world == null || world.isRemote)
return;
if (hasNetwork()) {
getNetwork().remove(this);
networkID = null;
}
if (source == null)
return;
KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source);
if (sourceTe == null)
return;
Create.torquePropagator.getNetworkFor(sourceTe).add(this);
if (reActivateSource && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed())) {
reActivateSource = false;
}
newNetworkID = sourceTe.newNetworkID;
updateNetwork = true;
}
public void removeSource() {
@ -186,23 +198,14 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
reActivateSource = true;
this.source = Optional.empty();
if (hasNetwork() && !isSource()) {
getNetwork().remove(this);
networkID = null;
}
newNetworkID = null;
updateNetwork = true;
setSpeed(0);
onSpeedChanged();
}
public KineticNetwork getNetwork() {
KineticNetwork networkFor = Create.torquePropagator.getNetworkFor(this);
if (!networkFor.initialized) {
networkFor.add(this);
networkFor.initialized = true;
}
return networkFor;
return Create.torquePropagator.getNetworkFor(this);
}
public boolean hasNetwork() {
@ -241,20 +244,49 @@ public abstract class KineticTileEntity extends SyncedTileEntity implements ITic
@Override
public void tick() {
if (world.isRemote)
return;
if (initNetwork) {
initNetwork = false;
KineticNetwork network = getNetwork();
if (!network.initialized)
network.initFromTE(this);
network.addSilently(this);
}
if (updateNetwork) {
updateNetwork = false;
if (hasNetwork() && !networkID.equals(newNetworkID)) {
getNetwork().remove(this);
networkID = null;
maxStress = currentStress = 0;
overStressed = false;
}
if (newNetworkID != null) {
networkID = newNetworkID;
KineticNetwork network = getNetwork();
network.initialized = true;
network.add(this);
}
sendData();
}
if (reActivateSource) {
reActivateSource();
reActivateSource = false;
}
}
if (initNetwork) {
initNetwork = false;
KineticNetwork network = getNetwork();
if (network.initialized) {
network.addSilently(this);
} else {
network.initFromTE(this);
}
}
public void addDebugInformation(List<String> lines) {
lines.add("Speed: " + GREEN + speed);
lines.add("Cost: " + GREEN + getStressApplied() + WHITE + "/" + GREEN + getAddedStressCapacity());
lines.add("Stress: " + GREEN + currentStress + WHITE + "/" + GREEN + maxStress);
// lines.add("Network: " + (hasNetwork() ? networkID.toString() : "Missing"));
}
}

View file

@ -11,6 +11,8 @@ import org.lwjgl.opengl.GL11;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.BufferManipulator;
import com.simibubi.create.modules.contraptions.KineticDebugger;
import com.simibubi.create.modules.logistics.management.base.LogisticalActorTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
@ -19,6 +21,7 @@ import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
@ -32,6 +35,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTileEntity> {
protected static Map<BlockState, BufferManipulator> cachedBuffers;
public static boolean rainbowMode = false;
protected static class BlockModelSpinner extends BufferManipulator {
@ -84,8 +88,19 @@ public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTil
protected static void renderFromCache(BufferBuilder buffer, BlockState state, World world, float x, float y,
float z, BlockPos pos, Axis axis, float angle) {
int packedLightmapCoords = state.getPackedLightmapCoords(world, pos);
buffer.putBulkData(((BlockModelSpinner) getBuffer(state)).getTransformed(x, y, z, angle, axis,
packedLightmapCoords));
ByteBuffer transformed = ((BlockModelSpinner) getBuffer(state)).getTransformed(x, y, z, angle, axis,
packedLightmapCoords);
if (KineticDebugger.isActive()) {
rainbowMode = true;
TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity instanceof KineticTileEntity && ((KineticTileEntity) tileEntity).hasNetwork()) {
int color = LogisticalActorTileEntity.colorFromUUID(((KineticTileEntity) tileEntity).getNetworkID());
BufferManipulator.recolorBuffer(transformed, color);
}
}
buffer.putBulkData(transformed);
}
public static BufferManipulator getBuffer(BlockState state) {

View file

@ -1,7 +1,6 @@
package com.simibubi.create.modules.contraptions.generators;
import com.simibubi.create.foundation.packet.TileEntityConfigurationPacket;
import com.simibubi.create.modules.contraptions.RotationPropagator;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
@ -31,10 +30,8 @@ public class ConfigureMotorPacket extends TileEntityConfigurationPacket<MotorTil
@Override
protected void applySettings(MotorTileEntity te) {
RotationPropagator.handleRemoved(te.getWorld(), te.getPos(), te);
te.setSpeed(speed);
te.sendData();
RotationPropagator.handleAdded(te.getWorld(), te.getPos(), te);
te.generatedSpeed = speed;
te.updateGeneratedRotation();
}
}

View file

@ -71,13 +71,13 @@ public class MotorBlock extends HorizontalKineticBlock
MotorTileEntity tileEntity = (MotorTileEntity) world.getTileEntity(pos);
if (tileEntity == null)
return 0;
return tileEntity.getSpeedValue();
return tileEntity.newGeneratedSpeed;
}
@Override
public void onScroll(BlockState state, IWorld world, BlockPos pos, double delta) {
withTileEntityDo(world, pos, te -> te
.setSpeedValueLazily((int) (te.getSpeedValue() * (delta > 0 ^ te.getSpeedValue() < 0 ? 2 : .5f))));
.setSpeedValueLazily((int) (te.newGeneratedSpeed * (delta > 0 ^ te.newGeneratedSpeed < 0 ? 2 : .5f))));
}
@Override

View file

@ -1,27 +1,38 @@
package com.simibubi.create.modules.contraptions.generators;
import java.util.UUID;
import com.simibubi.create.AllPackets;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.MathHelper;
public class MotorTileEntity extends KineticTileEntity {
public class MotorTileEntity extends GeneratingKineticTileEntity {
public static final int DEFAULT_SPEED = 64;
public int newSpeed;
public int newGeneratedSpeed;
public int generatedSpeed;
public int lastModified;
public MotorTileEntity() {
super(AllTileEntities.MOTOR.type);
setSpeed(DEFAULT_SPEED);
speed = generatedSpeed = newGeneratedSpeed = DEFAULT_SPEED;
updateNetwork = true;
newNetworkID = UUID.randomUUID();
lastModified = -1;
}
@Override
public float getGeneratedSpeed() {
return generatedSpeed;
}
@Override
public float getAddedStressCapacity() {
return 500;
return CreateConfig.parameters.motorCapacity.get().floatValue();
}
@Override
@ -30,39 +41,29 @@ public class MotorTileEntity extends KineticTileEntity {
}
@Override
public boolean isSource() {
return true;
public CompoundNBT write(CompoundNBT compound) {
compound.putInt("GeneratedSpeed", generatedSpeed);
return super.write(compound);
}
@Override
public void setSpeed(float speed) {
super.setSpeed(speed);
newSpeed = (int) speed;
}
@Override
public void removeSource() {
float speed = this.speed;
super.removeSource();
setSpeed(speed);
}
public int getSpeedValue() {
if (world.isRemote)
return newSpeed;
return (int) speed;
public void read(CompoundNBT compound) {
generatedSpeed = compound.getInt("GeneratedSpeed");
if (lastModified == -1)
newGeneratedSpeed = generatedSpeed;
super.read(compound);
}
public void setSpeedValueLazily(int speed) {
if (newSpeed == speed)
if (newGeneratedSpeed == speed)
return;
Integer max = CreateConfig.parameters.maxMotorSpeed.get();
if (newSpeed > 0 && speed == 0)
newSpeed = -1;
else if (newSpeed < 0 && speed == 0)
newSpeed = 1;
if (newGeneratedSpeed > 0 && speed == 0)
newGeneratedSpeed = -1;
else if (newGeneratedSpeed < 0 && speed == 0)
newGeneratedSpeed = 1;
else
newSpeed = MathHelper.clamp(speed, -max, max);
newGeneratedSpeed = MathHelper.clamp(speed, -max, max);
this.lastModified = 0;
}
@ -76,7 +77,7 @@ public class MotorTileEntity extends KineticTileEntity {
return;
if (lastModified++ > 10) {
lastModified = -1;
AllPackets.channel.sendToServer(new ConfigureMotorPacket(pos, newSpeed));
AllPackets.channel.sendToServer(new ConfigureMotorPacket(pos, newGeneratedSpeed));
}
}

View file

@ -108,7 +108,7 @@ public class WaterWheelBlock extends HorizontalKineticBlock {
WaterWheelTileEntity te = (WaterWheelTileEntity) world.getTileEntity(pos);
if (te == null)
return;
te.updateSpeed();
te.updateGeneratedRotation();
}
@Override

View file

@ -2,20 +2,18 @@ package com.simibubi.create.modules.contraptions.generators;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.RotationPropagator;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
public class WaterWheelTileEntity extends KineticTileEntity {
public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
private Map<Direction, Integer> flows;
private boolean hasFlows;
public WaterWheelTileEntity() {
super(AllTileEntities.WATER_WHEEL.type);
@ -55,39 +53,16 @@ public class WaterWheelTileEntity extends KineticTileEntity {
}
@Override
public void reActivateSource() {
updateSpeed();
}
public void updateSpeed() {
public float getGeneratedSpeed() {
float speed = 0;
for (Integer i : flows.values())
speed += i;
if (this.speed != speed) {
hasFlows = speed != 0;
notifyStressCapacityChange(getAddedStressCapacity());
source = Optional.empty();
RotationPropagator.handleRemoved(world, pos, this);
this.setSpeed(speed);
sendData();
RotationPropagator.handleAdded(world, pos, this);
}
onSpeedChanged();
}
@Override
public boolean isSource() {
return hasFlows;
return speed;
}
@Override
public float getAddedStressCapacity() {
float torque = 0;
for (Integer i : flows.values())
torque += i;
return Math.abs(torque);
return CreateConfig.parameters.waterWheelCapacity.get().floatValue();
}
}

View file

@ -14,6 +14,7 @@ import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.items.wrapper.RecipeWrapper;
public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEntity {
@ -26,6 +27,12 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
}
};
public class BasinInputInventory extends RecipeWrapper {
public BasinInputInventory() {
super(inputInventory);
}
}
protected ItemStackHandler inputInventory = new ItemStackHandler(9) {
protected void onContentsChanged(int slot) {
updateProcessing = true;
@ -69,10 +76,12 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
protected LazyOptional<IItemHandlerModifiable> inventory = LazyOptional
.of(() -> new BasinInventory(inputInventory, outputInventory));
public BasinInputInventory recipeInventory;
public BasinTileEntity() {
super(AllTileEntities.BASIN.type);
updateProcessing = true;
recipeInventory = new BasinInputInventory();
}
@Override

View file

@ -5,13 +5,12 @@ import java.util.List;
import com.simibubi.create.AllRecipes;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipe;
import com.simibubi.create.modules.contraptions.base.StochasticOutput;
import com.simibubi.create.modules.contraptions.receivers.CrushingWheelControllerTileEntity.Inventory;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
public class CrushingRecipe extends ProcessingRecipe<CrushingWheelControllerTileEntity.Inventory> {
public class CrushingRecipe extends ProcessingRecipe<ProcessingInventory> {
public CrushingRecipe(ResourceLocation id, String group, List<Ingredient> ingredients,
List<StochasticOutput> results, int processingDuration) {
@ -19,7 +18,7 @@ public class CrushingRecipe extends ProcessingRecipe<CrushingWheelControllerTile
}
@Override
public boolean matches(Inventory inv, World worldIn) {
public boolean matches(ProcessingInventory inv, World worldIn) {
if (inv.isEmpty())
return false;
return ingredients.get(0).test(inv.getStackInSlot(0));

View file

@ -10,6 +10,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
@ -39,6 +40,11 @@ public class CrushingWheelControllerBlock extends Block implements IWithoutBlock
return true;
}
@Override
public boolean isReplaceable(BlockState state, BlockItemUseContext useContext) {
return false;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new CrushingWheelControllerTileEntity();

View file

@ -12,7 +12,6 @@ import com.simibubi.create.foundation.block.SyncedTileEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
@ -23,59 +22,11 @@ import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.RecipeWrapper;
public class CrushingWheelControllerTileEntity extends SyncedTileEntity implements ITickableTileEntity {
public static class Inventory extends RecipeWrapper {
protected int processingDuration;
protected boolean appliedRecipe;
public Inventory() {
super(new ItemStackHandler(10));
}
@Override
public void clear() {
super.clear();
processingDuration = 0;
appliedRecipe = false;
}
public void write(CompoundNBT nbt) {
NonNullList<ItemStack> stacks = NonNullList.create();
for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stack = inv.getStackInSlot(slot);
stacks.add(stack);
}
ItemStackHelper.saveAllItems(nbt, stacks);
nbt.putInt("ProcessingTime", processingDuration);
nbt.putBoolean("AppliedRecipe", appliedRecipe);
}
public static Inventory read(CompoundNBT nbt) {
Inventory inventory = new Inventory();
NonNullList<ItemStack> stacks = NonNullList.withSize(10, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks);
for (int slot = 0; slot < stacks.size(); slot++)
inventory.setInventorySlotContents(slot, stacks.get(slot));
inventory.processingDuration = nbt.getInt("ProcessingTime");
inventory.appliedRecipe = nbt.getBoolean("AppliedRecipe");
return inventory;
}
public ItemStackHandler getItems() {
return (ItemStackHandler) inv;
}
}
private static DamageSource damageSource = new DamageSource("create.crush").setDamageBypassesArmor()
.setDifficultyScaled();
@ -83,12 +34,12 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
private UUID entityUUID;
protected boolean searchForEntity;
private Inventory contents;
private ProcessingInventory contents;
public float crushingspeed;
public CrushingWheelControllerTileEntity() {
super(AllTileEntities.CRUSHING_WHEEL_CONTROLLER.type);
contents = new Inventory();
contents = new ProcessingInventory();
}
@Override
@ -236,7 +187,7 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
this.searchForEntity = true;
}
crushingspeed = compound.getFloat("Speed");
contents = Inventory.read(compound);
contents = ProcessingInventory.read(compound);
}

View file

@ -0,0 +1,27 @@
package com.simibubi.create.modules.contraptions.receivers;
import java.util.List;
import com.simibubi.create.AllRecipes;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipe;
import com.simibubi.create.modules.contraptions.base.StochasticOutput;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
public class CuttingRecipe extends ProcessingRecipe<ProcessingInventory> {
public CuttingRecipe(ResourceLocation id, String group, List<Ingredient> ingredients,
List<StochasticOutput> results, int processingDuration) {
super(AllRecipes.CUTTING, id, group, ingredients, results, processingDuration);
}
@Override
public boolean matches(ProcessingInventory inv, World worldIn) {
if (inv.isEmpty())
return false;
return ingredients.get(0).test(inv.getStackInSlot(0));
}
}

View file

@ -76,7 +76,7 @@ public class DrillTileEntity extends KineticTileEntity {
if (world.isRemote)
return;
if (speed == 0)
if (getSpeed() == 0)
return;
BlockPos posToBreak = pos.offset(getBlockState().get(BlockStateProperties.FACING));

View file

@ -6,7 +6,6 @@ import static net.minecraft.util.Direction.AxisDirection.NEGATIVE;
import static net.minecraft.util.Direction.AxisDirection.POSITIVE;
import java.util.List;
import java.util.Optional;
import com.simibubi.create.AllBlockTags;
import com.simibubi.create.AllBlocks;
@ -14,7 +13,7 @@ import com.simibubi.create.AllTileEntities;
import com.simibubi.create.CreateClient;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import com.simibubi.create.modules.logistics.InWorldProcessing;
import com.simibubi.create.modules.logistics.InWorldProcessing.Type;
@ -35,7 +34,7 @@ import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
public class EncasedFanTileEntity extends KineticTileEntity {
public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled()
.setFireDamage();
@ -87,13 +86,13 @@ public class EncasedFanTileEntity extends KineticTileEntity {
}
@Override
public boolean isSource() {
return isGenerator;
public float getAddedStressCapacity() {
return isGenerator ? CreateConfig.parameters.generatingFanCapacity.get().floatValue() : 0;
}
@Override
public float getAddedStressCapacity() {
return 50;
public float getGeneratedSpeed() {
return isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0;
}
public void updateGenerator() {
@ -102,14 +101,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
return;
isGenerator = shouldGenerate;
if (isGenerator) {
notifyStressCapacityChange(getAddedStressCapacity());
removeSource();
} else {
notifyStressCapacityChange(0);
}
applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0);
sendData();
updateGeneratedRotation();
}
public boolean blockBelowIsHot() {
@ -122,7 +114,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
if (world.isRemote)
return;
float speed = Math.abs(this.speed);
float speed = Math.abs(this.getSpeed());
float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1);
pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get());
@ -180,9 +172,9 @@ public class EncasedFanTileEntity extends KineticTileEntity {
}
public Direction getAirFlow() {
if (speed == 0)
if (getSpeed() == 0)
return null;
return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), speed > 0 ? POSITIVE : NEGATIVE);
return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), getSpeed() > 0 ? POSITIVE : NEGATIVE);
}
@Override
@ -191,17 +183,11 @@ public class EncasedFanTileEntity extends KineticTileEntity {
updateFrontBlock();
}
@Override
public void reActivateSource() {
source = Optional.empty();
applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0);
}
@Override
public void tick() {
super.tick();
if (speed == 0 || isGenerator)
if (getSpeed() == 0 || isGenerator)
return;
List<Entity> frontEntities = world.getEntitiesWithinAABBExcludingEntity(null, frontBB);
@ -308,7 +294,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
Vec3i flow = getAirFlow().getDirectionVec();
float sneakModifier = entity.isSneaking() ? 4096f : 512f;
float acceleration = (float) (speed * 1 / sneakModifier
float acceleration = (float) (getSpeed() * 1 / sneakModifier
/ (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance)));
Vec3d previousMotion = entity.getMotion();
float maxAcceleration = 5;

View file

@ -87,6 +87,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
}
public float getRenderedHeadRotationSpeed(float partialTicks) {
float speed = getSpeed();
if (running) {
if (runningTicks < 15) {
return speed;
@ -154,13 +155,14 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
}
}
float speed = Math.abs(getSpeed());
if (running) {
if (world.isRemote && runningTicks == 20)
renderParticles();
if (!world.isRemote && runningTicks == 20) {
if (processingTicks < 0) {
processingTicks = (MathHelper.log2((int) (8000 / Math.abs(speed)))) * 15 + 1;
processingTicks = (MathHelper.log2((int) (8000 / speed))) * 15 + 1;
return;
}
processingTicks--;
@ -178,7 +180,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
return;
}
if (Math.abs(speed) < 32)
if (speed < 32)
return;
if (!checkBasin)
return;
@ -229,7 +231,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
float angle = world.rand.nextFloat() * 360;
Vec3d offset = new Vec3d(0, 0, 0.25f);
offset = VecHelper.rotate(offset, angle, Axis.Y);
Vec3d target = VecHelper.rotate(offset, speed > 0 ? 25 : -25, Axis.Y).add(0, .25f, 0);
Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y).add(0, .25f, 0);
Vec3d center = offset.add(VecHelper.getCenterOf(pos));
target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f);

View file

@ -0,0 +1,60 @@
package com.simibubi.create.modules.contraptions.receivers;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import com.simibubi.create.AllRecipes;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipe;
import com.simibubi.create.modules.contraptions.base.StochasticOutput;
import com.simibubi.create.modules.contraptions.receivers.BasinTileEntity.BasinInputInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
public class MixingRecipe extends ProcessingRecipe<BasinInputInventory> {
public MixingRecipe(ResourceLocation id, String group, List<Ingredient> ingredients,
List<StochasticOutput> results, int processingDuration) {
super(AllRecipes.MIXING, id, group, ingredients, results, processingDuration);
}
@Override
public boolean matches(BasinInputInventory inv, World worldIn) {
if (inv.isEmpty())
return false;
NonNullList<Ingredient> ingredients = getIngredients();
if (!ingredients.stream().allMatch(Ingredient::isSimple))
return false;
List<ItemStack> remaining = new ArrayList<>();
for (int slot = 0; slot < inv.getSizeInventory(); ++slot) {
ItemStack itemstack = inv.getStackInSlot(slot);
if (!itemstack.isEmpty()) {
remaining.add(itemstack.copy());
}
}
// sort by leniency
List<Ingredient> sortedIngredients = new LinkedList<>(ingredients);
sortedIngredients.sort((i1, i2) -> i1.getMatchingStacks().length - i2.getMatchingStacks().length);
Ingredients: for (Ingredient ingredient : sortedIngredients) {
for (ItemStack stack : remaining) {
if (stack.isEmpty())
continue;
if (ingredient.test(stack)) {
stack.shrink(1);
continue Ingredients;
}
}
return false;
}
return true;
}
}

View file

@ -0,0 +1,53 @@
package com.simibubi.create.modules.contraptions.receivers;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.NonNullList;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.RecipeWrapper;
public class ProcessingInventory extends RecipeWrapper {
protected int processingDuration;
protected boolean appliedRecipe;
public ProcessingInventory() {
super(new ItemStackHandler(10));
}
@Override
public void clear() {
super.clear();
processingDuration = 0;
appliedRecipe = false;
}
public void write(CompoundNBT nbt) {
NonNullList<ItemStack> stacks = NonNullList.create();
for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stack = inv.getStackInSlot(slot);
stacks.add(stack);
}
ItemStackHelper.saveAllItems(nbt, stacks);
nbt.putInt("ProcessingTime", processingDuration);
nbt.putBoolean("AppliedRecipe", appliedRecipe);
}
public static ProcessingInventory read(CompoundNBT nbt) {
ProcessingInventory inventory = new ProcessingInventory();
NonNullList<ItemStack> stacks = NonNullList.withSize(10, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks);
for (int slot = 0; slot < stacks.size(); slot++)
inventory.setInventorySlotContents(slot, stacks.get(slot));
inventory.processingDuration = nbt.getInt("ProcessingTime");
inventory.appliedRecipe = nbt.getBoolean("AppliedRecipe");
return inventory;
}
public ItemStackHandler getItems() {
return (ItemStackHandler) inv;
}
}

View file

@ -9,14 +9,19 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
@ -26,6 +31,7 @@ public class SawBlock extends DirectionalAxisKineticBlock
implements IWithTileEntity<SawTileEntity>, IHaveMovementBehavior {
public static final BooleanProperty RUNNING = BooleanProperty.create("running");
public static DamageSource damageSourceSaw = new DamageSource("create.saw").setDamageBypassesArmor();
public SawBlock() {
super(Properties.from(Blocks.ANDESITE));
@ -67,6 +73,29 @@ public class SawBlock extends DirectionalAxisKineticBlock
return VoxelShapers.SHORT_CASING.get(state.get(FACING));
}
@Override
public void onEntityCollision(BlockState state, World worldIn, BlockPos pos, Entity entityIn) {
if (entityIn instanceof ItemEntity)
return;
if (!new AxisAlignedBB(pos).shrink(.1f).intersects(entityIn.getBoundingBox()))
return;
withTileEntityDo(worldIn, pos, te -> {
if (te.getSpeed() == 0)
return;
entityIn.attackEntityFrom(damageSourceSaw, MathHelper.clamp(Math.abs(te.speed / 512f) + 1, 0, 20));
});
}
@Override
public void onLanded(IBlockReader worldIn, Entity entityIn) {
super.onLanded(worldIn, entityIn);
if (!(entityIn instanceof ItemEntity))
return;
withTileEntityDo(entityIn.world, entityIn.getPosition(), te -> {
});
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;

View file

@ -2,21 +2,48 @@ package com.simibubi.create.modules.contraptions.receivers;
import static com.simibubi.create.modules.contraptions.receivers.SawBlock.RUNNING;
import java.util.Optional;
import com.simibubi.create.AllRecipes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.entity.item.ItemEntity;
public class SawTileEntity extends KineticTileEntity {
public ProcessingInventory inventory;
public SawTileEntity() {
super(AllTileEntities.SAW.type);
inventory = new ProcessingInventory();
}
@Override
public void onSpeedChanged() {
boolean shouldRun = Math.abs(speed) > 1 / 64f;
boolean shouldRun = Math.abs(getSpeed()) > 1 / 64f;
boolean running = getBlockState().get(RUNNING);
if (shouldRun != running)
world.setBlockState(pos, getBlockState().with(RUNNING, shouldRun));
}
@Override
public void tick() {
super.tick();
}
public void insertItem(ItemEntity entity) {
if (!inventory.isEmpty())
return;
inventory.clear();
inventory.setInventorySlotContents(0, entity.getItem().copy());
Optional<CuttingRecipe> recipe = world.getRecipeManager().getRecipe(AllRecipes.Types.CUTTING, inventory, world);
inventory.processingDuration = recipe.isPresent() ? recipe.get().getProcessingDuration() : 100;
inventory.appliedRecipe = false;
entity.remove();
}
}

View file

@ -1,10 +1,8 @@
package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.util.Optional;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.RotationPropagator;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.CreateConfig;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@ -19,7 +17,7 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class MechanicalBearingTileEntity extends KineticTileEntity {
public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity {
protected RotationConstruct movingConstruct;
protected float angle;
@ -45,12 +43,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
@Override
public float getAddedStressCapacity() {
return getWindmillSpeed() * 50;
}
@Override
public boolean isSource() {
return isWindmill;
return isWindmill ? CreateConfig.parameters.mechanicalBearingCapacity.get().floatValue() : 0;
}
public void neighbourChanged() {
@ -59,20 +52,14 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
return;
isWindmill = shouldWindmill;
if (isWindmill)
removeSource();
if (isWindmill && !running) {
if (isWindmill && !running)
assembleNextTick = true;
}
if (isWindmill && running) {
applyNewSpeed(getWindmillSpeed());
}
if (isWindmill && running)
updateGeneratedRotation();
if (!isWindmill && running) {
applyNewSpeed(0);
if (speed == 0)
updateGeneratedRotation();
if (getSpeed() == 0)
disassembleConstruct();
}
@ -86,8 +73,9 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
super.remove();
}
public float getWindmillSpeed() {
if (!running)
@Override
public float getGeneratedSpeed() {
if (!running || !isWindmill)
return 0;
int sails = movingConstruct.getSailBlocks();
return MathHelper.clamp(sails, 0, 128);
@ -128,7 +116,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
}
public float getAngularSpeed() {
return speed / 2048;
return getSpeed() / 2048;
}
public void assembleConstruct() {
@ -150,17 +138,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
getWorld().setBlockState(info.pos.add(pos), Blocks.AIR.getDefaultState(), 67);
}
applyWindmillSpeed();
}
public void applyWindmillSpeed() {
if (isWindmill) {
RotationPropagator.handleRemoved(world, pos, this);
source = Optional.empty();
speed = getWindmillSpeed();
RotationPropagator.handleAdded(world, pos, this);
sendData();
}
updateGeneratedRotation();
}
public void disassembleConstruct() {
@ -186,14 +164,10 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
running = false;
movingConstruct = null;
angle = 0;
updateGeneratedRotation();
sendData();
}
@Override
public void reActivateSource() {
applyWindmillSpeed();
}
@Override
public void tick() {
super.tick();
@ -210,6 +184,8 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
}
return;
} else {
if (speed == 0 && !isWindmill)
return;
assembleConstruct();
}
return;

View file

@ -193,7 +193,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity {
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
if (speed == 0)
if (getSpeed() == 0)
disassembleConstruct();
else {
for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors())

View file

@ -49,8 +49,7 @@ public class GearshiftBlock extends EncasedShaftBlock {
boolean previouslyPowered = state.get(POWERED);
if (previouslyPowered != worldIn.isBlockPowered(pos)) {
worldIn.setBlockState(pos, state.cycle(POWERED), 2);
if (!previouslyPowered)
worldIn.setBlockState(pos, state.cycle(POWERED), 2 | 16);
RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) worldIn.getTileEntity(pos));
}
}

View file

@ -181,8 +181,8 @@ public class BeltItem extends Item {
if (axis != world.getBlockState(second).get(BlockStateProperties.AXIS))
return false;
float speed1 = ((KineticTileEntity) world.getTileEntity(first)).getSpeed();
float speed2 = ((KineticTileEntity) world.getTileEntity(second)).getSpeed();
float speed1 = ((KineticTileEntity) world.getTileEntity(first)).speed;
float speed2 = ((KineticTileEntity) world.getTileEntity(second)).speed;
if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0)
return false;

View file

@ -72,7 +72,7 @@ public class BeltTileEntity extends KineticTileEntity {
}
protected boolean isLastBelt() {
if (speed == 0)
if (getSpeed() == 0)
return false;
Direction direction = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING);
@ -83,7 +83,7 @@ public class BeltTileEntity extends KineticTileEntity {
if (part == Part.MIDDLE)
return false;
boolean movingPositively = (speed > 0 == (direction.getAxisDirection().getOffset() == 1))
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1))
^ direction.getAxis() == Axis.X;
return part == Part.START ^ movingPositively;
}
@ -169,7 +169,7 @@ public class BeltTileEntity extends KineticTileEntity {
passengers.remove(e);
});
if (speed == 0)
if (getSpeed() == 0)
return;
}
@ -180,7 +180,7 @@ public class BeltTileEntity extends KineticTileEntity {
BlockState blockState = info.lastCollidedState;
Direction movementFacing = Direction.getFacingFromAxisDirection(
blockState.get(BlockStateProperties.HORIZONTAL_FACING).getAxis(),
speed < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
getSpeed() < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
boolean collidedWithBelt = te instanceof BeltTileEntity;
boolean betweenBelts = tileEntityBelowPassenger instanceof BeltTileEntity && tileEntityBelowPassenger != te;

View file

@ -1,8 +1,17 @@
package com.simibubi.create.modules.curiosities.deforester;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.modules.curiosities.tools.AllToolTiers;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AxeItem;
import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class DeforesterItem extends AxeItem {
@ -10,4 +19,22 @@ public class DeforesterItem extends AxeItem {
super(AllToolTiers.RADIANT, 10.0F, -3.1F, builder);
}
@Override
public boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos,
LivingEntity entityLiving) {
if (state.isIn(BlockTags.LOGS) && !entityLiving.isSneaking()) {
Tree tree = TreeCutter.cutTree(worldIn, pos);
if (tree == null)
return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving);
boolean dropBlock = !(entityLiving instanceof PlayerEntity) || !((PlayerEntity) entityLiving).isCreative();
for (BlockPos log : tree.logs)
worldIn.destroyBlock(log, dropBlock);
for (BlockPos leaf : tree.leaves)
worldIn.destroyBlock(leaf, dropBlock);
}
return super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving);
}
}