mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-14 14:34:16 +01:00
Merge branch 'mc1.18/0.5.1' into mc1.18/0.5.1-repolish
This commit is contained in:
commit
41c462ab1a
@ -606,6 +606,7 @@
|
||||
"item.create.chocolate_glazed_berries": "s\u01DD\u0131\u0279\u0279\u01DD\u15FA p\u01DDz\u0250\u05DF\u2141 \u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186",
|
||||
"item.create.chromatic_compound": "punod\u026Fo\u0186 \u0254\u0131\u0287\u0250\u026Fo\u0279\u0265\u0186",
|
||||
"item.create.cinder_flour": "\u0279no\u05DF\u2132 \u0279\u01DDpu\u0131\u0186",
|
||||
"item.create.clipboard": "p\u0279\u0250oqd\u0131\u05DF\u0186",
|
||||
"item.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186",
|
||||
"item.create.copper_backtank_placeable": "\u01DD\u05DFq\u0250\u01DD\u0254\u0250\u05DF\u0500 \u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186",
|
||||
"item.create.copper_diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1 \u0279\u01DDddo\u0186",
|
||||
|
@ -613,6 +613,7 @@
|
||||
"item.create.chocolate_glazed_berries": "Chocolate Glazed Berries",
|
||||
"item.create.chromatic_compound": "Chromatic Compound",
|
||||
"item.create.cinder_flour": "Cinder Flour",
|
||||
"item.create.clipboard": "Clipboard",
|
||||
"item.create.copper_backtank": "Copper Backtank",
|
||||
"item.create.copper_backtank_placeable": "Copper Backtank Placeable",
|
||||
"item.create.copper_diving_boots": "Copper Diving Boots",
|
||||
@ -862,8 +863,6 @@
|
||||
"advancement.create.train_portal.desc": "Ride a Train through a Nether portal",
|
||||
"advancement.create.track_crafting_factory": "Track Factory",
|
||||
"advancement.create.track_crafting_factory.desc": "Produce more than 1000 Train Tracks with the same Mechanical Press",
|
||||
"advancement.create.long_bend": "The Longest Bend",
|
||||
"advancement.create.long_bend.desc": "Create a curved track section that spans more than 30 blocks in length",
|
||||
"advancement.create.long_train": "Ambitious Endeavours",
|
||||
"advancement.create.long_train.desc": "Create a Train with at least 6 carriages",
|
||||
"advancement.create.long_travel": "Field Trip",
|
||||
@ -1165,6 +1164,7 @@
|
||||
"create.gui.sequenced_gearshift.speed.forward_fast": "Double speed, Forwards",
|
||||
"create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed",
|
||||
"create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed",
|
||||
"create.gui.clipboard.erase_checked": "Erase checked items",
|
||||
|
||||
"create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s",
|
||||
"create.schematicAndQuill.firstPos": "First position set.",
|
||||
@ -1245,7 +1245,7 @@
|
||||
"create.gui.schematicannon.option.skipMissing": "Skip missing Blocks",
|
||||
"create.gui.schematicannon.option.skipBlockEntities": "Protect Block Entities",
|
||||
"create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon",
|
||||
"create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic",
|
||||
"create.gui.schematicannon.slot.listPrinter": "Place a Clipboard or Book here to print a Checklist for your Schematic",
|
||||
"create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.",
|
||||
"create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.",
|
||||
"create.gui.schematicannon.option.skipBlockEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.",
|
||||
@ -1611,6 +1611,7 @@
|
||||
"create.track.turn_start": "Cannot start connection from a Turn",
|
||||
"create.track.not_enough_tracks": "Not holding enough tracks",
|
||||
"create.track.not_enough_pavement": "Not holding enough pavement blocks",
|
||||
"create.track.hold_for_smooth_curve": "Hold %1$s for maximized turn",
|
||||
|
||||
"create.portal_track.failed": "Cannot place portal track:",
|
||||
"create.portal_track.missing": "Target portal not generated yet",
|
||||
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "create:item/clipboard"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"create:clipboard_type": 0.0
|
||||
},
|
||||
"model": "create:item/clipboard_0"
|
||||
},
|
||||
{
|
||||
"predicate": {
|
||||
"create:clipboard_type": 1.0
|
||||
},
|
||||
"model": "create:item/clipboard_1"
|
||||
},
|
||||
{
|
||||
"predicate": {
|
||||
"create:clipboard_type": 2.0
|
||||
},
|
||||
"model": "create:item/clipboard_2"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "create:item/empty_clipboard"
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "create:item/clipboard"
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "create:item/clipboard_and_quill"
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"parent": "create:track_crafting_factory",
|
||||
"display": {
|
||||
"icon": {
|
||||
"item": "create:track"
|
||||
},
|
||||
"title": {
|
||||
"translate": "advancement.create.long_bend"
|
||||
},
|
||||
"description": {
|
||||
"color": "#DBA213",
|
||||
"translate": "advancement.create.long_bend.desc"
|
||||
},
|
||||
"frame": "goal",
|
||||
"show_toast": true,
|
||||
"announce_to_chat": true,
|
||||
"hidden": false
|
||||
},
|
||||
"criteria": {
|
||||
"0": {
|
||||
"trigger": "create:long_bend_builtin",
|
||||
"conditions": {}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"0"
|
||||
]
|
||||
]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"parent": "create:long_bend",
|
||||
"parent": "create:track_crafting_factory",
|
||||
"display": {
|
||||
"icon": {
|
||||
"item": "minecraft:minecart"
|
||||
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"create:crafting/appliances/clipboard"
|
||||
]
|
||||
},
|
||||
"criteria": {
|
||||
"has_item": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
"create:andesite_alloy"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"trigger": "minecraft:recipe_unlocked",
|
||||
"conditions": {
|
||||
"recipe": "create:crafting/appliances/clipboard"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_item",
|
||||
"has_the_recipe"
|
||||
]
|
||||
]
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"create:crafting/appliances/clipboard_clear"
|
||||
]
|
||||
},
|
||||
"criteria": {
|
||||
"has_item": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
"create:clipboard"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"trigger": "minecraft:recipe_unlocked",
|
||||
"conditions": {
|
||||
"recipe": "create:crafting/appliances/clipboard_clear"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_item",
|
||||
"has_the_recipe"
|
||||
]
|
||||
]
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"A",
|
||||
"P",
|
||||
"G"
|
||||
],
|
||||
"key": {
|
||||
"G": {
|
||||
"tag": "minecraft:planks"
|
||||
},
|
||||
"P": {
|
||||
"item": "minecraft:paper"
|
||||
},
|
||||
"A": {
|
||||
"item": "create:andesite_alloy"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "create:clipboard"
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "create:clipboard"
|
||||
}
|
||||
],
|
||||
"result": {
|
||||
"item": "create:clipboard"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import com.simibubi.create.content.contraptions.components.actors.PloughMovement
|
||||
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock;
|
||||
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement;
|
||||
import com.simibubi.create.content.contraptions.components.actors.RollerBlock;
|
||||
import com.simibubi.create.content.contraptions.components.actors.RollerBlockItem;
|
||||
import com.simibubi.create.content.contraptions.components.actors.RollerMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.actors.SawMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.actors.SeatBlock;
|
||||
@ -929,6 +930,7 @@ public class AllBlocks {
|
||||
REGISTRATE.block("copper_valve_handle", ValveHandleBlock::copper)
|
||||
.transform(pickaxeOnly())
|
||||
.transform(BuilderTransformers.valveHandle(null))
|
||||
.transform(BlockStressDefaults.setCapacity(8.0))
|
||||
.register();
|
||||
|
||||
public static final DyedBlockList<ValveHandleBlock> DYED_VALVE_HANDLES = new DyedBlockList<>(colour -> {
|
||||
@ -1401,7 +1403,7 @@ public class AllBlocks {
|
||||
.onRegister(movementBehaviour(new RollerMovementBehaviour()))
|
||||
.blockstate(BlockStateGen.horizontalBlockProvider(true))
|
||||
.addLayer(() -> RenderType::cutoutMipped)
|
||||
.item()
|
||||
.item(RollerBlockItem::new)
|
||||
.transform(customItemModel())
|
||||
.register();
|
||||
|
||||
|
@ -39,6 +39,8 @@ import com.simibubi.create.content.curiosities.armor.BacktankItem;
|
||||
import com.simibubi.create.content.curiosities.armor.BacktankItem.BacktankBlockItem;
|
||||
import com.simibubi.create.content.curiosities.armor.DivingBootsItem;
|
||||
import com.simibubi.create.content.curiosities.armor.DivingHelmetItem;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardItem;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides;
|
||||
import com.simibubi.create.content.curiosities.symmetry.SymmetryWandItem;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintItem;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripItem;
|
||||
@ -72,7 +74,10 @@ public class AllItems {
|
||||
REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.BASE_CREATIVE_TAB);
|
||||
}
|
||||
|
||||
// Materials
|
||||
public static final ItemEntry<ClipboardItem> CLIPBOARD = REGISTRATE.item("clipboard", ClipboardItem::new)
|
||||
.onRegister(ClipboardItem::registerModelOverrides)
|
||||
.model((c, p) -> ClipboardOverrides.addOverrideModels(c, p))
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<Item> WHEAT_FLOUR =
|
||||
taggedIngredient("wheat_flour", forgeItemTag("flour/wheat"), forgeItemTag("flour")),
|
||||
|
@ -16,6 +16,7 @@ import com.simibubi.create.content.curiosities.weapons.PotatoCannonRenderHandler
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler;
|
||||
import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler;
|
||||
import com.simibubi.create.content.logistics.trains.GlobalRailwayManager;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackPlacement;
|
||||
import com.simibubi.create.content.schematics.ClientSchematicLoader;
|
||||
import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler;
|
||||
import com.simibubi.create.content.schematics.client.SchematicHandler;
|
||||
@ -109,6 +110,7 @@ public class CreateClient {
|
||||
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);
|
||||
OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Track Placement", TrackPlacement.OVERLAY);
|
||||
}
|
||||
|
||||
public static void invalidateRenderers() {
|
||||
|
@ -1,24 +1,43 @@
|
||||
package com.simibubi.create.content.contraptions.components.actors;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripItem;
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
|
||||
public class RollerBlock extends AttachedActorBlock implements IBE<RollerBlockEntity> {
|
||||
|
||||
public static DamageSource damageSourceRoller = new DamageSource("create.mechanical_roller");
|
||||
|
||||
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
||||
|
||||
public RollerBlock(Properties p_i48377_1_) {
|
||||
super(p_i48377_1_);
|
||||
}
|
||||
@ -50,4 +69,85 @@ public class RollerBlock extends AttachedActorBlock implements IBE<RollerBlockEn
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
|
||||
BlockHitResult ray) {
|
||||
ItemStack heldItem = player.getItemInHand(hand);
|
||||
|
||||
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
|
||||
if (!player.isShiftKeyDown() && player.mayBuild()) {
|
||||
if (placementHelper.matchesItem(heldItem)) {
|
||||
placementHelper.getOffset(player, world, state, pos, ray)
|
||||
.placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
private static class PlacementHelper implements IPlacementHelper {
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return AllBlocks.MECHANICAL_ROLLER::isIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<BlockState> getStatePredicate() {
|
||||
return AllBlocks.MECHANICAL_ROLLER::has;
|
||||
}
|
||||
|
||||
public int attachedSteps(Level world, BlockPos pos, Direction direction) {
|
||||
BlockPos checkPos = pos.relative(direction);
|
||||
BlockState state = world.getBlockState(checkPos);
|
||||
int count = 0;
|
||||
while (getStatePredicate().test(state)) {
|
||||
count++;
|
||||
checkPos = checkPos.relative(direction);
|
||||
state = world.getBlockState(checkPos);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
|
||||
BlockHitResult ray) {
|
||||
|
||||
Direction dir = null;
|
||||
Direction facing = state.getValue(FACING);
|
||||
|
||||
for (Direction nearest : Direction.orderedByNearest(player)) {
|
||||
if (nearest.getAxis() != facing.getClockWise()
|
||||
.getAxis())
|
||||
continue;
|
||||
dir = nearest;
|
||||
break;
|
||||
}
|
||||
|
||||
int range = AllConfigs.server().curiosities.placementAssistRange.get();
|
||||
if (player != null) {
|
||||
AttributeInstance reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get());
|
||||
if (reach != null && reach.hasModifier(ExtendoGripItem.singleRangeAttributeModifier))
|
||||
range += 4;
|
||||
}
|
||||
|
||||
int row = attachedSteps(world, pos, dir);
|
||||
if (row >= range)
|
||||
return PlacementOffset.fail();
|
||||
|
||||
BlockPos newPos = pos.relative(dir, row + 1);
|
||||
BlockState newState = world.getBlockState(newPos);
|
||||
|
||||
if (!state.canSurvive(world, newPos))
|
||||
return PlacementOffset.fail();
|
||||
|
||||
if (newState.getMaterial()
|
||||
.isReplaceable())
|
||||
return PlacementOffset.success(newPos, bState -> bState.setValue(FACING, facing));
|
||||
return PlacementOffset.fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.simibubi.create.content.contraptions.components.actors;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class RollerBlockItem extends BlockItem {
|
||||
|
||||
public RollerBlockItem(Block pBlock, Properties pProperties) {
|
||||
super(pBlock, pProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult place(BlockPlaceContext ctx) {
|
||||
BlockPos clickedPos = ctx.getClickedPos();
|
||||
Level level = ctx.getLevel();
|
||||
BlockState blockStateBelow = level.getBlockState(clickedPos.below());
|
||||
if (!Block.isFaceFull(blockStateBelow.getCollisionShape(level, clickedPos.below()), Direction.UP))
|
||||
return super.place(ctx);
|
||||
Direction clickedFace = ctx.getClickedFace();
|
||||
return super.place(BlockPlaceContext.at(ctx, clickedPos.relative(Direction.UP), clickedFace));
|
||||
}
|
||||
|
||||
}
|
@ -76,7 +76,8 @@ public class HandCrankBlockEntity extends GeneratingKineticBlockEntity {
|
||||
|
||||
@Override
|
||||
protected Block getStressConfigKey() {
|
||||
return AllBlocks.HAND_CRANK.get();
|
||||
return AllBlocks.HAND_CRANK.has(getBlockState()) ? AllBlocks.HAND_CRANK.get()
|
||||
: AllBlocks.COPPER_VALVE_HANDLE.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,9 +12,13 @@ import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
@ -24,6 +28,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
@ -40,7 +45,8 @@ public class SawBlock extends DirectionalAxisKineticBlock implements IBE<SawBloc
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockState stateForPlacement = super.getStateForPlacement(context);
|
||||
Direction facing = stateForPlacement.getValue(FACING);
|
||||
if (facing.getAxis().isVertical())
|
||||
if (facing.getAxis()
|
||||
.isVertical())
|
||||
return stateForPlacement;
|
||||
return stateForPlacement.setValue(AXIS_ALONG_FIRST_COORDINATE, facing.getAxis() == Axis.X);
|
||||
}
|
||||
@ -50,11 +56,34 @@ public class SawBlock extends DirectionalAxisKineticBlock implements IBE<SawBloc
|
||||
return AllShapes.CASING_12PX.get(state.getValue(FACING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn,
|
||||
BlockHitResult hit) {
|
||||
if (player.isSpectator() || !player.getItemInHand(handIn)
|
||||
.isEmpty())
|
||||
return InteractionResult.PASS;
|
||||
if (state.getOptionalValue(FACING)
|
||||
.orElse(Direction.WEST) != Direction.UP)
|
||||
return InteractionResult.PASS;
|
||||
return onBlockEntityUse(worldIn, pos, be -> {
|
||||
for (int i = 0; i < be.inventory.getSlots(); i++) {
|
||||
ItemStack heldItemStack = be.inventory.getStackInSlot(i);
|
||||
if (!worldIn.isClientSide && !heldItemStack.isEmpty())
|
||||
player.getInventory()
|
||||
.placeItemBackInInventory(heldItemStack);
|
||||
}
|
||||
be.inventory.clear();
|
||||
be.notifyUpdate();
|
||||
return InteractionResult.SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entityInside(BlockState state, Level worldIn, BlockPos pos, Entity entityIn) {
|
||||
if (entityIn instanceof ItemEntity)
|
||||
return;
|
||||
if (!new AABB(pos).deflate(.1f).intersects(entityIn.getBoundingBox()))
|
||||
if (!new AABB(pos).deflate(.1f)
|
||||
.intersects(entityIn.getBoundingBox()))
|
||||
return;
|
||||
withBlockEntityDo(worldIn, pos, be -> {
|
||||
if (be.getSpeed() == 0)
|
||||
@ -85,30 +114,33 @@ public class SawBlock extends DirectionalAxisKineticBlock implements IBE<SawBloc
|
||||
}
|
||||
|
||||
public static boolean isHorizontal(BlockState state) {
|
||||
return state.getValue(FACING).getAxis().isHorizontal();
|
||||
return state.getValue(FACING)
|
||||
.getAxis()
|
||||
.isHorizontal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Axis getRotationAxis(BlockState state) {
|
||||
return isHorizontal(state) ? state.getValue(FACING).getAxis() : super.getRotationAxis(state);
|
||||
return isHorizontal(state) ? state.getValue(FACING)
|
||||
.getAxis() : super.getRotationAxis(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
|
||||
return isHorizontal(state) ? face == state.getValue(FACING).getOpposite()
|
||||
: super.hasShaftTowards(world, pos, state, face);
|
||||
return isHorizontal(state) ? face == state.getValue(FACING)
|
||||
.getOpposite() : super.hasShaftTowards(world, pos, state, face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<SawBlockEntity> getBlockEntityClass() {
|
||||
return SawBlockEntity.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockEntityType<? extends SawBlockEntity> getBlockEntityType() {
|
||||
return AllBlockEntityTypes.SAW.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) {
|
||||
return false;
|
||||
|
@ -241,7 +241,7 @@ public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity
|
||||
}
|
||||
|
||||
public boolean isNearInitialAngle() {
|
||||
return Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45;
|
||||
return Math.abs(angle) < 22.5 || Math.abs(angle) > 360 - 22.5;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,7 +6,9 @@ import com.simibubi.create.content.contraptions.processing.EmptyingByBasin;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.foundation.advancement.AdvancementBehaviour;
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
|
||||
import com.simibubi.create.foundation.blockEntity.ComparatorUtil;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.belt.DirectBeltInputBehaviour;
|
||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -14,7 +16,9 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@ -25,6 +29,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
@ -56,7 +61,8 @@ public class ItemDrainBlock extends Block implements IWrenchable, IBE<ItemDrainB
|
||||
|
||||
ItemStack heldItemStack = be.getHeldItemStack();
|
||||
if (!worldIn.isClientSide && !heldItemStack.isEmpty()) {
|
||||
player.getInventory().placeItemBackInInventory(heldItemStack);
|
||||
player.getInventory()
|
||||
.placeItemBackInInventory(heldItemStack);
|
||||
be.heldItem = null;
|
||||
be.notifyUpdate();
|
||||
}
|
||||
@ -64,6 +70,31 @@ public class ItemDrainBlock extends Block implements IWrenchable, IBE<ItemDrainB
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) {
|
||||
super.updateEntityAfterFallOn(worldIn, entityIn);
|
||||
if (!(entityIn instanceof ItemEntity))
|
||||
return;
|
||||
if (!entityIn.isAlive())
|
||||
return;
|
||||
if (entityIn.level.isClientSide)
|
||||
return;
|
||||
|
||||
ItemEntity itemEntity = (ItemEntity) entityIn;
|
||||
DirectBeltInputBehaviour inputBehaviour =
|
||||
BlockEntityBehaviour.get(worldIn, entityIn.blockPosition(), DirectBeltInputBehaviour.TYPE);
|
||||
if (inputBehaviour == null)
|
||||
return;
|
||||
Vec3 deltaMovement = entityIn.getDeltaMovement()
|
||||
.multiply(1, 0, 1)
|
||||
.normalize();
|
||||
Direction nearest = Direction.getNearest(deltaMovement.x, deltaMovement.y, deltaMovement.z);
|
||||
ItemStack remainder = inputBehaviour.handleInsertion(itemEntity.getItem(), nearest, false);
|
||||
itemEntity.setItem(remainder);
|
||||
if (remainder.isEmpty())
|
||||
itemEntity.discard();
|
||||
}
|
||||
|
||||
protected InteractionResult tryExchange(Level worldIn, Player player, InteractionHand handIn, ItemStack heldItem,
|
||||
ItemDrainBlockEntity be) {
|
||||
if (FluidHelper.tryEmptyItemIntoTE(worldIn, player, handIn, heldItem, be))
|
||||
@ -95,13 +126,13 @@ public class ItemDrainBlock extends Block implements IWrenchable, IBE<ItemDrainB
|
||||
public Class<ItemDrainBlockEntity> getBlockEntityClass() {
|
||||
return ItemDrainBlockEntity.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) {
|
||||
super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack);
|
||||
AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockEntityType<? extends ItemDrainBlockEntity> getBlockEntityType() {
|
||||
return AllBlockEntityTypes.ITEM_DRAIN.get();
|
||||
|
@ -0,0 +1,44 @@
|
||||
package com.simibubi.create.content.curiosities.clipboard;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
|
||||
public class ClipboardEditPacket extends SimplePacketBase {
|
||||
|
||||
private int hotbarSlot;
|
||||
private CompoundTag data;
|
||||
|
||||
public ClipboardEditPacket(int hotbarSlot, CompoundTag data) {
|
||||
this.hotbarSlot = hotbarSlot;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ClipboardEditPacket(FriendlyByteBuf buffer) {
|
||||
hotbarSlot = buffer.readVarInt();
|
||||
data = buffer.readNbt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeVarInt(hotbarSlot);
|
||||
buffer.writeNbt(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Context context) {
|
||||
ServerPlayer sender = context.getSender();
|
||||
ItemStack itemStack = sender.getInventory()
|
||||
.getItem(hotbarSlot);
|
||||
if (!AllItems.CLIPBOARD.isIn(itemStack))
|
||||
return true;
|
||||
itemStack.setTag(data.isEmpty() ? null : data);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.simibubi.create.content.curiosities.clipboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public class ClipboardEntry {
|
||||
|
||||
public boolean checked;
|
||||
public MutableComponent text;
|
||||
public ItemStack icon;
|
||||
|
||||
public ClipboardEntry(boolean checked, MutableComponent text) {
|
||||
this.checked = checked;
|
||||
this.text = text;
|
||||
this.icon = ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
public ClipboardEntry displayItem(ItemStack icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static List<List<ClipboardEntry>> readAll(ItemStack clipboardItem) {
|
||||
CompoundTag tag = clipboardItem.getTag();
|
||||
if (tag == null)
|
||||
return new ArrayList<>();
|
||||
return NBTHelper.readCompoundList(tag.getList("Pages", Tag.TAG_COMPOUND), pageTag -> NBTHelper
|
||||
.readCompoundList(pageTag.getList("Entries", Tag.TAG_COMPOUND), ClipboardEntry::readNBT));
|
||||
}
|
||||
|
||||
public static List<ClipboardEntry> getLastViewedEntries(ItemStack heldItem) {
|
||||
List<List<ClipboardEntry>> pages = ClipboardEntry.readAll(heldItem);
|
||||
if (pages.isEmpty())
|
||||
return new ArrayList<>();
|
||||
int page = heldItem.getTag() == null ? 0
|
||||
: Math.min(heldItem.getTag()
|
||||
.getInt("PreviouslyOpenedPage"), pages.size() - 1);
|
||||
List<ClipboardEntry> entries = pages.get(page);
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static void saveAll(List<List<ClipboardEntry>> entries, ItemStack clipboardItem) {
|
||||
CompoundTag tag = clipboardItem.getOrCreateTag();
|
||||
tag.put("Pages", NBTHelper.writeCompoundList(entries, list -> {
|
||||
CompoundTag pageTag = new CompoundTag();
|
||||
pageTag.put("Entries", NBTHelper.writeCompoundList(list, ClipboardEntry::writeNBT));
|
||||
return pageTag;
|
||||
}));
|
||||
}
|
||||
|
||||
public CompoundTag writeNBT() {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putBoolean("Checked", checked);
|
||||
nbt.putString("Text", Component.Serializer.toJson(text));
|
||||
if (icon.isEmpty())
|
||||
return nbt;
|
||||
nbt.put("Icon", icon.serializeNBT());
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static ClipboardEntry readNBT(CompoundTag tag) {
|
||||
ClipboardEntry clipboardEntry =
|
||||
new ClipboardEntry(tag.getBoolean("Checked"), Component.Serializer.fromJson(tag.getString("Text")));
|
||||
if (tag.contains("Icon"))
|
||||
clipboardEntry.displayItem(ItemStack.of(tag.getCompound("Icon")));
|
||||
return clipboardEntry;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.simibubi.create.content.curiosities.clipboard;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.foundation.gui.ScreenOpener;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class ClipboardItem extends Item {
|
||||
|
||||
public ClipboardItem(Properties pProperties) {
|
||||
super(pProperties);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
if (context.getPlayer() == null)
|
||||
return InteractionResult.PASS;
|
||||
return use(context.getLevel(), context.getPlayer(), context.getHand()).getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
|
||||
ItemStack heldItem = player.getItemInHand(hand);
|
||||
if (hand == InteractionHand.OFF_HAND)
|
||||
return InteractionResultHolder.pass(heldItem);
|
||||
|
||||
player.getCooldowns()
|
||||
.addCooldown(heldItem.getItem(), 10);
|
||||
if (world.isClientSide)
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(player, heldItem));
|
||||
CompoundTag tag = heldItem.getOrCreateTag();
|
||||
tag.putInt("Type", ClipboardOverrides.ClipboardType.EDITING.ordinal());
|
||||
heldItem.setTag(tag);
|
||||
|
||||
return InteractionResultHolder.success(heldItem);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void openScreen(Player player, ItemStack stack) {
|
||||
if (Minecraft.getInstance().player == player)
|
||||
ScreenOpener.open(new ClipboardScreen(player.getInventory().selected, stack));
|
||||
}
|
||||
|
||||
public void registerModelOverrides() {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClipboardOverrides.registerModelOverridesClient(this));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.simibubi.create.content.curiosities.clipboard;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.tterrag.registrate.providers.DataGenContext;
|
||||
import com.tterrag.registrate.providers.RegistrateItemModelProvider;
|
||||
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.model.generators.ItemModelBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelFile.UncheckedModelFile;
|
||||
|
||||
public class ClipboardOverrides {
|
||||
|
||||
public enum ClipboardType {
|
||||
EMPTY("empty_clipboard"), WRITTEN("clipboard"), EDITING("clipboard_and_quill");
|
||||
|
||||
public String file;
|
||||
public static ResourceLocation ID = Create.asResource("clipboard_type");
|
||||
|
||||
private ClipboardType(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
}
|
||||
|
||||
public static void switchTo(ClipboardType type, ItemStack clipboardItem) {
|
||||
CompoundTag tag = clipboardItem.getOrCreateTag();
|
||||
tag.putInt("Type", type.ordinal());
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void registerModelOverridesClient(ClipboardItem item) {
|
||||
ItemProperties.register(item, ClipboardType.ID, (pStack, pLevel, pEntity, pSeed) -> {
|
||||
CompoundTag tag = pStack.getTag();
|
||||
return tag == null ? 0 : tag.getInt("Type");
|
||||
});
|
||||
}
|
||||
|
||||
public static ItemModelBuilder addOverrideModels(DataGenContext<Item, ClipboardItem> c,
|
||||
RegistrateItemModelProvider p) {
|
||||
ItemModelBuilder builder = p.generated(() -> c.get());
|
||||
for (int i = 0; i < ClipboardType.values().length; i++) {
|
||||
builder.override()
|
||||
.predicate(ClipboardType.ID, i)
|
||||
.model(p.getBuilder(c.getName() + "_" + i)
|
||||
.parent(new UncheckedModelFile("item/generated"))
|
||||
.texture("layer0", Create.asResource("item/" + ClipboardType.values()[i].file)))
|
||||
.end();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,792 @@
|
||||
package com.simibubi.create.content.curiosities.clipboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides.ClipboardType;
|
||||
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.widget.IconButton;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.StringSplitter;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
import net.minecraft.client.gui.font.TextFieldHelper;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.PageButton;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.util.FormattedCharSequence;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class ClipboardScreen extends AbstractSimiScreen {
|
||||
|
||||
private ItemStack item;
|
||||
|
||||
List<List<ClipboardEntry>> pages;
|
||||
List<ClipboardEntry> currentEntries;
|
||||
int editingIndex;
|
||||
int frameTick;
|
||||
PageButton forward;
|
||||
PageButton backward;
|
||||
int currentPage;
|
||||
long lastClickTime;
|
||||
int lastIndex = -1;
|
||||
|
||||
int hoveredEntry;
|
||||
boolean hoveredCheck;
|
||||
boolean readonly;
|
||||
|
||||
DisplayCache displayCache = DisplayCache.EMPTY;
|
||||
TextFieldHelper editContext;
|
||||
|
||||
IconButton closeBtn;
|
||||
IconButton clearBtn;
|
||||
|
||||
private int targetSlot;
|
||||
|
||||
public ClipboardScreen(int targetSlot, ItemStack item) {
|
||||
this.targetSlot = targetSlot;
|
||||
this.item = item;
|
||||
pages = ClipboardEntry.readAll(item);
|
||||
if (pages.isEmpty())
|
||||
pages.add(new ArrayList<>());
|
||||
currentPage = item.getTag() == null ? 0
|
||||
: item.getTag()
|
||||
.getInt("PreviouslyOpenedPage");
|
||||
currentPage = Mth.clamp(currentPage, 0, pages.size() - 1);
|
||||
currentEntries = pages.get(currentPage);
|
||||
boolean startEmpty = currentEntries.isEmpty();
|
||||
if (startEmpty)
|
||||
currentEntries.add(new ClipboardEntry(false, Components.empty()));
|
||||
editingIndex = 0;
|
||||
editContext = new TextFieldHelper(this::getCurrentEntryText, this::setCurrentEntryText, this::getClipboard,
|
||||
this::setClipboard, this::validateTextForEntry);
|
||||
editingIndex = startEmpty ? 0 : -1;
|
||||
readonly = item.getTag() != null && item.getTag()
|
||||
.getBoolean("Readonly");
|
||||
if (readonly)
|
||||
editingIndex = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
setWindowSize(256, 256);
|
||||
super.init();
|
||||
minecraft.keyboardHandler.setSendRepeatsToGui(true);
|
||||
clearDisplayCache();
|
||||
|
||||
int x = guiLeft;
|
||||
int y = guiTop - 8;
|
||||
|
||||
clearWidgets();
|
||||
clearBtn = new IconButton(x + 234, y + 153, AllIcons.I_CLEAR_CHECKED).withCallback(() -> {
|
||||
editingIndex = -1;
|
||||
currentEntries.removeIf(ce -> ce.checked);
|
||||
if (currentEntries.isEmpty())
|
||||
currentEntries.add(new ClipboardEntry(false, Components.empty()));
|
||||
});
|
||||
clearBtn.setToolTip(Lang.translateDirect("gui.clipboard.erase_checked"));
|
||||
closeBtn = new IconButton(x + 234, y + 175, AllIcons.I_PRIORITY_VERY_LOW)
|
||||
.withCallback(() -> minecraft.setScreen(null));
|
||||
closeBtn.setToolTip(Lang.translateDirect("station.close"));
|
||||
addRenderableWidget(closeBtn);
|
||||
addRenderableWidget(clearBtn);
|
||||
|
||||
forward = new PageButton(x + 176, y + 229, true, $ -> changePage(true), true);
|
||||
backward = new PageButton(x + 53, y + 229, false, $ -> changePage(false), true);
|
||||
addRenderableWidget(forward);
|
||||
addRenderableWidget(backward);
|
||||
|
||||
forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size());
|
||||
backward.visible = currentPage > 0;
|
||||
}
|
||||
|
||||
private int getNumPages() {
|
||||
return pages.size();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
super.tick();
|
||||
frameTick++;
|
||||
|
||||
int mx = (int) (this.minecraft.mouseHandler.xpos() * (double) this.minecraft.getWindow()
|
||||
.getGuiScaledWidth() / (double) this.minecraft.getWindow()
|
||||
.getScreenWidth());
|
||||
int my = (int) (this.minecraft.mouseHandler.ypos() * (double) this.minecraft.getWindow()
|
||||
.getGuiScaledHeight() / (double) this.minecraft.getWindow()
|
||||
.getScreenHeight());
|
||||
|
||||
mx -= guiLeft + 35;
|
||||
my -= guiTop + 41;
|
||||
|
||||
hoveredCheck = false;
|
||||
hoveredEntry = -1;
|
||||
|
||||
if (mx > 0 && mx < 183 && my > 0 && my < 190) {
|
||||
hoveredCheck = mx < 20;
|
||||
int totalHeight = 0;
|
||||
for (int i = 0; i < currentEntries.size(); i++) {
|
||||
ClipboardEntry clipboardEntry = currentEntries.get(i);
|
||||
String text = clipboardEntry.text.getString();
|
||||
totalHeight +=
|
||||
Math.max(12, font.split(Components.literal(text), clipboardEntry.icon.isEmpty() ? 150 : 130)
|
||||
.size() * 9 + 3);
|
||||
|
||||
if (totalHeight > my) {
|
||||
hoveredEntry = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
hoveredEntry = currentEntries.size();
|
||||
}
|
||||
}
|
||||
|
||||
private String getCurrentEntryText() {
|
||||
return currentEntries.get(editingIndex).text.getString();
|
||||
}
|
||||
|
||||
private void setCurrentEntryText(String text) {
|
||||
currentEntries.get(editingIndex).text = Components.literal(text);
|
||||
}
|
||||
|
||||
private void setClipboard(String p_98148_) {
|
||||
if (minecraft != null)
|
||||
TextFieldHelper.setClipboardContents(minecraft, p_98148_);
|
||||
}
|
||||
|
||||
private String getClipboard() {
|
||||
return minecraft != null ? TextFieldHelper.getClipboardContents(minecraft) : "";
|
||||
}
|
||||
|
||||
private boolean validateTextForEntry(String newText) {
|
||||
int totalHeight = 0;
|
||||
for (int i = 0; i < currentEntries.size(); i++) {
|
||||
ClipboardEntry clipboardEntry = currentEntries.get(i);
|
||||
String text = i == editingIndex ? newText : clipboardEntry.text.getString();
|
||||
totalHeight += Math.max(12, font.split(Components.literal(text), 150)
|
||||
.size() * 9 + 3);
|
||||
}
|
||||
return totalHeight < 185;
|
||||
}
|
||||
|
||||
private int yOffsetOfEditingEntry() {
|
||||
int totalHeight = 0;
|
||||
for (int i = 0; i < currentEntries.size(); i++) {
|
||||
if (i == editingIndex)
|
||||
break;
|
||||
ClipboardEntry clipboardEntry = currentEntries.get(i);
|
||||
totalHeight += Math.max(12, font.split(clipboardEntry.text, 150)
|
||||
.size() * 9 + 3);
|
||||
}
|
||||
return totalHeight;
|
||||
}
|
||||
|
||||
private void changePage(boolean next) {
|
||||
int previously = currentPage;
|
||||
currentPage = Mth.clamp(currentPage + (next ? 1 : -1), 0, 50);
|
||||
if (currentPage == previously)
|
||||
return;
|
||||
editingIndex = -1;
|
||||
if (pages.size() <= currentPage) {
|
||||
if (readonly) {
|
||||
currentPage = previously;
|
||||
return;
|
||||
}
|
||||
pages.add(new ArrayList<>());
|
||||
}
|
||||
currentEntries = pages.get(currentPage);
|
||||
if (currentEntries.isEmpty()) {
|
||||
currentEntries.add(new ClipboardEntry(false, Components.empty()));
|
||||
if (!readonly) {
|
||||
editingIndex = 0;
|
||||
editContext.setCursorToEnd();
|
||||
clearDisplayCacheAfterChange();
|
||||
}
|
||||
}
|
||||
|
||||
forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size());
|
||||
backward.visible = currentPage > 0;
|
||||
|
||||
if (next)
|
||||
return;
|
||||
if (pages.get(currentPage + 1)
|
||||
.stream()
|
||||
.allMatch(ce -> ce.text.getString()
|
||||
.isBlank()))
|
||||
pages.remove(currentPage + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
|
||||
int x = guiLeft;
|
||||
int y = guiTop - 8;
|
||||
|
||||
AllGuiTextures.CLIPBOARD.render(ms, x, y);
|
||||
font.draw(ms, new TranslatableComponent("book.pageIndicator", currentPage + 1, getNumPages()), x + 150, y + 9,
|
||||
0x43ffffff);
|
||||
|
||||
for (int i = 0; i < currentEntries.size(); i++) {
|
||||
ClipboardEntry clipboardEntry = currentEntries.get(i);
|
||||
boolean checked = clipboardEntry.checked;
|
||||
int iconOffset = clipboardEntry.icon.isEmpty() ? 0 : 16;
|
||||
|
||||
font.draw(ms, "\u25A1", x + 45, y + 51, checked ? 0x668D7F6B : 0xff8D7F6B);
|
||||
if (checked)
|
||||
font.draw(ms, "\u2714", x + 45, y + 50, 0x31B25D);
|
||||
|
||||
List<FormattedCharSequence> split = font.split(clipboardEntry.text, 150 - iconOffset);
|
||||
if (split.isEmpty()) {
|
||||
y += 12;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!clipboardEntry.icon.isEmpty())
|
||||
itemRenderer.renderGuiItem(clipboardEntry.icon, x + 54, y + 50);
|
||||
|
||||
for (FormattedCharSequence sequence : split) {
|
||||
if (i != editingIndex)
|
||||
font.draw(ms, sequence, x + 58 + iconOffset, y + 50, checked ? 0x31B25D : 0x311A00);
|
||||
y += 9;
|
||||
}
|
||||
y += 3;
|
||||
}
|
||||
|
||||
if (editingIndex == -1)
|
||||
return;
|
||||
|
||||
boolean checked = currentEntries.get(editingIndex).checked;
|
||||
|
||||
setFocused(null);
|
||||
DisplayCache cache = getDisplayCache();
|
||||
|
||||
for (LineInfo line : cache.lines)
|
||||
font.draw(ms, line.asComponent, line.x, line.y, checked ? 0x31B25D : 0x311A00);
|
||||
|
||||
renderHighlight(cache.selection);
|
||||
renderCursor(ms, cache.cursor, cache.cursorAtEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
minecraft.keyboardHandler.setSendRepeatsToGui(false);
|
||||
pages.forEach(list -> list.removeIf(ce -> ce.text.getString()
|
||||
.isBlank()));
|
||||
pages.removeIf(List::isEmpty);
|
||||
|
||||
ClipboardEntry.saveAll(pages, item);
|
||||
ClipboardOverrides.switchTo(ClipboardType.WRITTEN, item);
|
||||
|
||||
for (int i = 0; i < pages.size(); i++)
|
||||
if (pages.get(i) == currentEntries)
|
||||
item.getTag()
|
||||
.putInt("PreviouslyOpenedPage", i);
|
||||
|
||||
if (pages.isEmpty())
|
||||
item.setTag(new CompoundTag());
|
||||
AllPackets.getChannel()
|
||||
.sendToServer(new ClipboardEditPacket(targetSlot, item.getOrCreateTag()));
|
||||
super.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPauseScreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
|
||||
if (pKeyCode == 266) {
|
||||
backward.onPress();
|
||||
return true;
|
||||
}
|
||||
if (pKeyCode == 267) {
|
||||
forward.onPress();
|
||||
return true;
|
||||
}
|
||||
if (editingIndex != -1 && pKeyCode != 256) {
|
||||
keyPressedWhileEditing(pKeyCode, pScanCode, pModifiers);
|
||||
clearDisplayCache();
|
||||
return true;
|
||||
}
|
||||
if (super.keyPressed(pKeyCode, pScanCode, pModifiers))
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char pCodePoint, int pModifiers) {
|
||||
if (super.charTyped(pCodePoint, pModifiers))
|
||||
return true;
|
||||
if (!SharedConstants.isAllowedChatCharacter(pCodePoint))
|
||||
return false;
|
||||
if (editingIndex == -1)
|
||||
return false;
|
||||
editContext.insertText(Character.toString(pCodePoint));
|
||||
clearDisplayCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean keyPressedWhileEditing(int pKeyCode, int pScanCode, int pModifiers) {
|
||||
if (Screen.isSelectAll(pKeyCode)) {
|
||||
editContext.selectAll();
|
||||
return true;
|
||||
} else if (Screen.isCopy(pKeyCode)) {
|
||||
editContext.copy();
|
||||
return true;
|
||||
} else if (Screen.isPaste(pKeyCode)) {
|
||||
editContext.paste();
|
||||
return true;
|
||||
} else if (Screen.isCut(pKeyCode)) {
|
||||
editContext.cut();
|
||||
return true;
|
||||
} else {
|
||||
switch (pKeyCode) {
|
||||
case 257:
|
||||
case 335:
|
||||
if (hasShiftDown()) {
|
||||
editContext.insertText("\n");
|
||||
return true;
|
||||
} else if (!hasControlDown()) {
|
||||
if (currentEntries.size() <= editingIndex + 1
|
||||
|| !currentEntries.get(editingIndex + 1).text.getString()
|
||||
.isEmpty())
|
||||
currentEntries.add(editingIndex + 1, new ClipboardEntry(false, Components.empty()));
|
||||
editingIndex += 1;
|
||||
editContext.setCursorToEnd();
|
||||
if (validateTextForEntry(" "))
|
||||
return true;
|
||||
currentEntries.remove(editingIndex);
|
||||
editingIndex -= 1;
|
||||
editContext.setCursorToEnd();
|
||||
return true;
|
||||
}
|
||||
editingIndex = -1;
|
||||
return true;
|
||||
case 259:
|
||||
if (currentEntries.get(editingIndex).text.getString()
|
||||
.isEmpty() && currentEntries.size() > 1) {
|
||||
currentEntries.remove(editingIndex);
|
||||
editingIndex -= 1;
|
||||
editContext.setCursorToEnd();
|
||||
return true;
|
||||
} else if (hasControlDown()) {
|
||||
int prevPos = editContext.getCursorPos();
|
||||
editContext.moveByWords(-1);
|
||||
if (prevPos != editContext.getCursorPos())
|
||||
editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos());
|
||||
return true;
|
||||
}
|
||||
editContext.removeCharsFromCursor(-1);
|
||||
return true;
|
||||
case 261:
|
||||
if (hasControlDown()) {
|
||||
int prevPos = editContext.getCursorPos();
|
||||
editContext.moveByWords(1);
|
||||
if (prevPos != editContext.getCursorPos())
|
||||
editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos());
|
||||
return true;
|
||||
}
|
||||
editContext.removeCharsFromCursor(1);
|
||||
return true;
|
||||
case 262:
|
||||
if (hasControlDown()) {
|
||||
editContext.moveByWords(1, Screen.hasShiftDown());
|
||||
return true;
|
||||
}
|
||||
editContext.moveByChars(1, Screen.hasShiftDown());
|
||||
return true;
|
||||
case 263:
|
||||
if (hasControlDown()) {
|
||||
editContext.moveByWords(-1, Screen.hasShiftDown());
|
||||
return true;
|
||||
}
|
||||
editContext.moveByChars(-1, Screen.hasShiftDown());
|
||||
return true;
|
||||
case 264:
|
||||
keyDown();
|
||||
return true;
|
||||
case 265:
|
||||
keyUp();
|
||||
return true;
|
||||
case 268:
|
||||
keyHome();
|
||||
return true;
|
||||
case 269:
|
||||
keyEnd();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void keyUp() {
|
||||
changeLine(-1);
|
||||
}
|
||||
|
||||
private void keyDown() {
|
||||
changeLine(1);
|
||||
}
|
||||
|
||||
private void changeLine(int pYChange) {
|
||||
int i = editContext.getCursorPos();
|
||||
int j = getDisplayCache().changeLine(i, pYChange);
|
||||
editContext.setCursorPos(j, Screen.hasShiftDown());
|
||||
}
|
||||
|
||||
private void keyHome() {
|
||||
int i = editContext.getCursorPos();
|
||||
int j = getDisplayCache().findLineStart(i);
|
||||
editContext.setCursorPos(j, Screen.hasShiftDown());
|
||||
}
|
||||
|
||||
private void keyEnd() {
|
||||
DisplayCache cache = getDisplayCache();
|
||||
int i = editContext.getCursorPos();
|
||||
int j = cache.findLineEnd(i);
|
||||
editContext.setCursorPos(j, Screen.hasShiftDown());
|
||||
}
|
||||
|
||||
private void renderCursor(PoseStack pPoseStack, Pos2i pCursorPos, boolean pIsEndOfText) {
|
||||
if (frameTick / 6 % 2 != 0)
|
||||
return;
|
||||
pCursorPos = convertLocalToScreen(pCursorPos);
|
||||
if (!pIsEndOfText) {
|
||||
GuiComponent.fill(pPoseStack, pCursorPos.x, pCursorPos.y - 1, pCursorPos.x + 1, pCursorPos.y + 9,
|
||||
-16777216);
|
||||
} else {
|
||||
font.draw(pPoseStack, "_", (float) pCursorPos.x, (float) pCursorPos.y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderHighlight(Rect2i[] pSelected) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder bufferbuilder = tesselator.getBuilder();
|
||||
RenderSystem.setShader(GameRenderer::getPositionShader);
|
||||
RenderSystem.setShaderColor(0.0F, 0.0F, 255.0F, 255.0F);
|
||||
RenderSystem.disableTexture();
|
||||
RenderSystem.enableColorLogicOp();
|
||||
RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE);
|
||||
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION);
|
||||
|
||||
for (Rect2i rect2i : pSelected) {
|
||||
int i = rect2i.getX();
|
||||
int j = rect2i.getY();
|
||||
int k = i + rect2i.getWidth();
|
||||
int l = j + rect2i.getHeight();
|
||||
bufferbuilder.vertex((double) i, (double) l, 0.0D)
|
||||
.endVertex();
|
||||
bufferbuilder.vertex((double) k, (double) l, 0.0D)
|
||||
.endVertex();
|
||||
bufferbuilder.vertex((double) k, (double) j, 0.0D)
|
||||
.endVertex();
|
||||
bufferbuilder.vertex((double) i, (double) j, 0.0D)
|
||||
.endVertex();
|
||||
}
|
||||
|
||||
tesselator.end();
|
||||
RenderSystem.disableColorLogicOp();
|
||||
RenderSystem.enableTexture();
|
||||
}
|
||||
|
||||
private Pos2i convertScreenToLocal(Pos2i pScreenPos) {
|
||||
return new Pos2i(pScreenPos.x - (width - 192) / 2 - 36 + 10, pScreenPos.y - 32 - 24 - yOffsetOfEditingEntry());
|
||||
}
|
||||
|
||||
private Pos2i convertLocalToScreen(Pos2i pLocalScreenPos) {
|
||||
return new Pos2i(pLocalScreenPos.x + (width - 192) / 2 + 36 - 10,
|
||||
pLocalScreenPos.y + 32 + 24 + yOffsetOfEditingEntry());
|
||||
}
|
||||
|
||||
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
|
||||
if (super.mouseClicked(pMouseX, pMouseY, pButton))
|
||||
return true;
|
||||
if (pButton != 0)
|
||||
return true;
|
||||
|
||||
if (hoveredEntry != -1) {
|
||||
if (hoveredCheck) {
|
||||
editingIndex = -1;
|
||||
if (hoveredEntry < currentEntries.size())
|
||||
currentEntries.get(hoveredEntry).checked ^= true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hoveredEntry != editingIndex && !readonly) {
|
||||
editingIndex = hoveredEntry;
|
||||
if (hoveredEntry >= currentEntries.size()) {
|
||||
currentEntries.add(new ClipboardEntry(false, Components.empty()));
|
||||
if (!validateTextForEntry(" ")) {
|
||||
currentEntries.remove(hoveredEntry);
|
||||
editingIndex = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
clearDisplayCacheAfterChange();
|
||||
}
|
||||
}
|
||||
|
||||
if (editingIndex == -1)
|
||||
return false;
|
||||
|
||||
long i = Util.getMillis();
|
||||
DisplayCache cache = getDisplayCache();
|
||||
int j = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY)));
|
||||
if (j >= 0) {
|
||||
if (j == lastIndex && i - lastClickTime < 250L) {
|
||||
if (!editContext.isSelecting()) {
|
||||
selectWord(j);
|
||||
} else {
|
||||
editContext.selectAll();
|
||||
}
|
||||
} else {
|
||||
editContext.setCursorPos(j, Screen.hasShiftDown());
|
||||
}
|
||||
|
||||
clearDisplayCache();
|
||||
}
|
||||
|
||||
lastIndex = j;
|
||||
lastClickTime = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void selectWord(int pIndex) {
|
||||
String s = getCurrentEntryText();
|
||||
editContext.setSelectionRange(StringSplitter.getWordPosition(s, -1, pIndex, false),
|
||||
StringSplitter.getWordPosition(s, 1, pIndex, false));
|
||||
}
|
||||
|
||||
public boolean mouseDragged(double pMouseX, double pMouseY, int pButton, double pDragX, double pDragY) {
|
||||
if (super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY))
|
||||
return true;
|
||||
if (pButton != 0)
|
||||
return true;
|
||||
if (editingIndex == -1)
|
||||
return false;
|
||||
|
||||
DisplayCache cache = getDisplayCache();
|
||||
int i = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY)));
|
||||
editContext.setCursorPos(i, true);
|
||||
clearDisplayCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
private DisplayCache getDisplayCache() {
|
||||
if (displayCache == null)
|
||||
displayCache = rebuildDisplayCache();
|
||||
return displayCache;
|
||||
}
|
||||
|
||||
private void clearDisplayCache() {
|
||||
displayCache = null;
|
||||
}
|
||||
|
||||
private void clearDisplayCacheAfterChange() {
|
||||
editContext.setCursorToEnd();
|
||||
clearDisplayCache();
|
||||
}
|
||||
|
||||
private DisplayCache rebuildDisplayCache() {
|
||||
String s = getCurrentEntryText();
|
||||
if (s.isEmpty())
|
||||
return DisplayCache.EMPTY;
|
||||
|
||||
int i = editContext.getCursorPos();
|
||||
int j = editContext.getSelectionPos();
|
||||
IntList intlist = new IntArrayList();
|
||||
List<LineInfo> list = Lists.newArrayList();
|
||||
MutableInt mutableint = new MutableInt();
|
||||
MutableBoolean mutableboolean = new MutableBoolean();
|
||||
StringSplitter stringsplitter = font.getSplitter();
|
||||
stringsplitter.splitLines(s, 150, Style.EMPTY, true, (p_98132_, p_98133_, p_98134_) -> {
|
||||
int k3 = mutableint.getAndIncrement();
|
||||
String s2 = s.substring(p_98133_, p_98134_);
|
||||
mutableboolean.setValue(s2.endsWith("\n"));
|
||||
String s3 = StringUtils.stripEnd(s2, " \n");
|
||||
int l3 = k3 * 9;
|
||||
Pos2i pos1 = convertLocalToScreen(new Pos2i(0, l3));
|
||||
intlist.add(p_98133_);
|
||||
list.add(new LineInfo(p_98132_, s3, pos1.x, pos1.y));
|
||||
});
|
||||
|
||||
int[] aint = intlist.toIntArray();
|
||||
boolean flag = i == s.length();
|
||||
Pos2i pos;
|
||||
if (flag && mutableboolean.isTrue()) {
|
||||
pos = new Pos2i(0, list.size() * 9);
|
||||
} else {
|
||||
int k = findLineFromPos(aint, i);
|
||||
int l = font.width(s.substring(aint[k], i));
|
||||
pos = new Pos2i(l, k * 9);
|
||||
}
|
||||
|
||||
List<Rect2i> list1 = Lists.newArrayList();
|
||||
if (i != j) {
|
||||
int l2 = Math.min(i, j);
|
||||
int i1 = Math.max(i, j);
|
||||
int j1 = findLineFromPos(aint, l2);
|
||||
int k1 = findLineFromPos(aint, i1);
|
||||
if (j1 == k1) {
|
||||
int l1 = j1 * 9;
|
||||
int i2 = aint[j1];
|
||||
list1.add(createPartialLineSelection(s, stringsplitter, l2, i1, l1, i2));
|
||||
} else {
|
||||
int i3 = j1 + 1 > aint.length ? s.length() : aint[j1 + 1];
|
||||
list1.add(createPartialLineSelection(s, stringsplitter, l2, i3, j1 * 9, aint[j1]));
|
||||
|
||||
for (int j3 = j1 + 1; j3 < k1; ++j3) {
|
||||
int j2 = j3 * 9;
|
||||
String s1 = s.substring(aint[j3], aint[j3 + 1]);
|
||||
int k2 = (int) stringsplitter.stringWidth(s1);
|
||||
list1.add(createSelection(new Pos2i(0, j2), new Pos2i(k2, j2 + 9)));
|
||||
}
|
||||
|
||||
list1.add(createPartialLineSelection(s, stringsplitter, aint[k1], i1, k1 * 9, aint[k1]));
|
||||
}
|
||||
}
|
||||
|
||||
return new DisplayCache(s, pos, flag, aint, list.toArray(new LineInfo[0]), list1.toArray(new Rect2i[0]));
|
||||
}
|
||||
|
||||
static int findLineFromPos(int[] pLineStarts, int pFind) {
|
||||
int i = Arrays.binarySearch(pLineStarts, pFind);
|
||||
return i < 0 ? -(i + 2) : i;
|
||||
}
|
||||
|
||||
private Rect2i createPartialLineSelection(String pInput, StringSplitter pSplitter, int p_98122_, int p_98123_,
|
||||
int p_98124_, int p_98125_) {
|
||||
String s = pInput.substring(p_98125_, p_98122_);
|
||||
String s1 = pInput.substring(p_98125_, p_98123_);
|
||||
Pos2i firstPos = new Pos2i((int) pSplitter.stringWidth(s), p_98124_);
|
||||
Pos2i secondPos = new Pos2i((int) pSplitter.stringWidth(s1), p_98124_ + 9);
|
||||
return createSelection(firstPos, secondPos);
|
||||
}
|
||||
|
||||
private Rect2i createSelection(Pos2i pCorner1, Pos2i pCorner2) {
|
||||
Pos2i firstPos = convertLocalToScreen(pCorner1);
|
||||
Pos2i secondPos = convertLocalToScreen(pCorner2);
|
||||
int i = Math.min(firstPos.x, secondPos.x);
|
||||
int j = Math.max(firstPos.x, secondPos.x);
|
||||
int k = Math.min(firstPos.y, secondPos.y);
|
||||
int l = Math.max(firstPos.y, secondPos.y);
|
||||
return new Rect2i(i, k, j - i, l - k);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class DisplayCache {
|
||||
static final DisplayCache EMPTY = new DisplayCache("", new Pos2i(0, 0), true, new int[] { 0 },
|
||||
new LineInfo[] { new LineInfo(Style.EMPTY, "", 0, 0) }, new Rect2i[0]);
|
||||
private final String fullText;
|
||||
final Pos2i cursor;
|
||||
final boolean cursorAtEnd;
|
||||
private final int[] lineStarts;
|
||||
final LineInfo[] lines;
|
||||
final Rect2i[] selection;
|
||||
|
||||
public DisplayCache(String pFullText, Pos2i pCursor, boolean pCursorAtEnd, int[] pLineStarts, LineInfo[] pLines,
|
||||
Rect2i[] pSelection) {
|
||||
fullText = pFullText;
|
||||
cursor = pCursor;
|
||||
cursorAtEnd = pCursorAtEnd;
|
||||
lineStarts = pLineStarts;
|
||||
lines = pLines;
|
||||
selection = pSelection;
|
||||
}
|
||||
|
||||
public int getIndexAtPosition(Font pFont, Pos2i pCursorPosition) {
|
||||
int i = pCursorPosition.y / 9;
|
||||
if (i < 0)
|
||||
return 0;
|
||||
if (i >= lines.length)
|
||||
return fullText.length();
|
||||
LineInfo line = lines[i];
|
||||
return lineStarts[i] + pFont.getSplitter()
|
||||
.plainIndexAtWidth(line.contents, pCursorPosition.x, line.style);
|
||||
}
|
||||
|
||||
public int changeLine(int pXChange, int pYChange) {
|
||||
int i = findLineFromPos(lineStarts, pXChange);
|
||||
int j = i + pYChange;
|
||||
int k;
|
||||
if (0 <= j && j < lineStarts.length) {
|
||||
int l = pXChange - lineStarts[i];
|
||||
int i1 = lines[j].contents.length();
|
||||
k = lineStarts[j] + Math.min(l, i1);
|
||||
} else {
|
||||
k = pXChange;
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
public int findLineStart(int pLine) {
|
||||
int i = findLineFromPos(lineStarts, pLine);
|
||||
return lineStarts[i];
|
||||
}
|
||||
|
||||
public int findLineEnd(int pLine) {
|
||||
int i = findLineFromPos(lineStarts, pLine);
|
||||
return lineStarts[i] + lines[i].contents.length();
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class LineInfo {
|
||||
final Style style;
|
||||
final String contents;
|
||||
final Component asComponent;
|
||||
final int x;
|
||||
final int y;
|
||||
|
||||
public LineInfo(Style pStyle, String pContents, int pX, int pY) {
|
||||
style = pStyle;
|
||||
contents = pContents;
|
||||
x = pX;
|
||||
y = pY;
|
||||
asComponent = (new TextComponent(pContents)).setStyle(pStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class Pos2i {
|
||||
public final int x;
|
||||
public final int y;
|
||||
|
||||
Pos2i(int pX, int pY) {
|
||||
x = pX;
|
||||
y = pY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2,13 +2,16 @@ package com.simibubi.create.content.logistics.block.redstone;
|
||||
|
||||
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry;
|
||||
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
|
||||
import com.simibubi.create.content.schematics.ItemRequirement;
|
||||
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
||||
@ -19,6 +22,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
@ -76,20 +80,31 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName();
|
||||
boolean display =
|
||||
heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllItems.CLIPBOARD.isIn(heldItem);
|
||||
DyeColor dye = DyeColor.getColor(heldItem);
|
||||
|
||||
if (!display && dye == null)
|
||||
return InteractionResult.PASS;
|
||||
if (world.isClientSide)
|
||||
return InteractionResult.SUCCESS;
|
||||
|
||||
CompoundTag tag = heldItem.getTagElement("display");
|
||||
String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null;
|
||||
|
||||
if (AllItems.CLIPBOARD.isIn(heldItem)) {
|
||||
List<ClipboardEntry> entries = ClipboardEntry.getLastViewedEntries(heldItem);
|
||||
for (int i = 0; i < entries.size();) {
|
||||
tagElement = Component.Serializer.toJson(entries.get(i).text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (world.isClientSide)
|
||||
return InteractionResult.SUCCESS;
|
||||
|
||||
String tagUsed = tagElement;
|
||||
walkNixies(world, pos, (currentPos, rowPosition) -> {
|
||||
if (display)
|
||||
withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagElement, rowPosition));
|
||||
withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagUsed, rowPosition));
|
||||
if (dye != null)
|
||||
world.setBlockAndUpdate(currentPos, withColor(state, dye));
|
||||
});
|
||||
|
@ -8,12 +8,15 @@ import java.util.function.Predicate;
|
||||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.content.contraptions.base.KineticBlockEntity;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry;
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||
@ -27,6 +30,7 @@ import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@ -158,7 +162,8 @@ public class FlapDisplayBlock extends HorizontalKineticBlock
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName();
|
||||
boolean display =
|
||||
heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllItems.CLIPBOARD.isIn(heldItem);
|
||||
DyeColor dye = DyeColor.getColor(heldItem);
|
||||
|
||||
if (!display && dye == null)
|
||||
@ -171,8 +176,20 @@ public class FlapDisplayBlock extends HorizontalKineticBlock
|
||||
CompoundTag tag = heldItem.getTagElement("display");
|
||||
String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null;
|
||||
|
||||
if (display)
|
||||
if (display) {
|
||||
if (AllItems.CLIPBOARD.isIn(heldItem)) {
|
||||
List<ClipboardEntry> entries = ClipboardEntry.getLastViewedEntries(heldItem);
|
||||
int line = lineIndex;
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
for (String string : entries.get(i).text.getString()
|
||||
.split("\n"))
|
||||
flapBE.applyTextManually(line++, Component.Serializer.toJson(Components.literal(string)));
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
flapBE.applyTextManually(lineIndex, tagElement);
|
||||
}
|
||||
if (dye != null) {
|
||||
world.playSound(null, pos, SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
flapBE.setColour(lineIndex, dye);
|
||||
@ -315,7 +332,8 @@ public class FlapDisplayBlock extends HorizontalKineticBlock
|
||||
BlockPos relative = pPos.relative(d);
|
||||
BlockState adjacent = pLevel.getBlockState(relative);
|
||||
if (canConnect(pState, adjacent))
|
||||
KineticBlockEntity.switchToBlockState(pLevel, relative, updateColumn(pLevel, relative, adjacent, false));
|
||||
KineticBlockEntity.switchToBlockState(pLevel, relative,
|
||||
updateColumn(pLevel, relative, adjacent, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,17 +6,19 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.util.Color;
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllSpecialTextures;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
@ -27,6 +29,7 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -35,6 +38,7 @@ import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
@ -42,6 +46,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
@ -53,6 +58,9 @@ import net.minecraft.world.phys.HitResult.Type;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.gui.ForgeIngameGui;
|
||||
import net.minecraftforge.client.gui.IIngameOverlay;
|
||||
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class TrackPlacement {
|
||||
@ -98,6 +106,8 @@ public class TrackPlacement {
|
||||
static int hoveringAngle;
|
||||
static ItemStack lastItem;
|
||||
|
||||
static int extraTipWarmup;
|
||||
|
||||
public static PlacementInfo tryConnect(Level level, Player player, BlockPos pos2, BlockState state2,
|
||||
ItemStack stack, boolean girder, boolean maximiseTurn) {
|
||||
Vec3 lookVec = player.getLookAngle();
|
||||
@ -283,10 +293,10 @@ public class TrackPlacement {
|
||||
if (skipCurve && !Mth.equal(ascend, 0)) {
|
||||
int hDistance = info.end1Extent;
|
||||
if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) {
|
||||
|
||||
|
||||
if (axis1.y != 0 && axis1.y == -axis2.y)
|
||||
return info.withMessage("ascending_s_curve");
|
||||
|
||||
|
||||
info.end1Extent = 0;
|
||||
double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length();
|
||||
if (hDistance < minHDistance)
|
||||
@ -447,10 +457,6 @@ public class TrackPlacement {
|
||||
BlockItem paveItem = (BlockItem) offhandItem.getItem();
|
||||
paveTracks(level, info, paveItem, false);
|
||||
}
|
||||
|
||||
if (info.curve != null && info.curve.getLength() > 29)
|
||||
AllAdvancements.LONG_BEND.awardTo(player);
|
||||
|
||||
return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false);
|
||||
}
|
||||
|
||||
@ -576,6 +582,8 @@ public class TrackPlacement {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
HitResult hitResult = Minecraft.getInstance().hitResult;
|
||||
int restoreWarmup = extraTipWarmup;
|
||||
extraTipWarmup = 0;
|
||||
|
||||
if (hitResult == null)
|
||||
return;
|
||||
@ -609,8 +617,14 @@ public class TrackPlacement {
|
||||
if (!(hitState.getBlock() instanceof TrackBlock))
|
||||
return;
|
||||
|
||||
extraTipWarmup = restoreWarmup;
|
||||
boolean maxTurns = Minecraft.getInstance().options.keySprint.isDown();
|
||||
PlacementInfo info = tryConnect(level, player, pos, hitState, stack, false, maxTurns);
|
||||
if (extraTipWarmup < 20)
|
||||
extraTipWarmup++;
|
||||
if (!info.valid || !hoveringMaxed && (info.end1Extent == 0 || info.end2Extent == 0))
|
||||
extraTipWarmup = 0;
|
||||
|
||||
if (!player.isCreative() && (info.valid || !info.hasRequiredTracks || !info.hasRequiredPavement))
|
||||
BlueprintOverlayRenderer.displayTrackRequirements(info, player.getOffhandItem());
|
||||
|
||||
@ -625,7 +639,7 @@ public class TrackPlacement {
|
||||
if (bhr.getDirection() == Direction.UP) {
|
||||
Vec3 lookVec = player.getLookAngle();
|
||||
int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8;
|
||||
|
||||
|
||||
if (!pos.equals(hintPos) || lookAngle != hintAngle) {
|
||||
hints = Couple.create(ArrayList::new);
|
||||
hintAngle = lookAngle;
|
||||
@ -761,4 +775,38 @@ public class TrackPlacement {
|
||||
.colored(color);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static final IIngameOverlay OVERLAY = TrackPlacement::renderOverlay;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void renderOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width,
|
||||
int height) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR)
|
||||
return;
|
||||
if (hoveringPos == null)
|
||||
return;
|
||||
if (cached == null || cached.curve == null || !cached.valid)
|
||||
return;
|
||||
if (extraTipWarmup < 4)
|
||||
return;
|
||||
|
||||
if (ObfuscationReflectionHelper.getPrivateValue(Gui.class, gui,
|
||||
"toolHighlightTimer") instanceof Integer toolHighlightTimer && toolHighlightTimer > 0)
|
||||
return;
|
||||
|
||||
boolean active = mc.options.keySprint.isDown();
|
||||
MutableComponent text = Lang.translateDirect("track.hold_for_smooth_curve", Components.keybind("key.sprint")
|
||||
.withStyle(active ? ChatFormatting.WHITE : ChatFormatting.GRAY));
|
||||
|
||||
Window window = mc.getWindow();
|
||||
int x = (window.getGuiScaledWidth() - gui.getFont()
|
||||
.width(text)) / 2;
|
||||
int y = window.getGuiScaledHeight() - 61;
|
||||
Color color = new Color(0x4ADB4A).setAlpha(Mth.clamp((extraTipWarmup - 4) / 3f, 0.1f, 1));
|
||||
gui.getFont()
|
||||
.draw(poseStack, text, x, y, color.getRGB());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,10 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides.ClipboardType;
|
||||
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
@ -27,6 +31,7 @@ import net.minecraft.world.item.Items;
|
||||
public class MaterialChecklist {
|
||||
|
||||
public static final int MAX_ENTRIES_PER_PAGE = 5;
|
||||
public static final int MAX_ENTRIES_PER_CLIPBOARD_PAGE = 7;
|
||||
|
||||
public Object2IntMap<Item> gathered = new Object2IntArrayMap<>();
|
||||
public Object2IntMap<Item> required = new Object2IntArrayMap<>();
|
||||
@ -70,7 +75,7 @@ public class MaterialChecklist {
|
||||
gathered.put(item, stack.getCount());
|
||||
}
|
||||
|
||||
public ItemStack createItem() {
|
||||
public ItemStack createWrittenBook() {
|
||||
ItemStack book = new ItemStack(Items.WRITTEN_BOOK);
|
||||
|
||||
CompoundTag tag = book.getOrCreateTag();
|
||||
@ -88,9 +93,11 @@ public class MaterialChecklist {
|
||||
List<Item> keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet()));
|
||||
Collections.sort(keys, (item1, item2) -> {
|
||||
Locale locale = Locale.ENGLISH;
|
||||
String name1 = item1.getDescription().getString()
|
||||
String name1 = item1.getDescription()
|
||||
.getString()
|
||||
.toLowerCase(locale);
|
||||
String name2 = item2.getDescription().getString()
|
||||
String name2 = item2.getDescription()
|
||||
.getString()
|
||||
.toLowerCase(locale);
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
@ -109,30 +116,33 @@ public class MaterialChecklist {
|
||||
|
||||
if (itemsWritten == MAX_ENTRIES_PER_PAGE) {
|
||||
itemsWritten = 0;
|
||||
textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.BLUE));
|
||||
textComponent.append(Components.literal("\n >>>")
|
||||
.withStyle(ChatFormatting.BLUE));
|
||||
pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent)));
|
||||
textComponent = Components.empty();
|
||||
}
|
||||
|
||||
itemsWritten++;
|
||||
textComponent.append(entry(new ItemStack(item), amount, true));
|
||||
textComponent.append(entry(new ItemStack(item), amount, true, true));
|
||||
}
|
||||
|
||||
for (Item item : completed) {
|
||||
if (itemsWritten == MAX_ENTRIES_PER_PAGE) {
|
||||
itemsWritten = 0;
|
||||
textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.DARK_GREEN));
|
||||
textComponent.append(Components.literal("\n >>>")
|
||||
.withStyle(ChatFormatting.DARK_GREEN));
|
||||
pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent)));
|
||||
textComponent = Components.empty();
|
||||
}
|
||||
|
||||
itemsWritten++;
|
||||
textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false));
|
||||
textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false, true));
|
||||
}
|
||||
|
||||
pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent)));
|
||||
|
||||
tag.put("pages", pages);
|
||||
tag.putBoolean("readonly", true);
|
||||
tag.putString("author", "Schematicannon");
|
||||
tag.putString("title", ChatFormatting.BLUE + "Material Checklist");
|
||||
textComponent = Lang.translateDirect("materialChecklist")
|
||||
@ -145,6 +155,80 @@ public class MaterialChecklist {
|
||||
return book;
|
||||
}
|
||||
|
||||
public ItemStack createWrittenClipboard() {
|
||||
ItemStack clipboard = AllItems.CLIPBOARD.asStack();
|
||||
CompoundTag tag = clipboard.getOrCreateTag();
|
||||
int itemsWritten = 0;
|
||||
|
||||
List<List<ClipboardEntry>> pages = new ArrayList<>();
|
||||
List<ClipboardEntry> currentPage = new ArrayList<>();
|
||||
|
||||
if (blocksNotLoaded) {
|
||||
currentPage.add(new ClipboardEntry(false, Lang.translateDirect("materialChecklist.blocksNotLoaded")
|
||||
.withStyle(ChatFormatting.RED)));
|
||||
}
|
||||
|
||||
List<Item> keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet()));
|
||||
Collections.sort(keys, (item1, item2) -> {
|
||||
Locale locale = Locale.ENGLISH;
|
||||
String name1 = item1.getDescription()
|
||||
.getString()
|
||||
.toLowerCase(locale);
|
||||
String name2 = item2.getDescription()
|
||||
.getString()
|
||||
.toLowerCase(locale);
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
List<Item> completed = new ArrayList<>();
|
||||
for (Item item : keys) {
|
||||
int amount = getRequiredAmount(item);
|
||||
if (gathered.containsKey(item))
|
||||
amount -= gathered.getInt(item);
|
||||
|
||||
if (amount <= 0) {
|
||||
completed.add(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itemsWritten == MAX_ENTRIES_PER_CLIPBOARD_PAGE) {
|
||||
itemsWritten = 0;
|
||||
currentPage.add(new ClipboardEntry(false, Components.literal(">>>")
|
||||
.withStyle(ChatFormatting.DARK_GRAY)));
|
||||
pages.add(currentPage);
|
||||
currentPage = new ArrayList<>();
|
||||
}
|
||||
|
||||
itemsWritten++;
|
||||
currentPage.add(new ClipboardEntry(false, entry(new ItemStack(item), amount, true, false))
|
||||
.displayItem(new ItemStack(item)));
|
||||
}
|
||||
|
||||
for (Item item : completed) {
|
||||
if (itemsWritten == MAX_ENTRIES_PER_PAGE) {
|
||||
itemsWritten = 0;
|
||||
currentPage.add(new ClipboardEntry(true, Components.literal(">>>")
|
||||
.withStyle(ChatFormatting.DARK_GREEN)));
|
||||
pages.add(currentPage);
|
||||
currentPage = new ArrayList<>();
|
||||
}
|
||||
|
||||
itemsWritten++;
|
||||
currentPage.add(new ClipboardEntry(true, entry(new ItemStack(item), getRequiredAmount(item), false, false))
|
||||
.displayItem(new ItemStack(item)));
|
||||
}
|
||||
|
||||
pages.add(currentPage);
|
||||
ClipboardEntry.saveAll(pages, clipboard);
|
||||
ClipboardOverrides.switchTo(ClipboardType.WRITTEN, clipboard);
|
||||
clipboard.getOrCreateTagElement("display")
|
||||
.putString("Name", Component.Serializer.toJson(Lang.translateDirect("materialChecklist")
|
||||
.setStyle(Style.EMPTY.withItalic(Boolean.FALSE))));
|
||||
tag.putBoolean("Readonly", true);
|
||||
clipboard.setTag(tag);
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
public int getRequiredAmount(Item item) {
|
||||
int amount = required.getOrDefault(item, 0);
|
||||
if (damageRequired.containsKey(item))
|
||||
@ -152,7 +236,7 @@ public class MaterialChecklist {
|
||||
return amount;
|
||||
}
|
||||
|
||||
private Component entry(ItemStack item, int amount, boolean unfinished) {
|
||||
private MutableComponent entry(ItemStack item, int amount, boolean unfinished, boolean forBook) {
|
||||
int stacks = amount / 64;
|
||||
int remainder = amount % 64;
|
||||
MutableComponent tc = Components.empty();
|
||||
@ -160,11 +244,14 @@ public class MaterialChecklist {
|
||||
.setStyle(Style.EMPTY
|
||||
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(item)))));
|
||||
|
||||
if (!unfinished)
|
||||
if (!unfinished && forBook)
|
||||
tc.append(" \u2714");
|
||||
tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN);
|
||||
return tc.append(Components.literal("\n" + " x" + amount).withStyle(ChatFormatting.BLACK))
|
||||
.append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + "\n").withStyle(ChatFormatting.GRAY));
|
||||
if (!unfinished || forBook)
|
||||
tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN);
|
||||
return tc.append(Components.literal("\n" + " x" + amount)
|
||||
.withStyle(ChatFormatting.BLACK))
|
||||
.append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + (forBook ? "\n" : ""))
|
||||
.withStyle(ChatFormatting.GRAY));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -700,8 +700,9 @@ public class SchematicannonBlockEntity extends SmartBlockEntity implements MenuP
|
||||
updateChecklist();
|
||||
|
||||
dontUpdateChecklist = true;
|
||||
inventory.extractItem(BookInput, 1, false);
|
||||
ItemStack stack = checklist.createItem();
|
||||
ItemStack extractItem = inventory.extractItem(BookInput, 1, false);
|
||||
ItemStack stack = AllItems.CLIPBOARD.isIn(extractItem) ? checklist.createWrittenClipboard()
|
||||
: checklist.createWrittenBook();
|
||||
stack.setCount(inventory.getStackInSlot(BookOutput)
|
||||
.getCount() + 1);
|
||||
inventory.setStackInSlot(BookOutput, stack);
|
||||
|
@ -28,7 +28,8 @@ public class SchematicannonInventory extends ItemStackHandler {
|
||||
case 1: // Blueprint output
|
||||
return false;
|
||||
case 2: // Book input
|
||||
return stack.sameItem(new ItemStack(Items.BOOK)) || stack.sameItem(new ItemStack(Items.WRITTEN_BOOK));
|
||||
return AllItems.CLIPBOARD.isIn(stack) || stack.sameItem(new ItemStack(Items.BOOK))
|
||||
|| stack.sameItem(new ItemStack(Items.WRITTEN_BOOK));
|
||||
case 3: // Material List output
|
||||
return false;
|
||||
case 4: // Gunpowder
|
||||
|
@ -565,16 +565,10 @@ public class AllAdvancements implements DataProvider {
|
||||
.after(STURDY_SHEET)
|
||||
.special(EXPERT)),
|
||||
|
||||
LONG_BEND = create("long_bend", b -> b.icon(AllBlocks.TRACK)
|
||||
.title("The Longest Bend")
|
||||
.description("Create a curved track section that spans more than 30 blocks in length")
|
||||
.after(TRACK_CRAFTING)
|
||||
.special(EXPERT)),
|
||||
|
||||
LONG_TRAIN = create("long_train", b -> b.icon(Items.MINECART)
|
||||
.title("Ambitious Endeavours")
|
||||
.description("Create a Train with at least 6 carriages")
|
||||
.after(LONG_BEND)
|
||||
.after(TRACK_CRAFTING)
|
||||
.special(EXPERT)),
|
||||
|
||||
LONG_TRAVEL = create("long_travel", b -> b.icon(AllBlocks.SEATS.get(DyeColor.GREEN))
|
||||
|
@ -278,7 +278,6 @@ public class BuilderTransformers {
|
||||
.texture("3", p.modLoc("block/valve_handle/valve_handle_" + variant)));
|
||||
})
|
||||
.tag(AllBlockTags.BRITTLE.tag, AllBlockTags.VALVE_HANDLES.tag)
|
||||
.transform(BlockStressDefaults.setCapacity(8.0))
|
||||
.transform(BlockStressDefaults.setGeneratorSpeed(ValveHandleBlock::getSpeedRange))
|
||||
.onRegister(ItemUseOverrides::addBlock)
|
||||
.item()
|
||||
|
@ -1011,6 +1011,18 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
||||
.viaShapeless(b -> b.requires(I.wheatFlour())
|
||||
.requires(Items.WATER_BUCKET)),
|
||||
|
||||
CLIPBOARD = create(AllItems.CLIPBOARD).unlockedBy(I::andesite)
|
||||
.viaShaped(b -> b.define('G', I.planks())
|
||||
.define('P', Items.PAPER)
|
||||
.define('A', I.andesite())
|
||||
.pattern("A")
|
||||
.pattern("P")
|
||||
.pattern("G")),
|
||||
|
||||
CLIPBOARD_CLEAR = create(AllItems.CLIPBOARD).withSuffix("_clear")
|
||||
.unlockedBy(AllItems.CLIPBOARD::get)
|
||||
.viaShapeless(b -> b.requires(AllItems.CLIPBOARD.get())),
|
||||
|
||||
DIVING_HELMET = create(AllItems.COPPER_DIVING_HELMET).unlockedBy(I::copper)
|
||||
.viaShaped(b -> b.define('G', Tags.Items.GLASS)
|
||||
.define('P', I.copper())
|
||||
|
@ -72,6 +72,8 @@ public enum AllGuiTextures implements ScreenElement {
|
||||
|
||||
LINKED_CONTROLLER("curiosities_2", 179, 109),
|
||||
BLUEPRINT("curiosities_2", 0, 109, 179, 109),
|
||||
|
||||
CLIPBOARD("clipboard", 0, 0, 256, 256),
|
||||
|
||||
DATA_GATHERER("display_link", 235, 162),
|
||||
DATA_AREA_START("display_link", 0, 163, 2, 18),
|
||||
|
@ -127,6 +127,8 @@ public class AllIcons implements ScreenElement {
|
||||
I_PATTERN_CHANCE_75 = next(),
|
||||
I_FOLLOW_DIAGONAL = next(),
|
||||
I_FOLLOW_MATERIAL = next(),
|
||||
|
||||
I_CLEAR_CHECKED = next(),
|
||||
|
||||
I_SCHEMATIC = newRow(),
|
||||
I_SEQ_REPEAT = next(),
|
||||
|
@ -8,8 +8,10 @@ import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate.StressImpact;
|
||||
import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock;
|
||||
import com.simibubi.create.content.contraptions.components.steam.SteamEngineBlock;
|
||||
import com.simibubi.create.content.contraptions.goggles.GogglesItem;
|
||||
import com.simibubi.create.foundation.block.BlockStressValues;
|
||||
@ -71,6 +73,9 @@ public class KineticStats implements TooltipModifier {
|
||||
showStressImpact = true;
|
||||
}
|
||||
|
||||
if (block instanceof ValveHandleBlock)
|
||||
block = AllBlocks.COPPER_VALVE_HANDLE.get();
|
||||
|
||||
boolean hasStressImpact =
|
||||
StressImpact.isEnabled() && showStressImpact && BlockStressValues.getImpact(block) > 0;
|
||||
boolean hasStressCapacity = StressImpact.isEnabled() && BlockStressValues.hasCapacity(block);
|
||||
|
@ -37,6 +37,7 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Config
|
||||
import com.simibubi.create.content.contraptions.relays.gauge.GaugeObservedPacket;
|
||||
import com.simibubi.create.content.curiosities.armor.NetheriteDivingHandler;
|
||||
import com.simibubi.create.content.curiosities.bell.SoulPulseEffectPacket;
|
||||
import com.simibubi.create.content.curiosities.clipboard.ClipboardEditPacket;
|
||||
import com.simibubi.create.content.curiosities.symmetry.ConfigureSymmetryWandPacket;
|
||||
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
|
||||
import com.simibubi.create.content.curiosities.toolbox.ToolboxDisposeAllPacket;
|
||||
@ -155,6 +156,7 @@ public enum AllPackets {
|
||||
PLAY_TO_SERVER),
|
||||
ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER),
|
||||
VALUE_SETTINGS(ValueSettingsPacket.class, ValueSettingsPacket::new, PLAY_TO_SERVER),
|
||||
CLIPBOARD_EDIT(ClipboardEditPacket.class, ClipboardEditPacket::new, PLAY_TO_SERVER),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
||||
|
@ -301,6 +301,8 @@
|
||||
"create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed",
|
||||
"create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed",
|
||||
|
||||
"create.gui.clipboard.erase_checked": "Erase checked items",
|
||||
|
||||
"create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s",
|
||||
"create.schematicAndQuill.firstPos": "First position set.",
|
||||
"create.schematicAndQuill.secondPos": "Second position set.",
|
||||
@ -384,7 +386,7 @@
|
||||
"create.gui.schematicannon.option.skipBlockEntities": "Protect Block Entities",
|
||||
|
||||
"create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon",
|
||||
"create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic",
|
||||
"create.gui.schematicannon.slot.listPrinter": "Place a Clipboard or Book here to print a Checklist for your Schematic",
|
||||
"create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.",
|
||||
|
||||
"create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.",
|
||||
@ -763,6 +765,7 @@
|
||||
"create.track.turn_start": "Cannot start connection from a Turn",
|
||||
"create.track.not_enough_tracks": "Not holding enough tracks",
|
||||
"create.track.not_enough_pavement": "Not holding enough pavement blocks",
|
||||
"create.track.hold_for_smooth_curve": "Hold %1$s for maximized turn",
|
||||
|
||||
"create.portal_track.failed": "Cannot place portal track:",
|
||||
"create.portal_track.missing": "Target portal not generated yet",
|
||||
|
BIN
src/main/resources/assets/create/textures/gui/clipboard.pdn
Normal file
BIN
src/main/resources/assets/create/textures/gui/clipboard.pdn
Normal file
Binary file not shown.
BIN
src/main/resources/assets/create/textures/gui/clipboard.png
Normal file
BIN
src/main/resources/assets/create/textures/gui/clipboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
BIN
src/main/resources/assets/create/textures/item/clipboard.png
Normal file
BIN
src/main/resources/assets/create/textures/item/clipboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 290 B |
Binary file not shown.
After Width: | Height: | Size: 332 B |
Binary file not shown.
After Width: | Height: | Size: 281 B |
Loading…
Reference in New Issue
Block a user