Skip to content

Commit e0a80dd

Browse files
committed
feat: Match Chicken Sink to Cow in a Jar
1 parent 1146dab commit e0a80dd

4 files changed

Lines changed: 99 additions & 6 deletions

File tree

common/src/main/java/net/blay09/mods/cookingforblockheads/block/ChickenSinkBlock.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
7979
@Nullable
8080
@Override
8181
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
82-
return !level.isClientSide() ? createTickerHelper(type, ModBlockEntities.chickenSink.value(), ChickenSinkBlockEntity::serverTick) : null;
82+
return level.isClientSide()
83+
? createTickerHelper(type, ModBlockEntities.chickenSink.value(), ChickenSinkBlockEntity::clientTick)
84+
: createTickerHelper(type, ModBlockEntities.chickenSink.value(), ChickenSinkBlockEntity::serverTick);
8385
}
8486

8587
@Override

common/src/main/java/net/blay09/mods/cookingforblockheads/block/entity/ChickenSinkBlockEntity.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import net.minecraft.world.item.ItemStack;
3939
import net.minecraft.world.item.Items;
4040
import net.minecraft.world.level.Level;
41+
import net.minecraft.world.level.block.Blocks;
4142
import net.minecraft.world.level.block.entity.BlockEntity;
4243
import net.minecraft.world.level.block.state.BlockState;
4344
import net.minecraft.world.level.storage.ValueInput;
@@ -61,6 +62,8 @@ public void setChanged() {
6162
private int eggLayTime;
6263
private int eggLayTimeTarget = defaultEggLayTime();
6364
private @Nullable Component customName;
65+
private @Nullable BlockPos jukebox;
66+
private int partyBpm;
6467

6568
public ChickenSinkBlockEntity(BlockPos pos, BlockState state) {
6669
super(ModBlockEntities.chickenSink.value(), pos, state);
@@ -70,6 +73,14 @@ public static void serverTick(Level level, BlockPos pos, BlockState state, Chick
7073
blockEntity.serverTick(level);
7174
}
7275

76+
public static void clientTick(Level level, BlockPos pos, BlockState state, ChickenSinkBlockEntity blockEntity) {
77+
final var jukebox = blockEntity.jukebox;
78+
if (jukebox == null || !jukebox.closerToCenterThan(pos.getCenter(), 3.46f) || !level.getBlockState(jukebox).is(Blocks.JUKEBOX)) {
79+
blockEntity.partyBpm = 0;
80+
blockEntity.jukebox = null;
81+
}
82+
}
83+
7384
@Override
7485
protected void applyImplicitComponents(DataComponentGetter input) {
7586
final var customNameComponent = input.get(DataComponents.CUSTOM_NAME);
@@ -241,6 +252,15 @@ public void preRemoveSideEffects(BlockPos pos, BlockState state) {
241252
return BalmBlockEntityUtils.createUpdatePacket(this);
242253
}
243254

255+
public boolean isPartying() {
256+
return partyBpm > 0;
257+
}
258+
259+
public void setRecordPlayingNearby(BlockPos pos, boolean playing) {
260+
this.jukebox = pos;
261+
this.partyBpm = playing ? 85 : 0;
262+
}
263+
244264
public record TransferData(TransferableContainer container, int eggLayTime, int eggLayTimeTarget) {
245265
}
246266
}

common/src/main/java/net/blay09/mods/cookingforblockheads/client/render/ChickenSinkRenderer.java

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.mojang.blaze3d.vertex.PoseStack;
44
import com.mojang.math.Axis;
5+
import net.blay09.mods.cookingforblockheads.block.BaseKitchenBlock;
56
import net.blay09.mods.cookingforblockheads.block.ChickenSinkBlock;
67
import net.blay09.mods.cookingforblockheads.block.entity.ChickenSinkBlockEntity;
78
import net.minecraft.client.model.animal.chicken.AdultChickenModel;
@@ -20,9 +21,12 @@
2021
import net.minecraft.core.registries.Registries;
2122
import net.minecraft.resources.Identifier;
2223
import net.minecraft.util.Mth;
24+
import net.minecraft.world.attribute.EnvironmentAttributes;
2325
import net.minecraft.world.entity.animal.chicken.ChickenVariant;
2426
import net.minecraft.world.entity.animal.chicken.ChickenVariants;
2527
import net.minecraft.world.level.Level;
28+
import net.minecraft.world.level.MoonPhase;
29+
import net.minecraft.world.level.block.state.BlockState;
2630
import net.minecraft.world.phys.Vec3;
2731
import org.jspecify.annotations.Nullable;
2832

@@ -48,6 +52,74 @@ public ChickenSinkRenderState createRenderState() {
4852
return new ChickenSinkRenderState();
4953
}
5054

55+
private boolean shouldCreepyStare(@Nullable Level level, net.minecraft.core.BlockPos pos) {
56+
if (level == null) {
57+
return false;
58+
}
59+
60+
final var moonPhase = level.environmentAttributes().getValue(EnvironmentAttributes.MOON_PHASE, pos);
61+
final var moonAngle = level.environmentAttributes().getValue(EnvironmentAttributes.MOON_ANGLE, pos) % 360;
62+
boolean moonVisible = (moonAngle >= 270 || moonAngle <= 87.5);
63+
return moonPhase == MoonPhase.FULL_MOON && moonVisible;
64+
}
65+
66+
private void headbang(@Nullable Level level, ChickenSinkRenderState renderState, int bpm) {
67+
long gameTime = level != null ? level.getGameTime() : 0;
68+
float headbangIntensity = 25f;
69+
float headbangSpeed = bpm * (float) Math.PI / 600f;
70+
renderState.chicken.xRot = (float) Math.sin(gameTime * headbangSpeed) * headbangIntensity;
71+
renderState.chicken.yRot = (float) Math.cos(gameTime * headbangSpeed * 0.7f) * 10f;
72+
}
73+
74+
private void creepyStare(Level level, net.minecraft.core.BlockPos pos, BlockState state, float delta, ChickenSinkRenderState renderState) {
75+
final var nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5f, pos.getY() + 0.5f, pos.getZ() + 0.5f, 16f, false);
76+
if (nearestPlayer != null) {
77+
final var chickenPos = new Vec3(pos.getX() + 0.5f, pos.getY() + 0.5f, pos.getZ() + 0.5f);
78+
final var playerPos = nearestPlayer.getEyePosition(delta);
79+
final var direction = playerPos.subtract(chickenPos);
80+
81+
float blockYaw = state.getValue(BaseKitchenBlock.FACING).toYRot();
82+
double yaw = Math.atan2(-direction.x, direction.z);
83+
float yawDegrees = (float) Math.toDegrees(yaw);
84+
float relativeYaw = yawDegrees - blockYaw;
85+
while (relativeYaw > 180f) relativeYaw -= 360f;
86+
while (relativeYaw < -180f) relativeYaw += 360f;
87+
renderState.chicken.yRot = Mth.clamp(relativeYaw, -90f, 90f);
88+
89+
double horizontalDistance = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
90+
double pitch = Math.atan2(-direction.y, horizontalDistance);
91+
float pitchDegrees = (float) Math.toDegrees(pitch);
92+
renderState.chicken.xRot = Mth.clamp(pitchDegrees, -60f, 60f);
93+
} else {
94+
applyIdleAnimation(level, delta, renderState);
95+
}
96+
}
97+
98+
private void applyIdleAnimation(@Nullable Level level, float delta, ChickenSinkRenderState renderState) {
99+
long gameTime = level != null ? level.getGameTime() : 0L;
100+
float animationTime = (gameTime + delta) * 0.08f;
101+
renderState.chicken.xRot = -8f + Mth.sin(animationTime * 0.7f) * 4f;
102+
renderState.chicken.yRot = Mth.cos(animationTime * 0.55f) * 10f;
103+
}
104+
105+
private void updateChickenPose(ChickenSinkBlockEntity blockEntity, float delta, ChickenSinkRenderState renderState) {
106+
final var level = blockEntity.getLevel();
107+
final var pos = blockEntity.getBlockPos();
108+
final var state = blockEntity.getBlockState();
109+
110+
if (blockEntity.isPartying()) {
111+
headbang(level, renderState, 85);
112+
return;
113+
}
114+
115+
if (shouldCreepyStare(level, pos)) {
116+
creepyStare(level, pos, state, delta, renderState);
117+
return;
118+
}
119+
120+
applyIdleAnimation(level, delta, renderState);
121+
}
122+
51123
@Override
52124
public void extractRenderState(ChickenSinkBlockEntity blockEntity, ChickenSinkRenderState renderState, float delta, Vec3 vec, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
53125
BlockEntityRenderer.super.extractRenderState(blockEntity, renderState, delta, vec, crumblingOverlay);
@@ -58,11 +130,7 @@ public void extractRenderState(ChickenSinkBlockEntity blockEntity, ChickenSinkRe
58130
.flatMap(it -> it.getOptional(ChickenVariants.DEFAULT))
59131
.orElse(null)
60132
: null;
61-
62-
long gameTime = blockEntity.getLevel() != null ? blockEntity.getLevel().getGameTime() : 0L;
63-
float animationTime = (gameTime + delta) * 0.08f;
64-
renderState.chicken.xRot = -8f + Mth.sin(animationTime * 0.7f) * 4f;
65-
renderState.chicken.yRot = Mth.cos(animationTime * 0.55f) * 10f;
133+
updateChickenPose(blockEntity, delta, renderState);
66134
}
67135

68136
@Override

common/src/main/java/net/blay09/mods/cookingforblockheads/mixin/LevelEventHandlerMixin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.blay09.mods.cookingforblockheads.mixin;
22

33
import net.blay09.mods.cookingforblockheads.block.entity.CowJarBlockEntity;
4+
import net.blay09.mods.cookingforblockheads.block.entity.ChickenSinkBlockEntity;
45
import net.minecraft.client.renderer.LevelEventHandler;
56
import net.minecraft.core.BlockPos;
67
import net.minecraft.world.level.Level;
@@ -23,6 +24,8 @@ private void notifyNearbyEntities(Level level, BlockPos pos, boolean playing, Ca
2324
final var blockEntity = level.getBlockEntity(mutablePos);
2425
if (blockEntity instanceof CowJarBlockEntity cowJar) {
2526
cowJar.setRecordPlayingNearby(pos, playing);
27+
} else if (blockEntity instanceof ChickenSinkBlockEntity chickenSink) {
28+
chickenSink.setRecordPlayingNearby(pos, playing);
2629
}
2730
}
2831
}

0 commit comments

Comments
 (0)