From fdb6afebddef2469c639376aaa65d9b472909d2d Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 28 Feb 2024 07:40:55 +0100 Subject: [PATCH] Convert Redstone Input/Output, add Spray Can, fix models --- build.gradle | 2 +- changelog-next.txt | 10 +- .../block/data/AbstractCableBlock.java | 15 +- .../polyfactory/block/data/CableBlock.java | 3 +- .../data/output/HologramProjectorBlock.java | 5 +- .../data/output/RedstoneOutputBlock.java | 66 ++---- .../block/data/providers/ItemReaderBlock.java | 15 +- .../data/providers/RedstoneInputBlock.java | 4 +- .../data/providers/RotationMeterBlock.java | 5 +- .../data/providers/TinyPotatoSpringBlock.java | 6 +- .../data/util/GenericCabledDataBlock.java | 32 ++- .../util/GenericDirectionalDataBlock.java | 6 +- .../electric/ElectricGeneratorBlock.java | 5 +- .../block/electric/ElectricMotorBlock.java | 5 +- .../block/mechanical/ClutchBlock.java | 3 +- .../block/mechanical/FanBlock.java | 7 +- .../block/mechanical/GearboxBlock.java | 3 +- .../block/mechanical/machines/MinerBlock.java | 3 +- .../mechanical/machines/PlacerBlock.java | 3 +- .../mechanical/machines/PlanterBlock.java | 3 +- .../machines/crafting/GrinderBlock.java | 3 +- .../machines/crafting/MCrafterBlock.java | 6 +- .../machines/crafting/MixerBlock.java | 3 +- .../machines/crafting/PressBlock.java | 3 +- .../mechanical/source/SteamEngineBlock.java | 3 +- .../block/other/ContainerBlock.java | 5 +- .../polyfactory/block/other/LampBlock.java | 14 +- .../other/SelectivePassthroughBlock.java | 3 +- .../block/other/SmallLampBlock.java | 13 +- .../block/other/WirelessRedstoneBlock.java | 9 +- .../block/other/WorkbenchBlock.java | 6 +- .../pb4/polyfactory/datagen/LootTables.java | 40 ++-- .../polyfactory/datagen/RecipesProvider.java | 4 +- .../eu/pb4/polyfactory/item/FactoryItems.java | 9 + .../polyfactory/item/tool/DyeSprayItem.java | 218 ++++++++++++++++++ .../pb4/polyfactory/models/HopperModel.java | 10 +- .../assets/polyfactory/lang/en_us.json | 4 + .../polyfactory/models/block/cable_base.json | 27 ++- .../models/block/redstone_input.json | 10 +- .../models/block/redstone_output.json | 9 +- .../polyfactory/models/item/spray_can.json | 7 + .../models/item/spray_can_empty.json | 6 + .../block/cable/redstone_input_side.png | Bin 0 -> 4682 bytes .../block/cable/redstone_output_side.png | Bin 0 -> 4688 bytes .../polyfactory/textures/block/cable_base.png | Bin 4288 -> 4540 bytes .../textures/block/cable_center.png | Bin 4343 -> 4672 bytes .../polyfactory/textures/block/cable_top.png | Bin 512 -> 0 bytes .../textures/block/redstone_input_side.png | Bin 4476 -> 4838 bytes .../textures/block/redstone_output_side.png | Bin 730 -> 4848 bytes .../block/redstone_output_side_overlay.png | Bin 498 -> 4272 bytes .../polyfactory/textures/item/spray_can.png | Bin 0 -> 4628 bytes .../textures/item/spray_can_color.png | Bin 0 -> 4248 bytes .../textures/item/spray_can_empty.png | Bin 0 -> 4651 bytes 53 files changed, 454 insertions(+), 159 deletions(-) create mode 100644 src/main/java/eu/pb4/polyfactory/item/tool/DyeSprayItem.java create mode 100644 src/main/resources/assets/polyfactory/models/item/spray_can.json create mode 100644 src/main/resources/assets/polyfactory/models/item/spray_can_empty.json create mode 100644 src/main/resources/assets/polyfactory/textures/block/cable/redstone_input_side.png create mode 100644 src/main/resources/assets/polyfactory/textures/block/cable/redstone_output_side.png delete mode 100644 src/main/resources/assets/polyfactory/textures/block/cable_top.png create mode 100644 src/main/resources/assets/polyfactory/textures/item/spray_can.png create mode 100644 src/main/resources/assets/polyfactory/textures/item/spray_can_color.png create mode 100644 src/main/resources/assets/polyfactory/textures/item/spray_can_empty.png diff --git a/build.gradle b/build.gradle index 78eb97ba..63c11d7a 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { modImplementation include('eu.pb4:sidebar-api:0.3.0+1.20.3') modImplementation include('eu.pb4:sgui:1.4.1+1.20.4') modImplementation include('com.kneelawk:graphlib:1.4.0+1.20.4') - modImplementation include('eu.pb4:factorytools:0.1.4+1.20.4') + modImplementation include('eu.pb4:factorytools:0.1.5+1.20.4') // Temp hack to allow development //modImplementation include('com.kneelawk:graphlib:1.99.99+1.20.local') diff --git a/changelog-next.txt b/changelog-next.txt index 8f490a1d..6dce60e2 100644 --- a/changelog-next.txt +++ b/changelog-next.txt @@ -1,20 +1,24 @@ - Added Tachometer (measures rotations per minute) and Stressometer (measures stress units left). Both require connection to some display (Hologram Projector, Nixie Tube) to display their values. -- Reworked general "data provider/receiver blocks" (Item Counter, Nixie Tube Controller, Block Observer, Item Reader): +- Added Spray Can. It can be used to recolor Cables, Nixie Tubes, Lamps and most vanilla colored blocks. + You can create it in Mechanical Press with Empty Bucket and Copper Ingot. You can fill it with dye by putting it in the inventory (like bundles), with 8 charges per dye. +- Reworked general "data provider/receiver blocks" (Item Counter, Nixie Tube Controller, Block Observer, Item Reader, Redstone Input/Output): - Instead of having single directional input/output, you need to place cable inside of it. - The cable connects the same way as regular one, excluding the direction data-block is facing. + - Existing blocks will convert to the new ones, without any changes in connection until you change them yourself. - Improved Hologram Projectors: - Added option to force everything to display as text. - Added option to change pitch and yaw aside of just roll of hologram. - Fixed some bugs with displaying holograms. - Mechanical Placers can now use selected items on blocks. -- Improved placement of Windmills to always point to connected side. - Improved physics of players effected by fans. +- Improved placement of Windmills to always point to connected side. - Added new advancements! - Hoppers, Pistons, Redstone Repeater, Redstone Comparator, Dispensers and Droppers can be rotated by using Wrench. - Added breaking particles to all the blocks that didn't have them. - All crafting-machines should now work with hoppers. +- Fixed dynamic blocks not having correct visuals sometimes. - Changed multiple textures and models: - - Most notably: Item Splitter, Cables and Ender-Amethyst Crystal, + - Most notably: Item Splitter, Cables, Wireless Redstone Input/Output, Treated Kelp and Ender-Amethyst Crystal diff --git a/src/main/java/eu/pb4/polyfactory/block/data/AbstractCableBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/AbstractCableBlock.java index 627ef79a..e7b7b87a 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/AbstractCableBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/AbstractCableBlock.java @@ -4,6 +4,7 @@ import com.google.common.collect.Maps; import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.advancement.FactoryTriggers; import eu.pb4.factorytools.api.advancement.TriggerCriterion; import eu.pb4.factorytools.api.block.FactoryBlock; @@ -50,6 +51,7 @@ public abstract class AbstractCableBlock extends NetworkBlock implements FactoryBlock, BlockEntityProvider, CableConnectable, NetworkComponent.Data, NetworkComponent.Energy { public static final int DEFAULT_COLOR = 0xbbbbbb; + public static final BooleanProperty HAS_CABLE = BooleanProperty.of("has_cable"); public static final BooleanProperty NORTH = Properties.NORTH; public static final BooleanProperty EAST = Properties.EAST; @@ -109,7 +111,7 @@ public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) { return stack; } - protected boolean setColor(BlockState state, World world, BlockPos pos, int color) { + public boolean setColor(BlockState state, World world, BlockPos pos, int color) { color = FactoryItems.CABLE.downSampleColor(color); if (world.getBlockEntity(pos) instanceof ColorProvider provider && provider.getColor() != color) { provider.setColor(color); @@ -246,13 +248,17 @@ public boolean canCableConnect(WorldAccess world, int cableColor, BlockPos pos, return true; } + public boolean hasCable(BlockState state) { + return true; + } + public static class BaseCableModel extends BlockModel { private final ItemDisplayElement cable; private int color = AbstractCableBlock.DEFAULT_COLOR; private BlockState state; public BaseCableModel(BlockState state, boolean addCable) { - this.cable = LodItemDisplayElement.createSimple(); + this.cable = ItemDisplayElementUtil.createSimple(); this.cable.setViewRange(0.5f); this.state = state; updateModel(); @@ -278,8 +284,9 @@ protected void setState(BlockState blockState) { updateModel(); } - protected boolean hasCable(BlockState state) { - return true; + + protected final boolean hasCable(BlockState state) { + return ((AbstractCableBlock) state.getBlock()).hasCable(state); } protected void updateModel() { diff --git a/src/main/java/eu/pb4/polyfactory/block/data/CableBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/CableBlock.java index b59d956c..c8480d78 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/CableBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/CableBlock.java @@ -1,5 +1,6 @@ package eu.pb4.polyfactory.block.data; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.block.FactoryBlocks; import eu.pb4.polyfactory.block.data.util.GenericCabledDataBlock; @@ -97,7 +98,7 @@ public static final class Model extends BaseCableModel { private Model(BlockState state) { super(state, true); - this.frame = LodItemDisplayElement.createSimple(FactoryItems.FRAME); + this.frame = ItemDisplayElementUtil.createSimple(FactoryItems.FRAME); this.frame.setScale(new Vector3f(2)); this.frame.setViewRange(0.8f); if (state.get(FRAMED)) { diff --git a/src/main/java/eu/pb4/polyfactory/block/data/output/HologramProjectorBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/output/HologramProjectorBlock.java index 701b431f..b7e7f852 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/output/HologramProjectorBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/output/HologramProjectorBlock.java @@ -6,6 +6,7 @@ import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.factorytools.api.resourcepack.BaseItemProvider; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.mapcanvas.api.font.DefaultFonts; import eu.pb4.polyfactory.advancement.FactoryTriggers; @@ -234,7 +235,7 @@ public static class Model extends BlockModel { 0.2f); private static final Random RANDOM = Random.create(); - private final LodItemDisplayElement base; + private final ItemDisplayElement base; private DisplayElement currentDisplay; private DisplayElement currentDisplayExtra; private Direction facing; @@ -252,7 +253,7 @@ public static class Model extends BlockModel { private float extraOffset; public Model(BlockState state) { - this.base = LodItemDisplayElement.createSimple(state.get(ACTIVE) ? ACTIVE_MODEL : LodItemDisplayElement.getModel(state.getBlock().asItem())); + this.base = ItemDisplayElementUtil.createSimple(state.get(ACTIVE) ? ACTIVE_MODEL : LodItemDisplayElement.getModel(state.getBlock().asItem())); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/data/output/RedstoneOutputBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/output/RedstoneOutputBlock.java index b71794c9..3268fe66 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/output/RedstoneOutputBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/output/RedstoneOutputBlock.java @@ -2,21 +2,24 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.advancement.TriggerCriterion; +import eu.pb4.factorytools.api.block.RedstoneConnectable; +import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.advancement.FactoryTriggers; import eu.pb4.polyfactory.block.FactoryBlocks; import eu.pb4.polyfactory.block.data.DataReceiver; +import eu.pb4.polyfactory.block.data.util.GenericCabledDataBlock; import eu.pb4.polyfactory.block.data.util.GenericDirectionalDataBlock; -import eu.pb4.factorytools.api.block.RedstoneConnectable; import eu.pb4.polyfactory.data.DataContainer; -import eu.pb4.factorytools.api.virtualentity.BlockModel; -import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.nodes.data.ChannelReceiverDirectionNode; +import eu.pb4.polyfactory.nodes.data.ChannelReceiverSelectiveSideNode; import eu.pb4.polyfactory.util.FactoryUtil; import eu.pb4.polymer.resourcepack.api.PolymerModelData; import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -42,7 +45,7 @@ import static eu.pb4.polyfactory.util.FactoryUtil.id; -public class RedstoneOutputBlock extends GenericDirectionalDataBlock implements DataReceiver, RedstoneConnectable { +public class RedstoneOutputBlock extends GenericCabledDataBlock implements DataReceiver, RedstoneConnectable { public static final IntProperty POWER = Properties.POWER; public RedstoneOutputBlock(Settings settings) { @@ -50,11 +53,6 @@ public RedstoneOutputBlock(Settings settings) { this.setDefaultState(this.getDefaultState().with(POWER, 0)); } - @Override - public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { - return this.getDefaultState().with(FACING, ctx.getPlayerLookDirection()); - } - @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder); @@ -73,7 +71,7 @@ public int getWeakRedstonePower(BlockState state, BlockView world, BlockPos pos, @Override public Collection createDataNodes(BlockState state, ServerWorld world, BlockPos pos) { - return List.of(new ChannelReceiverDirectionNode(state.get(FACING).getOpposite(), getChannel(world, pos))); + return List.of(new ChannelReceiverSelectiveSideNode(getDirections(state), getChannel(world, pos))); } @Override @@ -104,22 +102,18 @@ public boolean canRedstoneConnect(BlockState state, @Nullable Direction dir) { return state.get(FACING).getOpposite() == dir; } - public static class Model extends BlockModel { + public static class Model extends GenericCabledDataBlock.Model { public static final PolymerModelData OUTPUT_OVERLAY = PolymerResourcePackUtils.requestModel(Items.LEATHER_HELMET, id("block/redstone_output_overlay")); public static final PolymerModelData INPUT_OVERLAY = PolymerResourcePackUtils.requestModel(Items.LEATHER_HELMET, id("block/redstone_input_overlay")); - private final LodItemDisplayElement base; - private final LodItemDisplayElement overlay; + private final ItemDisplayElement overlay; public Model(BlockState state) { - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); - this.overlay = LodItemDisplayElement.createSimple(createOverlay(state)); - //this.overlay.setBrightness(new Brightness(state.get(POWER), 0)); - this.base.setScale(new Vector3f(2)); - this.overlay.setScale(new Vector3f(2)); + super(state); + this.overlay = ItemDisplayElementUtil.createSimple(createOverlay(state)); + this.overlay.setScale(new Vector3f(2.005f)); this.overlay.setViewRange(0.6f); updateStatePos(state); - this.addElement(this.base); this.addElement(this.overlay); } @@ -133,34 +127,20 @@ private ItemStack createOverlay(BlockState state) { return stack; } - private void updateStatePos(BlockState state) { - var dir = state.get(FACING); - float p = -90; - float y = 0; - - if (dir.getAxis() != Direction.Axis.Y) { - p = 0; - y = dir.asRotation(); - } else if (dir == Direction.DOWN) { - p = 90; + @Override + protected void updateStatePos(BlockState state) { + super.updateStatePos(state); + if (this.overlay != null) { + this.overlay.setYaw(this.base.getYaw()); + this.overlay.setPitch(this.base.getPitch()); } - - - this.base.setYaw(y); - this.base.setPitch(p); - this.overlay.setYaw(y); - this.overlay.setPitch(p); } @Override - public void notifyUpdate(HolderAttachment.UpdateType updateType) { - if (updateType == BlockBoundAttachment.BLOCK_STATE_UPDATE) { - var state = this.blockState(); - updateStatePos(state); - this.overlay.setItem(createOverlay(state)); - this.base.tick(); - this.overlay.tick(); - } + protected void setState(BlockState blockState) { + super.setState(blockState); + this.overlay.setItem(createOverlay(blockState)); + this.overlay.tick(); } } } diff --git a/src/main/java/eu/pb4/polyfactory/block/data/providers/ItemReaderBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/providers/ItemReaderBlock.java index 232c3133..87c58882 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/providers/ItemReaderBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/providers/ItemReaderBlock.java @@ -1,10 +1,12 @@ package eu.pb4.polyfactory.block.data.providers; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -101,15 +103,15 @@ public BlockState getPolymerBreakEventBlockState(BlockState state, ServerPlayerE } public static class Model extends BaseCableModel { - private final LodItemDisplayElement base; - private final LodItemDisplayElement book; + private final ItemDisplayElement base; + private final ItemDisplayElement book; private Model(BlockState state) { super(state, state.get(HAS_CABLE)); - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); - this.book = LodItemDisplayElement.createSimple(); + this.book = ItemDisplayElementUtil.createSimple(); this.book.setScale(new Vector3f(0.5f)); this.book.setDisplaySize(1, 1); this.book.setTranslation(new Vector3f(0, 0, 0.35f)); @@ -119,11 +121,6 @@ private Model(BlockState state) { this.addElement(this.book); } - @Override - protected boolean hasCable(BlockState state) { - return state.get(HAS_CABLE); - } - private void updateStatePos(BlockState state) { var dir = state.get(FACING); float p = -90; diff --git a/src/main/java/eu/pb4/polyfactory/block/data/providers/RedstoneInputBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/providers/RedstoneInputBlock.java index 411cc54f..d4ebf969 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/providers/RedstoneInputBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/providers/RedstoneInputBlock.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldAccess; import org.jetbrains.annotations.Nullable; -public class RedstoneInputBlock extends DataProviderBlock implements RedstoneConnectable { +public class RedstoneInputBlock extends CabledDataProviderBlock implements RedstoneConnectable { public static final IntProperty POWER = RedstoneOutputBlock.POWER; public RedstoneInputBlock(AbstractBlock.Settings settings) { @@ -42,7 +42,7 @@ protected void appendProperties(StateManager.Builder builder) @Nullable public BlockState getPlacementState(ItemPlacementContext ctx) { - return this.getDefaultState().with(FACING, ctx.getPlayerLookDirection()).with(POWER, clamp(ctx.getWorld().getReceivedRedstonePower(ctx.getBlockPos()))); + return super.getPlacementState(ctx).with(POWER, clamp(ctx.getWorld().getReceivedRedstonePower(ctx.getBlockPos()))); } @Override diff --git a/src/main/java/eu/pb4/polyfactory/block/data/providers/RotationMeterBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/providers/RotationMeterBlock.java index 59f808d4..2e25d8b3 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/providers/RotationMeterBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/providers/RotationMeterBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.block.data.CableConnectable; import eu.pb4.polyfactory.block.data.ChannelContainer; @@ -201,11 +202,11 @@ public String asString() { public static final class Model extends RotationAwareModel { private final ItemDisplayElement axle; - private final LodItemDisplayElement base; + private final ItemDisplayElement base; public Model(BlockState state) { this.axle = LodItemDisplayElement.createSimple(AxleBlock.Model.ITEM_MODEL, this.getUpdateRate(), 0.3f, 0.6f); - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/data/providers/TinyPotatoSpringBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/providers/TinyPotatoSpringBlock.java index 5beeea93..ef82316b 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/providers/TinyPotatoSpringBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/providers/TinyPotatoSpringBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.advancement.FactoryTriggers; import eu.pb4.factorytools.api.advancement.TriggerCriterion; import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; @@ -21,6 +22,7 @@ import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -169,7 +171,7 @@ public Collection createDataNodes(BlockState state, ServerWorld world public static final class Model extends BlockModel { public static final ItemStack BASE_MODEL = BaseItemProvider.requestModel(id("block/tiny_potato_spring_base")); public static final ItemStack TATER_MODEL = BaseItemProvider.requestModel(id("block/tiny_potato_spring")); - private final LodItemDisplayElement base; + private final ItemDisplayElement base; private final LodItemDisplayElement tater; private float extraRotation = 0; @@ -177,7 +179,7 @@ public static final class Model extends BlockModel { private float interactionYaw; private Model(ServerWorld world, BlockPos pos, BlockState state) { - this.base = LodItemDisplayElement.createSimple(BASE_MODEL); + this.base = ItemDisplayElementUtil.createSimple(BASE_MODEL); this.tater = LodItemDisplayElement.createSimple(TATER_MODEL, 1); this.tater.setTranslation(new Vector3f(0, -6f / 16, 0)); //this.tater.setOffset(new Vec3d(0, 2f / 16, 0)); diff --git a/src/main/java/eu/pb4/polyfactory/block/data/util/GenericCabledDataBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/util/GenericCabledDataBlock.java index 455225d3..6116431a 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/util/GenericCabledDataBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/util/GenericCabledDataBlock.java @@ -2,6 +2,7 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.*; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.block.FactoryBlocks; import eu.pb4.polyfactory.block.data.AbstractCableBlock; @@ -14,6 +15,7 @@ import eu.pb4.polyfactory.item.wrench.WrenchableBlock; import eu.pb4.polyfactory.util.FactoryUtil; import eu.pb4.polymer.virtualentity.api.ElementHolder; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -44,7 +46,6 @@ public abstract class GenericCabledDataBlock extends AbstractCableBlock implements WrenchableBlock, BlockEntityProvider, CableConnectable { public static final DirectionProperty FACING = Properties.FACING; - public static final BooleanProperty HAS_CABLE = BooleanProperty.of("has_cable"); public final WrenchAction facingAction = WrenchAction.of("facing", WrenchValueGetter.ofProperty(Properties.FACING), WrenchApplyAction.ofState( @@ -111,7 +112,14 @@ public boolean canReplace(BlockState state, ItemPlacementContext context) { @Override public BlockState getPlacementState(ItemPlacementContext ctx) { var state = ctx.getWorld().getBlockState(ctx.getBlockPos()); - return super.getPlacementState(ctx).with(FACING, ctx.getPlayerLookDirection()) + + var delta = ctx.getHitPos().subtract(ctx.getBlockPos().getX() + 0.5, ctx.getBlockPos().getY() + 0.5, ctx.getBlockPos().getZ() + 0.5); + + return super.getPlacementState(ctx).with(FACING, state.isOf(FactoryBlocks.CABLE) + && delta.getX() < 4 / 16f && delta.getX() > -4 / 16f + && delta.getY() < 4 / 16f && delta.getY() > -4 / 16f + && delta.getZ() < 4 / 16f && delta.getZ() > -4 / 16f + ? ctx.getSide() : ctx.getPlayerLookDirection()) .with(HAS_CABLE, state.isOf(FactoryBlocks.CABLE)) .with(FACING_PROPERTIES.get(ctx.getPlayerLookDirection()), false); } @@ -126,6 +134,11 @@ public boolean canCableConnect(WorldAccess world, int cableColor, BlockPos pos, return state.get(FACING) != dir && state.get(HAS_CABLE) && super.canCableConnect(world, cableColor, pos, state, dir); } + @Override + public boolean hasCable(BlockState state) { + return state.get(HAS_CABLE); + } + @Override public Block getPolymerBlock(BlockState state) { return Blocks.BARRIER; @@ -150,7 +163,7 @@ public List getWrenchActions() { } @Override - protected boolean setColor(BlockState state, World world, BlockPos pos, int color) { + public boolean setColor(BlockState state, World world, BlockPos pos, int color) { return state.get(HAS_CABLE) && super.setColor(state, world, pos, color); } @@ -173,23 +186,18 @@ public BlockState rotate(BlockState state, BlockRotation rotation) { } public static class Model extends BaseCableModel { - private final LodItemDisplayElement base; + protected final ItemDisplayElement base; - private Model(BlockState state) { + protected Model(BlockState state) { super(state, state.get(HAS_CABLE)); - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); this.addElement(this.base); } - @Override - protected boolean hasCable(BlockState state) { - return state.get(HAS_CABLE); - } - - private void updateStatePos(BlockState state) { + protected void updateStatePos(BlockState state) { var dir = state.get(FACING); float p = -90; float y = 0; diff --git a/src/main/java/eu/pb4/polyfactory/block/data/util/GenericDirectionalDataBlock.java b/src/main/java/eu/pb4/polyfactory/block/data/util/GenericDirectionalDataBlock.java index ae7303ea..10e9b36f 100644 --- a/src/main/java/eu/pb4/polyfactory/block/data/util/GenericDirectionalDataBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/data/util/GenericDirectionalDataBlock.java @@ -1,6 +1,7 @@ package eu.pb4.polyfactory.block.data.util; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.data.CableConnectable; import eu.pb4.polyfactory.block.data.ChannelContainer; import eu.pb4.polyfactory.item.wrench.WrenchAction; @@ -11,6 +12,7 @@ import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -90,10 +92,10 @@ public BlockState rotate(BlockState state, BlockRotation rotation) { } public static class Model extends BlockModel { - private final LodItemDisplayElement base; + private final ItemDisplayElement base; private Model(BlockState state) { - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/electric/ElectricGeneratorBlock.java b/src/main/java/eu/pb4/polyfactory/block/electric/ElectricGeneratorBlock.java index 782b5f25..b5a734c1 100644 --- a/src/main/java/eu/pb4/polyfactory/block/electric/ElectricGeneratorBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/electric/ElectricGeneratorBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.data.CableConnectable; import eu.pb4.polyfactory.block.mechanical.AxleBlock; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -116,11 +117,11 @@ public boolean canCableConnect(WorldAccess world, int cableColor, BlockPos pos, public static final class Model extends RotationAwareModel { private final ItemDisplayElement axle; - private final LodItemDisplayElement base; + private final ItemDisplayElement base; public Model(BlockState state) { this.axle = LodItemDisplayElement.createSimple(AxleBlock.Model.ITEM_MODEL, this.getUpdateRate(), 0.3f, 0.6f); - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/electric/ElectricMotorBlock.java b/src/main/java/eu/pb4/polyfactory/block/electric/ElectricMotorBlock.java index 28d729e6..a0ddbe1c 100644 --- a/src/main/java/eu/pb4/polyfactory/block/electric/ElectricMotorBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/electric/ElectricMotorBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.data.CableConnectable; import eu.pb4.polyfactory.block.mechanical.AxleBlock; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -144,11 +145,11 @@ public List getWrenchActions() { public static final class Model extends RotationAwareModel { private final ItemDisplayElement axle; - private final LodItemDisplayElement base; + private final ItemDisplayElement base; public Model(BlockState state) { this.axle = LodItemDisplayElement.createSimple(AxleBlock.Model.ITEM_MODEL_SHORT, this.getUpdateRate(), 0.3f, 0.6f); - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/ClutchBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/ClutchBlock.java index d47b1646..f62968c3 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/ClutchBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/ClutchBlock.java @@ -5,6 +5,7 @@ import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.factorytools.api.util.VirtualDestroyStage; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.item.wrench.WrenchAction; import eu.pb4.polyfactory.item.wrench.WrenchableBlock; @@ -150,7 +151,7 @@ public static final class Model extends RotationAwareModel { private final ItemDisplayElement left; private final ItemDisplayElement right; private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.main = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.main.setScale(new Vector3f(2)); this.left = LodItemDisplayElement.createSimple(AxleBlock.Model.ITEM_MODEL_SHORT, this.getUpdateRate(), 0.3f, 0.6f); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/FanBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/FanBlock.java index e4cb0b25..827e602d 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/FanBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/FanBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.item.wrench.WrenchAction; import eu.pb4.polyfactory.item.wrench.WrenchableBlock; @@ -160,12 +161,8 @@ public static final class Model extends RotationAwareModel { private boolean reverse; private Model(BlockState state) { - this.mainElement = new LodItemDisplayElement(FactoryItems.FAN.getDefaultStack()); - this.mainElement.setDisplaySize(1, 1); - this.mainElement.setModelTransformation(ModelTransformationMode.FIXED); + this.mainElement = ItemDisplayElementUtil.createSimple(FactoryItems.FAN); this.mainElement.setScale(new Vector3f(2f)); - this.mainElement.setViewRange(0.8f); - this.mainElement.setInvisible(true); this.fan = LodItemDisplayElement.createSimple(ITEM_MODEL, 2, 0.2f, 0.4f); this.fan.setViewRange(0.3f); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/GearboxBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/GearboxBlock.java index 7c3918d0..d2a92708 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/GearboxBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/GearboxBlock.java @@ -3,6 +3,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.item.FactoryItems; import eu.pb4.polyfactory.models.RotationAwareModel; @@ -90,7 +91,7 @@ public final class Model extends RotationAwareModel { private final ItemDisplayElement zAxle; private Model() { - this.mainElement = LodItemDisplayElement.createSimple(FactoryItems.GEARBOX); + this.mainElement = ItemDisplayElementUtil.createSimple(FactoryItems.GEARBOX); this.mainElement.setScale(new Vector3f(2)); this.addElement(this.mainElement); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/MinerBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/MinerBlock.java index 4c7f9e9b..cb73f4fc 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/MinerBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/MinerBlock.java @@ -3,6 +3,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.block.mechanical.RotationUser; import eu.pb4.polyfactory.block.mechanical.RotationalNetworkBlock; @@ -186,7 +187,7 @@ public final class Model extends RotationAwareModel { private float rotation = 0; private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.MINER); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.MINER); this.item = LodItemDisplayElement.createSimple(ItemStack.EMPTY, 1, 0.5f); this.updateAnimation(state.get(FACING)); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlacerBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlacerBlock.java index 433d6b25..074433d6 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlacerBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlacerBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -188,7 +189,7 @@ public final class Model extends RotationAwareModel { private float rotation = 0; private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.PLACER); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.PLACER); this.item = LodItemDisplayElement.createSimple(ItemStack.EMPTY, 3, 0.5f); this.updateAnimation(state.get(FACING)); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlanterBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlanterBlock.java index 909e1c97..6d283c85 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlanterBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/PlanterBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -171,7 +172,7 @@ public final class Model extends RotationAwareModel { EightWayDirection direction = null; private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.PLANTER); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.PLANTER); this.output1 = LodItemDisplayElement.createSimple(OUTPUT_1, 5, 0.3f); this.output2 = LodItemDisplayElement.createSimple(OUTPUT_2, 5, 0.3f); this.output1.setViewRange(0.5f); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/GrinderBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/GrinderBlock.java index db0cc555..e80311a8 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/GrinderBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/GrinderBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.AbovePlacingLimiter; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.block.FactoryBlockTags; import eu.pb4.factorytools.api.block.FactoryBlock; @@ -183,7 +184,7 @@ public static final class Model extends RotationAwareModel { private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.GRINDER); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.GRINDER); this.stoneWheel = LodItemDisplayElement.createSimple(MODEL_STONE_WHEEL, this.getUpdateRate(), 0.6f, 0.6f); this.updateAnimation(0, state.get(INPUT_FACING)); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MCrafterBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MCrafterBlock.java index 3ad1aca2..d3fcc882 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MCrafterBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MCrafterBlock.java @@ -1,6 +1,7 @@ package eu.pb4.polyfactory.block.mechanical.machines.crafting; import com.kneelawk.graphlib.api.graph.user.BlockNode; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -12,6 +13,7 @@ import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -145,10 +147,10 @@ public void updateRotationalData(RotationData.State modifier, BlockState state, } public static class Model extends BlockModel { - private final LodItemDisplayElement base; + private final ItemDisplayElement base; private Model(BlockState state) { - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); updateStatePos(state); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MixerBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MixerBlock.java index b062573e..4f83e403 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MixerBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/MixerBlock.java @@ -1,5 +1,6 @@ package eu.pb4.polyfactory.block.mechanical.machines.crafting; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.block.mechanical.RotationUser; import eu.pb4.polyfactory.block.mechanical.machines.TallItemMachineBlock; @@ -142,7 +143,7 @@ public static final class Model extends RotationAwareModel { private boolean active; private Model(BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.MIXER); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.MIXER); this.main.setScale(new Vector3f(2)); this.main.setTranslation(new Vector3f(0, 0.5f, 0)); this.whisk = LodItemDisplayElement.createSimple(MODEL_PISTON, 2, 0.4f, 0.8f); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/PressBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/PressBlock.java index 0879f6fc..50141889 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/PressBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/machines/crafting/PressBlock.java @@ -1,6 +1,7 @@ package eu.pb4.polyfactory.block.mechanical.machines.crafting; import eu.pb4.factorytools.api.resourcepack.BaseItemProvider; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -157,7 +158,7 @@ public static final class Model extends RotationAwareModel { private float value; private Model(ServerWorld world, BlockState state) { - this.main = LodItemDisplayElement.createSimple(FactoryItems.PRESS); + this.main = ItemDisplayElementUtil.createSimple(FactoryItems.PRESS); this.main.setScale(new Vector3f(2)); this.main.setTranslation(new Vector3f(0, 0.5f, 0)); this.piston = LodItemDisplayElement.createSimple(MODEL_PISTON, 2, 0.4f, 0.8f); diff --git a/src/main/java/eu/pb4/polyfactory/block/mechanical/source/SteamEngineBlock.java b/src/main/java/eu/pb4/polyfactory/block/mechanical/source/SteamEngineBlock.java index 7d847745..b97d8004 100644 --- a/src/main/java/eu/pb4/polyfactory/block/mechanical/source/SteamEngineBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/mechanical/source/SteamEngineBlock.java @@ -2,6 +2,7 @@ import com.kneelawk.graphlib.api.graph.user.BlockNode; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.block.mechanical.RotationUser; import eu.pb4.factorytools.api.block.MultiBlock; import eu.pb4.polyfactory.block.network.NetworkComponent; @@ -188,7 +189,7 @@ public final class Model extends RotationAwareModel { private final LodItemDisplayElement axle; private Model(BlockState state) { - this.main = LodItemDisplayElement.createSimple(state.get(SteamEngineBlock.LIT) ? LIT : FactoryItems.STEAM_ENGINE.getDefaultStack(), 0); + this.main = ItemDisplayElementUtil.createSimple(state.get(SteamEngineBlock.LIT) ? LIT : FactoryItems.STEAM_ENGINE.getDefaultStack()); this.main.setScale(new Vector3f(2)); var facing = state.get(FACING); var offset = new Vec3d( diff --git a/src/main/java/eu/pb4/polyfactory/block/other/ContainerBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/ContainerBlock.java index ad01631e..436b9881 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/ContainerBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/ContainerBlock.java @@ -2,6 +2,7 @@ import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.advancement.FactoryTriggers; import eu.pb4.factorytools.api.advancement.TriggerCriterion; import eu.pb4.factorytools.api.block.AttackableBlock; @@ -211,9 +212,9 @@ public final class Model extends BlockModel { private final TextDisplayElement countElement; private Model(ServerWorld world, BlockPos pos, BlockState state) { - this.mainElement = LodItemDisplayElement.createSimple(ContainerBlock.this.asItem()); + this.mainElement = ItemDisplayElementUtil.createSimple(ContainerBlock.this.asItem()); - this.itemElement = LodItemDisplayElement.createSimple(); + this.itemElement = ItemDisplayElementUtil.createSimple(); this.itemElement.setDisplaySize(1, 1); this.itemElement.setModelTransformation(ModelTransformationMode.GUI); this.itemElement.setViewRange(0.3f); diff --git a/src/main/java/eu/pb4/polyfactory/block/other/LampBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/LampBlock.java index 7543ec74..69694a17 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/LampBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/LampBlock.java @@ -1,6 +1,7 @@ package eu.pb4.polyfactory.block.other; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.item.FactoryItems; import eu.pb4.polyfactory.item.util.ColoredItem; import eu.pb4.factorytools.api.virtualentity.BlockModel; @@ -22,6 +23,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.minecraft.world.WorldView; @@ -46,6 +48,16 @@ public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) { return stack; } + public boolean setColor(World world, BlockPos pos, int color) { + color = FactoryItems.LAMP.downSampleColor(color); + if (world.getBlockEntity(pos) instanceof ColorProvider provider && provider.getColor() != color) { + provider.setColor(color); + return true; + } + + return false; + } + @Override public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) { if (world.getBlockEntity(pos) instanceof ColorableBlockEntity be) { @@ -106,7 +118,7 @@ public static final class Model extends BlockModel implements ColorProvider.Cons private BlockState state; private Model(BlockPos pos, BlockState state, boolean inverted) { - this.main = LodItemDisplayElement.createSimple(); + this.main = ItemDisplayElementUtil.createSimple(); this.main.setScale(new Vector3f(2 + (pos.getManhattanDistance(BlockPos.ORIGIN) % 2) * 0.001f)); this.main.setViewRange(0.5f); this.state = state; diff --git a/src/main/java/eu/pb4/polyfactory/block/other/SelectivePassthroughBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/SelectivePassthroughBlock.java index c0b1a0bd..b66dba2e 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/SelectivePassthroughBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/SelectivePassthroughBlock.java @@ -3,6 +3,7 @@ import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.entity.FactoryEntityTags; import eu.pb4.factorytools.api.util.VirtualDestroyStage; @@ -82,7 +83,7 @@ public void onEntityCollision(BlockState state, World world, BlockPos pos, Entit @Override public @Nullable ElementHolder createElementHolder(ServerWorld world, BlockPos pos, BlockState initialBlockState) { var model = new BlockModel(); - var element = LodItemDisplayElement.createSimple(this.asItem()); + var element = ItemDisplayElementUtil.createSimple(this.asItem()); element.setScale(new Vector3f(1.9995f)); model.addElement(element); return model; diff --git a/src/main/java/eu/pb4/polyfactory/block/other/SmallLampBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/SmallLampBlock.java index 0db74ceb..0406afd5 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/SmallLampBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/SmallLampBlock.java @@ -2,6 +2,7 @@ import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.polyfactory.item.FactoryItems; import eu.pb4.polyfactory.item.util.ColoredItem; import eu.pb4.factorytools.api.virtualentity.BlockModel; @@ -97,6 +98,16 @@ public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Ran } } + public boolean setColor(World world, BlockPos pos, int color) { + color = FactoryItems.LAMP.downSampleColor(color); + if (world.getBlockEntity(pos) instanceof ColorProvider provider && provider.getColor() != color) { + provider.setColor(color); + return true; + } + + return false; + } + @Override public boolean forceLightUpdates(BlockState blockState) { return true; @@ -156,7 +167,7 @@ public static final class Model extends BlockModel implements ColorProvider.Cons private BlockState state; private Model(BlockPos pos, BlockState state, boolean inverted) { - this.main = LodItemDisplayElement.createSimple(); + this.main = ItemDisplayElementUtil.createSimple(); this.main.setScale(new Vector3f(2)); this.main.setViewRange(0.5f); this.state = state; diff --git a/src/main/java/eu/pb4/polyfactory/block/other/WirelessRedstoneBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/WirelessRedstoneBlock.java index fe670184..61688698 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/WirelessRedstoneBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/WirelessRedstoneBlock.java @@ -7,6 +7,7 @@ import eu.pb4.factorytools.api.block.SneakBypassingBlock; import eu.pb4.factorytools.api.util.VirtualDestroyStage; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.advancement.FactoryTriggers; import eu.pb4.polyfactory.block.FactoryBlocks; @@ -239,10 +240,10 @@ public final class Model extends BlockModel implements WirelessRedstoneBlockEnti private final ItemDisplayElement key2; private Model(ServerWorld world, BlockPos pos, BlockState state) { - this.main = LodItemDisplayElement.createSimple(WirelessRedstoneBlock.this.asItem()); + this.main = ItemDisplayElementUtil.createSimple(WirelessRedstoneBlock.this.asItem()); this.main.setScale(new Vector3f(2)); - this.key1 = LodItemDisplayElement.createSimple(); + this.key1 = ItemDisplayElementUtil.createSimple(); this.key1.setDisplaySize(1, 1); this.key1.setModelTransformation(ModelTransformationMode.GUI); this.key1.setViewRange(0.3f); @@ -258,7 +259,7 @@ private Model(ServerWorld world, BlockPos pos, BlockState state) { this.key2.setScale(new Vector3f(4 / 16f, 4 / 16f, 0.01f)); this.key2.setTranslation(new Vector3f(0, -2.5f / 16f, -2.2f / 16f)); - this.overlay = LodItemDisplayElement.createSimple(createOverlay(state)); + this.overlay = ItemDisplayElementUtil.createSimple(createOverlay(state)); this.overlay.setScale(new Vector3f(2.001f)); this.overlay.setViewRange(0.6f); @@ -285,6 +286,8 @@ private ItemStack createOverlay(BlockState state) { public void updateItems(ItemStack key1, ItemStack key2) { this.key1.setItem(key1.copy()); this.key2.setItem(key2.copy()); + this.key1.tick(); + this.key2.tick(); } private void updateStatePos(BlockState state) { diff --git a/src/main/java/eu/pb4/polyfactory/block/other/WorkbenchBlock.java b/src/main/java/eu/pb4/polyfactory/block/other/WorkbenchBlock.java index 4fb13fdf..1fcbde25 100644 --- a/src/main/java/eu/pb4/polyfactory/block/other/WorkbenchBlock.java +++ b/src/main/java/eu/pb4/polyfactory/block/other/WorkbenchBlock.java @@ -4,6 +4,7 @@ import eu.pb4.factorytools.api.block.BarrierBasedWaterloggable; import eu.pb4.factorytools.api.block.FactoryBlock; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; import eu.pb4.polyfactory.block.FactoryBlockEntities; import eu.pb4.polyfactory.block.mechanical.RotationUser; @@ -14,6 +15,7 @@ import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -127,10 +129,10 @@ public ElementHolder createElementHolder(ServerWorld world, BlockPos pos, BlockS } public static class Model extends BlockModel { - private final LodItemDisplayElement base; + private final ItemDisplayElement base; private Model(BlockState state) { - this.base = LodItemDisplayElement.createSimple(state.getBlock().asItem()); + this.base = ItemDisplayElementUtil.createSimple(state.getBlock().asItem()); this.base.setScale(new Vector3f(2)); this.addElement(this.base); } diff --git a/src/main/java/eu/pb4/polyfactory/datagen/LootTables.java b/src/main/java/eu/pb4/polyfactory/datagen/LootTables.java index 02fbceb0..9adafd30 100644 --- a/src/main/java/eu/pb4/polyfactory/datagen/LootTables.java +++ b/src/main/java/eu/pb4/polyfactory/datagen/LootTables.java @@ -55,8 +55,6 @@ public void generate() { this.addDrop(FactoryBlocks.WIRELESS_REDSTONE_TRANSMITTER); this.addDrop(FactoryBlocks.TACHOMETER); this.addDrop(FactoryBlocks.STRESSOMETER); - this.addDrop(FactoryBlocks.REDSTONE_INPUT); - this.addDrop(FactoryBlocks.REDSTONE_OUTPUT); this.addDrop(FactoryBlocks.INVERTED_REDSTONE_LAMP); this.addDrop(FactoryBlocks.ELECTRIC_GENERATOR); @@ -71,12 +69,15 @@ public void generate() { this.addOptionalCable(FactoryBlocks.ITEM_COUNTER); this.addOptionalCable(FactoryBlocks.ITEM_READER); this.addOptionalCable(FactoryBlocks.BLOCK_OBSERVER); + this.addOptionalCable(FactoryBlocks.REDSTONE_INPUT); + this.addOptionalCable(FactoryBlocks.REDSTONE_OUTPUT); this.addAxle(FactoryBlocks.AXLE_WITH_LARGE_GEAR, FactoryItems.LARGE_STEEL_GEAR); this.addAxle(FactoryBlocks.AXLE_WITH_GEAR, FactoryItems.STEEL_GEAR); - this.addColored(FactoryBlocks.CABLE, (x) -> x.with(ItemEntry.builder(FactoryItems.FRAME) + this.addColored(FactoryBlocks.CABLE, (x) -> x.pool(LootPool.builder() + .with(ItemEntry.builder(FactoryItems.FRAME)) .conditionally(BlockStatePropertyLootCondition.builder(FactoryBlocks.CABLE) .properties(StatePredicate.Builder.create().exactMatch(CableBlock.FRAMED, true))))); this.addColored(FactoryBlocks.LAMP); @@ -99,31 +100,34 @@ private void addAxle(Block block, Item item) { } private void addOptionalCable(Block block) { - var x = LootPool.builder() - .conditionally(SurvivesExplosionLootCondition.builder()) - .rolls(ConstantLootNumberProvider.create(1.0F)) - .with(ItemEntry.builder(block)) - .with(ItemEntry.builder(FactoryItems.CABLE) - .conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create() - .exactMatch(GenericCabledDataBlock.HAS_CABLE, true))) - .apply(() -> CopyColorLootFunction.INSTANCE) - ); - - this.addDrop(block, LootTable.builder().pool(x)); + this.addDrop(block, LootTable.builder() + .pool(LootPool.builder() + .conditionally(SurvivesExplosionLootCondition.builder() + .and(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create() + .exactMatch(GenericCabledDataBlock.HAS_CABLE, true)))) + .with(ItemEntry.builder(FactoryItems.CABLE) + .apply(() -> CopyColorLootFunction.INSTANCE) + ) + ) + .pool(LootPool.builder() + .conditionally(SurvivesExplosionLootCondition.builder()) + .rolls(ConstantLootNumberProvider.create(1.0F)) + .with(ItemEntry.builder(block))) + ); } private void addColored(Block block) { addColored(block, (x) -> {}); } - private void addColored(Block block, Consumer consumer) { - var x = LootPool.builder() + private void addColored(Block block, Consumer consumer) { + var x = LootTable.builder().pool(LootPool.builder() .conditionally(SurvivesExplosionLootCondition.builder()) .rolls(ConstantLootNumberProvider.create(1.0F)) .with(ItemEntry.builder(block) .apply(() -> CopyColorLootFunction.INSTANCE) - ); + )); consumer.accept(x); - this.addDrop(block, LootTable.builder().pool(x)); + this.addDrop(block, x); } } diff --git a/src/main/java/eu/pb4/polyfactory/datagen/RecipesProvider.java b/src/main/java/eu/pb4/polyfactory/datagen/RecipesProvider.java index dbdc81d2..f1559913 100644 --- a/src/main/java/eu/pb4/polyfactory/datagen/RecipesProvider.java +++ b/src/main/java/eu/pb4/polyfactory/datagen/RecipesProvider.java @@ -551,7 +551,9 @@ public void generate(RecipeExporter exporter) { GenericPressRecipe.of("glistening_melon_slice", CountedIngredient.ofItems(1, Items.MELON_SLICE), CountedIngredient.ofItems(8, Items.GOLD_NUGGET), 5, OutputStack.of(Items.GLISTERING_MELON_SLICE)), GenericPressRecipe.of("golden_apple", CountedIngredient.ofItems(1, Items.APPLE), CountedIngredient.ofItems(8, Items.GOLD_INGOT), - 5, OutputStack.of(Items.GOLDEN_APPLE)) + 5, OutputStack.of(Items.GOLDEN_APPLE)), + GenericPressRecipe.of("spray_can", CountedIngredient.ofItems(1, Items.BUCKET), CountedIngredient.ofItems(1, Items.COPPER_INGOT), + 5f, OutputStack.of(FactoryItems.SPRAY_CAN)) ); of(exporter, new RecipeEntry<>(id("crafting/inverted_colored_lamp"), diff --git a/src/main/java/eu/pb4/polyfactory/item/FactoryItems.java b/src/main/java/eu/pb4/polyfactory/item/FactoryItems.java index 38eafc1e..ab99ddad 100644 --- a/src/main/java/eu/pb4/polyfactory/item/FactoryItems.java +++ b/src/main/java/eu/pb4/polyfactory/item/FactoryItems.java @@ -6,6 +6,7 @@ import eu.pb4.factorytools.api.block.MultiBlock; import eu.pb4.polyfactory.block.data.AbstractCableBlock; import eu.pb4.polyfactory.item.block.*; +import eu.pb4.polyfactory.item.tool.DyeSprayItem; import eu.pb4.polyfactory.item.tool.DynamiteItem; import eu.pb4.polyfactory.item.tool.FilterItem; import eu.pb4.polyfactory.item.tool.WirelessRedstoneTransmitterItem; @@ -104,6 +105,7 @@ public class FactoryItems { public static final Item CRUSHED_RAW_IRON = register("crushed_raw_iron", new ModeledItem(new Item.Settings())); public static final Item CRUSHED_RAW_COPPER = register("crushed_raw_copper", new ModeledItem(new Item.Settings())); public static final Item CRUSHED_RAW_GOLD = register("crushed_raw_gold", new ModeledItem(new Item.Settings())); + public static final Item SPRAY_CAN = register("spray_can", new DyeSprayItem(new Item.Settings().maxCount(1))); public static final Item THE_CUBE = register(FactoryBlocks.THE_CUBE); @@ -186,6 +188,7 @@ public static void register() { // Other items entries.add(DYNAMITE); + entries.add(SPRAY_CAN); // Generic Materials entries.add(SAW_DUST); @@ -248,6 +251,12 @@ public static void register() { for (var dye : DyeColor.values()) { entries.add(ColoredItem.stack(INVERTED_CAGED_LAMP, 1, DyeColorExtra.getColor(dye))); } + + for (var dye : DyeColor.values()) { + var x = ColoredItem.stack(SPRAY_CAN, 1, DyeColorExtra.getColor(dye)); + x.getOrCreateNbt().putInt("uses", 128); + entries.add(x); + } })).build() ); diff --git a/src/main/java/eu/pb4/polyfactory/item/tool/DyeSprayItem.java b/src/main/java/eu/pb4/polyfactory/item/tool/DyeSprayItem.java new file mode 100644 index 00000000..a641c6e3 --- /dev/null +++ b/src/main/java/eu/pb4/polyfactory/item/tool/DyeSprayItem.java @@ -0,0 +1,218 @@ +package eu.pb4.polyfactory.item.tool; + +import eu.pb4.factorytools.api.item.RegistryCallbackItem; +import eu.pb4.factorytools.api.resourcepack.BaseItemProvider; +import eu.pb4.polyfactory.block.data.AbstractCableBlock; +import eu.pb4.polyfactory.block.data.output.NixieTubeBlock; +import eu.pb4.polyfactory.block.data.output.NixieTubeBlockEntity; +import eu.pb4.polyfactory.block.mechanical.source.WindmillBlock; +import eu.pb4.polyfactory.block.mechanical.source.WindmillBlockEntity; +import eu.pb4.polyfactory.block.other.LampBlock; +import eu.pb4.polyfactory.block.other.SmallLampBlock; +import eu.pb4.polyfactory.item.FactoryItems; +import eu.pb4.polyfactory.item.util.ColoredItem; +import eu.pb4.polyfactory.util.DyeColorExtra; +import eu.pb4.polyfactory.util.inventory.WrappingRecipeInputInventory; +import eu.pb4.polymer.core.api.item.PolymerItem; +import eu.pb4.polymer.resourcepack.api.PolymerModelData; +import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.minecraft.block.BedBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.SignBlock; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.block.enums.BedPart; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.inventory.StackReference; +import net.minecraft.item.*; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.registry.Registries; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ClickType; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.ColorHelper; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +public class DyeSprayItem extends Item implements RegistryCallbackItem, PolymerItem, ColoredItem { + private static final int MAX_USES = 128; + private PolymerModelData mainModel; + private PolymerModelData emptyModel; + + public DyeSprayItem(Settings settings) { + super(settings); + } + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + var stack = context.getStack(); + var color = ColoredItem.getColor(stack); + var uses = getUses(stack); + + if (color == -1 || uses == 0) { + return ActionResult.FAIL; + } + + var state = context.getWorld().getBlockState(context.getBlockPos()); + var blockEntity = context.getWorld().getBlockEntity(context.getBlockPos()); + boolean success = false; + + if (state.getBlock() instanceof AbstractCableBlock cableBlock && cableBlock.hasCable(state)) { + success = cableBlock.setColor(state, context.getWorld(), context.getBlockPos(), color); + } else if (state.getBlock() instanceof LampBlock lampBlock) { + success = lampBlock.setColor(context.getWorld(), context.getBlockPos(), color); + } else if (state.getBlock() instanceof SmallLampBlock lampBlock) { + success = lampBlock.setColor(context.getWorld(), context.getBlockPos(), color); + } else if (state.getBlock() instanceof WindmillBlock && context.getWorld().getBlockEntity(context.getBlockPos()) instanceof WindmillBlockEntity be) { + var stacks = be.getSails(); + for (int i = 0; i < stacks.size(); i++) { + var x = stacks.get(i); + if (!x.isEmpty() && be.getSailColor(i) != color) { + FactoryItems.WINDMILL_SAIL.setColor(x, color); + be.addSail(i, x); + success = true; + break; + } + } + } else if (state.getBlock() instanceof NixieTubeBlock && context.getWorld().getBlockEntity(context.getBlockPos()) instanceof NixieTubeBlockEntity be) { + success = be.setColor(color); + if (success) { + be.updateTextDisplay(); + } + } else if (DyeColorExtra.BY_COLOR.get(color) != null && !(blockEntity instanceof Inventory)) { + var dye = DyeColorExtra.BY_COLOR.get(color); + var id = Registries.BLOCK.getId(state.getBlock()); + Identifier newId; + if (id.getPath().equals("glass") || id.getPath().equals("glass_pane")) { + newId = id.withPrefixedPath(dye.asString() + "_stained_"); + } else { + var x = id.getPath().split("_", 2); + newId = DyeColor.byName(x[0], null) == null ? id.withPath(dye.asString() + "_" + id.getPath()) : id.withPath(dye.asString() + "_" + x[1]); + } + + var block = Registries.BLOCK.get(newId); + if (block != Blocks.AIR && block != state.getBlock()) { + context.getWorld().setBlockState(context.getBlockPos(), block.getStateWithProperties(state), Block.FORCE_STATE); + + if (state.getBlock() instanceof BedBlock) { + var dir = state.get(BedBlock.FACING); + var offset = context.getBlockPos().offset(dir, state.get(BedBlock.PART) == BedPart.HEAD ? -1 : 1); + context.getWorld().setBlockState(offset, block.getStateWithProperties(context.getWorld().getBlockState(offset)), Block.FORCE_STATE); + } + success = true; + } + + } + + if (success) { + context.getWorld().playSound(null, context.getBlockPos(), SoundEvents.ITEM_DYE_USE, SoundCategory.BLOCKS); + if (context.getPlayer() == null || !context.getPlayer().isCreative()) { + setUses(stack, uses - 1); + } + + var p = new Vector3f(ColorHelper.Argb.getRed(color) / 255f, ColorHelper.Argb.getGreen(color) / 255f, ColorHelper.Argb.getBlue(color) / 255f); + ((ServerWorld) context.getWorld()).spawnParticles(new DustParticleEffect(p, 1), context.getHitPos().x, context.getHitPos().y, context.getHitPos().z, 10, 0.2f, 0.2f, 0.2f, 1); + + return ActionResult.SUCCESS; + } + return ActionResult.FAIL; + } + + @Override + public Text getName(ItemStack stack) { + if (getUses(stack) == 0) { + return Text.translatable(getTranslationKey() + ".empty"); + } + var color = ColoredItem.getColor(stack); + if (!DyeColorExtra.hasLang(color)) { + return Text.translatable( this.getTranslationKey() + ".colored.full", + ColoredItem.getColorName(color), ColoredItem.getHexName(color)); + } else { + return Text.translatable(this.getTranslationKey() + ".colored", ColoredItem.getColorName(color)); + } + } + + @Override + public boolean onClicked(ItemStack stack, ItemStack otherStack, Slot slot, ClickType clickType, PlayerEntity player, StackReference cursorStackReference) { + var color = ColoredItem.getColor(stack); + var uses = getUses(stack); + + if (otherStack.isIn(ConventionalItemTags.DYES) && uses + 8 <= MAX_USES) { + var dyeColor = DyeColorExtra.getColor(otherStack); + + if (dyeColor == color || uses == 0) { + ColoredItem.setColor(stack, dyeColor); + setUses(stack, uses + 8); + otherStack.decrement(1); + } + } else if (otherStack.isOf(Items.WATER_BUCKET)) { + setUses(stack, 0); + } else { + return false; + } + + return true; + } + + @Override + public int downSampleColor(int color, boolean isVanilla) { + return color; + } + + @Override + public int getDefaultColor() { + return -1; + } + + @Override + public int getPolymerArmorColor(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return ColoredItem.getColor(itemStack); + } + + private int getUses(ItemStack stack) { + return stack.hasNbt() ? stack.getNbt().getInt("uses") : 0; + } + + private void setUses(ItemStack stack, int count) { + stack.getOrCreateNbt().putInt("uses", count); + } + + @Override + public void onRegistered(Identifier selfId) { + this.mainModel = PolymerResourcePackUtils.requestModel(Items.LEATHER_BOOTS, selfId.withPrefixedPath("item/")); + this.emptyModel = PolymerResourcePackUtils.requestModel(BaseItemProvider.requestItem(), selfId.withPrefixedPath("item/").withSuffixedPath("_empty")); + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return getUses(itemStack) == 0 ? this.emptyModel.item() : this.mainModel.item(); + } + + @Override + public int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return getUses(itemStack) == 0 ? this.emptyModel.value() : this.mainModel.value(); + } + + @Override + public ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, @Nullable ServerPlayerEntity player) { + var out = PolymerItem.super.getPolymerItemStack(itemStack, context, player); + var uses = getUses(itemStack); + + if (uses != 0) { + out.getNbt().putInt("Damage", (int) ((((double) MAX_USES - uses) / MAX_USES) * out.getItem().getMaxDamage())); + } + return out; + } +} diff --git a/src/main/java/eu/pb4/polyfactory/models/HopperModel.java b/src/main/java/eu/pb4/polyfactory/models/HopperModel.java index 2e7bda99..fc8015b3 100644 --- a/src/main/java/eu/pb4/polyfactory/models/HopperModel.java +++ b/src/main/java/eu/pb4/polyfactory/models/HopperModel.java @@ -1,7 +1,9 @@ package eu.pb4.polyfactory.models; import eu.pb4.factorytools.api.virtualentity.BlockModel; +import eu.pb4.factorytools.api.virtualentity.ItemDisplayElementUtil; import eu.pb4.factorytools.api.virtualentity.LodItemDisplayElement; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import net.minecraft.block.BlockState; import net.minecraft.block.HopperBlock; import net.minecraft.client.render.model.json.ModelTransformationMode; @@ -12,14 +14,14 @@ import org.joml.Vector3f; public class HopperModel extends BlockModel { - private final LodItemDisplayElement icon; - private final LodItemDisplayElement model; + private final ItemDisplayElement icon; + private final ItemDisplayElement model; public HopperModel(BlockState cachedState) { - this.model = LodItemDisplayElement.createSimple(GenericParts.FILTER_MESH); + this.model = ItemDisplayElementUtil.createSimple(GenericParts.FILTER_MESH); this.model.setScale(new Vector3f(2)); this.model.setTranslation(new Vector3f(0, 15 / 16f, 0)); - this.icon = LodItemDisplayElement.createSimple(); + this.icon = ItemDisplayElementUtil.createSimple(); this.icon.setModelTransformation(ModelTransformationMode.GUI); this.icon.setViewRange(0.1f); this.icon.setScale(new Vector3f(0.3f, 0.3f, 0.005f)); diff --git a/src/main/resources/assets/polyfactory/lang/en_us.json b/src/main/resources/assets/polyfactory/lang/en_us.json index 82669e0e..4ba70611 100644 --- a/src/main/resources/assets/polyfactory/lang/en_us.json +++ b/src/main/resources/assets/polyfactory/lang/en_us.json @@ -76,6 +76,10 @@ "item.polyfactory.wooden_plate": "Wooden Plate", "item.polyfactory.treated_dried_kelp": "Treated Dried Kelp", "item.polyfactory.portable_redstone_transmitter": "Portable Redstone Transmitter", + "item.polyfactory.spray_can": "Splay Can", + "item.polyfactory.spray_can.empty": "Empty Splay Can", + "item.polyfactory.spray_can.colored": "%s Spray Can", + "item.polyfactory.spray_can.colored.full": "%s Spray Can (%s)", "block.polyfactory.colored_lamp": "Colored Lamp", "block.polyfactory.colored_lamp.colored": "%s Lamp", diff --git a/src/main/resources/assets/polyfactory/models/block/cable_base.json b/src/main/resources/assets/polyfactory/models/block/cable_base.json index 6ea4bddc..98e0a456 100644 --- a/src/main/resources/assets/polyfactory/models/block/cable_base.json +++ b/src/main/resources/assets/polyfactory/models/block/cable_base.json @@ -1,7 +1,6 @@ { "textures": { "0": "polyfactory:block/cable_base", - "1": "polyfactory:block/cable_top", "2": "polyfactory:block/cable_center", "particle": "polyfactory:block/cable_base" }, @@ -15,8 +14,8 @@ "east": {"uv": [12, 0, 16, 6], "texture": "#0", "tintindex": 0}, "south": {"uv": [8, 0, 12, 6], "texture": "#0", "tintindex": 0}, "west": {"uv": [4, 0, 8, 6], "texture": "#0", "tintindex": 0}, - "up": {"uv": [0, 0, 4, 4], "texture": "#1", "tintindex": 0}, - "down": {"uv": [0, 0, 4, 4], "texture": "#1", "tintindex": 0} + "up": {"uv": [8, 0, 12, 4], "texture": "#2", "tintindex": 0}, + "down": {"uv": [8, 0, 12, 4], "texture": "#2", "tintindex": 0} } }, { @@ -28,8 +27,8 @@ "east": {"uv": [12, 10, 16, 16], "texture": "#0", "tintindex": 0}, "south": {"uv": [8, 10, 12, 16], "texture": "#0", "tintindex": 0}, "west": {"uv": [4, 10, 8, 16], "texture": "#0", "tintindex": 0}, - "up": {"uv": [0, 0, 4, 4], "texture": "#1", "tintindex": 0}, - "down": {"uv": [0, 0, 4, 4], "texture": "#1", "tintindex": 0} + "up": {"uv": [8, 0, 12, 4], "texture": "#2", "tintindex": 0}, + "down": {"uv": [8, 0, 12, 4], "texture": "#2", "tintindex": 0} } }, { @@ -38,9 +37,9 @@ "to": [16, 10, 10], "faces": { "north": {"uv": [0, 0, 4, 6], "rotation": 90, "texture": "#0", "tintindex": 0}, - "east": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "east": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "south": {"uv": [8, 0, 12, 6], "rotation": 270, "texture": "#0", "tintindex": 0}, - "west": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "west": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "up": {"uv": [12, 0, 16, 6], "rotation": 270, "texture": "#0", "tintindex": 0}, "down": {"uv": [4, 0, 8, 6], "rotation": 270, "texture": "#0", "tintindex": 0} } @@ -51,9 +50,9 @@ "to": [6, 10, 10], "faces": { "north": {"uv": [0, 10, 4, 16], "rotation": 90, "texture": "#0", "tintindex": 0}, - "east": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "east": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "south": {"uv": [8, 10, 12, 16], "rotation": 270, "texture": "#0", "tintindex": 0}, - "west": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "west": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "up": {"uv": [12, 10, 16, 16], "rotation": 270, "texture": "#0", "tintindex": 0}, "down": {"uv": [4, 10, 8, 16], "rotation": 270, "texture": "#0", "tintindex": 0} } @@ -63,11 +62,11 @@ "from": [6, 6, 10], "to": [10, 10, 16], "faces": { - "north": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "north": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "east": {"uv": [0, 0, 4, 6], "rotation": 90, "texture": "#0", "tintindex": 0}, - "south": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "south": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "west": {"uv": [8, 0, 12, 6], "rotation": 270, "texture": "#0", "tintindex": 0}, - "up": {"uv": [12, 0, 16, 6], "texture": "#1", "tintindex": 0}, + "up": {"uv": [12, 0, 16, 6], "texture": "#0", "tintindex": 0}, "down": {"uv": [4, 0, 8, 6], "rotation": 180, "texture": "#0", "tintindex": 0} } }, @@ -76,9 +75,9 @@ "from": [6, 6, 0], "to": [10, 10, 6], "faces": { - "north": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "north": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "east": {"uv": [0, 10, 4, 16], "rotation": 90, "texture": "#0", "tintindex": 0}, - "south": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#1", "tintindex": 0}, + "south": {"uv": [8, 0, 12, 4], "rotation": 270, "texture": "#2", "tintindex": 0}, "west": {"uv": [8, 10, 12, 16], "rotation": 270, "texture": "#0", "tintindex": 0}, "up": {"uv": [12, 10, 16, 16], "texture": "#0", "tintindex": 0}, "down": {"uv": [4, 10, 8, 16], "rotation": 180, "texture": "#0", "tintindex": 0} diff --git a/src/main/resources/assets/polyfactory/models/block/redstone_input.json b/src/main/resources/assets/polyfactory/models/block/redstone_input.json index 6bd25908..5e83d000 100644 --- a/src/main/resources/assets/polyfactory/models/block/redstone_input.json +++ b/src/main/resources/assets/polyfactory/models/block/redstone_input.json @@ -1,9 +1,11 @@ { - "parent": "polyfactory:block/item_counter_old", + "parent": "polyfactory:block/nixie_tube_controller", "textures": { - "2": "polyfactory:block/redstone_input_side", - "particle": "polyfactory:block/redstone_input_side", + "particle": "polyfactory:block/cable/redstone_input_side", + "side": "polyfactory:block/cable/redstone_input_side", + "back_inner": "polyfactory:block/cable/back_inner", "front": "polyfactory:block/redstone_input_front", - "back": "polyfactory:block/steel_plate_connection" + "back": "polyfactory:block/cable/integrated_back_data", + "back_inner_center": "polyfactory:block/cable/back_inner_center_data" } } \ No newline at end of file diff --git a/src/main/resources/assets/polyfactory/models/block/redstone_output.json b/src/main/resources/assets/polyfactory/models/block/redstone_output.json index 3742d2d8..1d2e9c0f 100644 --- a/src/main/resources/assets/polyfactory/models/block/redstone_output.json +++ b/src/main/resources/assets/polyfactory/models/block/redstone_output.json @@ -1,9 +1,8 @@ { - "parent": "polyfactory:block/item_counter_old", + "parent": "polyfactory:block/redstone_input", "textures": { - "2": "polyfactory:block/redstone_output_side", - "particle": "polyfactory:block/redstone_output_side", - "front": "polyfactory:block/redstone_output_front", - "back": "polyfactory:block/steel_plate_connection" + "side": "polyfactory:block/cable/redstone_output_side", + "particle": "polyfactory:block/cable/redstone_output_side", + "front": "polyfactory:block/redstone_output_front" } } \ No newline at end of file diff --git a/src/main/resources/assets/polyfactory/models/item/spray_can.json b/src/main/resources/assets/polyfactory/models/item/spray_can.json new file mode 100644 index 00000000..f435bf80 --- /dev/null +++ b/src/main/resources/assets/polyfactory/models/item/spray_can.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "polyfactory:item/spray_can_color", + "layer1": "polyfactory:item/spray_can" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/polyfactory/models/item/spray_can_empty.json b/src/main/resources/assets/polyfactory/models/item/spray_can_empty.json new file mode 100644 index 00000000..21a79243 --- /dev/null +++ b/src/main/resources/assets/polyfactory/models/item/spray_can_empty.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "polyfactory:item/spray_can_empty" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/polyfactory/textures/block/cable/redstone_input_side.png b/src/main/resources/assets/polyfactory/textures/block/cable/redstone_input_side.png new file mode 100644 index 0000000000000000000000000000000000000000..3c0095edfee68d6b50281a7547d99701a26aebd5 GIT binary patch literal 4682 zcmeHLdvFuS89zzHcKu)oF-_{aZKUvyXyRa%RyC54ukUUqlvkvxC)RvV2|4zSgn}=O5XmI&l zu31PHe1J&ZBt)lTVAG8n>vaai0O!`hHWiLljM@rxcWM1*IR0jOybX?v(-?IRsna8Q zunLULjP7t4o9sd2nZ7IXx(bBesgZ&*(d5>oi#1BTcC6g=f z{Zr$`t6vlvo;>eut9hUktZSTc5$(LVzo6shM#ui*SI%5LbLGLMTasI^J@t;!j24qa`zlNa=2U-r*~mx7YrmZ}H&UJARzM z+0cg{yG3SCYFX{;J9hHv;PHe$`NHbiZ~W~b)3&qbx7UJLWKwR(aPNhn`*#LYtnH68 z9Trga$-DWVBre_Be4->Lw@-hoDI|BdcFaMfk7p$eg@t&12infzVJ)1WlC7jS|cH1VSB1*Ui~tR56%E02eHp$RCc7x<-+-8gXkq!E=w zyYVrzn{bC6V7XMiG6L#XF7ya1n*>%gme0wy#W_e21PYJFgMm<#i`$JFF9*l!G;TyS zh|**?Ho*LG$Ps`tCdNcym2s(sGS10HZ4uGO)j1zZQ@|&?ak-*|IUJA0Vx|~vk|Tbc zWLXv`D4e1&h`^$Wkiy5YP_#&;NO3qpRES7nMUq3P%E^1>X2ota!gX}WzhKzy9;OdP z(<(qc@HijFNfUtwgZStjQKhm4lB6B_${kTpA`I|45S5!F0;p^OA*Ev~w zS~#MBg8&FZXcSr{$Cy-a+VBol0>2atYrCM>V~~pE8xd=aZ|aH`&S*#A_F>*J=%Ls( zFhsfCoKqH>Rrg#@yHT~ziLxMxoHitB*2h>Z0tS3#G{#s(FUEUWA7&+Znj#1@O%UWL zDpx3~@F4-HRFK>xK^`mVwOB}j#%RF;FvcPX7;hFS%wq9TB55YdD4}c=MNLG4S;+@R zd!K9T0lltv{A+(U9C$iw55g1jH#;gDZj zPzC4a)w=9P%0!IJ)CPFP2RGP_3#3qUd}P5R1wp;St7?)~qKt)xShKZ^Ag%NWXc34+ zVJ51aTFul})MMdbFi==t%~MFA&BItYM+ESS9P!9V*n#!yl7@I7^XmzBE@>G{8*>|rw}b)&WUu0He4->Lx*a^|Kr$G zfKhc6N|Ty{^%<6Xe7N4HHB&3=9ekzJ?G9Ri)DuR=rSF7X6LO79fpLK+vTH)FaVan^ z@I-d~-{i_3`NRl9@E^Sx{5+Vo_q|QU(qL9WX=&r|l!u4fND`6e-CUHQf=|Ibf-+x_+q zdvEV!{j-&8bo?zt{CfRIj~veEY1DtiCK7#mvSIC3^yAtBS^Uz5D?4rsF36gCinTttuFUmJc(v}O{KZZC zP~HAl%bz*Vet0bJo@B$p#_mO>+aLb(jlmCG#g`wge&I6f`c2CZc1s2AJw=s|Y}h@y z&SpI^aN?xxNJHtq0p!wOOo>Se$Ck^3+hWH)H#9G;nL0(TNV*&KwHM6i*`x0-F>NPi zhR#J+C3~|R%er?3_LO(;-?nGq^JPW9-dAvSdmEV{PLu~*6 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/polyfactory/textures/block/cable/redstone_output_side.png b/src/main/resources/assets/polyfactory/textures/block/cable/redstone_output_side.png new file mode 100644 index 0000000000000000000000000000000000000000..d76fd7081b388b70a1ab5bbe65a87397eabe51c8 GIT binary patch literal 4688 zcmeHLdvFuS89zxR2H6-)O`r}8hj`fzr+eu1xT}N#%drF&c5OGol(aeB?U}=tPDm$9 zcJPGQl!U3CZHv!vDT?f&++-}l>Zztd@R$%?{>#w;U(AQQbFcPXqVt7ZIy@O#!*_c&N}f|Xv; z>&->R!wZPijYD)Q1{U40wq9pI46tt#EK^`x#i%7q_kdP!h3$uv?Om{)oy4efNSz*; z2+~bqg%gvx&9dfo=6QUVGd1h=v%b3%$M)lrocq*DJYJQaVo284V*FX1iq1Z$&@OtChjz87cS2yjm zita0SXBgK0!M~w+?tZYTVqQ18zx!xb^PSE4N3&l)f8~7d{3mww?Y#E<1-UsjJ=JLu zUMu_R{A~Y;&U4FB+Fto(MsY@Ax$p4$*}ZRkP`jn=vDOnGxxPtlWa`15Yjoj`v!*6= z$;O7PW!VRx&pyWHJXCse)}5Qr&OGBb|7`U7Ti^h8Z*T`~x5SES0ZRR{DxqUJjT!LG}Z4JP=Yh3UTJeLmXcP6x0tYrJ&1nqy3Btl?0dR zajTE;h4R4~$x{~wWpyjc`MN5e5lnfDjLtX<2?9Xj(0HIa7-8cslg7)!w%U!GPz|C~ zxlAiz{N&4FfYN5#Okf3ZsfIEwGNR6~AhMtEQJ(F4x%b2=a-|3%VdJ%=zx8Jkk2c@kaq-nz;_J{ zQ9d8*miee^p4aU%sq3?X%u52RHEnha#c_TPBM8ch(RPx@7|P+tNY2I(B4=?hfEY&Q z4Mr3$$ODxMlA9&SQwngE01pK#wEkTMhiAS=CC@fn1vQ?l)zgk zk+zOxkI14Du@h z4m(p6udg8Gsy@q@ntf#591HxTV2anhq}*{~-_P6EzDs0o%KLt*(=&NzS8->@j<6l2U4Qe1r`d zPo%|9{q$nzyG55amKrzwx^=>A{qEPK^uB+uebYGYrYGm(s@^J2{mBzF3M@xa<-@Ep<8v%&gjhO6K$7o6qHO#OW)GdA3t#8 zsirBH^R6GxSoZ1izIfeyU)c+DE9O5LT3?Xf*!#t28GKqr)6OfWQ**h;n~<%&j_ns$ zwI5CKT?#FFsp9y@Cj;&86`eV{@X)8>(;FXt|LK3>w;bDU*Khx5@3pVl|D21W+P1?i(}tY4}m>d5U?cp_k~ zPDhtjmS|Ui;uWs7Rx@Jk7kWBRdh|$RhnUQth&5I_EMC8QpvBQ7uW*jfuS+lJ(f>(K z-4gtLzdyda_xPQx!j;oLrq;(8LO1uM*r+WtUY+znlhM^o9jH{eYDco`}rP!nIuLIXjL6^{}4FXF;m5;hi`j#yBZ^Ps1CzeiF&EnR_8nVEt?9YSx54)p{?G5YS zsj((IJnzn}=V5M)T@bkW?fc~0d2<;4r9be>{;6G>@NDvzDDQ3=#=W->94++@{?>3> zHsOQkbl#g2|CqGa$W_=c&OgQQce}&)S+}E$<(Kn2bnWuG!@%Btz@u@~b=!M)uim@8 zKYiBUzYME1i}udcp3A|&z!#kv5>XQ2>tmIizj-oK1CxrenYmd?Vv3n=vPG(iu8CQq zg>Is8VzREWL8_stWst1+VwBBOl1)twOcR0Trkd)S7^hn5S|pn!>n0f*o0u6I7@8y+O?G7WLDoB+ zJ&!}|;|`Crz=Xn<g8LH%@Gb&eRSlow`F?K zxi@=nRttYMZ=9K!<}&wM)S9gtO9Q+VUy0{_C~n$4xkEw8W$ruEyRzl#uR^kyUOQ#k rUd$J`KcQKE|KG+{i&nY(wK&LnbP0l+XkKspdQq delta 688 zcmdm^d_Zx+9Ys?GLnA8_ATnWKWMEvt3?v!A7)UYf&|nRl_*b%iYmgRSSwJC2#9W<@ zE{iPDu7HJCxYkX?(-2LFz2M>-XT|Ia-GMqi!QQ!|lVOc>?$wZ<5(?z0= zR21ClFaIuA{+?lBT-vIehI}h#r7n47XgE1mlzF{?L4(3B10BQQ`QB>6A7tXcfB5)S z@6_f!=l@z(O__6&VZMjW>H3nxO7|4z-P=-f?)Qv{Y+QF`;K`8n2h z)_Iae@($&$Re}2^6h=PWb2L&nJo59rKdlSrY}<6Ebe3~R zvY@wzQ%jGQm&ReIDPg@L!kV}GD}S)d)=!Et+Ub?>B*KAJOXWEKKlc5*O+Qbr7tRaP zU@O^o zVp58!ZenVhfu*roN=k~E;be2x6+9MZhQ?+l=H})Gre>30vleohhQQ)@avGZo5_j_y zHbKVC9UKW9Vn<}{mjh#*Ey>&6h2cL4F4((#^5lO43iXoQS~><_%mskbsh%#5Ar`04 zUf9UXV#vXI(K0Dn~>#hf^TOa-VV7W`> R7$^yPy0ZDXtaD0e0syw|BM|@q diff --git a/src/main/resources/assets/polyfactory/textures/block/cable_center.png b/src/main/resources/assets/polyfactory/textures/block/cable_center.png index 92bc6f815fc173bfc4cff5d99b756655cb2a40cf..679316b15f07706b2954d622ea05882eca8d8a9f 100644 GIT binary patch delta 913 zcmV;C18)5HA;2V%83+ad001BJ|6!3KyCF6pF*!OlI65*n00962paTE_0000100000 z0001wz!RF0{TY9yA{9XkN^!_goh*ooI%*Y)P$AR`tvZ-oKcPuOlH%ehxE37zSgbm@ zIP2=*DhPrfAkGd>iY`*(|B^zB7!Qv7@$TN^?j0c1%S<&p#sF2bjAT3}rZcNz;1vSG z=)*JyWM=Afl9Yhw__~LWuXjvrK#I?W-(v4|x|5TT%o63Va;rBx%vM3VMn9{#Z7m&m1%s{}@l1yrCycKqOf z@Vi?xKQVvqCIw?a=ZkHB3(i|qi@Op{kK5(n%i4*AEysMin>bN00)P_NP)7~J>K2b z-rK)tn*IF%swr~4nJb+L000hKX;fHrSWQeiV{fyQ0)PS}H(@t8W;ii5EjBebVJ$Rc zH#99cVP-ikVK+H8F*RglV_`96lQ#vZ3pqD4IWRXlG&M9elj;R>3N}tGB>l71`z?1!UkLYk6o=tAHKdkAf@g@6;5T>yk~y_-_zz!du83ya0zNB@Qhd5Za}JaS(#^4un4QIWPRIjd;5h2>?*- z0pLr(-Brf|NYk_o!w^*^&vT+EviPIsOTb5e_no!X6^;%P8q+iMi=sLR!;tmOEe=o4 zFvbAz+*~fZ=X)hUZ3@`m-N6`xF@~fSGa8MmfU4qoE`z}k5dmOnVUd@&R{(6)9wLH> zpsK$QzFP(IJm>PFjfjwC836OAx77^$`wOn`pGaCUs>;p7BTl1U1;#gzvuEc5`bEJc nal3=(xj0Up!RL^PiT~vXjipnuvn7R500000NkvXXu0mjfYcYRX delta 754 zcmX@0@?CL)BnJ}%1H*)g8DE?54ZVPRa_s+)#~gHaSnkStWu`8|JiMOdyMlzJ=?l1)Ak3kr`dU~-@4_5 z;Dz11F)`asD*1QZVf;0}XQ2>tmIizj-oK1CxrWiGjIc zs%eU@kwr?1u8Fa6lCGt3nuTtXrGa^}u|-N!l2PJhbJi8y7G{QKmZrv*<`x!{U$GW( znTEikcybz>3KDno6gEM|%^e&G9Afk8J?;P_oGr=Q-G$*l2rk&WeDdUf0t)q#+y?wg z`}XVvO3(3haSYKopWNf=Cn_YAoRCoQ{hcT?GxPol5%t;3%y|cn=&O8t^YL(iegCON zOn!X#uKUk7dcf*)hKJ|p&6izZz#4gSf8AfD1rP7;4tD~B_xJWze}5;-Z*R`X`@hcE zXNKALe}8{}e}8|zO|2QTt>OVC4ZUx_US59nD@;x<&&=$bzWn}2*AM)7eLbHoh(VaS fGa=;gg9{7{A=*aa9~__7gHo=itDnm{r-UW|O~yXp diff --git a/src/main/resources/assets/polyfactory/textures/block/cable_top.png b/src/main/resources/assets/polyfactory/textures/block/cable_top.png deleted file mode 100644 index a0897fc56fd5f0eb8433eee5df39be7a69841b46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 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 delta 698 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 S%6|yJn73$_XXo^VOa26PxUJU! delta 483 zcmV<90UZ9YA@T!|8Gi%-006c6H|hWY0dZ+VLr`gBV*mhn+Lh5eNJ3E@$MLUPSW!e& z5Ycc4Yf6ZUXe14i@hLEBIu~?&FZxQ&FTyEd+z6Y| z$eiOoKuR@OX|S3$b;px{Pty&}aja%dxFoD+iz>Bp0i6kBc}etvA%ZNhNEiu)A{nw2 z@RPwn!XiSDK!20@LBxERA_`eDs7TC{Lq|r;BmUrbwpMat8~|5m09v1H`)wG!+fXgr z_UEB(SC7E+2p2|uK39S1ckqLOzZ^GGSy{GKJ`4$X3U6#0bB|-a(ym)_y_<1010qNS#tmY z3ljhU3ljkVnw%H_001XRL_t(|+G7|J;Lm>o3U2@Z^MB=kye8cKzY+-XDF7>>#0rL? Z4*=1o9c|gV-cSGl002ovPDHLkV1hVo(`5hv diff --git a/src/main/resources/assets/polyfactory/textures/item/spray_can.png b/src/main/resources/assets/polyfactory/textures/item/spray_can.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5d67324fbc954487131dc92ebe07c198d70306 GIT binary patch literal 4628 zcmeHLdvFuS89zzJHfl*^a7qT#R2-zic24)u^RAW?BNoC!fxi z>_P&>r749F5<0wW@~WpvYA6{d>4Xpnt|%T72!#Se9@M2wNt!8?Kxx8I=-x?|O`4gG zXTpD$z25J3f8TF+f8V#Ceg1iPZq)?y6f=S#6M_MM4eTvi%g=>Bzjx&p3%g^WJ}3r* zB}hJefJj3QV$d+K8AjMfg9$OgvDL6mgtms!+7!b$yrx1xH+cCcESBwMQG4{|RoKSz`flw77SZw^kL@!0u2=Pnmr*!!;W z{cmr3<$PJ|=KA-3x9fO+-{K{y+El^36UB{zpY$nb&-MMXq_4I5W`B5oW5eH=BW&um zC+`nfUU+^LI%iiw@4N>N&U)q=AGz_w&PH_8texn+^moFmbI<(iiCYIQMR$C3zH3wA z8bc5M)D_a0)4sCvWb3~5-~IJt#xI^*S^D;;_~{i}s*nFBgef^!qo&EHL!mP!TVln^ z2YfED;PVrO3O)Frwfl-qSO0AMc0F|{SBQ4Q5lk}oGF9U6D z7)Px-L|y7d>tP=GWCd6qHiwPCDw9$>g_fJGWr`p&HU8Nd3i#wjn^iT&;CLdDuqEs^ zS!u#anx=7r!YK-a2rS+aRoNsKjZfDo(j0ye=M^cYN^;byak8A;rg~8n&Rd7}7m0;J zS^8)^qXN_ePqHzbv=MkDf{*lwtCj7LB(tHf^@!JX!~k9c;&Pk9gUWUgRi}@n5csTr ztW9ark0bCnXaNxjjl)&R+m_UBT-HOAph=3vbT26OZAeuThsC;WZ`zE0oRJ%W?pfa3 z&_id}!4MS+F@BkE)3z7%dr@tDMv!?)V02TY0p|j4Cq{c5F3jO1DU9Y^0_LJco^%jA z!P(gnRKaLmWurXMs35sbf;^(YkuHMcF@okr%)#+AMmq%pqeb8*L?m|n9Q2};jTjyYx3H=R9lYqHQnW2OJW(e_K&{GZYLae(CY*%JP0@tiMR|rn z^MMkFnW%BEv(q7Xodi~8{j3Tg zX|@j64b|aNf@FyF_BFbYEJ$L<|3hn+$65yQFysL#4%hF{htfBy7PO|H(vK~YewD0N z{ZcS2pFTpIZ3pRKL9X-^-^@mv0IVLFbR8O(z9tnsoB%UHBr$<=keGueD2!tTJ4OVYcOHOrzC%|MF+6bysZl&g-iL!B7P zkr52P^G9^K?7-vZ-5Bi#Eanhs8uPeC0&^397VW_8_PD;uBf7tu6PY8H;aXW73Thet zKVeS;M$}O#O?nL0XISp>Y`xED21UM;pG>;l$tA4Tu|-Cu@0eU;a*axXQGv&@YfP?D zDKIMVSayA5a+!zU7(o>Np_hQ~gJ+0;4#0QGT<(!7zy4NA9u%)tb#-_lef&2IVbl0|7 zFAWytR8$sR&RvzX>>eE7mnxmveC*}kmp^^*52r-a!u*@p?q2UUnI7-?@K?6a=FdAU zmb}4z{OaM0PrrtrO|A2HBdya5_U~TYxYuxOPQ$c)>&mvh|HmWKkXOiyrC0a-xP}j` zt0)EIz5sd0=d>P;AMLmpjSWyA97z@3ef_?7#NBPCWf#6o?kUJ8g>^zAcR_-cbNxGK HEnf9sGwv$E literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/polyfactory/textures/item/spray_can_color.png b/src/main/resources/assets/polyfactory/textures/item/spray_can_color.png new file mode 100644 index 0000000000000000000000000000000000000000..33b2f623278c7f42577ea0963ba955d6ef07f151 GIT binary patch literal 4248 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 literal 0 HcmV?d00001