In World in Style

- Overhauled UX of scroll values and item filtering
- Filtered item extraction can now be configured to pull "up to x items" per operation
- Removed some unused assets
This commit is contained in:
simibubi 2023-03-01 18:45:25 +01:00
parent 4924dfda5d
commit ac182991f4
84 changed files with 1808 additions and 902 deletions

View file

@ -577,7 +577,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
30815cc68ddf59924be78b1c37a0e374fafe552a assets/create/lang/en_ud.json
c1aabd0f4dfd58bbbb2618a367fc9b6b02bfb1b6 assets/create/lang/en_us.json
c6c72491c2586f70e72d7510b230e7307a4d7c99 assets/create/lang/en_us.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json

View file

@ -1070,20 +1070,41 @@
"create.contraptions.cart_movement_mode.rotate_paused": "Pause actors while rotating",
"create.contraptions.cart_movement_mode.rotation_locked": "Lock rotation",
"create.contraptions.windmill.rotation_direction": "Rotation Direction",
"create.contraptions.clockwork.clock_hands": "Clock Hands",
"create.contraptions.clockwork.clock_hands": "Clock Hand Arrangement",
"create.contraptions.clockwork.hour_first": "Hour hand first",
"create.contraptions.clockwork.minute_first": "Minute hand first",
"create.contraptions.clockwork.hour_first_24": "24-Hour hand first",
"create.logistics.crafter.connected": "Connected Crafters",
"create.logistics.crafter.click_to_merge": "Click to merge Inventories",
"create.logistics.crafter.click_to_separate": "Click to separate Inventories",
"create.logistics.filter": "Filter",
"create.logistics.recipe_filter": "Recipe Filter",
"create.logistics.fluid_filter": "Fluid Filter",
"create.logistics.firstFrequency": "Freq. #1",
"create.logistics.secondFrequency": "Freq. #2",
"create.logistics.filter.apply": "Applied filter to %1$s.",
"create.logistics.filter.apply_click_again": "Applied filter to %1$s, click again to copy the amount.",
"create.logistics.filter.apply_count": "Applied extraction count to filter.",
"create.logistics.firstFrequency": "Frequency #1",
"create.logistics.secondFrequency": "Frequency #2",
"create.logistics.filter.click_to_set": "Click with item to set",
"create.logistics.filter.click_to_replace": "Click with item to replace",
"create.logistics.filter.hold_to_set_amount": "Click and hold for amount",
"create.logistics.filter.extracted_amount": "Extracted Amount",
"create.logistics.filter.any_amount_short": "Any",
"create.logistics.filter.up_to": "Up to",
"create.logistics.filter.exactly": "Exactly",
"create.logistics.creative_crate.supply": "Infinite Supply",
"create.logistics.train_observer.cargo_filter": "Cargo Filter",
"create.kinetics.creative_motor.rotation_speed": "Generated Speed in RPM",
"create.kinetics.speed_controller.rotation_speed": "Targeted Speed in RPM",
"create.logistics.redstone_interval": "Redstone Interval",
"create.contraptions.contoller.target": "Targeted Component",
"create.contraptions.chassis.radius": "Radius when Sticky",
"create.contraptions.chassis.range": "Range of Sticky Sides",
"create.contraptions.chassis.distance": "Distance",
"create.gui.value_settings.hold_to_edit": "Click and hold to edit",
"create.gui.value_settings.release_to_confirm": "Release %1$s to Confirm",
"create.gui.goggles.generator_stats": "Generator Stats:",
"create.gui.goggles.kinetic_stats": "Kinetic Stats:",
"create.gui.goggles.at_current_speed": "at current speed",
@ -1374,7 +1395,7 @@
"create.weighted_ejector.targeting": "Ejecting to [%1$s,%2$s,%3$s]",
"create.weighted_ejector.stack_size": "Ejected Stack Size",
"create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available",
"create.logistics.when_multiple_outputs_available": "Distribution Method",
"create.mechanical_arm.selection_mode.round_robin": "Round Robin",
"create.mechanical_arm.selection_mode.forced_round_robin": "Forced Round Robin",

View file

@ -42,8 +42,7 @@ public class AllSpriteShifts {
VERTICAL_FRAMED_GLASS = getCT(AllCTTypes.VERTICAL, "palettes/framed_glass", "palettes/vertical_framed_glass"),
ORNATE_IRON_WINDOW = vertical("palettes/ornate_iron_window");
public static final CTSpriteShiftEntry CRAFTER_FRONT =
getCT(AllCTTypes.OMNIDIRECTIONAL, "crafter_top", "brass_casing"), CRAFTER_SIDE = vertical("crafter_side"),
public static final CTSpriteShiftEntry CRAFTER_SIDE = vertical("crafter_side"),
CRAFTER_OTHERSIDE = horizontal("crafter_side"),
ANDESITE_ENCASED_COGWHEEL_SIDE = vertical("andesite_encased_cogwheel_side"),
ANDESITE_ENCASED_COGWHEEL_OTHERSIDE = horizontal("andesite_encased_cogwheel_side"),

View file

@ -20,6 +20,7 @@ import com.simibubi.create.content.schematics.ClientSchematicLoader;
import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler;
import com.simibubi.create.content.schematics.client.SchematicHandler;
import com.simibubi.create.foundation.ClientResourceReloadListener;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsClient;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.UIRenderHelper;
import com.simibubi.create.foundation.ponder.content.PonderIndex;
@ -61,6 +62,7 @@ public class CreateClient {
public static final PotatoCannonRenderHandler POTATO_CANNON_RENDER_HANDLER = new PotatoCannonRenderHandler();
public static final SoulPulseEffectHandler SOUL_PULSE_EFFECT_HANDLER = new SoulPulseEffectHandler();
public static final GlobalRailwayManager RAILWAYS = new GlobalRailwayManager();
public static final ValueSettingsClient VALUE_SETTINGS_HANDLER = new ValueSettingsClient();
public static final ClientResourceReloadListener RESOURCE_RELOAD_LISTENER = new ClientResourceReloadListener();
@ -106,6 +108,7 @@ public class CreateClient {
OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Linked Controller", LinkedControllerClientHandler.OVERLAY);
OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Schematics", SCHEMATIC_HANDLER.getOverlayRenderer());
OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Toolboxes", ToolboxHandlerClient.OVERLAY);
OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Value Settings", VALUE_SETTINGS_HANDLER);
}
public static void invalidateRenderers() {

View file

@ -48,7 +48,8 @@ public class ContraptionControlsBlockEntity extends SmartBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(filtering = new FilteringBehaviour(this, new ControlsSlot()).moveText(new Vec3(-30, 20, 10)));
behaviours.add(filtering = new FilteringBehaviour(this, new ControlsSlot()));
filtering.setLabel(Lang.translateDirect("contraptions.contoller.target"));
}
public void pressButton() {
@ -107,13 +108,13 @@ public class ContraptionControlsBlockEntity extends SmartBlockEntity {
.color(DyeHelper.DYE_TABLE.get(enabled ? DyeColor.LIME : DyeColor.ORANGE)
.getFirst())
.component();
if (filter.isEmpty()) {
Lang.translate("contraption.controls.all_actor_toggle", state)
.sendStatus(player);
return;
}
Lang.translate("contraption.controls.specific_actor_toggle", filter.getHoverName()
.getString(), state)
.sendStatus(player);
@ -125,7 +126,7 @@ public class ContraptionControlsBlockEntity extends SmartBlockEntity {
protected Vec3 getLocalOffset(BlockState state) {
Direction facing = state.getValue(ControlsBlock.FACING);
float yRot = AngleHelper.horizontalAngle(facing);
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 10.875f, 5.1f), yRot, Axis.Y);
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12f, 5.5f), yRot, Axis.Y);
}
@Override

View file

@ -47,12 +47,14 @@ public class ContraptionControlsRenderer extends SmartBlockEntityRenderer<Contra
BlockState blockState = blockEntity.getBlockState();
Direction facing = blockState.getValue(ContraptionControlsBlock.FACING)
.getOpposite();
Vec3 buttonAxis = VecHelper.rotate(new Vec3(0, 1, -.325), AngleHelper.horizontalAngle(facing), Axis.Y)
.scale(-1 / 24f * blockEntity.button.getValue(pt));
Vec3 buttonMovementAxis = VecHelper.rotate(new Vec3(0, 1, -.325), AngleHelper.horizontalAngle(facing), Axis.Y);
Vec3 buttonMovement = buttonMovementAxis.scale(-0.07f + -1 / 24f * blockEntity.button.getValue(pt));
Vec3 buttonOffset = buttonMovementAxis.scale(0.07f);
ms.pushPose();
ms.translate(buttonAxis.x, buttonAxis.y, buttonAxis.z);
ms.translate(buttonMovement.x, buttonMovement.y, buttonMovement.z);
super.renderSafe(blockEntity, pt, ms, buffer, light, overlay);
ms.translate(buttonOffset.x, buttonOffset.y, buttonOffset.z);
VertexConsumer vc = buffer.getBuffer(RenderType.solid());
CachedBufferer.partialFacing(AllPartialModels.CONTRAPTION_CONTROLS_BUTTON, blockState, facing)

View file

@ -5,7 +5,6 @@ import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlo
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
@ -26,23 +25,7 @@ public class CrafterCTBehaviour extends ConnectedTextureBehaviour.Base {
return false;
if (state.getValue(HORIZONTAL_FACING) != other.getValue(HORIZONTAL_FACING))
return false;
ConnectedInput input1 = CrafterHelper.getInput(reader, pos);
ConnectedInput input2 = CrafterHelper.getInput(reader, otherPos);
if (input1 == null || input2 == null)
return false;
if (input1.data.isEmpty() || input2.data.isEmpty())
return false;
try {
if (pos.offset(input1.data.get(0))
.equals(otherPos.offset(input2.data.get(0))))
return true;
} catch (IndexOutOfBoundsException e) {
// race condition. data somehow becomes empty between the last 2 if statements
}
return false;
return CrafterHelper.areCraftersConnected(reader, pos, otherPos);
}
@Override
@ -67,7 +50,7 @@ public class CrafterCTBehaviour extends ConnectedTextureBehaviour.Base {
boolean isVertical = direction.getAxis()
.isVertical();
boolean facingX = facing.getAxis() == Axis.X;
return isFront ? AllSpriteShifts.CRAFTER_FRONT
return isFront ? AllSpriteShifts.BRASS_CASING
: isVertical && !facingX ? AllSpriteShifts.CRAFTER_OTHERSIDE : AllSpriteShifts.CRAFTER_SIDE;
}

View file

@ -1,5 +1,7 @@
package com.simibubi.create.content.contraptions.components.crafter;
import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -18,4 +20,23 @@ public class CrafterHelper {
return crafter == null ? null : crafter.input;
}
public static boolean areCraftersConnected(BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos) {
ConnectedInput input1 = getInput(reader, pos);
ConnectedInput input2 = getInput(reader, otherPos);
if (input1 == null || input2 == null)
return false;
if (input1.data.isEmpty() || input2.data.isEmpty())
return false;
try {
if (pos.offset(input1.data.get(0))
.equals(otherPos.offset(input2.data.get(0))))
return true;
} catch (IndexOutOfBoundsException e) {
// race condition. data somehow becomes empty between the last 2 if statements
}
return false;
}
}

View file

@ -16,7 +16,7 @@ public class DeployerFilterSlot extends ValueBoxTransform {
@Override
protected Vec3 getLocalOffset(BlockState state) {
Direction facing = state.getValue(DeployerBlock.FACING);
Vec3 vec = VecHelper.voxelSpace(8f, 13.5f, 11.5f);
Vec3 vec = VecHelper.voxelSpace(8f, 13f, 11.5f);
float yRot = AngleHelper.horizontalAngle(facing);
float xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0;

View file

@ -2,22 +2,29 @@ package com.simibubi.create.content.contraptions.components.motor;
import java.util.List;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.base.GeneratingKineticBlockEntity;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class CreativeMotorBlockEntity extends GeneratingKineticBlockEntity {
public static final int DEFAULT_SPEED = 16;
public static final int MAX_SPEED = 256;
protected ScrollValueBehaviour generatedSpeed;
public CreativeMotorBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
@ -27,18 +34,12 @@ public class CreativeMotorBlockEntity extends GeneratingKineticBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
Integer max = AllConfigs.server().kinetics.maxMotorSpeed.get();
CenteredSideValueBoxTransform slot = new CenteredSideValueBoxTransform(
(motor, side) -> motor.getValue(CreativeMotorBlock.FACING) == side.getOpposite());
generatedSpeed = new ScrollValueBehaviour(Lang.translateDirect("generic.speed"), this, slot);
int max = MAX_SPEED;
generatedSpeed = new KineticScrollValueBehaviour(Lang.translateDirect("kinetics.creative_motor.rotation_speed"),
this, new MotorValueBox());
generatedSpeed.between(-max, max);
generatedSpeed.value = DEFAULT_SPEED;
generatedSpeed.scrollableValue = DEFAULT_SPEED;
generatedSpeed.withUnit(i -> Lang.translateDirect("generic.unit.rpm"));
generatedSpeed.withCallback(i -> this.updateGeneratedRotation());
generatedSpeed.withStepFunction(CreativeMotorBlockEntity::step);
behaviours.add(generatedSpeed);
}
@ -56,22 +57,40 @@ public class CreativeMotorBlockEntity extends GeneratingKineticBlockEntity {
return convertToDirection(generatedSpeed.getValue(), getBlockState().getValue(CreativeMotorBlock.FACING));
}
public static int step(StepContext context) {
int current = context.currentValue;
int step = 1;
class MotorValueBox extends ValueBoxTransform.Sided {
if (!context.shift) {
int magnitude = Math.abs(current) - (context.forward == current > 0 ? 0 : 1);
if (magnitude >= 4)
step *= 4;
if (magnitude >= 32)
step *= 4;
if (magnitude >= 128)
step *= 4;
@Override
protected Vec3 getSouthLocation() {
return VecHelper.voxelSpace(8, 8, 12.5);
}
@Override
protected Vec3 getLocalOffset(BlockState state) {
Direction facing = state.getValue(CreativeMotorBlock.FACING);
return super.getLocalOffset(state).add(Vec3.atLowerCornerOf(facing.getNormal())
.scale(-1 / 16f));
}
@Override
protected void rotate(BlockState state, PoseStack ms) {
super.rotate(state, ms);
Direction facing = state.getValue(CreativeMotorBlock.FACING);
if (facing.getAxis() == Axis.Y)
return;
if (getSide() != Direction.UP)
return;
TransformStack.cast(ms)
.rotateZ(-AngleHelper.horizontalAngle(facing) + 180);
}
@Override
protected boolean isSideActive(BlockState state, Direction direction) {
Direction facing = state.getValue(CreativeMotorBlock.FACING);
if (facing.getAxis() != Axis.Y && direction == Direction.DOWN)
return false;
return direction.getAxis() != facing.getAxis();
}
return (int) (current + (context.forward ? step : -step) == 0 ? step + 1 : step);
}
}

View file

@ -0,0 +1,55 @@
package com.simibubi.create.content.contraptions.components.motor;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.BlockHitResult;
public class KineticScrollValueBehaviour extends ScrollValueBehaviour {
public KineticScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot) {
super(label, be, slot);
withFormatter(v -> String.valueOf(Math.abs(v)));
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
ImmutableList<Component> rows = ImmutableList.of(Components.literal("\u27f3")
.withStyle(ChatFormatting.BOLD),
Components.literal("\u27f2")
.withStyle(ChatFormatting.BOLD));
ValueSettingsFormatter formatter = new ValueSettingsFormatter(this::formatSettings);
return new ValueSettingsBoard(label, 256, 32, rows, formatter);
}
@Override
public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlHeld) {
int value = Math.max(1, valueSetting.value());
if (!valueSetting.equals(getValueSettings()))
playFeedbackSound(this);
setValue(valueSetting.row() == 0 ? -value : value);
}
@Override
public ValueSettings getValueSettings() {
return new ValueSettings(value < 0 ? 0 : 1, Math.abs(value));
}
public MutableComponent formatSettings(ValueSettings settings) {
return Lang.number(Math.max(1, Math.abs(settings.value())))
.add(Lang.text(settings.row() == 0 ? "\u27f3" : "\u27f2")
.style(ChatFormatting.BOLD))
.component();
}
}

View file

@ -15,8 +15,8 @@ public class SawFilterSlot extends ValueBoxTransform {
protected Vec3 getLocalOffset(BlockState state) {
if (state.getValue(SawBlock.FACING) != Direction.UP)
return null;
Vec3 x = VecHelper.voxelSpace(8f, 12.5f, 12.25f);
Vec3 z = VecHelper.voxelSpace(12.25f, 12.5f, 8f);
Vec3 x = VecHelper.voxelSpace(8f, 12.5f, 11f);
Vec3 z = VecHelper.voxelSpace(11f, 12.5f, 8f);
return state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? z : x;
}

View file

@ -40,7 +40,7 @@ public class SteamEngineValueBox extends ValueBoxTransform.Sided {
if (engineFacing.getAxis() == Axis.Y)
recessed ^= state.getValue(SteamEngineBlock.FACING).getAxis() == Axis.X;
Vec3 local = VecHelper.voxelSpace(8, recessed ? 13 : 15, 9);
Vec3 local = VecHelper.voxelSpace(8, recessed ? 12.5 : 14.5, 9);
local = VecHelper.rotateCentered(local, roll, Axis.Z);
local = VecHelper.rotateCentered(local, horizontalAngle, Axis.Y);

View file

@ -7,12 +7,18 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllKeys;
import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.BulkScrollValueBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.config.AllConfigs;
@ -23,17 +29,24 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
public class ChassisBlockEntity extends SmartBlockEntity {
ScrollValueBehaviour range;
public int currentlySelectedRange;
public ChassisBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
@ -41,22 +54,30 @@ public class ChassisBlockEntity extends SmartBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
int max = AllConfigs.server().kinetics.maxChassisRange.get();
range = new BulkScrollValueBehaviour(Lang.translateDirect("generic.range"), this, new CenteredSideValueBoxTransform(),
be -> ((ChassisBlockEntity) be).collectChassisGroup());
range = new ChassisScrollValueBehaviour(Lang.translateDirect("contraptions.chassis.range"), this,
new CenteredSideValueBoxTransform(), be -> ((ChassisBlockEntity) be).collectChassisGroup());
range.requiresWrench();
range.between(1, max);
range
.withClientCallback(
i -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ChassisRangeDisplay.display(this)));
range.value = max / 2;
range.withClientCallback(
i -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ChassisRangeDisplay.display(this)));
range.setValue(max / 2);
range.withFormatter(s -> String.valueOf(currentlySelectedRange));
behaviours.add(range);
currentlySelectedRange = range.getValue();
}
@Override
public void initialize() {
super.initialize();
if (getBlockState().getBlock() instanceof RadialChassisBlock)
range.setLabel(Lang.translateDirect("generic.radius"));
range.setLabel(Lang.translateDirect("contraptions.chassis.radius"));
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
if (clientPacket)
currentlySelectedRange = getRange();
}
public int getRange() {
@ -67,11 +88,12 @@ public class ChassisBlockEntity extends SmartBlockEntity {
if (!(getBlockState().getBlock() instanceof AbstractChassisBlock))
return Collections.emptyList();
return isRadial() ? getIncludedBlockPositionsRadial(forcedMovement, visualize)
: getIncludedBlockPositionsLinear(forcedMovement, visualize);
: getIncludedBlockPositionsLinear(forcedMovement, visualize);
}
protected boolean isRadial() {
return level.getBlockState(worldPosition).getBlock() instanceof RadialChassisBlock;
return level.getBlockState(worldPosition)
.getBlock() instanceof RadialChassisBlock;
}
public List<ChassisBlockEntity> collectChassisGroup() {
@ -149,7 +171,7 @@ public class ChassisBlockEntity extends SmartBlockEntity {
AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock();
Axis axis = state.getValue(AbstractChassisBlock.AXIS);
Direction facing = Direction.get(AxisDirection.POSITIVE, axis);
int chassisRange = visualize ? range.scrollableValue : getRange();
int chassisRange = visualize ? currentlySelectedRange : getRange();
for (int offset : new int[] { 1, -1 }) {
if (offset == -1)
@ -183,7 +205,7 @@ public class ChassisBlockEntity extends SmartBlockEntity {
BlockState state = level.getBlockState(worldPosition);
Axis axis = state.getValue(AbstractChassisBlock.AXIS);
AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock();
int chassisRange = visualize ? range.scrollableValue : getRange();
int chassisRange = visualize ? currentlySelectedRange : getRange();
for (Direction facing : Iterate.directions) {
if (facing.getAxis() == axis)
@ -229,4 +251,46 @@ public class ChassisBlockEntity extends SmartBlockEntity {
return positions;
}
class ChassisScrollValueBehaviour extends BulkScrollValueBehaviour {
public ChassisScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot,
Function<SmartBlockEntity, List<? extends SmartBlockEntity>> groupGetter) {
super(label, be, slot, groupGetter);
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
ImmutableList<Component> rows = ImmutableList.of(Lang.translateDirect("contraptions.chassis.distance"));
ValueSettingsFormatter formatter =
new ValueSettingsFormatter(vs -> new ValueSettings(vs.row(), vs.value() + 1).format());
return new ValueSettingsBoard(label, max - 1, 1, rows, formatter);
}
@Override
@OnlyIn(Dist.CLIENT)
public void newSettingHovered(ValueSettings valueSetting) {
if (!level.isClientSide)
return;
if (!AllKeys.ctrlDown())
currentlySelectedRange = valueSetting.value() + 1;
else
for (SmartBlockEntity be : getBulk())
if (be instanceof ChassisBlockEntity cbe)
cbe.currentlySelectedRange = valueSetting.value() + 1;
ChassisRangeDisplay.display(ChassisBlockEntity.this);
}
@Override
public void setValueSettings(Player player, ValueSettings vs, boolean ctrlHeld) {
super.setValueSettings(player, new ValueSettings(vs.row(), vs.value() + 1), ctrlHeld);
}
@Override
public ValueSettings getValueSettings() {
ValueSettings vs = super.getValueSettings();
return new ValueSettings(vs.row(), vs.value() - 1);
}
}
}

View file

@ -36,10 +36,10 @@ public class ChassisRangeDisplay {
this.be = be;
timer = DISPLAY_TIME;
CreateClient.OUTLINER.showCluster(getOutlineKey(), createSelection(be))
.colored(0xFFFFFF)
.disableNormals()
.lineWidth(1 / 16f)
.withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED);
.colored(0xFFFFFF)
.disableNormals()
.lineWidth(1 / 16f)
.withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED);
}
protected Object getOutlineKey() {
@ -173,7 +173,7 @@ public class ChassisRangeDisplay {
GroupEntry hoveredGroup = new GroupEntry(chassis);
for (ChassisBlockEntity included : hoveredGroup.includedBEs)
CreateClient.OUTLINER.remove(included.getBlockPos());
CreateClient.OUTLINER.remove(Pair.of(included.getBlockPos(), 1));
groupEntries.forEach(entry -> CreateClient.OUTLINER.remove(entry.getOutlineKey()));
groupEntries.clear();

View file

@ -277,7 +277,7 @@ public class CartAssemblerBlockEntity extends SmartBlockEntity implements IDispl
@Override
protected Vec3 getSouthLocation() {
return VecHelper.voxelSpace(8, 8, 18);
return VecHelper.voxelSpace(8, 8, 17.5);
}
}

View file

@ -71,10 +71,15 @@ public class SmartFluidPipeBlockEntity extends SmartBlockEntity {
@Override
protected Vec3 getLocalOffset(BlockState state) {
AttachFace face = state.getValue(SmartFluidPipeBlock.FACE);
float y = face == AttachFace.CEILING ? 0.3f : face == AttachFace.WALL ? 11.3f : 15.3f;
float z = face == AttachFace.CEILING ? 4.6f : face == AttachFace.WALL ? 0.6f : 4.6f;
float y = face == AttachFace.CEILING ? 0.55f : face == AttachFace.WALL ? 11.4f : 15.45f;
float z = face == AttachFace.CEILING ? 4.6f : face == AttachFace.WALL ? 0.55f : 4.625f;
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, y, z), angleY(state), Axis.Y);
}
@Override
protected float getScale() {
return super.getScale() * 1.02f;
}
@Override
protected void rotate(BlockState state, PoseStack ms) {

View file

@ -123,8 +123,7 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this));
filtering = new FilteringBehaviour(this, new BasinValueBox()).moveText(new Vec3(2, -8, 0))
.withCallback(newFilter -> contentsChanged = true)
filtering = new FilteringBehaviour(this, new BasinValueBox()).withCallback(newFilter -> contentsChanged = true)
.forRecipes();
behaviours.add(filtering);
@ -194,7 +193,7 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
visualizedOutputItems.clear();
visualizedOutputFluids.clear();
}
@Override
public void destroy() {
super.destroy();
@ -202,7 +201,7 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
ItemHelper.dropContents(level, worldPosition, outputInventory);
spoutputBuffer.forEach(is -> Block.popResource(level, worldPosition, is));
}
@Override
public void remove() {
super.remove();
@ -212,7 +211,7 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
public void onEmptied() {
getOperator().ifPresent(be -> be.basinRemoved = true);
}
@Override
public void invalidate() {
super.invalidate();
@ -740,7 +739,7 @@ public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
@Override
protected Vec3 getSouthLocation() {
return VecHelper.voxelSpace(8, 12, 15.75);
return VecHelper.voxelSpace(8, 12, 16.05);
}
@Override

View file

@ -4,7 +4,7 @@ import java.util.List;
import com.simibubi.create.content.contraptions.RotationPropagator;
import com.simibubi.create.content.contraptions.base.KineticBlockEntity;
import com.simibubi.create.content.contraptions.components.motor.CreativeMotorBlockEntity;
import com.simibubi.create.content.contraptions.components.motor.KineticScrollValueBehaviour;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
import com.simibubi.create.foundation.advancement.AllAdvancements;
@ -44,16 +44,13 @@ public class SpeedControllerBlockEntity extends KineticBlockEntity {
super.addBehaviours(behaviours);
Integer max = AllConfigs.server().kinetics.maxRotationSpeed.get();
targetSpeed =
new ScrollValueBehaviour(Lang.translateDirect("generic.speed"), this, new ControllerValueBoxTransform());
targetSpeed = new KineticScrollValueBehaviour(Lang.translateDirect("kinetics.speed_controller.rotation_speed"),
this, new ControllerValueBoxTransform());
targetSpeed.between(-max, max);
targetSpeed.value = DEFAULT_SPEED;
targetSpeed.moveText(new Vec3(9, 0, 10));
targetSpeed.withUnit(i -> Lang.translateDirect("generic.unit.rpm"));
targetSpeed.withCallback(i -> this.updateTargetRotation());
targetSpeed.withStepFunction(CreativeMotorBlockEntity::step);
behaviours.add(targetSpeed);
registerAwardables(behaviours, AllAdvancements.SPEED_CONTROLLER);
}
@ -63,7 +60,7 @@ public class SpeedControllerBlockEntity extends KineticBlockEntity {
RotationPropagator.handleRemoved(level, worldPosition, this);
removeSource();
attachKinetics();
if (isCogwheelPresent() && getSpeed() != 0)
award(AllAdvancements.SPEED_CONTROLLER);
}
@ -124,14 +121,15 @@ public class SpeedControllerBlockEntity extends KineticBlockEntity {
private boolean isCogwheelPresent() {
BlockState stateAbove = level.getBlockState(worldPosition.above());
return ICogWheel.isDedicatedCogWheel(stateAbove.getBlock()) && ICogWheel.isLargeCog(stateAbove)
&& stateAbove.getValue(CogWheelBlock.AXIS).isHorizontal();
&& stateAbove.getValue(CogWheelBlock.AXIS)
.isHorizontal();
}
private class ControllerValueBoxTransform extends ValueBoxTransform.Sided {
@Override
protected Vec3 getSouthLocation() {
return VecHelper.voxelSpace(8, 11f, 16);
return VecHelper.voxelSpace(8, 11f, 15.5f);
}
@Override
@ -144,7 +142,7 @@ public class SpeedControllerBlockEntity extends KineticBlockEntity {
@Override
protected float getScale() {
return 0.275f;
return 0.5f;
}
}

View file

@ -32,7 +32,7 @@ public class SmartChuteBlockEntity extends ChuteBlockEntity {
@Override
protected ExtractionCountMode getExtractionMode() {
return filtering.isCountVisible() && !filtering.anyAmount() ? ExtractionCountMode.EXACTLY
return filtering.isCountVisible() && !filtering.anyAmount() && !filtering.upTo ? ExtractionCountMode.EXACTLY
: ExtractionCountMode.UPTO;
}

View file

@ -36,6 +36,11 @@ public class BrassDiodeBlock extends AbstractDiodeBlock implements IBE<BrassDiod
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player player, InteractionHand pHand,
BlockHitResult pHit) {
return toggle(pLevel, pPos, pState, player, pHand);
}
public InteractionResult toggle(Level pLevel, BlockPos pPos, BlockState pState, Player player,
InteractionHand pHand) {
if (!player.mayBuild())
return InteractionResult.PASS;
if (player.isShiftKeyDown())

View file

@ -7,12 +7,10 @@ import java.util.List;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
@ -29,12 +27,11 @@ public abstract class BrassDiodeBlockEntity extends SmartBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
maxState = new ScrollValueBehaviour(Lang.translateDirect("generic.delay"), this, new BrassDiodeScrollSlot())
.between(2, 60 * 20 * 30);
maxState.withStepFunction(this::step);
maxState = new BrassDiodeScrollValueBehaviour(Lang.translateDirect("logistics.redstone_interval"), this,
new BrassDiodeScrollSlot()).between(2, 60 * 20 * 60);
maxState.withFormatter(this::format);
maxState.withUnit(this::getUnit);
maxState.withCallback(this::onMaxDelayChanged);
maxState.setValue(2);
behaviours.add(maxState);
}
@ -76,32 +73,12 @@ public abstract class BrassDiodeBlockEntity extends SmartBlockEntity {
super.write(compound, clientPacket);
}
private int step(StepContext context) {
int value = context.currentValue;
if (!context.forward)
value--;
if (value < 20)
return 1;
if (value < 20 * 60)
return 20;
return 20 * 60;
}
private String format(int value) {
if (value < 20)
if (value < 60)
return value + "t";
if (value < 20 * 60)
return (value / 20) + "s";
return (value / 20 / 60) + "m";
}
private Component getUnit(int value) {
if (value < 20)
return Lang.translateDirect("generic.unit.ticks");
if (value < 20 * 60)
return Lang.translateDirect("generic.unit.seconds");
return Lang.translateDirect("generic.unit.minutes");
}
}

View file

@ -14,7 +14,7 @@ public class BrassDiodeScrollSlot extends ValueBoxTransform {
@Override
protected Vec3 getLocalOffset(BlockState state) {
return VecHelper.voxelSpace(8, 3f, 8);
return VecHelper.voxelSpace(8, 2.6f, 8);
}
@Override

View file

@ -0,0 +1,77 @@
package com.simibubi.create.content.logistics.block.diodes;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
public class BrassDiodeScrollValueBehaviour extends ScrollValueBehaviour {
public BrassDiodeScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot) {
super(label, be, slot);
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
return new ValueSettingsBoard(label, 60, 10,
Lang.translatedOptions("generic.unit", "ticks", "seconds", "minutes"),
new ValueSettingsFormatter(this::formatSettings));
}
@Override
public void onShortInteract(Player player, InteractionHand hand, Direction side) {
BlockState blockState = blockEntity.getBlockState();
if (blockState.getBlock()instanceof BrassDiodeBlock bdb)
bdb.toggle(getWorld(), getPos(), blockState, player, hand);
}
@Override
public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlHeld) {
int value = valueSetting.value();
int multiplier = switch (valueSetting.row()) {
case 0 -> 1;
case 1 -> 20;
default -> 60 * 20;
};
if (!valueSetting.equals(getValueSettings()))
playFeedbackSound(this);
setValue(Math.max(2, Math.max(1, value) * multiplier));
}
@Override
public ValueSettings getValueSettings() {
int row = 0;
int value = this.value;
if (value > 60 * 20) {
value = value / (60 * 20);
row = 2;
} else if (value > 60) {
value = value / 20;
row = 1;
}
return new ValueSettings(row, value);
}
public MutableComponent formatSettings(ValueSettings settings) {
int value = Math.max(1, settings.value());
return Components.literal(switch (settings.row()) {
case 0 -> Math.max(2, value) + "t";
case 1 -> "0:" + (value < 10 ? "0" : "") + value;
default -> value + ":00";
});
}
}

View file

@ -19,6 +19,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.belt.DirectBeltInput
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.VecHelper;
@ -74,7 +75,8 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
BeltBlockEntity belt = BeltHelper.getSegmentBE(level, worldPosition.below());
if (belt != null)
return belt.getMovementFacing() == state.getValue(BeltFunnelBlock.HORIZONTAL_FACING) ? Mode.PUSHING_TO_BELT
return belt.getMovementFacing() == state.getValue(BeltFunnelBlock.HORIZONTAL_FACING)
? Mode.PUSHING_TO_BELT
: Mode.TAKING_FROM_BELT;
return Mode.INVALID;
}
@ -136,8 +138,9 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
// Find other entities blocking the extract (only if necessary)
int amountToExtract = getAmountToExtract();
ExtractionCountMode mode = getModeToExtract();
ItemStack stack = invManipulation.simulate()
.extract(amountToExtract);
.extract(mode, amountToExtract);
if (stack.isEmpty())
return;
for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) {
@ -146,7 +149,7 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
}
// Extract
stack = invManipulation.extract(amountToExtract);
stack = invManipulation.extract(mode, amountToExtract);
if (stack.isEmpty())
return;
@ -176,8 +179,7 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
startCooldown();
}
static final AABB coreBB =
new AABB(VecHelper.CENTER_OF_ORIGIN, VecHelper.CENTER_OF_ORIGIN).inflate(.75f);
static final AABB coreBB = new AABB(VecHelper.CENTER_OF_ORIGIN, VecHelper.CENTER_OF_ORIGIN).inflate(.75f);
private AABB getEntityOverflowScanningArea() {
Direction facing = AbstractFunnelBlock.getFunnelFacing(getBlockState());
@ -199,8 +201,10 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
return;
int amountToExtract = getAmountToExtract();
ItemStack stack = invManipulation.extract(amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true)
.isEmpty());
ExtractionCountMode mode = getModeToExtract();
ItemStack stack =
invManipulation.extract(mode, amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true)
.isEmpty());
if (stack.isEmpty())
return;
flap(false);
@ -211,13 +215,19 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
public int getAmountToExtract() {
if (!supportsAmountOnFilter())
return -1;
return 64;
int amountToExtract = invManipulation.getAmountFromFilter();
if (!filtering.isActive())
amountToExtract = 1;
return amountToExtract;
}
public ExtractionCountMode getModeToExtract() {
if (!supportsAmountOnFilter() || !filtering.isActive())
return ExtractionCountMode.UPTO;
return invManipulation.getModeFromFilter();
}
private int startCooldown() {
return extractionCooldown = AllConfigs.server().logistics.defaultExtractionTimer.get();
}
@ -284,7 +294,8 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
public void flap(boolean inward) {
if (!level.isClientSide) {
AllPackets.getChannel().send(packetTarget(), new FunnelFlapPacket(this, inward));
AllPackets.getChannel()
.send(packetTarget(), new FunnelFlapPacket(this, inward));
} else {
flap.setValue(inward ? 1 : -1);
AllSoundEvents.FUNNEL_FLAP.playAt(level, worldPosition, 1, 1, true);
@ -336,7 +347,7 @@ public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHovering
.onFunnelTransfer(level, worldPosition, stack);
award(AllAdvancements.FUNNEL);
}
private LerpedFloat createChasingFlap() {
return LerpedFloat.linear()
.startWithValue(.25f)

View file

@ -28,7 +28,7 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided {
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 15.5f, 13), stateAngle, Axis.Y);
case PULLING:
case PUSHING:
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y);
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.0f, 8.675f), horizontalAngle, Axis.Y);
default:
case RETRACTED:
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 13, 7.5f), horizontalAngle, Axis.Y);
@ -41,7 +41,7 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided {
return VecHelper.rotateCentered(southLocation, horizontalAngle, Axis.Y);
}
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y);
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.2, 8.55f), horizontalAngle, Axis.Y);
}
@Override

View file

@ -5,7 +5,6 @@ import java.util.List;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper;
import net.minecraft.core.BlockPos;
@ -74,11 +73,13 @@ public class FunnelMovementBehaviour implements MovementBehaviour {
ItemStack filter = getFilter(context);
int filterAmount = context.blockEntityData.getInt("FilterAmount");
boolean upTo = context.blockEntityData.getBoolean("UpTo");
if (filterAmount <= 0)
filterAmount = hasFilter ? AllConfigs.server().logistics.defaultExtractionLimit.get() : 1;
filterAmount = hasFilter ? 64 : 1;
ItemStack extract = ItemHelper.extract(context.contraption.getSharedInventory(),
s -> FilterItem.test(world, s, filter), ItemHelper.ExtractionCountMode.UPTO, filterAmount, false);
s -> FilterItem.test(world, s, filter),
upTo ? ItemHelper.ExtractionCountMode.UPTO : ItemHelper.ExtractionCountMode.EXACTLY, filterAmount, false);
if (extract.isEmpty())
return;

View file

@ -7,6 +7,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -33,6 +34,7 @@ public class CreativeCrateBlockEntity extends CrateBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(filtering = createFilter());
filtering.setLabel(Lang.translateDirect("logistics.creative_crate.supply"));
}
@Override
@ -60,11 +62,11 @@ public class CreativeCrateBlockEntity extends CrateBlockEntity {
@Override
protected Vec3 getLocalOffset(BlockState state) {
return new Vec3(0.5, 13 / 16d, 0.5);
return new Vec3(0.5, 13.5 / 16d, 0.5);
}
protected float getScale() {
return super.getScale() * 1.5f;
return super.getScale();
};
});

View file

@ -598,14 +598,14 @@ public class ArmBlockEntity extends KineticBlockEntity implements ITransformable
@Override
protected Vec3 getLocalOffset(BlockState state) {
int yPos = state.getValue(ArmBlock.CEILING) ? 16 - 3 : 3;
Vec3 location = VecHelper.voxelSpace(8, yPos, 15.95);
Vec3 location = VecHelper.voxelSpace(8, yPos, 15.5);
location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Direction.Axis.Y);
return location;
}
@Override
protected float getScale() {
return .3f;
return super.getScale();
}
}

View file

@ -19,7 +19,6 @@ import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class ContentObserverBlockEntity extends SmartBlockEntity {
@ -36,7 +35,7 @@ public class ContentObserverBlockEntity extends SmartBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot()).moveText(new Vec3(0, 5, 0));
filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot());
behaviours.add(filtering);
InterfaceProvider towardBlockFacing = InterfaceProvider.towardBlockFacing();

View file

@ -20,7 +20,6 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.ticks.TickPriority;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
@ -101,10 +100,10 @@ public class StockpileSwitchBlockEntity extends SmartBlockEntity {
if (targetBlockEntity instanceof StockpileSwitchObservable observable) {
currentLevel = observable.getPercent() / 100f;
} else if (StorageDrawers.isDrawer(targetBlockEntity) && observedInventory.hasInventory()) {
currentLevel = StorageDrawers.getTrueFillLevel(observedInventory.getInventory(), filtering);
} else if (observedInventory.hasInventory() || observedTank.hasInventory()) {
if (observedInventory.hasInventory()) {
// Item inventory
@ -154,7 +153,7 @@ public class StockpileSwitchBlockEntity extends SmartBlockEntity {
currentLevel = Mth.clamp(currentLevel, 0, 1);
changed = currentLevel != prevLevel;
boolean previouslyPowered = redstoneState;
if (redstoneState && currentLevel <= offWhenBelow)
redstoneState = false;
@ -194,8 +193,8 @@ public class StockpileSwitchBlockEntity extends SmartBlockEntity {
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot()).moveText(new Vec3(0, 5, 0))
.withCallback($ -> updateCurrentLevel());
filtering =
new FilteringBehaviour(this, new FilteredDetectorFilterSlot()).withCallback($ -> updateCurrentLevel());
behaviours.add(filtering);
InterfaceProvider towardBlockFacing = InterfaceProvider.towardBlockFacing();

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
@ -37,6 +38,7 @@ public class TrackObserverBlockEntity extends SmartBlockEntity implements ITrans
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.OBSERVER));
behaviours.add(filtering = createFilter().withCallback(this::onFilterChanged));
filtering.setLabel(Lang.translateDirect("logistics.train_observer.cargo_filter"));
}
private void onFilterChanged(ItemStack newFilter) {
@ -102,13 +104,9 @@ public class TrackObserverBlockEntity extends SmartBlockEntity implements ITrans
@Override
protected Vec3 getLocalOffset(BlockState state) {
return new Vec3(0.5, 15 / 16d, 0.5);
return new Vec3(0.5, 15.5 / 16d, 0.5);
}
protected float getScale() {
return super.getScale() * 1.5f;
};
});
}

View file

@ -112,7 +112,6 @@ public class ClientEvents {
SoundScapes.tick();
AnimationTickHolder.tick();
ScrollValueHandler.tick();
CreateClient.SCHEMATIC_SENDER.tick();
CreateClient.SCHEMATIC_AND_QUILL_HANDLER.tick();
@ -160,6 +159,8 @@ public class ClientEvents {
CameraDistanceModifier.tick();
CameraAngleAnimationService.tick();
TrainHUD.tick();
CreateClient.VALUE_SETTINGS_HANDLER.tick();
ScrollValueHandler.tick();
}
@SubscribeEvent

View file

@ -7,8 +7,6 @@ import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient;
import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler;
import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringHandler;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueHandler;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
@ -43,8 +41,7 @@ public class InputEvents {
double delta = event.getScrollDelta();
// CollisionDebugger.onScroll(delta);
boolean cancelled = CreateClient.SCHEMATIC_HANDLER.mouseScrolled(delta)
|| CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|| ScrollValueHandler.onScroll(delta) || TrainHUD.onScroll(delta)
|| CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || TrainHUD.onScroll(delta)
|| ElevatorControlsHandler.onScroll(delta);
event.setCanceled(cancelled);
}

View file

@ -1,6 +1,7 @@
package com.simibubi.create.foundation.blockEntity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -26,7 +27,8 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity implements IPartialSafeNBT, IInteractionChecker, ISpecialBlockEntityItemRequirement {
public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity
implements IPartialSafeNBT, IInteractionChecker, ISpecialBlockEntityItemRequirement {
private final Map<BehaviourType<?>, BlockEntityBehaviour> behaviours = new HashMap<>();
private boolean initialized = false;
@ -51,8 +53,8 @@ public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity impleme
public abstract void addBehaviours(List<BlockEntityBehaviour> behaviours);
/**
* Gets called just before reading block entity data for behaviours. Register anything
* here that depends on your custom BE data.
* Gets called just before reading block entity data for behaviours. Register
* anything here that depends on your custom BE data.
*/
public void addBehavioursDeferred(List<BlockEntityBehaviour> behaviours) {}
@ -173,9 +175,12 @@ public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity impleme
return (T) behaviours.get(type);
}
protected void forEachBehaviour(Consumer<BlockEntityBehaviour> action) {
behaviours.values()
.forEach(action);
public void forEachBehaviour(Consumer<BlockEntityBehaviour> action) {
getAllBehaviours().forEach(action);
}
public Collection<BlockEntityBehaviour> getAllBehaviours() {
return behaviours.values();
}
protected void attachBehaviourLate(BlockEntityBehaviour behaviour) {
@ -184,8 +189,7 @@ public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity impleme
}
public ItemRequirement getRequiredItems(BlockState state) {
return behaviours.values()
.stream()
return getAllBehaviours().stream()
.reduce(ItemRequirement.NONE, (r, b) -> r.union(b.getRequiredItems()), (r, r1) -> r.union(r1));
}
@ -208,7 +212,7 @@ public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity impleme
public boolean isVirtual() {
return virtualMode;
}
public boolean isChunkUnloaded() {
return chunkUnloaded;
}

View file

@ -22,7 +22,7 @@ public class CenteredSideValueBoxTransform extends ValueBoxTransform.Sided {
@Override
protected Vec3 getSouthLocation() {
return VecHelper.voxelSpace(8, 8, 16);
return VecHelper.voxelSpace(8, 8, 15.5);
}
@Override

View file

@ -6,21 +6,22 @@ import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Si
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.INamedIconOptions;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Color;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.outliner.ChasingAABBOutline;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.model.ItemMultiLayerBakedModel;
public class ValueBox extends ChasingAABBOutline {
@ -37,10 +38,12 @@ public class ValueBox extends ChasingAABBOutline {
protected ValueBoxTransform transform;
protected BlockState blockState;
protected AllIcons outline = AllIcons.VALUE_BOX_HOVER_4PX;
public ValueBox(Component label, AABB bb, BlockPos pos) {
this(label, bb, pos, Minecraft.getInstance().level.getBlockState(pos));
}
public ValueBox(Component label, AABB bb, BlockPos pos, BlockState state) {
super(bb);
this.label = label;
@ -53,24 +56,8 @@ public class ValueBox extends ChasingAABBOutline {
return this;
}
public ValueBox offsetLabel(Vec3 offset) {
this.labelOffset = offset;
return this;
}
public ValueBox subLabel(Component sublabel) {
this.sublabel = sublabel;
return this;
}
public ValueBox scrollTooltip(Component scrollTip) {
this.scrollTooltip = scrollTip;
return this;
}
public ValueBox withColors(int passive, int highlight) {
this.passiveColor = passive;
this.highlightColor = highlight;
public ValueBox wideOutline() {
this.outline = AllIcons.VALUE_BOX_HOVER_6PX;
return this;
}
@ -94,69 +81,82 @@ public class ValueBox extends ChasingAABBOutline {
transformNormals = ms.last()
.normal()
.copy();
params.colored(isPassive ? passiveColor : highlightColor);
super.render(ms, buffer, pt);
float fontScale = hasTransform ? -transform.getFontScale() : -1 / 64f;
ms.scale(fontScale, fontScale, fontScale);
ms.pushPose();
renderContents(ms, buffer);
ms.popPose();
if (!isPassive) {
ms.pushPose();
ms.translate(17.5, -.5, 7);
ms.translate(labelOffset.x, labelOffset.y, labelOffset.z);
renderHoveringText(ms, buffer, label);
if (!sublabel.getString().isEmpty()) {
ms.translate(0, 10, 0);
renderHoveringText(ms, buffer, sublabel);
}
if (!scrollTooltip.getString().isEmpty()) {
ms.translate(0, 10, 0);
renderHoveringText(ms, buffer, scrollTooltip, 0x998899, 0x111111);
}
ms.scale(-2.01f, -2.01f, 2.01f);
ms.translate(-8 / 16.0, -8 / 16.0, -.5 / 16.0);
getOutline().render(ms, buffer, 0xffffff);
ms.popPose();
}
float fontScale = hasTransform ? -transform.getFontScale() : -1 / 64f;
ms.scale(fontScale, fontScale, fontScale);
renderContents(ms, buffer);
ms.popPose();
}
public AllIcons getOutline() {
return outline;
}
public void renderContents(PoseStack ms, MultiBufferSource buffer) {}
public static class ItemValueBox extends ValueBox {
ItemStack stack;
int count;
boolean upTo;
public ItemValueBox(Component label, AABB bb, BlockPos pos, ItemStack stack, int count) {
public ItemValueBox(Component label, AABB bb, BlockPos pos, ItemStack stack, int count, boolean upTo) {
super(label, bb, pos);
this.stack = stack;
this.count = count;
this.upTo = upTo;
}
@Override
public AllIcons getOutline() {
if (stack.getItem() instanceof FilterItem)
return AllIcons.VALUE_BOX_HOVER_8PX;
if (!stack.isEmpty())
return AllIcons.VALUE_BOX_HOVER_6PX;
return super.getOutline();
}
@Override
public void renderContents(PoseStack ms, MultiBufferSource buffer) {
super.renderContents(ms, buffer);
if (count == -1)
return;
Font font = Minecraft.getInstance().font;
Component countString = Components.literal(count == 0 ? "*" : count + "");
boolean wildcard = count == 0 || upTo && count == stack.getMaxStackSize();
Component countString = Components.literal(wildcard ? "*" : count + "");
ms.translate(17.5f, -5f, 7f);
boolean isFilter = stack.getItem() instanceof FilterItem;
boolean isEmpty = stack.isEmpty();
ItemRenderer itemRenderer = Minecraft.getInstance()
.getItemRenderer();
BakedModel modelWithOverrides = itemRenderer.getModel(stack, null, null, 0);
boolean blockItem =
modelWithOverrides.isGui3d() && !(modelWithOverrides instanceof ItemMultiLayerBakedModel);
float scale = 1.5f;
ms.translate(-font.width(countString), 0, 0);
if (isFilter)
ms.translate(3, 8, 7.25f);
ms.translate(-5, 8, 7.25f);
else if (isEmpty) {
ms.translate(-17, -2, 3f);
scale = 2f;
}
else
ms.translate(-7, 10, 10 + 1 / 4f);
ms.translate(-15, -1f, -2.75f);
scale = 1.65f;
} else
ms.translate(-7, 10, blockItem ? 10 + 1 / 4f : 0);
if (wildcard)
ms.translate(-1, 3f, 0);
ms.scale(scale, scale, scale);
drawString(ms, buffer, countString, 0, 0, isFilter ? 0xFFFFFF : 0xEDEDED);
@ -173,7 +173,7 @@ public class ValueBox extends ChasingAABBOutline {
super(label, bb, pos);
this.text = text;
}
public TextValueBox(Component label, AABB bb, BlockPos pos, BlockState state, Component text) {
super(label, bb, pos, state);
this.text = text;
@ -183,7 +183,7 @@ public class ValueBox extends ChasingAABBOutline {
public void renderContents(PoseStack ms, MultiBufferSource buffer) {
super.renderContents(ms, buffer);
Font font = Minecraft.getInstance().font;
float scale = 4;
float scale = 3;
ms.scale(scale, scale, 1);
ms.translate(-4, -4, 5);
@ -207,27 +207,20 @@ public class ValueBox extends ChasingAABBOutline {
public IconValueBox(Component label, INamedIconOptions iconValue, AABB bb, BlockPos pos) {
super(label, bb, pos);
subLabel(Lang.translateDirect(iconValue.getTranslationKey()));
icon = iconValue.getIcon();
}
@Override
public void renderContents(PoseStack ms, MultiBufferSource buffer) {
super.renderContents(ms, buffer);
float scale = 4 * 16;
float scale = 2 * 16;
ms.scale(scale, scale, scale);
ms.translate(-.5f, -.5f, 1 / 32f);
ms.translate(-.5f, -.5f, 5 / 32f);
icon.render(ms, buffer, 0xFFFFFF);
}
}
// util
protected void renderHoveringText(PoseStack ms, MultiBufferSource buffer, Component text) {
renderHoveringText(ms, buffer, text, highlightColor, Color.mixColors(passiveColor, 0, 0.75f));
}
protected void renderHoveringText(PoseStack ms, MultiBufferSource buffer, Component text, int color,
int shadowColor) {
ms.pushPose();
@ -237,7 +230,8 @@ public class ValueBox extends ChasingAABBOutline {
ms.popPose();
}
private static void drawString(PoseStack ms, MultiBufferSource buffer, Component text, float x, float y, int color) {
private static void drawString(PoseStack ms, MultiBufferSource buffer, Component text, float x, float y,
int color) {
Minecraft.getInstance().font.drawInBatch(text, x, y, color, false, ms.last()
.pose(), buffer, false, 0, LightTexture.FULL_BRIGHT);
}

View file

@ -30,8 +30,8 @@ public class ValueBoxRenderer {
.getItemRenderer();
BakedModel modelWithOverrides = itemRenderer.getModel(filter, null, null, 0);
boolean blockItem = modelWithOverrides.isGui3d() && !(modelWithOverrides instanceof ItemMultiLayerBakedModel);
float scale = (!blockItem ? .5f : 1f) - 1 / 64f;
float zOffset = (!blockItem ? -.225f : 0) + customZOffset(filter.getItem());
float scale = (!blockItem ? .5f : 1f) + 1 / 64f;
float zOffset = (!blockItem ? -.15f : 0) + customZOffset(filter.getItem());
ms.scale(scale, scale, scale);
ms.translate(0, 0, zOffset);
itemRenderer.renderStatic(filter, TransformType.FIXED, light, overlay, ms, buffer, 0);

View file

@ -54,7 +54,7 @@ public abstract class ValueBoxTransform {
}
protected float getScale() {
return .4f;
return .5f;
}
protected float getFontScale() {

View file

@ -0,0 +1,57 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
public interface ValueSettingsBehaviour {
public static record ValueSettings(int row, int value) {
public MutableComponent format() {
return Lang.number(value)
.component();
}
};
public boolean testHit(Vec3 hit);
public boolean isActive();
default boolean onlyVisibleWithWrench() {
return false;
}
default void newSettingHovered(ValueSettings valueSetting) {}
public ValueBoxTransform getSlotPositioning();
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult);
public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown);
public ValueSettings getValueSettings();
default boolean acceptsValueSettings() {
return true;
}
default void playFeedbackSound(BlockEntityBehaviour origin) {
origin.getWorld()
.playSound(null, origin.getPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.25f, 2f);
origin.getWorld()
.playSound(null, origin.getPos(), SoundEvents.NOTE_BLOCK_IRON_XYLOPHONE, SoundSource.BLOCKS, 0.03f, 1.125f);
}
default void onShortInteract(Player player, InteractionHand hand, Direction side) {}
}

View file

@ -0,0 +1,9 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import java.util.List;
import net.minecraft.network.chat.Component;
public record ValueSettingsBoard(Component title, int maxValue, int milestoneInterval, List<Component> rows,
ValueSettingsFormatter formatter) {
}

View file

@ -0,0 +1,143 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import java.util.List;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.gui.ScreenOpener;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Color;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.client.gui.ForgeIngameGui;
import net.minecraftforge.client.gui.IIngameOverlay;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
public class ValueSettingsClient implements IIngameOverlay {
private Minecraft mc;
public int interactHeldTicks = -1;
public BlockPos interactHeldPos = null;
public BehaviourType<?> interactHeldBehaviour = null;
public InteractionHand interactHeldHand = null;
public Direction interactHeldFace = null;
public List<MutableComponent> lastHoverTip;
public int hoverTicks;
public int hoverWarmup;
public ValueSettingsClient() {
mc = Minecraft.getInstance();
}
public void cancelIfWarmupAlreadyStarted(PlayerInteractEvent.RightClickBlock event) {
if (interactHeldTicks != -1 && event.getPos()
.equals(interactHeldPos)) {
event.setCanceled(true);
event.setCancellationResult(InteractionResult.FAIL);
}
}
public void startInteractionWith(BlockPos pos, BehaviourType<?> behaviourType, InteractionHand hand,
Direction side) {
interactHeldTicks = 0;
interactHeldPos = pos;
interactHeldBehaviour = behaviourType;
interactHeldHand = hand;
interactHeldFace = side;
}
public void cancelInteraction() {
interactHeldTicks = -1;
}
public void tick() {
if (hoverWarmup > 0)
hoverWarmup--;
if (hoverTicks > 0)
hoverTicks--;
if (interactHeldTicks == -1)
return;
Player player = mc.player;
if (!ValueSettingsInputHandler.canInteract(player)) {
cancelInteraction();
return;
}
HitResult hitResult = mc.hitResult;
if (!(hitResult instanceof BlockHitResult blockHitResult) || !blockHitResult.getBlockPos()
.equals(interactHeldPos)) {
cancelInteraction();
return;
}
BlockEntityBehaviour behaviour = BlockEntityBehaviour.get(mc.level, interactHeldPos, interactHeldBehaviour);
if (!(behaviour instanceof ValueSettingsBehaviour valueSettingBehaviour)
|| !valueSettingBehaviour.testHit(blockHitResult.getLocation())) {
cancelInteraction();
return;
}
if (!mc.options.keyUse.isDown()) {
AllPackets.getChannel()
.sendToServer(
new ValueSettingsPacket(interactHeldPos, 0, 0, interactHeldHand, interactHeldFace, false));
cancelInteraction();
return;
}
if (interactHeldTicks > 3)
player.swinging = false;
if (interactHeldTicks++ < 5)
return;
ScreenOpener
.open(new ValueSettingsScreen(interactHeldPos, valueSettingBehaviour.createBoard(player, blockHitResult),
valueSettingBehaviour.getValueSettings(), valueSettingBehaviour::newSettingHovered));
interactHeldTicks = -1;
}
public void showHoverTip(List<MutableComponent> tip) {
if (mc.screen != null)
return;
if (hoverWarmup < 6) {
hoverWarmup += 2;
return;
} else
hoverWarmup++;
hoverTicks = hoverTicks == 0 ? 11 : Math.max(hoverTicks, 6);
lastHoverTip = tip;
}
@Override
public void render(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, int height) {
Minecraft mc = Minecraft.getInstance();
if (mc.options.hideGui || !ValueSettingsInputHandler.canInteract(mc.player))
return;
if (hoverTicks == 0 || lastHoverTip == null)
return;
int x = width / 2;
int y = height - 93;
float alpha = hoverTicks > 5 ? (11 - hoverTicks) / 5f : Math.min(1, hoverTicks / 5f);
Color color = new Color(0xffffff);
Color titleColor = new Color(0xFBDC7D);
color.setAlpha(alpha);
titleColor.setAlpha(alpha);
for (int i = 0; i < lastHoverTip.size(); i++) {
MutableComponent mutableComponent = lastHoverTip.get(i);
mc.font.drawShadow(poseStack, mutableComponent, x - mc.font.width(mutableComponent) / 2, y,
(i == 0 ? titleColor : color).getRGB());
y += 12;
}
}
}

View file

@ -0,0 +1,39 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import java.util.function.Function;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.INamedIconOptions;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.network.chat.MutableComponent;
public class ValueSettingsFormatter {
private Function<ValueSettings, MutableComponent> formatter;
public ValueSettingsFormatter(Function<ValueSettings, MutableComponent> formatter) {
this.formatter = formatter;
}
public MutableComponent format(ValueSettings valueSettings) {
return formatter.apply(valueSettings);
}
public static class ScrollOptionSettingsFormatter extends ValueSettingsFormatter {
private INamedIconOptions[] options;
public ScrollOptionSettingsFormatter(INamedIconOptions[] options) {
super(v -> Lang.translateDirect(options[v.value()].getTranslationKey()));
this.options = options;
}
public AllIcons getIcon(ValueSettings valueSettings) {
return options[valueSettings.value()].getIcon();
}
}
}

View file

@ -0,0 +1,90 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import com.simibubi.create.AllTags.AllItemTags;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.SidedFilteringBehaviour;
import com.simibubi.create.foundation.utility.RaycastHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber
public class ValueSettingsInputHandler {
@SubscribeEvent
public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) {
Level world = event.getWorld();
BlockPos pos = event.getPos();
Player player = event.getPlayer();
InteractionHand hand = event.getHand();
if (!canInteract(player))
return;
if (!(world.getBlockEntity(pos)instanceof SmartBlockEntity sbe))
return;
if (event.getSide() == LogicalSide.CLIENT)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
() -> () -> CreateClient.VALUE_SETTINGS_HANDLER.cancelIfWarmupAlreadyStarted(event));
if (event.isCanceled())
return;
for (BlockEntityBehaviour behaviour : sbe.getAllBehaviours()) {
if (!(behaviour instanceof ValueSettingsBehaviour valueSettingsBehaviour))
continue;
BlockHitResult ray = RaycastHelper.rayTraceRange(world, player, 10);
if (ray == null)
return;
if (behaviour instanceof SidedFilteringBehaviour) {
behaviour = ((SidedFilteringBehaviour) behaviour).get(ray.getDirection());
if (behaviour == null)
continue;
}
if (!valueSettingsBehaviour.isActive())
continue;
if (valueSettingsBehaviour.onlyVisibleWithWrench()
&& !AllItemTags.WRENCH.matches(player.getItemInHand(hand)))
continue;
if (valueSettingsBehaviour.getSlotPositioning()instanceof ValueBoxTransform.Sided sidedSlot)
sidedSlot.fromSide(ray.getDirection());
if (!valueSettingsBehaviour.testHit(ray.getLocation()))
continue;
event.setCanceled(true);
event.setCancellationResult(InteractionResult.SUCCESS);
if (!valueSettingsBehaviour.acceptsValueSettings()) {
valueSettingsBehaviour.onShortInteract(player, hand, ray.getDirection());
return;
}
if (event.getSide() == LogicalSide.CLIENT) {
BehaviourType<?> type = behaviour.getType();
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.VALUE_SETTINGS_HANDLER
.startInteractionWith(pos, type, hand, ray.getDirection()));
}
return;
}
}
public static boolean canInteract(Player player) {
return player != null && !player.isSpectator() && !player.isShiftKeyDown();
}
}

View file

@ -0,0 +1,78 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import javax.annotation.Nullable;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings;
import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
public class ValueSettingsPacket extends BlockEntityConfigurationPacket<SmartBlockEntity> {
private int row;
private int value;
private InteractionHand interactHand;
private Direction side;
private boolean ctrlDown;
public ValueSettingsPacket(BlockPos pos, int row, int value, @Nullable InteractionHand interactHand, Direction side,
boolean ctrlDown) {
super(pos);
this.row = row;
this.value = value;
this.interactHand = interactHand;
this.side = side;
this.ctrlDown = ctrlDown;
}
public ValueSettingsPacket(FriendlyByteBuf buffer) {
super(buffer);
}
@Override
protected void writeSettings(FriendlyByteBuf buffer) {
buffer.writeVarInt(value);
buffer.writeVarInt(row);
buffer.writeBoolean(interactHand != null);
if (interactHand != null)
buffer.writeBoolean(interactHand == InteractionHand.MAIN_HAND);
buffer.writeVarInt(side.ordinal());
buffer.writeBoolean(ctrlDown);
}
@Override
protected void readSettings(FriendlyByteBuf buffer) {
value = buffer.readVarInt();
row = buffer.readVarInt();
if (buffer.readBoolean())
interactHand = buffer.readBoolean() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
side = Direction.values()[buffer.readVarInt()];
ctrlDown = buffer.readBoolean();
}
@Override
protected void applySettings(ServerPlayer player, SmartBlockEntity be) {
for (BlockEntityBehaviour behaviour : be.getAllBehaviours()) {
if (!(behaviour instanceof ValueSettingsBehaviour valueSettingsBehaviour))
continue;
if (!valueSettingsBehaviour.acceptsValueSettings())
continue;
if (interactHand != null) {
valueSettingsBehaviour.onShortInteract(player, interactHand, side);
return;
}
valueSettingsBehaviour.setValueSettings(player, new ValueSettings(row, value), ctrlDown);
return;
}
}
@Override
protected void applySettings(SmartBlockEntity be) {}
}

View file

@ -0,0 +1,315 @@
package com.simibubi.create.foundation.blockEntity.behaviour;
import java.util.function.Consumer;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllKeys;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter.ScrollOptionSettingsFormatter;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueHandler;
import com.simibubi.create.foundation.gui.AbstractSimiScreen;
import com.simibubi.create.foundation.gui.AllGuiTextures;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.UIRenderHelper;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec2;
public class ValueSettingsScreen extends AbstractSimiScreen {
private int ticksOpen;
private ValueSettingsBoard board;
private int maxLabelWidth;
private int valueBarWidth;
private BlockPos pos;
private ValueSettings initialSettings;
private ValueSettings lastHovered = new ValueSettings(-1, -1);
private Consumer<ValueSettings> onHover;
private boolean iconMode;
private int milestoneSize;
private int soundCoolDown;
public ValueSettingsScreen(BlockPos pos, ValueSettingsBoard board, ValueSettings valueSettings,
Consumer<ValueSettings> onHover) {
this.pos = pos;
this.board = board;
this.initialSettings = valueSettings;
this.onHover = onHover;
this.iconMode = board.formatter() instanceof ScrollOptionSettingsFormatter;
this.milestoneSize = iconMode ? 8 : 4;
}
@Override
protected void init() {
int maxValue = board.maxValue();
maxLabelWidth = 0;
int milestoneCount = maxValue / board.milestoneInterval() + 1;
int scale = maxValue > 128 ? 1 : 2;
for (Component component : board.rows())
maxLabelWidth = Math.max(maxLabelWidth, font.width(component));
if (iconMode)
maxLabelWidth = -18;
valueBarWidth = (maxValue + 1) * scale + 1 + milestoneCount * milestoneSize;
int width = (maxLabelWidth + 14) + (valueBarWidth + 10);
int height = (board.rows()
.size() * 11);
setWindowSize(width, height);
super.init();
Vec2 coordinateOfValue = getCoordinateOfValue(initialSettings.row(), initialSettings.value());
setCursor(coordinateOfValue);
}
private void setCursor(Vec2 coordinateOfValue) {
double guiScale = minecraft.getWindow()
.getGuiScale();
GLFW.glfwSetCursorPos(minecraft.getWindow()
.getWindow(), coordinateOfValue.x * guiScale, coordinateOfValue.y * guiScale);
}
public ValueSettings getClosestCoordinate(int mouseX, int mouseY) {
int row = 0;
int column = 0;
boolean milestonesOnly = hasShiftDown();
double bestDiff = Double.MAX_VALUE;
for (; row < board.rows()
.size(); row++) {
Vec2 coord = getCoordinateOfValue(row, 0);
double diff = Math.abs(coord.y - mouseY);
if (bestDiff < diff)
break;
bestDiff = diff;
}
row -= 1;
bestDiff = Double.MAX_VALUE;
for (; column <= board.maxValue(); column++) {
Vec2 coord = getCoordinateOfValue(row, milestonesOnly ? column * board.milestoneInterval() : column);
double diff = Math.abs(coord.x - mouseX);
if (bestDiff < diff)
break;
bestDiff = diff;
}
column -= 1;
return new ValueSettings(row,
milestonesOnly ? Math.min(column * board.milestoneInterval(), board.maxValue()) : column);
}
public Vec2 getCoordinateOfValue(int row, int column) {
int scale = board.maxValue() > 128 ? 1 : 2;
float xOut =
guiLeft + ((Math.max(1, column) - 1) / board.milestoneInterval()) * milestoneSize + column * scale + 1.5f;
xOut += maxLabelWidth + 14 + 4;
if (column % board.milestoneInterval() == 0)
xOut += milestoneSize / 2;
if (column > 0)
xOut += milestoneSize;
float yOut = guiTop + (row + .5f) * 11 - .5f;
return new Vec2(xOut, yOut);
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
int x = guiLeft;
int y = guiTop;
int milestoneCount = board.maxValue() / board.milestoneInterval() + 1;
int blitOffset = getBlitOffset();
int scale = board.maxValue() > 128 ? 1 : 2;
Component title = board.title();
Component tip = Lang.translateDirect("gui.value_settings.release_to_confirm", Components.keybind("key.use"));
double fadeIn = Math.pow(Mth.clamp((ticksOpen + partialTicks) / 4.0, 0, 1), 1);
int fattestLabel = Math.max(font.width(tip), font.width(title));
if (iconMode)
for (int i = 0; i <= board.maxValue(); i++)
fattestLabel = Math.max(fattestLabel, font.width(board.formatter()
.format(new ValueSettings(0, i))));
int fatTipOffset = Math.max(0, fattestLabel + 10 - (windowWidth + 13)) / 2;
int bgWidth = Math.max((windowWidth + 13), fattestLabel + 10);
int fadeInWidth = (int) (bgWidth * fadeIn);
int fadeInStart = (bgWidth - fadeInWidth) / 2 - fatTipOffset;
int additionalHeight = iconMode ? 46 : 33;
UIRenderHelper.drawStretched(ms, x - 11 + fadeInStart, y - 17, fadeInWidth, windowHeight + additionalHeight,
blitOffset, AllGuiTextures.VALUE_SETTINGS_OUTER_BG);
UIRenderHelper.drawStretched(ms, x - 10 + fadeInStart, y - 18, fadeInWidth - 2, 1, blitOffset,
AllGuiTextures.VALUE_SETTINGS_OUTER_BG);
UIRenderHelper.drawStretched(ms, x - 10 + fadeInStart, y - 17 + windowHeight + additionalHeight,
fadeInWidth - 2, 1, blitOffset, AllGuiTextures.VALUE_SETTINGS_OUTER_BG);
if (fadeInWidth > fattestLabel) {
int textX = x - 11 - fatTipOffset + bgWidth / 2;
font.draw(ms, title, textX - font.width(title) / 2, y - 14, 0xdddddd);
font.draw(ms, tip, textX - font.width(tip) / 2, y + windowHeight + additionalHeight - 27, 0xdddddd);
}
renderBrassFrame(ms, x + maxLabelWidth + 14, y - 3, valueBarWidth + 8, board.rows()
.size() * 11 + 5);
UIRenderHelper.drawStretched(ms, x + maxLabelWidth + 17, y, valueBarWidth + 2, board.rows()
.size() * 11 - 1, blitOffset, AllGuiTextures.VALUE_SETTINGS_BAR_BG);
int originalY = y;
for (Component component : board.rows()) {
int valueBarX = x + maxLabelWidth + 14 + 4;
if (!iconMode) {
UIRenderHelper.drawCropped(ms, x - 4, y, maxLabelWidth + 8, 11, blitOffset,
AllGuiTextures.VALUE_SETTINGS_LABEL_BG);
for (int w = 0; w < valueBarWidth; w += AllGuiTextures.VALUE_SETTINGS_BAR.width - 1)
UIRenderHelper.drawCropped(ms, valueBarX + w, y + 1,
Math.min(AllGuiTextures.VALUE_SETTINGS_BAR.width - 1, valueBarWidth - w), 8, blitOffset,
AllGuiTextures.VALUE_SETTINGS_BAR);
font.draw(ms, component, x, y + 1, 0x442000);
}
int milestoneX = valueBarX;
for (int milestone = 0; milestone < milestoneCount; milestone++) {
if (iconMode)
AllGuiTextures.VALUE_SETTINGS_WIDE_MILESTONE.render(ms, milestoneX, y + 1);
else
AllGuiTextures.VALUE_SETTINGS_MILESTONE.render(ms, milestoneX, y + 1);
milestoneX += milestoneSize + board.milestoneInterval() * scale;
}
y += 11;
}
if (!iconMode)
renderBrassFrame(ms, x - 7, originalY - 3, maxLabelWidth + 14, board.rows()
.size() * 11 + 5);
if (ticksOpen < 1)
return;
ValueSettings closest = getClosestCoordinate(mouseX, mouseY);
if (!closest.equals(lastHovered)) {
onHover.accept(closest);
if (soundCoolDown == 0) {
float pitch = (closest.value()) / (float) (board.maxValue());
pitch = Mth.lerp(pitch, 1.15f, 1.5f);
minecraft.getSoundManager()
.play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), pitch, 0.25F));
ScrollValueHandler.wrenchCog.bump(3, -(closest.value() - lastHovered.value()) * 10);
soundCoolDown = 1;
}
}
lastHovered = closest;
Vec2 coordinate = getCoordinateOfValue(closest.row(), closest.value());
Component cursorText = board.formatter()
.format(closest);
AllIcons cursorIcon = null;
if (board.formatter()instanceof ScrollOptionSettingsFormatter sosf)
cursorIcon = sosf.getIcon(closest);
int cursorWidth = ((cursorIcon != null ? 16 : font.width(cursorText)) / 2) * 2 + 3;
int cursorX = ((int) (coordinate.x)) - cursorWidth / 2;
int cursorY = ((int) (coordinate.y)) - 7;
if (cursorIcon != null) {
AllGuiTextures.VALUE_SETTINGS_CURSOR_ICON.render(ms, cursorX - 2, cursorY - 3);
RenderSystem.setShaderColor(0.265625f, 0.125f, 0, 1);
cursorIcon.render(ms, cursorX + 1, cursorY - 1);
RenderSystem.setShaderColor(1, 1, 1, 1);
if (fadeInWidth > fattestLabel)
font.draw(ms, cursorText, x - 11 - fatTipOffset + (bgWidth - font.width(cursorText)) / 2,
originalY + windowHeight + additionalHeight - 40, 0xFBDC7D);
return;
}
AllGuiTextures.VALUE_SETTINGS_CURSOR_LEFT.render(ms, cursorX - 3, cursorY);
UIRenderHelper.drawCropped(ms, cursorX, cursorY, cursorWidth, 14, blitOffset,
AllGuiTextures.VALUE_SETTINGS_CURSOR);
AllGuiTextures.VALUE_SETTINGS_CURSOR_RIGHT.render(ms, cursorX + cursorWidth, cursorY);
font.draw(ms, cursorText, cursorX + 2, cursorY + 3, 0x442000);
}
protected void renderBrassFrame(PoseStack ms, int x, int y, int w, int h) {
AllGuiTextures.BRASS_FRAME_TL.render(ms, x, y);
AllGuiTextures.BRASS_FRAME_TR.render(ms, x + w - 4, y);
AllGuiTextures.BRASS_FRAME_BL.render(ms, x, y + h - 4);
AllGuiTextures.BRASS_FRAME_BR.render(ms, x + w - 4, y + h - 4);
if (h > 8) {
UIRenderHelper.drawStretched(ms, x, y + 4, 3, h - 8, getBlitOffset(), AllGuiTextures.BRASS_FRAME_LEFT);
UIRenderHelper.drawStretched(ms, x + w - 3, y + 4, 3, h - 8, getBlitOffset(),
AllGuiTextures.BRASS_FRAME_RIGHT);
}
if (w > 8) {
UIRenderHelper.drawCropped(ms, x + 4, y, w - 8, 3, getBlitOffset(), AllGuiTextures.BRASS_FRAME_TOP);
UIRenderHelper.drawCropped(ms, x + 4, y + h - 3, w - 8, 3, getBlitOffset(),
AllGuiTextures.BRASS_FRAME_BOTTOM);
}
}
@Override
public void renderBackground(PoseStack p_238651_1_, int p_238651_2_) {
int a = ((int) (0x50 * Math.min(1, (ticksOpen + AnimationTickHolder.getPartialTicks()) / 20f))) << 24;
fillGradient(p_238651_1_, 0, 0, this.width, this.height, 0x101010 | a, 0x101010 | a);
}
@Override
public void tick() {
ticksOpen++;
if (soundCoolDown > 0)
soundCoolDown--;
super.tick();
}
@Override
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
ValueSettings closest = getClosestCoordinate((int) pMouseX, (int) pMouseY);
int column = closest.value() + ((int) Math.signum(pDelta)) * (hasShiftDown() ? board.milestoneInterval() : 1);
column = Mth.clamp(column, 0, board.maxValue());
if (column == closest.value())
return false;
setCursor(getCoordinateOfValue(closest.row(), column));
return true;
}
@Override
public boolean mouseReleased(double pMouseX, double pMouseY, int pButton) {
if (pButton == 1) {
ValueSettings closest = getClosestCoordinate((int) pMouseX, (int) pMouseY);
// FIXME: value settings may be face-sensitive on future components
AllPackets.getChannel()
.sendToServer(new ValueSettingsPacket(pos, closest.row(), closest.value(), null, Direction.UP,
AllKeys.ctrlDown()));
onClose();
return true;
}
return super.mouseReleased(pMouseX, pMouseY, pButton);
}
@Override
public void onClose() {
super.onClose();
}
}

View file

@ -96,7 +96,7 @@ public class EdgeInteractionHandler {
int x = vec.getX();
int y = vec.getY();
int z = vec.getZ();
double margin = 12 / 16f;
double margin = 10 / 16f;
double absX = Math.abs(x) * margin;
double absY = Math.abs(y) * margin;
double absZ = Math.abs(z) * margin;

View file

@ -1,21 +1,26 @@
package com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.AllSpecialTextures;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.crafter.CrafterHelper;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
@ -52,8 +57,9 @@ public class EdgeInteractionRenderer {
double bestDistance = Double.MAX_VALUE;
Vec3 center = VecHelper.getCenterOf(pos);
for (Direction direction : connectiveSides) {
double distance = Vec3.atLowerCornerOf(direction.getNormal()).subtract(target.getLocation()
.subtract(center))
double distance = Vec3.atLowerCornerOf(direction.getNormal())
.subtract(target.getLocation()
.subtract(center))
.length();
if (distance > bestDistance)
continue;
@ -63,31 +69,51 @@ public class EdgeInteractionRenderer {
AABB bb = EdgeInteractionHandler.getBB(pos, closestEdge);
boolean hit = bb.contains(target.getLocation());
Vec3 offset = Vec3.atLowerCornerOf(closestEdge.getNormal())
.scale(.5)
.add(Vec3.atLowerCornerOf(face.getNormal())
.scale(.469))
.add(VecHelper.CENTER_OF_ORIGIN);
ValueBox box = new ValueBox(Components.immutableEmpty(), bb.move(-pos.getX(), -pos.getY(), -pos.getZ()), pos);
Vec3 textOffset = Vec3.ZERO;
ValueBox box = new ValueBox(Components.immutableEmpty(), bb, pos).passive(!hit)
.transform(new EdgeValueBoxTransform(offset))
.wideOutline();
CreateClient.OUTLINER.showValueBox("edge", box)
.highlightFace(face);
boolean positive = closestEdge.getAxisDirection() == AxisDirection.POSITIVE;
if (positive) {
if (face.getAxis()
.isHorizontal()) {
if (closestEdge.getAxis()
.isVertical())
textOffset = textOffset.add(0, -128, 0);
else
textOffset = textOffset.add(-128, 0, 0);
} else
textOffset = textOffset.add(-128, 0, 0);
if (!hit)
return;
List<MutableComponent> tip = new ArrayList<>();
tip.add(Lang.translateDirect("logistics.crafter.connected"));
tip.add(Lang.translateDirect(CrafterHelper.areCraftersConnected(world, pos, pos.relative(closestEdge))
? "logistics.crafter.click_to_separate"
: "logistics.crafter.click_to_merge"));
CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip);
}
static class EdgeValueBoxTransform extends ValueBoxTransform.Sided {
private Vec3 add;
public EdgeValueBoxTransform(Vec3 add) {
this.add = add;
}
box.offsetLabel(textOffset)
.withColors(0x7A6A2C, 0xB79D64)
.passive(!hit);
@Override
protected Vec3 getSouthLocation() {
return Vec3.ZERO;
}
CreateClient.OUTLINER.showValueBox("edge", box)
.lineWidth(1 / 64f)
.withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null)
.highlightFace(face);
@Override
protected Vec3 getLocalOffset(BlockState state) {
return add;
}
@Override
protected void rotate(BlockState state, PoseStack ms) {
super.rotate(state, ms);
}
}

View file

@ -3,43 +3,55 @@ package com.simibubi.create.foundation.blockEntity.behaviour.filtering;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.ItemHandlerHelper;
public class FilteringBehaviour extends BlockEntityBehaviour {
public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSettingsBehaviour {
public static final BehaviourType<FilteringBehaviour> TYPE = new BehaviourType<>();
public MutableComponent customLabel;
ValueBoxTransform slotPositioning;
boolean showCount;
Vec3 textShift;
private ItemStack filter;
public int count;
public boolean upTo;
private Consumer<ItemStack> callback;
private Supplier<Boolean> isActive;
private Supplier<Boolean> showCountPredicate;
int scrollableValue;
int ticksUntilScrollPacket;
boolean forceClientState;
boolean recipeFilter;
boolean fluidFilter;
@ -51,26 +63,23 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
callback = stack -> {
};
isActive = () -> true;
textShift = Vec3.ZERO;
count = 0;
ticksUntilScrollPacket = -1;
count = 64;
showCountPredicate = () -> showCount;
recipeFilter = false;
fluidFilter = false;
upTo = true;
}
@Override
public boolean isSafeNBT() { return true; }
public boolean isSafeNBT() {
return true;
}
@Override
public void write(CompoundTag nbt, boolean clientPacket) {
nbt.put("Filter", getFilter().serializeNBT());
nbt.putInt("FilterAmount", count);
if (clientPacket && forceClientState) {
nbt.putBoolean("ForceScrollable", true);
forceClientState = false;
}
nbt.putBoolean("UpTo", upTo);
super.write(nbt, clientPacket);
}
@ -78,30 +87,10 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
public void read(CompoundTag nbt, boolean clientPacket) {
filter = ItemStack.of(nbt.getCompound("Filter"));
count = nbt.getInt("FilterAmount");
if (nbt.contains("ForceScrollable")) {
scrollableValue = count;
ticksUntilScrollPacket = -1;
}
upTo = nbt.getBoolean("UpTo");
super.read(nbt, clientPacket);
}
@Override
public void tick() {
super.tick();
if (!getWorld().isClientSide)
return;
if (ticksUntilScrollPacket == -1)
return;
if (ticksUntilScrollPacket > 0) {
ticksUntilScrollPacket--;
return;
}
AllPackets.getChannel().sendToServer(new FilteringCountUpdatePacket(getPos(), scrollableValue));
ticksUntilScrollPacket = -1;
}
public FilteringBehaviour withCallback(Consumer<ItemStack> filterCallback) {
callback = filterCallback;
return this;
@ -132,33 +121,38 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
return this;
}
public FilteringBehaviour moveText(Vec3 shift) {
textShift = shift;
return this;
}
@Override
public void initialize() {
super.initialize();
scrollableValue = count;
}
public void setFilter(Direction face, ItemStack stack) {
setFilter(stack);
}
public void setLabel(MutableComponent label) {
this.customLabel = label;
}
public void setFilter(ItemStack stack) {
boolean confirm = ItemHandlerHelper.canItemStacksStack(stack, filter);
filter = stack.copy();
callback.accept(filter);
count = !confirm ? 0
: (filter.getItem() instanceof FilterItem) ? 0 : Math.min(stack.getCount(), stack.getMaxStackSize());
forceClientState = true;
count = Math.min(count, stack.getMaxStackSize());
blockEntity.setChanged();
blockEntity.sendData();
}
@Override
public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) {
if (getValueSettings().equals(settings))
return;
count = Mth.clamp(settings.value(), 1, filter.getMaxStackSize());
upTo = settings.row() == 0;
blockEntity.setChanged();
blockEntity.sendData();
playFeedbackSound(this);
}
@Override
public ValueSettings getValueSettings() {
return new ValueSettings(upTo ? 0 : 1, count == 0 ? filter.getMaxStackSize() : count);
}
@Override
public void destroy() {
if (filter.getItem() instanceof FilterItem) {
@ -166,7 +160,6 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
Level world = getWorld();
world.addFreshEntity(new ItemEntity(world, pos.x, pos.y, pos.z, filter.copy()));
}
super.destroy();
}
@ -188,7 +181,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
}
public boolean isCountVisible() {
return showCountPredicate.get();
return showCountPredicate.get() && filter.getMaxStackSize() > 1;
}
public boolean test(ItemStack stack) {
@ -204,6 +197,7 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
return TYPE;
}
@Override
public boolean testHit(Vec3 hit) {
BlockState state = blockEntity.getBlockState();
Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos()));
@ -218,8 +212,74 @@ public class FilteringBehaviour extends BlockEntityBehaviour {
return count == 0;
}
@Override
public boolean acceptsValueSettings() {
return isCountVisible();
}
@Override
public boolean isActive() {
return isActive.get();
}
@Override
public ValueBoxTransform getSlotPositioning() {
return slotPositioning;
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
ItemStack filter = getFilter(hitResult.getDirection());
int maxAmount = (filter.getItem() instanceof FilterItem) ? 64 : filter.getMaxStackSize();
return new ValueSettingsBoard(Lang.translateDirect("logistics.filter.extracted_amount"), maxAmount, 16,
Lang.translatedOptions("logistics.filter", "up_to", "exactly"),
new ValueSettingsFormatter(this::formatValue));
}
public MutableComponent formatValue(ValueSettings value) {
if (value.row() == 0 && value.value() == filter.getMaxStackSize())
return Components.literal("Any");
return Components.literal(((value.row() == 0) ? "\u2264" : "=") + Math.max(1, value.value()));
}
@Override
public void onShortInteract(Player player, InteractionHand hand, Direction side) {
Level level = getWorld();
BlockPos pos = getPos();
ItemStack toApply = player.getItemInHand(hand)
.copy();
if (AllItems.WRENCH.isIn(toApply))
return;
if (AllBlocks.MECHANICAL_ARM.isIn(toApply))
return;
if (level.isClientSide())
return;
if (!player.isCreative()) {
if (toApply.getItem() instanceof FilterItem) {
if (toApply.getCount() == 1)
player.setItemInHand(hand, ItemStack.EMPTY);
else
player.getItemInHand(hand)
.shrink(1);
}
if (getFilter().getItem() instanceof FilterItem)
player.getInventory()
.placeItemBackInInventory(getFilter());
}
if (toApply.getItem() instanceof FilterItem)
toApply.setCount(1);
setFilter(side, toApply);
level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f);
}
public MutableComponent getLabel() {
if (customLabel != null)
return customLabel;
return Lang.translateDirect(
recipeFilter ? "logistics.recipe_filter" : fluidFilter ? "logistics.fluid_filter" : "logistics.filter");
}
}

View file

@ -1,43 +0,0 @@
package com.simibubi.create.foundation.blockEntity.behaviour.filtering;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class FilteringCountUpdatePacket extends BlockEntityConfigurationPacket<SmartBlockEntity> {
int amount;
public FilteringCountUpdatePacket(FriendlyByteBuf buffer) {
super(buffer);
}
public FilteringCountUpdatePacket(BlockPos pos, int amount) {
super(pos);
this.amount = amount;
}
@Override
protected void writeSettings(FriendlyByteBuf buffer) {
buffer.writeInt(amount);
}
@Override
protected void readSettings(FriendlyByteBuf buffer) {
amount = buffer.readInt();
}
@Override
protected void applySettings(SmartBlockEntity be) {
FilteringBehaviour behaviour = be.getBehaviour(FilteringBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.forceClientState = true;
behaviour.count = amount;
be.setChanged();
be.sendData();
}
}

View file

@ -1,152 +0,0 @@
package com.simibubi.create.foundation.blockEntity.behaviour.filtering;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.RaycastHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.items.ItemHandlerHelper;
@EventBusSubscriber
public class FilteringHandler {
@SubscribeEvent
public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) {
Level world = event.getWorld();
BlockPos pos = event.getPos();
Player player = event.getPlayer();
InteractionHand hand = event.getHand();
if (player.isShiftKeyDown() || player.isSpectator())
return;
FilteringBehaviour behaviour = BlockEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
if (behaviour == null)
return;
BlockHitResult ray = RaycastHelper.rayTraceRange(world, player, 10);
if (ray == null)
return;
if (behaviour instanceof SidedFilteringBehaviour) {
behaviour = ((SidedFilteringBehaviour) behaviour).get(ray.getDirection());
if (behaviour == null)
return;
}
if (!behaviour.isActive())
return;
if (behaviour.slotPositioning instanceof ValueBoxTransform.Sided)
((Sided) behaviour.slotPositioning).fromSide(ray.getDirection());
if (!behaviour.testHit(ray.getLocation()))
return;
ItemStack toApply = player.getItemInHand(hand)
.copy();
if (AllItems.WRENCH.isIn(toApply))
return;
if (AllBlocks.MECHANICAL_ARM.isIn(toApply))
return;
if (event.getSide() != LogicalSide.CLIENT) {
if (!player.isCreative()) {
if (toApply.getItem() instanceof FilterItem)
player.getItemInHand(hand)
.shrink(1);
if (behaviour.getFilter()
.getItem() instanceof FilterItem)
player.getInventory().placeItemBackInInventory(behaviour.getFilter());
}
if (toApply.getItem() instanceof FilterItem)
toApply.setCount(1);
behaviour.setFilter(toApply);
} else {
ItemStack filter = behaviour.getFilter();
String feedback = "apply_click_again";
if (toApply.getItem() instanceof FilterItem || !behaviour.isCountVisible())
feedback = "apply";
else if (ItemHandlerHelper.canItemStacksStack(toApply, filter))
feedback = "apply_count";
Component formattedText = world.getBlockState(pos)
.getBlock()
.getName();
player.displayClientMessage(Lang.translateDirect("logistics.filter." + feedback, formattedText)
.withStyle(ChatFormatting.WHITE), true);
}
event.setCanceled(true);
event.setCancellationResult(InteractionResult.SUCCESS);
world.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f);
}
@OnlyIn(Dist.CLIENT)
public static boolean onScroll(double delta) {
HitResult objectMouseOver = Minecraft.getInstance().hitResult;
if (!(objectMouseOver instanceof BlockHitResult))
return false;
BlockHitResult result = (BlockHitResult) objectMouseOver;
Minecraft mc = Minecraft.getInstance();
ClientLevel world = mc.level;
BlockPos blockPos = result.getBlockPos();
FilteringBehaviour filtering = BlockEntityBehaviour.get(world, blockPos, FilteringBehaviour.TYPE);
if (filtering == null)
return false;
if (mc.player.isShiftKeyDown())
return false;
if (!mc.player.mayBuild())
return false;
if (!filtering.isCountVisible())
return false;
if (!filtering.isActive())
return false;
if (filtering.slotPositioning instanceof ValueBoxTransform.Sided)
((Sided) filtering.slotPositioning).fromSide(result.getDirection());
if (!filtering.testHit(objectMouseOver.getLocation()))
return false;
ItemStack filterItem = filtering.getFilter();
filtering.ticksUntilScrollPacket = 10;
int maxAmount = (filterItem.getItem() instanceof FilterItem) ? 64 : filterItem.getMaxStackSize();
int prev = filtering.scrollableValue;
filtering.scrollableValue =
(int) Mth.clamp(filtering.scrollableValue + delta * (AllKeys.ctrlDown() ? 16 : 1), 0, maxAmount);
if (prev != filtering.scrollableValue) {
float pitch = (filtering.scrollableValue) / (float) (maxAmount);
pitch = Mth.lerp(pitch, 1.5f, 2f);
AllSoundEvents.SCROLL_VALUE.play(world, mc.player, blockPos, 1, pitch);
}
return true;
}
}

View file

@ -1,5 +1,8 @@
package com.simibubi.create.foundation.blockEntity.behaviour.filtering;
import java.util.ArrayList;
import java.util.List;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSpecialTextures;
@ -13,7 +16,6 @@ import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxRenderer;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair;
@ -25,6 +27,7 @@ import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
@ -66,28 +69,32 @@ public class FilteringRenderer {
ItemStack filter = behaviour.getFilter();
boolean isFilterSlotted = filter.getItem() instanceof FilterItem;
boolean showCount = behaviour.isCountVisible();
boolean fluids = behaviour.fluidFilter;
Component label = isFilterSlotted ? Components.immutableEmpty()
: Lang.translateDirect(behaviour.recipeFilter ? "logistics.recipe_filter"
: fluids ? "logistics.fluid_filter" : "logistics.filter");
Component label = behaviour.getLabel();
boolean hit = behaviour.slotPositioning.testHit(state, target.getLocation()
.subtract(Vec3.atLowerCornerOf(pos)));
AABB emptyBB = new AABB(Vec3.ZERO, Vec3.ZERO);
AABB bb = isFilterSlotted ? emptyBB.inflate(.45f, .31f, .2f) : emptyBB.inflate(.25f);
ValueBox box = showCount ? new ItemValueBox(label, bb, pos, filter, behaviour.scrollableValue)
: new ValueBox(label, bb, pos);
box.offsetLabel(behaviour.textShift)
.withColors(fluids ? 0x407088 : 0x7A6A2C, fluids ? 0x70adb5 : 0xB79D64)
.scrollTooltip(showCount && !isFilterSlotted ? Components.literal("[").append(Lang.translateDirect("action.scroll")).append("]") : Components.immutableEmpty())
.passive(!hit);
ValueBox box = new ItemValueBox(label, bb, pos, filter, showCount ? behaviour.count : -1, behaviour.upTo);
box.passive(!hit);
CreateClient.OUTLINER.showValueBox(Pair.of("filter", pos), box.transform(behaviour.slotPositioning))
.lineWidth(1 / 64f)
.withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null)
.highlightFace(result.getDirection());
.lineWidth(1 / 64f)
.withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null)
.highlightFace(result.getDirection());
if (!hit)
return;
List<MutableComponent> tip = new ArrayList<>();
tip.add(label.copy());
tip.add(Lang
.translateDirect(filter.isEmpty() ? "logistics.filter.click_to_set" : "logistics.filter.click_to_replace"));
if (showCount)
tip.add(Lang.translateDirect("logistics.filter.hold_to_set_amount"));
CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip);
}
public static void renderOnBlockEntity(SmartBlockEntity be, float partialTicks, PoseStack ms,
@ -100,7 +107,8 @@ public class FilteringRenderer {
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
if (cameraEntity != null && be.getLevel() == cameraEntity.getLevel()) {
float max = AllConfigs.client().filterItemRenderDistance.getF();
if (cameraEntity.position().distanceToSqr(VecHelper.getCenterOf(be.getBlockPos())) > (max * max)) {
if (cameraEntity.position()
.distanceToSqr(VecHelper.getCenterOf(be.getBlockPos())) > (max * max)) {
return;
}
}

View file

@ -5,6 +5,7 @@ import javax.annotation.Nullable;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.utility.BlockFace;
import net.minecraft.core.BlockPos;
@ -101,6 +102,14 @@ public abstract class CapManipulationBehaviourBase<T, S extends CapManipulationB
amount = filter.getAmount();
return amount;
}
public ExtractionCountMode getModeFromFilter() {
ExtractionCountMode mode = ExtractionCountMode.UPTO;
FilteringBehaviour filter = blockEntity.getBehaviour(FilteringBehaviour.TYPE);
if (filter != null && !filter.upTo)
mode = ExtractionCountMode.EXACTLY;
return mode;
}
public void findNewCapability() {
Level world = getWorld();

View file

@ -1,6 +1,5 @@
package com.simibubi.create.foundation.blockEntity.behaviour.inventory;
import java.util.function.Function;
import java.util.function.Predicate;
import com.google.common.base.Predicates;
@ -8,6 +7,7 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
@ -48,18 +48,14 @@ public class InvManipulationBehaviour extends CapManipulationBehaviourBase<IItem
}
public ItemStack extract() {
return extract(getAmountFromFilter());
return extract(getModeFromFilter(), getAmountFromFilter());
}
public ItemStack extract(int amount) {
return extract(amount, Predicates.alwaysTrue());
public ItemStack extract(ExtractionCountMode mode, int amount) {
return extract(mode, amount, Predicates.alwaysTrue());
}
public ItemStack extract(int amount, Predicate<ItemStack> filter) {
return extract(amount, filter, ItemStack::getMaxStackSize);
}
public ItemStack extract(int amount, Predicate<ItemStack> filter, Function<ItemStack, Integer> amountThreshold) {
public ItemStack extract(ExtractionCountMode mode, int amount, Predicate<ItemStack> filter) {
boolean shouldSimulate = simulateNext;
simulateNext = false;
@ -70,19 +66,10 @@ public class InvManipulationBehaviour extends CapManipulationBehaviourBase<IItem
return ItemStack.EMPTY;
Predicate<ItemStack> test = getFilterTest(filter);
ItemStack simulatedItems = extractAmountOrThresh(inventory, test, amount, amountThreshold, true);
ItemStack simulatedItems = ItemHelper.extract(inventory, test, mode, amount, true);
if (shouldSimulate || simulatedItems.isEmpty())
return simulatedItems;
return extractAmountOrThresh(inventory, test, amount, amountThreshold, false);
}
private static ItemStack extractAmountOrThresh(IItemHandler inventory, Predicate<ItemStack> test, int amount,
Function<ItemStack, Integer> amountThreshold, boolean shouldSimulate) {
if (amount == -1)
return ItemHelper.extract(inventory, test, amountThreshold, shouldSimulate);
return ItemHelper.extract(inventory, test, amount, shouldSimulate);
return ItemHelper.extract(inventory, test, mode, amount, false);
}
public ItemStack insert(ItemStack stack) {

View file

@ -1,8 +1,10 @@
package com.simibubi.create.foundation.blockEntity.behaviour.linked;
import java.util.ArrayList;
import java.util.List;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.datafixers.util.Pair;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
@ -19,6 +21,7 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB;
@ -51,13 +54,26 @@ public class LinkRenderer {
boolean hit = behaviour.testHit(first, target.getLocation());
ValueBoxTransform transform = first ? behaviour.firstSlot : behaviour.secondSlot;
ValueBox box = new ValueBox(label, bb, pos).withColors(0x601F18, 0xB73C2D)
.offsetLabel(behaviour.textShift)
.passive(!hit);
ValueBox box = new ValueBox(label, bb, pos).passive(!hit);
boolean empty = behaviour.getNetworkKey()
.get(first)
.getStack()
.isEmpty();
if (!empty)
box.wideOutline();
CreateClient.OUTLINER.showValueBox(Pair.of(Boolean.valueOf(first), pos), box.transform(transform))
.lineWidth(1 / 64f)
.withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null)
.highlightFace(result.getDirection());
.highlightFace(result.getDirection());
if (!hit)
continue;
List<MutableComponent> tip = new ArrayList<>();
tip.add(label.copy());
tip.add(
Lang.translateDirect(empty ? "logistics.filter.click_to_set" : "logistics.filter.click_to_replace"));
CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip);
}
}
@ -66,7 +82,7 @@ public class LinkRenderer {
if (be == null || be.isRemoved())
return;
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
float max = AllConfigs.client().filterItemRenderDistance.getF();
if (!be.isVirtual() && cameraEntity != null && cameraEntity.position()

View file

@ -7,18 +7,34 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
public class BulkScrollValueBehaviour extends ScrollValueBehaviour {
Function<SmartBlockEntity, List<? extends SmartBlockEntity>> groupGetter;
public BulkScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot,
Function<SmartBlockEntity, List<? extends SmartBlockEntity>> groupGetter) {
Function<SmartBlockEntity, List<? extends SmartBlockEntity>> groupGetter) {
super(label, be, slot);
this.groupGetter = groupGetter;
}
List<? extends SmartBlockEntity> getBulk() {
@Override
public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown) {
if (!ctrlDown) {
super.setValueSettings(player, valueSetting, ctrlDown);
return;
}
if (!valueSetting.equals(getValueSettings()))
playFeedbackSound(this);
for (SmartBlockEntity be : getBulk()) {
ScrollValueBehaviour other = be.getBehaviour(ScrollValueBehaviour.TYPE);
if (other != null)
other.setValue(valueSetting.value());
}
}
public List<? extends SmartBlockEntity> getBulk() {
return groupGetter.apply(blockEntity);
}

View file

@ -1,9 +1,15 @@
package com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter.ScrollOptionSettingsFormatter;
import com.simibubi.create.foundation.utility.Components;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.BlockHitResult;
public class ScrollOptionBehaviour<E extends Enum<E> & INamedIconOptions> extends ScrollValueBehaviour {
@ -13,15 +19,20 @@ public class ScrollOptionBehaviour<E extends Enum<E> & INamedIconOptions> extend
super(label, be, slot);
options = enum_.getEnumConstants();
between(0, options.length - 1);
withStepFunction((c) -> -1);
}
INamedIconOptions getIconForSelected() {
return get();
}
public E get() {
return options[scrollableValue];
return options[value];
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
return new ValueSettingsBoard(label, max, 1, ImmutableList.of(Components.literal("Select")),
new ScrollOptionSettingsFormatter(options));
}
}

View file

@ -4,19 +4,25 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter;
import com.simibubi.create.foundation.utility.Components;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
public class ScrollValueBehaviour extends BlockEntityBehaviour {
public class ScrollValueBehaviour extends BlockEntityBehaviour implements ValueSettingsBehaviour {
public static final BehaviourType<ScrollValueBehaviour> TYPE = new BehaviourType<>();
@ -24,17 +30,12 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
Vec3 textShift;
int min = 0;
int max = 1;
protected int max = 1;
public int value;
public int scrollableValue;
int ticksUntilScrollPacket;
boolean forceClientState;
Component label;
public Component label;
Consumer<Integer> callback;
Consumer<Integer> clientCallback;
Function<Integer, String> formatter;
Function<Integer, Component> unit;
Function<StepContext, Integer> step;
private Supplier<Boolean> isActive;
boolean needsWrench;
@ -46,54 +47,28 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
};
clientCallback = i -> {
};
textShift = Vec3.ZERO;
formatter = i -> Integer.toString(i);
step = (c) -> 1;
value = 0;
isActive = () -> true;
ticksUntilScrollPacket = -1;
}
@Override
public boolean isSafeNBT() { return true; }
public boolean isSafeNBT() {
return true;
}
@Override
public void write(CompoundTag nbt, boolean clientPacket) {
nbt.putInt("ScrollValue", value);
if (clientPacket && forceClientState) {
nbt.putBoolean("ForceScrollable", true);
forceClientState = false;
}
super.write(nbt, clientPacket);
}
@Override
public void read(CompoundTag nbt, boolean clientPacket) {
value = nbt.getInt("ScrollValue");
if (nbt.contains("ForceScrollable")) {
ticksUntilScrollPacket = -1;
scrollableValue = value;
}
super.read(nbt, clientPacket);
}
@Override
public void tick() {
super.tick();
if (!getWorld().isClientSide)
return;
if (ticksUntilScrollPacket == -1)
return;
if (ticksUntilScrollPacket > 0) {
ticksUntilScrollPacket--;
return;
}
AllPackets.getChannel().sendToServer(new ScrollValueUpdatePacket(getPos(), scrollableValue));
ticksUntilScrollPacket = -1;
}
public ScrollValueBehaviour withClientCallback(Consumer<Integer> valueCallback) {
clientCallback = valueCallback;
return this;
@ -110,11 +85,6 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
return this;
}
public ScrollValueBehaviour moveText(Vec3 shift) {
textShift = shift;
return this;
}
public ScrollValueBehaviour requiresWrench() {
this.needsWrench = true;
return this;
@ -125,38 +95,19 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
return this;
}
public ScrollValueBehaviour withUnit(Function<Integer, Component> unit) {
this.unit = unit;
return this;
}
public ScrollValueBehaviour onlyActiveWhen(Supplier<Boolean> condition) {
isActive = condition;
return this;
}
public ScrollValueBehaviour withStepFunction(Function<StepContext, Integer> step) {
this.step = step;
return this;
}
@Override
public void initialize() {
super.initialize();
setValue(value);
scrollableValue = value;
}
public void setValue(int value) {
value = Mth.clamp(value, min, max);
if (value == this.value)
return;
this.value = value;
forceClientState = true;
callback.accept(value);
blockEntity.setChanged();
blockEntity.sendData();
scrollableValue = value;
}
public int getValue() {
@ -164,7 +115,7 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
}
public String formatValue() {
return formatter.apply(scrollableValue);
return formatter.apply(value);
}
@Override
@ -172,10 +123,12 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
return TYPE;
}
@Override
public boolean isActive() {
return isActive.get();
}
@Override
public boolean testHit(Vec3 hit) {
BlockState state = blockEntity.getBlockState();
Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos()));
@ -193,4 +146,33 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour {
public boolean control;
}
@Override
public ValueBoxTransform getSlotPositioning() {
return slotPositioning;
}
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
return new ValueSettingsBoard(label, max, 10, ImmutableList.of(Components.literal("Value")),
new ValueSettingsFormatter(ValueSettings::format));
}
@Override
public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown) {
if (valueSetting.equals(getValueSettings()))
return;
setValue(valueSetting.value());
playFeedbackSound(this);
}
@Override
public ValueSettings getValueSettings() {
return new ValueSettings(0, value);
}
@Override
public boolean onlyVisibleWithWrench() {
return needsWrench;
}
}

View file

@ -1,82 +1,20 @@
package com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext;
import com.simibubi.create.foundation.utility.animation.PhysicalFloat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber
public class ScrollValueHandler {
private static float lastPassiveScroll = 0.0f;
private static float passiveScroll = 0.0f;
private static float passiveScrollDirection = 1f;
private static final PhysicalFloat wrenchCog = PhysicalFloat.create()
public static final PhysicalFloat wrenchCog = PhysicalFloat.create()
.withDrag(0.3);
@OnlyIn(Dist.CLIENT)
public static boolean onScroll(double delta) {
Minecraft mc = Minecraft.getInstance();
HitResult objectMouseOver = mc.hitResult;
if (!(objectMouseOver instanceof BlockHitResult))
return false;
BlockHitResult result = (BlockHitResult) objectMouseOver;
ClientLevel world = mc.level;
BlockPos blockPos = result.getBlockPos();
ScrollValueBehaviour scrolling = BlockEntityBehaviour.get(world, blockPos, ScrollValueBehaviour.TYPE);
if (scrolling == null)
return false;
if (!scrolling.isActive())
return false;
if (!mc.player.mayBuild())
return false;
if (scrolling.needsWrench && !AllItems.WRENCH.isIn(mc.player.getMainHandItem()))
return false;
passiveScrollDirection = (float) -delta;
wrenchCog.bump(3, -delta * 10);
int prev = scrolling.scrollableValue;
if (scrolling.slotPositioning instanceof Sided)
((Sided) scrolling.slotPositioning).fromSide(result.getDirection());
if (!scrolling.testHit(objectMouseOver.getLocation()))
return false;
if (scrolling instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) {
BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) scrolling;
for (SmartBlockEntity be : bulkScrolling.getBulk()) {
ScrollValueBehaviour other = be.getBehaviour(ScrollValueBehaviour.TYPE);
if (other != null)
applyTo(delta, other);
}
} else
applyTo(delta, scrolling);
if (prev != scrolling.scrollableValue) {
float pitch = (scrolling.scrollableValue - scrolling.min) / (float) (scrolling.max - scrolling.min);
pitch = Mth.lerp(pitch, 1.5f, 2f);
AllSoundEvents.SCROLL_VALUE.play(world, mc.player, blockPos, 1, pitch);
}
return true;
}
public static float getScroll(float partialTicks) {
return wrenchCog.getValue(partialTicks) + Mth.lerp(partialTicks, lastPassiveScroll, passiveScroll);
}
@ -91,21 +29,4 @@ public class ScrollValueHandler {
}
}
protected static void applyTo(double delta, ScrollValueBehaviour scrolling) {
scrolling.ticksUntilScrollPacket = 10;
int valueBefore = scrolling.scrollableValue;
StepContext context = new StepContext();
context.control = AllKeys.ctrlDown();
context.shift = AllKeys.shiftDown();
context.currentValue = scrolling.scrollableValue;
context.forward = delta > 0;
double newValue = scrolling.scrollableValue + Math.signum(delta) * scrolling.step.apply(context);
scrolling.scrollableValue = (int) Mth.clamp(newValue, scrolling.min, scrolling.max);
if (valueBefore != scrolling.scrollableValue)
scrolling.clientCallback.accept(scrolling.scrollableValue);
}
}

View file

@ -1,5 +1,8 @@
package com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys;
import com.simibubi.create.CreateClient;
@ -16,6 +19,7 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
@ -52,6 +56,14 @@ public class ScrollValueRenderer {
}
} else
addBox(world, pos, face, behaviour, highlight);
if (!highlight)
return;
List<MutableComponent> tip = new ArrayList<>();
tip.add(behaviour.label.copy());
tip.add(Lang.translateDirect("gui.value_settings.hold_to_edit"));
CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip);
}
protected static void addBox(ClientLevel world, BlockPos pos, Direction face, ScrollValueBehaviour behaviour,
@ -66,18 +78,13 @@ public class ScrollValueRenderer {
box = new IconValueBox(label, ((ScrollOptionBehaviour<?>) behaviour).getIconForSelected(), bb, pos);
} else {
box = new TextValueBox(label, bb, pos, Components.literal(behaviour.formatValue()));
if (behaviour.unit != null)
box.subLabel(Components.literal("(").append(behaviour.unit.apply(behaviour.scrollableValue)).append(")"));
}
box.scrollTooltip(Components.literal("[").append(Lang.translateDirect("action.scroll")).append("]"));
box.offsetLabel(behaviour.textShift.add(20, -10, 0))
.withColors(0x5A5D5A, 0xB5B7B6)
.passive(!highlight);
box.passive(!highlight)
.wideOutline();
CreateClient.OUTLINER.showValueBox(pos, box.transform(behaviour.slotPositioning))
.lineWidth(1 / 64f)
.highlightFace(face);
.highlightFace(face);
}
}

View file

@ -1,40 +0,0 @@
package com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class ScrollValueUpdatePacket extends BlockEntityConfigurationPacket<SmartBlockEntity> {
int value;
public ScrollValueUpdatePacket(FriendlyByteBuf buffer) {
super(buffer);
}
public ScrollValueUpdatePacket(BlockPos pos, int amount) {
super(pos);
this.value = amount;
}
@Override
protected void writeSettings(FriendlyByteBuf buffer) {
buffer.writeInt(value);
}
@Override
protected void readSettings(FriendlyByteBuf buffer) {
value = buffer.readInt();
}
@Override
protected void applySettings(SmartBlockEntity be) {
ScrollValueBehaviour behaviour = be.getBehaviour(ScrollValueBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.setValue(value);
}
}

View file

@ -1,6 +1,5 @@
package com.simibubi.create.foundation.config;
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
import com.simibubi.create.foundation.utility.ContraptionData;
public class CKinetics extends ConfigBase {
@ -8,7 +7,6 @@ public class CKinetics extends ConfigBase {
public final ConfigBool disableStress = b(false, "disableStress", Comments.disableStress);
public final ConfigInt maxBeltLength = i(20, 5, "maxBeltLength", Comments.maxBeltLength);
public final ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
public final ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed, ConfigAnnotations.RequiresRestart.BOTH.asComment());
public final ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed);
public final ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
@ -65,7 +63,6 @@ public class CKinetics extends ConfigBase {
private static class Comments {
static String maxBeltLength = "Maximum length in blocks of mechanical belts.";
static String crushingDamage = "Damage dealt by active Crushing Wheels.";
static String maxMotorSpeed = "Maximum allowed speed of a configurable motor.";
static String maxRotationSpeed = "Maximum allowed rotation speed for any Kinetic Block.";
static String fanPushDistance = "Maximum distance in blocks Fans can push entities.";
static String fanPullDistance = "Maximum distance in blocks from where Fans can pull entities.";

View file

@ -2,8 +2,6 @@ package com.simibubi.create.foundation.config;
public class CLogistics extends ConfigBase {
public final ConfigInt defaultExtractionLimit =
i(64, 1, 64, "defaultExtractionLimit", Comments.defaultExtractionLimit);
public final ConfigInt defaultExtractionTimer = i(8, 1, "defaultExtractionTimer", Comments.defaultExtractionTimer);
public final ConfigInt psiTimeout = i(20, 1, "psiTimeout", Comments.psiTimeout);
public final ConfigInt mechanicalArmRange = i(5, 1, "mechanicalArmRange", Comments.mechanicalArmRange);
@ -17,8 +15,6 @@ public class CLogistics extends ConfigBase {
}
private static class Comments {
static String defaultExtractionLimit =
"The maximum amount of items a funnel pulls at a time without an applied filter.";
static String defaultExtractionTimer =
"The amount of ticks a funnel waits between item transferrals, when it is not re-activated by redstone.";
static String linkRange = "Maximum possible range in blocks of redstone link connections.";

View file

@ -48,10 +48,6 @@ public enum AllGuiTextures implements ScreenElement {
STOCKSWITCH_UNPOWERED_LANE("logistics", 36, 18, 102, 18),
STOCKSWITCH_POWERED_LANE("logistics", 36, 40, 102, 18),
ADJUSTABLE_CRATE("logistics_2", 124, 127),
ADJUSTABLE_DOUBLE_CRATE("logistics_2", 0, 127, 196, 127),
ADJUSTABLE_CRATE_LOCKED_SLOT("logistics_2", 125, 109, 18, 18),
FILTER("filters", 214, 97),
ATTRIBUTE_FILTER("filters", 0, 97, 241, 83),
@ -77,12 +73,6 @@ public enum AllGuiTextures implements ScreenElement {
LINKED_CONTROLLER("curiosities_2", 179, 109),
BLUEPRINT("curiosities_2", 0, 109, 179, 109),
PROJECTOR("projector", 235, 185),
PROJECTOR_FILTER_STRENGTH("projector", 0, 14, 162, 22),
PROJECTOR_FILTER("projector", 0, 36, 162, 22),
PROJECTOR_END("projector", 0, 58, 162, 22),
PROJECTOR_EMPTY("projector", 0, 80, 162, 22),
DATA_GATHERER("display_link", 235, 162),
DATA_AREA_START("display_link", 0, 163, 2, 18),
DATA_AREA_SPEECH("display_link", 8, 163, 5, 18),
@ -134,6 +124,26 @@ public enum AllGuiTextures implements ScreenElement {
ELEVATOR_CONTACT("display_link", 20, 172, 233, 82),
BRASS_FRAME_TL("value_settings", 65, 9, 4, 4),
BRASS_FRAME_TR("value_settings", 70, 9, 4, 4),
BRASS_FRAME_BL("value_settings", 65, 19, 4, 4),
BRASS_FRAME_BR("value_settings", 70, 19, 4, 4),
BRASS_FRAME_LEFT("value_settings", 65, 14, 3, 4),
BRASS_FRAME_RIGHT("value_settings", 71, 14, 3, 4),
BRASS_FRAME_TOP("value_settings", 0, 24, 256, 3),
BRASS_FRAME_BOTTOM("value_settings", 0, 27, 256, 3),
VALUE_SETTINGS_MILESTONE("value_settings", 0, 0, 7, 8),
VALUE_SETTINGS_WIDE_MILESTONE("value_settings", 75, 14, 13, 8),
VALUE_SETTINGS_BAR("value_settings", 7, 0, 249, 8),
VALUE_SETTINGS_BAR_BG("value_settings", 75, 9, 1, 1),
VALUE_SETTINGS_OUTER_BG("value_settings", 80, 9, 1, 1),
VALUE_SETTINGS_CURSOR_LEFT("value_settings", 0, 9, 3, 14),
VALUE_SETTINGS_CURSOR("value_settings", 4, 9, 56, 14),
VALUE_SETTINGS_CURSOR_RIGHT("value_settings", 61, 9, 3, 14),
VALUE_SETTINGS_CURSOR_ICON("value_settings", 0, 44, 22, 20),
VALUE_SETTINGS_LABEL_BG("value_settings", 0, 31, 81, 11),
// JEI
JEI_SLOT("jei/widgets", 18, 18),
JEI_CHANCE_SLOT("jei/widgets", 20, 156, 18, 18),

View file

@ -126,6 +126,9 @@ public class AllIcons implements ScreenElement {
I_SCHEMATIC = newRow(),
I_SEQ_REPEAT = next(),
VALUE_BOX_HOVER_6PX = next(),
VALUE_BOX_HOVER_4PX = next(),
VALUE_BOX_HOVER_8PX = next(),
I_MTD_LEFT = newRow(),
I_MTD_CLOSE = next(),
@ -187,7 +190,7 @@ public class AllIcons implements ScreenElement {
@OnlyIn(Dist.CLIENT)
public void render(PoseStack ms, MultiBufferSource buffer, int color) {
VertexConsumer builder = buffer.getBuffer(RenderType.textSeeThrough(ICON_ATLAS));
VertexConsumer builder = buffer.getBuffer(RenderType.text(ICON_ATLAS));
Matrix4f matrix = ms.last().pose();
Color rgb = new Color(color);
int light = LightTexture.FULL_BRIGHT;

View file

@ -252,6 +252,13 @@ public class UIRenderHelper {
tex.startY / 256f, (tex.startY + tex.height) / 256f);
}
public static void drawCropped(PoseStack ms, int left, int top, int w, int h, int z, AllGuiTextures tex) {
tex.bind();
drawTexturedQuad(ms.last()
.pose(), Color.WHITE, left, left + w, top, top + h, z, tex.startX / 256f, (tex.startX + w) / 256f,
tex.startY / 256f, (tex.startY + h) / 256f);
}
private static void drawColoredTexture(PoseStack ms, Color c, int left, int right, int top, int bot, int z, int tex_width, int tex_height, float tex_left, float tex_top, int sheet_width, int sheet_height) {
drawTexturedQuad(ms.last().pose(), c, left, right, top, bot, z, (tex_left + 0.0F) / (float) sheet_width, (tex_left + (float) tex_width) / (float) sheet_width, (tex_top + 0.0F) / (float) sheet_height, (tex_top + (float) tex_height) / (float) sheet_height);
}

View file

@ -9,7 +9,6 @@ import javax.annotation.Nullable;
import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.core.BlockPos;
@ -148,8 +147,7 @@ public class ItemHelper {
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, boolean simulate) {
return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.server().logistics.defaultExtractionLimit.get(),
simulate);
return extract(inv, test, ExtractionCountMode.UPTO, 64, simulate);
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, int exactAmount, boolean simulate) {
@ -224,7 +222,7 @@ public class ItemHelper {
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test,
Function<ItemStack, Integer> amountFunction, boolean simulate) {
ItemStack extracting = ItemStack.EMPTY;
int maxExtractionCount = AllConfigs.server().logistics.defaultExtractionLimit.get();
int maxExtractionCount = 64;
for (int slot = 0; slot < inv.getSlots(); slot++) {
if (extracting.isEmpty()) {

View file

@ -80,8 +80,7 @@ import com.simibubi.create.content.schematics.packet.SchematicPlacePacket;
import com.simibubi.create.content.schematics.packet.SchematicSyncPacket;
import com.simibubi.create.content.schematics.packet.SchematicUploadPacket;
import com.simibubi.create.foundation.blockEntity.RemoveBlockEntityPacket;
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringCountUpdatePacket;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollvalue.ScrollValueUpdatePacket;
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsPacket;
import com.simibubi.create.foundation.command.HighlightPacket;
import com.simibubi.create.foundation.command.SConfigureConfigPacket;
import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket;
@ -111,8 +110,6 @@ public enum AllPackets {
UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new, PLAY_TO_SERVER),
CLEAR_CONTAINER(ClearMenuPacket.class, ClearMenuPacket::new, PLAY_TO_SERVER),
CONFIGURE_FILTER(FilterScreenPacket.class, FilterScreenPacket::new, PLAY_TO_SERVER),
CONFIGURE_FILTERING_AMOUNT(FilteringCountUpdatePacket.class, FilteringCountUpdatePacket::new, PLAY_TO_SERVER),
CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new, PLAY_TO_SERVER),
EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new, PLAY_TO_SERVER),
CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new, PLAY_TO_SERVER),
CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new, PLAY_TO_SERVER),
@ -157,6 +154,7 @@ public enum AllPackets {
REQUEST_FLOOR_LIST(ElevatorFloorListPacket.RequestFloorList.class, ElevatorFloorListPacket.RequestFloorList::new,
PLAY_TO_SERVER),
ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER),
VALUE_SETTINGS(ValueSettingsPacket.class, ValueSettingsPacket::new, PLAY_TO_SERVER),
// Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),

View file

@ -193,21 +193,47 @@
"create.contraptions.cart_movement_mode.rotation_locked": "Lock rotation",
"create.contraptions.windmill.rotation_direction": "Rotation Direction",
"create.contraptions.clockwork.clock_hands": "Clock Hands",
"create.contraptions.clockwork.clock_hands": "Clock Hand Arrangement",
"create.contraptions.clockwork.hour_first": "Hour hand first",
"create.contraptions.clockwork.minute_first": "Minute hand first",
"create.contraptions.clockwork.hour_first_24": "24-Hour hand first",
"create.logistics.crafter.connected": "Connected Crafters",
"create.logistics.crafter.click_to_merge": "Click to merge Inventories",
"create.logistics.crafter.click_to_separate": "Click to separate Inventories",
"create.logistics.filter": "Filter",
"create.logistics.recipe_filter": "Recipe Filter",
"create.logistics.fluid_filter": "Fluid Filter",
"create.logistics.firstFrequency": "Freq. #1",
"create.logistics.secondFrequency": "Freq. #2",
"create.logistics.filter.apply": "Applied filter to %1$s.",
"create.logistics.filter.apply_click_again": "Applied filter to %1$s, click again to copy the amount.",
"create.logistics.filter.apply_count": "Applied extraction count to filter.",
"create.logistics.firstFrequency": "Frequency #1",
"create.logistics.secondFrequency": "Frequency #2",
"create.logistics.filter.click_to_set": "Click with item to set",
"create.logistics.filter.click_to_replace": "Click with item to replace",
"create.logistics.filter.hold_to_set_amount": "Click and hold for amount",
"create.logistics.filter.extracted_amount": "Extracted Amount",
"create.logistics.filter.any_amount_short": "Any",
"create.logistics.filter.up_to": "Up to",
"create.logistics.filter.exactly": "Exactly",
"create.logistics.creative_crate.supply": "Infinite Supply",
"create.logistics.train_observer.cargo_filter": "Cargo Filter",
"create.kinetics.creative_motor.rotation_speed": "Generated Speed in RPM",
"create.kinetics.speed_controller.rotation_speed": "Targeted Speed in RPM",
"create.logistics.redstone_interval": "Redstone Interval",
"create.contraptions.contoller.target": "Targeted Component",
"create.contraptions.chassis.radius": "Radius when Sticky",
"create.contraptions.chassis.range": "Range of Sticky Sides",
"create.contraptions.chassis.distance": "Distance",
"create.gui.value_settings.hold_to_edit": "Click and hold to edit",
"create.gui.value_settings.release_to_confirm": "Release %1$s to Confirm",
"create.gui.goggles.generator_stats": "Generator Stats:",
"create.gui.goggles.kinetic_stats": "Kinetic Stats:",
"create.gui.goggles.at_current_speed": "at current speed",
@ -515,7 +541,7 @@
"create.weighted_ejector.targeting": "Ejecting to [%1$s,%2$s,%3$s]",
"create.weighted_ejector.stack_size": "Ejected Stack Size",
"create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available",
"create.logistics.when_multiple_outputs_available": "Distribution Method",
"create.mechanical_arm.selection_mode.round_robin": "Round Robin",
"create.mechanical_arm.selection_mode.forced_round_robin": "Forced Round Robin",

View file

@ -50,13 +50,13 @@
},
{
"name": "Between Rims",
"from": [3.5, 3.5, 3],
"to": [12.5, 12.5, 6],
"from": [3.5, 3.5, 2],
"to": [12.5, 12.5, 5],
"faces": {
"east": {"uv": [3, 10, 12, 13], "rotation": 270, "texture": "#6"},
"west": {"uv": [3, 10, 12, 13], "rotation": 90, "texture": "#6"},
"up": {"uv": [3, 10, 12, 13], "rotation": 180, "texture": "#6"},
"down": {"uv": [3, 10, 12, 13], "texture": "#6"}
"east": {"uv": [3.5, 10, 12.5, 13], "rotation": 270, "texture": "#6"},
"west": {"uv": [3.5, 10, 12.5, 13], "rotation": 90, "texture": "#6"},
"up": {"uv": [3.5, 10, 12.5, 13], "rotation": 180, "texture": "#6"},
"down": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"}
}
},
{
@ -131,6 +131,30 @@
"up": {"uv": [1, 2, 8, 16], "rotation": 90, "texture": "#7"},
"down": {"uv": [1, 4, 15, 11], "texture": "#7"}
}
},
{
"from": [5, 7, 4],
"to": [11, 13, 10],
"faces": {
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "texture": "#6"}
}
},
{
"from": [3, 5, 4],
"to": [13, 11, 10],
"faces": {
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "texture": "#6"}
}
}
],
"display": {
@ -155,6 +179,8 @@
"origin": [8, 8, 8],
"color": 0,
"children": []
}
},
10,
11
]
}

View file

@ -4,7 +4,6 @@
"textures": {
"5": "create:block/creative_casing",
"6": "create:block/creative_motor",
"7": "create:block/flap_display_front",
"particle": "create:block/creative_casing",
"1_0": "create:block/axis"
},
@ -74,6 +73,19 @@
"down": {"uv": [10, 0, 0, 10], "rotation": 180, "texture": "#6"}
}
},
{
"name": "Back",
"from": [3, 0.1, 3],
"to": [13, 2.1, 13],
"faces": {
"north": {"uv": [3, 16, 13, 14], "rotation": 180, "texture": "#5"},
"east": {"uv": [3, 16, 13, 14], "rotation": 180, "texture": "#5"},
"south": {"uv": [3, 16, 13, 14], "rotation": 180, "texture": "#5"},
"west": {"uv": [3, 16, 13, 14], "rotation": 180, "texture": "#5"},
"up": {"uv": [10, 0, 0, 10], "texture": "#6"},
"down": {"uv": [10, 0, 0, 10], "rotation": 180, "texture": "#6"}
}
},
{
"name": "Between Rims",
"from": [5, 9, 5],
@ -89,14 +101,14 @@
},
{
"name": "Between Rims",
"from": [3.5, 5, 3.5],
"to": [12.5, 8, 12.5],
"from": [3.5, 2, 3.5],
"to": [12.5, 5, 12.5],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 8]},
"faces": {
"north": {"uv": [3, 10, 12, 13], "texture": "#6"},
"east": {"uv": [3, 10, 12, 13], "texture": "#6"},
"south": {"uv": [3, 10, 12, 13], "texture": "#6"},
"west": {"uv": [3, 10, 12, 13], "texture": "#6"}
"north": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"},
"east": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"},
"south": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"},
"west": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"}
}
},
{
@ -113,15 +125,28 @@
}
},
{
"from": [3, 0.2, 3],
"to": [13, 4, 13],
"from": [3, 4, 5],
"to": [13, 10, 11],
"faces": {
"north": {"uv": [5, 0, 15, 4], "texture": "#7"},
"east": {"uv": [5, 0, 15, 4], "texture": "#7"},
"south": {"uv": [5, 0, 15, 4], "texture": "#7"},
"west": {"uv": [3, 0, 13, 4], "rotation": 180, "texture": "#7"},
"up": {"uv": [10, 10, 0, 0], "rotation": 90, "texture": "#6"},
"down": {"uv": [10, 10, 0, 0], "rotation": 180, "texture": "#6"}
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "texture": "#6"}
}
},
{
"from": [5, 4, 3],
"to": [11, 10, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]},
"faces": {
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "rotation": 90, "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "rotation": 270, "texture": "#6"}
}
}
],
@ -146,6 +171,8 @@
"origin": [8, 8, 8],
"color": 0,
"children": []
}
},
9,
10
]
}

View file

@ -5,11 +5,25 @@
"5": "create:block/creative_casing",
"6": "create:block/creative_motor",
"7": "create:block/flap_display_front",
"1_1": "create:block/axis_top",
"particle": "create:block/creative_casing",
"1_0": "create:block/axis",
"1_1": "create:block/axis_top"
"1_0": "create:block/axis"
},
"elements": [
{
"name": "Axis",
"from": [6, 6, 6],
"to": [10, 10, 16],
"rotation": {"angle": 22.5, "axis": "z", "origin": [8, 8, 8]},
"faces": {
"north": {"uv": [6, 6, 10, 10], "rotation": 180, "texture": "#1_1"},
"east": {"uv": [6, 0, 10, 10], "rotation": 270, "texture": "#1_0"},
"south": {"uv": [6, 6, 10, 10], "texture": "#1_1"},
"west": {"uv": [6, 0, 10, 10], "rotation": 90, "texture": "#1_0"},
"up": {"uv": [6, 0, 10, 10], "rotation": 180, "texture": "#1_0"},
"down": {"uv": [6, 0, 10, 10], "texture": "#1_0"}
}
},
{
"name": "Back",
"from": [3, 3, 0.1],
@ -51,13 +65,13 @@
},
{
"name": "Between Rims",
"from": [3.5, 3.5, 3],
"to": [12.5, 12.5, 6],
"from": [3.5, 3.5, 2],
"to": [12.5, 12.5, 5],
"faces": {
"east": {"uv": [3, 10, 12, 13], "rotation": 270, "texture": "#6"},
"west": {"uv": [3, 10, 12, 13], "rotation": 90, "texture": "#6"},
"up": {"uv": [3, 10, 12, 13], "rotation": 180, "texture": "#6"},
"down": {"uv": [3, 10, 12, 13], "texture": "#6"}
"east": {"uv": [3.5, 10, 12.5, 13], "rotation": 270, "texture": "#6"},
"west": {"uv": [3.5, 10, 12.5, 13], "rotation": 90, "texture": "#6"},
"up": {"uv": [3.5, 10, 12.5, 13], "rotation": 180, "texture": "#6"},
"down": {"uv": [3.5, 10, 12.5, 13], "texture": "#6"}
}
},
{
@ -134,17 +148,27 @@
}
},
{
"name": "Axis",
"from": [6, 6, 6],
"to": [10, 10, 16],
"rotation": {"angle": 22.5, "axis": "z", "origin": [8, 8, 8]},
"from": [5, 7, 4],
"to": [11, 13, 10],
"faces": {
"north": {"uv": [6, 6, 10, 10], "rotation": 180, "texture": "#1_1"},
"east": {"uv": [6, 0, 10, 10], "rotation": 270, "texture": "#1_0"},
"south": {"uv": [6, 6, 10, 10], "texture": "#1_1"},
"west": {"uv": [6, 0, 10, 10], "rotation": 90, "texture": "#1_0"},
"up": {"uv": [6, 0, 10, 10], "rotation": 180, "texture": "#1_0"},
"down": {"uv": [6, 0, 10, 10], "texture": "#1_0"}
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "texture": "#6"}
}
},
{
"from": [3, 5, 4],
"to": [13, 11, 10],
"faces": {
"north": {"uv": [10, 0, 16, 6], "texture": "#6"},
"east": {"uv": [10, 0, 16, 6], "texture": "#6"},
"south": {"uv": [10, 0, 16, 6], "texture": "#6"},
"west": {"uv": [10, 0, 16, 6], "texture": "#6"},
"up": {"uv": [10, 0, 16, 6], "texture": "#6"},
"down": {"uv": [10, 0, 16, 6], "texture": "#6"}
}
}
],
@ -155,21 +179,36 @@
}
},
"groups": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
{
"name": "shaft",
"origin": [8, 8, 8],
"color": 0,
"children": [10]
"children": [0]
},
{
"name": "block",
"origin": [8, 8, 8],
"color": 0,
"children": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
{
"name": "shaft",
"origin": [8, 8, 8],
"color": 0,
"children": []
},
11,
12
]
}
]
}

View file

@ -2,7 +2,7 @@
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"3": "create:block/belt/brass_belt_casing_sideways",
"3": "create:block/mechanical_arm_side",
"7": "create:block/brass_block",
"particle": "create:block/crafter_top"
},
@ -12,10 +12,10 @@
"from": [0, 0, 0],
"to": [16, 6, 16],
"faces": {
"north": {"uv": [0, 6.5, 8, 9.5], "texture": "#3"},
"east": {"uv": [0, 6.5, 8, 9.5], "texture": "#3"},
"south": {"uv": [0, 6.5, 8, 9.5], "texture": "#3"},
"west": {"uv": [0, 6.5, 8, 9.5], "texture": "#3"},
"north": {"uv": [0, 0, 16, 6], "texture": "#3"},
"east": {"uv": [0, 0, 16, 6], "texture": "#3"},
"south": {"uv": [0, 0, 16, 6], "texture": "#3"},
"west": {"uv": [0, 0, 16, 6], "texture": "#3"},
"up": {"uv": [0, 0, 16, 16], "texture": "#7"},
"down": {"uv": [0, 0, 16, 16], "texture": "#7"}
}

View file

@ -8,103 +8,108 @@
"elements": [
{
"name": "siderim",
"from": [13, 0, 3],
"to": [15, 2, 13],
"from": [5, -0.25, 6],
"to": [6, 0.75, 10],
"faces": {
"north": {"uv": [14, 0, 16, 2], "texture": "#0"},
"east": {"uv": [0, 0, 2, 10], "rotation": 90, "texture": "#0"},
"south": {"uv": [14, 0, 16, 2], "rotation": 180, "texture": "#0"},
"west": {"uv": [14, 10, 16, 0], "rotation": 270, "texture": "#0"},
"up": {"uv": [14, 0, 16, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [14, 0, 16, 10], "rotation": 180, "texture": "#0"}
"north": {"uv": [15, 0, 16, 1], "texture": "#0"},
"east": {"uv": [14, 7, 15, 3], "rotation": 270, "texture": "#0"},
"south": {"uv": [15, 0, 16, 1], "texture": "#0"},
"west": {"uv": [15, 8, 16, 4], "rotation": 270, "texture": "#0"},
"up": {"uv": [15, 4, 16, 8], "rotation": 180, "texture": "#0"},
"down": {"uv": [15, 4, 14, 8], "rotation": 180, "texture": "#0"}
}
},
{
"name": "siderim",
"from": [1, 0, 3],
"to": [3, 2, 13],
"from": [10, -0.25, 6],
"to": [11, 0.75, 10],
"faces": {
"north": {"uv": [16, 0, 14, 2], "texture": "#0"},
"east": {"uv": [14, 0, 16, 10], "rotation": 270, "texture": "#0"},
"south": {"uv": [16, 0, 14, 2], "rotation": 180, "texture": "#0"},
"west": {"uv": [0, 10, 2, 0], "rotation": 90, "texture": "#0"},
"up": {"uv": [16, 0, 14, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [16, 0, 14, 10], "rotation": 180, "texture": "#0"}
"north": {"uv": [15, 0, 16, 1], "texture": "#0"},
"east": {"uv": [15, 8, 16, 4], "rotation": 270, "texture": "#0"},
"south": {"uv": [15, 0, 16, 1], "texture": "#0"},
"west": {"uv": [14, 7, 15, 3], "rotation": 270, "texture": "#0"},
"up": {"uv": [15, 5, 16, 9], "rotation": 180, "texture": "#0"},
"down": {"uv": [15, 4, 14, 8], "rotation": 180, "texture": "#0"}
}
},
{
"name": "net",
"from": [3, 1, 4],
"to": [13, 1.1, 12],
"from": [6, 0.5, 6],
"to": [10, 0.6, 10],
"faces": {
"north": {"uv": [0, 0, 0, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [0, 0, 0, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [2.5, 0.5, 12.5, 8.5], "texture": "#0"},
"down": {"uv": [2.5, 0.5, 12.5, 8.5], "texture": "#0"}
"north": {"uv": [0, 0, 4, 0.1], "texture": "#0"},
"east": {"uv": [0, 0, 4, 0.1], "texture": "#0"},
"south": {"uv": [0, 0, 4, 0.1], "texture": "#0"},
"west": {"uv": [0, 0, 4, 0.1], "texture": "#0"},
"up": {"uv": [2, 0, 6, 4], "texture": "#0"},
"down": {"uv": [2.5, 0.5, 6.5, 4.5], "texture": "#0"}
}
},
{
"name": "toprim",
"from": [3, 0.5, 3],
"to": [13, 1.5, 4],
"from": [5, -0.25, 5],
"to": [11, 0.75, 6],
"faces": {
"north": {"uv": [3, 9, 13, 10], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"}
"north": {"uv": [3, 9, 9, 10], "texture": "#0"},
"east": {"uv": [12, 9, 13, 10], "texture": "#0"},
"south": {"uv": [3, 9, 9, 10], "rotation": 180, "texture": "#0"},
"west": {"uv": [12, 9, 13, 10], "texture": "#0"},
"up": {"uv": [3, 9, 9, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [3, 9, 9, 10], "rotation": 180, "texture": "#0"}
}
},
{
"name": "toprim",
"from": [3, 0.5, 12],
"to": [13, 1.5, 13],
"from": [5, -0.25, 10],
"to": [11, 0.75, 11],
"faces": {
"north": {"uv": [3, 9, 13, 10], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [3, 9, 13, 10], "rotation": 180, "texture": "#0"}
"north": {"uv": [3, 9, 9, 10], "texture": "#0"},
"east": {"uv": [12, 9, 13, 10], "texture": "#0"},
"south": {"uv": [5, 9, 11, 10], "rotation": 180, "texture": "#0"},
"west": {"uv": [12, 9, 13, 10], "texture": "#0"},
"up": {"uv": [5, 9, 11, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [3, 9, 9, 10], "rotation": 180, "texture": "#0"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, -180, 0],
"translation": [-2.75, 3.25, 3.25],
"scale": [0.5, 0.5, 0.5]
"translation": [-2.75, 2, 4.75],
"scale": [0.6, 0.6, 0.6]
},
"thirdperson_lefthand": {
"rotation": [75, -180, 0],
"translation": [-2.75, 3.25, 3.25],
"scale": [0.5, 0.5, 0.5]
"translation": [-2.75, 2, 4.75],
"scale": [0.6, 0.6, 0.6]
},
"firstperson_righthand": {
"rotation": [75, -180, 0],
"translation": [-2.75, 3.25, 3.25],
"scale": [0.5, 0.5, 0.5]
"translation": [2.25, 1.5, 4.75],
"scale": [1.35, 1.35, 1.35]
},
"firstperson_lefthand": {
"rotation": [75, -180, 0],
"translation": [-2.75, 3.25, 3.25],
"scale": [0.5, 0.5, 0.5]
"translation": [2.25, 1.5, 4.75],
"scale": [1.35, 1.35, 1.35]
},
"ground": {
"translation": [0, 3, 0],
"scale": [0.5, 0.5, 0.5]
"scale": [0.76, 0.76, 0.76]
},
"gui": {
"rotation": [30, 225, 0],
"translation": [0, 4.25, 0],
"scale": [0.75, 0.75, 0.75]
"translation": [0, 9.5, 0],
"scale": [1.5, 1.5, 1.5]
},
"head": {
"translation": [0, 18.25, 0],
"scale": [1.43, 1.43, 1.43]
},
"fixed": {
"rotation": [90, -180, 0],
"translation": [0, 0, 6.5]
"rotation": [90, 0, 179.5],
"translation": [0, 0, -15],
"scale": [2.04, 2.04, 2.04]
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 B

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 237 B