diff --git a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java index cb6ddde..7f5828e 100644 --- a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java +++ b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java @@ -12,11 +12,13 @@ import dev.imabad.theatrical.blockentities.light.BaseLightBlockEntity; import dev.imabad.theatrical.blockentities.light.FresnelBlockEntity; import dev.imabad.theatrical.blocks.light.MovingLightBlock; +import dev.imabad.theatrical.blocks.light.MovingWashBlock; import dev.imabad.theatrical.client.LazyRenderers; import dev.imabad.theatrical.client.blockentities.BasicLightingConsoleRenderer; import dev.imabad.theatrical.client.blockentities.FresnelRenderer; import dev.imabad.theatrical.client.blockentities.LEDPanelRenderer; import dev.imabad.theatrical.client.blockentities.MovingLightRenderer; +import dev.imabad.theatrical.client.blockentities.MovingWashRenderer; import dev.imabad.theatrical.client.dmx.ArtNetManager; import dev.imabad.theatrical.client.dmx.ArtNetToNetworkClientData; import dev.imabad.theatrical.client.dmx.TheatricalArtNetClient; @@ -57,6 +59,7 @@ public class TheatricalClient { private static ArtNetManager artNetManager; public static void init() { BlockEntityRendererRegistry.register(BlockEntities.MOVING_LIGHT.get(), MovingLightRenderer::new); + BlockEntityRendererRegistry.register(BlockEntities.MOVING_WASH.get(), MovingWashRenderer::new); BlockEntityRendererRegistry.register(BlockEntities.LED_FRESNEL.get(), FresnelRenderer::new); BlockEntityRendererRegistry.register(BlockEntities.LED_PANEL.get(), LEDPanelRenderer::new); BlockEntityRendererRegistry.register(BlockEntities.BASIC_LIGHTING_DESK.get(), BasicLightingConsoleRenderer::new); diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/BlockEntities.java b/common/src/main/java/dev/imabad/theatrical/blockentities/BlockEntities.java index 828dcd4..05b0d35 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/BlockEntities.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/BlockEntities.java @@ -9,6 +9,7 @@ import dev.imabad.theatrical.blockentities.light.FresnelBlockEntity; import dev.imabad.theatrical.blockentities.light.LEDPanelBlockEntity; import dev.imabad.theatrical.blockentities.light.MovingLightBlockEntity; +import dev.imabad.theatrical.blockentities.light.MovingWashBlockEntity; import dev.imabad.theatrical.blocks.Blocks; import net.minecraft.core.registries.Registries; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -22,4 +23,5 @@ public class BlockEntities { public static final RegistrySupplier> REDSTONE_INTERFACE = BLOCK_ENTITIES.register("redstone_interface", () -> BlockEntityType.Builder.of(RedstoneInterfaceBlockEntity::new, Blocks.REDSTONE_INTERFACE.get()).build(null)); public static final RegistrySupplier> LED_PANEL = BLOCK_ENTITIES.register("led_panel", () -> BlockEntityType.Builder.of(LEDPanelBlockEntity::new, Blocks.LED_PANEL.get()).build(null)); public static final RegistrySupplier> BASIC_LIGHTING_DESK = BLOCK_ENTITIES.register("basic_lighting_desk", () -> BlockEntityType.Builder.of(BasicLightingDeskBlockEntity::new, Blocks.BASIC_LIGHTING_DESK.get()).build(null)); + public static final RegistrySupplier> MOVING_WASH = BLOCK_ENTITIES.register("moving_wash", () -> BlockEntityType.Builder.of(MovingWashBlockEntity::new, Blocks.MOVING_WASH_BLOCK.get()).build(null)); } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingWashBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingWashBlockEntity.java new file mode 100644 index 0000000..ed2371b --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingWashBlockEntity.java @@ -0,0 +1,84 @@ +package dev.imabad.theatrical.blockentities.light; + +import dev.imabad.theatrical.api.Fixture; +import dev.imabad.theatrical.blockentities.BlockEntities; +import dev.imabad.theatrical.blocks.light.MovingWashBlock; +import dev.imabad.theatrical.fixtures.Fixtures; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Arrays; + +public class MovingWashBlockEntity extends BaseDMXConsumerLightBlockEntity { + public MovingWashBlockEntity(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { + super(blockEntityType, blockPos, blockState); + setChannelCount(7); + } + + public MovingWashBlockEntity(BlockPos pos, BlockState state) { + this(BlockEntities.MOVING_WASH.get(), pos, state); + } + @Override + public Fixture getFixture() { + return Fixtures.MOVING_WASH.get(); + } + + @Override + public void consume(byte[] dmxValues) { + int start = this.getChannelStart() > 0 ? this.getChannelStart() - 1 : 0; + byte[] ourValues = Arrays.copyOfRange(dmxValues, start, + start+ this.getChannelCount()); + if(ourValues.length < 7){ + return; + } + if(this.storePrev()){ + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + } + intensity = convertByteToInt(ourValues[0]); + red = convertByteToInt(ourValues[1]); + green = convertByteToInt(ourValues[2]); + blue = convertByteToInt(ourValues[3]); + focus = convertByteToInt(ourValues[4]); + pan = (int) ((convertByteToInt(ourValues[5]) * 360) / 255f) - 180; + tilt = (int) ((convertByteToInt(ourValues[6]) * 270) / 255F) - 225; + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + setChanged(); + } + + @Override + public int getDeviceTypeId() { + return 0x01; + } + + @Override + public String getModelName() { + return "Moving Wash"; + } + + @Override + public ResourceLocation getFixtureId() { + return Fixtures.MOVING_WASH.getId(); + } + + @Override + public int getActivePersonality() { + return 0; + } + + public int convertByteToInt(byte val) { + return Byte.toUnsignedInt(val); + } + @Override + public boolean isUpsideDown() { + return getBlockState().getValue(MovingWashBlock.HANGING) && getBlockState().getValue(MovingWashBlock.HANG_DIRECTION) == Direction.UP; + } + + @Override + public int getBasePan() { + return 0; + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/Blocks.java b/common/src/main/java/dev/imabad/theatrical/blocks/Blocks.java index 7b7e500..518d9f3 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/Blocks.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/Blocks.java @@ -9,6 +9,7 @@ import dev.imabad.theatrical.blocks.light.FresnelBlock; import dev.imabad.theatrical.blocks.light.LEDPanelBlock; import dev.imabad.theatrical.blocks.light.MovingLightBlock; +import dev.imabad.theatrical.blocks.light.MovingWashBlock; import dev.imabad.theatrical.blocks.rigging.TankTrapBlock; import dev.imabad.theatrical.blocks.rigging.TrussBlock; import net.minecraft.core.BlockPos; @@ -23,6 +24,7 @@ public class Blocks { public static final DeferredRegister BLOCKS = TheatricalRegistry.get(Registries.BLOCK); public static final RegistrySupplier MOVING_LIGHT_BLOCK = BLOCKS.register("moving_light", MovingLightBlock::new); + public static final RegistrySupplier MOVING_WASH_BLOCK = BLOCKS.register("moving_wash", MovingWashBlock::new); public static final RegistrySupplier PIPE_BLOCK = BLOCKS.register("pipe", dev.imabad.theatrical.blocks.rigging.PipeBlock::new); public static final RegistrySupplier ART_NET_INTERFACE = BLOCKS.register("artnet_interface", ArtNetInterfaceBlock::new); public static final RegistrySupplier LED_FRESNEL = BLOCKS.register("led_fresnel", FresnelBlock::new); diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingWashBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingWashBlock.java new file mode 100644 index 0000000..e3253c7 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingWashBlock.java @@ -0,0 +1,125 @@ +package dev.imabad.theatrical.blocks.light; + +import dev.imabad.theatrical.TheatricalClient; +import dev.imabad.theatrical.TheatricalScreen; +import dev.imabad.theatrical.blockentities.BlockEntities; +import dev.imabad.theatrical.blockentities.light.MovingWashBlockEntity; +import dev.imabad.theatrical.blocks.Blocks; +import dev.imabad.theatrical.net.OpenScreen; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.EntityCollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +public class MovingWashBlock extends BaseLightBlock{ + + + public MovingWashBlock() { + super(Properties.of() + .requiresCorrectToolForDrops() + .strength(3, 3) + .noOcclusion() + .isValidSpawn(Blocks::neverAllowSpawn) + .mapColor(MapColor.METAL) + .sound(SoundType.METAL) + .pushReaction(PushReaction.DESTROY)); + } + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return new MovingWashBlockEntity(blockPos, blockState); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + super.createBlockStateDefinition(builder); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext blockPlaceContext) { + return super.getStateForPlacement(blockPlaceContext).setValue(HANGING, + blockPlaceContext.getClickedFace() == Direction.DOWN || + isHanging(blockPlaceContext.getLevel(), blockPlaceContext.getClickedPos())); + } + + @Override + public boolean canSurvive(BlockState blockState, LevelReader levelReader, BlockPos blockPos) { + if(blockState.getValue(HANGING)){ + return isHanging(levelReader, blockPos); + } + return !levelReader.getBlockState(blockPos.below()).isAir(); + } + + @Override + public Direction getLightFacing(Direction hangDirection, Player placingPlayer) { + if(hangDirection == Direction.UP){ + return placingPlayer.getDirection(); + } + Direction playerFacing = placingPlayer.getDirection(); + return playerFacing.getOpposite(); + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { + return blockEntityType == BlockEntities.MOVING_WASH.get() ? MovingWashBlockEntity::tick : null; + } + + @Override + public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + if(context instanceof EntityCollisionContext entityCollisionContext && entityCollisionContext.getEntity() == null){ + return Shapes.empty(); + } + return super.getVisualShape(state, level, pos, context); + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if(super.use(state, level, pos, player, hand, hit) == InteractionResult.PASS) { + if (level.isClientSide) { + if (player.isCrouching()) { + if (TheatricalClient.DEBUG_BLOCKS.contains(pos)) { + TheatricalClient.DEBUG_BLOCKS.remove(pos); + } else { + TheatricalClient.DEBUG_BLOCKS.add(pos); + } + return InteractionResult.SUCCESS; + } + } else { + new OpenScreen(pos, TheatricalScreen.GENERIC_DMX).sendTo((ServerPlayer) player); + } + } + return InteractionResult.SUCCESS; + } + + @Override + public void destroy(LevelAccessor level, BlockPos pos, BlockState state) { + if(level.isClientSide()) { + TheatricalClient.DEBUG_BLOCKS.remove(pos); + } + super.destroy(level, pos, state); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingWashRenderer.java b/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingWashRenderer.java new file mode 100644 index 0000000..b019c53 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingWashRenderer.java @@ -0,0 +1,215 @@ +package dev.imabad.theatrical.client.blockentities; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import dev.imabad.theatrical.TheatricalExpectPlatform; +import dev.imabad.theatrical.blockentities.light.LEDPanelBlockEntity; +import dev.imabad.theatrical.blockentities.light.MovingWashBlockEntity; +import dev.imabad.theatrical.blocks.HangableBlock; +import dev.imabad.theatrical.client.LazyRenderers; +import dev.imabad.theatrical.client.TheatricalRenderTypes; +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +import java.util.Optional; + +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +public class MovingWashRenderer extends FixtureRenderer { + private BakedModel cachedPanModel, cachedTiltModel, cachedStaticModel; + + public MovingWashRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + public void renderModel(MovingWashBlockEntity blockEntity, PoseStack poseStack, VertexConsumer vertexConsumer, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging, int packedLight, int packedOverlay) { + if(cachedStaticModel == null){ + cachedStaticModel = TheatricalExpectPlatform.getBakedModel(blockEntity.getFixture().getStaticModel()); + } + if (cachedPanModel == null){ + cachedPanModel = TheatricalExpectPlatform.getBakedModel(blockEntity.getFixture().getPanModel()); + } + if (cachedTiltModel == null){ + cachedTiltModel = TheatricalExpectPlatform.getBakedModel(blockEntity.getFixture().getTiltModel()); + } + //#region Fixture Hanging + poseStack.translate(0.5F, 0, .5F); + if(isHanging){ + Direction hangDirection = blockState.getValue(HangableBlock.HANG_DIRECTION); + poseStack.translate(0, 0.5, 0F); + if(hangDirection.getAxis() != Direction.Axis.Y){ + if(hangDirection.getAxis() == Direction.Axis.Z){ + if(hangDirection == Direction.SOUTH) { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + } + } else { + if(hangDirection == Direction.EAST) { + poseStack.mulPose(Axis.ZN.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZN.rotationDegrees(90)); + } + } + } else { + //TODO: Handle hanging up + } + poseStack.translate(0, -0.5, 0F); + } + //#endregion + poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot())); + poseStack.translate(-0.5F, 0, -.5F); + if (isHanging) { + Optional optionalSupport = blockEntity.getSupportingStructure(); + if (optionalSupport.isPresent()) { + float[] transforms = blockEntity.getFixture().getTransforms(blockState, optionalSupport.get()); + poseStack.translate(transforms[0], transforms[1], transforms[2]); + } else { + poseStack.translate(0, 0.19, 0); + } + poseStack.translate(0, -0.08, 0); + } + if (isFlipped) { + poseStack.translate(0.5F, 0.5, .5F); + poseStack.mulPose(Axis.ZP.rotationDegrees(180)); + poseStack.translate(-0.5F, -0.5, -.5F); + } + // Static Model Render + minecraftRenderModel(poseStack, vertexConsumer, blockState, cachedStaticModel, packedLight, packedOverlay); + //#region Model Pan + float[] pans = blockEntity.getFixture().getPanRotationPosition(); + poseStack.translate(pans[0], pans[1], pans[2]); + int prevPan = blockEntity.getPrevPan(); + int pan = blockEntity.getPan(); + poseStack.mulPose(Axis.YP.rotationDegrees((prevPan + (pan - prevPan) * partialTicks))); + poseStack.translate(-pans[0], -pans[1], -pans[2]); + minecraftRenderModel(poseStack, vertexConsumer, blockState, cachedPanModel, packedLight, packedOverlay); + //#endregion + //#region Model Tilt + float[] tilts = blockEntity.getFixture().getTiltRotationPosition(); + poseStack.translate(tilts[0], tilts[1], tilts[2]); + int prevTilt = blockEntity.getPrevTilt(); + int tilt = blockEntity.getTilt(); + if (isFlipped) { + poseStack.mulPose(Axis.XP.rotationDegrees(-180)); + } else { + poseStack.mulPose(Axis.XP.rotationDegrees(180)); + } + poseStack.mulPose(Axis.XP.rotationDegrees((prevTilt + (tilt - prevTilt) * partialTicks))); + poseStack.translate(-tilts[0], -tilts[1], -tilts[2]); + minecraftRenderModel(poseStack, vertexConsumer, blockState, cachedTiltModel, packedLight, packedOverlay); + //#endregion + } + @Override + public void beforeRenderBeam(MovingWashBlockEntity blockEntity, PoseStack poseStack, VertexConsumer vertexConsumer, MultiBufferSource multiBufferSource, Direction facing, float partialTicks, boolean isFlipped, BlockState blockstate, boolean isHanging, int packedLight, int packedOverlay) { + if(blockEntity.getIntensity() > 0){ + LazyRenderers.addLazyRender(new LazyRenderers.LazyRenderer() { + @Override + public void render(MultiBufferSource.BufferSource bufferSource, PoseStack poseStack, Camera camera, float partialTick) { + poseStack.pushPose(); + Vec3 offset = Vec3.atLowerCornerOf(blockEntity.getBlockPos()).subtract(camera.getPosition()); + poseStack.translate(offset.x, offset.y, offset.z); + preparePoseStack(blockEntity, poseStack, facing, partialTick, isFlipped, blockstate, isHanging); + VertexConsumer beamConsumer = multiBufferSource.getBuffer(TheatricalRenderTypes.BEAM); +// poseStack.translate(blockEntity.getFixture().getBeamStartPosition()[0], blockEntity.getFixture().getBeamStartPosition()[1], blockEntity.getFixture().getBeamStartPosition()[2]); + float intensity = (blockEntity.getPrevIntensity() + ((blockEntity.getIntensity()) - blockEntity.getPrevIntensity()) * partialTicks); + int color = blockEntity.getColour(); + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + int a = (int) (((float) ((intensity * 1) / 255f)) * 255); + poseStack.translate(0.5, 0.87f, 0.29f); + Matrix4f m = poseStack.last().pose(); + Matrix3f normal = poseStack.last().normal(); + addVertex(beamConsumer, m, normal, r, g, b, a, -0.3125f, 0.3125f , 0f); + addVertex(beamConsumer, m, normal, r, g, b, a, 0.3125f, 0.3125f, 0f); + addVertex(beamConsumer, m, normal, r, g, b, a, 0.3125f, -0.3125f,0f); + addVertex(beamConsumer, m, normal, r, g, b, a,-0.3125f, -0.3125f, 0f); + poseStack.popPose(); + } + + @Override + public Vec3 getPos(float partialTick) { + return blockEntity.getBlockPos().getCenter(); + } + }); + } + } + + @Override + public void preparePoseStack(MovingWashBlockEntity blockEntity, PoseStack poseStack, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging) { + poseStack.translate(0.5F, 0, .5F); + if(isHanging){ + Direction hangDirection = blockState.getValue(HangableBlock.HANG_DIRECTION); + poseStack.translate(0, 0.5, 0F); + if(hangDirection.getAxis() != Direction.Axis.Y){ + if(hangDirection.getAxis() == Direction.Axis.Z){ + if(hangDirection == Direction.SOUTH) { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + } + } else { + if(hangDirection == Direction.EAST) { + poseStack.mulPose(Axis.ZN.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZN.rotationDegrees(90)); + } + } + } else { + //TODO: Handle hanging up + } + poseStack.translate(0, -0.5, 0F); + } + //#endregion + poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot())); + poseStack.translate(-0.5F, 0, -.5F); + if (isHanging) { + Optional optionalSupport = blockEntity.getSupportingStructure(); + if (optionalSupport.isPresent()) { + float[] transforms = blockEntity.getFixture().getTransforms(blockState, optionalSupport.get()); + poseStack.translate(transforms[0], transforms[1], transforms[2]); + } else { + poseStack.translate(0, 0.19, 0); + } + poseStack.translate(0, -0.08, 0); + } + if (isFlipped) { + poseStack.translate(0.5F, 0.5, .5F); + poseStack.mulPose(Axis.ZP.rotationDegrees(180)); + poseStack.translate(-0.5F, -0.5, -.5F); + } + float[] pans = blockEntity.getFixture().getPanRotationPosition(); + poseStack.translate(pans[0], pans[1], pans[2]); + int prevPan = blockEntity.getPrevPan(); + int pan = blockEntity.getPan(); + poseStack.mulPose(Axis.YP.rotationDegrees((prevPan + (pan - prevPan) * partialTicks))); + poseStack.translate(-pans[0], -pans[1], -pans[2]); + //#endregion + //#region Model Tilt + float[] tilts = blockEntity.getFixture().getTiltRotationPosition(); + poseStack.translate(tilts[0], tilts[1], tilts[2]); + int prevTilt = blockEntity.getPrevTilt(); + int tilt = blockEntity.getTilt(); + if (isFlipped) { + poseStack.mulPose(Axis.XP.rotationDegrees(-180)); + } else { + poseStack.mulPose(Axis.XP.rotationDegrees(180)); + } + poseStack.mulPose(Axis.XP.rotationDegrees((prevTilt + (tilt - prevTilt) * partialTicks))); + poseStack.translate(-tilts[0], -tilts[1], -tilts[2]); + //#endregion + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/fixtures/Fixtures.java b/common/src/main/java/dev/imabad/theatrical/fixtures/Fixtures.java index cc32e9c..90fee8d 100644 --- a/common/src/main/java/dev/imabad/theatrical/fixtures/Fixtures.java +++ b/common/src/main/java/dev/imabad/theatrical/fixtures/Fixtures.java @@ -14,6 +14,9 @@ public class Fixtures { public static final RegistrySupplier MOVING_LIGHT = FIXTURES.register(new ResourceLocation(Theatrical.MOD_ID, "moving_light"), MovingLightFixture::new); + public static final RegistrySupplier MOVING_WASH = + FIXTURES.register(new ResourceLocation(Theatrical.MOD_ID, "moving_wash"), MovingWashFixture::new); + public static final RegistrySupplier LED_FRESNEL = FIXTURES.register(new ResourceLocation(Theatrical.MOD_ID, "fresnel"), LEDFresnelFixture::new); diff --git a/common/src/main/java/dev/imabad/theatrical/fixtures/MovingWashFixture.java b/common/src/main/java/dev/imabad/theatrical/fixtures/MovingWashFixture.java new file mode 100644 index 0000000..b465374 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/fixtures/MovingWashFixture.java @@ -0,0 +1,99 @@ +package dev.imabad.theatrical.fixtures; + +import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.api.Fixture; +import dev.imabad.theatrical.api.HangType; +import dev.imabad.theatrical.api.dmx.DMXPersonality; +import dev.imabad.theatrical.blocks.light.BaseLightBlock; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Collections; +import java.util.List; + +public class MovingWashFixture extends Fixture { + + private static final List PERSONALITIES = Collections.singletonList( + new DMXPersonality(7, "7-Channel Mode") + .addSlot(SharedSlots.INTENSITY) + .addSlot(SharedSlots.RED) + .addSlot(SharedSlots.GREEN) + .addSlot(SharedSlots.BLUE) + .addSlot(SharedSlots.FOCUS) + .addSlot(SharedSlots.PAN) + .addSlot(SharedSlots.TILT) + ); + + private static final ResourceLocation TILT_MODEL = new ResourceLocation(Theatrical.MOD_ID, "block/moving_wash/moving_wash_tilt"); + private static final ResourceLocation PAN_MODEL = new ResourceLocation(Theatrical.MOD_ID, "block/moving_wash/moving_wash_pan"); + private static final ResourceLocation STATIC_MODEL = new ResourceLocation(Theatrical.MOD_ID, "block/moving_wash/moving_wash_static"); + + private final float[] tiltRotation = new float[]{0.5F, .8F, .5F}; + private final float[] panRotation = new float[]{0.5F, .5F, .5F}; +// private final float[] beamStartPosition = new float[]{0.5F, -0.8F, 0F}; + + + @Override + public ResourceLocation getTiltModel() { + return TILT_MODEL; + } + + @Override + public ResourceLocation getPanModel() { + return PAN_MODEL; + } + + @Override + public ResourceLocation getStaticModel() { + return STATIC_MODEL; + } + + @Override + public float[] getTiltRotationPosition() { + return tiltRotation; + } + + @Override + public float[] getPanRotationPosition() { + return panRotation; + } + + @Override + public float[] getBeamStartPosition() { + return new float[]{0.7F, 0.8F, 0.4F}; + } + + @Override + public float getDefaultRotation() { + return 90; + } + + @Override + public float getBeamWidth() { + return 0.0f; + } + + @Override + public float getRayTraceRotation() { + return 0; + } + + @Override + public HangType getHangType() { + return HangType.BRACE_BAR; + } + + @Override + public float[] getTransforms(BlockState fixtureBlockState, BlockState supportBlockState) { + if(fixtureBlockState.getValue(BaseLightBlock.HANG_DIRECTION) == Direction.UP){ + return new float[]{0, .5f, 0}; + } + return new float[]{0, -0.35F, 0}; + } + + @Override + public List getDMXPersonalities() { + return PERSONALITIES; + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/items/Items.java b/common/src/main/java/dev/imabad/theatrical/items/Items.java index 5fc9a6b..f9bcabe 100644 --- a/common/src/main/java/dev/imabad/theatrical/items/Items.java +++ b/common/src/main/java/dev/imabad/theatrical/items/Items.java @@ -51,4 +51,8 @@ public class Items { "configuration_card", ConfigurationCard::new ); + public static final RegistrySupplier MOVING_WASH = ITEMS.register( + "moving_wash", + () -> new BlockItem(Blocks.MOVING_WASH_BLOCK.get(), new Item.Properties().arch$tab(Theatrical.TAB)) + ); } diff --git a/common/src/main/resources/assets/theatrical/blockstates/moving_wash.json b/common/src/main/resources/assets/theatrical/blockstates/moving_wash.json new file mode 100644 index 0000000..b1d31f1 --- /dev/null +++ b/common/src/main/resources/assets/theatrical/blockstates/moving_wash.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": {"model": "theatrical:block/moving_wash/moving_wash_whole"} + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_pan.json b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_pan.json new file mode 100644 index 0000000..f3f65ab --- /dev/null +++ b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_pan.json @@ -0,0 +1,65 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "theatrical:block/light_side", + "particle": "theatrical:block/moving_head_whole" + }, + "elements": [ + { + "name": "LeftSide", + "from": [13, 3, 6], + "to": [15, 14, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "name": "RightSide", + "from": [1, 3, 6], + "to": [3, 14, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [2, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "name": "RotateBase", + "from": [3, 3, 6], + "to": [13, 5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 0, 4, 2], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 0, 4, 2], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + }, + { + "name": "RotateBase", + "from": [6.5, 2, 6.75], + "to": [9.5, 3, 9.25], + "rotation": {"angle": 0, "axis": "y", "origin": [13.5, 2, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_static.json b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_static.json new file mode 100644 index 0000000..d8bf436 --- /dev/null +++ b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_static.json @@ -0,0 +1,22 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "theatrical:block/moving_head_body", + "2": "theatrical:block/light_side", + "particle": "theatrical:block/moving_head_whole" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 2, 16], + "faces": { + "north": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "east": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "west": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_tilt.json b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_tilt.json new file mode 100644 index 0000000..51b6311 --- /dev/null +++ b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_tilt.json @@ -0,0 +1,200 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "theatrical:block/moving_head_body", + "2": "theatrical:block/light_side", + "particle": "theatrical:block/moving_head_whole" + }, + "elements": [ + { + "from": [3.25, 9, 4.25], + "to": [12.75, 9.25, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [3, 9, 4.25], + "to": [3.25, 19, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [3.25, 10.75, 4.25], + "to": [12.75, 11, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [5, 9.25, 4.25], + "to": [5.25, 18.75, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [7, 9.25, 4.25], + "to": [7.25, 18.75, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [9, 9.25, 4.25], + "to": [9.25, 18.75, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [11, 9.25, 4.25], + "to": [11.25, 18.75, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [12.75, 9, 4.25], + "to": [13, 19, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [1, 1, 0.25, 10], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 5.25, 15], "texture": "#2"} + } + }, + { + "from": [3.25, 12.75, 4.25], + "to": [12.75, 13, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [3.25, 14.75, 4.25], + "to": [12.75, 15, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [3.25, 16.75, 4.25], + "to": [12.75, 17, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [3, 18.75, 4.25], + "to": [13, 19, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "texture": "#2"}, + "south": {"uv": [1, 1, 10, 0.25], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "from": [3, 9, 11.25], + "to": [13, 19, 11.75], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "east": {"uv": [1, 1, 15.25, 15], "texture": "#2"}, + "south": {"uv": [2, 2, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 9.25, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 15.25, 15], "rotation": 90, "texture": "#2"}, + "down": {"uv": [1, 1, 15.25, 15], "rotation": 270, "texture": "#2"} + } + }, + { + "from": [3.25, 9.25, 5], + "to": [12.75, 18.75, 5.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [7, 1, 11, 5], "texture": "#1"}, + "east": {"uv": [0, 0, 0.5, 9.5], "texture": "#missing"}, + "south": {"uv": [0, 0, 9.5, 9.5], "texture": "#missing"}, + "west": {"uv": [0, 0, 0.5, 9.5], "texture": "#missing"}, + "up": {"uv": [0, 0, 9.5, 0.5], "texture": "#missing"}, + "down": {"uv": [0, 0, 9.5, 0.5], "texture": "#missing"} + } + } + ], + "groups": [ + { + "name": "Spotbit", + "origin": [4, 22, 7], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_whole.json b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_whole.json new file mode 100644 index 0000000..236ce3b --- /dev/null +++ b/common/src/main/resources/assets/theatrical/models/block/moving_wash/moving_wash_whole.json @@ -0,0 +1,273 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "theatrical:block/moving_head_body", + "2": "theatrical:block/light_side", + "particle": "theatrical:block/moving_head_whole" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 2, 16], + "faces": { + "north": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "east": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "west": {"uv": [0, 13, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + }, + { + "name": "LeftSide", + "from": [13, 3, 6], + "to": [15, 14, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "name": "LeftSide", + "from": [1, 3, 6], + "to": [3, 14, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [2, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#2"} + } + }, + { + "name": "RotateBase", + "from": [3, 3, 6], + "to": [13, 5, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 3, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 0, 4, 2], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 0, 4, 2], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + }, + { + "name": "RotateBase", + "from": [6.5, 2, 6.75], + "to": [9.5, 3, 9.25], + "rotation": {"angle": 0, "axis": "y", "origin": [13.5, 2, 8]}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#2"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#2"} + } + }, + { + "from": [3.25, 10, 3.25], + "to": [12.75, 17, 3.5], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [3, 10, 3.25], + "to": [3.25, 17, 13.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [3.25, 10, 5], + "to": [12.75, 17, 5.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [5, 10, 3.5], + "to": [5.25, 17, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [7, 10, 3.5], + "to": [7.25, 17, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [9, 10, 3.5], + "to": [9.25, 17, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [11, 10, 3.5], + "to": [11.25, 17, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [12.75, 10, 3.25], + "to": [13, 17, 13.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 5.25, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 5.25, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 0.25, 10], "texture": "#2"} + } + }, + { + "from": [3.25, 10, 7], + "to": [12.75, 17, 7.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [3.25, 10, 9], + "to": [12.75, 17, 9.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [3.25, 10, 11], + "to": [12.75, 17, 11.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [3, 10, 13], + "to": [13, 17, 13.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "east": {"uv": [2, 1, 15, 5.25], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15, 15], "texture": "#2"}, + "west": {"uv": [1, 1, 15, 5.25], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 5.25], "rotation": 180, "texture": "#2"}, + "down": {"uv": [1, 1, 10, 0.25], "texture": "#2"} + } + }, + { + "from": [3, 9.5, 3.25], + "to": [13, 10, 13.25], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [1, 1, 15.25, 15], "rotation": 90, "texture": "#2"}, + "east": {"uv": [1, 1, 15.25, 15], "rotation": 270, "texture": "#2"}, + "south": {"uv": [1, 1, 15.25, 15], "rotation": 90, "texture": "#2"}, + "west": {"uv": [1, 1, 9.25, 15], "rotation": 90, "texture": "#2"}, + "up": {"uv": [1, 1, 15, 15], "rotation": 180, "texture": "#2"}, + "down": {"uv": [2, 2, 15, 15], "texture": "#2"} + } + }, + { + "from": [3.25, 15.75, 3.5], + "to": [12.75, 16.25, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 13.5, 7.75]}, + "faces": { + "north": {"uv": [0, 0, 9.5, 0.5], "rotation": 180, "texture": "#missing"}, + "east": {"uv": [0, 0, 0.5, 9.5], "rotation": 270, "texture": "#missing"}, + "south": {"uv": [0, 0, 9.5, 0.5], "texture": "#missing"}, + "west": {"uv": [0, 0, 0.5, 9.5], "rotation": 90, "texture": "#missing"}, + "up": {"uv": [7, 1, 11, 5], "rotation": 180, "texture": "#1"}, + "down": {"uv": [0, 0, 9.5, 9.5], "texture": "#missing"} + } + } + ], + "groups": [ + 0, + 1, + 2, + 3, + 4, + { + "name": "Spotbit", + "origin": [4, 22, 7], + "color": 0, + "children": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] + } + ] +} \ No newline at end of file