From 3f4a12485bf0df383c5859052f843d73eb1ec93f Mon Sep 17 00:00:00 2001 From: Evan Kreutzwiser <53940800+Evan-Kreutzwiser@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:56:09 -0400 Subject: [PATCH 1/4] Prevent undesired drop from breaking top half of sunshine monolith --- .../block/impl/SunshineMonolithBlock.java | 17 +++++++++++++---- src/main/resources/affinity.accesswidener | 4 +++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java b/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java index 3831b471..b97f90cc 100644 --- a/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java +++ b/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java @@ -5,15 +5,13 @@ import io.wispforest.affinity.blockentity.template.TickedBlockEntity; import io.wispforest.affinity.object.AffinityBlocks; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.ShapeContext; +import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.enums.DoubleBlockHalf; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.state.StateManager; @@ -94,6 +92,17 @@ public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { return downState.isOf(this) && downState.get(HALF) == DoubleBlockHalf.LOWER; } + @Override + public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + // This is how vanilla doors handle preventing unwanted drops + if (!world.isClient && (player.isCreative() || !player.canHarvest(state))) { + TallPlantBlock.onBreakInCreative(world, pos, state, player); + } + + return super.onBreak(world, pos, state, player); + } + + @Override public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { return state.get(HALF) == DoubleBlockHalf.LOWER ? LOWER_SHAPE : UPPER_SHAPE; diff --git a/src/main/resources/affinity.accesswidener b/src/main/resources/affinity.accesswidener index 2e9fca7b..886ae23a 100644 --- a/src/main/resources/affinity.accesswidener +++ b/src/main/resources/affinity.accesswidener @@ -32,4 +32,6 @@ accessible field net/minecraft/block/CandleBlock CANDLES_TO_PARTICLE_OFFSETS Lit accessible class net/minecraft/server/world/ServerChunkLoadingManager$TicketManager -accessible class net/minecraft/datafixer/fix/ItemStackComponentizationFix$StackData \ No newline at end of file +accessible class net/minecraft/datafixer/fix/ItemStackComponentizationFix$StackData + +accessible method net/minecraft/block/TallPlantBlock onBreakInCreative (Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/entity/player/PlayerEntity;)V \ No newline at end of file From 78b43a5838c90073ff45f8fdbce03b8fc84d1ed7 Mon Sep 17 00:00:00 2001 From: Evan Kreutzwiser <53940800+Evan-Kreutzwiser@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:56:57 -0400 Subject: [PATCH 2/4] Render top half of sunshine monolith in inquiry gui --- .../impl/SunshineMonolithBlockEntity.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java b/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java index 9b356157..e8488833 100644 --- a/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java +++ b/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java @@ -1,5 +1,7 @@ package io.wispforest.affinity.blockentity.impl; +import io.wispforest.affinity.aethumflux.net.AethumNetworkMember; +import io.wispforest.affinity.aethumflux.net.MultiblockAethumNetworkMember; import io.wispforest.affinity.block.impl.SunshineMonolithBlock; import io.wispforest.affinity.blockentity.template.AethumNetworkMemberBlockEntity; import io.wispforest.affinity.blockentity.template.TickedBlockEntity; @@ -8,7 +10,10 @@ import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; -public class SunshineMonolithBlockEntity extends AethumNetworkMemberBlockEntity implements TickedBlockEntity { +import java.util.Collection; +import java.util.List; + +public class SunshineMonolithBlockEntity extends AethumNetworkMemberBlockEntity implements TickedBlockEntity, MultiblockAethumNetworkMember { public SunshineMonolithBlockEntity(BlockPos pos, BlockState state) { super(AffinityBlocks.Entities.SUNSHINE_MONOLITH, pos, state); @@ -66,4 +71,19 @@ private void removeMonolithFromChunks() { } } } + + @Override + public Collection memberBlocks() { + return List.of(this.getPos(), this.getPos().up()); + } + + @Override + public boolean isParent() { + return true; + } + + @Override + public AethumNetworkMember parent() { + return this; + } } From 644aa6c77e96b48e014580dda82dcd45866d1afe Mon Sep 17 00:00:00 2001 From: Evan Kreutzwiser <53940800+Evan-Kreutzwiser@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:32:41 -0400 Subject: [PATCH 3/4] disable sunshine monolith on redstone signal (w/ tooltip) --- .../block/impl/SunshineMonolithBlock.java | 27 +++++++++++++++--- .../impl/SunshineMonolithBlockEntity.java | 13 ++++++++- .../resources/assets/affinity/lang/en_us.json | 1 + .../affinity/textures/gui/tooltip_icons.png | Bin 636 -> 781 bytes 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java b/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java index b97f90cc..09071905 100644 --- a/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java +++ b/src/main/java/io/wispforest/affinity/block/impl/SunshineMonolithBlock.java @@ -31,6 +31,7 @@ public class SunshineMonolithBlock extends AethumNetworkMemberBlock { public static final BooleanProperty ENABLED = Properties.ENABLED; + public static final BooleanProperty POWERED = Properties.POWERED; public static final EnumProperty HALF = Properties.DOUBLE_BLOCK_HALF; public static final VoxelShape LOWER_SHAPE = VoxelShapes.union( @@ -41,8 +42,25 @@ public class SunshineMonolithBlock extends AethumNetworkMemberBlock { public static final VoxelShape UPPER_SHAPE = Block.createCuboidShape(2, 0, 2, 14, 16, 14); public SunshineMonolithBlock() { - super(FabricBlockSettings.copyOf(Blocks.SMOOTH_STONE), CONSUMER_TOOLTIP); - this.setDefaultState(this.getDefaultState().with(Properties.ENABLED, false).with(HALF, DoubleBlockHalf.LOWER)); + super(Settings.copy(Blocks.SMOOTH_STONE), CONSUMER_TOOLTIP); + this.setDefaultState(this.getDefaultState().with(ENABLED, false).with(HALF, DoubleBlockHalf.LOWER).with(POWERED, false)); + } + + @Override + protected void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { + var otherHalfPos = pos.offset(state.get(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN); + var powered = world.isReceivingRedstonePower(pos) | world.isReceivingRedstonePower(otherHalfPos); + + if (state.get(POWERED) != powered) { + world.setBlockState(pos, state.with(POWERED, powered), 2); + + var otherState = world.getBlockState(otherHalfPos); + if (otherState.isOf(this) && otherState.get(POWERED) != powered) { + world.setBlockState(otherHalfPos, otherState.with(POWERED, powered)); + } + } + + super.neighborUpdate(state, world, pos, sourceBlock, sourcePos, notify); } @Override @@ -73,9 +91,10 @@ public BlockState getStateForNeighborUpdate(BlockState state, Direction directio public BlockState getPlacementState(ItemPlacementContext context) { var pos = context.getBlockPos(); var world = context.getWorld(); + var powered = world.isReceivingRedstonePower(pos); return pos.getY() < world.getTopY() - 1 && world.getBlockState(pos.up()).canReplace(context) - ? super.getPlacementState(context) + ? super.getPlacementState(context).with(POWERED, powered) : null; } @@ -110,7 +129,7 @@ public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos po @Override protected void appendProperties(StateManager.Builder builder) { - builder.add(Properties.ENABLED).add(HALF); + builder.add(ENABLED).add(HALF).add(POWERED); } @Nullable diff --git a/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java b/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java index e8488833..ed6ecf91 100644 --- a/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java +++ b/src/main/java/io/wispforest/affinity/blockentity/impl/SunshineMonolithBlockEntity.java @@ -8,6 +8,8 @@ import io.wispforest.affinity.component.AffinityComponents; import io.wispforest.affinity.object.AffinityBlocks; import net.minecraft.block.BlockState; +import net.minecraft.state.property.Properties; +import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import java.util.Collection; @@ -24,7 +26,7 @@ public SunshineMonolithBlockEntity(BlockPos pos, BlockState state) { @Override public void tickServer() { long flux = flux(); - boolean shouldBeEnabled = flux >= 1; + boolean shouldBeEnabled = flux >= 1 && !this.getCachedState().get(SunshineMonolithBlock.POWERED); if (shouldBeEnabled != this.getCachedState().get(SunshineMonolithBlock.ENABLED)) { this.world.setBlockState(this.pos, this.getCachedState().with(SunshineMonolithBlock.ENABLED, shouldBeEnabled)); @@ -72,6 +74,15 @@ private void removeMonolithFromChunks() { } } + @Override + public void appendTooltipEntries(List entries) { + super.appendTooltipEntries(entries); + + if (getCachedState().get(Properties.POWERED)) { + entries.add(Entry.icon(Text.translatable("text.affinity.tooltip.disabled_by_redstone"), 24, 8)); + } + } + @Override public Collection memberBlocks() { return List.of(this.getPos(), this.getPos().up()); diff --git a/src/main/resources/assets/affinity/lang/en_us.json b/src/main/resources/assets/affinity/lang/en_us.json index 33030713..4df0a5c5 100644 --- a/src/main/resources/assets/affinity/lang/en_us.json +++ b/src/main/resources/assets/affinity/lang/en_us.json @@ -798,6 +798,7 @@ "text.affinity.tooltip.aethum_storage": "Flux: %d/%d", "text.affinity.tooltip.creative_flux_cache_flux_level": "All of it, really", + "text.affinity.tooltip.disabled_by_redstone": "Disabled by redstone", "death.attack.asteroid": "%s was expunged by an Asteroid", "death.attack.asteroid.player": "%s was expunged by %s's Asteroid", diff --git a/src/main/resources/assets/affinity/textures/gui/tooltip_icons.png b/src/main/resources/assets/affinity/textures/gui/tooltip_icons.png index f936befa4fe5ac1f92b91250822ca22061a08a62..90dd79af2a85bf5df78d289aa176093a1f1a7d0d 100644 GIT binary patch delta 752 zcmV0Dy!5 z0Qvv`0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000JJOGiWi{{a60|De66lK=n!32;bR za{vGf6951U69E94oEQKA00(qQO+^Rl1`iT53a2!Tf&c&lQGZE9K~z}7?UXT06JZ#J zpWk#-5~+h7>;SiP0Bp1=P#ujS3@$KOMiXO-0|OHzu51bnk{FYYdV?&T8qzpnX$diy zbYSq(ggUf|DG9WUd=Bs*cfC6TMiz7L((ms3+xPvx_wBE^W(+mE;(V^HcU=95F21bQ z?Ss>^14`G4{C|wxdHRrV_vV$e4kB?8yuPadYO$NjSKa%Tc*y;p6Zsi=^y{tk)Sg58ei#T0D@^iGGjTy%(QUB99}s?QR0l z{5Yjt7K~2xt7`GUR{HhF!C(13+&bp>nA(yrbOKXL%2)RpXcwpYIJe3`V2KObbA zZRSXc=YJ-2l52E29ghXwN+WRn0F~}xAUUQ9BCKSyU?QvRsECu?vMc}$!{F%XNc#Hv zlwSEp@*M!V=(7El#!^-3l_xh$0HV1CyT8<^sWNF9XB$3O&tk9GBFzdrKDROF zMA6e&XZxxX z0oZx--8ZL$50C!Jguu{H46k|?{;2q0(Z0~sO9P+4NYF=K48w5aXg)1Y)rR6_pzwUu zkgC(8$d$XVlp4!zdE&WAsx`jixtgMQsmLsjJ*|Aykbj(Gt0Gq_!~Eo@H^P_zT{KAf zG+s1LZZuBc2)rEw3ex6{o7K(rv4bwM zdvvTORad9S=IX;)FMzp9rQ&uzskp|B8${O(tWNM4;^q=-(c5&a=F9>VOgEnU3`dgT;n~goK2IgoJ2*0ZW7xuNfI{X8-^I07*qoM6N<$f{~yzz5oCK From cc4f5385fca649af173e69ee806d6a4496384aca Mon Sep 17 00:00:00 2001 From: Evan Kreutzwiser <53940800+Evan-Kreutzwiser@users.noreply.github.com> Date: Tue, 16 Jun 2026 12:06:47 -0400 Subject: [PATCH 4/4] make sunshine monolith prevent snow accumulation --- .../affinity/mixin/ServerWorldMixin.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/io/wispforest/affinity/mixin/ServerWorldMixin.java b/src/main/java/io/wispforest/affinity/mixin/ServerWorldMixin.java index 98ead23b..cd69e3c8 100644 --- a/src/main/java/io/wispforest/affinity/mixin/ServerWorldMixin.java +++ b/src/main/java/io/wispforest/affinity/mixin/ServerWorldMixin.java @@ -1,6 +1,8 @@ package io.wispforest.affinity.mixin; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import io.wispforest.affinity.Affinity; import io.wispforest.affinity.component.AffinityComponents; @@ -93,4 +95,17 @@ private BlockPos makeSunshineMonolithsStopThunder(BlockPos pos) { return pos; } + + // tickIceAndSnow doesn't use the position-aware hasRain call hooked in WorldMixin + // Ice is still permitted to form, only precipitation is blocked + @WrapOperation(method = "tickIceAndSnow", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;isRaining()Z")) + private boolean makeSunshineMonolithPreventSnow(ServerWorld instance, Operation original, BlockPos pos) { + var chunk = getWorldChunk(pos); + if (chunk instanceof EmptyChunk) { + return original.call(instance); + } + + var component = chunk.getComponent(AffinityComponents.LOCAL_WEATHER); + return component.getRainGradient() > 0.2; + } }