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.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipeSerializer; import com.simibubi.create.modules.contraptions.base.ProcessingRecipeSerializer;
import com.simibubi.create.modules.contraptions.receivers.CrushingRecipe; 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.PressingRecipe;
import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe; import com.simibubi.create.modules.contraptions.receivers.SplashingRecipe;
import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunUpgradeRecipe; import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunUpgradeRecipe;
@ -23,6 +25,8 @@ public enum AllRecipes {
CRUSHING(() -> new ProcessingRecipeSerializer<>(CrushingRecipe::new), Types.CRUSHING), CRUSHING(() -> new ProcessingRecipeSerializer<>(CrushingRecipe::new), Types.CRUSHING),
SPLASHING(() -> new ProcessingRecipeSerializer<>(SplashingRecipe::new), Types.SPLASHING), SPLASHING(() -> new ProcessingRecipeSerializer<>(SplashingRecipe::new), Types.SPLASHING),
PRESSING(() -> new ProcessingRecipeSerializer<>(PressingRecipe::new), Types.PRESSING), 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<CrushingRecipe> CRUSHING = register("crushing");
public static IRecipeType<SplashingRecipe> SPLASHING = register("splashing"); public static IRecipeType<SplashingRecipe> SPLASHING = register("splashing");
public static IRecipeType<PressingRecipe> PRESSING = register("pressing"); 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) { static <T extends IRecipe<?>> IRecipeType<T> register(final String key) {
return Registry.register(Registry.RECIPE_TYPE, new ResourceLocation(key), new IRecipeType<T>() { 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.gui.ScreenOpener;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.TooltipHelper; 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.receivers.TurntableHandler;
import com.simibubi.create.modules.contraptions.relays.belt.BeltItemHandler; import com.simibubi.create.modules.contraptions.relays.belt.BeltItemHandler;
@ -43,6 +45,11 @@ public class ClientEvents {
if (!isGameActive()) if (!isGameActive())
return; return;
if (!KineticDebugger.isActive() && KineticTileEntityRenderer.rainbowMode) {
KineticTileEntityRenderer.rainbowMode = false;
KineticTileEntityRenderer.invalidateCache();
}
ScreenOpener.tick(); ScreenOpener.tick();
onGameTick(); onGameTick();
} }
@ -57,6 +64,7 @@ public class ClientEvents {
CreateClient.schematicHandler.render(); CreateClient.schematicHandler.render();
CreateClient.schematicAndQuillHandler.render(); CreateClient.schematicAndQuillHandler.render();
CreateClient.schematicHologram.render(); CreateClient.schematicHologram.render();
KineticDebugger.renderSourceOutline();
} }
@SubscribeEvent @SubscribeEvent
@ -69,6 +77,7 @@ public class ClientEvents {
public static void onRenderHotbar() { public static void onRenderHotbar() {
CreateClient.schematicHandler.renderOverlay(); CreateClient.schematicHandler.renderOverlay();
KineticDebugger.renderOverlayText();
} }
@SubscribeEvent @SubscribeEvent

View file

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

View file

@ -2,9 +2,13 @@ package com.simibubi.create;
import java.nio.file.InvalidPathException; import java.nio.file.InvalidPathException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.tuple.Pair; 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;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.Builder; import net.minecraftforge.common.ForgeConfigSpec.Builder;
@ -56,6 +60,12 @@ public class CreateConfig {
inWorldProcessingTime; inWorldProcessingTime;
public IntValue maxChassisForTranslation, maxChassisForRotation, maxChassisRange, maxPistonPoles; 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 // Logistics
public IntValue extractorDelay, extractorAmount, linkRange; public IntValue extractorDelay, extractorAmount, linkRange;
@ -136,7 +146,7 @@ public class CreateConfig {
name = "cocoaLogGrowthSpeed"; name = "cocoaLogGrowthSpeed";
cocoaLogGrowthSpeed = builder.comment("", "% of random Ticks causing a Cocoa log to grow.") 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(); builder.pop();
} }
@ -231,6 +241,8 @@ public class CreateConfig {
maxPistonPoles = builder.comment("", "Maximum amount of extension poles behind a Mechanical Piston.") maxPistonPoles = builder.comment("", "Maximum amount of extension poles behind a Mechanical Piston.")
.translation(basePath + name).defineInRange(name, 64, 1, Integer.MAX_VALUE); .translation(basePath + name).defineInRange(name, 64, 1, Integer.MAX_VALUE);
initStress(builder);
builder.pop(); builder.pop();
} }
@ -256,7 +268,8 @@ public class CreateConfig {
.translation(basePath + name).defineInRange(name, 50, 10, Integer.MAX_VALUE); .translation(basePath + name).defineInRange(name, 50, 10, Integer.MAX_VALUE);
name = "allowGlassPanesInPartialBlocks"; 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); .translation(basePath + name).define(name, true);
builder.pop(); builder.pop();
@ -318,6 +331,83 @@ public class CreateConfig {
builder.pop(); 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) { private boolean isValidPath(Object path) {
if (!(path instanceof String)) if (!(path instanceof String))
return false; return false;

View file

@ -122,4 +122,24 @@ public abstract class BufferManipulator {
return buffer; 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 com.simibubi.create.Create;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class Lang { public class Lang {
@ -27,21 +23,6 @@ public class Lang {
player.sendStatusMessage(getTranslationComponent(key, args), true); 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) { public static List<String> translatedOptions(String prefix, String... keys) {
List<String> result = new ArrayList<>(keys.length); List<String> result = new ArrayList<>(keys.length);
for (String key : keys) { 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; package com.simibubi.create.modules.contraptions;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
public class KineticNetwork { public class KineticNetwork {
public UUID id; public UUID id;
private float stressCapacityPool;
private float maxStress;
private float currentStress;
public boolean initialized; public boolean initialized;
private float maxStress;
private float currentStress;
private float unloadedStressCapacity;
private float unloadedStress;
public Map<KineticTileEntity, Float> sources; public Map<KineticTileEntity, Float> sources;
public Set<KineticTileEntity> members; public Map<KineticTileEntity, Float> members;
public KineticNetwork() { public KineticNetwork() {
id = UUID.randomUUID(); id = UUID.randomUUID();
maxStress = stressCapacityPool = 0;
setCurrentStress(0);
sources = new HashMap<>(); sources = new HashMap<>();
members = new HashSet<>(); members = new HashMap<>();
} }
public void initFromTE(KineticTileEntity te) { public void initFromTE(KineticTileEntity te) {
maxStress = stressCapacityPool = te.maxStress; unloadedStressCapacity = te.maxStress;
currentStress = te.currentStress; unloadedStress = te.currentStress;
initialized = true; initialized = true;
addSilently(te); updateStress();
updateStressCapacity();
} }
public void addSilently(KineticTileEntity te) { public void addSilently(KineticTileEntity te) {
if (members.contains(te)) if (members.containsKey(te))
return; return;
if (te.isSource()) { if (te.isSource()) {
float capacity = te.getAddedStressCapacity(); float capacity = te.getAddedStressCapacity();
stressCapacityPool -= capacity; unloadedStressCapacity -= capacity;
sources.put(te, capacity); sources.put(te, capacity);
} }
members.add(te); float stressApplied = te.getStressApplied();
unloadedStress -= stressApplied;
members.put(te, stressApplied);
} }
public void add(KineticTileEntity te) { public void add(KineticTileEntity te) {
if (members.contains(te)) if (members.containsKey(te))
return; return;
Lang.debugChat(te.getType().getRegistryName().getPath() + " added to Network"); // Debug.debugChatAndShowStack(te.getType().getRegistryName().getPath() + " added to Network", 5);
te.setNetworkID(this.id);
if (te.isSource()) { if (te.isSource()) {
float capacity = te.getAddedStressCapacity(); sources.put(te, te.getAddedStressCapacity());
sources.put(te, capacity); updateStressCapacity();
updateMaxStress();
} }
members.add(te);
setCurrentStress(getCurrentStress() + te.getStressApplied()); members.put(te, te.getStressApplied());
updateStress();
sync(); sync();
} }
public void updateCapacityFor(KineticTileEntity te, float capacity) { public void updateCapacityFor(KineticTileEntity te, float capacity) {
sources.put(te, capacity); sources.put(te, capacity);
updateMaxStress(); updateStressCapacity();
}
public void updateStressFor(KineticTileEntity te, float stress) {
members.put(te, stress);
updateStress();
} }
public void remove(KineticTileEntity te) { public void remove(KineticTileEntity te) {
if (!members.contains(te)) if (!members.containsKey(te))
return; return;
Lang.debugChat(te.getType().getRegistryName().getPath() + " removed from Network"); // Debug.debugChat(te.getType().getRegistryName().getPath() + " removed from Network");
if (te.isSource()) { if (te.isSource()) {
sources.remove(te); sources.remove(te);
updateMaxStress(); updateStressCapacity();
} }
members.remove(te); members.remove(te);
setCurrentStress(getCurrentStress() - te.getStressApplied()); updateStress();
sync(); sync();
} }
public void sync() { public void sync() {
for (KineticTileEntity te : members) { for (KineticTileEntity te : members.keySet()) {
te.sync(id, getMaxStress(), getCurrentStress()); te.sync(maxStress, currentStress);
} }
} }
public float getMaxStress() { public void updateStressCapacity() {
return maxStress;
}
private void updateMaxStress() {
float presentCapacity = 0; float presentCapacity = 0;
for (Float cap : sources.values()) for (KineticTileEntity te : sources.keySet())
presentCapacity += cap; presentCapacity += sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
float newMaxStress = presentCapacity + stressCapacityPool; float newMaxStress = presentCapacity + unloadedStressCapacity;
if (maxStress != newMaxStress) { if (maxStress != newMaxStress) {
maxStress = newMaxStress; maxStress = newMaxStress;
sync(); sync();
// Debug.debugChatAndShowStack("Current Stress level: " + currentStress + "/" + maxStress, 5);
} }
Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress);
} }
public float getCurrentStress() { public void updateStress() {
return currentStress; 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);
}
} }
public void setCurrentStress(float currentStress) { private float getStressMultiplierForSpeed(float speed) {
this.currentStress = currentStress; return Math.abs(speed);
Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress);
} }
} }

View file

@ -223,46 +223,40 @@ public class RotationPropagator {
return; return;
} }
boolean isSource = neighbourTE.isSource(); if (incompatible) {
boolean hasSource = neighbourTE.hasSource(); // Opposite directions
boolean poweredBySomethingElse = isSource world.destroyBlock(pos, true);
|| hasSource && !neighbourTE.getSource().equals(updateTE.getPos()); return;
if (poweredBySomethingElse) { } else {
if (neighbourTE.speed != newSpeed) { // Same direction: overpower the slower speed
if (incompatible) { if (Math.abs(oppositeSpeed) > Math.abs(updateTE.speed)) {
// Opposite directions // Neighbour faster, overpower the incoming tree
world.destroyBlock(pos, true); updateTE.setSource(neighbourTE.getPos());
return; updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE));
updateTE.onSpeedChanged();
updateTE.sendData();
} else { propagateNewSource(updateTE);
// Same direction: overpower the slower speed return;
if (Math.abs(oppositeSpeed) > Math.abs(updateTE.speed)) { }
// Neighbour faster, overpower the incoming tree if (Math.abs(newSpeed) >= Math.abs(neighbourTE.speed)) {
updateTE.setSource(neighbourTE.getPos()); if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed) || updateTE.newNetworkID != null
updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE)); && !updateTE.newNetworkID.equals(neighbourTE.newNetworkID)) {
updateTE.onSpeedChanged(); // Current faster, overpower the neighbours' tree
updateTE.sendData();
propagateNewSource(updateTE); if (updateTE.hasSource() && updateTE.getSource().equals(neighbourTE.getPos())) {
return; updateTE.removeSource();
} }
if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed)) {
// Current faster, overpower the neighbours' tree neighbourTE.setSource(updateTE.getPos());
neighbourTE.setSpeed(updateTE.speed * getRotationSpeedModifier(updateTE, neighbourTE));
if (updateTE.hasSource() && updateTE.getSource().equals(neighbourTE.getPos())) { neighbourTE.onSpeedChanged();
updateTE.removeSource(); neighbourTE.sendData();
} propagateNewSource(neighbourTE);
}
neighbourTE.setSource(updateTE.getPos()); continue;
neighbourTE.setSpeed(updateTE.speed * getRotationSpeedModifier(updateTE, neighbourTE));
neighbourTE.onSpeedChanged();
neighbourTE.sendData();
propagateNewSource(neighbourTE);
continue;
}
}
} }
continue;
} }
if (neighbourTE.speed == newSpeed) if (neighbourTE.speed == newSpeed)

View file

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

View file

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

View file

@ -11,6 +11,8 @@ import org.lwjgl.opengl.GL11;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.BufferManipulator; 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.block.BlockState;
import net.minecraft.client.Minecraft; 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.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -32,6 +35,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTileEntity> { public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTileEntity> {
protected static Map<BlockState, BufferManipulator> cachedBuffers; protected static Map<BlockState, BufferManipulator> cachedBuffers;
public static boolean rainbowMode = false;
protected static class BlockModelSpinner extends BufferManipulator { 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, protected static void renderFromCache(BufferBuilder buffer, BlockState state, World world, float x, float y,
float z, BlockPos pos, Axis axis, float angle) { float z, BlockPos pos, Axis axis, float angle) {
int packedLightmapCoords = state.getPackedLightmapCoords(world, pos); int packedLightmapCoords = state.getPackedLightmapCoords(world, pos);
buffer.putBulkData(((BlockModelSpinner) getBuffer(state)).getTransformed(x, y, z, angle, axis, ByteBuffer transformed = ((BlockModelSpinner) getBuffer(state)).getTransformed(x, y, z, angle, axis,
packedLightmapCoords)); 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) { public static BufferManipulator getBuffer(BlockState state) {

View file

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

View file

@ -71,13 +71,13 @@ public class MotorBlock extends HorizontalKineticBlock
MotorTileEntity tileEntity = (MotorTileEntity) world.getTileEntity(pos); MotorTileEntity tileEntity = (MotorTileEntity) world.getTileEntity(pos);
if (tileEntity == null) if (tileEntity == null)
return 0; return 0;
return tileEntity.getSpeedValue(); return tileEntity.newGeneratedSpeed;
} }
@Override @Override
public void onScroll(BlockState state, IWorld world, BlockPos pos, double delta) { public void onScroll(BlockState state, IWorld world, BlockPos pos, double delta) {
withTileEntityDo(world, pos, te -> te 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 @Override

View file

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

View file

@ -2,20 +2,18 @@ package com.simibubi.create.modules.contraptions.generators;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.RotationPropagator; 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.nbt.CompoundNBT;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
public class WaterWheelTileEntity extends KineticTileEntity { public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
private Map<Direction, Integer> flows; private Map<Direction, Integer> flows;
private boolean hasFlows;
public WaterWheelTileEntity() { public WaterWheelTileEntity() {
super(AllTileEntities.WATER_WHEEL.type); super(AllTileEntities.WATER_WHEEL.type);
@ -55,39 +53,16 @@ public class WaterWheelTileEntity extends KineticTileEntity {
} }
@Override @Override
public void reActivateSource() { public float getGeneratedSpeed() {
updateSpeed();
}
public void updateSpeed() {
float speed = 0; float speed = 0;
for (Integer i : flows.values()) for (Integer i : flows.values())
speed += i; speed += i;
return speed;
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;
} }
@Override @Override
public float getAddedStressCapacity() { public float getAddedStressCapacity() {
float torque = 0; return CreateConfig.parameters.waterWheelCapacity.get().floatValue();
for (Integer i : flows.values())
torque += i;
return Math.abs(torque);
} }
} }

View file

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

View file

@ -5,13 +5,12 @@ import java.util.List;
import com.simibubi.create.AllRecipes; import com.simibubi.create.AllRecipes;
import com.simibubi.create.modules.contraptions.base.ProcessingRecipe; import com.simibubi.create.modules.contraptions.base.ProcessingRecipe;
import com.simibubi.create.modules.contraptions.base.StochasticOutput; 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.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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, public CrushingRecipe(ResourceLocation id, String group, List<Ingredient> ingredients,
List<StochasticOutput> results, int processingDuration) { List<StochasticOutput> results, int processingDuration) {
@ -19,7 +18,7 @@ public class CrushingRecipe extends ProcessingRecipe<CrushingWheelControllerTile
} }
@Override @Override
public boolean matches(Inventory inv, World worldIn) { public boolean matches(ProcessingInventory inv, World worldIn) {
if (inv.isEmpty()) if (inv.isEmpty())
return false; return false;
return ingredients.get(0).test(inv.getStackInSlot(0)); 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.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.particles.ParticleTypes; import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty; import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
@ -39,6 +40,11 @@ public class CrushingWheelControllerBlock extends Block implements IWithoutBlock
return true; return true;
} }
@Override
public boolean isReplaceable(BlockState state, BlockItemUseContext useContext) {
return false;
}
@Override @Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) { public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new CrushingWheelControllerTileEntity(); 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.Entity;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
@ -23,59 +22,11 @@ import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes; import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.util.DamageSource; import net.minecraft.util.DamageSource;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d; 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 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() private static DamageSource damageSource = new DamageSource("create.crush").setDamageBypassesArmor()
.setDifficultyScaled(); .setDifficultyScaled();
@ -83,12 +34,12 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
private UUID entityUUID; private UUID entityUUID;
protected boolean searchForEntity; protected boolean searchForEntity;
private Inventory contents; private ProcessingInventory contents;
public float crushingspeed; public float crushingspeed;
public CrushingWheelControllerTileEntity() { public CrushingWheelControllerTileEntity() {
super(AllTileEntities.CRUSHING_WHEEL_CONTROLLER.type); super(AllTileEntities.CRUSHING_WHEEL_CONTROLLER.type);
contents = new Inventory(); contents = new ProcessingInventory();
} }
@Override @Override
@ -236,7 +187,7 @@ public class CrushingWheelControllerTileEntity extends SyncedTileEntity implemen
this.searchForEntity = true; this.searchForEntity = true;
} }
crushingspeed = compound.getFloat("Speed"); 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) if (world.isRemote)
return; return;
if (speed == 0) if (getSpeed() == 0)
return; return;
BlockPos posToBreak = pos.offset(getBlockState().get(BlockStateProperties.FACING)); 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 static net.minecraft.util.Direction.AxisDirection.POSITIVE;
import java.util.List; import java.util.List;
import java.util.Optional;
import com.simibubi.create.AllBlockTags; import com.simibubi.create.AllBlockTags;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
@ -14,7 +13,7 @@ import com.simibubi.create.AllTileEntities;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.CreateConfig; import com.simibubi.create.CreateConfig;
import com.simibubi.create.foundation.utility.VecHelper; 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;
import com.simibubi.create.modules.logistics.InWorldProcessing.Type; 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.Vec3d;
import net.minecraft.util.math.Vec3i; 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() private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled()
.setFireDamage(); .setFireDamage();
@ -87,13 +86,13 @@ public class EncasedFanTileEntity extends KineticTileEntity {
} }
@Override @Override
public boolean isSource() { public float getAddedStressCapacity() {
return isGenerator; return isGenerator ? CreateConfig.parameters.generatingFanCapacity.get().floatValue() : 0;
} }
@Override @Override
public float getAddedStressCapacity() { public float getGeneratedSpeed() {
return 50; return isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0;
} }
public void updateGenerator() { public void updateGenerator() {
@ -102,14 +101,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
return; return;
isGenerator = shouldGenerate; isGenerator = shouldGenerate;
if (isGenerator) { updateGeneratedRotation();
notifyStressCapacityChange(getAddedStressCapacity());
removeSource();
} else {
notifyStressCapacityChange(0);
}
applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0);
sendData();
} }
public boolean blockBelowIsHot() { public boolean blockBelowIsHot() {
@ -122,7 +114,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
if (world.isRemote) if (world.isRemote)
return; return;
float speed = Math.abs(this.speed); float speed = Math.abs(this.getSpeed());
float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1); float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1);
pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get()); pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get());
@ -180,9 +172,9 @@ public class EncasedFanTileEntity extends KineticTileEntity {
} }
public Direction getAirFlow() { public Direction getAirFlow() {
if (speed == 0) if (getSpeed() == 0)
return null; return null;
return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), speed > 0 ? POSITIVE : NEGATIVE); return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), getSpeed() > 0 ? POSITIVE : NEGATIVE);
} }
@Override @Override
@ -191,17 +183,11 @@ public class EncasedFanTileEntity extends KineticTileEntity {
updateFrontBlock(); updateFrontBlock();
} }
@Override
public void reActivateSource() {
source = Optional.empty();
applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0);
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
if (speed == 0 || isGenerator) if (getSpeed() == 0 || isGenerator)
return; return;
List<Entity> frontEntities = world.getEntitiesWithinAABBExcludingEntity(null, frontBB); List<Entity> frontEntities = world.getEntitiesWithinAABBExcludingEntity(null, frontBB);
@ -308,7 +294,7 @@ public class EncasedFanTileEntity extends KineticTileEntity {
Vec3i flow = getAirFlow().getDirectionVec(); Vec3i flow = getAirFlow().getDirectionVec();
float sneakModifier = entity.isSneaking() ? 4096f : 512f; 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))); / (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance)));
Vec3d previousMotion = entity.getMotion(); Vec3d previousMotion = entity.getMotion();
float maxAcceleration = 5; float maxAcceleration = 5;

View file

@ -87,6 +87,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
} }
public float getRenderedHeadRotationSpeed(float partialTicks) { public float getRenderedHeadRotationSpeed(float partialTicks) {
float speed = getSpeed();
if (running) { if (running) {
if (runningTicks < 15) { if (runningTicks < 15) {
return speed; return speed;
@ -154,13 +155,14 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
} }
} }
float speed = Math.abs(getSpeed());
if (running) { if (running) {
if (world.isRemote && runningTicks == 20) if (world.isRemote && runningTicks == 20)
renderParticles(); renderParticles();
if (!world.isRemote && runningTicks == 20) { if (!world.isRemote && runningTicks == 20) {
if (processingTicks < 0) { if (processingTicks < 0) {
processingTicks = (MathHelper.log2((int) (8000 / Math.abs(speed)))) * 15 + 1; processingTicks = (MathHelper.log2((int) (8000 / speed))) * 15 + 1;
return; return;
} }
processingTicks--; processingTicks--;
@ -178,7 +180,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
return; return;
} }
if (Math.abs(speed) < 32) if (speed < 32)
return; return;
if (!checkBasin) if (!checkBasin)
return; return;
@ -229,7 +231,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
float angle = world.rand.nextFloat() * 360; float angle = world.rand.nextFloat() * 360;
Vec3d offset = new Vec3d(0, 0, 0.25f); Vec3d offset = new Vec3d(0, 0, 0.25f);
offset = VecHelper.rotate(offset, angle, Axis.Y); 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)); Vec3d center = offset.add(VecHelper.getCenterOf(pos));
target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f); 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.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction; 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.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty; import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.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.world.IBlockReader; import net.minecraft.world.IBlockReader;
@ -26,6 +31,7 @@ public class SawBlock extends DirectionalAxisKineticBlock
implements IWithTileEntity<SawTileEntity>, IHaveMovementBehavior { implements IWithTileEntity<SawTileEntity>, IHaveMovementBehavior {
public static final BooleanProperty RUNNING = BooleanProperty.create("running"); public static final BooleanProperty RUNNING = BooleanProperty.create("running");
public static DamageSource damageSourceSaw = new DamageSource("create.saw").setDamageBypassesArmor();
public SawBlock() { public SawBlock() {
super(Properties.from(Blocks.ANDESITE)); super(Properties.from(Blocks.ANDESITE));
@ -67,6 +73,29 @@ public class SawBlock extends DirectionalAxisKineticBlock
return VoxelShapers.SHORT_CASING.get(state.get(FACING)); 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 @Override
public PushReaction getPushReaction(BlockState state) { public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY; 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 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.AllTileEntities;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.entity.item.ItemEntity;
public class SawTileEntity extends KineticTileEntity { public class SawTileEntity extends KineticTileEntity {
public ProcessingInventory inventory;
public SawTileEntity() { public SawTileEntity() {
super(AllTileEntities.SAW.type); super(AllTileEntities.SAW.type);
inventory = new ProcessingInventory();
} }
@Override @Override
public void onSpeedChanged() { public void onSpeedChanged() {
boolean shouldRun = Math.abs(speed) > 1 / 64f; boolean shouldRun = Math.abs(getSpeed()) > 1 / 64f;
boolean running = getBlockState().get(RUNNING); boolean running = getBlockState().get(RUNNING);
if (shouldRun != running) if (shouldRun != running)
world.setBlockState(pos, getBlockState().with(RUNNING, shouldRun)); 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; package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.util.Optional;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.RotationPropagator; import com.simibubi.create.CreateConfig;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; 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.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
public class MechanicalBearingTileEntity extends KineticTileEntity { public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity {
protected RotationConstruct movingConstruct; protected RotationConstruct movingConstruct;
protected float angle; protected float angle;
@ -45,12 +43,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
@Override @Override
public float getAddedStressCapacity() { public float getAddedStressCapacity() {
return getWindmillSpeed() * 50; return isWindmill ? CreateConfig.parameters.mechanicalBearingCapacity.get().floatValue() : 0;
}
@Override
public boolean isSource() {
return isWindmill;
} }
public void neighbourChanged() { public void neighbourChanged() {
@ -59,20 +52,14 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
return; return;
isWindmill = shouldWindmill; isWindmill = shouldWindmill;
if (isWindmill) if (isWindmill && !running)
removeSource();
if (isWindmill && !running) {
assembleNextTick = true; assembleNextTick = true;
} if (isWindmill && running)
updateGeneratedRotation();
if (isWindmill && running) {
applyNewSpeed(getWindmillSpeed());
}
if (!isWindmill && running) { if (!isWindmill && running) {
applyNewSpeed(0); updateGeneratedRotation();
if (speed == 0) if (getSpeed() == 0)
disassembleConstruct(); disassembleConstruct();
} }
@ -86,8 +73,9 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
super.remove(); super.remove();
} }
public float getWindmillSpeed() { @Override
if (!running) public float getGeneratedSpeed() {
if (!running || !isWindmill)
return 0; return 0;
int sails = movingConstruct.getSailBlocks(); int sails = movingConstruct.getSailBlocks();
return MathHelper.clamp(sails, 0, 128); return MathHelper.clamp(sails, 0, 128);
@ -128,7 +116,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
} }
public float getAngularSpeed() { public float getAngularSpeed() {
return speed / 2048; return getSpeed() / 2048;
} }
public void assembleConstruct() { public void assembleConstruct() {
@ -150,17 +138,7 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
getWorld().setBlockState(info.pos.add(pos), Blocks.AIR.getDefaultState(), 67); getWorld().setBlockState(info.pos.add(pos), Blocks.AIR.getDefaultState(), 67);
} }
applyWindmillSpeed(); updateGeneratedRotation();
}
public void applyWindmillSpeed() {
if (isWindmill) {
RotationPropagator.handleRemoved(world, pos, this);
source = Optional.empty();
speed = getWindmillSpeed();
RotationPropagator.handleAdded(world, pos, this);
sendData();
}
} }
public void disassembleConstruct() { public void disassembleConstruct() {
@ -186,14 +164,10 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
running = false; running = false;
movingConstruct = null; movingConstruct = null;
angle = 0; angle = 0;
updateGeneratedRotation();
sendData(); sendData();
} }
@Override
public void reActivateSource() {
applyWindmillSpeed();
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
@ -210,6 +184,8 @@ public class MechanicalBearingTileEntity extends KineticTileEntity {
} }
return; return;
} else { } else {
if (speed == 0 && !isWindmill)
return;
assembleConstruct(); assembleConstruct();
} }
return; return;

View file

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

View file

@ -49,9 +49,8 @@ public class GearshiftBlock extends EncasedShaftBlock {
boolean previouslyPowered = state.get(POWERED); boolean previouslyPowered = state.get(POWERED);
if (previouslyPowered != worldIn.isBlockPowered(pos)) { if (previouslyPowered != worldIn.isBlockPowered(pos)) {
worldIn.setBlockState(pos, state.cycle(POWERED), 2); worldIn.setBlockState(pos, state.cycle(POWERED), 2 | 16);
if (!previouslyPowered) RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) worldIn.getTileEntity(pos));
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)) if (axis != world.getBlockState(second).get(BlockStateProperties.AXIS))
return false; return false;
float speed1 = ((KineticTileEntity) world.getTileEntity(first)).getSpeed(); float speed1 = ((KineticTileEntity) world.getTileEntity(first)).speed;
float speed2 = ((KineticTileEntity) world.getTileEntity(second)).getSpeed(); float speed2 = ((KineticTileEntity) world.getTileEntity(second)).speed;
if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0) if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0)
return false; return false;

View file

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

View file

@ -1,8 +1,17 @@
package com.simibubi.create.modules.curiosities.deforester; 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 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.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 { public class DeforesterItem extends AxeItem {
@ -10,4 +19,22 @@ public class DeforesterItem extends AxeItem {
super(AllToolTiers.RADIANT, 10.0F, -3.1F, builder); 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);
}
} }